diff options
author | Len Brown <len.brown@intel.com> | 2009-04-05 02:14:15 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-04-05 02:14:15 -0400 |
commit | 478c6a43fcbc6c11609f8cee7c7b57223907754f (patch) | |
tree | a7f7952099da60d33032aed6de9c0c56c9f8779e /drivers/ide/ide-atapi.c | |
parent | 8a3f257c704e02aee9869decd069a806b45be3f1 (diff) | |
parent | 6bb597507f9839b13498781e481f5458aea33620 (diff) |
Merge branch 'linus' into release
Conflicts:
arch/x86/kernel/cpu/cpufreq/longhaul.c
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/ide/ide-atapi.c')
-rw-r--r-- | drivers/ide/ide-atapi.c | 242 |
1 files changed, 120 insertions, 122 deletions
diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index e9d042dba0e0..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)); |
@@ -149,7 +101,10 @@ static void ide_queue_pc_head(ide_drive_t *drive, struct gendisk *disk, | |||
149 | memcpy(rq->cmd, pc->c, 12); | 101 | memcpy(rq->cmd, pc->c, 12); |
150 | if (drive->media == ide_tape) | 102 | if (drive->media == ide_tape) |
151 | rq->cmd[13] = REQ_IDETAPE_PC1; | 103 | rq->cmd[13] = REQ_IDETAPE_PC1; |
152 | ide_do_drive_cmd(drive, rq); | 104 | |
105 | drive->hwif->rq = NULL; | ||
106 | |||
107 | elv_add_request(drive->queue, rq, ELEVATOR_INSERT_FRONT, 0); | ||
153 | } | 108 | } |
154 | 109 | ||
155 | /* | 110 | /* |
@@ -297,6 +252,21 @@ int ide_cd_get_xferlen(struct request *rq) | |||
297 | } | 252 | } |
298 | EXPORT_SYMBOL_GPL(ide_cd_get_xferlen); | 253 | EXPORT_SYMBOL_GPL(ide_cd_get_xferlen); |
299 | 254 | ||
255 | void ide_read_bcount_and_ireason(ide_drive_t *drive, u16 *bcount, u8 *ireason) | ||
256 | { | ||
257 | struct ide_cmd cmd; | ||
258 | |||
259 | memset(&cmd, 0, sizeof(cmd)); | ||
260 | cmd.tf_flags = IDE_TFLAG_IN_LBAH | IDE_TFLAG_IN_LBAM | | ||
261 | IDE_TFLAG_IN_NSECT; | ||
262 | |||
263 | drive->hwif->tp_ops->tf_read(drive, &cmd); | ||
264 | |||
265 | *bcount = (cmd.tf.lbah << 8) | cmd.tf.lbam; | ||
266 | *ireason = cmd.tf.nsect & 3; | ||
267 | } | ||
268 | EXPORT_SYMBOL_GPL(ide_read_bcount_and_ireason); | ||
269 | |||
300 | /* | 270 | /* |
301 | * This is the usual interrupt handler which will be called during a packet | 271 | * This is the usual interrupt handler which will be called during a packet |
302 | * command. We will transfer some of the data (as requested by the drive) | 272 | * command. We will transfer some of the data (as requested by the drive) |
@@ -306,29 +276,31 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
306 | { | 276 | { |
307 | struct ide_atapi_pc *pc = drive->pc; | 277 | struct ide_atapi_pc *pc = drive->pc; |
308 | ide_hwif_t *hwif = drive->hwif; | 278 | ide_hwif_t *hwif = drive->hwif; |
279 | struct ide_cmd *cmd = &hwif->cmd; | ||
309 | struct request *rq = hwif->rq; | 280 | struct request *rq = hwif->rq; |
310 | const struct ide_tp_ops *tp_ops = hwif->tp_ops; | 281 | const struct ide_tp_ops *tp_ops = hwif->tp_ops; |
311 | xfer_func_t *xferfunc; | 282 | xfer_func_t *xferfunc; |
312 | unsigned int timeout, temp; | 283 | unsigned int timeout, done; |
313 | u16 bcount; | 284 | u16 bcount; |
314 | u8 stat, ireason, dsc = 0; | 285 | u8 stat, ireason, dsc = 0; |
286 | u8 write = !!(pc->flags & PC_FLAG_WRITING); | ||
315 | 287 | ||
316 | debug_log("Enter %s - interrupt handler\n", __func__); | 288 | debug_log("Enter %s - interrupt handler\n", __func__); |
317 | 289 | ||
318 | timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD | 290 | timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD |
319 | : WAIT_TAPE_CMD; | 291 | : WAIT_TAPE_CMD; |
320 | 292 | ||
321 | if (pc->flags & PC_FLAG_TIMEDOUT) { | ||
322 | drive->pc_callback(drive, 0); | ||
323 | return ide_stopped; | ||
324 | } | ||
325 | |||
326 | /* Clear the interrupt */ | 293 | /* Clear the interrupt */ |
327 | stat = tp_ops->read_status(hwif); | 294 | stat = tp_ops->read_status(hwif); |
328 | 295 | ||
329 | if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) { | 296 | if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) { |
330 | if (hwif->dma_ops->dma_end(drive) || | 297 | int rc; |
331 | (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))) { | ||
332 | if (drive->media == ide_floppy) | 304 | if (drive->media == ide_floppy) |
333 | printk(KERN_ERR "%s: DMA %s error\n", | 305 | printk(KERN_ERR "%s: DMA %s error\n", |
334 | drive->name, rq_data_dir(pc->rq) | 306 | drive->name, rq_data_dir(pc->rq) |
@@ -344,6 +316,9 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
344 | 316 | ||
345 | /* No more interrupts */ | 317 | /* No more interrupts */ |
346 | if ((stat & ATA_DRQ) == 0) { | 318 | if ((stat & ATA_DRQ) == 0) { |
319 | int uptodate, error; | ||
320 | unsigned int done; | ||
321 | |||
347 | debug_log("Packet command completed, %d bytes transferred\n", | 322 | debug_log("Packet command completed, %d bytes transferred\n", |
348 | pc->xferred); | 323 | pc->xferred); |
349 | 324 | ||
@@ -382,8 +357,31 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
382 | dsc = 1; | 357 | dsc = 1; |
383 | 358 | ||
384 | /* Command finished - Call the callback function */ | 359 | /* Command finished - Call the callback function */ |
385 | drive->pc_callback(drive, dsc); | 360 | uptodate = drive->pc_callback(drive, dsc); |
361 | |||
362 | if (uptodate == 0) | ||
363 | drive->failed_pc = NULL; | ||
364 | |||
365 | if (blk_special_request(rq)) { | ||
366 | rq->errors = 0; | ||
367 | done = blk_rq_bytes(rq); | ||
368 | error = 0; | ||
369 | } else { | ||
386 | 370 | ||
371 | if (blk_fs_request(rq) == 0 && uptodate <= 0) { | ||
372 | if (rq->errors == 0) | ||
373 | rq->errors = -EIO; | ||
374 | } | ||
375 | |||
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; | ||
382 | } | ||
383 | |||
384 | ide_complete_rq(drive, error, done); | ||
387 | return ide_stopped; | 385 | return ide_stopped; |
388 | } | 386 | } |
389 | 387 | ||
@@ -403,8 +401,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
403 | return ide_do_reset(drive); | 401 | return ide_do_reset(drive); |
404 | } | 402 | } |
405 | 403 | ||
406 | if (((ireason & ATAPI_IO) == ATAPI_IO) == | 404 | if (((ireason & ATAPI_IO) == ATAPI_IO) == write) { |
407 | !!(pc->flags & PC_FLAG_WRITING)) { | ||
408 | /* Hopefully, we will never get here */ | 405 | /* Hopefully, we will never get here */ |
409 | 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 " |
410 | "to %s!\n", drive->name, | 407 | "to %s!\n", drive->name, |
@@ -413,59 +410,57 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
413 | return ide_do_reset(drive); | 410 | return ide_do_reset(drive); |
414 | } | 411 | } |
415 | 412 | ||
416 | if (!(pc->flags & PC_FLAG_WRITING)) { | 413 | xferfunc = write ? tp_ops->output_data : tp_ops->input_data; |
417 | /* Reading - Check that we have enough space */ | ||
418 | temp = pc->xferred + bcount; | ||
419 | if (temp > pc->req_xfer) { | ||
420 | if (temp > pc->buf_size) { | ||
421 | printk(KERN_ERR "%s: The device wants to send " | ||
422 | "us more data than expected - " | ||
423 | "discarding data\n", | ||
424 | drive->name); | ||
425 | |||
426 | ide_pad_transfer(drive, 0, bcount); | ||
427 | goto next_irq; | ||
428 | } | ||
429 | debug_log("The device wants to send us more data than " | ||
430 | "expected - allowing transfer\n"); | ||
431 | } | ||
432 | xferfunc = tp_ops->input_data; | ||
433 | } else | ||
434 | xferfunc = tp_ops->output_data; | ||
435 | |||
436 | if ((drive->media == ide_floppy && !pc->buf) || | ||
437 | (drive->media == ide_tape && pc->bh)) { | ||
438 | int done = drive->pc_io_buffers(drive, pc, bcount, | ||
439 | !!(pc->flags & PC_FLAG_WRITING)); | ||
440 | 414 | ||
441 | /* FIXME: don't do partial completions */ | 415 | if (drive->media == ide_floppy && pc->buf == NULL) { |
442 | if (drive->media == ide_floppy) | 416 | done = min_t(unsigned int, bcount, cmd->nleft); |
443 | ide_end_request(drive, 1, done >> 9); | 417 | ide_pio_bytes(drive, cmd, write, done); |
444 | } else | 418 | } else if (drive->media == ide_tape && pc->bh) { |
445 | xferfunc(drive, NULL, pc->cur_pos, bcount); | 419 | done = drive->pc_io_buffers(drive, pc, bcount, write); |
420 | } else { | ||
421 | done = min_t(unsigned int, bcount, pc->req_xfer - pc->xferred); | ||
422 | xferfunc(drive, NULL, pc->cur_pos, done); | ||
423 | } | ||
446 | 424 | ||
447 | /* Update the current position */ | 425 | /* Update the current position */ |
448 | pc->xferred += bcount; | 426 | pc->xferred += done; |
449 | 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); | ||
450 | 436 | ||
451 | debug_log("[cmd %x] transferred %d bytes on that intr.\n", | ||
452 | rq->cmd[0], bcount); | ||
453 | next_irq: | ||
454 | /* And set the interrupt handler again */ | 437 | /* And set the interrupt handler again */ |
455 | ide_set_handler(drive, ide_pc_intr, timeout, NULL); | 438 | ide_set_handler(drive, ide_pc_intr, timeout); |
456 | return ide_started; | 439 | return ide_started; |
457 | } | 440 | } |
458 | 441 | ||
442 | static void ide_init_packet_cmd(struct ide_cmd *cmd, u32 tf_flags, | ||
443 | u16 bcount, u8 dma) | ||
444 | { | ||
445 | cmd->protocol = dma ? ATAPI_PROT_DMA : ATAPI_PROT_PIO; | ||
446 | cmd->tf_flags |= IDE_TFLAG_OUT_LBAH | IDE_TFLAG_OUT_LBAM | | ||
447 | IDE_TFLAG_OUT_FEATURE | tf_flags; | ||
448 | cmd->tf.command = ATA_CMD_PACKET; | ||
449 | cmd->tf.feature = dma; /* Use PIO/DMA */ | ||
450 | cmd->tf.lbam = bcount & 0xff; | ||
451 | cmd->tf.lbah = (bcount >> 8) & 0xff; | ||
452 | } | ||
453 | |||
459 | static u8 ide_read_ireason(ide_drive_t *drive) | 454 | static u8 ide_read_ireason(ide_drive_t *drive) |
460 | { | 455 | { |
461 | ide_task_t task; | 456 | struct ide_cmd cmd; |
462 | 457 | ||
463 | memset(&task, 0, sizeof(task)); | 458 | memset(&cmd, 0, sizeof(cmd)); |
464 | task.tf_flags = IDE_TFLAG_IN_NSECT; | 459 | cmd.tf_flags = IDE_TFLAG_IN_NSECT; |
465 | 460 | ||
466 | drive->hwif->tp_ops->tf_read(drive, &task); | 461 | drive->hwif->tp_ops->tf_read(drive, &cmd); |
467 | 462 | ||
468 | return task.tf.nsect & 3; | 463 | return cmd.tf.nsect & 3; |
469 | } | 464 | } |
470 | 465 | ||
471 | static u8 ide_wait_ireason(ide_drive_t *drive, u8 ireason) | 466 | static u8 ide_wait_ireason(ide_drive_t *drive, u8 ireason) |
@@ -560,11 +555,17 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive) | |||
560 | } | 555 | } |
561 | } | 556 | } |
562 | 557 | ||
558 | hwif->expiry = expiry; | ||
559 | |||
563 | /* Set the interrupt routine */ | 560 | /* Set the interrupt routine */ |
564 | ide_set_handler(drive, | 561 | ide_set_handler(drive, |
565 | (dev_is_idecd(drive) ? drive->irq_handler | 562 | (dev_is_idecd(drive) ? drive->irq_handler |
566 | : ide_pc_intr), | 563 | : ide_pc_intr), |
567 | timeout, expiry); | 564 | timeout); |
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); | ||
568 | 569 | ||
569 | /* Begin DMA, if necessary */ | 570 | /* Begin DMA, if necessary */ |
570 | if (dev_is_idecd(drive)) { | 571 | if (dev_is_idecd(drive)) { |
@@ -577,30 +578,28 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive) | |||
577 | } | 578 | } |
578 | } | 579 | } |
579 | 580 | ||
580 | /* Send the actual packet */ | ||
581 | if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0) | ||
582 | hwif->tp_ops->output_data(drive, NULL, rq->cmd, cmd_len); | ||
583 | |||
584 | return ide_started; | 581 | return ide_started; |
585 | } | 582 | } |
586 | 583 | ||
587 | ide_startstop_t ide_issue_pc(ide_drive_t *drive) | 584 | ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd) |
588 | { | 585 | { |
589 | struct ide_atapi_pc *pc; | 586 | struct ide_atapi_pc *pc; |
590 | ide_hwif_t *hwif = drive->hwif; | 587 | ide_hwif_t *hwif = drive->hwif; |
591 | ide_expiry_t *expiry = NULL; | 588 | ide_expiry_t *expiry = NULL; |
589 | struct request *rq = hwif->rq; | ||
592 | unsigned int timeout; | 590 | unsigned int timeout; |
593 | u32 tf_flags; | 591 | u32 tf_flags; |
594 | u16 bcount; | 592 | u16 bcount; |
593 | u8 drq_int = !!(drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT); | ||
595 | 594 | ||
596 | if (dev_is_idecd(drive)) { | 595 | if (dev_is_idecd(drive)) { |
597 | tf_flags = IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL; | 596 | tf_flags = IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL; |
598 | bcount = ide_cd_get_xferlen(hwif->rq); | 597 | bcount = ide_cd_get_xferlen(rq); |
599 | expiry = ide_cd_expiry; | 598 | expiry = ide_cd_expiry; |
600 | timeout = ATAPI_WAIT_PC; | 599 | timeout = ATAPI_WAIT_PC; |
601 | 600 | ||
602 | if (drive->dma) | 601 | if (drive->dma) |
603 | drive->dma = !hwif->dma_ops->dma_setup(drive); | 602 | drive->dma = !ide_dma_prepare(drive, cmd); |
604 | } else { | 603 | } else { |
605 | pc = drive->pc; | 604 | pc = drive->pc; |
606 | 605 | ||
@@ -618,9 +617,8 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive) | |||
618 | ide_dma_off(drive); | 617 | ide_dma_off(drive); |
619 | } | 618 | } |
620 | 619 | ||
621 | if ((pc->flags & PC_FLAG_DMA_OK) && | 620 | if (pc->flags & PC_FLAG_DMA_OK) |
622 | (drive->dev_flags & IDE_DFLAG_USING_DMA)) | 621 | drive->dma = !ide_dma_prepare(drive, cmd); |
623 | drive->dma = !hwif->dma_ops->dma_setup(drive); | ||
624 | 622 | ||
625 | if (!drive->dma) | 623 | if (!drive->dma) |
626 | pc->flags &= ~PC_FLAG_DMA_OK; | 624 | pc->flags &= ~PC_FLAG_DMA_OK; |
@@ -629,18 +627,18 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive) | |||
629 | : WAIT_TAPE_CMD; | 627 | : WAIT_TAPE_CMD; |
630 | } | 628 | } |
631 | 629 | ||
632 | ide_pktcmd_tf_load(drive, tf_flags, bcount, drive->dma); | 630 | ide_init_packet_cmd(cmd, tf_flags, bcount, drive->dma); |
633 | 631 | ||
634 | /* Issue the packet command */ | 632 | (void)do_rw_taskfile(drive, cmd); |
635 | if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) { | 633 | |
634 | if (drq_int) { | ||
636 | if (drive->dma) | 635 | if (drive->dma) |
637 | drive->waiting_for_dma = 0; | 636 | drive->waiting_for_dma = 0; |
638 | ide_execute_command(drive, ATA_CMD_PACKET, ide_transfer_pc, | 637 | hwif->expiry = expiry; |
639 | timeout, expiry); | ||
640 | return ide_started; | ||
641 | } else { | ||
642 | ide_execute_pkt_cmd(drive); | ||
643 | return ide_transfer_pc(drive); | ||
644 | } | 638 | } |
639 | |||
640 | ide_execute_command(drive, cmd, ide_transfer_pc, timeout); | ||
641 | |||
642 | return drq_int ? ide_started : ide_transfer_pc(drive); | ||
645 | } | 643 | } |
646 | EXPORT_SYMBOL_GPL(ide_issue_pc); | 644 | EXPORT_SYMBOL_GPL(ide_issue_pc); |