diff options
author | James Bottomley <James.Bottomley@steeleye.com> | 2005-09-22 21:33:28 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.(none)> | 2005-09-25 13:01:48 -0400 |
commit | 6f3a20242db2597312c50abc11f1e747c5d2326a (patch) | |
tree | edfc17cfd7e1813dbe728602f80630cfab985c20 /drivers/scsi/scsi_scan.c | |
parent | 49bfd8db4a39ea14fb3780b162012b4b3611fce8 (diff) |
[SCSI] allow REPORT LUN scanning even for LUN 0 PQ of 3
Currently we just ignore the device, which means there are a few
arrays out there that we don't find.
This patch updates the scsi_report_lun_scan() to take a target instead
of a device so it can be called on a return of
SCSI_SCAN_TARGET_PRESENT, which is what a PQ 3 device returns.
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/scsi_scan.c')
-rw-r--r-- | drivers/scsi/scsi_scan.c | 96 |
1 files changed, 47 insertions, 49 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index fcf9f6cbb142..327c5d7e5bd2 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c | |||
@@ -587,6 +587,7 @@ static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result, | |||
587 | if (sdev->scsi_level >= 2 || | 587 | if (sdev->scsi_level >= 2 || |
588 | (sdev->scsi_level == 1 && (inq_result[3] & 0x0f) == 1)) | 588 | (sdev->scsi_level == 1 && (inq_result[3] & 0x0f) == 1)) |
589 | sdev->scsi_level++; | 589 | sdev->scsi_level++; |
590 | sdev->sdev_target->scsi_level = sdev->scsi_level; | ||
590 | 591 | ||
591 | return 0; | 592 | return 0; |
592 | } | 593 | } |
@@ -771,6 +772,15 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags) | |||
771 | return SCSI_SCAN_LUN_PRESENT; | 772 | return SCSI_SCAN_LUN_PRESENT; |
772 | } | 773 | } |
773 | 774 | ||
775 | static inline void scsi_destroy_sdev(struct scsi_device *sdev) | ||
776 | { | ||
777 | if (sdev->host->hostt->slave_destroy) | ||
778 | sdev->host->hostt->slave_destroy(sdev); | ||
779 | transport_destroy_device(&sdev->sdev_gendev); | ||
780 | put_device(&sdev->sdev_gendev); | ||
781 | } | ||
782 | |||
783 | |||
774 | /** | 784 | /** |
775 | * scsi_probe_and_add_lun - probe a LUN, if a LUN is found add it | 785 | * scsi_probe_and_add_lun - probe a LUN, if a LUN is found add it |
776 | * @starget: pointer to target device structure | 786 | * @starget: pointer to target device structure |
@@ -803,9 +813,9 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, | |||
803 | * The rescan flag is used as an optimization, the first scan of a | 813 | * The rescan flag is used as an optimization, the first scan of a |
804 | * host adapter calls into here with rescan == 0. | 814 | * host adapter calls into here with rescan == 0. |
805 | */ | 815 | */ |
806 | if (rescan) { | 816 | sdev = scsi_device_lookup_by_target(starget, lun); |
807 | sdev = scsi_device_lookup_by_target(starget, lun); | 817 | if (sdev) { |
808 | if (sdev) { | 818 | if (rescan || sdev->sdev_state != SDEV_CREATED) { |
809 | SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO | 819 | SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO |
810 | "scsi scan: device exists on %s\n", | 820 | "scsi scan: device exists on %s\n", |
811 | sdev->sdev_gendev.bus_id)); | 821 | sdev->sdev_gendev.bus_id)); |
@@ -820,9 +830,9 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, | |||
820 | sdev->model); | 830 | sdev->model); |
821 | return SCSI_SCAN_LUN_PRESENT; | 831 | return SCSI_SCAN_LUN_PRESENT; |
822 | } | 832 | } |
823 | } | 833 | scsi_device_put(sdev); |
824 | 834 | } else | |
825 | sdev = scsi_alloc_sdev(starget, lun, hostdata); | 835 | sdev = scsi_alloc_sdev(starget, lun, hostdata); |
826 | if (!sdev) | 836 | if (!sdev) |
827 | goto out; | 837 | goto out; |
828 | 838 | ||
@@ -877,12 +887,8 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, | |||
877 | res = SCSI_SCAN_NO_RESPONSE; | 887 | res = SCSI_SCAN_NO_RESPONSE; |
878 | } | 888 | } |
879 | } | 889 | } |
880 | } else { | 890 | } else |
881 | if (sdev->host->hostt->slave_destroy) | 891 | scsi_destroy_sdev(sdev); |
882 | sdev->host->hostt->slave_destroy(sdev); | ||
883 | transport_destroy_device(&sdev->sdev_gendev); | ||
884 | put_device(&sdev->sdev_gendev); | ||
885 | } | ||
886 | out: | 892 | out: |
887 | return res; | 893 | return res; |
888 | } | 894 | } |
@@ -1054,7 +1060,7 @@ EXPORT_SYMBOL(int_to_scsilun); | |||
1054 | * 0: scan completed (or no memory, so further scanning is futile) | 1060 | * 0: scan completed (or no memory, so further scanning is futile) |
1055 | * 1: no report lun scan, or not configured | 1061 | * 1: no report lun scan, or not configured |
1056 | **/ | 1062 | **/ |
1057 | static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, | 1063 | static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, |
1058 | int rescan) | 1064 | int rescan) |
1059 | { | 1065 | { |
1060 | char devname[64]; | 1066 | char devname[64]; |
@@ -1067,7 +1073,8 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, | |||
1067 | struct scsi_lun *lunp, *lun_data; | 1073 | struct scsi_lun *lunp, *lun_data; |
1068 | u8 *data; | 1074 | u8 *data; |
1069 | struct scsi_sense_hdr sshdr; | 1075 | struct scsi_sense_hdr sshdr; |
1070 | struct scsi_target *starget = scsi_target(sdev); | 1076 | struct scsi_device *sdev; |
1077 | struct Scsi_Host *shost = dev_to_shost(&starget->dev); | ||
1071 | 1078 | ||
1072 | /* | 1079 | /* |
1073 | * Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set. | 1080 | * Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set. |
@@ -1075,15 +1082,23 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, | |||
1075 | * support more than 8 LUNs. | 1082 | * support more than 8 LUNs. |
1076 | */ | 1083 | */ |
1077 | if ((bflags & BLIST_NOREPORTLUN) || | 1084 | if ((bflags & BLIST_NOREPORTLUN) || |
1078 | sdev->scsi_level < SCSI_2 || | 1085 | starget->scsi_level < SCSI_2 || |
1079 | (sdev->scsi_level < SCSI_3 && | 1086 | (starget->scsi_level < SCSI_3 && |
1080 | (!(bflags & BLIST_REPORTLUN2) || sdev->host->max_lun <= 8)) ) | 1087 | (!(bflags & BLIST_REPORTLUN2) || shost->max_lun <= 8)) ) |
1081 | return 1; | 1088 | return 1; |
1082 | if (bflags & BLIST_NOLUN) | 1089 | if (bflags & BLIST_NOLUN) |
1083 | return 0; | 1090 | return 0; |
1084 | 1091 | ||
1092 | if (!(sdev = scsi_device_lookup_by_target(starget, 0))) { | ||
1093 | sdev = scsi_alloc_sdev(starget, 0, NULL); | ||
1094 | if (!sdev) | ||
1095 | return 0; | ||
1096 | if (scsi_device_get(sdev)) | ||
1097 | return 0; | ||
1098 | } | ||
1099 | |||
1085 | sprintf(devname, "host %d channel %d id %d", | 1100 | sprintf(devname, "host %d channel %d id %d", |
1086 | sdev->host->host_no, sdev->channel, sdev->id); | 1101 | shost->host_no, sdev->channel, sdev->id); |
1087 | 1102 | ||
1088 | /* | 1103 | /* |
1089 | * Allocate enough to hold the header (the same size as one scsi_lun) | 1104 | * Allocate enough to hold the header (the same size as one scsi_lun) |
@@ -1098,8 +1113,10 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, | |||
1098 | length = (max_scsi_report_luns + 1) * sizeof(struct scsi_lun); | 1113 | length = (max_scsi_report_luns + 1) * sizeof(struct scsi_lun); |
1099 | lun_data = kmalloc(length, GFP_ATOMIC | | 1114 | lun_data = kmalloc(length, GFP_ATOMIC | |
1100 | (sdev->host->unchecked_isa_dma ? __GFP_DMA : 0)); | 1115 | (sdev->host->unchecked_isa_dma ? __GFP_DMA : 0)); |
1101 | if (!lun_data) | 1116 | if (!lun_data) { |
1117 | printk(ALLOC_FAILURE_MSG, __FUNCTION__); | ||
1102 | goto out; | 1118 | goto out; |
1119 | } | ||
1103 | 1120 | ||
1104 | scsi_cmd[0] = REPORT_LUNS; | 1121 | scsi_cmd[0] = REPORT_LUNS; |
1105 | 1122 | ||
@@ -1201,10 +1218,6 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, | |||
1201 | for (i = 0; i < sizeof(struct scsi_lun); i++) | 1218 | for (i = 0; i < sizeof(struct scsi_lun); i++) |
1202 | printk("%02x", data[i]); | 1219 | printk("%02x", data[i]); |
1203 | printk(" has a LUN larger than currently supported.\n"); | 1220 | printk(" has a LUN larger than currently supported.\n"); |
1204 | } else if (lun == 0) { | ||
1205 | /* | ||
1206 | * LUN 0 has already been scanned. | ||
1207 | */ | ||
1208 | } else if (lun > sdev->host->max_lun) { | 1221 | } else if (lun > sdev->host->max_lun) { |
1209 | printk(KERN_WARNING "scsi: %s lun%d has a LUN larger" | 1222 | printk(KERN_WARNING "scsi: %s lun%d has a LUN larger" |
1210 | " than allowed by the host adapter\n", | 1223 | " than allowed by the host adapter\n", |
@@ -1227,13 +1240,13 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, | |||
1227 | } | 1240 | } |
1228 | 1241 | ||
1229 | kfree(lun_data); | 1242 | kfree(lun_data); |
1230 | return 0; | ||
1231 | |||
1232 | out: | 1243 | out: |
1233 | /* | 1244 | scsi_device_put(sdev); |
1234 | * We are out of memory, don't try scanning any further. | 1245 | if (sdev->sdev_state == SDEV_CREATED) |
1235 | */ | 1246 | /* |
1236 | printk(ALLOC_FAILURE_MSG, __FUNCTION__); | 1247 | * the sdev we used didn't appear in the report luns scan |
1248 | */ | ||
1249 | scsi_destroy_sdev(sdev); | ||
1237 | return 0; | 1250 | return 0; |
1238 | } | 1251 | } |
1239 | 1252 | ||
@@ -1299,7 +1312,6 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel, | |||
1299 | struct Scsi_Host *shost = dev_to_shost(parent); | 1312 | struct Scsi_Host *shost = dev_to_shost(parent); |
1300 | int bflags = 0; | 1313 | int bflags = 0; |
1301 | int res; | 1314 | int res; |
1302 | struct scsi_device *sdev = NULL; | ||
1303 | struct scsi_target *starget; | 1315 | struct scsi_target *starget; |
1304 | 1316 | ||
1305 | if (shost->this_id == id) | 1317 | if (shost->this_id == id) |
@@ -1325,27 +1337,16 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel, | |||
1325 | * Scan LUN 0, if there is some response, scan further. Ideally, we | 1337 | * Scan LUN 0, if there is some response, scan further. Ideally, we |
1326 | * would not configure LUN 0 until all LUNs are scanned. | 1338 | * would not configure LUN 0 until all LUNs are scanned. |
1327 | */ | 1339 | */ |
1328 | res = scsi_probe_and_add_lun(starget, 0, &bflags, &sdev, rescan, NULL); | 1340 | res = scsi_probe_and_add_lun(starget, 0, &bflags, NULL, rescan, NULL); |
1329 | if (res == SCSI_SCAN_LUN_PRESENT) { | 1341 | if (res == SCSI_SCAN_LUN_PRESENT || res == SCSI_SCAN_TARGET_PRESENT) { |
1330 | if (scsi_report_lun_scan(sdev, bflags, rescan) != 0) | 1342 | if (scsi_report_lun_scan(starget, bflags, rescan) != 0) |
1331 | /* | 1343 | /* |
1332 | * The REPORT LUN did not scan the target, | 1344 | * The REPORT LUN did not scan the target, |
1333 | * do a sequential scan. | 1345 | * do a sequential scan. |
1334 | */ | 1346 | */ |
1335 | scsi_sequential_lun_scan(starget, bflags, | 1347 | scsi_sequential_lun_scan(starget, bflags, |
1336 | res, sdev->scsi_level, rescan); | 1348 | res, starget->scsi_level, rescan); |
1337 | } else if (res == SCSI_SCAN_TARGET_PRESENT) { | ||
1338 | /* | ||
1339 | * There's a target here, but lun 0 is offline so we | ||
1340 | * can't use the report_lun scan. Fall back to a | ||
1341 | * sequential lun scan with a bflags of SPARSELUN and | ||
1342 | * a default scsi level of SCSI_2 | ||
1343 | */ | ||
1344 | scsi_sequential_lun_scan(starget, BLIST_SPARSELUN, | ||
1345 | SCSI_SCAN_TARGET_PRESENT, SCSI_2, rescan); | ||
1346 | } | 1349 | } |
1347 | if (sdev) | ||
1348 | scsi_device_put(sdev); | ||
1349 | 1350 | ||
1350 | out_reap: | 1351 | out_reap: |
1351 | /* now determine if the target has any children at all | 1352 | /* now determine if the target has any children at all |
@@ -1542,10 +1543,7 @@ void scsi_free_host_dev(struct scsi_device *sdev) | |||
1542 | { | 1543 | { |
1543 | BUG_ON(sdev->id != sdev->host->this_id); | 1544 | BUG_ON(sdev->id != sdev->host->this_id); |
1544 | 1545 | ||
1545 | if (sdev->host->hostt->slave_destroy) | 1546 | scsi_destroy_sdev(sdev); |
1546 | sdev->host->hostt->slave_destroy(sdev); | ||
1547 | transport_destroy_device(&sdev->sdev_gendev); | ||
1548 | put_device(&sdev->sdev_gendev); | ||
1549 | } | 1547 | } |
1550 | EXPORT_SYMBOL(scsi_free_host_dev); | 1548 | EXPORT_SYMBOL(scsi_free_host_dev); |
1551 | 1549 | ||