]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] Report Luns for scsi devices 2.5.10
authorDouglas Gilbert <dougg@torque.net>
Sun, 28 Apr 2002 11:45:21 +0000 (04:45 -0700)
committerJaroslav Kysela <perex@suse.cz>
Sun, 28 Apr 2002 11:45:21 +0000 (04:45 -0700)
Here's a patch for SCSI REPORT LUN scanning, including Douglas Gilbert's
recent changes to support a short INQUIRY followed by a longer INQUIRY.

Please apply, or let me know if you think it needs any modifications.

It's against linux-2.5.4. It does _not_ change the size of the linux lun.

A description of the 8 byte LUN layout can be found on page 35 of:

ftp://ftp.t10.org/t10/drafts/scc2/scc2r04.pdf

The above is a draft, but matches the layout seen on most disk arrays
(including EMC, IBM, LSI, and Hitachi). Later drafts (post SCSI-3) have
this information in the SCSI Architectural Model.

Patch description:

Adds REPORT LUN scanning.

Adds Douglas Gilbert's INQUIRY modification so broken devices that cannot handlean INQUIRY
of more than 36 bytes can be black-listed, plus saving the INQUIRY
result in Scsi_Device.

Adds scan_scsis_target function, replacing code in scan_scsis and parts
of scan_scsis_single. This cleans up the scanning code, and removes a
really ugly for loop. It would be difficult to add REPORT LUN scanning
without this change.

Adds missing scsi_release_commandblocks().

No longer sets max_dev_lun out of bounds for BLIST_FORCELUN devices.

Fixes scanning past LUN 7 for SCSI-3 devices (the patch in 2.4.17
for that fix will not cleanly apply against this code).

-- Patrick Mansfield

drivers/scsi/Config.help
drivers/scsi/Config.in
drivers/scsi/scsi.c
drivers/scsi/scsi.h
drivers/scsi/scsi_scan.c
include/scsi/scsi.h

index 073406482dd497471810d71a960629798d46b542..ed68406474d9bbe3307eca4a93cb4a64469ba57c 100644 (file)
@@ -145,6 +145,13 @@ CONFIG_SCSI_MULTI_LUN
   so most people can say N here and should in fact do so, because it
   is safer.
 
+CONFIG_SCSI_REPORT_LUNS
+  If you want to build with SCSI REPORT LUNS support in the kernel, say Y here.
+  The REPORT LUNS command is useful for devices (such as disk arrays) with
+  large numbers of LUNs where the LUN values are not contiguous (sparse LUN).
+  REPORT LUNS scanning is done only for SCSI-3 devices. Most users can safely
+  answer N here.
+
 CONFIG_SCSI_CONSTANTS
   The error messages regarding your SCSI hardware will be easier to
   understand if you say Y here; it will enlarge your kernel by about
index 522c2c8da07dfb980388fb36dad9db9b5dd4062a..38394b028c52312afa26fadee29f1057aed43dad 100644 (file)
@@ -21,6 +21,7 @@ dep_tristate '  SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
 comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
 
 bool '  Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
+bool '  Build with SCSI REPORT LUNS support' CONFIG_SCSI_REPORT_LUNS
   
 bool '  Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS
 bool '  SCSI logging facility' CONFIG_SCSI_LOGGING
index 2ea3aa10eeafd8b363400f4e548fa6f40b15fe27..620989e347329e09b56ff5f27378e4cff3b981ae 100644 (file)
@@ -158,6 +158,8 @@ const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
        "Enclosure        ",
 };
 
+static char * scsi_null_device_strs = "nullnullnullnull";
+
 /* 
  * Function prototypes.
  */
@@ -1831,6 +1833,8 @@ static int proc_scsi_gen_write(struct file * file, const char * buf,
                                HBA_ptr->host_queue = scd->next;
                        }
                        blk_cleanup_queue(&scd->request_queue);
+                       if (scd->inquiry)
+                               kfree(scd->inquiry);
                        kfree((char *) scd);
                } else {
                        goto out;
@@ -2129,6 +2133,8 @@ int scsi_unregister_host(Scsi_Host_Template * tpnt)
                        blk_cleanup_queue(&SDpnt->request_queue);
                        /* Next free up the Scsi_Device structures for this host */
                        shpnt->host_queue = SDpnt->next;
+                       if (SDpnt->inquiry)
+                               kfree(SDpnt->inquiry);
                        kfree((char *) SDpnt);
 
                }
@@ -2618,6 +2624,9 @@ Scsi_Device * scsi_get_host_dev(struct Scsi_Host * SHpnt)
                return NULL;
                
         memset(SDpnt, 0, sizeof(Scsi_Device));
+       SDpnt->vendor = scsi_null_device_strs;
+       SDpnt->model = scsi_null_device_strs;
+       SDpnt->rev = scsi_null_device_strs;
 
         SDpnt->host = SHpnt;
         SDpnt->id = SHpnt->this_id;
@@ -2664,6 +2673,8 @@ void scsi_free_host_dev(Scsi_Device * SDpnt)
          * it now.
          */
        scsi_release_commandblocks(SDpnt);
+       if (SDpnt->inquiry)
+               kfree(SDpnt->inquiry);
         kfree(SDpnt);
 }
 
index 47601c34075e46beb1e950cc74eeac27743bbda2..791921ffce05850763a6b0169d1431552eeaef31 100644 (file)
@@ -575,7 +575,11 @@ struct scsi_device {
        devfs_handle_t de;      /* directory for the device      */
        char type;
        char scsi_level;
-       char vendor[8], model[16], rev[4];
+       unsigned char inquiry_len;      /* valid bytes in 'inquiry' */
+       unsigned char * inquiry;        /* INQUIRY response data */
+       char * vendor;          /* [back_compat] point into 'inquiry' ... */
+       char * model;           /* ... after scan; point to static string */
+       char * rev;             /* ... "nullnullnullnull" before scan */
        unsigned char current_tag;      /* current tag */
        unsigned char sync_min_period;  /* Not less than this period */
        unsigned char sync_max_offset;  /* Not greater than this offset */
index 8f4d70c1e6a26cb53b58c3fa403fca37925a6539..7b0ab7dcab0d6a6bca5c8fb282fef06632ad5046 100644 (file)
 #include <linux/kmod.h>
 #endif
 
-/* The following devices are known not to tolerate a lun != 0 scan for
- * one reason or another.  Some will respond to all luns, others will
- * lock up.
+/*
+ * Flags for irregular SCSI devices that need special treatment
  */
+#define BLIST_NOLUN            0x001   /* Don't scan for LUNs */
+#define BLIST_FORCELUN         0x002   /* Known to have LUNs, force sanning */
+#define BLIST_BORKEN           0x004   /* Flag for broken handshaking */
+#define BLIST_KEY              0x008   /* Needs to be unlocked by special command */
+#define BLIST_SINGLELUN        0x010   /* LUNs should better not be used in parallel */
+#define BLIST_NOTQ             0x020   /* Buggy Tagged Command Queuing */
+#define BLIST_SPARSELUN        0x040   /* Non consecutive LUN numbering */
+#define BLIST_MAX5LUN          0x080   /* Avoid LUNS >= 5 */
+#define BLIST_ISDISK           0x100   /* Treat as (removable) disk */
+#define BLIST_ISROM            0x200   /* Treat as (removable) CD-ROM */
+#define BLIST_LARGELUN         0x400   /* LUNs larger than 7 despite reporting as SCSI 2 */
+#define BLIST_INQUIRY_36       0x800   /* override additional length field */
+#define BLIST_INQUIRY_58       0x1000  /* ... for broken inquiry responses */
 
-#define BLIST_NOLUN            0x001
-#define BLIST_FORCELUN         0x002
-#define BLIST_BORKEN           0x004
-#define BLIST_KEY              0x008
-#define BLIST_SINGLELUN        0x010
-#define BLIST_NOTQ             0x020
-#define BLIST_SPARSELUN        0x040
-#define BLIST_MAX5LUN          0x080
-#define BLIST_ISDISK           0x100
-#define BLIST_ISROM            0x200
+/*
+ * scan_scsis_single() return values.
+ */
+#define SCSI_SCAN_NO_RESPONSE      0
+#define SCSI_SCAN_DEVICE_PRESENT   1
+#define SCSI_SCAN_DEVICE_ADDED     2
 
 static void print_inquiry(unsigned char *data);
 static int scan_scsis_single(unsigned int channel, unsigned int dev,
-               unsigned int lun, int lun0_scsi_level, 
-               unsigned int *max_scsi_dev, unsigned int *sparse_lun, 
-               Scsi_Device ** SDpnt, struct Scsi_Host *shpnt, 
+               unsigned int lun, int scsi_level, Scsi_Device ** SDpnt2,
+               struct Scsi_Host *shpnt, char *scsi_result);
+static void scan_scsis_target(unsigned int channel, unsigned int dev,
+               Scsi_Device ** SDpnt2, struct Scsi_Host *shpnt,
                char *scsi_result);
 static int find_lun0_scsi_level(unsigned int channel, unsigned int dev,
                                struct Scsi_Host *shpnt);
@@ -61,6 +70,10 @@ struct dev_info {
  */
 static struct dev_info device_list[] =
 {
+/* The following devices are known not to tolerate a lun != 0 scan for
+ * one reason or another.  Some will respond to all luns, others will
+ * lock up.
+ */
        {"Aashima", "IMAGERY 2400SP", "1.03", BLIST_NOLUN},     /* Locks up if polled for lun != 0 */
        {"CHINON", "CD-ROM CDS-431", "H42", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
        {"CHINON", "CD-ROM CDS-535", "Q14", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
@@ -74,7 +87,6 @@ static struct dev_info device_list[] =
        {"MAXTOR", "XT-4170S", "B5A", BLIST_NOLUN},             /* Locks-up sometimes when LUN>0 polled. */
        {"MAXTOR", "XT-8760S", "B7B", BLIST_NOLUN},             /* guess what? */
        {"MEDIAVIS", "RENO CD-ROMX2A", "2.03", BLIST_NOLUN},    /*Responds to all lun */
-       {"MICROP", "4110", "*", BLIST_NOTQ},                    /* Buggy Tagged Queuing */
        {"NEC", "CD-ROM DRIVE:841", "1.0", BLIST_NOLUN},        /* Locks-up when LUN>0 polled. */
        {"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN},            /* Responds to all lun */
        {"RODIME", "RO3000S", "2.33", BLIST_NOLUN},             /* Locks up if polled for lun != 0 */
@@ -125,6 +137,7 @@ static struct dev_info device_list[] =
        {"INSITE", "Floptical   F*8I", "*", BLIST_KEY},
        {"INSITE", "I325VM", "*", BLIST_KEY},
        {"LASOUND","CDX7405","3.10", BLIST_MAX5LUN | BLIST_SINGLELUN},
+       {"MICROP", "4110", "*", BLIST_NOTQ},                    /* Buggy Tagged Queuing */
        {"NRC", "MBR-7", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
        {"NRC", "MBR-7.4", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
        {"REGAL", "CDC-4X", "*", BLIST_MAX5LUN | BLIST_SINGLELUN},
@@ -151,7 +164,8 @@ static struct dev_info device_list[] =
        {"DELL", "PV660F   PSEUDO",   "*", BLIST_SPARSELUN},
        {"DELL", "PSEUDO DEVICE .",   "*", BLIST_SPARSELUN}, // Dell PV 530F
        {"DELL", "PV530F",    "*", BLIST_SPARSELUN}, // Dell PV 530F
-       {"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN},
+       {"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
+       {"HP", "A6189A", "*", BLIST_SPARSELUN |  BLIST_LARGELUN}, // HP VA7400, by Alar Aun
        {"CMD", "CRA-7280", "*", BLIST_SPARSELUN},   // CMD RAID Controller
        {"CNSI", "G7324", "*", BLIST_SPARSELUN},     // Chaparral G7324 RAID
        {"CNSi", "G8324", "*", BLIST_SPARSELUN},     // Chaparral G8324 RAID
@@ -162,6 +176,9 @@ static struct dev_info device_list[] =
        {"HP", "NetRAID-4M", "*", BLIST_FORCELUN},
        {"ADAPTEC", "AACRAID", "*", BLIST_FORCELUN},
        {"ADAPTEC", "Adaptec 5400S", "*", BLIST_FORCELUN},
+       {"COMPAQ", "MSA1000", "*", BLIST_FORCELUN},
+       {"HP", "C1557A", "*", BLIST_FORCELUN},
+       {"IBM", "AuSaV1S2", "*", BLIST_FORCELUN},
 
        /*
         * Must be at end of list...
@@ -169,6 +186,8 @@ static struct dev_info device_list[] =
        {NULL, NULL, NULL}
 };
 
+static char * scsi_null_device_strs = "nullnullnullnull";
+
 #define MAX_SCSI_LUNS 0xFFFFFFFF
 
 #ifdef CONFIG_SCSI_MULTI_LUN
@@ -177,11 +196,27 @@ static unsigned int max_scsi_luns = MAX_SCSI_LUNS;
 static unsigned int max_scsi_luns = 1;
 #endif
 
+#ifdef CONFIG_SCSI_REPORT_LUNS
+/* 
+ * max_scsi_report_luns: the maximum number of LUNS that will be
+ * returned from the REPORT LUNS command. 8 times this value must
+ * be allocated. In theory this could be up to an 8 byte value, but
+ * in practice, the maximum number of LUNs suppored by any device
+ * is about 16k.
+ */
+static unsigned int max_scsi_report_luns = 128;
+#endif
+
 #ifdef MODULE
 
 MODULE_PARM(max_scsi_luns, "i");
 MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 2^32-1)");
 
+#ifdef CONFIG_SCSI_REPORT_LUNS
+MODULE_PARM(max_scsi_report_luns, "i");
+MODULE_PARM_DESC(max_scsi_report_luns, "REPORT LUNS maximum number of LUNS received (should be between 1 and 16384)");
+#endif
+
 #else
 
 static int __init scsi_luns_setup(char *str)
@@ -200,6 +235,59 @@ static int __init scsi_luns_setup(char *str)
 
 __setup("max_scsi_luns=", scsi_luns_setup);
 
+#ifdef CONFIG_SCSI_REPORT_LUNS
+static int __init max_scsi_report_luns_setup(char *str)
+{
+       unsigned int tmp;
+
+       if (get_option(&str, &tmp) == 1) {
+               max_scsi_report_luns = tmp;
+               return 1;
+       } else {
+               printk("scsi_report_luns_setup : usage max_scsi_report_luns=n "
+                      "(n should be between 1 and 16384)\n");
+               return 0;
+       }
+}
+
+__setup("max_scsi_report_luns=", max_scsi_report_luns_setup);
+#endif /* CONFIG_SCSI_REPORT_LUNS */
+
+#endif
+
+#ifdef CONFIG_SCSI_REPORT_LUNS
+/*
+ * Function:    scsilun_to_int
+ *
+ * Purpose:     Convert ScsiLun (8 byte LUN) to an int.
+ *
+ * Arguments:   scsilun_pnt - pointer to a ScsiLun to be converted
+ *
+ * Lock status: None
+ *
+ * Returns:     cpu ordered integer containing the truncated LUN value
+ *
+ * Notes:       The ScsiLun is assumed to be four levels, with each level
+ *             effectively containing a SCSI byte-ordered (big endidan)
+ *             short; the addressing bits of each level are ignored (the
+ *             highest two bits). For a description of the LUN format, post
+ *             SCSI-3 see the SCSI Architecture Model, for SCSI-3 see the
+ *             SCSI Controller Commands.
+ *
+ *             Given a ScsiLun of: 0a 04 0b 03 00 00 00 00, this function
+ *             returns the integer: 0x0b030a04
+ */
+static int scsilun_to_int(ScsiLun *scsilun_pnt) 
+{
+       int i;
+       unsigned int lun;
+
+       lun = 0;
+       for (i = 0; i < sizeof(lun); i += 2)
+               lun = lun | (((scsilun_pnt->scsi_lun[i] << 8) |
+                       scsilun_pnt->scsi_lun[i + 1]) << (i * 8));
+       return lun;
+}
 #endif
 
 static void print_inquiry(unsigned char *data)
@@ -243,23 +331,20 @@ static void print_inquiry(unsigned char *data)
                printk("\n");
 }
 
-static int get_device_flags(unsigned char *response_data)
+static int get_device_flags(unsigned char *vendor_pnt, unsigned char *model_pnt)
 {
        int i = 0;
-       unsigned char *pnt;
        for (i = 0; 1; i++) {
                if (device_list[i].vendor == NULL)
                        return 0;
-               pnt = &response_data[8];
-               while (*pnt && *pnt == ' ')
-                       pnt++;
-               if (memcmp(device_list[i].vendor, pnt,
+               while (*vendor_pnt && *vendor_pnt == ' ')
+                       vendor_pnt++;
+               if (memcmp(device_list[i].vendor, vendor_pnt,
                           strlen(device_list[i].vendor)))
                        continue;
-               pnt = &response_data[16];
-               while (*pnt && *pnt == ' ')
-                       pnt++;
-               if (memcmp(device_list[i].model, pnt,
+               while (*model_pnt && *model_pnt == ' ')
+                       model_pnt++;
+               if (memcmp(device_list[i].model, model_pnt,
                           strlen(device_list[i].model)))
                        continue;
                return device_list[i].flags;
@@ -283,13 +368,10 @@ void scan_scsis(struct Scsi_Host *shpnt,
        uint channel;
        unsigned int dev;
        unsigned int lun;
-       unsigned int max_dev_lun;
        unsigned char *scsi_result;
        unsigned char scsi_result0[256];
        Scsi_Device *SDpnt;
        Scsi_Device *SDtail;
-       unsigned int sparse_lun;
-       int lun0_sl;
 
        scsi_result = NULL;
 
@@ -297,6 +379,9 @@ void scan_scsis(struct Scsi_Host *shpnt,
                                        GFP_ATOMIC);
        if (SDpnt) {
                memset(SDpnt, 0, sizeof(Scsi_Device));
+               SDpnt->vendor = scsi_null_device_strs;
+               SDpnt->model = scsi_null_device_strs;
+               SDpnt->rev = scsi_null_device_strs;
                /*
                 * Register the queue for the device.  All I/O requests will
                 * come in through here.  We also need to register a pointer to
@@ -352,6 +437,8 @@ void scan_scsis(struct Scsi_Host *shpnt,
        if (hardcoded == 1) {
                Scsi_Device *oldSDpnt = SDpnt;
                struct Scsi_Device_Template *sdtpnt;
+               unsigned int lun0_sl;
+
                channel = hchannel;
                if (channel > shpnt->max_channel)
                        goto leave;
@@ -365,8 +452,8 @@ void scan_scsis(struct Scsi_Host *shpnt,
                        lun0_sl = SCSI_3; /* actually don't care for 0 == lun */
                else
                        lun0_sl = find_lun0_scsi_level(channel, dev, shpnt);
-               scan_scsis_single(channel, dev, lun, lun0_sl, &max_dev_lun, 
-                                 &sparse_lun, &SDpnt, shpnt, scsi_result);
+               scan_scsis_single(channel, dev, lun, lun0_sl, &SDpnt, shpnt,
+                                 scsi_result);
                if (SDpnt != oldSDpnt) {
 
                        /* it could happen the blockdevice hasn't yet been inited */
@@ -411,31 +498,11 @@ void scan_scsis(struct Scsi_Host *shpnt,
                                        order_dev = dev;
 
                                if (shpnt->this_id != order_dev) {
-
-                                       /*
-                                        * We need the for so our continue, etc. work fine. We put this in
-                                        * a variable so that we can override it during the scan if we
-                                        * detect a device *KNOWN* to have multiple logical units.
-                                        */
-                                       max_dev_lun = (max_scsi_luns < shpnt->max_lun ?
-                                        max_scsi_luns : shpnt->max_lun);
-                                       sparse_lun = 0;
-                                       for (lun = 0, lun0_sl = SCSI_2; lun < max_dev_lun; ++lun) {
-                                               /* don't probe further for luns > 7 for targets <= SCSI_2 */
-                                               if ((lun0_sl < SCSI_3) && (lun > 7))
-                                                       break;
-
-                                               if (!scan_scsis_single(channel, order_dev, lun, lun0_sl,
-                                                                      &max_dev_lun, &sparse_lun, &SDpnt, shpnt,
-                                                                      scsi_result)
-                                                   && !sparse_lun)
-                                                       break;  /* break means don't probe further for luns!=0 */
-                                               if (SDpnt && (0 == lun))
-                                                       lun0_sl = SDpnt->scsi_level;
-                                       }       /* for lun ends */
-                               }       /* if this_id != id ends */
-                       }       /* for dev ends */
-               }               /* for channel ends */
+                                       scan_scsis_target(channel, order_dev,
+                                               &SDpnt, shpnt, scsi_result);
+                               }
+                       }
+               }
        }                       /* if/else hardcoded */
 
       leave:
@@ -461,6 +528,8 @@ void scan_scsis(struct Scsi_Host *shpnt,
        /* Last device block does not exist.  Free memory. */
        if (SDpnt != NULL) {
                blk_cleanup_queue(&SDpnt->request_queue);
+               if (SDpnt->inquiry)
+                       kfree(SDpnt->inquiry);
                kfree((char *) SDpnt);
        }
 
@@ -483,15 +552,38 @@ void scan_scsis(struct Scsi_Host *shpnt,
 }
 
 /*
- * The worker for scan_scsis.
- * Returning 0 means Please don't ask further for lun!=0, 1 means OK go on.
- * Global variables used : scsi_devices(linked list)
+ * Function:    scan_scsis_single
+ *
+ * Purpose:     Determine if a SCSI device (a single LUN) exists, and
+ *             configure it into the system.
+ *
+ * Arguments:   channel    - the host's channel
+ *             dev        - target dev (target id)
+ *             lun        - LUN
+ *             scsi_level - SCSI 1, 2 or 3
+ *             SDpnt2     - pointer to pointer of a preallocated Scsi_Device
+ *             shpnt      - host device to use
+ *             scsi_result - preallocated buffer for the SCSI command result
+ *
+ * Lock status: None
+ *
+ * Returns:     SCSI_SCAN_NO_RESPONSE - no valid response received from the
+ *             device, this includes allocation failures preventing IO from
+ *             being sent, or any general failures.
+ *
+ *             SCSI_SCAN_DEVICE_PRESENT - device responded, SDpnt2 has all
+ *             values needed to send IO set, plus scsi_level is set, but no
+ *             new Scsi_Device was added/allocated.
+ *
+ *             SCSI_SCAN_DEVICE_ADDED - device responded, and added to list;
+ *             SDpnt2 filled, and pointed to new allocated Scsi_Device.
+ *
+ * Notes:       This could be cleaned up more by moving SDpnt2 and Scsi_Device
+ *             allocation into scan_scsis_target.
  */
 static int scan_scsis_single(unsigned int channel, unsigned int dev,
-               unsigned int lun, int lun0_scsi_level,
-               unsigned int *max_dev_lun, unsigned int *sparse_lun, 
-               Scsi_Device ** SDpnt2, struct Scsi_Host *shpnt, 
-               char *scsi_result)
+               unsigned int lun, int scsi_level, Scsi_Device ** SDpnt2,
+               struct Scsi_Host *shpnt, char *scsi_result)
 {
        char devname[64];
        unsigned char scsi_cmd[MAX_COMMAND_SIZE];
@@ -499,6 +591,7 @@ static int scan_scsis_single(unsigned int channel, unsigned int dev,
        Scsi_Device *SDtail, *SDpnt = *SDpnt2;
        Scsi_Request * SRpnt;
        int bflags, type = -1;
+       int possible_inq_resp_len;
        extern devfs_handle_t scsi_devfs_handle;
 
        SDpnt->host = shpnt;
@@ -523,7 +616,8 @@ static int scan_scsis_single(unsigned int channel, unsigned int dev,
 
        if (NULL == (SRpnt = scsi_allocate_request(SDpnt))) {
                printk("scan_scsis_single: no memory\n");
-               return 0;
+               scsi_release_commandblocks(SDpnt);
+               return SCSI_SCAN_NO_RESPONSE;
        }
 
        /*
@@ -532,25 +626,26 @@ static int scan_scsis_single(unsigned int channel, unsigned int dev,
         * devices (and TEST_UNIT_READY to poll for media change). - Paul G.
         */
 
-       SCSI_LOG_SCAN_BUS(3, printk("scsi: performing INQUIRY\n"));
+       SCSI_LOG_SCAN_BUS(3,
+               printk("scsi scan: INQUIRY to host %d channel %d id %d lun %d\n",
+                      shpnt->host_no, channel, dev, lun)
+       );
+
        /*
         * Build an INQUIRY command block.
         */
+       memset(scsi_cmd, 0, 6);
        scsi_cmd[0] = INQUIRY;
-       if ((lun > 0) && (lun0_scsi_level <= SCSI_2))
+       if ((lun > 0) && (scsi_level <= SCSI_2))
                scsi_cmd[1] = (lun << 5) & 0xe0;
-       else    
-               scsi_cmd[1] = 0;        /* SCSI_3 and higher, don't touch */
-       scsi_cmd[2] = 0;
-       scsi_cmd[3] = 0;
-       scsi_cmd[4] = 255;
-       scsi_cmd[5] = 0;
+       scsi_cmd[4] = 36;       /* issue conservative alloc_length */
        SRpnt->sr_cmd_len = 0;
        SRpnt->sr_data_direction = SCSI_DATA_READ;
 
+       memset(scsi_result, 0, 36);
        scsi_wait_req (SRpnt, (void *) scsi_cmd,
                  (void *) scsi_result,
-                 256, SCSI_TIMEOUT+4*HZ, 3);
+                 36, SCSI_TIMEOUT+4*HZ, 3);
 
        SCSI_LOG_SCAN_BUS(3, printk("scsi: INQUIRY %s with code 0x%x\n",
                SRpnt->sr_result ? "failed" : "successful", SRpnt->sr_result));
@@ -565,6 +660,7 @@ static int scan_scsis_single(unsigned int channel, unsigned int dev,
                    SRpnt->sr_sense_buffer[12] == 0x28 &&
                    SRpnt->sr_sense_buffer[13] == 0) {
                        /* not-ready to ready transition - good */
+                       /* dpg: bogus? INQUIRY never returns UNIT_ATTENTION */
                } else {
                        /* assume no peripheral if any other sort of error */
                        scsi_release_request(SRpnt);
@@ -572,26 +668,64 @@ static int scan_scsis_single(unsigned int channel, unsigned int dev,
                }
        }
 
-       /*
-        * Check for SPARSELUN before checking the peripheral qualifier,
-        * so sparse lun devices are completely scanned.
-        */
-
        /*
         * Get any flags for this device.  
         */
-       bflags = get_device_flags (scsi_result);
+       bflags = get_device_flags (&scsi_result[8], &scsi_result[16]);
+
+       possible_inq_resp_len = (unsigned char)scsi_result[4] + 5;
+       if (BLIST_INQUIRY_36 & bflags)
+               possible_inq_resp_len = 36;
+       else if (BLIST_INQUIRY_58 & bflags)
+               possible_inq_resp_len = 58;
+       else if (possible_inq_resp_len > 255)
+               possible_inq_resp_len = 36;     /* sanity */
+
+       if (possible_inq_resp_len > 36) { /* do additional INQUIRY */
+               memset(scsi_cmd, 0, 6);
+               scsi_cmd[0] = INQUIRY;
+               if ((lun > 0) && (scsi_level <= SCSI_2))
+                       scsi_cmd[1] = (lun << 5) & 0xe0;
+               scsi_cmd[4] = (unsigned char)possible_inq_resp_len;
+               SRpnt->sr_cmd_len = 0;
+               SRpnt->sr_data_direction = SCSI_DATA_READ;
 
-       if (bflags & BLIST_SPARSELUN) {
-         *sparse_lun = 1;
+               scsi_wait_req (SRpnt, (void *) scsi_cmd,
+                         (void *) scsi_result,
+                         256, SCSI_TIMEOUT+4*HZ, 3);
+               /* assume successful */
+       }
+       SDpnt->inquiry_len = possible_inq_resp_len;
+       SDpnt->inquiry = kmalloc(possible_inq_resp_len, GFP_ATOMIC);
+       if (NULL == SDpnt->inquiry) {
+               scsi_release_commandblocks(SDpnt);
+               scsi_release_request(SRpnt);
+               return SCSI_SCAN_NO_RESPONSE;
        }
+       memcpy(SDpnt->inquiry, scsi_result, possible_inq_resp_len);
+       SDpnt->vendor = (char *)(SDpnt->inquiry + 8);
+       SDpnt->model = (char *)(SDpnt->inquiry + 16);
+       SDpnt->rev = (char *)(SDpnt->inquiry + 32);
+
+       SDpnt->scsi_level = scsi_result[2] & 0x07;
+       if (SDpnt->scsi_level >= 2 ||
+           (SDpnt->scsi_level == 1 &&
+            (scsi_result[3] & 0x0f) == 1))
+               SDpnt->scsi_level++;
+
        /*
         * Check the peripheral qualifier field - this tells us whether LUNS
         * are supported here or not.
         */
        if ((scsi_result[0] >> 5) == 3) {
-               scsi_release_request(SRpnt);
-               return 0;       /* assume no peripheral if any sort of error */
+               /*
+                * Peripheral qualifier 3 (011b): The device server is not
+                * capable of supporting a physical device on this logical
+                * unit.
+                */
+               scsi_release_commandblocks(SDpnt);
+               scsi_release_request(SRpnt);
+               return SCSI_SCAN_DEVICE_PRESENT;
        }
         /*   The Toshiba ROM was "gender-changed" here as an inline hack.
              This is now much more generic.
@@ -609,9 +743,6 @@ static int scan_scsis_single(unsigned int channel, unsigned int dev,
                scsi_result[1] |= 0x80;     /* removable */
        }
     
-       memcpy(SDpnt->vendor, scsi_result + 8, 8);
-       memcpy(SDpnt->model, scsi_result + 16, 16);
-       memcpy(SDpnt->rev, scsi_result + 32, 4);
 
        SDpnt->removable = (0x80 & scsi_result[1]) >> 7;
        /* Use the peripheral qualifier field to determine online/offline */
@@ -630,6 +761,7 @@ static int scan_scsis_single(unsigned int channel, unsigned int dev,
        switch (type = (scsi_result[0] & 0x1f)) {
        case TYPE_TAPE:
        case TYPE_DISK:
+       case TYPE_PRINTER:
        case TYPE_MOD:
        case TYPE_PROCESSOR:
        case TYPE_SCANNER:
@@ -667,12 +799,6 @@ static int scan_scsis_single(unsigned int channel, unsigned int dev,
                        SDpnt->attached +=
                            (*sdtpnt->detect) (SDpnt);
 
-       SDpnt->scsi_level = scsi_result[2] & 0x07;
-       if (SDpnt->scsi_level >= 2 ||
-           (SDpnt->scsi_level == 1 &&
-            (scsi_result[3] & 0x0f) == 1))
-               SDpnt->scsi_level++;
-
        /*
         * Accommodate drivers that want to sleep when they should be in a polling
         * loop.
@@ -726,6 +852,9 @@ static int scan_scsis_single(unsigned int channel, unsigned int dev,
                scsi_wait_req (SRpnt, (void *) scsi_cmd,
                        (void *) scsi_result, 0x2a,
                        SCSI_TIMEOUT, 3);
+               /*
+                * scsi_result no longer holds inquiry data.
+                */
        }
 
        scsi_release_request(SRpnt);
@@ -741,14 +870,18 @@ static int scan_scsis_single(unsigned int channel, unsigned int dev,
        SDpnt = (Scsi_Device *) kmalloc(sizeof(Scsi_Device), GFP_ATOMIC);
        if (!SDpnt) {
                printk("scsi: scan_scsis_single: Cannot malloc\n");
-               return 0;
+               return SCSI_SCAN_NO_RESPONSE;
        }
         memset(SDpnt, 0, sizeof(Scsi_Device));
+       SDpnt->vendor = scsi_null_device_strs;
+       SDpnt->model = scsi_null_device_strs;
+       SDpnt->rev = scsi_null_device_strs;
 
        *SDpnt2 = SDpnt;
        SDpnt->queue_depth = 1;
        SDpnt->host = shpnt;
        SDpnt->online = TRUE;
+       SDpnt->scsi_level = scsi_level;
 
        /*
         * Register the queue for the device.  All I/O requests will come
@@ -788,62 +921,375 @@ static int scan_scsis_single(unsigned int channel, unsigned int dev,
        SDpnt->prev = SDtail;
        SDpnt->next = NULL;
 
+       return SCSI_SCAN_DEVICE_ADDED;
+}
+
+/*
+ * Function:    scsi_report_lun_scan
+ *
+ * Purpose:     Use a SCSI REPORT LUN to determine what LUNs to scan.
+ *
+ * Arguments:   SDlun0_pnt - pointer to a Scsi_Device for LUN 0
+ *             channel    - the host's channel
+ *             dev        - target dev (target id)
+ *             SDpnt2     - pointer to pointer of a preallocated Scsi_Device
+ *             shpnt      - host device to use
+ *             scsi_result - preallocated buffer for the SCSI command result
+ *
+ * Lock status: None
+ *
+ * Returns:     If the LUNs for device at shpnt/channel/dev are scanned,
+ *             return 0, else return 1.
+ *
+ * Notes:       This code copies and truncates the 8 byte LUN into the
+ *             current 4 byte (int) lun.
+ */
+static int scsi_report_lun_scan(Scsi_Device *SDlun0_pnt, unsigned
+               int channel, unsigned int dev, Scsi_Device **SDpnt2,
+               struct Scsi_Host *shpnt, char *scsi_result)
+{
+#ifdef CONFIG_SCSI_REPORT_LUNS
+
+       char devname[64];
+       unsigned char scsi_cmd[MAX_COMMAND_SIZE];
+       unsigned int length;
+       unsigned int lun;
+       unsigned int num_luns;
+       unsigned int retries;
+       ScsiLun *fcp_cur_lun_pnt, *lun_data_pnt;
+       Scsi_Request *SRpnt;
+       int scsi_level;
+       char *byte_pnt;
+       int got_command_blocks = 0;
+
        /*
-        * Some scsi devices cannot be polled for lun != 0 due to firmware bugs
+        * Only support SCSI-3 and up devices.
         */
-       if (bflags & BLIST_NOLUN)
-               return 0;       /* break; */
+       if (SDlun0_pnt->scsi_level < SCSI_3)
+               return 1;
 
        /*
-        * If this device is known to support sparse multiple units, override the
-        * other settings, and scan all of them.
+        * Note SDlun0_pnt might be invalid after scan_scsis_single is called.
         */
-       if (bflags & BLIST_SPARSELUN) {
-               *max_dev_lun = shpnt->max_lun;
-               *sparse_lun = 1;
-               return 1;
+
+       /*
+        * Command blocks might be built depending on whether LUN 0 was
+        * configured or not. Checking has_cmdblocks here is ugly.
+        */
+       if (SDlun0_pnt->has_cmdblocks == 0) {
+               got_command_blocks = 1;
+               scsi_build_commandblocks(SDlun0_pnt);
        }
+       SRpnt = scsi_allocate_request(SDlun0_pnt);
+
+       sprintf (devname, "host %d channel %d id %d",
+                SDlun0_pnt->host->host_no, SDlun0_pnt->channel,
+                SDlun0_pnt->id);
        /*
-        * If this device is known to support multiple units, override the other
-        * settings, and scan all of them.
+        * Allocate enough to hold the header (the same size as one ScsiLun)
+        * plus the max number of luns we are requesting.
+        *
+        * XXX: Maybe allocate this once, like scsi_result, and pass it down.
+        * scsi_result can't be used, as it is needed for the scan INQUIRY
+        * data. In addition, 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 limits of kmalloc).
         */
-       if (bflags & BLIST_FORCELUN) {
-               /* 
-                * Scanning MAX_SCSI_LUNS units would be a bad idea.
-                * Any better idea?
-                * I think we need REPORT LUNS in future to avoid scanning
-                * of unused LUNs. But, that is another item.
-                */
-               if (*max_dev_lun < shpnt->max_lun)
-                       *max_dev_lun = shpnt->max_lun;
-               else    if ((max_scsi_luns >> 1) >= *max_dev_lun)
-                               *max_dev_lun += shpnt->max_lun;
-                       else    *max_dev_lun = max_scsi_luns;
+       length = (max_scsi_report_luns + 1) * sizeof(ScsiLun);
+       lun_data_pnt = (ScsiLun *) kmalloc(length,
+                       (shpnt->unchecked_isa_dma ?  GFP_DMA : GFP_ATOMIC));
+       if (lun_data_pnt == NULL) {
+               printk("scsi: scsi_report_lun_scan: Cannot malloc\n");
+               if (got_command_blocks)
+                       scsi_release_commandblocks(SDlun0_pnt);
                return 1;
        }
+
+       scsi_cmd[0] = REPORT_LUNS;
        /*
-        * REGAL CDC-4X: avoid hang after LUN 4
+        * bytes 1 - 5: reserved, set to zero.
+        */
+       memset(&scsi_cmd[1], 0, 5);
+       /*
+        * bytes 6 - 9: length of the command.
+        */
+       scsi_cmd[6] = (unsigned char) (length >> 24) & 0xff;
+       scsi_cmd[7] = (unsigned char) (length >> 16) & 0xff;
+       scsi_cmd[8] = (unsigned char) (length >> 8) & 0xff;
+       scsi_cmd[9] = (unsigned char) length & 0xff;
+
+       scsi_cmd[10] = 0; /* reserved */
+       scsi_cmd[11] = 0; /* control */
+       SRpnt->sr_cmd_len = 0;
+       SRpnt->sr_data_direction = SCSI_DATA_READ;
+
+       /*
+        * We can get a UNIT ATTENTION, for example a power on/reset, so retry
+        * a few times (like sd.c does for TEST UNIT READY). Experience shows
+        * some combinations of adapter/devices get at least two power
+        * on/resets.
+        *
+        * Illegal requests (for devices that do not support REPORT LUNS)
+        * should come through as a check condition, and will not generate a
+        * retry.
         */
-       if (bflags & BLIST_MAX5LUN) {
-               *max_dev_lun = 5;
+       retries = 0;
+       while (retries++ < 3) {
+               SCSI_LOG_SCAN_BUS(3,
+                       printk("scsi: Sending REPORT LUNS to %s (try %d)\n",
+                               devname, retries));
+
+               scsi_wait_req (SRpnt, (void *) scsi_cmd, (void *) lun_data_pnt,
+                         length, SCSI_TIMEOUT+4*HZ, 3);
+
+               SCSI_LOG_SCAN_BUS(3,
+                       printk("scsi: REPORT LUNS %s (try %d) result 0x%x\n",
+                       SRpnt->sr_result ? "failed" : "successful", retries,
+                       SRpnt->sr_result));
+
+               if (SRpnt->sr_result == 0
+                   || SRpnt->sr_sense_buffer[2] != UNIT_ATTENTION)
+                       break;
+       }
+
+       scsi_release_request(SRpnt);
+       if (got_command_blocks)
+               scsi_release_commandblocks(SDlun0_pnt);
+
+       if (SRpnt->sr_result) {
+               kfree((char *) lun_data_pnt);
                return 1;
        }
 
        /*
-        * We assume the device can't handle lun!=0 if: - it reports scsi-0
-        * (ANSI SCSI Revision 0) (old drives like MAXTOR XT-3280) or - it
-        * reports scsi-1 (ANSI SCSI Revision 1) and Response Data Format 0
+        * Get the length from the first four bytes of lun_data_pnt.
         */
-       if (((scsi_result[2] & 0x07) == 0)
-           ||
-           ((scsi_result[2] & 0x07) == 1 &&
-            (scsi_result[3] & 0x0f) == 0))
-               return 0;
+       byte_pnt = (char*) lun_data_pnt->scsi_lun;
+       length = ((byte_pnt[0] << 24) | (byte_pnt[1] << 16) |
+                        (byte_pnt[2] << 8) | (byte_pnt[3] << 0));
+       if ((length / sizeof(ScsiLun)) > max_scsi_report_luns) {
+               printk("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,
+                       length / sizeof(ScsiLun));
+               num_luns = max_scsi_report_luns;
+       } else
+               num_luns = (length / sizeof(ScsiLun));
+
+       scsi_level = SDlun0_pnt->scsi_level;
+
+       SCSI_LOG_SCAN_BUS(3,
+               printk("scsi: REPORT LUN scan of host %d channel %d id %d\n",
+                SDlun0_pnt->host->host_no, SDlun0_pnt->channel,
+                SDlun0_pnt->id));
+       /*
+        * Scan the luns in lun_data_pnt. The entry at offset 0 is really
+        * the header, so start at 1 and go up to and including num_luns.
+        */
+       for (fcp_cur_lun_pnt = &lun_data_pnt[1];
+            fcp_cur_lun_pnt <= &lun_data_pnt[num_luns];
+            fcp_cur_lun_pnt++) {
+               lun = scsilun_to_int(fcp_cur_lun_pnt);
+               /*
+                * Check if the unused part of fcp_cur_lun_pnt is non-zero,
+                * and so does not fit in lun.
+                */
+               if (memcmp(&fcp_cur_lun_pnt->scsi_lun[sizeof(lun)],
+                          "\0\0\0\0", 4) != 0) {
+                       int i;
+
+                       /*
+                        * Output an error displaying the LUN in byte order,
+                        * this differs from what linux would print for the
+                        * integer LUN value.
+                        */
+                       printk("scsi: %s lun 0x", devname);
+                       byte_pnt = (char*) fcp_cur_lun_pnt->scsi_lun;
+                       for (i = 0; i < sizeof(ScsiLun); i++)
+                               printk("%02x", byte_pnt[i]);
+                       printk(" has a LUN larger than that supported by"
+                               " the kernel\n");
+               } else if (lun == 0) {
+                       /*
+                        * LUN 0 has already been scanned.
+                        */
+               } else if (lun > shpnt->max_lun) {
+                       printk("scsi: %s lun %d has a LUN larger than allowed"
+                               " by the host adapter\n", devname, lun);
+               } else {
+                       /*
+                        * Don't use SDlun0_pnt after this call - it can be
+                        * overwritten via SDpnt2 if there was no real device
+                        * at LUN 0.
+                        */
+                       if (scan_scsis_single(channel, dev, lun,
+                           scsi_level, SDpnt2, shpnt, scsi_result)
+                               == SCSI_SCAN_NO_RESPONSE) {
+                               /*
+                                * Got some results, but now none, abort.
+                                */
+                               printk("scsi: no response from %s lun %d while"
+                                      " scanning, scan aborted\n", devname, 
+                                      lun);
+                               break;
+                       }
+               }
+       }
+
+       kfree((char *) lun_data_pnt);
+       return 0;
+
+#else
        return 1;
+#endif /* CONFIG_SCSI_REPORT_LUNS */
+
+}
+
+/*
+ * Function:    scan_scsis_target
+ *
+ * Purpose:     Scan the given scsi target dev, and as needed all LUNs
+ *             on the target dev.
+ *
+ * Arguments:   channel    - the host's channel
+ *             dev        - target dev (target id)
+ *             SDpnt2     - pointer to pointer of a preallocated Scsi_Device
+ *             shpnt      - host device to use
+ *             scsi_result - preallocated buffer for the SCSI command result
+ *
+ * Lock status: None
+ *
+ * Returns:     void
+ *
+ * Notes:       This tries to be compatible with linux 2.4.x. This function
+ *             relies on scan_scsis_single to setup SDlun0_pnt. 
+ *
+ *             It would be better if the Scsi_Device allocation and freeing
+ *             was done here, rather than oddly embedded in scan_scsis_single
+ *             and scan_scsis.
+ */
+static void scan_scsis_target(unsigned int channel, unsigned int dev,
+               Scsi_Device **SDpnt2, struct Scsi_Host *shpnt,
+               char *scsi_result)
+{
+       int bflags, scsi_level;
+       Scsi_Device *SDlun0_pnt;
+       unsigned int sparse_lun = 0;
+       unsigned int max_dev_lun, lun;
+       unsigned int sdlun0_res;
+
+       /*
+        * Scan lun 0, use the results to determine whether to scan further.
+        * Ideally, we would not configure LUN 0 until we scan.
+        */
+       SDlun0_pnt = *SDpnt2;
+       sdlun0_res = scan_scsis_single(channel, dev, 0 /* LUN 0 */, SCSI_2,
+               SDpnt2, shpnt, scsi_result);
+       if (sdlun0_res == SCSI_SCAN_NO_RESPONSE)
+               return;
+
+       /*
+        * If no new SDpnt was allocated (SCSI_SCAN_DEVICE_PRESENT), SDlun0_pnt
+        * can later be modified. It is unlikely the lun level would change,
+        * but save it just in case.
+        */
+       scsi_level = SDlun0_pnt->scsi_level;
+
+       /*
+        * We could probably use and save the bflags from lun 0 for all luns
+        * on a target, but be safe and match current behaviour. (LUN 0
+        * bflags controls the target settings checked within this function.)
+        */
+       bflags = get_device_flags (SDlun0_pnt->vendor,  SDlun0_pnt->model);
+
+       /*
+        * Some scsi devices cannot be polled for lun != 0 due to firmware bugs
+        */
+       if (bflags & BLIST_NOLUN)
+               return;
+
+       /*
+        * Ending the scan here if max_scsi_luns == 1 breaks scanning of
+        * SPARSE, FORCE, MAX5 LUN devices, and the report lun scans.
+        */
+
+       if (scsi_report_lun_scan(SDlun0_pnt, channel, dev, SDpnt2, shpnt,
+           scsi_result) == 0)
+               return;
+
+       SCSI_LOG_SCAN_BUS(3,
+               printk("scsi: Sequential scan of host %d channel %d id %d\n",
+                SDlun0_pnt->host->host_no, SDlun0_pnt->channel,
+                SDlun0_pnt->id));
+
+       max_dev_lun = (max_scsi_luns < shpnt->max_lun ?
+                       max_scsi_luns : shpnt->max_lun);
+       /*
+        * If this device is known to support sparse multiple units,
+        * override the other settings, and scan all of them.
+        */
+       if (bflags & BLIST_SPARSELUN) {
+               max_dev_lun = shpnt->max_lun;
+               sparse_lun = 1;
+       } else if (sdlun0_res == SCSI_SCAN_DEVICE_PRESENT) {
+               /*
+                * LUN 0 responded, but no LUN 0 was added, don't scan any
+                * further. This matches linux 2.4.x behaviour.
+                */
+               return;
+       }
+       /*
+        * If less than SCSI_1_CSS, and not a forced lun scan, stop
+        * scanning, this matches 2.4 behaviour, but it could be a bug
+        * to scan SCSI_1_CSS devices past LUN 0.
+        */
+       if ((scsi_level < SCSI_1_CCS) && ((bflags &
+            (BLIST_FORCELUN | BLIST_SPARSELUN | BLIST_MAX5LUN)) == 0))
+               return;
+       /*
+        * If this device is known to support multiple units, override
+        * the other settings, and scan all of them.
+        */
+       if (bflags & BLIST_FORCELUN)
+               max_dev_lun = shpnt->max_lun;
+       /*
+        * REGAL CDC-4X: avoid hang after LUN 4
+        */
+       if (bflags & BLIST_MAX5LUN)
+               max_dev_lun = min(5U, max_dev_lun);
+       /*
+        * Do not scan past LUN 7.
+        */
+       if (scsi_level < SCSI_3)
+               max_dev_lun = min(8U, max_dev_lun);
+
+       /*
+        * We have already scanned lun 0.
+        */
+       for (lun = 1; lun < max_dev_lun; ++lun) {
+               int res;
+               /*
+                * Scan until scan_scsis_single says stop,
+                * unless sparse_lun is set.
+                */
+               res = scan_scsis_single(channel, dev, lun,
+                    scsi_level, SDpnt2, shpnt, scsi_result);
+               if (res == SCSI_SCAN_NO_RESPONSE) {
+                       /*
+                        * Got a response on LUN 0, but now no response.
+                        */
+                       printk("scsi: no response from device"
+                               " host%d/bus%d/target%d/lun%d"
+                               " while scanning, scan aborted\n",
+                               shpnt->host_no, channel, dev, lun);
+                       return;
+               } else if ((res == SCSI_SCAN_DEVICE_PRESENT)
+                           && !sparse_lun)
+                       return;
+       }
 }
 
 /*
- * The worker for scan_scsis.
  * Returns the scsi_level of lun0 on this host, channel and dev (if already
  * known), otherwise returns SCSI_2.
  */
index 1bcce4c08dcdff730dabda2af3c5049bf91b7189..a85c7804d2c0820b086554509152f9cb74e7d017 100644 (file)
@@ -78,6 +78,7 @@
 #define MODE_SENSE_10         0x5a
 #define PERSISTENT_RESERVE_IN 0x5e
 #define PERSISTENT_RESERVE_OUT 0x5f
+#define REPORT_LUNS           0xa0
 #define MOVE_MEDIUM           0xa5
 #define READ_12               0xa8
 #define WRITE_12              0xaa
 
 #define TYPE_DISK           0x00
 #define TYPE_TAPE           0x01
+#define TYPE_PRINTER        0x02
 #define TYPE_PROCESSOR      0x03    /* HP scanners use this */
 #define TYPE_WORM           0x04    /* Treated as ROM by our system */
 #define TYPE_ROM            0x05
@@ -163,6 +165,13 @@ struct ccs_modesel_head
     u_char  block_length_lo;
 };
 
+/*
+ * ScsiLun: 8 byte LUN.
+ */
+typedef struct scsi_lun {
+       u8 scsi_lun[8];
+} ScsiLun;
+
 /*
  *  MESSAGE CODES
  */