diff options
author | Albert Lee <albertcc@tw.ibm.com> | 2005-05-12 15:29:42 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-05-12 15:29:42 -0400 |
commit | 8bf62ecee58360749c5f0e68bc97d5e02a6816b1 (patch) | |
tree | a3da6e695fc5a71ac7f3246707380a9ac22f6402 /drivers/scsi/libata-scsi.c | |
parent | 88d7bd8cb9eb8d64bf7997600b0d64f7834047c5 (diff) |
[libata] C/H/S support, for older devices
Diffstat (limited to 'drivers/scsi/libata-scsi.c')
-rw-r--r-- | drivers/scsi/libata-scsi.c | 280 |
1 files changed, 177 insertions, 103 deletions
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 4c96df060c3b..8b065ef0e39a 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c | |||
@@ -435,77 +435,107 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) | |||
435 | static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) | 435 | static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) |
436 | { | 436 | { |
437 | struct ata_taskfile *tf = &qc->tf; | 437 | struct ata_taskfile *tf = &qc->tf; |
438 | struct ata_device *dev = qc->dev; | ||
439 | unsigned int lba = tf->flags & ATA_TFLAG_LBA; | ||
438 | unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; | 440 | unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; |
439 | u64 dev_sectors = qc->dev->n_sectors; | 441 | u64 dev_sectors = qc->dev->n_sectors; |
440 | u64 sect = 0; | 442 | u64 block = 0; |
441 | u32 n_sect = 0; | 443 | u32 n_block = 0; |
442 | 444 | ||
443 | tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; | 445 | tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; |
444 | tf->protocol = ATA_PROT_NODATA; | 446 | tf->protocol = ATA_PROT_NODATA; |
445 | tf->device |= ATA_LBA; | ||
446 | 447 | ||
447 | if (scsicmd[0] == VERIFY) { | 448 | if (scsicmd[0] == VERIFY) { |
448 | sect |= ((u64)scsicmd[2]) << 24; | 449 | block |= ((u64)scsicmd[2]) << 24; |
449 | sect |= ((u64)scsicmd[3]) << 16; | 450 | block |= ((u64)scsicmd[3]) << 16; |
450 | sect |= ((u64)scsicmd[4]) << 8; | 451 | block |= ((u64)scsicmd[4]) << 8; |
451 | sect |= ((u64)scsicmd[5]); | 452 | block |= ((u64)scsicmd[5]); |
452 | 453 | ||
453 | n_sect |= ((u32)scsicmd[7]) << 8; | 454 | n_block |= ((u32)scsicmd[7]) << 8; |
454 | n_sect |= ((u32)scsicmd[8]); | 455 | n_block |= ((u32)scsicmd[8]); |
455 | } | 456 | } |
456 | 457 | ||
457 | else if (scsicmd[0] == VERIFY_16) { | 458 | else if (scsicmd[0] == VERIFY_16) { |
458 | sect |= ((u64)scsicmd[2]) << 56; | 459 | block |= ((u64)scsicmd[2]) << 56; |
459 | sect |= ((u64)scsicmd[3]) << 48; | 460 | block |= ((u64)scsicmd[3]) << 48; |
460 | sect |= ((u64)scsicmd[4]) << 40; | 461 | block |= ((u64)scsicmd[4]) << 40; |
461 | sect |= ((u64)scsicmd[5]) << 32; | 462 | block |= ((u64)scsicmd[5]) << 32; |
462 | sect |= ((u64)scsicmd[6]) << 24; | 463 | block |= ((u64)scsicmd[6]) << 24; |
463 | sect |= ((u64)scsicmd[7]) << 16; | 464 | block |= ((u64)scsicmd[7]) << 16; |
464 | sect |= ((u64)scsicmd[8]) << 8; | 465 | block |= ((u64)scsicmd[8]) << 8; |
465 | sect |= ((u64)scsicmd[9]); | 466 | block |= ((u64)scsicmd[9]); |
466 | 467 | ||
467 | n_sect |= ((u32)scsicmd[10]) << 24; | 468 | n_block |= ((u32)scsicmd[10]) << 24; |
468 | n_sect |= ((u32)scsicmd[11]) << 16; | 469 | n_block |= ((u32)scsicmd[11]) << 16; |
469 | n_sect |= ((u32)scsicmd[12]) << 8; | 470 | n_block |= ((u32)scsicmd[12]) << 8; |
470 | n_sect |= ((u32)scsicmd[13]); | 471 | n_block |= ((u32)scsicmd[13]); |
471 | } | 472 | } |
472 | 473 | ||
473 | else | 474 | else |
474 | return 1; | 475 | return 1; |
475 | 476 | ||
476 | if (!n_sect) | 477 | if (!n_block) |
477 | return 1; | 478 | return 1; |
478 | if (sect >= dev_sectors) | 479 | if (block >= dev_sectors) |
479 | return 1; | 480 | return 1; |
480 | if ((sect + n_sect) > dev_sectors) | 481 | if ((block + n_block) > dev_sectors) |
481 | return 1; | 482 | return 1; |
482 | if (lba48) { | 483 | if (lba48) { |
483 | if (n_sect > (64 * 1024)) | 484 | if (n_block > (64 * 1024)) |
484 | return 1; | 485 | return 1; |
485 | } else { | 486 | } else { |
486 | if (n_sect > 256) | 487 | if (n_block > 256) |
487 | return 1; | 488 | return 1; |
488 | } | 489 | } |
489 | 490 | ||
490 | if (lba48) { | 491 | if (lba) { |
491 | tf->command = ATA_CMD_VERIFY_EXT; | 492 | if (lba48) { |
493 | tf->command = ATA_CMD_VERIFY_EXT; | ||
492 | 494 | ||
493 | tf->hob_nsect = (n_sect >> 8) & 0xff; | 495 | tf->hob_nsect = (n_block >> 8) & 0xff; |
494 | 496 | ||
495 | tf->hob_lbah = (sect >> 40) & 0xff; | 497 | tf->hob_lbah = (block >> 40) & 0xff; |
496 | tf->hob_lbam = (sect >> 32) & 0xff; | 498 | tf->hob_lbam = (block >> 32) & 0xff; |
497 | tf->hob_lbal = (sect >> 24) & 0xff; | 499 | tf->hob_lbal = (block >> 24) & 0xff; |
498 | } else { | 500 | } else { |
499 | tf->command = ATA_CMD_VERIFY; | 501 | tf->command = ATA_CMD_VERIFY; |
500 | 502 | ||
501 | tf->device |= (sect >> 24) & 0xf; | 503 | tf->device |= (block >> 24) & 0xf; |
502 | } | 504 | } |
505 | |||
506 | tf->nsect = n_block & 0xff; | ||
503 | 507 | ||
504 | tf->nsect = n_sect & 0xff; | 508 | tf->lbah = (block >> 16) & 0xff; |
509 | tf->lbam = (block >> 8) & 0xff; | ||
510 | tf->lbal = block & 0xff; | ||
505 | 511 | ||
506 | tf->lbah = (sect >> 16) & 0xff; | 512 | tf->device |= ATA_LBA; |
507 | tf->lbam = (sect >> 8) & 0xff; | 513 | } else { |
508 | tf->lbal = sect & 0xff; | 514 | /* CHS */ |
515 | u32 sect, head, cyl, track; | ||
516 | |||
517 | /* Convert LBA to CHS */ | ||
518 | track = (u32)block / dev->sectors; | ||
519 | cyl = track / dev->heads; | ||
520 | head = track % dev->heads; | ||
521 | sect = (u32)block % dev->sectors + 1; | ||
522 | |||
523 | DPRINTK("block[%u] track[%u] cyl[%u] head[%u] sect[%u] \n", (u32)block, track, cyl, head, sect); | ||
524 | |||
525 | /* Check whether the converted CHS can fit. | ||
526 | Cylinder: 0-65535 | ||
527 | Head: 0-15 | ||
528 | Sector: 1-255*/ | ||
529 | if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) | ||
530 | return 1; | ||
531 | |||
532 | tf->command = ATA_CMD_VERIFY; | ||
533 | tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ | ||
534 | tf->lbal = sect; | ||
535 | tf->lbam = cyl; | ||
536 | tf->lbah = cyl >> 8; | ||
537 | tf->device |= head; | ||
538 | } | ||
509 | 539 | ||
510 | return 0; | 540 | return 0; |
511 | } | 541 | } |
@@ -533,11 +563,14 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) | |||
533 | static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) | 563 | static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) |
534 | { | 564 | { |
535 | struct ata_taskfile *tf = &qc->tf; | 565 | struct ata_taskfile *tf = &qc->tf; |
566 | struct ata_device *dev = qc->dev; | ||
567 | unsigned int lba = tf->flags & ATA_TFLAG_LBA; | ||
536 | unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; | 568 | unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; |
569 | u64 block = 0; | ||
570 | u32 n_block = 0; | ||
537 | 571 | ||
538 | tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; | 572 | tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; |
539 | tf->protocol = qc->dev->xfer_protocol; | 573 | tf->protocol = qc->dev->xfer_protocol; |
540 | tf->device |= ATA_LBA; | ||
541 | 574 | ||
542 | if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 || | 575 | if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 || |
543 | scsicmd[0] == READ_16) { | 576 | scsicmd[0] == READ_16) { |
@@ -547,80 +580,111 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) | |||
547 | tf->flags |= ATA_TFLAG_WRITE; | 580 | tf->flags |= ATA_TFLAG_WRITE; |
548 | } | 581 | } |
549 | 582 | ||
583 | /* Calculate the SCSI LBA and transfer length. */ | ||
550 | if (scsicmd[0] == READ_10 || scsicmd[0] == WRITE_10) { | 584 | if (scsicmd[0] == READ_10 || scsicmd[0] == WRITE_10) { |
551 | if (lba48) { | 585 | block |= ((u64)scsicmd[2]) << 24; |
552 | tf->hob_nsect = scsicmd[7]; | 586 | block |= ((u64)scsicmd[3]) << 16; |
553 | tf->hob_lbal = scsicmd[2]; | 587 | block |= ((u64)scsicmd[4]) << 8; |
554 | 588 | block |= ((u64)scsicmd[5]); | |
555 | qc->nsect = ((unsigned int)scsicmd[7] << 8) | | ||
556 | scsicmd[8]; | ||
557 | } else { | ||
558 | /* if we don't support LBA48 addressing, the request | ||
559 | * -may- be too large. */ | ||
560 | if ((scsicmd[2] & 0xf0) || scsicmd[7]) | ||
561 | return 1; | ||
562 | |||
563 | /* stores LBA27:24 in lower 4 bits of device reg */ | ||
564 | tf->device |= scsicmd[2]; | ||
565 | 589 | ||
566 | qc->nsect = scsicmd[8]; | 590 | n_block |= ((u32)scsicmd[7]) << 8; |
567 | } | 591 | n_block |= ((u32)scsicmd[8]); |
568 | |||
569 | tf->nsect = scsicmd[8]; | ||
570 | tf->lbal = scsicmd[5]; | ||
571 | tf->lbam = scsicmd[4]; | ||
572 | tf->lbah = scsicmd[3]; | ||
573 | 592 | ||
574 | VPRINTK("ten-byte command\n"); | 593 | VPRINTK("ten-byte command\n"); |
575 | return 0; | 594 | } else if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) { |
576 | } | 595 | block |= ((u64)scsicmd[2]) << 8; |
577 | 596 | block |= ((u64)scsicmd[3]); | |
578 | if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) { | 597 | n_block |= ((u32)scsicmd[4]); |
579 | qc->nsect = tf->nsect = scsicmd[4]; | 598 | |
580 | tf->lbal = scsicmd[3]; | ||
581 | tf->lbam = scsicmd[2]; | ||
582 | tf->lbah = scsicmd[1] & 0x1f; /* mask out reserved bits */ | ||
583 | |||
584 | VPRINTK("six-byte command\n"); | 599 | VPRINTK("six-byte command\n"); |
585 | return 0; | 600 | } else if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) { |
601 | block |= ((u64)scsicmd[2]) << 56; | ||
602 | block |= ((u64)scsicmd[3]) << 48; | ||
603 | block |= ((u64)scsicmd[4]) << 40; | ||
604 | block |= ((u64)scsicmd[5]) << 32; | ||
605 | block |= ((u64)scsicmd[6]) << 24; | ||
606 | block |= ((u64)scsicmd[7]) << 16; | ||
607 | block |= ((u64)scsicmd[8]) << 8; | ||
608 | block |= ((u64)scsicmd[9]); | ||
609 | |||
610 | n_block |= ((u32)scsicmd[10]) << 24; | ||
611 | n_block |= ((u32)scsicmd[11]) << 16; | ||
612 | n_block |= ((u32)scsicmd[12]) << 8; | ||
613 | n_block |= ((u32)scsicmd[13]); | ||
614 | |||
615 | VPRINTK("sixteen-byte command\n"); | ||
616 | } else { | ||
617 | DPRINTK("no-byte command\n"); | ||
618 | return 1; | ||
586 | } | 619 | } |
587 | 620 | ||
588 | if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) { | 621 | /* Check and compose ATA command */ |
589 | /* rule out impossible LBAs and sector counts */ | 622 | if (!n_block) |
590 | if (scsicmd[2] || scsicmd[3] || scsicmd[10] || scsicmd[11]) | 623 | /* In ATA, sector count 0 means 256 or 65536 sectors, not 0 sectors. */ |
591 | return 1; | 624 | return 1; |
592 | 625 | ||
626 | if (lba) { | ||
593 | if (lba48) { | 627 | if (lba48) { |
594 | tf->hob_nsect = scsicmd[12]; | 628 | /* The request -may- be too large for LBA48. */ |
595 | tf->hob_lbal = scsicmd[6]; | 629 | if ((block >> 48) || (n_block > 65536)) |
596 | tf->hob_lbam = scsicmd[5]; | ||
597 | tf->hob_lbah = scsicmd[4]; | ||
598 | |||
599 | qc->nsect = ((unsigned int)scsicmd[12] << 8) | | ||
600 | scsicmd[13]; | ||
601 | } else { | ||
602 | /* once again, filter out impossible non-zero values */ | ||
603 | if (scsicmd[4] || scsicmd[5] || scsicmd[12] || | ||
604 | (scsicmd[6] & 0xf0)) | ||
605 | return 1; | 630 | return 1; |
606 | 631 | ||
607 | /* stores LBA27:24 in lower 4 bits of device reg */ | 632 | tf->hob_nsect = (n_block >> 8) & 0xff; |
608 | tf->device |= scsicmd[6]; | 633 | |
634 | tf->hob_lbah = (block >> 40) & 0xff; | ||
635 | tf->hob_lbam = (block >> 32) & 0xff; | ||
636 | tf->hob_lbal = (block >> 24) & 0xff; | ||
637 | } else { | ||
638 | /* LBA28 */ | ||
639 | |||
640 | /* The request -may- be too large for LBA28. */ | ||
641 | if ((block >> 28) || (n_block > 256)) | ||
642 | return 1; | ||
609 | 643 | ||
610 | qc->nsect = scsicmd[13]; | 644 | tf->device |= (block >> 24) & 0xf; |
611 | } | 645 | } |
646 | |||
647 | qc->nsect = n_block; | ||
648 | tf->nsect = n_block & 0xff; | ||
612 | 649 | ||
613 | tf->nsect = scsicmd[13]; | 650 | tf->lbah = (block >> 16) & 0xff; |
614 | tf->lbal = scsicmd[9]; | 651 | tf->lbam = (block >> 8) & 0xff; |
615 | tf->lbam = scsicmd[8]; | 652 | tf->lbal = block & 0xff; |
616 | tf->lbah = scsicmd[7]; | ||
617 | 653 | ||
618 | VPRINTK("sixteen-byte command\n"); | 654 | tf->device |= ATA_LBA; |
619 | return 0; | 655 | } else { |
656 | /* CHS */ | ||
657 | u32 sect, head, cyl, track; | ||
658 | |||
659 | /* The request -may- be too large for CHS addressing. */ | ||
660 | if ((block >> 28) || (n_block > 256)) | ||
661 | return 1; | ||
662 | |||
663 | /* Convert LBA to CHS */ | ||
664 | track = (u32)block / dev->sectors; | ||
665 | cyl = track / dev->heads; | ||
666 | head = track % dev->heads; | ||
667 | sect = (u32)block % dev->sectors + 1; | ||
668 | |||
669 | DPRINTK("block[%u] track[%u] cyl[%u] head[%u] sect[%u] \n", | ||
670 | (u32)block, track, cyl, head, sect); | ||
671 | |||
672 | /* Check whether the converted CHS can fit. | ||
673 | Cylinder: 0-65535 | ||
674 | Head: 0-15 | ||
675 | Sector: 1-255*/ | ||
676 | if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) | ||
677 | return 1; | ||
678 | |||
679 | qc->nsect = n_block; | ||
680 | tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ | ||
681 | tf->lbal = sect; | ||
682 | tf->lbam = cyl; | ||
683 | tf->lbah = cyl >> 8; | ||
684 | tf->device |= head; | ||
620 | } | 685 | } |
621 | 686 | ||
622 | DPRINTK("no-byte command\n"); | 687 | return 0; |
623 | return 1; | ||
624 | } | 688 | } |
625 | 689 | ||
626 | static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) | 690 | static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) |
@@ -1167,10 +1231,20 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, | |||
1167 | 1231 | ||
1168 | VPRINTK("ENTER\n"); | 1232 | VPRINTK("ENTER\n"); |
1169 | 1233 | ||
1170 | if (ata_id_has_lba48(args->id)) | 1234 | if (ata_id_has_lba(args->id)) { |
1171 | n_sectors = ata_id_u64(args->id, 100); | 1235 | if (ata_id_has_lba48(args->id)) |
1172 | else | 1236 | n_sectors = ata_id_u64(args->id, 100); |
1173 | n_sectors = ata_id_u32(args->id, 60); | 1237 | else |
1238 | n_sectors = ata_id_u32(args->id, 60); | ||
1239 | } else { | ||
1240 | /* CHS default translation */ | ||
1241 | n_sectors = args->id[1] * args->id[3] * args->id[6]; | ||
1242 | |||
1243 | if (ata_id_current_chs_valid(args->id)) | ||
1244 | /* CHS current translation */ | ||
1245 | n_sectors = ata_id_u32(args->id, 57); | ||
1246 | } | ||
1247 | |||
1174 | n_sectors--; /* ATA TotalUserSectors - 1 */ | 1248 | n_sectors--; /* ATA TotalUserSectors - 1 */ |
1175 | 1249 | ||
1176 | tmp = n_sectors; /* note: truncates, if lba48 */ | 1250 | tmp = n_sectors; /* note: truncates, if lba48 */ |