diff options
Diffstat (limited to 'drivers/ide/ide-atapi.c')
-rw-r--r-- | drivers/ide/ide-atapi.c | 168 |
1 files changed, 55 insertions, 113 deletions
diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index 2fb5d28a9be5..3e43b889dd64 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c | |||
@@ -6,6 +6,8 @@ | |||
6 | #include <linux/cdrom.h> | 6 | #include <linux/cdrom.h> |
7 | #include <linux/delay.h> | 7 | #include <linux/delay.h> |
8 | #include <linux/ide.h> | 8 | #include <linux/ide.h> |
9 | #include <linux/scatterlist.h> | ||
10 | |||
9 | #include <scsi/scsi.h> | 11 | #include <scsi/scsi.h> |
10 | 12 | ||
11 | #ifdef DEBUG | 13 | #ifdef DEBUG |
@@ -69,56 +71,6 @@ int ide_check_atapi_device(ide_drive_t *drive, const char *s) | |||
69 | } | 71 | } |
70 | EXPORT_SYMBOL_GPL(ide_check_atapi_device); | 72 | EXPORT_SYMBOL_GPL(ide_check_atapi_device); |
71 | 73 | ||
72 | /* PIO data transfer routine using the scatter gather table. */ | ||
73 | int ide_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, | ||
74 | unsigned int bcount, int write) | ||
75 | { | ||
76 | ide_hwif_t *hwif = drive->hwif; | ||
77 | const struct ide_tp_ops *tp_ops = hwif->tp_ops; | ||
78 | xfer_func_t *xf = write ? tp_ops->output_data : tp_ops->input_data; | ||
79 | struct scatterlist *sg = pc->sg; | ||
80 | char *buf; | ||
81 | int count, done = 0; | ||
82 | |||
83 | while (bcount) { | ||
84 | count = min(sg->length - pc->b_count, bcount); | ||
85 | |||
86 | if (PageHighMem(sg_page(sg))) { | ||
87 | unsigned long flags; | ||
88 | |||
89 | local_irq_save(flags); | ||
90 | buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; | ||
91 | xf(drive, NULL, buf + pc->b_count, count); | ||
92 | kunmap_atomic(buf - sg->offset, KM_IRQ0); | ||
93 | local_irq_restore(flags); | ||
94 | } else { | ||
95 | buf = sg_virt(sg); | ||
96 | xf(drive, NULL, buf + pc->b_count, count); | ||
97 | } | ||
98 | |||
99 | bcount -= count; | ||
100 | pc->b_count += count; | ||
101 | done += count; | ||
102 | |||
103 | if (pc->b_count == sg->length) { | ||
104 | if (!--pc->sg_cnt) | ||
105 | break; | ||
106 | pc->sg = sg = sg_next(sg); | ||
107 | pc->b_count = 0; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | if (bcount) { | ||
112 | printk(KERN_ERR "%s: %d leftover bytes, %s\n", drive->name, | ||
113 | bcount, write ? "padding with zeros" | ||
114 | : "discarding data"); | ||
115 | ide_pad_transfer(drive, write, bcount); | ||
116 | } | ||
117 | |||
118 | return done; | ||
119 | } | ||
120 | EXPORT_SYMBOL_GPL(ide_io_buffers); | ||
121 | |||
122 | void ide_init_pc(struct ide_atapi_pc *pc) | 74 | void ide_init_pc(struct ide_atapi_pc *pc) |
123 | { | 75 | { |
124 | memset(pc, 0, sizeof(*pc)); | 76 | memset(pc, 0, sizeof(*pc)); |
@@ -324,12 +276,14 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
324 | { | 276 | { |
325 | struct ide_atapi_pc *pc = drive->pc; | 277 | struct ide_atapi_pc *pc = drive->pc; |
326 | ide_hwif_t *hwif = drive->hwif; | 278 | ide_hwif_t *hwif = drive->hwif; |
279 | struct ide_cmd *cmd = &hwif->cmd; | ||
327 | struct request *rq = hwif->rq; | 280 | struct request *rq = hwif->rq; |
328 | const struct ide_tp_ops *tp_ops = hwif->tp_ops; | 281 | const struct ide_tp_ops *tp_ops = hwif->tp_ops; |
329 | xfer_func_t *xferfunc; | 282 | xfer_func_t *xferfunc; |
330 | unsigned int timeout, temp; | 283 | unsigned int timeout, done; |
331 | u16 bcount; | 284 | u16 bcount; |
332 | u8 stat, ireason, dsc = 0; | 285 | u8 stat, ireason, dsc = 0; |
286 | u8 write = !!(pc->flags & PC_FLAG_WRITING); | ||
333 | 287 | ||
334 | debug_log("Enter %s - interrupt handler\n", __func__); | 288 | debug_log("Enter %s - interrupt handler\n", __func__); |
335 | 289 | ||
@@ -340,8 +294,13 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
340 | stat = tp_ops->read_status(hwif); | 294 | stat = tp_ops->read_status(hwif); |
341 | 295 | ||
342 | if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) { | 296 | if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) { |
343 | if (hwif->dma_ops->dma_end(drive) || | 297 | int rc; |
344 | (drive->media == ide_tape && (stat & ATA_ERR))) { | 298 | |
299 | drive->waiting_for_dma = 0; | ||
300 | rc = hwif->dma_ops->dma_end(drive); | ||
301 | ide_dma_unmap_sg(drive, cmd); | ||
302 | |||
303 | if (rc || (drive->media == ide_tape && (stat & ATA_ERR))) { | ||
345 | if (drive->media == ide_floppy) | 304 | if (drive->media == ide_floppy) |
346 | printk(KERN_ERR "%s: DMA %s error\n", | 305 | printk(KERN_ERR "%s: DMA %s error\n", |
347 | drive->name, rq_data_dir(pc->rq) | 306 | drive->name, rq_data_dir(pc->rq) |
@@ -357,7 +316,8 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
357 | 316 | ||
358 | /* No more interrupts */ | 317 | /* No more interrupts */ |
359 | if ((stat & ATA_DRQ) == 0) { | 318 | if ((stat & ATA_DRQ) == 0) { |
360 | int uptodate; | 319 | int uptodate, error; |
320 | unsigned int done; | ||
361 | 321 | ||
362 | debug_log("Packet command completed, %d bytes transferred\n", | 322 | debug_log("Packet command completed, %d bytes transferred\n", |
363 | pc->xferred); | 323 | pc->xferred); |
@@ -404,16 +364,24 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
404 | 364 | ||
405 | if (blk_special_request(rq)) { | 365 | if (blk_special_request(rq)) { |
406 | rq->errors = 0; | 366 | rq->errors = 0; |
407 | ide_complete_rq(drive, 0, blk_rq_bytes(rq)); | 367 | done = blk_rq_bytes(rq); |
368 | error = 0; | ||
408 | } else { | 369 | } else { |
370 | |||
409 | if (blk_fs_request(rq) == 0 && uptodate <= 0) { | 371 | if (blk_fs_request(rq) == 0 && uptodate <= 0) { |
410 | if (rq->errors == 0) | 372 | if (rq->errors == 0) |
411 | rq->errors = -EIO; | 373 | rq->errors = -EIO; |
412 | } | 374 | } |
413 | ide_complete_rq(drive, uptodate ? 0 : -EIO, | 375 | |
414 | ide_rq_bytes(rq)); | 376 | if (drive->media == ide_tape) |
377 | done = ide_rq_bytes(rq); /* FIXME */ | ||
378 | else | ||
379 | done = blk_rq_bytes(rq); | ||
380 | |||
381 | error = uptodate ? 0 : -EIO; | ||
415 | } | 382 | } |
416 | 383 | ||
384 | ide_complete_rq(drive, error, done); | ||
417 | return ide_stopped; | 385 | return ide_stopped; |
418 | } | 386 | } |
419 | 387 | ||
@@ -433,8 +401,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
433 | return ide_do_reset(drive); | 401 | return ide_do_reset(drive); |
434 | } | 402 | } |
435 | 403 | ||
436 | if (((ireason & ATAPI_IO) == ATAPI_IO) == | 404 | if (((ireason & ATAPI_IO) == ATAPI_IO) == write) { |
437 | !!(pc->flags & PC_FLAG_WRITING)) { | ||
438 | /* Hopefully, we will never get here */ | 405 | /* Hopefully, we will never get here */ |
439 | printk(KERN_ERR "%s: We wanted to %s, but the device wants us " | 406 | printk(KERN_ERR "%s: We wanted to %s, but the device wants us " |
440 | "to %s!\n", drive->name, | 407 | "to %s!\n", drive->name, |
@@ -443,45 +410,30 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
443 | return ide_do_reset(drive); | 410 | return ide_do_reset(drive); |
444 | } | 411 | } |
445 | 412 | ||
446 | if (!(pc->flags & PC_FLAG_WRITING)) { | 413 | xferfunc = write ? tp_ops->output_data : tp_ops->input_data; |
447 | /* Reading - Check that we have enough space */ | 414 | |
448 | temp = pc->xferred + bcount; | 415 | if (drive->media == ide_floppy && pc->buf == NULL) { |
449 | if (temp > pc->req_xfer) { | 416 | done = min_t(unsigned int, bcount, cmd->nleft); |
450 | if (temp > pc->buf_size) { | 417 | ide_pio_bytes(drive, cmd, write, done); |
451 | printk(KERN_ERR "%s: The device wants to send " | 418 | } else if (drive->media == ide_tape && pc->bh) { |
452 | "us more data than expected - " | 419 | done = drive->pc_io_buffers(drive, pc, bcount, write); |
453 | "discarding data\n", | 420 | } else { |
454 | drive->name); | 421 | done = min_t(unsigned int, bcount, pc->req_xfer - pc->xferred); |
455 | 422 | xferfunc(drive, NULL, pc->cur_pos, done); | |
456 | ide_pad_transfer(drive, 0, bcount); | 423 | } |
457 | goto next_irq; | ||
458 | } | ||
459 | debug_log("The device wants to send us more data than " | ||
460 | "expected - allowing transfer\n"); | ||
461 | } | ||
462 | xferfunc = tp_ops->input_data; | ||
463 | } else | ||
464 | xferfunc = tp_ops->output_data; | ||
465 | |||
466 | if ((drive->media == ide_floppy && !pc->buf) || | ||
467 | (drive->media == ide_tape && pc->bh)) { | ||
468 | int done = drive->pc_io_buffers(drive, pc, bcount, | ||
469 | !!(pc->flags & PC_FLAG_WRITING)); | ||
470 | |||
471 | /* FIXME: don't do partial completions */ | ||
472 | if (drive->media == ide_floppy) | ||
473 | ide_complete_rq(drive, 0, | ||
474 | done ? done : ide_rq_bytes(rq)); | ||
475 | } else | ||
476 | xferfunc(drive, NULL, pc->cur_pos, bcount); | ||
477 | 424 | ||
478 | /* Update the current position */ | 425 | /* Update the current position */ |
479 | pc->xferred += bcount; | 426 | pc->xferred += done; |
480 | pc->cur_pos += bcount; | 427 | pc->cur_pos += done; |
428 | |||
429 | bcount -= done; | ||
430 | |||
431 | if (bcount) | ||
432 | ide_pad_transfer(drive, write, bcount); | ||
433 | |||
434 | debug_log("[cmd %x] transferred %d bytes, padded %d bytes\n", | ||
435 | rq->cmd[0], done, bcount); | ||
481 | 436 | ||
482 | debug_log("[cmd %x] transferred %d bytes on that intr.\n", | ||
483 | rq->cmd[0], bcount); | ||
484 | next_irq: | ||
485 | /* And set the interrupt handler again */ | 437 | /* And set the interrupt handler again */ |
486 | ide_set_handler(drive, ide_pc_intr, timeout); | 438 | ide_set_handler(drive, ide_pc_intr, timeout); |
487 | return ide_started; | 439 | return ide_started; |
@@ -611,6 +563,10 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive) | |||
611 | : ide_pc_intr), | 563 | : ide_pc_intr), |
612 | timeout); | 564 | timeout); |
613 | 565 | ||
566 | /* Send the actual packet */ | ||
567 | if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0) | ||
568 | hwif->tp_ops->output_data(drive, NULL, rq->cmd, cmd_len); | ||
569 | |||
614 | /* Begin DMA, if necessary */ | 570 | /* Begin DMA, if necessary */ |
615 | if (dev_is_idecd(drive)) { | 571 | if (dev_is_idecd(drive)) { |
616 | if (drive->dma) | 572 | if (drive->dma) |
@@ -622,10 +578,6 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive) | |||
622 | } | 578 | } |
623 | } | 579 | } |
624 | 580 | ||
625 | /* Send the actual packet */ | ||
626 | if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0) | ||
627 | hwif->tp_ops->output_data(drive, NULL, rq->cmd, cmd_len); | ||
628 | |||
629 | return ide_started; | 581 | return ide_started; |
630 | } | 582 | } |
631 | 583 | ||
@@ -633,7 +585,6 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd) | |||
633 | { | 585 | { |
634 | struct ide_atapi_pc *pc; | 586 | struct ide_atapi_pc *pc; |
635 | ide_hwif_t *hwif = drive->hwif; | 587 | ide_hwif_t *hwif = drive->hwif; |
636 | const struct ide_dma_ops *dma_ops = hwif->dma_ops; | ||
637 | ide_expiry_t *expiry = NULL; | 588 | ide_expiry_t *expiry = NULL; |
638 | struct request *rq = hwif->rq; | 589 | struct request *rq = hwif->rq; |
639 | unsigned int timeout; | 590 | unsigned int timeout; |
@@ -647,12 +598,8 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd) | |||
647 | expiry = ide_cd_expiry; | 598 | expiry = ide_cd_expiry; |
648 | timeout = ATAPI_WAIT_PC; | 599 | timeout = ATAPI_WAIT_PC; |
649 | 600 | ||
650 | if (drive->dma) { | 601 | if (drive->dma) |
651 | if (ide_build_sglist(drive, cmd)) | 602 | drive->dma = !ide_dma_prepare(drive, cmd); |
652 | drive->dma = !dma_ops->dma_setup(drive, cmd); | ||
653 | else | ||
654 | drive->dma = 0; | ||
655 | } | ||
656 | } else { | 603 | } else { |
657 | pc = drive->pc; | 604 | pc = drive->pc; |
658 | 605 | ||
@@ -670,13 +617,8 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd) | |||
670 | ide_dma_off(drive); | 617 | ide_dma_off(drive); |
671 | } | 618 | } |
672 | 619 | ||
673 | if ((pc->flags & PC_FLAG_DMA_OK) && | 620 | if (pc->flags & PC_FLAG_DMA_OK) |
674 | (drive->dev_flags & IDE_DFLAG_USING_DMA)) { | 621 | drive->dma = !ide_dma_prepare(drive, cmd); |
675 | if (ide_build_sglist(drive, cmd)) | ||
676 | drive->dma = !dma_ops->dma_setup(drive, cmd); | ||
677 | else | ||
678 | drive->dma = 0; | ||
679 | } | ||
680 | 622 | ||
681 | if (!drive->dma) | 623 | if (!drive->dma) |
682 | pc->flags &= ~PC_FLAG_DMA_OK; | 624 | pc->flags &= ~PC_FLAG_DMA_OK; |