diff options
Diffstat (limited to 'drivers/scsi/scsi_scan.c')
-rw-r--r-- | drivers/scsi/scsi_scan.c | 146 |
1 files changed, 77 insertions, 69 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 1bd92b9b46d9..fd9e281c3bfe 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c | |||
@@ -134,59 +134,6 @@ static void scsi_unlock_floptical(struct scsi_device *sdev, | |||
134 | } | 134 | } |
135 | 135 | ||
136 | /** | 136 | /** |
137 | * print_inquiry - printk the inquiry information | ||
138 | * @inq_result: printk this SCSI INQUIRY | ||
139 | * | ||
140 | * Description: | ||
141 | * printk the vendor, model, and other information found in the | ||
142 | * INQUIRY data in @inq_result. | ||
143 | * | ||
144 | * Notes: | ||
145 | * Remove this, and replace with a hotplug event that logs any | ||
146 | * relevant information. | ||
147 | **/ | ||
148 | static void print_inquiry(unsigned char *inq_result) | ||
149 | { | ||
150 | int i; | ||
151 | |||
152 | printk(KERN_NOTICE " Vendor: "); | ||
153 | for (i = 8; i < 16; i++) | ||
154 | if (inq_result[i] >= 0x20 && i < inq_result[4] + 5) | ||
155 | printk("%c", inq_result[i]); | ||
156 | else | ||
157 | printk(" "); | ||
158 | |||
159 | printk(" Model: "); | ||
160 | for (i = 16; i < 32; i++) | ||
161 | if (inq_result[i] >= 0x20 && i < inq_result[4] + 5) | ||
162 | printk("%c", inq_result[i]); | ||
163 | else | ||
164 | printk(" "); | ||
165 | |||
166 | printk(" Rev: "); | ||
167 | for (i = 32; i < 36; i++) | ||
168 | if (inq_result[i] >= 0x20 && i < inq_result[4] + 5) | ||
169 | printk("%c", inq_result[i]); | ||
170 | else | ||
171 | printk(" "); | ||
172 | |||
173 | printk("\n"); | ||
174 | |||
175 | i = inq_result[0] & 0x1f; | ||
176 | |||
177 | printk(KERN_NOTICE " Type: %s ", | ||
178 | i < | ||
179 | MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] : | ||
180 | "Unknown "); | ||
181 | printk(" ANSI SCSI revision: %02x", | ||
182 | inq_result[2] & 0x07); | ||
183 | if ((inq_result[2] & 0x07) == 1 && (inq_result[3] & 0x0f) == 1) | ||
184 | printk(" CCS\n"); | ||
185 | else | ||
186 | printk("\n"); | ||
187 | } | ||
188 | |||
189 | /** | ||
190 | * scsi_alloc_sdev - allocate and setup a scsi_Device | 137 | * scsi_alloc_sdev - allocate and setup a scsi_Device |
191 | * | 138 | * |
192 | * Description: | 139 | * Description: |
@@ -319,6 +266,18 @@ static struct scsi_target *__scsi_find_target(struct device *parent, | |||
319 | return found_starget; | 266 | return found_starget; |
320 | } | 267 | } |
321 | 268 | ||
269 | /** | ||
270 | * scsi_alloc_target - allocate a new or find an existing target | ||
271 | * @parent: parent of the target (need not be a scsi host) | ||
272 | * @channel: target channel number (zero if no channels) | ||
273 | * @id: target id number | ||
274 | * | ||
275 | * Return an existing target if one exists, provided it hasn't already | ||
276 | * gone into STARGET_DEL state, otherwise allocate a new target. | ||
277 | * | ||
278 | * The target is returned with an incremented reference, so the caller | ||
279 | * is responsible for both reaping and doing a last put | ||
280 | */ | ||
322 | static struct scsi_target *scsi_alloc_target(struct device *parent, | 281 | static struct scsi_target *scsi_alloc_target(struct device *parent, |
323 | int channel, uint id) | 282 | int channel, uint id) |
324 | { | 283 | { |
@@ -384,14 +343,15 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
384 | return NULL; | 343 | return NULL; |
385 | } | 344 | } |
386 | } | 345 | } |
346 | get_device(dev); | ||
387 | 347 | ||
388 | return starget; | 348 | return starget; |
389 | 349 | ||
390 | found: | 350 | found: |
391 | found_target->reap_ref++; | 351 | found_target->reap_ref++; |
392 | spin_unlock_irqrestore(shost->host_lock, flags); | 352 | spin_unlock_irqrestore(shost->host_lock, flags); |
393 | put_device(parent); | ||
394 | if (found_target->state != STARGET_DEL) { | 353 | if (found_target->state != STARGET_DEL) { |
354 | put_device(parent); | ||
395 | kfree(starget); | 355 | kfree(starget); |
396 | return found_target; | 356 | return found_target; |
397 | } | 357 | } |
@@ -450,6 +410,32 @@ void scsi_target_reap(struct scsi_target *starget) | |||
450 | } | 410 | } |
451 | 411 | ||
452 | /** | 412 | /** |
413 | * sanitize_inquiry_string - remove non-graphical chars from an INQUIRY result string | ||
414 | * @s: INQUIRY result string to sanitize | ||
415 | * @len: length of the string | ||
416 | * | ||
417 | * Description: | ||
418 | * The SCSI spec says that INQUIRY vendor, product, and revision | ||
419 | * strings must consist entirely of graphic ASCII characters, | ||
420 | * padded on the right with spaces. Since not all devices obey | ||
421 | * this rule, we will replace non-graphic or non-ASCII characters | ||
422 | * with spaces. Exception: a NUL character is interpreted as a | ||
423 | * string terminator, so all the following characters are set to | ||
424 | * spaces. | ||
425 | **/ | ||
426 | static void sanitize_inquiry_string(unsigned char *s, int len) | ||
427 | { | ||
428 | int terminated = 0; | ||
429 | |||
430 | for (; len > 0; (--len, ++s)) { | ||
431 | if (*s == 0) | ||
432 | terminated = 1; | ||
433 | if (terminated || *s < 0x20 || *s > 0x7e) | ||
434 | *s = ' '; | ||
435 | } | ||
436 | } | ||
437 | |||
438 | /** | ||
453 | * scsi_probe_lun - probe a single LUN using a SCSI INQUIRY | 439 | * scsi_probe_lun - probe a single LUN using a SCSI INQUIRY |
454 | * @sdev: scsi_device to probe | 440 | * @sdev: scsi_device to probe |
455 | * @inq_result: area to store the INQUIRY result | 441 | * @inq_result: area to store the INQUIRY result |
@@ -463,7 +449,7 @@ void scsi_target_reap(struct scsi_target *starget) | |||
463 | * INQUIRY data is in @inq_result; the scsi_level and INQUIRY length | 449 | * INQUIRY data is in @inq_result; the scsi_level and INQUIRY length |
464 | * are copied to the scsi_device any flags value is stored in *@bflags. | 450 | * are copied to the scsi_device any flags value is stored in *@bflags. |
465 | **/ | 451 | **/ |
466 | static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result, | 452 | static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, |
467 | int result_len, int *bflags) | 453 | int result_len, int *bflags) |
468 | { | 454 | { |
469 | unsigned char scsi_cmd[MAX_COMMAND_SIZE]; | 455 | unsigned char scsi_cmd[MAX_COMMAND_SIZE]; |
@@ -522,7 +508,11 @@ static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result, | |||
522 | } | 508 | } |
523 | 509 | ||
524 | if (result == 0) { | 510 | if (result == 0) { |
525 | response_len = (unsigned char) inq_result[4] + 5; | 511 | sanitize_inquiry_string(&inq_result[8], 8); |
512 | sanitize_inquiry_string(&inq_result[16], 16); | ||
513 | sanitize_inquiry_string(&inq_result[32], 4); | ||
514 | |||
515 | response_len = inq_result[4] + 5; | ||
526 | if (response_len > 255) | 516 | if (response_len > 255) |
527 | response_len = first_inquiry_len; /* sanity */ | 517 | response_len = first_inquiry_len; /* sanity */ |
528 | 518 | ||
@@ -628,7 +618,8 @@ static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result, | |||
628 | * SCSI_SCAN_NO_RESPONSE: could not allocate or setup a scsi_device | 618 | * SCSI_SCAN_NO_RESPONSE: could not allocate or setup a scsi_device |
629 | * SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized | 619 | * SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized |
630 | **/ | 620 | **/ |
631 | static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags) | 621 | static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, |
622 | int *bflags) | ||
632 | { | 623 | { |
633 | /* | 624 | /* |
634 | * XXX do not save the inquiry, since it can change underneath us, | 625 | * XXX do not save the inquiry, since it can change underneath us, |
@@ -653,9 +644,8 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags) | |||
653 | if (*bflags & BLIST_ISROM) { | 644 | if (*bflags & BLIST_ISROM) { |
654 | /* | 645 | /* |
655 | * It would be better to modify sdev->type, and set | 646 | * It would be better to modify sdev->type, and set |
656 | * sdev->removable, but then the print_inquiry() output | 647 | * sdev->removable; this can now be done since |
657 | * would not show TYPE_ROM; if print_inquiry() is removed | 648 | * print_inquiry has gone away. |
658 | * the issue goes away. | ||
659 | */ | 649 | */ |
660 | inq_result[0] = TYPE_ROM; | 650 | inq_result[0] = TYPE_ROM; |
661 | inq_result[1] |= 0x80; /* removable */ | 651 | inq_result[1] |= 0x80; /* removable */ |
@@ -684,8 +674,6 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags) | |||
684 | printk(KERN_INFO "scsi: unknown device type %d\n", sdev->type); | 674 | printk(KERN_INFO "scsi: unknown device type %d\n", sdev->type); |
685 | } | 675 | } |
686 | 676 | ||
687 | print_inquiry(inq_result); | ||
688 | |||
689 | /* | 677 | /* |
690 | * For a peripheral qualifier (PQ) value of 1 (001b), the SCSI | 678 | * For a peripheral qualifier (PQ) value of 1 (001b), the SCSI |
691 | * spec says: The device server is capable of supporting the | 679 | * spec says: The device server is capable of supporting the |
@@ -715,6 +703,12 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags) | |||
715 | if (inq_result[7] & 0x10) | 703 | if (inq_result[7] & 0x10) |
716 | sdev->sdtr = 1; | 704 | sdev->sdtr = 1; |
717 | 705 | ||
706 | sdev_printk(KERN_NOTICE, sdev, "%s %.8s %.16s %.4s PQ: %d " | ||
707 | "ANSI: %d%s\n", scsi_device_type(sdev->type), | ||
708 | sdev->vendor, sdev->model, sdev->rev, | ||
709 | sdev->inq_periph_qual, inq_result[2] & 0x07, | ||
710 | (inq_result[3] & 0x0f) == 1 ? " CCS" : ""); | ||
711 | |||
718 | /* | 712 | /* |
719 | * End sysfs code. | 713 | * End sysfs code. |
720 | */ | 714 | */ |
@@ -943,11 +937,26 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, | |||
943 | } | 937 | } |
944 | 938 | ||
945 | /* | 939 | /* |
946 | * Non-standard SCSI targets may set the PDT to 0x1f (unknown or | 940 | * Some targets may set slight variations of PQ and PDT to signal |
947 | * no device type) instead of using the Peripheral Qualifier to | 941 | * that no LUN is present, so don't add sdev in these cases. |
948 | * indicate that no LUN is present. For example, USB UFI does this. | 942 | * Two specific examples are: |
943 | * 1) NetApp targets: return PQ=1, PDT=0x1f | ||
944 | * 2) USB UFI: returns PDT=0x1f, with the PQ bits being "reserved" | ||
945 | * in the UFI 1.0 spec (we cannot rely on reserved bits). | ||
946 | * | ||
947 | * References: | ||
948 | * 1) SCSI SPC-3, pp. 145-146 | ||
949 | * PQ=1: "A peripheral device having the specified peripheral | ||
950 | * device type is not connected to this logical unit. However, the | ||
951 | * device server is capable of supporting the specified peripheral | ||
952 | * device type on this logical unit." | ||
953 | * PDT=0x1f: "Unknown or no device type" | ||
954 | * 2) USB UFI 1.0, p. 20 | ||
955 | * PDT=00h Direct-access device (floppy) | ||
956 | * PDT=1Fh none (no FDD connected to the requested logical unit) | ||
949 | */ | 957 | */ |
950 | if (starget->pdt_1f_for_no_lun && (result[0] & 0x1f) == 0x1f) { | 958 | if (((result[0] >> 5) == 1 || starget->pdt_1f_for_no_lun) && |
959 | (result[0] & 0x1f) == 0x1f) { | ||
951 | SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO | 960 | SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO |
952 | "scsi scan: peripheral device type" | 961 | "scsi scan: peripheral device type" |
953 | " of 31, no device added\n")); | 962 | " of 31, no device added\n")); |
@@ -1345,7 +1354,6 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel, | |||
1345 | if (!starget) | 1354 | if (!starget) |
1346 | return ERR_PTR(-ENOMEM); | 1355 | return ERR_PTR(-ENOMEM); |
1347 | 1356 | ||
1348 | get_device(&starget->dev); | ||
1349 | mutex_lock(&shost->scan_mutex); | 1357 | mutex_lock(&shost->scan_mutex); |
1350 | if (scsi_host_scan_allowed(shost)) | 1358 | if (scsi_host_scan_allowed(shost)) |
1351 | scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); | 1359 | scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); |
@@ -1404,7 +1412,6 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel, | |||
1404 | if (!starget) | 1412 | if (!starget) |
1405 | return; | 1413 | return; |
1406 | 1414 | ||
1407 | get_device(&starget->dev); | ||
1408 | if (lun != SCAN_WILD_CARD) { | 1415 | if (lun != SCAN_WILD_CARD) { |
1409 | /* | 1416 | /* |
1410 | * Scan for a specific host/chan/id/lun. | 1417 | * Scan for a specific host/chan/id/lun. |
@@ -1586,7 +1593,8 @@ struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost) | |||
1586 | if (sdev) { | 1593 | if (sdev) { |
1587 | sdev->sdev_gendev.parent = get_device(&starget->dev); | 1594 | sdev->sdev_gendev.parent = get_device(&starget->dev); |
1588 | sdev->borken = 0; | 1595 | sdev->borken = 0; |
1589 | } | 1596 | } else |
1597 | scsi_target_reap(starget); | ||
1590 | put_device(&starget->dev); | 1598 | put_device(&starget->dev); |
1591 | out: | 1599 | out: |
1592 | mutex_unlock(&shost->scan_mutex); | 1600 | mutex_unlock(&shost->scan_mutex); |