| Start/ | End/ | |||
| True | False | - | Line | Source |
| 1 | /* | |||
| 2 | * linux/drivers/scsi/ide-scsi.c Version 0.9 Jul 4, 1999 | |||
| 3 | * | |||
| 4 | * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il> | |||
| 5 | */ | |||
| 6 | ||||
| 7 | /* | |||
| 8 | * Emulation of a SCSI host adapter for IDE ATAPI devices. | |||
| 9 | * | |||
| 10 | * With this driver, one can use the Linux SCSI drivers instead of the | |||
| 11 | * native IDE ATAPI drivers. | |||
| 12 | * | |||
| 13 | * Ver 0.1 Dec 3 96 Initial version. | |||
| 14 | * Ver 0.2 Jan 26 97 Fixed bug in cleanup_module() and added emulation | |||
| 15 | * of MODE_SENSE_6/MODE_SELECT_6 for cdroms. Thanks | |||
| 16 | * to Janos Farkas for pointing this out. | |||
| 17 | * Avoid using bitfields in structures for m68k. | |||
| 18 | * Added Scatter/Gather and DMA support. | |||
| 19 | * Ver 0.4 Dec 7 97 Add support for ATAPI PD/CD drives. | |||
| 20 | * Use variable timeout for each command. | |||
| 21 | * Ver 0.5 Jan 2 98 Fix previous PD/CD support. | |||
| 22 | * Allow disabling of SCSI-6 to SCSI-10 transformation. | |||
| 23 | * Ver 0.6 Jan 27 98 Allow disabling of SCSI command translation layer | |||
| 24 | * for access through /dev/sg. | |||
| 25 | * Fix MODE_SENSE_6/MODE_SELECT_6/INQUIRY translation. | |||
| 26 | * Ver 0.7 Dec 04 98 Ignore commands where lun != 0 to avoid multiple | |||
| 27 | * detection of devices with CONFIG_SCSI_MULTI_LUN | |||
| 28 | * Ver 0.8 Feb 05 99 Optical media need translation too. Reverse 0.7. | |||
| 29 | * Ver 0.9 Jul 04 99 Fix a bug in SG_SET_TRANSFORM. | |||
| 30 | * Ver 0.91 Jun 10 02 Fix "off by one" error in transforms | |||
| 31 | * Ver 0.92 Dec 31 02 Implement new SCSI mid level API | |||
| 32 | */ | |||
| 33 | ||||
| 34 | #define IDESCSI_VERSION "0.92" | |||
| 35 | ||||
| 36 | #include <linux/module.h> | |||
| 37 | #include <linux/config.h> | |||
| 38 | #include <linux/types.h> | |||
| 39 | #include <linux/string.h> | |||
| 40 | #include <linux/kernel.h> | |||
| 41 | #include <linux/mm.h> | |||
| 42 | #include <linux/ioport.h> | |||
| 43 | #include <linux/blkdev.h> | |||
| 44 | #include <linux/errno.h> | |||
| 45 | #include <linux/hdreg.h> | |||
| 46 | #include <linux/slab.h> | |||
| 47 | #include <linux/ide.h> | |||
| 48 | #include <linux/scatterlist.h> | |||
| 49 | #include <linux/delay.h> | |||
| 50 | ||||
| 51 | #include <asm/io.h> | |||
| 52 | #include <asm/bitops.h> | |||
| 53 | #include <asm/uaccess.h> | |||
| 54 | ||||
| 55 | #include <scsi/scsi.h> | |||
| 56 | #include <scsi/scsi_cmnd.h> | |||
| 57 | #include <scsi/scsi_device.h> | |||
| 58 | #include <scsi/scsi_host.h> | |||
| 59 | #include <scsi/scsi_tcq.h> | |||
| 60 | #include <scsi/sg.h> | |||
| 61 | ||||
| 62 | #define IDESCSI_DEBUG_LOG 0 | |||
| 63 | ||||
| 64 | typedef struct idescsi_pc_s { | |||
| 65 | u8 c[12]; /* Actual packet bytes */ | |||
| 66 | int request_transfer; /* Bytes to transfer */ | |||
| 67 | int actually_transferred; /* Bytes actually transferred */ | |||
| 68 | int buffer_size; /* Size of our data buffer */ | |||
| 69 | struct request *rq; /* The corresponding request */ | |||
| 70 | u8 *buffer; /* Data buffer */ | |||
| 71 | u8 *current_position; /* Pointer into the above buffer */ | |||
| 72 | struct scatterlist *sg; /* Scatter gather table */ | |||
| 73 | int b_count; /* Bytes transferred from current entry */ | |||
| 74 | struct scsi_cmnd *scsi_cmd; /* SCSI command */ | |||
| 75 | void (*done)(struct scsi_cmnd *); /* Scsi completion routine */ | |||
| 76 | unsigned long flags; /* Status/Action flags */ | |||
| 77 | unsigned long timeout; /* Command timeout */ | |||
| 78 | } idescsi_pc_t; | |||
| 79 | ||||
| 80 | /* | |||
| 81 | * Packet command status bits. | |||
| 82 | */ | |||
| 83 | #define PC_DMA_IN_PROGRESS 0 /* 1 while DMA in progress */ | |||
| 84 | #define PC_WRITING 1 /* Data direction */ | |||
| 85 | #define PC_TRANSFORM 2 /* transform SCSI commands */ | |||
| 86 | #define PC_TIMEDOUT 3 /* command timed out */ | |||
| 87 | #define PC_DMA_OK 4 /* Use DMA */ | |||
| 88 | ||||
| 89 | /* | |||
| 90 | * SCSI command transformation layer | |||
| 91 | */ | |||
| 92 | #define IDESCSI_TRANSFORM 0 /* Enable/Disable transformation */ | |||
| 93 | #define IDESCSI_SG_TRANSFORM 1 /* /dev/sg transformation */ | |||
| 94 | ||||
| 95 | /* | |||
| 96 | * Log flags | |||
| 97 | */ | |||
| 98 | #define IDESCSI_LOG_CMD 0 /* Log SCSI commands */ | |||
| 99 | ||||
| 100 | typedef struct ide_scsi_obj { | |||
| 101 | ide_drive_t *drive; | |||
| 102 | ide_driver_t *driver; | |||
| 103 | struct gendisk *disk; | |||
| 104 | struct Scsi_Host *host; | |||
| 105 | ||||
| 106 | idescsi_pc_t *pc; /* Current packet command */ | |||
| 107 | unsigned long flags; /* Status/Action flags */ | |||
| 108 | unsigned long transform; /* SCSI cmd translation layer */ | |||
| 109 | unsigned long log; /* log flags */ | |||
| 110 | } idescsi_scsi_t; | |||
| 111 | ||||
| 112 | static DECLARE_MUTEX(idescsi_ref_sem); | |||
| 113 | ||||
| 114 | #define ide_scsi_g(disk) \ | |||
| 115 | container_of((disk)->private_data, struct ide_scsi_obj, driver) | |||
| 116 | ||||
| 0 | 0 | - | 117 | static struct ide_scsi_obj *ide_scsi_get(struct gendisk *disk) |
| 118 | { | |||
| 119 | struct ide_scsi_obj *scsi = NULL; | |||
| 120 | ||||
| 121 | down(&idescsi_ref_sem); | |||
| 122 | scsi = ide_scsi_g(disk); | |||
| 0 | 0 | - | 123 | if (scsi) |
| 124 | scsi_host_get(scsi->host); | |||
| 125 | up(&idescsi_ref_sem); | |||
| 0 | - | 126 | return scsi; | |
| 127 | } | |||
| 128 | ||||
| 0 | 0 | - | 129 | static void ide_scsi_put(struct ide_scsi_obj *scsi) |
| 130 | { | |||
| 131 | down(&idescsi_ref_sem); | |||
| 132 | scsi_host_put(scsi->host); | |||
| 133 | up(&idescsi_ref_sem); | |||
| 134 | } | |||
| 135 | ||||
| 0 | 0 | - | 136 | static inline idescsi_scsi_t *scsihost_to_idescsi(struct Scsi_Host *host) |
| 137 | { | |||
| 0 | - | 138 | return (idescsi_scsi_t*) (&host[1]); | |
| 139 | } | |||
| 140 | ||||
| 0 | 0 | - | 141 | static inline idescsi_scsi_t *drive_to_idescsi(ide_drive_t *ide_drive) |
| 142 | { | |||
| 0 | - | 143 | return scsihost_to_idescsi(ide_drive->driver_data); | |
| 144 | } | |||
| 145 | ||||
| 146 | /* | |||
| 147 | * Per ATAPI device status bits. | |||
| 148 | */ | |||
| 149 | #define IDESCSI_DRQ_INTERRUPT 0 /* DRQ interrupt device */ | |||
| 150 | ||||
| 151 | /* | |||
| 152 | * ide-scsi requests. | |||
| 153 | */ | |||
| 154 | #define IDESCSI_PC_RQ 90 | |||
| 155 | ||||
| 0 | 0 | - | 156 | static void idescsi_discard_data (ide_drive_t *drive, unsigned int bcount) |
| 157 | { | |||
| 0 | 0 | - | 158 | while (bcount--) |
| 159 | (void) HWIF(drive)->INB(IDE_DATA_REG); | |||
| 160 | } | |||
| 161 | ||||
| 0 | 0 | - | 162 | static void idescsi_output_zeros (ide_drive_t *drive, unsigned int bcount) |
| 163 | { | |||
| 0 | 0 | - | 164 | while (bcount--) |
| 165 | HWIF(drive)->OUTB(0, IDE_DATA_REG); | |||
| 166 | } | |||
| 167 | ||||
| 168 | /* | |||
| 169 | * PIO data transfer routines using the scatter gather table. | |||
| 170 | */ | |||
| 0 | 0 | - | 171 | static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigned int bcount) |
| 172 | { | |||
| 173 | int count; | |||
| 174 | char *buf; | |||
| 175 | ||||
| 0 | 0 | - | 176 | while (bcount) { |
| 0 | 0 | - | 177 | if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) { |
| 178 | printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n"); | |||
| 179 | idescsi_discard_data (drive, bcount); | |||
| 0 | - | 180 | return; | |
| 181 | } | |||
| 182 | count = min(pc->sg->length - pc->b_count, bcount); | |||
| 0 | 0 | - | 183 | if (PageHighMem(pc->sg->page)) { |
| 184 | unsigned long flags; | |||
| 185 | ||||
| 186 | local_irq_save(flags); | |||
| 186 | do | |||
| 0 | 0 | - | 186 | do-while (0) |
| 0 | 0 | - | 186 | do-while (0) |
| 187 | buf = kmap_atomic(pc->sg->page, KM_IRQ0) + | |||
| 188 | pc->sg->offset; | |||
| 189 | drive->hwif->atapi_input_bytes(drive, | |||
| 190 | buf + pc->b_count, count); | |||
| 191 | kunmap_atomic(buf - pc->sg->offset, KM_IRQ0); | |||
| 0 | 0 | - | 191 | do-while (0) |
| 192 | local_irq_restore(flags); | |||
| 193 | } else { | |||
| 194 | buf = page_address(pc->sg->page) + pc->sg->offset; | |||
| 195 | drive->hwif->atapi_input_bytes(drive, | |||
| 196 | buf + pc->b_count, count); | |||
| 197 | } | |||
| 198 | bcount -= count; pc->b_count += count; | |||
| 0 | 0 | - | 199 | if (pc->b_count == pc->sg->length) { |
| 200 | pc->sg++; | |||
| 201 | pc->b_count = 0; | |||
| 202 | } | |||
| 203 | } | |||
| 204 | } | |||
| 205 | ||||
| 0 | 0 | - | 206 | static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigned int bcount) |
| 207 | { | |||
| 208 | int count; | |||
| 209 | char *buf; | |||
| 210 | ||||
| 0 | 0 | - | 211 | while (bcount) { |
| 0 | 0 | - | 212 | if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) { |
| 213 | printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n"); | |||
| 214 | idescsi_output_zeros (drive, bcount); | |||
| 0 | - | 215 | return; | |
| 216 | } | |||
| 217 | count = min(pc->sg->length - pc->b_count, bcount); | |||
| 0 | 0 | - | 218 | if (PageHighMem(pc->sg->page)) { |
| 219 | unsigned long flags; | |||
| 220 | ||||
| 221 | local_irq_save(flags); | |||
| 221 | do | |||
| 0 | 0 | - | 221 | do-while (0) |
| 0 | 0 | - | 221 | do-while (0) |
| 222 | buf = kmap_atomic(pc->sg->page, KM_IRQ0) + | |||
| 223 | pc->sg->offset; | |||
| 224 | drive->hwif->atapi_output_bytes(drive, | |||
| 225 | buf + pc->b_count, count); | |||
| 226 | kunmap_atomic(buf - pc->sg->offset, KM_IRQ0); | |||
| 0 | 0 | - | 226 | do-while (0) |
| 227 | local_irq_restore(flags); | |||
| 228 | } else { | |||
| 229 | buf = page_address(pc->sg->page) + pc->sg->offset; | |||
| 230 | drive->hwif->atapi_output_bytes(drive, | |||
| 231 | buf + pc->b_count, count); | |||
| 232 | } | |||
| 233 | bcount -= count; pc->b_count += count; | |||
| 0 | 0 | - | 234 | if (pc->b_count == pc->sg->length) { |
| 235 | pc->sg++; | |||
| 236 | pc->b_count = 0; | |||
| 237 | } | |||
| 238 | } | |||
| 239 | } | |||
| 240 | ||||
| 241 | /* | |||
| 242 | * Most of the SCSI commands are supported directly by ATAPI devices. | |||
| 243 | * idescsi_transform_pc handles the few exceptions. | |||
| 244 | */ | |||
| 0 | 0 | - | 245 | static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc) |
| 246 | { | |||
| 247 | u8 *c = pc->c, *scsi_buf = pc->buffer, *sc = pc->scsi_cmd->cmnd; | |||
| 248 | char *atapi_buf; | |||
| 249 | ||||
| 0 | 0 | - | 250 | if (!test_bit(PC_TRANSFORM, &pc->flags)) |
| 0 | 0 | - | 250 | ternary-?: __builtin_constant_p ( 2 ) |
| 0 | - | 251 | return; | |
| 0 | 0 | - | 252 | if (drive->media == ide_cdrom || drive->media == ide_optical) { |
| 0 | - | 252 | T || _ | |
| 0 | - | 252 | F || T | |
| 0 | - | 252 | F || F | |
| 0 | 0 | - | 253 | if (c[0] == READ_6 || c[0] == WRITE_6) { |
| 0 | - | 253 | T || _ | |
| 0 | - | 253 | F || T | |
| 0 | - | 253 | F || F | |
| 254 | c[8] = c[4]; c[5] = c[3]; c[4] = c[2]; | |||
| 255 | c[3] = c[1] & 0x1f; c[2] = 0; c[1] &= 0xe0; | |||
| 256 | c[0] += (READ_10 - READ_6); | |||
| 257 | } | |||
| 0 | 0 | - | 258 | if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) { |
| 0 | - | 258 | T || _ | |
| 0 | - | 258 | F || T | |
| 0 | - | 258 | F || F | |
| 259 | unsigned short new_len; | |||
| 0 | 0 | - | 260 | if (!scsi_buf) |
| 0 | - | 261 | return; | |
| 0 | 0 | - | 262 | if ((atapi_buf = kmalloc(pc->buffer_size + 4, GFP_ATOMIC)) == NULL) |
| 0 | - | 263 | return; | |
| 264 | memset(atapi_buf, 0, pc->buffer_size + 4); | |||
| 265 | memset (c, 0, 12); | |||
| 266 | c[0] = sc[0] | 0x40; | |||
| 267 | c[1] = sc[1]; | |||
| 268 | c[2] = sc[2]; | |||
| 269 | new_len = sc[4] + 4; | |||
| 270 | c[8] = new_len; | |||
| 271 | c[7] = new_len >> 8; | |||
| 272 | c[9] = sc[5]; | |||
| 0 | 0 | - | 273 | if (c[0] == MODE_SELECT_10) { |
| 274 | atapi_buf[1] = scsi_buf[0]; /* Mode data length */ | |||
| 275 | atapi_buf[2] = scsi_buf[1]; /* Medium type */ | |||
| 276 | atapi_buf[3] = scsi_buf[2]; /* Device specific parameter */ | |||
| 277 | atapi_buf[7] = scsi_buf[3]; /* Block descriptor length */ | |||
| 278 | memcpy(atapi_buf + 8, scsi_buf + 4, pc->buffer_size - 4); | |||
| 279 | } | |||
| 280 | pc->buffer = atapi_buf; | |||
| 281 | pc->request_transfer += 4; | |||
| 282 | pc->buffer_size += 4; | |||
| 283 | } | |||
| 284 | } | |||
| 285 | } | |||
| 286 | ||||
| 0 | 0 | - | 287 | static inline void idescsi_transform_pc2 (ide_drive_t *drive, idescsi_pc_t *pc) |
| 288 | { | |||
| 289 | u8 *atapi_buf = pc->buffer; | |||
| 290 | u8 *sc = pc->scsi_cmd->cmnd; | |||
| 291 | u8 *scsi_buf = pc->scsi_cmd->request_buffer; | |||
| 292 | ||||
| 0 | 0 | - | 293 | if (!test_bit(PC_TRANSFORM, &pc->flags)) |
| 0 | 0 | - | 293 | ternary-?: __builtin_constant_p ( 2 ) |
| 0 | - | 294 | return; | |
| 0 | 0 | - | 295 | if (drive->media == ide_cdrom || drive->media == ide_optical) { |
| 0 | - | 295 | T || _ | |
| 0 | - | 295 | F || T | |
| 0 | - | 295 | F || F | |
| 0 | 0 | - | 296 | if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) { |
| 0 | - | 296 | T && T | |
| 0 | - | 296 | T && F | |
| 0 | - | 296 | F && _ | |
| 297 | scsi_buf[0] = atapi_buf[1]; /* Mode data length */ | |||
| 298 | scsi_buf[1] = atapi_buf[2]; /* Medium type */ | |||
| 299 | scsi_buf[2] = atapi_buf[3]; /* Device specific parameter */ | |||
| 300 | scsi_buf[3] = atapi_buf[7]; /* Block descriptor length */ | |||
| 301 | memcpy(scsi_buf + 4, atapi_buf + 8, pc->request_transfer - 8); | |||
| 302 | } | |||
| 0 | 0 | - | 303 | if (pc->c[0] == INQUIRY) { |
| 304 | scsi_buf[2] |= 2; /* ansi_revision */ | |||
| 305 | scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2; /* response data format */ | |||
| 306 | } | |||
| 307 | } | |||
| 0 | 0 | - | 308 | if (atapi_buf && atapi_buf != scsi_buf) |
| 0 | - | 308 | T && T | |
| 0 | - | 308 | T && F | |
| 0 | - | 308 | F && _ | |
| 309 | kfree(atapi_buf); | |||
| 310 | } | |||
| 311 | ||||
| 0 | 0 | - | 312 | static void hexdump(u8 *x, int len) |
| 313 | { | |||
| 314 | int i; | |||
| 315 | ||||
| 316 | printk("[ "); | |||
| 0 | 0 | - | 317 | for (i = 0; i < len; i++) |
| 318 | printk("%x ", x[i]); | |||
| 319 | printk("]\n"); | |||
| 320 | } | |||
| 321 | ||||
| 0 | 0 | - | 322 | static int idescsi_check_condition(ide_drive_t *drive, struct request *failed_command) |
| 323 | { | |||
| 324 | idescsi_scsi_t *scsi = drive_to_idescsi(drive); | |||
| 325 | idescsi_pc_t *pc; | |||
| 326 | struct request *rq; | |||
| 327 | u8 *buf; | |||
| 328 | ||||
| 329 | /* stuff a sense request in front of our current request */ | |||
| 330 | pc = kmalloc (sizeof (idescsi_pc_t), GFP_ATOMIC); | |||
| 331 | rq = kmalloc (sizeof (struct request), GFP_ATOMIC); | |||
| 332 | buf = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_ATOMIC); | |||
| 0 | 0 | - | 333 | if (pc == NULL || rq == NULL || buf == NULL) { |
| 0 | - | 333 | T || _ || _ | |
| 0 | - | 333 | F || T || _ | |
| 0 | - | 333 | F || F || T | |
| 0 | - | 333 | F || F || F | |
| 334 | kfree(buf); | |||
| 335 | kfree(rq); | |||
| 336 | kfree(pc); | |||
| 0 | - | 337 | return -ENOMEM; | |
| 338 | } | |||
| 339 | memset (pc, 0, sizeof (idescsi_pc_t)); | |||
| 340 | memset (buf, 0, SCSI_SENSE_BUFFERSIZE); | |||
| 341 | ide_init_drive_cmd(rq); | |||
| 342 | rq->special = (char *) pc; | |||
| 343 | pc->rq = rq; | |||
| 344 | pc->buffer = buf; | |||
| 345 | pc->c[0] = REQUEST_SENSE; | |||
| 346 | pc->c[4] = pc->request_transfer = pc->buffer_size = SCSI_SENSE_BUFFERSIZE; | |||
| 347 | rq->flags = REQ_SENSE; | |||
| 348 | pc->timeout = jiffies + WAIT_READY; | |||
| 349 | /* NOTE! Save the failed packet command in "rq->buffer" */ | |||
| 350 | rq->buffer = (void *) failed_command->special; | |||
| 351 | pc->scsi_cmd = ((idescsi_pc_t *) failed_command->special)->scsi_cmd; | |||
| 0 | 0 | - | 352 | if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) { |
| 0 | 0 | - | 352 | ternary-?: __builtin_constant_p ( 0 ) |
| 353 | printk ("ide-scsi: %s: queue cmd = ", drive->name); | |||
| 354 | hexdump(pc->c, 6); | |||
| 355 | } | |||
| 356 | rq->rq_disk = scsi->disk; | |||
| 0 | - | 357 | return ide_do_drive_cmd(drive, rq, ide_preempt); | |
| 358 | } | |||
| 359 | ||||
| 360 | static int idescsi_end_request(ide_drive_t *, int, int); | |||
| 361 | ||||
| 362 | static ide_startstop_t | |||
| 0 | 0 | - | 363 | idescsi_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err) |
| 364 | { | |||
| 0 | 0 | - | 365 | if (HWIF(drive)->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) |
| 366 | /* force an abort */ | |||
| 367 | HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); | |||
| 368 | ||||
| 369 | rq->errors++; | |||
| 370 | ||||
| 371 | idescsi_end_request(drive, 0, 0); | |||
| 372 | ||||
| 0 | - | 373 | return ide_stopped; | |
| 374 | } | |||
| 375 | ||||
| 376 | static ide_startstop_t | |||
| 0 | 0 | - | 377 | idescsi_atapi_abort(ide_drive_t *drive, struct request *rq) |
| 378 | { | |||
| 379 | #if IDESCSI_DEBUG_LOG | |||
| 380 | printk(KERN_WARNING "idescsi_atapi_abort called for %lu\n", | |||
| 381 | ((idescsi_pc_t *) rq->special)->scsi_cmd->serial_number); | |||
| 382 | #endif | |||
| 383 | rq->errors |= ERROR_MAX; | |||
| 384 | ||||
| 385 | idescsi_end_request(drive, 0, 0); | |||
| 386 | ||||
| 0 | - | 387 | return ide_stopped; | |
| 388 | } | |||
| 389 | ||||
| 0 | 0 | - | 390 | static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs) |
| 391 | { | |||
| 392 | idescsi_scsi_t *scsi = drive_to_idescsi(drive); | |||
| 393 | struct request *rq = HWGROUP(drive)->rq; | |||
| 394 | idescsi_pc_t *pc = (idescsi_pc_t *) rq->special; | |||
| 395 | int log = test_bit(IDESCSI_LOG_CMD, &scsi->log); | |||
| 0 | 0 | - | 395 | ternary-?: __builtin_constant_p ( 0 ) |
| 396 | struct Scsi_Host *host; | |||
| 397 | u8 *scsi_buf; | |||
| 398 | int errors = rq->errors; | |||
| 399 | unsigned long flags; | |||
| 400 | ||||
| 0 | 0 | - | 401 | if (!(rq->flags & (REQ_SPECIAL|REQ_SENSE))) { |
| 402 | ide_end_request(drive, uptodate, nrsecs); | |||
| 0 | - | 403 | return 0; | |
| 404 | } | |||
| 405 | ide_end_drive_cmd (drive, 0, 0); | |||
| 0 | 0 | - | 406 | if (rq->flags & REQ_SENSE) { |
| 407 | idescsi_pc_t *opc = (idescsi_pc_t *) rq->buffer; | |||
| 0 | 0 | - | 408 | if (log) { |
| 409 | printk ("ide-scsi: %s: wrap up check %lu, rst = ", drive->name, opc->scsi_cmd->serial_number); | |||
| 410 | hexdump(pc->buffer,16); | |||
| 411 | } | |||
| 412 | memcpy((void *) opc->scsi_cmd->sense_buffer, pc->buffer, SCSI_SENSE_BUFFERSIZE); | |||
| 413 | kfree(pc->buffer); | |||
| 414 | kfree(pc); | |||
| 415 | kfree(rq); | |||
| 416 | pc = opc; | |||
| 417 | rq = pc->rq; | |||
| 418 | pc->scsi_cmd->result = (CHECK_CONDITION << 1) | | |||
| 419 | ((test_bit(PC_TIMEDOUT, &pc->flags)?DID_TIME_OUT:DID_OK) << 16); | |||
| 0 | 0 | - | 419 | ternary-?: __builtin_constant_p ( 3 ) |
| 0 | 0 | - | 419 | ternary-?: ( __builtin_constant_p ( 3 ) ? co.. |
| 0 | 0 | - | 420 | } else if (test_bit(PC_TIMEDOUT, &pc->flags)) { |
| 0 | 0 | - | 420 | ternary-?: __builtin_constant_p ( 3 ) |
| 0 | 0 | - | 421 | if (log) |
| 422 | printk (KERN_WARNING "ide-scsi: %s: timed out for %lu\n", | |||
| 423 | drive->name, pc->scsi_cmd->serial_number); | |||
| 424 | pc->scsi_cmd->result = DID_TIME_OUT << 16; | |||
| 0 | 0 | - | 425 | } else if (errors >= ERROR_MAX) { |
| 426 | pc->scsi_cmd->result = DID_ERROR << 16; | |||
| 0 | 0 | - | 427 | if (log) |
| 428 | printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number); | |||
| 0 | 0 | - | 429 | } else if (errors) { |
| 0 | 0 | - | 430 | if (log) |
| 431 | printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number); | |||
| 0 | 0 | - | 432 | if (!idescsi_check_condition(drive, rq)) |
| 433 | /* we started a request sense, so we'll be back, exit for now */ | |||
| 0 | - | 434 | return 0; | |
| 435 | pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16); | |||
| 436 | } else { | |||
| 437 | pc->scsi_cmd->result = DID_OK << 16; | |||
| 438 | idescsi_transform_pc2 (drive, pc); | |||
| 0 | 0 | - | 439 | if (log) { |
| 440 | printk ("ide-scsi: %s: suc %lu", drive->name, pc->scsi_cmd->serial_number); | |||
| 0 | 0 | - | 441 | if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) { |
| 0 | - | 441 | !(F) && T && T && T | |
| 0 | - | 441 | !(T) && _ && _ && _ | |
| 0 | - | 441 | !(F) && T && T && F | |
| 0 | - | 441 | !(F) && T && F && _ | |
| 0 | - | 441 | !(F) && F && _ && _ | |
| 0 | 0 | - | 441 | ternary-?: __builtin_constant_p ( 1 ) |
| 442 | printk(", rst = "); | |||
| 443 | scsi_buf = pc->scsi_cmd->request_buffer; | |||
| 444 | hexdump(scsi_buf, min_t(unsigned, 16, pc->scsi_cmd->request_bufflen)); | |||
| 445 | } else printk("\n"); | |||
| 446 | } | |||
| 447 | } | |||
| 448 | host = pc->scsi_cmd->device->host; | |||
| 449 | spin_lock_irqsave(host->host_lock, flags); | |||
| 449 | do | |||
| 449 | do | |||
| 0 | 0 | - | 449 | do-while (0) |
| 0 | 0 | - | 449 | do-while (0) |
| 449 | do | |||
| 449 | do | |||
| 0 | 0 | - | 449 | do-while (0) |
| 0 | 0 | - | 449 | do-while (0) |
| 0 | 0 | - | 449 | do-while (0) |
| 450 | pc->done(pc->scsi_cmd); | |||
| 451 | spin_unlock_irqrestore(host->host_lock, flags); | |||
|   | ||||