Change default value of max_report_luns to 16k-1.

Use data returned from max report luns command to configure the number
of logical units present if previous default of 511 isn't enough.

Signed-off-by: Rob Evers <rev...@redhat.com>
---
 drivers/scsi/scsi_scan.c | 79 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 58 insertions(+), 21 deletions(-)

diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index b2abf22..0f7ce45 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -109,12 +109,13 @@ MODULE_PARM_DESC(scan, "sync, async or none");
  * in practice, the maximum number of LUNs suppored by any device
  * is about 16k.
  */
-static unsigned int max_scsi_report_luns = 511;
+static unsigned int max_scsi_report_luns = 16383;
 
 module_param_named(max_report_luns, max_scsi_report_luns, uint, 
S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(max_report_luns,
                 "REPORT LUNS maximum number of LUNS received (should be"
-                " between 1 and 16384)");
+                " between 1 and 16383)");
+#define INITIAL_MAX_REPORT_LUNS 511
 
 static unsigned int scsi_inq_timeout = SCSI_TIMEOUT/HZ + 18;
 
@@ -1366,9 +1367,10 @@ static int scsi_report_lun_scan(struct scsi_target 
*starget, int bflags,
        char devname[64];
        unsigned int length;
        unsigned int lun;
-       unsigned int num_luns;
+       unsigned int num_luns, num_luns_reported;
        int result;
        struct scsi_lun *lunp, *lun_data;
+       struct scsi_lun *first_lun_data, *second_lun_data;
        u8 *data;
        struct scsi_device *sdev;
        struct Scsi_Host *shost = dev_to_shost(&starget->dev);
@@ -1409,45 +1411,80 @@ static int scsi_report_lun_scan(struct scsi_target 
*starget, int bflags,
        /*
         * Allocate enough to hold the header (the same size as one scsi_lun)
         * plus the max number of luns we are requesting.
-        *
-        * Reallocating and trying again (with the exact amount we need)
-        * would be nice, but then we need to somehow limit the size
-        * allocated based on the available memory and the limits of
-        * kmalloc - we don't want a kmalloc() failure of a huge value to
-        * prevent us from finding any LUNs on this target.
         */
-       length = (max_scsi_report_luns + 1) * sizeof(struct scsi_lun);
-       lun_data = kmalloc(length, GFP_ATOMIC |
-                          (sdev->host->unchecked_isa_dma ? __GFP_DMA : 0));
-       if (!lun_data) {
+       if (max_scsi_report_luns > INITIAL_MAX_REPORT_LUNS)
+               length = (INITIAL_MAX_REPORT_LUNS + 1) *
+                       sizeof(struct scsi_lun);
+       else
+               length = (max_scsi_report_luns + 1) *
+                       sizeof(struct scsi_lun);
+
+       first_lun_data = kmalloc(length, GFP_ATOMIC |
+                                (sdev->host->unchecked_isa_dma ?
+                                __GFP_DMA : 0));
+       if (!first_lun_data) {
                printk(ALLOC_FAILURE_MSG, __func__);
                goto out;
        }
 
-       result = scsi_do_report_luns(sdev, length, lun_data, devname);
+       result = scsi_do_report_luns(sdev, length, first_lun_data, devname);
 
        if (result) {
                /*
                 * The device probably does not support a REPORT LUN command
                 */
+               lun_data = first_lun_data;
                ret = 1;
                goto out_err;
        }
 
        /*
-        * Get the length from the first four bytes of lun_data.
+        * Get the length from the first four bytes of first_lun_data.
         */
-       data = (u8 *) lun_data->scsi_lun;
+       data = (u8 *) first_lun_data->scsi_lun;
        length = ((data[0] << 24) | (data[1] << 16) |
                  (data[2] << 8) | (data[3] << 0));
 
-       num_luns = (length / sizeof(struct scsi_lun));
-       if (num_luns > max_scsi_report_luns) {
+       num_luns_reported = (length / sizeof(struct scsi_lun));
+
+       if (num_luns_reported > max_scsi_report_luns) {
+               num_luns = max_scsi_report_luns;
+               length = num_luns * sizeof(struct scsi_lun);
                printk(KERN_WARNING "scsi: On %s only %d (max_scsi_report_luns)"
                       " of %d luns reported, try increasing"
-                      " max_scsi_report_luns.\n", devname,
-                      max_scsi_report_luns, num_luns);
-               num_luns = max_scsi_report_luns;
+                      " max_report_luns parameter.\n", devname,
+                      max_scsi_report_luns, num_luns_reported);
+       } else {
+               num_luns = num_luns_reported;
+       }
+
+       if (num_luns > INITIAL_MAX_REPORT_LUNS) {
+               /*
+                * add one for the header
+                */
+               length = length + sizeof(struct scsi_lun);
+               second_lun_data = kmalloc(length, GFP_ATOMIC |
+                                         (sdev->host->unchecked_isa_dma ?
+                                         __GFP_DMA : 0));
+               if (!second_lun_data) {
+                       num_luns = INITIAL_MAX_REPORT_LUNS;
+                       lun_data = first_lun_data;
+                       printk(ALLOC_FAILURE_MSG, __func__);
+                       printk(KERN_WARNING "scsi: On %s %d of %d luns 
reported.\n",
+                              devname, num_luns,
+                              num_luns_reported);
+               } else {
+                       kfree(first_lun_data);
+                       lun_data = second_lun_data;
+                       result = scsi_do_report_luns(sdev, length,
+                                                    lun_data, devname);
+                       if (result) {
+                               ret = 1;
+                               goto out_err;
+                       }
+               }
+       } else {
+               lun_data = first_lun_data;
        }
 
        SCSI_LOG_SCAN_BUS(3, sdev_printk (KERN_INFO, sdev,
-- 
1.7.11.7

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to