*  SAS disks.
  *
  *
- *  For documentation see http://www.torque.net/sg/sdebug26.html
+ *  For documentation see http://sg.danny.cz/sg/sdebug26.html
  *
  *   D. Gilbert (dpg) work for Magneto-Optical device test [20010421]
  *   dpg: work for devfs large number of disks [20010809]
 #include "sd.h"
 #include "scsi_logging.h"
 
-#define SCSI_DEBUG_VERSION "1.81"
-static const char * scsi_debug_version_date = "20070104";
+#define SCSI_DEBUG_VERSION "1.82"
+static const char * scsi_debug_version_date = "20100324";
 
 /* Additional Sense Code (ASC) */
 #define NO_ADDITIONAL_SENSE 0x0
 #define SAM2_LUN_ADDRESS_METHOD 0
 #define SAM2_WLUN_REPORT_LUNS 0xc101
 
+/* Can queue up to this number of commands. Typically commands that
+ * that have a non-zero delay are queued. */
+#define SCSI_DEBUG_CANQUEUE  255
+
 static int scsi_debug_add_host = DEF_NUM_HOST;
 static int scsi_debug_delay = DEF_DELAY;
 static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
 static int scsi_debug_every_nth = DEF_EVERY_NTH;
 static int scsi_debug_max_luns = DEF_MAX_LUNS;
+static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE;
 static int scsi_debug_num_parts = DEF_NUM_PARTS;
+static int scsi_debug_no_uld = 0;
 static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
 static int scsi_debug_opts = DEF_OPTS;
 static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
 
 #define SDEBUG_SENSE_LEN 32
 
-#define SCSI_DEBUG_CANQUEUE  255
 #define SCSI_DEBUG_MAX_CMD_LEN 32
 
 struct sdebug_dev_info {
        struct sdebug_queued_cmd * sqcp;
        unsigned long iflags;
 
-       if (indx >= SCSI_DEBUG_CANQUEUE) {
+       if (indx >= scsi_debug_max_queue) {
                printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
                       "large\n");
                return;
                scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
                                        sdp->host->cmd_per_lun);
        blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
+       if (scsi_debug_no_uld)
+               sdp->no_uld_attach = 1;
        return 0;
 }
 
        struct sdebug_queued_cmd *sqcp;
 
        spin_lock_irqsave(&queued_arr_lock, iflags);
-       for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+       for (k = 0; k < scsi_debug_max_queue; ++k) {
                sqcp = &queued_arr[k];
                if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
                        del_timer_sync(&sqcp->cmnd_timer);
                }
        }
        spin_unlock_irqrestore(&queued_arr_lock, iflags);
-       return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
+       return (k < scsi_debug_max_queue) ? 1 : 0;
 }
 
 /* Deletes (stops) timers of all queued commands */
        struct sdebug_queued_cmd *sqcp;
 
        spin_lock_irqsave(&queued_arr_lock, iflags);
-       for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+       for (k = 0; k < scsi_debug_max_queue; ++k) {
                sqcp = &queued_arr[k];
                if (sqcp->in_use && sqcp->a_cmnd) {
                        del_timer_sync(&sqcp->cmnd_timer);
        struct sdebug_queued_cmd * sqcp;
 
        spin_lock_irqsave(&queued_arr_lock, iflags);
-       for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+       for (k = 0; k < scsi_debug_max_queue; ++k) {
                sqcp = &queued_arr[k];
                init_timer(&sqcp->cmnd_timer);
                sqcp->in_use = 0;
                struct sdebug_queued_cmd * sqcp = NULL;
 
                spin_lock_irqsave(&queued_arr_lock, iflags);
-               for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+               for (k = 0; k < scsi_debug_max_queue; ++k) {
                        sqcp = &queued_arr[k];
                        if (! sqcp->in_use)
                                break;
                }
-               if (k >= SCSI_DEBUG_CANQUEUE) {
+               if (k >= scsi_debug_max_queue) {
                        spin_unlock_irqrestore(&queued_arr_lock, iflags);
                        printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
                        return 1;       /* report busy to mid level */
 module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
 module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
 module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
+module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);
 module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
+module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);
 module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
 module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
 module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
 MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
 MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
+MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to 255(def))");
 MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
+MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
 MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
 MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
 MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
 DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
            sdebug_max_luns_store);
 
+static ssize_t sdebug_max_queue_show(struct device_driver * ddp, char * buf)
+{
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue);
+}
+static ssize_t sdebug_max_queue_store(struct device_driver * ddp,
+                                     const char * buf, size_t count)
+{
+        int n;
+
+       if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
+           (n <= SCSI_DEBUG_CANQUEUE)) {
+               scsi_debug_max_queue = n;
+               return count;
+       }
+       return -EINVAL;
+}
+DRIVER_ATTR(max_queue, S_IRUGO | S_IWUSR, sdebug_max_queue_show,
+           sdebug_max_queue_store);
+
+static ssize_t sdebug_no_uld_show(struct device_driver * ddp, char * buf)
+{
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld);
+}
+DRIVER_ATTR(no_uld, S_IRUGO, sdebug_no_uld_show, NULL);
+
 static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
 {
         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
        ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
        ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
        ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
+       ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_queue);
        ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
+       ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_uld);
        ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
        ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
        ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
        driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
        driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
        driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
+       driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_uld);
        driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
+       driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_queue);
        driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
        driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
        driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
 
        sdbg_host = to_sdebug_host(dev);
 
-        hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
-        if (NULL == hpnt) {
-                printk(KERN_ERR "%s: scsi_register failed\n", __func__);
-                error = -ENODEV;
+       sdebug_driver_template.can_queue = scsi_debug_max_queue;
+       hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
+       if (NULL == hpnt) {
+               printk(KERN_ERR "%s: scsi_register failed\n", __func__);
+               error = -ENODEV;
                return error;
-        }
+       }
 
         sdbg_host->shost = hpnt;
        *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;