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 = {
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)
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 * SECT_SIZE),
+ (num - rest) * SECT_SIZE);
+ if (!ret && rest)
+ ret = func(scmd, fake_storep, rest * SECT_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)) {
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 * SECT_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 * SECT_SIZE, ret);
return 0;
}
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;
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);
+ set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags);
+ return 0;
+}
- sbuff = devip->sense_buff;
- memset(sbuff, 0, SDEBUG_SENSE_LEN);
+static int scsi_debug_slave_configure(struct scsi_device *sdp)
+{
+ struct sdebug_dev_info *devip;
- scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
+ 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: [sense_key,asc,ascq]: "
- "[0x%x,0x%x,0x%x]\n", key, asc, asq);
+ 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)
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)
{
}
static void __init sdebug_build_parts(unsigned char *ramp,
- unsigned int store_size)
+ unsigned long store_size)
{
struct partition * pp;
int starts[SDEBUG_MAX_PARTS + 2];
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
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 = {
+ .bus_id = "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;
if (scsi_debug_dev_size_mb < 1)
scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
- sz = (unsigned int)scsi_debug_dev_size_mb * 1048576;
+ sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
sdebug_store_sectors = sz / SECT_SIZE;
sdebug_capacity = get_sdebug_capacity();
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;
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,
+};