| Bartlomiej Zolnierkiewicz | 594c16d | 2008-07-15 21:21:58 +0200 | [diff] [blame] | 1 | /* | 
|  | 2 | * ATAPI support. | 
|  | 3 | */ | 
|  | 4 |  | 
|  | 5 | #include <linux/kernel.h> | 
|  | 6 | #include <linux/delay.h> | 
|  | 7 | #include <linux/ide.h> | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 8 | #include <scsi/scsi.h> | 
|  | 9 |  | 
|  | 10 | #ifdef DEBUG | 
|  | 11 | #define debug_log(fmt, args...) \ | 
|  | 12 | printk(KERN_INFO "ide: " fmt, ## args) | 
|  | 13 | #else | 
|  | 14 | #define debug_log(fmt, args...) do {} while (0) | 
|  | 15 | #endif | 
|  | 16 |  | 
| Bartlomiej Zolnierkiewicz | 51509ee | 2008-10-10 22:39:34 +0200 | [diff] [blame] | 17 | /* | 
|  | 18 | * Check whether we can support a device, | 
|  | 19 | * based on the ATAPI IDENTIFY command results. | 
|  | 20 | */ | 
|  | 21 | int ide_check_atapi_device(ide_drive_t *drive, const char *s) | 
|  | 22 | { | 
|  | 23 | u16 *id = drive->id; | 
|  | 24 | u8 gcw[2], protocol, device_type, removable, drq_type, packet_size; | 
|  | 25 |  | 
|  | 26 | *((u16 *)&gcw) = id[ATA_ID_CONFIG]; | 
|  | 27 |  | 
|  | 28 | protocol    = (gcw[1] & 0xC0) >> 6; | 
|  | 29 | device_type =  gcw[1] & 0x1F; | 
|  | 30 | removable   = (gcw[0] & 0x80) >> 7; | 
|  | 31 | drq_type    = (gcw[0] & 0x60) >> 5; | 
|  | 32 | packet_size =  gcw[0] & 0x03; | 
|  | 33 |  | 
|  | 34 | #ifdef CONFIG_PPC | 
|  | 35 | /* kludge for Apple PowerBook internal zip */ | 
|  | 36 | if (drive->media == ide_floppy && device_type == 5 && | 
|  | 37 | !strstr((char *)&id[ATA_ID_PROD], "CD-ROM") && | 
|  | 38 | strstr((char *)&id[ATA_ID_PROD], "ZIP")) | 
|  | 39 | device_type = 0; | 
|  | 40 | #endif | 
|  | 41 |  | 
|  | 42 | if (protocol != 2) | 
|  | 43 | printk(KERN_ERR "%s: %s: protocol (0x%02x) is not ATAPI\n", | 
|  | 44 | s, drive->name, protocol); | 
|  | 45 | else if ((drive->media == ide_floppy && device_type != 0) || | 
|  | 46 | (drive->media == ide_tape && device_type != 1)) | 
|  | 47 | printk(KERN_ERR "%s: %s: invalid device type (0x%02x)\n", | 
|  | 48 | s, drive->name, device_type); | 
|  | 49 | else if (removable == 0) | 
|  | 50 | printk(KERN_ERR "%s: %s: the removable flag is not set\n", | 
|  | 51 | s, drive->name); | 
|  | 52 | else if (drive->media == ide_floppy && drq_type == 3) | 
|  | 53 | printk(KERN_ERR "%s: %s: sorry, DRQ type (0x%02x) not " | 
|  | 54 | "supported\n", s, drive->name, drq_type); | 
|  | 55 | else if (packet_size != 0) | 
|  | 56 | printk(KERN_ERR "%s: %s: packet size (0x%02x) is not 12 " | 
|  | 57 | "bytes\n", s, drive->name, packet_size); | 
|  | 58 | else | 
|  | 59 | return 1; | 
|  | 60 | return 0; | 
|  | 61 | } | 
|  | 62 | EXPORT_SYMBOL_GPL(ide_check_atapi_device); | 
|  | 63 |  | 
| Bartlomiej Zolnierkiewicz | acaa0f5 | 2008-10-10 22:39:36 +0200 | [diff] [blame] | 64 | /* PIO data transfer routine using the scatter gather table. */ | 
|  | 65 | int ide_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, | 
|  | 66 | unsigned int bcount, int write) | 
|  | 67 | { | 
|  | 68 | ide_hwif_t *hwif = drive->hwif; | 
|  | 69 | const struct ide_tp_ops *tp_ops = hwif->tp_ops; | 
|  | 70 | xfer_func_t *xf = write ? tp_ops->output_data : tp_ops->input_data; | 
|  | 71 | struct scatterlist *sg = pc->sg; | 
|  | 72 | char *buf; | 
|  | 73 | int count, done = 0; | 
|  | 74 |  | 
|  | 75 | while (bcount) { | 
|  | 76 | count = min(sg->length - pc->b_count, bcount); | 
|  | 77 |  | 
|  | 78 | if (PageHighMem(sg_page(sg))) { | 
|  | 79 | unsigned long flags; | 
|  | 80 |  | 
|  | 81 | local_irq_save(flags); | 
|  | 82 | buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; | 
|  | 83 | xf(drive, NULL, buf + pc->b_count, count); | 
|  | 84 | kunmap_atomic(buf - sg->offset, KM_IRQ0); | 
|  | 85 | local_irq_restore(flags); | 
|  | 86 | } else { | 
|  | 87 | buf = sg_virt(sg); | 
|  | 88 | xf(drive, NULL, buf + pc->b_count, count); | 
|  | 89 | } | 
|  | 90 |  | 
|  | 91 | bcount -= count; | 
|  | 92 | pc->b_count += count; | 
|  | 93 | done += count; | 
|  | 94 |  | 
|  | 95 | if (pc->b_count == sg->length) { | 
|  | 96 | if (!--pc->sg_cnt) | 
|  | 97 | break; | 
|  | 98 | pc->sg = sg = sg_next(sg); | 
|  | 99 | pc->b_count = 0; | 
|  | 100 | } | 
|  | 101 | } | 
|  | 102 |  | 
|  | 103 | if (bcount) { | 
|  | 104 | printk(KERN_ERR "%s: %d leftover bytes, %s\n", drive->name, | 
|  | 105 | bcount, write ? "padding with zeros" | 
|  | 106 | : "discarding data"); | 
|  | 107 | ide_pad_transfer(drive, write, bcount); | 
|  | 108 | } | 
|  | 109 |  | 
|  | 110 | return done; | 
|  | 111 | } | 
|  | 112 | EXPORT_SYMBOL_GPL(ide_io_buffers); | 
|  | 113 |  | 
| Bartlomiej Zolnierkiewicz | 7bf7420 | 2008-10-10 22:39:37 +0200 | [diff] [blame] | 114 | void ide_init_pc(struct ide_atapi_pc *pc) | 
|  | 115 | { | 
|  | 116 | memset(pc, 0, sizeof(*pc)); | 
|  | 117 | pc->buf = pc->pc_buf; | 
|  | 118 | pc->buf_size = IDE_PC_BUFFER_SIZE; | 
|  | 119 | } | 
|  | 120 | EXPORT_SYMBOL_GPL(ide_init_pc); | 
|  | 121 |  | 
| Bartlomiej Zolnierkiewicz | 7645c15 | 2008-10-10 22:39:37 +0200 | [diff] [blame] | 122 | /* | 
|  | 123 | * Generate a new packet command request in front of the request queue, before | 
|  | 124 | * the current request, so that it will be processed immediately, on the next | 
|  | 125 | * pass through the driver. | 
|  | 126 | */ | 
| Bartlomiej Zolnierkiewicz | 6b0da28 | 2008-10-13 21:39:32 +0200 | [diff] [blame] | 127 | static void ide_queue_pc_head(ide_drive_t *drive, struct gendisk *disk, | 
|  | 128 | struct ide_atapi_pc *pc, struct request *rq) | 
| Bartlomiej Zolnierkiewicz | 7645c15 | 2008-10-10 22:39:37 +0200 | [diff] [blame] | 129 | { | 
|  | 130 | blk_rq_init(NULL, rq); | 
|  | 131 | rq->cmd_type = REQ_TYPE_SPECIAL; | 
|  | 132 | rq->cmd_flags |= REQ_PREEMPT; | 
|  | 133 | rq->buffer = (char *)pc; | 
|  | 134 | rq->rq_disk = disk; | 
|  | 135 | memcpy(rq->cmd, pc->c, 12); | 
|  | 136 | if (drive->media == ide_tape) | 
|  | 137 | rq->cmd[13] = REQ_IDETAPE_PC1; | 
|  | 138 | ide_do_drive_cmd(drive, rq); | 
|  | 139 | } | 
| Bartlomiej Zolnierkiewicz | 7645c15 | 2008-10-10 22:39:37 +0200 | [diff] [blame] | 140 |  | 
| Bartlomiej Zolnierkiewicz | 2ac07d9 | 2008-10-10 22:39:38 +0200 | [diff] [blame] | 141 | /* | 
|  | 142 | * Add a special packet command request to the tail of the request queue, | 
|  | 143 | * and wait for it to be serviced. | 
|  | 144 | */ | 
|  | 145 | int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk, | 
|  | 146 | struct ide_atapi_pc *pc) | 
|  | 147 | { | 
|  | 148 | struct request *rq; | 
|  | 149 | int error; | 
|  | 150 |  | 
|  | 151 | rq = blk_get_request(drive->queue, READ, __GFP_WAIT); | 
|  | 152 | rq->cmd_type = REQ_TYPE_SPECIAL; | 
|  | 153 | rq->buffer = (char *)pc; | 
|  | 154 | memcpy(rq->cmd, pc->c, 12); | 
|  | 155 | if (drive->media == ide_tape) | 
|  | 156 | rq->cmd[13] = REQ_IDETAPE_PC1; | 
|  | 157 | error = blk_execute_rq(drive->queue, disk, rq, 0); | 
|  | 158 | blk_put_request(rq); | 
|  | 159 |  | 
|  | 160 | return error; | 
|  | 161 | } | 
|  | 162 | EXPORT_SYMBOL_GPL(ide_queue_pc_tail); | 
|  | 163 |  | 
| Bartlomiej Zolnierkiewicz | de699ad | 2008-10-10 22:39:39 +0200 | [diff] [blame] | 164 | int ide_do_test_unit_ready(ide_drive_t *drive, struct gendisk *disk) | 
|  | 165 | { | 
|  | 166 | struct ide_atapi_pc pc; | 
|  | 167 |  | 
|  | 168 | ide_init_pc(&pc); | 
|  | 169 | pc.c[0] = TEST_UNIT_READY; | 
|  | 170 |  | 
|  | 171 | return ide_queue_pc_tail(drive, disk, &pc); | 
|  | 172 | } | 
|  | 173 | EXPORT_SYMBOL_GPL(ide_do_test_unit_ready); | 
|  | 174 |  | 
| Bartlomiej Zolnierkiewicz | 0c8a6c7 | 2008-10-10 22:39:39 +0200 | [diff] [blame] | 175 | int ide_do_start_stop(ide_drive_t *drive, struct gendisk *disk, int start) | 
|  | 176 | { | 
|  | 177 | struct ide_atapi_pc pc; | 
|  | 178 |  | 
|  | 179 | ide_init_pc(&pc); | 
|  | 180 | pc.c[0] = START_STOP; | 
|  | 181 | pc.c[4] = start; | 
|  | 182 |  | 
|  | 183 | if (drive->media == ide_tape) | 
|  | 184 | pc.flags |= PC_FLAG_WAIT_FOR_DSC; | 
|  | 185 |  | 
|  | 186 | return ide_queue_pc_tail(drive, disk, &pc); | 
|  | 187 | } | 
|  | 188 | EXPORT_SYMBOL_GPL(ide_do_start_stop); | 
|  | 189 |  | 
| Bartlomiej Zolnierkiewicz | 0578042 | 2008-10-10 22:39:38 +0200 | [diff] [blame] | 190 | int ide_set_media_lock(ide_drive_t *drive, struct gendisk *disk, int on) | 
|  | 191 | { | 
|  | 192 | struct ide_atapi_pc pc; | 
|  | 193 |  | 
| Bartlomiej Zolnierkiewicz | 42619d3 | 2008-10-17 18:09:11 +0200 | [diff] [blame] | 194 | if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0) | 
| Bartlomiej Zolnierkiewicz | 0578042 | 2008-10-10 22:39:38 +0200 | [diff] [blame] | 195 | return 0; | 
|  | 196 |  | 
|  | 197 | ide_init_pc(&pc); | 
|  | 198 | pc.c[0] = ALLOW_MEDIUM_REMOVAL; | 
|  | 199 | pc.c[4] = on; | 
|  | 200 |  | 
|  | 201 | return ide_queue_pc_tail(drive, disk, &pc); | 
|  | 202 | } | 
|  | 203 | EXPORT_SYMBOL_GPL(ide_set_media_lock); | 
|  | 204 |  | 
| Bartlomiej Zolnierkiewicz | 6b0da28 | 2008-10-13 21:39:32 +0200 | [diff] [blame] | 205 | void ide_create_request_sense_cmd(ide_drive_t *drive, struct ide_atapi_pc *pc) | 
|  | 206 | { | 
|  | 207 | ide_init_pc(pc); | 
|  | 208 | pc->c[0] = REQUEST_SENSE; | 
|  | 209 | if (drive->media == ide_floppy) { | 
|  | 210 | pc->c[4] = 255; | 
|  | 211 | pc->req_xfer = 18; | 
|  | 212 | } else { | 
|  | 213 | pc->c[4] = 20; | 
|  | 214 | pc->req_xfer = 20; | 
|  | 215 | } | 
|  | 216 | } | 
|  | 217 | EXPORT_SYMBOL_GPL(ide_create_request_sense_cmd); | 
|  | 218 |  | 
|  | 219 | /* | 
|  | 220 | * Called when an error was detected during the last packet command. | 
|  | 221 | * We queue a request sense packet command in the head of the request list. | 
|  | 222 | */ | 
|  | 223 | void ide_retry_pc(ide_drive_t *drive, struct gendisk *disk) | 
|  | 224 | { | 
|  | 225 | struct request *rq = &drive->request_sense_rq; | 
|  | 226 | struct ide_atapi_pc *pc = &drive->request_sense_pc; | 
|  | 227 |  | 
|  | 228 | (void)ide_read_error(drive); | 
|  | 229 | ide_create_request_sense_cmd(drive, pc); | 
|  | 230 | if (drive->media == ide_tape) | 
|  | 231 | set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags); | 
|  | 232 | ide_queue_pc_head(drive, disk, pc, rq); | 
|  | 233 | } | 
|  | 234 | EXPORT_SYMBOL_GPL(ide_retry_pc); | 
|  | 235 |  | 
| Bartlomiej Zolnierkiewicz | 844b946 | 2008-10-13 21:39:31 +0200 | [diff] [blame] | 236 | int ide_scsi_expiry(ide_drive_t *drive) | 
|  | 237 | { | 
|  | 238 | struct ide_atapi_pc *pc = drive->pc; | 
|  | 239 |  | 
|  | 240 | debug_log("%s called for %lu at %lu\n", __func__, | 
|  | 241 | pc->scsi_cmd->serial_number, jiffies); | 
|  | 242 |  | 
|  | 243 | pc->flags |= PC_FLAG_TIMEDOUT; | 
|  | 244 |  | 
|  | 245 | return 0; /* we do not want the IDE subsystem to retry */ | 
|  | 246 | } | 
|  | 247 | EXPORT_SYMBOL_GPL(ide_scsi_expiry); | 
|  | 248 |  | 
| Bartlomiej Zolnierkiewicz | aa5d2de | 2008-10-13 21:39:32 +0200 | [diff] [blame] | 249 | /* | 
|  | 250 | * This is the usual interrupt handler which will be called during a packet | 
|  | 251 | * command.  We will transfer some of the data (as requested by the drive) | 
|  | 252 | * and will re-point interrupt handler to us. | 
|  | 253 | */ | 
|  | 254 | static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 255 | { | 
| Bartlomiej Zolnierkiewicz | 2b9efba | 2008-10-13 21:39:31 +0200 | [diff] [blame] | 256 | struct ide_atapi_pc *pc = drive->pc; | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 257 | ide_hwif_t *hwif = drive->hwif; | 
| Borislav Petkov | 8fccf89 | 2008-07-23 19:56:01 +0200 | [diff] [blame] | 258 | struct request *rq = hwif->hwgroup->rq; | 
| Bartlomiej Zolnierkiewicz | 374e042 | 2008-07-23 19:55:56 +0200 | [diff] [blame] | 259 | const struct ide_tp_ops *tp_ops = hwif->tp_ops; | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 260 | xfer_func_t *xferfunc; | 
| Bartlomiej Zolnierkiewicz | 844b946 | 2008-10-13 21:39:31 +0200 | [diff] [blame] | 261 | ide_expiry_t *expiry; | 
|  | 262 | unsigned int timeout, temp; | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 263 | u16 bcount; | 
| Bartlomiej Zolnierkiewicz | 97100fc | 2008-10-13 21:39:36 +0200 | [diff] [blame] | 264 | u8 stat, ireason, scsi = !!(drive->dev_flags & IDE_DFLAG_SCSI), dsc = 0; | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 265 |  | 
|  | 266 | debug_log("Enter %s - interrupt handler\n", __func__); | 
|  | 267 |  | 
| Bartlomiej Zolnierkiewicz | 844b946 | 2008-10-13 21:39:31 +0200 | [diff] [blame] | 268 | if (scsi) { | 
|  | 269 | timeout = ide_scsi_get_timeout(pc); | 
|  | 270 | expiry = ide_scsi_expiry; | 
|  | 271 | } else { | 
|  | 272 | timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD | 
|  | 273 | : WAIT_TAPE_CMD; | 
|  | 274 | expiry = NULL; | 
|  | 275 | } | 
|  | 276 |  | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 277 | if (pc->flags & PC_FLAG_TIMEDOUT) { | 
| Bartlomiej Zolnierkiewicz | b14c721 | 2008-10-13 21:39:30 +0200 | [diff] [blame] | 278 | drive->pc_callback(drive, 0); | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 279 | return ide_stopped; | 
|  | 280 | } | 
|  | 281 |  | 
|  | 282 | /* Clear the interrupt */ | 
| Bartlomiej Zolnierkiewicz | 374e042 | 2008-07-23 19:55:56 +0200 | [diff] [blame] | 283 | stat = tp_ops->read_status(hwif); | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 284 |  | 
|  | 285 | if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) { | 
|  | 286 | if (hwif->dma_ops->dma_end(drive) || | 
| Bartlomiej Zolnierkiewicz | 3a7d248 | 2008-10-10 22:39:21 +0200 | [diff] [blame] | 287 | (drive->media == ide_tape && !scsi && (stat & ATA_ERR))) { | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 288 | if (drive->media == ide_floppy && !scsi) | 
|  | 289 | printk(KERN_ERR "%s: DMA %s error\n", | 
|  | 290 | drive->name, rq_data_dir(pc->rq) | 
|  | 291 | ? "write" : "read"); | 
|  | 292 | pc->flags |= PC_FLAG_DMA_ERROR; | 
|  | 293 | } else { | 
|  | 294 | pc->xferred = pc->req_xfer; | 
| Bartlomiej Zolnierkiewicz | 85e3903 | 2008-10-13 21:39:32 +0200 | [diff] [blame] | 295 | if (drive->pc_update_buffers) | 
|  | 296 | drive->pc_update_buffers(drive, pc); | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 297 | } | 
|  | 298 | debug_log("%s: DMA finished\n", drive->name); | 
|  | 299 | } | 
|  | 300 |  | 
|  | 301 | /* No more interrupts */ | 
| Bartlomiej Zolnierkiewicz | 3a7d248 | 2008-10-10 22:39:21 +0200 | [diff] [blame] | 302 | if ((stat & ATA_DRQ) == 0) { | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 303 | debug_log("Packet command completed, %d bytes transferred\n", | 
|  | 304 | pc->xferred); | 
|  | 305 |  | 
|  | 306 | pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS; | 
|  | 307 |  | 
|  | 308 | local_irq_enable_in_hardirq(); | 
|  | 309 |  | 
|  | 310 | if (drive->media == ide_tape && !scsi && | 
| Bartlomiej Zolnierkiewicz | 3a7d248 | 2008-10-10 22:39:21 +0200 | [diff] [blame] | 311 | (stat & ATA_ERR) && rq->cmd[0] == REQUEST_SENSE) | 
|  | 312 | stat &= ~ATA_ERR; | 
| Borislav Petkov | 8fccf89 | 2008-07-23 19:56:01 +0200 | [diff] [blame] | 313 |  | 
| Bartlomiej Zolnierkiewicz | 3a7d248 | 2008-10-10 22:39:21 +0200 | [diff] [blame] | 314 | if ((stat & ATA_ERR) || (pc->flags & PC_FLAG_DMA_ERROR)) { | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 315 | /* Error detected */ | 
|  | 316 | debug_log("%s: I/O error\n", drive->name); | 
|  | 317 |  | 
|  | 318 | if (drive->media != ide_tape || scsi) { | 
|  | 319 | pc->rq->errors++; | 
|  | 320 | if (scsi) | 
|  | 321 | goto cmd_finished; | 
|  | 322 | } | 
|  | 323 |  | 
| Borislav Petkov | 8fccf89 | 2008-07-23 19:56:01 +0200 | [diff] [blame] | 324 | if (rq->cmd[0] == REQUEST_SENSE) { | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 325 | printk(KERN_ERR "%s: I/O error in request sense" | 
|  | 326 | " command\n", drive->name); | 
|  | 327 | return ide_do_reset(drive); | 
|  | 328 | } | 
|  | 329 |  | 
| Borislav Petkov | 8fccf89 | 2008-07-23 19:56:01 +0200 | [diff] [blame] | 330 | debug_log("[cmd %x]: check condition\n", rq->cmd[0]); | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 331 |  | 
|  | 332 | /* Retry operation */ | 
| Bartlomiej Zolnierkiewicz | 6b0da28 | 2008-10-13 21:39:32 +0200 | [diff] [blame] | 333 | ide_retry_pc(drive, rq->rq_disk); | 
| Borislav Petkov | 8fccf89 | 2008-07-23 19:56:01 +0200 | [diff] [blame] | 334 |  | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 335 | /* queued, but not started */ | 
|  | 336 | return ide_stopped; | 
|  | 337 | } | 
|  | 338 | cmd_finished: | 
|  | 339 | pc->error = 0; | 
| Bartlomiej Zolnierkiewicz | b14c721 | 2008-10-13 21:39:30 +0200 | [diff] [blame] | 340 |  | 
|  | 341 | if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && (stat & ATA_DSC) == 0) | 
|  | 342 | dsc = 1; | 
| Borislav Petkov | 8fccf89 | 2008-07-23 19:56:01 +0200 | [diff] [blame] | 343 |  | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 344 | /* Command finished - Call the callback function */ | 
| Bartlomiej Zolnierkiewicz | b14c721 | 2008-10-13 21:39:30 +0200 | [diff] [blame] | 345 | drive->pc_callback(drive, dsc); | 
| Borislav Petkov | 8fccf89 | 2008-07-23 19:56:01 +0200 | [diff] [blame] | 346 |  | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 347 | return ide_stopped; | 
|  | 348 | } | 
|  | 349 |  | 
|  | 350 | if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) { | 
|  | 351 | pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS; | 
|  | 352 | printk(KERN_ERR "%s: The device wants to issue more interrupts " | 
|  | 353 | "in DMA mode\n", drive->name); | 
|  | 354 | ide_dma_off(drive); | 
|  | 355 | return ide_do_reset(drive); | 
|  | 356 | } | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 357 |  | 
| Bartlomiej Zolnierkiewicz | 1823649 | 2008-07-23 19:55:54 +0200 | [diff] [blame] | 358 | /* Get the number of bytes to transfer on this interrupt. */ | 
|  | 359 | ide_read_bcount_and_ireason(drive, &bcount, &ireason); | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 360 |  | 
| Bartlomiej Zolnierkiewicz | 3a7d248 | 2008-10-10 22:39:21 +0200 | [diff] [blame] | 361 | if (ireason & ATAPI_COD) { | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 362 | printk(KERN_ERR "%s: CoD != 0 in %s\n", drive->name, __func__); | 
|  | 363 | return ide_do_reset(drive); | 
|  | 364 | } | 
| Borislav Petkov | 8fccf89 | 2008-07-23 19:56:01 +0200 | [diff] [blame] | 365 |  | 
| Bartlomiej Zolnierkiewicz | 3a7d248 | 2008-10-10 22:39:21 +0200 | [diff] [blame] | 366 | if (((ireason & ATAPI_IO) == ATAPI_IO) == | 
|  | 367 | !!(pc->flags & PC_FLAG_WRITING)) { | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 368 | /* Hopefully, we will never get here */ | 
|  | 369 | printk(KERN_ERR "%s: We wanted to %s, but the device wants us " | 
|  | 370 | "to %s!\n", drive->name, | 
| Bartlomiej Zolnierkiewicz | 3a7d248 | 2008-10-10 22:39:21 +0200 | [diff] [blame] | 371 | (ireason & ATAPI_IO) ? "Write" : "Read", | 
|  | 372 | (ireason & ATAPI_IO) ? "Read" : "Write"); | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 373 | return ide_do_reset(drive); | 
|  | 374 | } | 
| Borislav Petkov | 8fccf89 | 2008-07-23 19:56:01 +0200 | [diff] [blame] | 375 |  | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 376 | if (!(pc->flags & PC_FLAG_WRITING)) { | 
|  | 377 | /* Reading - Check that we have enough space */ | 
|  | 378 | temp = pc->xferred + bcount; | 
|  | 379 | if (temp > pc->req_xfer) { | 
|  | 380 | if (temp > pc->buf_size) { | 
|  | 381 | printk(KERN_ERR "%s: The device wants to send " | 
|  | 382 | "us more data than expected - " | 
|  | 383 | "discarding data\n", | 
|  | 384 | drive->name); | 
|  | 385 | if (scsi) | 
|  | 386 | temp = pc->buf_size - pc->xferred; | 
|  | 387 | else | 
|  | 388 | temp = 0; | 
|  | 389 | if (temp) { | 
|  | 390 | if (pc->sg) | 
| Bartlomiej Zolnierkiewicz | 85e3903 | 2008-10-13 21:39:32 +0200 | [diff] [blame] | 391 | drive->pc_io_buffers(drive, pc, | 
|  | 392 | temp, 0); | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 393 | else | 
| Bartlomiej Zolnierkiewicz | 374e042 | 2008-07-23 19:55:56 +0200 | [diff] [blame] | 394 | tp_ops->input_data(drive, NULL, | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 395 | pc->cur_pos, temp); | 
|  | 396 | printk(KERN_ERR "%s: transferred %d of " | 
|  | 397 | "%d bytes\n", | 
|  | 398 | drive->name, | 
|  | 399 | temp, bcount); | 
|  | 400 | } | 
|  | 401 | pc->xferred += temp; | 
|  | 402 | pc->cur_pos += temp; | 
|  | 403 | ide_pad_transfer(drive, 0, bcount - temp); | 
| Bartlomiej Zolnierkiewicz | 844b946 | 2008-10-13 21:39:31 +0200 | [diff] [blame] | 404 | goto next_irq; | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 405 | } | 
|  | 406 | debug_log("The device wants to send us more data than " | 
|  | 407 | "expected - allowing transfer\n"); | 
|  | 408 | } | 
| Bartlomiej Zolnierkiewicz | 374e042 | 2008-07-23 19:55:56 +0200 | [diff] [blame] | 409 | xferfunc = tp_ops->input_data; | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 410 | } else | 
| Bartlomiej Zolnierkiewicz | 374e042 | 2008-07-23 19:55:56 +0200 | [diff] [blame] | 411 | xferfunc = tp_ops->output_data; | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 412 |  | 
|  | 413 | if ((drive->media == ide_floppy && !scsi && !pc->buf) || | 
|  | 414 | (drive->media == ide_tape && !scsi && pc->bh) || | 
| Bartlomiej Zolnierkiewicz | acaa0f5 | 2008-10-10 22:39:36 +0200 | [diff] [blame] | 415 | (scsi && pc->sg)) { | 
| Bartlomiej Zolnierkiewicz | 85e3903 | 2008-10-13 21:39:32 +0200 | [diff] [blame] | 416 | int done = drive->pc_io_buffers(drive, pc, bcount, | 
| Bartlomiej Zolnierkiewicz | acaa0f5 | 2008-10-10 22:39:36 +0200 | [diff] [blame] | 417 | !!(pc->flags & PC_FLAG_WRITING)); | 
|  | 418 |  | 
|  | 419 | /* FIXME: don't do partial completions */ | 
|  | 420 | if (drive->media == ide_floppy && !scsi) | 
|  | 421 | ide_end_request(drive, 1, done >> 9); | 
|  | 422 | } else | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 423 | xferfunc(drive, NULL, pc->cur_pos, bcount); | 
|  | 424 |  | 
|  | 425 | /* Update the current position */ | 
|  | 426 | pc->xferred += bcount; | 
|  | 427 | pc->cur_pos += bcount; | 
|  | 428 |  | 
|  | 429 | debug_log("[cmd %x] transferred %d bytes on that intr.\n", | 
| Borislav Petkov | 8fccf89 | 2008-07-23 19:56:01 +0200 | [diff] [blame] | 430 | rq->cmd[0], bcount); | 
| Bartlomiej Zolnierkiewicz | 844b946 | 2008-10-13 21:39:31 +0200 | [diff] [blame] | 431 | next_irq: | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 432 | /* And set the interrupt handler again */ | 
| Bartlomiej Zolnierkiewicz | aa5d2de | 2008-10-13 21:39:32 +0200 | [diff] [blame] | 433 | ide_set_handler(drive, ide_pc_intr, timeout, expiry); | 
| Bartlomiej Zolnierkiewicz | 646c0cb | 2008-07-15 21:22:03 +0200 | [diff] [blame] | 434 | return ide_started; | 
|  | 435 | } | 
| Bartlomiej Zolnierkiewicz | 594c16d | 2008-07-15 21:21:58 +0200 | [diff] [blame] | 436 |  | 
| Bartlomiej Zolnierkiewicz | 88a7210 | 2008-07-23 19:55:54 +0200 | [diff] [blame] | 437 | static u8 ide_read_ireason(ide_drive_t *drive) | 
|  | 438 | { | 
|  | 439 | ide_task_t task; | 
|  | 440 |  | 
|  | 441 | memset(&task, 0, sizeof(task)); | 
|  | 442 | task.tf_flags = IDE_TFLAG_IN_NSECT; | 
|  | 443 |  | 
| Bartlomiej Zolnierkiewicz | 374e042 | 2008-07-23 19:55:56 +0200 | [diff] [blame] | 444 | drive->hwif->tp_ops->tf_read(drive, &task); | 
| Bartlomiej Zolnierkiewicz | 88a7210 | 2008-07-23 19:55:54 +0200 | [diff] [blame] | 445 |  | 
|  | 446 | return task.tf.nsect & 3; | 
|  | 447 | } | 
|  | 448 |  | 
| Bartlomiej Zolnierkiewicz | 594c16d | 2008-07-15 21:21:58 +0200 | [diff] [blame] | 449 | static u8 ide_wait_ireason(ide_drive_t *drive, u8 ireason) | 
|  | 450 | { | 
| Bartlomiej Zolnierkiewicz | 594c16d | 2008-07-15 21:21:58 +0200 | [diff] [blame] | 451 | int retries = 100; | 
|  | 452 |  | 
| Bartlomiej Zolnierkiewicz | 3a7d248 | 2008-10-10 22:39:21 +0200 | [diff] [blame] | 453 | while (retries-- && ((ireason & ATAPI_COD) == 0 || | 
|  | 454 | (ireason & ATAPI_IO))) { | 
| Bartlomiej Zolnierkiewicz | 594c16d | 2008-07-15 21:21:58 +0200 | [diff] [blame] | 455 | printk(KERN_ERR "%s: (IO,CoD != (0,1) while issuing " | 
|  | 456 | "a packet command, retrying\n", drive->name); | 
|  | 457 | udelay(100); | 
| Bartlomiej Zolnierkiewicz | 88a7210 | 2008-07-23 19:55:54 +0200 | [diff] [blame] | 458 | ireason = ide_read_ireason(drive); | 
| Bartlomiej Zolnierkiewicz | 594c16d | 2008-07-15 21:21:58 +0200 | [diff] [blame] | 459 | if (retries == 0) { | 
|  | 460 | printk(KERN_ERR "%s: (IO,CoD != (0,1) while issuing " | 
|  | 461 | "a packet command, ignoring\n", | 
|  | 462 | drive->name); | 
| Bartlomiej Zolnierkiewicz | 3a7d248 | 2008-10-10 22:39:21 +0200 | [diff] [blame] | 463 | ireason |= ATAPI_COD; | 
|  | 464 | ireason &= ~ATAPI_IO; | 
| Bartlomiej Zolnierkiewicz | 594c16d | 2008-07-15 21:21:58 +0200 | [diff] [blame] | 465 | } | 
|  | 466 | } | 
|  | 467 |  | 
|  | 468 | return ireason; | 
|  | 469 | } | 
|  | 470 |  | 
| Bartlomiej Zolnierkiewicz | baf08f0 | 2008-10-13 21:39:32 +0200 | [diff] [blame] | 471 | static int ide_delayed_transfer_pc(ide_drive_t *drive) | 
|  | 472 | { | 
|  | 473 | /* Send the actual packet */ | 
|  | 474 | drive->hwif->tp_ops->output_data(drive, NULL, drive->pc->c, 12); | 
|  | 475 |  | 
|  | 476 | /* Timeout for the packet command */ | 
|  | 477 | return WAIT_FLOPPY_CMD; | 
|  | 478 | } | 
|  | 479 |  | 
|  | 480 | static ide_startstop_t ide_transfer_pc(ide_drive_t *drive) | 
| Bartlomiej Zolnierkiewicz | 594c16d | 2008-07-15 21:21:58 +0200 | [diff] [blame] | 481 | { | 
| Bartlomiej Zolnierkiewicz | 2b9efba | 2008-10-13 21:39:31 +0200 | [diff] [blame] | 482 | struct ide_atapi_pc *pc = drive->pc; | 
| Bartlomiej Zolnierkiewicz | 594c16d | 2008-07-15 21:21:58 +0200 | [diff] [blame] | 483 | ide_hwif_t *hwif = drive->hwif; | 
| Borislav Petkov | 8fccf89 | 2008-07-23 19:56:01 +0200 | [diff] [blame] | 484 | struct request *rq = hwif->hwgroup->rq; | 
| Bartlomiej Zolnierkiewicz | baf08f0 | 2008-10-13 21:39:32 +0200 | [diff] [blame] | 485 | ide_expiry_t *expiry; | 
|  | 486 | unsigned int timeout; | 
| Bartlomiej Zolnierkiewicz | 594c16d | 2008-07-15 21:21:58 +0200 | [diff] [blame] | 487 | ide_startstop_t startstop; | 
|  | 488 | u8 ireason; | 
|  | 489 |  | 
| Bartlomiej Zolnierkiewicz | 3a7d248 | 2008-10-10 22:39:21 +0200 | [diff] [blame] | 490 | if (ide_wait_stat(&startstop, drive, ATA_DRQ, ATA_BUSY, WAIT_READY)) { | 
| Bartlomiej Zolnierkiewicz | 594c16d | 2008-07-15 21:21:58 +0200 | [diff] [blame] | 491 | printk(KERN_ERR "%s: Strange, packet command initiated yet " | 
|  | 492 | "DRQ isn't asserted\n", drive->name); | 
|  | 493 | return startstop; | 
|  | 494 | } | 
|  | 495 |  | 
| Bartlomiej Zolnierkiewicz | 88a7210 | 2008-07-23 19:55:54 +0200 | [diff] [blame] | 496 | ireason = ide_read_ireason(drive); | 
| Bartlomiej Zolnierkiewicz | 97100fc | 2008-10-13 21:39:36 +0200 | [diff] [blame] | 497 | if (drive->media == ide_tape && | 
|  | 498 | (drive->dev_flags & IDE_DFLAG_SCSI) == 0) | 
| Bartlomiej Zolnierkiewicz | 594c16d | 2008-07-15 21:21:58 +0200 | [diff] [blame] | 499 | ireason = ide_wait_ireason(drive, ireason); | 
|  | 500 |  | 
| Bartlomiej Zolnierkiewicz | 3a7d248 | 2008-10-10 22:39:21 +0200 | [diff] [blame] | 501 | if ((ireason & ATAPI_COD) == 0 || (ireason & ATAPI_IO)) { | 
| Bartlomiej Zolnierkiewicz | 594c16d | 2008-07-15 21:21:58 +0200 | [diff] [blame] | 502 | printk(KERN_ERR "%s: (IO,CoD) != (0,1) while issuing " | 
|  | 503 | "a packet command\n", drive->name); | 
|  | 504 | return ide_do_reset(drive); | 
|  | 505 | } | 
|  | 506 |  | 
| Bartlomiej Zolnierkiewicz | baf08f0 | 2008-10-13 21:39:32 +0200 | [diff] [blame] | 507 | /* | 
|  | 508 | * If necessary schedule the packet transfer to occur 'timeout' | 
|  | 509 | * miliseconds later in ide_delayed_transfer_pc() after the device | 
|  | 510 | * says it's ready for a packet. | 
|  | 511 | */ | 
|  | 512 | if (drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) { | 
|  | 513 | timeout = drive->pc_delay; | 
|  | 514 | expiry = &ide_delayed_transfer_pc; | 
|  | 515 | } else { | 
| Bartlomiej Zolnierkiewicz | 97100fc | 2008-10-13 21:39:36 +0200 | [diff] [blame] | 516 | if (drive->dev_flags & IDE_DFLAG_SCSI) { | 
| Bartlomiej Zolnierkiewicz | baf08f0 | 2008-10-13 21:39:32 +0200 | [diff] [blame] | 517 | timeout = ide_scsi_get_timeout(pc); | 
|  | 518 | expiry = ide_scsi_expiry; | 
|  | 519 | } else { | 
|  | 520 | timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD | 
|  | 521 | : WAIT_TAPE_CMD; | 
|  | 522 | expiry = NULL; | 
|  | 523 | } | 
|  | 524 | } | 
|  | 525 |  | 
| Bartlomiej Zolnierkiewicz | 594c16d | 2008-07-15 21:21:58 +0200 | [diff] [blame] | 526 | /* Set the interrupt routine */ | 
| Bartlomiej Zolnierkiewicz | aa5d2de | 2008-10-13 21:39:32 +0200 | [diff] [blame] | 527 | ide_set_handler(drive, ide_pc_intr, timeout, expiry); | 
| Bartlomiej Zolnierkiewicz | 594c16d | 2008-07-15 21:21:58 +0200 | [diff] [blame] | 528 |  | 
|  | 529 | /* Begin DMA, if necessary */ | 
|  | 530 | if (pc->flags & PC_FLAG_DMA_OK) { | 
|  | 531 | pc->flags |= PC_FLAG_DMA_IN_PROGRESS; | 
|  | 532 | hwif->dma_ops->dma_start(drive); | 
|  | 533 | } | 
|  | 534 |  | 
|  | 535 | /* Send the actual packet */ | 
| Borislav Petkov | ea68d27 | 2008-07-23 19:56:01 +0200 | [diff] [blame] | 536 | if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0) | 
| Borislav Petkov | 8fccf89 | 2008-07-23 19:56:01 +0200 | [diff] [blame] | 537 | hwif->tp_ops->output_data(drive, NULL, rq->cmd, 12); | 
| Bartlomiej Zolnierkiewicz | 594c16d | 2008-07-15 21:21:58 +0200 | [diff] [blame] | 538 |  | 
|  | 539 | return ide_started; | 
|  | 540 | } | 
| Bartlomiej Zolnierkiewicz | 6bf1641 | 2008-07-15 21:22:00 +0200 | [diff] [blame] | 541 |  | 
| Bartlomiej Zolnierkiewicz | baf08f0 | 2008-10-13 21:39:32 +0200 | [diff] [blame] | 542 | ide_startstop_t ide_issue_pc(ide_drive_t *drive, unsigned int timeout, | 
| Bartlomiej Zolnierkiewicz | 6bf1641 | 2008-07-15 21:22:00 +0200 | [diff] [blame] | 543 | ide_expiry_t *expiry) | 
|  | 544 | { | 
| Bartlomiej Zolnierkiewicz | 2b9efba | 2008-10-13 21:39:31 +0200 | [diff] [blame] | 545 | struct ide_atapi_pc *pc = drive->pc; | 
| Bartlomiej Zolnierkiewicz | 6bf1641 | 2008-07-15 21:22:00 +0200 | [diff] [blame] | 546 | ide_hwif_t *hwif = drive->hwif; | 
| Borislav Petkov | f9476b9 | 2008-10-13 21:39:50 +0200 | [diff] [blame] | 547 | u32 tf_flags; | 
| Bartlomiej Zolnierkiewicz | 6bf1641 | 2008-07-15 21:22:00 +0200 | [diff] [blame] | 548 | u16 bcount; | 
| Borislav Petkov | 0a9b6f8 | 2008-10-13 21:39:49 +0200 | [diff] [blame] | 549 | u8 scsi = !!(drive->dev_flags & IDE_DFLAG_SCSI); | 
| Bartlomiej Zolnierkiewicz | 6bf1641 | 2008-07-15 21:22:00 +0200 | [diff] [blame] | 550 |  | 
|  | 551 | /* We haven't transferred any data yet */ | 
|  | 552 | pc->xferred = 0; | 
|  | 553 | pc->cur_pos = pc->buf; | 
|  | 554 |  | 
|  | 555 | /* Request to transfer the entire buffer at once */ | 
| Bartlomiej Zolnierkiewicz | 97100fc | 2008-10-13 21:39:36 +0200 | [diff] [blame] | 556 | if (drive->media == ide_tape && scsi == 0) | 
| Bartlomiej Zolnierkiewicz | 6bf1641 | 2008-07-15 21:22:00 +0200 | [diff] [blame] | 557 | bcount = pc->req_xfer; | 
|  | 558 | else | 
|  | 559 | bcount = min(pc->req_xfer, 63 * 1024); | 
|  | 560 |  | 
|  | 561 | if (pc->flags & PC_FLAG_DMA_ERROR) { | 
|  | 562 | pc->flags &= ~PC_FLAG_DMA_ERROR; | 
|  | 563 | ide_dma_off(drive); | 
|  | 564 | } | 
|  | 565 |  | 
| Bartlomiej Zolnierkiewicz | 97100fc | 2008-10-13 21:39:36 +0200 | [diff] [blame] | 566 | if ((pc->flags & PC_FLAG_DMA_OK) && | 
|  | 567 | (drive->dev_flags & IDE_DFLAG_USING_DMA)) { | 
|  | 568 | if (scsi) | 
| Bartlomiej Zolnierkiewicz | 6bf1641 | 2008-07-15 21:22:00 +0200 | [diff] [blame] | 569 | hwif->sg_mapped = 1; | 
| Borislav Petkov | 0a9b6f8 | 2008-10-13 21:39:49 +0200 | [diff] [blame] | 570 | drive->dma = !hwif->dma_ops->dma_setup(drive); | 
| Bartlomiej Zolnierkiewicz | 97100fc | 2008-10-13 21:39:36 +0200 | [diff] [blame] | 571 | if (scsi) | 
| Bartlomiej Zolnierkiewicz | 6bf1641 | 2008-07-15 21:22:00 +0200 | [diff] [blame] | 572 | hwif->sg_mapped = 0; | 
|  | 573 | } | 
|  | 574 |  | 
| Borislav Petkov | 0a9b6f8 | 2008-10-13 21:39:49 +0200 | [diff] [blame] | 575 | if (!drive->dma) | 
| Bartlomiej Zolnierkiewicz | 6bf1641 | 2008-07-15 21:22:00 +0200 | [diff] [blame] | 576 | pc->flags &= ~PC_FLAG_DMA_OK; | 
|  | 577 |  | 
| Borislav Petkov | f9476b9 | 2008-10-13 21:39:50 +0200 | [diff] [blame] | 578 | if (scsi) | 
|  | 579 | tf_flags = 0; | 
|  | 580 | else if (drive->media == ide_cdrom || drive->media == ide_optical) | 
|  | 581 | tf_flags = IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL; | 
|  | 582 | else | 
|  | 583 | tf_flags = IDE_TFLAG_OUT_DEVICE; | 
|  | 584 |  | 
|  | 585 | ide_pktcmd_tf_load(drive, tf_flags, bcount, drive->dma); | 
| Bartlomiej Zolnierkiewicz | 6bf1641 | 2008-07-15 21:22:00 +0200 | [diff] [blame] | 586 |  | 
|  | 587 | /* Issue the packet command */ | 
| Borislav Petkov | ac77ef8 | 2008-07-23 19:56:01 +0200 | [diff] [blame] | 588 | if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) { | 
| Bartlomiej Zolnierkiewicz | baf08f0 | 2008-10-13 21:39:32 +0200 | [diff] [blame] | 589 | ide_execute_command(drive, ATA_CMD_PACKET, ide_transfer_pc, | 
| Bartlomiej Zolnierkiewicz | 6bf1641 | 2008-07-15 21:22:00 +0200 | [diff] [blame] | 590 | timeout, NULL); | 
|  | 591 | return ide_started; | 
|  | 592 | } else { | 
|  | 593 | ide_execute_pkt_cmd(drive); | 
| Bartlomiej Zolnierkiewicz | baf08f0 | 2008-10-13 21:39:32 +0200 | [diff] [blame] | 594 | return ide_transfer_pc(drive); | 
| Bartlomiej Zolnierkiewicz | 6bf1641 | 2008-07-15 21:22:00 +0200 | [diff] [blame] | 595 | } | 
|  | 596 | } | 
|  | 597 | EXPORT_SYMBOL_GPL(ide_issue_pc); |