diff options
author | Ben Efros <ben@pc-doctor.com> | 2008-11-18 16:31:13 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-01-07 12:59:55 -0500 |
commit | 1537e0ad944acf3a4c2b311a646d7993b89499f7 (patch) | |
tree | 991031a1d14089ba4a0794806c9d702d9764941b | |
parent | a658367dae9dc572480f41817dbe1088a1a049ee (diff) |
USB: storage devices and SAT
Add the SANE SENSE flag to indicate that a device is capable of handling
more than 18-bytes of sense data. This functionality is required for
USB-ATA bridges implementing SAT. A future patch will actually enable this
function for several devices.
The logic behind this is that we can detect support for SANE_SENSE in a few ways:
1) ATA PASS THROUGH (12) or (16) execute successfully
2) SPC-3 or higher is in use
3) A previous CHECK CONDITION occurred with sense format 70-73 and had
a length greater than 18-bytes total
Signed-off-by: Ben Efros <ben@pc-doctor.com>
Signed-off-by: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/usb/storage/scsiglue.c | 4 | ||||
-rw-r--r-- | drivers/usb/storage/transport.c | 40 | ||||
-rw-r--r-- | include/linux/usb_usual.h | 5 |
3 files changed, 46 insertions, 3 deletions
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 09779f6a8179..1b35e011a34f 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c | |||
@@ -170,6 +170,10 @@ static int slave_configure(struct scsi_device *sdev) | |||
170 | if (us->fflags & US_FL_CAPACITY_HEURISTICS) | 170 | if (us->fflags & US_FL_CAPACITY_HEURISTICS) |
171 | sdev->guess_capacity = 1; | 171 | sdev->guess_capacity = 1; |
172 | 172 | ||
173 | /* assume SPC3 or latter devices support sense size > 18 */ | ||
174 | if (sdev->scsi_level > SCSI_SPC_2) | ||
175 | us->fflags |= US_FL_SANE_SENSE; | ||
176 | |||
173 | /* Some devices report a SCSI revision level above 2 but are | 177 | /* Some devices report a SCSI revision level above 2 but are |
174 | * unable to handle the REPORT LUNS command (for which | 178 | * unable to handle the REPORT LUNS command (for which |
175 | * support is mandatory at level 3). Since we already have | 179 | * support is mandatory at level 3). Since we already have |
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 2058db41618c..f584e72cc689 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c | |||
@@ -579,6 +579,20 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) | |||
579 | } | 579 | } |
580 | 580 | ||
581 | /* | 581 | /* |
582 | * Determine if this device is SAT by seeing if the | ||
583 | * command executed successfully. Otherwise we'll have | ||
584 | * to wait for at least one CHECK_CONDITION to determine | ||
585 | * SANE_SENSE support | ||
586 | */ | ||
587 | if ((srb->cmnd[0] == ATA_16 || srb->cmnd[0] == ATA_12) && | ||
588 | result == USB_STOR_TRANSPORT_GOOD && | ||
589 | !(us->fflags & US_FL_SANE_SENSE) && | ||
590 | !(srb->cmnd[2] & 0x20)) { | ||
591 | US_DEBUGP("-- SAT supported, increasing auto-sense\n"); | ||
592 | us->fflags |= US_FL_SANE_SENSE; | ||
593 | } | ||
594 | |||
595 | /* | ||
582 | * A short transfer on a command where we don't expect it | 596 | * A short transfer on a command where we don't expect it |
583 | * is unusual, but it doesn't mean we need to auto-sense. | 597 | * is unusual, but it doesn't mean we need to auto-sense. |
584 | */ | 598 | */ |
@@ -595,10 +609,15 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) | |||
595 | if (need_auto_sense) { | 609 | if (need_auto_sense) { |
596 | int temp_result; | 610 | int temp_result; |
597 | struct scsi_eh_save ses; | 611 | struct scsi_eh_save ses; |
612 | int sense_size = US_SENSE_SIZE; | ||
613 | |||
614 | /* device supports and needs bigger sense buffer */ | ||
615 | if (us->fflags & US_FL_SANE_SENSE) | ||
616 | sense_size = ~0; | ||
598 | 617 | ||
599 | US_DEBUGP("Issuing auto-REQUEST_SENSE\n"); | 618 | US_DEBUGP("Issuing auto-REQUEST_SENSE\n"); |
600 | 619 | ||
601 | scsi_eh_prep_cmnd(srb, &ses, NULL, 0, US_SENSE_SIZE); | 620 | scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sense_size); |
602 | 621 | ||
603 | /* FIXME: we must do the protocol translation here */ | 622 | /* FIXME: we must do the protocol translation here */ |
604 | if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI || | 623 | if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI || |
@@ -632,6 +651,25 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) | |||
632 | return; | 651 | return; |
633 | } | 652 | } |
634 | 653 | ||
654 | /* If the sense data returned is larger than 18-bytes then we | ||
655 | * assume this device supports requesting more in the future. | ||
656 | * The response code must be 70h through 73h inclusive. | ||
657 | */ | ||
658 | if (srb->sense_buffer[7] > (US_SENSE_SIZE - 8) && | ||
659 | !(us->fflags & US_FL_SANE_SENSE) && | ||
660 | (srb->sense_buffer[0] & 0x7C) == 0x70) { | ||
661 | US_DEBUGP("-- SANE_SENSE support enabled\n"); | ||
662 | us->fflags |= US_FL_SANE_SENSE; | ||
663 | |||
664 | /* Indicate to the user that we truncated their sense | ||
665 | * because we didn't know it supported larger sense. | ||
666 | */ | ||
667 | US_DEBUGP("-- Sense data truncated to %i from %i\n", | ||
668 | US_SENSE_SIZE, | ||
669 | srb->sense_buffer[7] + 8); | ||
670 | srb->sense_buffer[7] = (US_SENSE_SIZE - 8); | ||
671 | } | ||
672 | |||
635 | US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); | 673 | US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); |
636 | US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", | 674 | US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", |
637 | srb->sense_buffer[0], | 675 | srb->sense_buffer[0], |
diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h index d9a3bbe38e6b..998e5cbbf29e 100644 --- a/include/linux/usb_usual.h +++ b/include/linux/usb_usual.h | |||
@@ -52,8 +52,9 @@ | |||
52 | US_FLAG(MAX_SECTORS_MIN,0x00002000) \ | 52 | US_FLAG(MAX_SECTORS_MIN,0x00002000) \ |
53 | /* Sets max_sectors to arch min */ \ | 53 | /* Sets max_sectors to arch min */ \ |
54 | US_FLAG(BULK_IGNORE_TAG,0x00004000) \ | 54 | US_FLAG(BULK_IGNORE_TAG,0x00004000) \ |
55 | /* Ignore tag mismatch in bulk operations */ | 55 | /* Ignore tag mismatch in bulk operations */ \ |
56 | 56 | US_FLAG(SANE_SENSE, 0x00008000) | |
57 | /* Sane Sense (> 18 bytes) */ | ||
57 | 58 | ||
58 | #define US_FLAG(name, value) US_FL_##name = value , | 59 | #define US_FLAG(name, value) US_FL_##name = value , |
59 | enum { US_DO_ALL_FLAGS }; | 60 | enum { US_DO_ALL_FLAGS }; |