powerpc: Cleanup from l64 to ll64 change drivers/scsi
[safe/jmp/linux-2.6] / drivers / scsi / scsi_debug.c
index 4f4c5b7..6eebd0b 100644 (file)
@@ -46,6 +46,7 @@
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsicam.h>
+#include <scsi/scsi_eh.h>
 
 #include <linux/stat.h>
 
@@ -93,6 +94,7 @@ static const char * scsi_debug_version_date = "20070104";
 #define DEF_VIRTUAL_GB   0
 #define DEF_FAKE_RW    0
 #define DEF_VPD_USE_HOSTNO 1
+#define DEF_SECTOR_SIZE 512
 
 /* bit mask values for scsi_debug_opts */
 #define SCSI_DEBUG_OPT_NOISE   1
@@ -141,13 +143,13 @@ static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
 static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
 static int scsi_debug_fake_rw = DEF_FAKE_RW;
 static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
+static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
 
 static int scsi_debug_cmnd_count = 0;
 
 #define DEV_READONLY(TGT)      (0)
 #define DEV_REMOVEABLE(TGT)    (0)
 
-static unsigned int sdebug_store_size; /* in bytes */
 static unsigned int sdebug_store_sectors;
 static sector_t sdebug_capacity;       /* in sectors */
 
@@ -157,11 +159,6 @@ static int sdebug_heads;           /* heads per disk */
 static int sdebug_cylinders_per;       /* cylinders per surface */
 static int sdebug_sectors_per;         /* sectors per cylinder */
 
-/* default sector size is 512 bytes, 2**9 bytes */
-#define POW2_SECT_SIZE 9
-#define SECT_SIZE (1 << POW2_SECT_SIZE)
-#define SECT_SIZE_PER(TGT) SECT_SIZE
-
 #define SDEBUG_MAX_PARTS 4
 
 #define SDEBUG_SENSE_LEN 32
@@ -218,8 +215,6 @@ static DEFINE_RWLOCK(atomic_rw);
 
 static char sdebug_proc_name[] = "scsi_debug";
 
-static int sdebug_driver_probe(struct device *);
-static int sdebug_driver_remove(struct device *);
 static struct bus_type pseudo_lld_bus;
 
 static struct device_driver sdebug_driverfs_driver = {
@@ -235,49 +230,77 @@ static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
 static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
                                   0, 0, 0x0, 0x0};
 
-static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev);
-static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
-                           int asc, int asq);
-static void stop_all_queued(void);
-static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
-
 static int sdebug_add_adapter(void);
 static void sdebug_remove_adapter(void);
-static void sdebug_max_tgts_luns(void);
 
-static struct device pseudo_primary;
-static struct bus_type pseudo_lld_bus;
+static void sdebug_max_tgts_luns(void)
+{
+       struct sdebug_host_info *sdbg_host;
+       struct Scsi_Host *hpnt;
+
+       spin_lock(&sdebug_host_list_lock);
+       list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
+               hpnt = sdbg_host->shost;
+               if ((hpnt->this_id >= 0) &&
+                   (scsi_debug_num_tgts > hpnt->this_id))
+                       hpnt->max_id = scsi_debug_num_tgts + 1;
+               else
+                       hpnt->max_id = scsi_debug_num_tgts;
+               /* scsi_debug_max_luns; */
+               hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
+       }
+       spin_unlock(&sdebug_host_list_lock);
+}
+
+static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
+                           int asc, int asq)
+{
+       unsigned char *sbuff;
+
+       sbuff = devip->sense_buff;
+       memset(sbuff, 0, SDEBUG_SENSE_LEN);
+
+       scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
+
+       if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+               printk(KERN_INFO "scsi_debug:    [sense_key,asc,ascq]: "
+                     "[0x%x,0x%x,0x%x]\n", key, asc, asq);
+}
 
 static void get_data_transfer_info(unsigned char *cmd,
                                   unsigned long long *lba, unsigned int *num)
 {
-       int i;
-
        switch (*cmd) {
        case WRITE_16:
        case READ_16:
-               for (*lba = 0, i = 0; i < 8; ++i) {
-                       if (i > 0)
-                               *lba <<= 8;
-                       *lba += cmd[2 + i];
-               }
-               *num = cmd[13] + (cmd[12] << 8) +
-                       (cmd[11] << 16) + (cmd[10] << 24);
+               *lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
+                       (u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
+                       (u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
+                       (u64)cmd[3] << 48 | (u64)cmd[2] << 56;
+
+               *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
+                       (u32)cmd[10] << 24;
                break;
        case WRITE_12:
        case READ_12:
-               *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
-               *num = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
+               *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
+                       (u32)cmd[2] << 24;
+
+               *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
+                       (u32)cmd[6] << 24;
                break;
        case WRITE_10:
        case READ_10:
        case XDWRITEREAD_10:
-               *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
-               *num = cmd[8] + (cmd[7] << 8);
+               *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
+                       (u32)cmd[2] << 24;
+
+               *num = (u32)cmd[8] | (u32)cmd[7] << 8;
                break;
        case WRITE_6:
        case READ_6:
-               *lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
+               *lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
+                       (u32)(cmd[1] & 0x1f) << 16;
                *num = (0 == cmd[4]) ? 256 : cmd[4];
                break;
        default:
@@ -620,6 +643,14 @@ static int inquiry_evpd_b0(unsigned char * arr)
        return sizeof(vpdb0_data);
 }
 
+static int inquiry_evpd_b1(unsigned char *arr)
+{
+       memset(arr, 0, 0x3c);
+       arr[0] = 0;
+       arr[1] = 1;
+
+       return 0x3c;
+}
 
 #define SDEBUG_LONG_INQ_SZ 96
 #define SDEBUG_MAX_INQ_ARR_SZ 584
@@ -675,6 +706,7 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,
                        arr[n++] = 0x88;  /* SCSI ports */
                        arr[n++] = 0x89;  /* ATA information */
                        arr[n++] = 0xb0;  /* Block limits (SBC) */
+                       arr[n++] = 0xb1;  /* Block characteristics (SBC) */
                        arr[3] = n - 4;   /* number of supported VPD pages */
                } else if (0x80 == cmd[2]) { /* unit serial number */
                        arr[1] = cmd[2];        /*sanity */
@@ -714,6 +746,9 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,
                } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
                        arr[1] = cmd[2];        /*sanity */
                        arr[3] = inquiry_evpd_b0(&arr[4]);
+               } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
+                       arr[1] = cmd[2];        /*sanity */
+                       arr[3] = inquiry_evpd_b1(&arr[4]);
                } else {
                        /* Illegal request, invalid field in cdb */
                        mk_sense_buffer(devip, ILLEGAL_REQUEST,
@@ -819,6 +854,14 @@ static int resp_start_stop(struct scsi_cmnd * scp,
        return 0;
 }
 
+static sector_t get_sdebug_capacity(void)
+{
+       if (scsi_debug_virtual_gb > 0)
+               return 2048 * 1024 * scsi_debug_virtual_gb;
+       else
+               return sdebug_store_sectors;
+}
+
 #define SDEBUG_READCAP_ARR_SZ 8
 static int resp_readcap(struct scsi_cmnd * scp,
                        struct sdebug_dev_info * devip)
@@ -830,11 +873,7 @@ static int resp_readcap(struct scsi_cmnd * scp,
        if ((errsts = check_readiness(scp, 1, devip)))
                return errsts;
        /* following just in case virtual_gb changed */
-       if (scsi_debug_virtual_gb > 0) {
-               sdebug_capacity = 2048 * 1024;
-               sdebug_capacity *= scsi_debug_virtual_gb;
-       } else
-               sdebug_capacity = sdebug_store_sectors;
+       sdebug_capacity = get_sdebug_capacity();
        memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
        if (sdebug_capacity < 0xffffffff) {
                capac = (unsigned int)sdebug_capacity - 1;
@@ -848,8 +887,8 @@ static int resp_readcap(struct scsi_cmnd * scp,
                arr[2] = 0xff;
                arr[3] = 0xff;
        }
-       arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
-       arr[7] = SECT_SIZE_PER(target) & 0xff;
+       arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
+       arr[7] = scsi_debug_sector_size & 0xff;
        return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
 }
 
@@ -867,19 +906,15 @@ static int resp_readcap16(struct scsi_cmnd * scp,
        alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
                     + cmd[13]);
        /* following just in case virtual_gb changed */
-       if (scsi_debug_virtual_gb > 0) {
-               sdebug_capacity = 2048 * 1024;
-               sdebug_capacity *= scsi_debug_virtual_gb;
-       } else
-               sdebug_capacity = sdebug_store_sectors;
+       sdebug_capacity = get_sdebug_capacity();
        memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
        capac = sdebug_capacity - 1;
        for (k = 0; k < 8; ++k, capac >>= 8)
                arr[7 - k] = capac & 0xff;
-       arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
-       arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
-       arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
-       arr[11] = SECT_SIZE_PER(target) & 0xff;
+       arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
+       arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
+       arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
+       arr[11] = scsi_debug_sector_size & 0xff;
        return fill_from_dev_buffer(scp, arr,
                                    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
 }
@@ -993,20 +1028,20 @@ static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
 
 static int resp_format_pg(unsigned char * p, int pcontrol, int target)
 {       /* Format device page for mode_sense */
-        unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
-                                     0, 0, 0, 0, 0, 0, 0, 0,
-                                     0, 0, 0, 0, 0x40, 0, 0, 0};
-
-        memcpy(p, format_pg, sizeof(format_pg));
-        p[10] = (sdebug_sectors_per >> 8) & 0xff;
-        p[11] = sdebug_sectors_per & 0xff;
-        p[12] = (SECT_SIZE >> 8) & 0xff;
-        p[13] = SECT_SIZE & 0xff;
-        if (DEV_REMOVEABLE(target))
-                p[20] |= 0x20; /* should agree with INQUIRY */
-        if (1 == pcontrol)
-                memset(p + 2, 0, sizeof(format_pg) - 2);
-        return sizeof(format_pg);
+       unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
+                                    0, 0, 0, 0, 0, 0, 0, 0,
+                                    0, 0, 0, 0, 0x40, 0, 0, 0};
+
+       memcpy(p, format_pg, sizeof(format_pg));
+       p[10] = (sdebug_sectors_per >> 8) & 0xff;
+       p[11] = sdebug_sectors_per & 0xff;
+       p[12] = (scsi_debug_sector_size >> 8) & 0xff;
+       p[13] = scsi_debug_sector_size & 0xff;
+       if (DEV_REMOVEABLE(target))
+               p[20] |= 0x20; /* should agree with INQUIRY */
+       if (1 == pcontrol)
+               memset(p + 2, 0, sizeof(format_pg) - 2);
+       return sizeof(format_pg);
 }
 
 static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
@@ -1165,13 +1200,9 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target,
                offset = 8;
        }
        ap = arr + offset;
-       if ((bd_len > 0) && (0 == sdebug_capacity)) {
-               if (scsi_debug_virtual_gb > 0) {
-                       sdebug_capacity = 2048 * 1024;
-                       sdebug_capacity *= scsi_debug_virtual_gb;
-               } else
-                       sdebug_capacity = sdebug_store_sectors;
-       }
+       if ((bd_len > 0) && (!sdebug_capacity))
+               sdebug_capacity = get_sdebug_capacity();
+
        if (8 == bd_len) {
                if (sdebug_capacity > 0xfffffffe) {
                        ap[0] = 0xff;
@@ -1184,8 +1215,8 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target,
                        ap[2] = (sdebug_capacity >> 8) & 0xff;
                        ap[3] = sdebug_capacity & 0xff;
                }
-               ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
-               ap[7] = SECT_SIZE_PER(target) & 0xff;
+               ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
+               ap[7] = scsi_debug_sector_size & 0xff;
                offset += bd_len;
                ap = arr + offset;
        } else if (16 == bd_len) {
@@ -1193,10 +1224,10 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target,
 
                for (k = 0; k < 8; ++k, capac >>= 8)
                        ap[7 - k] = capac & 0xff;
-               ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
-               ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
-               ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
-               ap[15] = SECT_SIZE_PER(target) & 0xff;
+               ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
+               ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
+               ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
+               ap[15] = scsi_debug_sector_size & 0xff;
                offset += bd_len;
                ap = arr + offset;
        }
@@ -1468,25 +1499,53 @@ static int resp_log_sense(struct scsi_cmnd * scp,
                    min(len, SDEBUG_MAX_INQ_ARR_SZ));
 }
 
-static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
-                    unsigned int num, struct sdebug_dev_info * devip)
+static int check_device_access_params(struct sdebug_dev_info *devi,
+                                     unsigned long long lba, unsigned int num)
 {
-       unsigned long iflags;
-       unsigned int block, from_bottom;
-       unsigned long long u;
-       int ret;
-
        if (lba + num > sdebug_capacity) {
-               mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
-                               0);
+               mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
                return check_condition_result;
        }
        /* transfer length excessive (tie in to block limits VPD page) */
        if (num > sdebug_store_sectors) {
-               mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
-                               0);
+               mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
                return check_condition_result;
        }
+       return 0;
+}
+
+static int do_device_access(struct scsi_cmnd *scmd,
+                           struct sdebug_dev_info *devi,
+                           unsigned long long lba, unsigned int num, int write)
+{
+       int ret;
+       unsigned int block, rest = 0;
+       int (*func)(struct scsi_cmnd *, unsigned char *, int);
+
+       func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
+
+       block = do_div(lba, sdebug_store_sectors);
+       if (block + num > sdebug_store_sectors)
+               rest = block + num - sdebug_store_sectors;
+
+       ret = func(scmd, fake_storep + (block * scsi_debug_sector_size),
+                  (num - rest) * scsi_debug_sector_size);
+       if (!ret && rest)
+               ret = func(scmd, fake_storep, rest * scsi_debug_sector_size);
+
+       return ret;
+}
+
+static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
+                    unsigned int num, struct sdebug_dev_info *devip)
+{
+       unsigned long iflags;
+       int ret;
+
+       ret = check_device_access_params(devip, lba, num);
+       if (ret)
+               return ret;
+
        if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
            (lba <= OPT_MEDIUM_ERR_ADDR) &&
            ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
@@ -1505,74 +1564,30 @@ static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
                return check_condition_result;
        }
        read_lock_irqsave(&atomic_rw, iflags);
-       if ((lba + num) <= sdebug_store_sectors)
-               ret = fill_from_dev_buffer(SCpnt,
-                                          fake_storep + (lba * SECT_SIZE),
-                                          num * SECT_SIZE);
-       else {
-               /* modulo when one arg is 64 bits needs do_div() */
-               u = lba;
-               block = do_div(u, sdebug_store_sectors);
-               from_bottom = 0;
-               if ((block + num) > sdebug_store_sectors)
-                       from_bottom = (block + num) - sdebug_store_sectors;
-               ret = fill_from_dev_buffer(SCpnt,
-                                          fake_storep + (block * SECT_SIZE),
-                                          (num - from_bottom) * SECT_SIZE);
-               if ((0 == ret) && (from_bottom > 0))
-                       ret = fill_from_dev_buffer(SCpnt, fake_storep,
-                                                  from_bottom * SECT_SIZE);
-       }
+       ret = do_device_access(SCpnt, devip, lba, num, 0);
        read_unlock_irqrestore(&atomic_rw, iflags);
        return ret;
 }
 
-static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
-                     unsigned int num, struct sdebug_dev_info * devip)
+static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
+                     unsigned int num, struct sdebug_dev_info *devip)
 {
        unsigned long iflags;
-       unsigned int block, to_bottom;
-       unsigned long long u;
-       int res;
+       int ret;
 
-       if (lba + num > sdebug_capacity) {
-               mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
-                               0);
-               return check_condition_result;
-       }
-       /* transfer length excessive (tie in to block limits VPD page) */
-       if (num > sdebug_store_sectors) {
-               mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
-                               0);
-               return check_condition_result;
-       }
+       ret = check_device_access_params(devip, lba, num);
+       if (ret)
+               return ret;
 
        write_lock_irqsave(&atomic_rw, iflags);
-       if ((lba + num) <= sdebug_store_sectors)
-               res = fetch_to_dev_buffer(SCpnt,
-                                         fake_storep + (lba * SECT_SIZE),
-                                         num * SECT_SIZE);
-       else {
-               /* modulo when one arg is 64 bits needs do_div() */
-               u = lba;
-               block = do_div(u, sdebug_store_sectors);
-               to_bottom = 0;
-               if ((block + num) > sdebug_store_sectors)
-                       to_bottom = (block + num) - sdebug_store_sectors;
-               res = fetch_to_dev_buffer(SCpnt,
-                                         fake_storep + (block * SECT_SIZE),
-                                         (num - to_bottom) * SECT_SIZE);
-               if ((0 == res) && (to_bottom > 0))
-                       res = fetch_to_dev_buffer(SCpnt, fake_storep,
-                                                 to_bottom * SECT_SIZE);
-       }
+       ret = do_device_access(SCpnt, devip, lba, num, 1);
        write_unlock_irqrestore(&atomic_rw, iflags);
-       if (-1 == res)
+       if (-1 == ret)
                return (DID_ERROR << 16);
-       else if ((res < (num * SECT_SIZE)) &&
+       else if ((ret < (num * scsi_debug_sector_size)) &&
                 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
                printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
-                      " IO sent=%d bytes\n", num * SECT_SIZE, res);
+                      " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
        return 0;
 }
 
@@ -1696,52 +1711,9 @@ static void timer_intr_handler(unsigned long indx)
        spin_unlock_irqrestore(&queued_arr_lock, iflags);
 }
 
-static int scsi_debug_slave_alloc(struct scsi_device * sdp)
-{
-       if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
-               printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
-                      sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
-       set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags);
-       return 0;
-}
-
-static int scsi_debug_slave_configure(struct scsi_device * sdp)
-{
-       struct sdebug_dev_info * devip;
 
-       if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
-               printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
-                      sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
-       if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
-               sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
-       devip = devInfoReg(sdp);
-       if (NULL == devip)
-               return 1;       /* no resources, will be marked offline */
-       sdp->hostdata = devip;
-       if (sdp->host->cmd_per_lun)
-               scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
-                                       sdp->host->cmd_per_lun);
-       blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
-       return 0;
-}
-
-static void scsi_debug_slave_destroy(struct scsi_device * sdp)
-{
-       struct sdebug_dev_info * devip =
-                               (struct sdebug_dev_info *)sdp->hostdata;
-
-       if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
-               printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
-                      sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
-       if (devip) {
-               /* make this slot avaliable for re-use */
-               devip->used = 0;
-               sdp->hostdata = NULL;
-       }
-}
-
-struct sdebug_dev_info *sdebug_device_create(struct sdebug_host_info *sdbg_host,
-                                            gfp_t flags)
+static struct sdebug_dev_info *
+sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
 {
        struct sdebug_dev_info *devip;
 
@@ -1781,7 +1753,7 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
                open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
                if (!open_devip) {
                        printk(KERN_ERR "%s: out of memory at line %d\n",
-                               __FUNCTION__, __LINE__);
+                               __func__, __LINE__);
                        return NULL;
                }
        }
@@ -1805,28 +1777,88 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
        return open_devip;
 }
 
-static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
-                           int asc, int asq)
+static int scsi_debug_slave_alloc(struct scsi_device *sdp)
 {
-       unsigned char * sbuff;
+       if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+               printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
+                      sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
+       queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
+       return 0;
+}
+
+static int scsi_debug_slave_configure(struct scsi_device *sdp)
+{
+       struct sdebug_dev_info *devip;
 
-       sbuff = devip->sense_buff;
-       memset(sbuff, 0, SDEBUG_SENSE_LEN);
-       if (scsi_debug_dsense) {
-               sbuff[0] = 0x72;  /* descriptor, current */
-               sbuff[1] = key;
-               sbuff[2] = asc;
-               sbuff[3] = asq;
-       } else {
-               sbuff[0] = 0x70;  /* fixed, current */
-               sbuff[2] = key;
-               sbuff[7] = 0xa;   /* implies 18 byte sense buffer */
-               sbuff[12] = asc;
-               sbuff[13] = asq;
-       }
        if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
-               printk(KERN_INFO "scsi_debug:    [sense_key,asc,ascq]: "
-                     "[0x%x,0x%x,0x%x]\n", key, asc, asq);
+               printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
+                      sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
+       if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
+               sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
+       devip = devInfoReg(sdp);
+       if (NULL == devip)
+               return 1;       /* no resources, will be marked offline */
+       sdp->hostdata = devip;
+       if (sdp->host->cmd_per_lun)
+               scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
+                                       sdp->host->cmd_per_lun);
+       blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
+       return 0;
+}
+
+static void scsi_debug_slave_destroy(struct scsi_device *sdp)
+{
+       struct sdebug_dev_info *devip =
+               (struct sdebug_dev_info *)sdp->hostdata;
+
+       if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+               printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
+                      sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
+       if (devip) {
+               /* make this slot avaliable for re-use */
+               devip->used = 0;
+               sdp->hostdata = NULL;
+       }
+}
+
+/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
+static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
+{
+       unsigned long iflags;
+       int k;
+       struct sdebug_queued_cmd *sqcp;
+
+       spin_lock_irqsave(&queued_arr_lock, iflags);
+       for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+               sqcp = &queued_arr[k];
+               if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
+                       del_timer_sync(&sqcp->cmnd_timer);
+                       sqcp->in_use = 0;
+                       sqcp->a_cmnd = NULL;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&queued_arr_lock, iflags);
+       return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
+}
+
+/* Deletes (stops) timers of all queued commands */
+static void stop_all_queued(void)
+{
+       unsigned long iflags;
+       int k;
+       struct sdebug_queued_cmd *sqcp;
+
+       spin_lock_irqsave(&queued_arr_lock, iflags);
+       for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+               sqcp = &queued_arr[k];
+               if (sqcp->in_use && sqcp->a_cmnd) {
+                       del_timer_sync(&sqcp->cmnd_timer);
+                       sqcp->in_use = 0;
+                       sqcp->a_cmnd = NULL;
+               }
+       }
+       spin_unlock_irqrestore(&queued_arr_lock, iflags);
 }
 
 static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
@@ -1916,46 +1948,6 @@ static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
        return SUCCESS;
 }
 
-/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
-static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
-{
-       unsigned long iflags;
-       int k;
-       struct sdebug_queued_cmd * sqcp;
-
-       spin_lock_irqsave(&queued_arr_lock, iflags);
-       for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
-               sqcp = &queued_arr[k];
-               if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
-                       del_timer_sync(&sqcp->cmnd_timer);
-                       sqcp->in_use = 0;
-                       sqcp->a_cmnd = NULL;
-                       break;
-               }
-       }
-       spin_unlock_irqrestore(&queued_arr_lock, iflags);
-       return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
-}
-
-/* Deletes (stops) timers of all queued commands */
-static void stop_all_queued(void)
-{
-       unsigned long iflags;
-       int k;
-       struct sdebug_queued_cmd * sqcp;
-
-       spin_lock_irqsave(&queued_arr_lock, iflags);
-       for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
-               sqcp = &queued_arr[k];
-               if (sqcp->in_use && sqcp->a_cmnd) {
-                       del_timer_sync(&sqcp->cmnd_timer);
-                       sqcp->in_use = 0;
-                       sqcp->a_cmnd = NULL;
-               }
-       }
-       spin_unlock_irqrestore(&queued_arr_lock, iflags);
-}
-
 /* Initializes timers in queued array */
 static void __init init_all_queued(void)
 {
@@ -1973,7 +1965,8 @@ static void __init init_all_queued(void)
        spin_unlock_irqrestore(&queued_arr_lock, iflags);
 }
 
-static void __init sdebug_build_parts(unsigned char * ramp)
+static void __init sdebug_build_parts(unsigned char *ramp,
+                                     unsigned long store_size)
 {
        struct partition * pp;
        int starts[SDEBUG_MAX_PARTS + 2];
@@ -1981,7 +1974,7 @@ static void __init sdebug_build_parts(unsigned char * ramp)
        int heads_by_sects, start_sec, end_sec;
 
        /* assume partition table already zeroed */
-       if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576))
+       if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
                return;
        if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
                scsi_debug_num_parts = SDEBUG_MAX_PARTS;
@@ -2079,7 +2072,6 @@ static int schedule_resp(struct scsi_cmnd * cmnd,
                return 0;
        }
 }
-
 /* Note: The following macros create attribute files in the
    /sys/module/scsi_debug/parameters directory. Unfortunately this
    driver is unaware of a change and cannot trigger auxiliary actions
@@ -2102,6 +2094,7 @@ module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
 module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
 module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
                   S_IRUGO | S_IWUSR);
+module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
 
 MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
 MODULE_DESCRIPTION("SCSI debug adapter driver");
@@ -2123,6 +2116,7 @@ MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
 MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
 MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
 MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
+MODULE_PARM_DESC(sector_size, "hardware sector size in bytes (def=512)");
 
 
 static char sdebug_info[256];
@@ -2175,8 +2169,9 @@ static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **sta
            scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
            scsi_debug_cmnd_count, scsi_debug_delay,
            scsi_debug_max_luns, scsi_debug_scsi_level,
-           SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
-           num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
+           scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
+           sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
+           num_host_resets);
        if (pos < offset) {
                len = 0;
                begin = pos;
@@ -2396,11 +2391,9 @@ static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
 
        if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
                scsi_debug_virtual_gb = n;
-               if (scsi_debug_virtual_gb > 0) {
-                       sdebug_capacity = 2048 * 1024;
-                       sdebug_capacity *= scsi_debug_virtual_gb;
-               } else
-                       sdebug_capacity = sdebug_store_sectors;
+
+               sdebug_capacity = get_sdebug_capacity();
+
                return count;
        }
        return -EINVAL;
@@ -2453,6 +2446,12 @@ static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
 DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
            sdebug_vpd_use_hostno_store);
 
+static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf)
+{
+       return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
+}
+DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL);
+
 /* Note: The following function creates attribute files in the
    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
    files (over those found in the /sys/module/scsi_debug/parameters
@@ -2478,11 +2477,13 @@ static int do_create_driverfs_files(void)
        ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
        ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
        ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
+       ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
        return ret;
 }
 
 static void do_remove_driverfs_files(void)
 {
+       driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
        driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
        driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
        driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
@@ -2500,22 +2501,41 @@ static void do_remove_driverfs_files(void)
        driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
 }
 
+static void pseudo_0_release(struct device *dev)
+{
+       if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+               printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
+}
+
+static struct device pseudo_primary = {
+       .init_name      = "pseudo_0",
+       .release        = pseudo_0_release,
+};
+
 static int __init scsi_debug_init(void)
 {
-       unsigned int sz;
+       unsigned long sz;
        int host_to_add;
        int k;
        int ret;
 
+       switch (scsi_debug_sector_size) {
+       case  512:
+       case 1024:
+       case 2048:
+       case 4096:
+               break;
+       default:
+               printk(KERN_ERR "scsi_debug_init: invalid sector_size %u\n",
+                      scsi_debug_sector_size);
+               return -EINVAL;
+       }
+
        if (scsi_debug_dev_size_mb < 1)
                scsi_debug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
-       sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576;
-       sdebug_store_sectors = sdebug_store_size / SECT_SIZE;
-       if (scsi_debug_virtual_gb > 0) {
-               sdebug_capacity = 2048 * 1024;
-               sdebug_capacity *= scsi_debug_virtual_gb;
-       } else
-               sdebug_capacity = sdebug_store_sectors;
+       sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
+       sdebug_store_sectors = sz / scsi_debug_sector_size;
+       sdebug_capacity = get_sdebug_capacity();
 
        /* play around with geometry, don't waste too much on track 0 */
        sdebug_heads = 8;
@@ -2534,7 +2554,6 @@ static int __init scsi_debug_init(void)
                               (sdebug_sectors_per * sdebug_heads);
        }
 
-       sz = sdebug_store_size;
        fake_storep = vmalloc(sz);
        if (NULL == fake_storep) {
                printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
@@ -2542,7 +2561,7 @@ static int __init scsi_debug_init(void)
        }
        memset(fake_storep, 0, sz);
        if (scsi_debug_num_parts > 0)
-               sdebug_build_parts(fake_storep);
+               sdebug_build_parts(fake_storep, sz);
 
        ret = device_register(&pseudo_primary);
        if (ret < 0) {
@@ -2619,30 +2638,6 @@ static void __exit scsi_debug_exit(void)
 device_initcall(scsi_debug_init);
 module_exit(scsi_debug_exit);
 
-static void pseudo_0_release(struct device * dev)
-{
-       if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
-               printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
-}
-
-static struct device pseudo_primary = {
-       .bus_id         = "pseudo_0",
-       .release        = pseudo_0_release,
-};
-
-static int pseudo_lld_bus_match(struct device *dev,
-                          struct device_driver *dev_driver)
-{
-        return 1;
-}
-
-static struct bus_type pseudo_lld_bus = {
-        .name = "pseudo",
-        .match = pseudo_lld_bus_match,
-       .probe = sdebug_driver_probe,
-       .remove = sdebug_driver_remove,
-};
-
 static void sdebug_release_adapter(struct device * dev)
 {
         struct sdebug_host_info *sdbg_host;
@@ -2661,7 +2656,7 @@ static int sdebug_add_adapter(void)
         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
         if (NULL == sdbg_host) {
                 printk(KERN_ERR "%s: out of memory at line %d\n",
-                       __FUNCTION__, __LINE__);
+                       __func__, __LINE__);
                 return -ENOMEM;
         }
 
@@ -2672,7 +2667,7 @@ static int sdebug_add_adapter(void)
                sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
                if (!sdbg_devinfo) {
                         printk(KERN_ERR "%s: out of memory at line %d\n",
-                               __FUNCTION__, __LINE__);
+                               __func__, __LINE__);
                         error = -ENOMEM;
                        goto clean;
                 }
@@ -2685,7 +2680,7 @@ static int sdebug_add_adapter(void)
         sdbg_host->dev.bus = &pseudo_lld_bus;
         sdbg_host->dev.parent = &pseudo_primary;
         sdbg_host->dev.release = &sdebug_release_adapter;
-        sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
+        dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
 
         error = device_register(&sdbg_host->dev);
 
@@ -2992,7 +2987,7 @@ static int sdebug_driver_probe(struct device * dev)
 
         hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
         if (NULL == hpnt) {
-                printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
+                printk(KERN_ERR "%s: scsi_register failed\n", __func__);
                 error = -ENODEV;
                return error;
         }
@@ -3007,7 +3002,7 @@ static int sdebug_driver_probe(struct device * dev)
 
         error = scsi_add_host(hpnt, &sdbg_host->dev);
         if (error) {
-                printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
+                printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
                 error = -ENODEV;
                scsi_host_put(hpnt);
         } else
@@ -3026,7 +3021,7 @@ static int sdebug_driver_remove(struct device * dev)
 
        if (!sdbg_host) {
                printk(KERN_ERR "%s: Unable to locate host info\n",
-                      __FUNCTION__);
+                      __func__);
                return -ENODEV;
        }
 
@@ -3042,20 +3037,15 @@ static int sdebug_driver_remove(struct device * dev)
         return 0;
 }
 
-static void sdebug_max_tgts_luns(void)
+static int pseudo_lld_bus_match(struct device *dev,
+                               struct device_driver *dev_driver)
 {
-       struct sdebug_host_info * sdbg_host;
-       struct Scsi_Host *hpnt;
-
-       spin_lock(&sdebug_host_list_lock);
-       list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
-               hpnt = sdbg_host->shost;
-               if ((hpnt->this_id >= 0) &&
-                   (scsi_debug_num_tgts > hpnt->this_id))
-                       hpnt->max_id = scsi_debug_num_tgts + 1;
-               else
-                       hpnt->max_id = scsi_debug_num_tgts;
-               hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
-       }
-       spin_unlock(&sdebug_host_list_lock);
+       return 1;
 }
+
+static struct bus_type pseudo_lld_bus = {
+       .name = "pseudo",
+       .match = pseudo_lld_bus_match,
+       .probe = sdebug_driver_probe,
+       .remove = sdebug_driver_remove,
+};