diff options
Diffstat (limited to 'drivers/ide/ide-atapi.c')
-rw-r--r-- | drivers/ide/ide-atapi.c | 183 |
1 files changed, 135 insertions, 48 deletions
diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index 608c5bade929..2e305714c209 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c | |||
@@ -124,8 +124,8 @@ EXPORT_SYMBOL_GPL(ide_init_pc); | |||
124 | * the current request, so that it will be processed immediately, on the next | 124 | * the current request, so that it will be processed immediately, on the next |
125 | * pass through the driver. | 125 | * pass through the driver. |
126 | */ | 126 | */ |
127 | void ide_queue_pc_head(ide_drive_t *drive, struct gendisk *disk, | 127 | static void ide_queue_pc_head(ide_drive_t *drive, struct gendisk *disk, |
128 | struct ide_atapi_pc *pc, struct request *rq) | 128 | struct ide_atapi_pc *pc, struct request *rq) |
129 | { | 129 | { |
130 | blk_rq_init(NULL, rq); | 130 | blk_rq_init(NULL, rq); |
131 | rq->cmd_type = REQ_TYPE_SPECIAL; | 131 | rq->cmd_type = REQ_TYPE_SPECIAL; |
@@ -137,7 +137,6 @@ void ide_queue_pc_head(ide_drive_t *drive, struct gendisk *disk, | |||
137 | rq->cmd[13] = REQ_IDETAPE_PC1; | 137 | rq->cmd[13] = REQ_IDETAPE_PC1; |
138 | ide_do_drive_cmd(drive, rq); | 138 | ide_do_drive_cmd(drive, rq); |
139 | } | 139 | } |
140 | EXPORT_SYMBOL_GPL(ide_queue_pc_head); | ||
141 | 140 | ||
142 | /* | 141 | /* |
143 | * Add a special packet command request to the tail of the request queue, | 142 | * Add a special packet command request to the tail of the request queue, |
@@ -203,25 +202,80 @@ int ide_set_media_lock(ide_drive_t *drive, struct gendisk *disk, int on) | |||
203 | } | 202 | } |
204 | EXPORT_SYMBOL_GPL(ide_set_media_lock); | 203 | EXPORT_SYMBOL_GPL(ide_set_media_lock); |
205 | 204 | ||
206 | /* TODO: unify the code thus making some arguments go away */ | 205 | void ide_create_request_sense_cmd(ide_drive_t *drive, struct ide_atapi_pc *pc) |
207 | ide_startstop_t ide_pc_intr(ide_drive_t *drive, struct ide_atapi_pc *pc, | ||
208 | ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry, | ||
209 | void (*update_buffers)(ide_drive_t *, struct ide_atapi_pc *), | ||
210 | void (*retry_pc)(ide_drive_t *), void (*dsc_handle)(ide_drive_t *), | ||
211 | int (*io_buffers)(ide_drive_t *, struct ide_atapi_pc *, unsigned, int)) | ||
212 | { | 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 | |||
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 | |||
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) | ||
255 | { | ||
256 | struct ide_atapi_pc *pc = drive->pc; | ||
213 | ide_hwif_t *hwif = drive->hwif; | 257 | ide_hwif_t *hwif = drive->hwif; |
214 | struct request *rq = hwif->hwgroup->rq; | 258 | struct request *rq = hwif->hwgroup->rq; |
215 | const struct ide_tp_ops *tp_ops = hwif->tp_ops; | 259 | const struct ide_tp_ops *tp_ops = hwif->tp_ops; |
216 | xfer_func_t *xferfunc; | 260 | xfer_func_t *xferfunc; |
217 | unsigned int temp; | 261 | ide_expiry_t *expiry; |
262 | unsigned int timeout, temp; | ||
218 | u16 bcount; | 263 | u16 bcount; |
219 | u8 stat, ireason, scsi = drive->scsi; | 264 | u8 stat, ireason, scsi = !!(drive->dev_flags & IDE_DFLAG_SCSI), dsc = 0; |
220 | 265 | ||
221 | debug_log("Enter %s - interrupt handler\n", __func__); | 266 | debug_log("Enter %s - interrupt handler\n", __func__); |
222 | 267 | ||
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 | |||
223 | if (pc->flags & PC_FLAG_TIMEDOUT) { | 277 | if (pc->flags & PC_FLAG_TIMEDOUT) { |
224 | drive->pc_callback(drive); | 278 | drive->pc_callback(drive, 0); |
225 | return ide_stopped; | 279 | return ide_stopped; |
226 | } | 280 | } |
227 | 281 | ||
@@ -238,8 +292,8 @@ ide_startstop_t ide_pc_intr(ide_drive_t *drive, struct ide_atapi_pc *pc, | |||
238 | pc->flags |= PC_FLAG_DMA_ERROR; | 292 | pc->flags |= PC_FLAG_DMA_ERROR; |
239 | } else { | 293 | } else { |
240 | pc->xferred = pc->req_xfer; | 294 | pc->xferred = pc->req_xfer; |
241 | if (update_buffers) | 295 | if (drive->pc_update_buffers) |
242 | update_buffers(drive, pc); | 296 | drive->pc_update_buffers(drive, pc); |
243 | } | 297 | } |
244 | debug_log("%s: DMA finished\n", drive->name); | 298 | debug_log("%s: DMA finished\n", drive->name); |
245 | } | 299 | } |
@@ -276,21 +330,19 @@ ide_startstop_t ide_pc_intr(ide_drive_t *drive, struct ide_atapi_pc *pc, | |||
276 | debug_log("[cmd %x]: check condition\n", rq->cmd[0]); | 330 | debug_log("[cmd %x]: check condition\n", rq->cmd[0]); |
277 | 331 | ||
278 | /* Retry operation */ | 332 | /* Retry operation */ |
279 | retry_pc(drive); | 333 | ide_retry_pc(drive, rq->rq_disk); |
280 | 334 | ||
281 | /* queued, but not started */ | 335 | /* queued, but not started */ |
282 | return ide_stopped; | 336 | return ide_stopped; |
283 | } | 337 | } |
284 | cmd_finished: | 338 | cmd_finished: |
285 | pc->error = 0; | 339 | pc->error = 0; |
286 | if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && | 340 | |
287 | (stat & ATA_DSC) == 0) { | 341 | if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && (stat & ATA_DSC) == 0) |
288 | dsc_handle(drive); | 342 | dsc = 1; |
289 | return ide_stopped; | ||
290 | } | ||
291 | 343 | ||
292 | /* Command finished - Call the callback function */ | 344 | /* Command finished - Call the callback function */ |
293 | drive->pc_callback(drive); | 345 | drive->pc_callback(drive, dsc); |
294 | 346 | ||
295 | return ide_stopped; | 347 | return ide_stopped; |
296 | } | 348 | } |
@@ -336,7 +388,8 @@ cmd_finished: | |||
336 | temp = 0; | 388 | temp = 0; |
337 | if (temp) { | 389 | if (temp) { |
338 | if (pc->sg) | 390 | if (pc->sg) |
339 | io_buffers(drive, pc, temp, 0); | 391 | drive->pc_io_buffers(drive, pc, |
392 | temp, 0); | ||
340 | else | 393 | else |
341 | tp_ops->input_data(drive, NULL, | 394 | tp_ops->input_data(drive, NULL, |
342 | pc->cur_pos, temp); | 395 | pc->cur_pos, temp); |
@@ -348,9 +401,7 @@ cmd_finished: | |||
348 | pc->xferred += temp; | 401 | pc->xferred += temp; |
349 | pc->cur_pos += temp; | 402 | pc->cur_pos += temp; |
350 | ide_pad_transfer(drive, 0, bcount - temp); | 403 | ide_pad_transfer(drive, 0, bcount - temp); |
351 | ide_set_handler(drive, handler, timeout, | 404 | goto next_irq; |
352 | expiry); | ||
353 | return ide_started; | ||
354 | } | 405 | } |
355 | debug_log("The device wants to send us more data than " | 406 | debug_log("The device wants to send us more data than " |
356 | "expected - allowing transfer\n"); | 407 | "expected - allowing transfer\n"); |
@@ -362,7 +413,7 @@ cmd_finished: | |||
362 | if ((drive->media == ide_floppy && !scsi && !pc->buf) || | 413 | if ((drive->media == ide_floppy && !scsi && !pc->buf) || |
363 | (drive->media == ide_tape && !scsi && pc->bh) || | 414 | (drive->media == ide_tape && !scsi && pc->bh) || |
364 | (scsi && pc->sg)) { | 415 | (scsi && pc->sg)) { |
365 | int done = io_buffers(drive, pc, bcount, | 416 | int done = drive->pc_io_buffers(drive, pc, bcount, |
366 | !!(pc->flags & PC_FLAG_WRITING)); | 417 | !!(pc->flags & PC_FLAG_WRITING)); |
367 | 418 | ||
368 | /* FIXME: don't do partial completions */ | 419 | /* FIXME: don't do partial completions */ |
@@ -377,12 +428,11 @@ cmd_finished: | |||
377 | 428 | ||
378 | debug_log("[cmd %x] transferred %d bytes on that intr.\n", | 429 | debug_log("[cmd %x] transferred %d bytes on that intr.\n", |
379 | rq->cmd[0], bcount); | 430 | rq->cmd[0], bcount); |
380 | 431 | next_irq: | |
381 | /* And set the interrupt handler again */ | 432 | /* And set the interrupt handler again */ |
382 | ide_set_handler(drive, handler, timeout, expiry); | 433 | ide_set_handler(drive, ide_pc_intr, timeout, expiry); |
383 | return ide_started; | 434 | return ide_started; |
384 | } | 435 | } |
385 | EXPORT_SYMBOL_GPL(ide_pc_intr); | ||
386 | 436 | ||
387 | static u8 ide_read_ireason(ide_drive_t *drive) | 437 | static u8 ide_read_ireason(ide_drive_t *drive) |
388 | { | 438 | { |
@@ -418,12 +468,22 @@ static u8 ide_wait_ireason(ide_drive_t *drive, u8 ireason) | |||
418 | return ireason; | 468 | return ireason; |
419 | } | 469 | } |
420 | 470 | ||
421 | ide_startstop_t ide_transfer_pc(ide_drive_t *drive, struct ide_atapi_pc *pc, | 471 | static int ide_delayed_transfer_pc(ide_drive_t *drive) |
422 | ide_handler_t *handler, unsigned int timeout, | ||
423 | ide_expiry_t *expiry) | ||
424 | { | 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) | ||
481 | { | ||
482 | struct ide_atapi_pc *pc = drive->pc; | ||
425 | ide_hwif_t *hwif = drive->hwif; | 483 | ide_hwif_t *hwif = drive->hwif; |
426 | struct request *rq = hwif->hwgroup->rq; | 484 | struct request *rq = hwif->hwgroup->rq; |
485 | ide_expiry_t *expiry; | ||
486 | unsigned int timeout; | ||
427 | ide_startstop_t startstop; | 487 | ide_startstop_t startstop; |
428 | u8 ireason; | 488 | u8 ireason; |
429 | 489 | ||
@@ -434,7 +494,8 @@ ide_startstop_t ide_transfer_pc(ide_drive_t *drive, struct ide_atapi_pc *pc, | |||
434 | } | 494 | } |
435 | 495 | ||
436 | ireason = ide_read_ireason(drive); | 496 | ireason = ide_read_ireason(drive); |
437 | if (drive->media == ide_tape && !drive->scsi) | 497 | if (drive->media == ide_tape && |
498 | (drive->dev_flags & IDE_DFLAG_SCSI) == 0) | ||
438 | ireason = ide_wait_ireason(drive, ireason); | 499 | ireason = ide_wait_ireason(drive, ireason); |
439 | 500 | ||
440 | if ((ireason & ATAPI_COD) == 0 || (ireason & ATAPI_IO)) { | 501 | if ((ireason & ATAPI_COD) == 0 || (ireason & ATAPI_IO)) { |
@@ -443,8 +504,27 @@ ide_startstop_t ide_transfer_pc(ide_drive_t *drive, struct ide_atapi_pc *pc, | |||
443 | return ide_do_reset(drive); | 504 | return ide_do_reset(drive); |
444 | } | 505 | } |
445 | 506 | ||
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 { | ||
516 | if (drive->dev_flags & IDE_DFLAG_SCSI) { | ||
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 | |||
446 | /* Set the interrupt routine */ | 526 | /* Set the interrupt routine */ |
447 | ide_set_handler(drive, handler, timeout, expiry); | 527 | ide_set_handler(drive, ide_pc_intr, timeout, expiry); |
448 | 528 | ||
449 | /* Begin DMA, if necessary */ | 529 | /* Begin DMA, if necessary */ |
450 | if (pc->flags & PC_FLAG_DMA_OK) { | 530 | if (pc->flags & PC_FLAG_DMA_OK) { |
@@ -458,22 +538,22 @@ ide_startstop_t ide_transfer_pc(ide_drive_t *drive, struct ide_atapi_pc *pc, | |||
458 | 538 | ||
459 | return ide_started; | 539 | return ide_started; |
460 | } | 540 | } |
461 | EXPORT_SYMBOL_GPL(ide_transfer_pc); | ||
462 | 541 | ||
463 | ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_atapi_pc *pc, | 542 | ide_startstop_t ide_issue_pc(ide_drive_t *drive, unsigned int timeout, |
464 | ide_handler_t *handler, unsigned int timeout, | ||
465 | ide_expiry_t *expiry) | 543 | ide_expiry_t *expiry) |
466 | { | 544 | { |
545 | struct ide_atapi_pc *pc = drive->pc; | ||
467 | ide_hwif_t *hwif = drive->hwif; | 546 | ide_hwif_t *hwif = drive->hwif; |
547 | u32 tf_flags; | ||
468 | u16 bcount; | 548 | u16 bcount; |
469 | u8 dma = 0; | 549 | u8 scsi = !!(drive->dev_flags & IDE_DFLAG_SCSI); |
470 | 550 | ||
471 | /* We haven't transferred any data yet */ | 551 | /* We haven't transferred any data yet */ |
472 | pc->xferred = 0; | 552 | pc->xferred = 0; |
473 | pc->cur_pos = pc->buf; | 553 | pc->cur_pos = pc->buf; |
474 | 554 | ||
475 | /* Request to transfer the entire buffer at once */ | 555 | /* Request to transfer the entire buffer at once */ |
476 | if (drive->media == ide_tape && !drive->scsi) | 556 | if (drive->media == ide_tape && scsi == 0) |
477 | bcount = pc->req_xfer; | 557 | bcount = pc->req_xfer; |
478 | else | 558 | else |
479 | bcount = min(pc->req_xfer, 63 * 1024); | 559 | bcount = min(pc->req_xfer, 63 * 1024); |
@@ -483,28 +563,35 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_atapi_pc *pc, | |||
483 | ide_dma_off(drive); | 563 | ide_dma_off(drive); |
484 | } | 564 | } |
485 | 565 | ||
486 | if ((pc->flags & PC_FLAG_DMA_OK) && drive->using_dma) { | 566 | if ((pc->flags & PC_FLAG_DMA_OK) && |
487 | if (drive->scsi) | 567 | (drive->dev_flags & IDE_DFLAG_USING_DMA)) { |
568 | if (scsi) | ||
488 | hwif->sg_mapped = 1; | 569 | hwif->sg_mapped = 1; |
489 | dma = !hwif->dma_ops->dma_setup(drive); | 570 | drive->dma = !hwif->dma_ops->dma_setup(drive); |
490 | if (drive->scsi) | 571 | if (scsi) |
491 | hwif->sg_mapped = 0; | 572 | hwif->sg_mapped = 0; |
492 | } | 573 | } |
493 | 574 | ||
494 | if (!dma) | 575 | if (!drive->dma) |
495 | pc->flags &= ~PC_FLAG_DMA_OK; | 576 | pc->flags &= ~PC_FLAG_DMA_OK; |
496 | 577 | ||
497 | ide_pktcmd_tf_load(drive, drive->scsi ? 0 : IDE_TFLAG_OUT_DEVICE, | 578 | if (scsi) |
498 | bcount, dma); | 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); | ||
499 | 586 | ||
500 | /* Issue the packet command */ | 587 | /* Issue the packet command */ |
501 | if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) { | 588 | if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) { |
502 | ide_execute_command(drive, ATA_CMD_PACKET, handler, | 589 | ide_execute_command(drive, ATA_CMD_PACKET, ide_transfer_pc, |
503 | timeout, NULL); | 590 | timeout, NULL); |
504 | return ide_started; | 591 | return ide_started; |
505 | } else { | 592 | } else { |
506 | ide_execute_pkt_cmd(drive); | 593 | ide_execute_pkt_cmd(drive); |
507 | return (*handler)(drive); | 594 | return ide_transfer_pc(drive); |
508 | } | 595 | } |
509 | } | 596 | } |
510 | EXPORT_SYMBOL_GPL(ide_issue_pc); | 597 | EXPORT_SYMBOL_GPL(ide_issue_pc); |