* add timers for delayed responses [20020721]
* Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031]
* Mike Anderson <andmike@us.ibm.com> sysfs work [20021118]
- * dpg: change style of boot options to "scsi_debug.num_devs=2" and
- * module options to "modprobe scsi_debug num_devs=2" [20021221]
+ * dpg: change style of boot options to "scsi_debug.num_tgts=2" and
+ * module options to "modprobe scsi_debug num_tgts=2" [20021221]
*/
#include <linux/config.h>
#include "scsi_debug.h"
-static const char * scsi_debug_version_str = "Version: 1.68 (20030314)";
+static const char * scsi_debug_version_str = "Version: 1.69 (20030329)";
+
+/* Additional Sense Code (ASC) used */
+#define NO_ADDED_SENSE 0x0
+#define UNRECOVERED_READ_ERR 0x11
+#define INVALID_OPCODE 0x20
+#define ADDR_OUT_OF_RANGE 0x21
+#define INVALID_FIELD_IN_CDB 0x24
+#define POWERON_RESET 0x29
+#define SAVING_PARAMS_UNSUP 0x39
+#define THRESHHOLD_EXCEEDED 0x5d
#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
/* Default values for driver parameters */
-#define DEF_NUM_DEVS 1
+#define DEF_NUM_HOST 1
+#define DEF_NUM_TGTS 1
+#define DEF_MAX_LUNS 1
+/* With these defaults, this driver will make 1 host with 1 target
+ * (id 0) containing 1 logical unit (lun 0). That is 1 device.
+ */
#define DEF_DEV_SIZE_MB 8
#define DEF_EVERY_NTH 0
#define DEF_DELAY 1
-#define DEF_MAX_LUNS 2
#define DEF_SCSI_LEVEL 3
-#define DEF_NUM_HOST 1
#define DEF_OPTS 0
/* bit mask values for scsi_debug_opts */
* sector on read commands: */
#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
+/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
+ * or "peripheral device" addressing (value 0) */
+#define SAM2_LUN_ADDRESS_METHOD 0
+
static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
-static int scsi_debug_num_devs = DEF_NUM_DEVS; /* max devs per host */
+static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
static int scsi_debug_opts = DEF_OPTS;
static int scsi_debug_every_nth = DEF_EVERY_NTH;
static int scsi_debug_cmnd_count = 0;
sbuff = devip->sense_buff;
memcpy(buff, sbuff, (bufflen < SDEBUG_SENSE_LEN) ?
bufflen : SDEBUG_SENSE_LEN);
- mk_sense_buffer(devip, 0, 0x0, 0, 7);
+ mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0, 7);
} else {
memset(buff, 0, bufflen);
buff[0] = 0x70;
}
errsts = resp_read(SCpnt, upper_blk, block, num, devip);
if (inj_recovered && (0 == errsts)) {
- mk_sense_buffer(devip, RECOVERED_ERROR, 0x5d, 0, 14);
+ mk_sense_buffer(devip, RECOVERED_ERROR,
+ THRESHHOLD_EXCEEDED, 0, 18);
errsts = check_condition_result;
}
break;
}
errsts = resp_write(SCpnt, upper_blk, block, num, devip);
if (inj_recovered && (0 == errsts)) {
- mk_sense_buffer(devip, RECOVERED_ERROR, 0x5d, 0, 14);
+ mk_sense_buffer(devip, RECOVERED_ERROR,
+ THRESHHOLD_EXCEEDED, 0, 18);
errsts = check_condition_result;
}
break;
default:
if ((errsts = check_reset(SCpnt, devip)))
break;
- mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x20, 0, 14);
+ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0, 18);
errsts = check_condition_result;
break;
}
{
if (devip->reset) {
devip->reset = 0;
- mk_sense_buffer(devip, UNIT_ATTENTION, 0x29, 0, 14);
+ mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0, 18);
return check_condition_result;
}
return 0;
pq_pdt = PERIPH_DEVICE_TYPE(target);
arr[0] = pq_pdt;
if (0x2 & cmd[1]) { /* CMDDT bit set */
- mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14);
+ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
+ 0, 18);
return check_condition_result;
} else if (0x1 & cmd[1]) { /* EVPD bit set */
int dev_id_num, len;
dev_id_str, len);
} else {
/* Illegal request, invalid field in cdb */
- mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14);
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_CDB, 0, 18);
return check_condition_result;
}
memcpy(buff, arr, min_len);
memset(buff, 0, bufflen);
memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
if (0x3 == pcontrol) { /* Saving values not supported */
- mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x39, 0, 14);
+ mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
+ 0, 18);
return check_condition_result;
}
dev_spec = DEV_READONLY(target) ? 0x80 : 0x0;
offset += len;
break;
default:
- mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14);
+ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
+ 0, 18);
return check_condition_result;
}
if (msense_6)
unsigned long iflags;
if (upper_blk || (block + num > sdebug_capacity)) {
- mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x21, 0, 14);
+ mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
+ 0, 18);
return check_condition_result;
}
if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
(block <= OPT_MEDIUM_ERR_ADDR) &&
((block + num) > OPT_MEDIUM_ERR_ADDR)) {
- mk_sense_buffer(devip, MEDIUM_ERROR, 0x11, 0, 14);
+ mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
+ 0, 18);
/* claim unrecoverable read error */
return check_condition_result;
}
unsigned long iflags;
if (upper_blk || (block + num > sdebug_capacity)) {
- mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x21, 0, 14);
+ mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
+ 0, 18);
return check_condition_result;
}
static int resp_report_luns(unsigned char * cmd, unsigned char * buff,
int bufflen, struct sdebug_dev_info * devip)
{
- unsigned int alloc_len, lun_cnt, i;
+ unsigned int alloc_len;
+ int lun_cnt, i, upper;
int select_report = (int)cmd[2];
ScsiLun *one_lun;
alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
if ((alloc_len < 16) || (select_report > 2)) {
- mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14);
+ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
+ 0, 18);
return check_condition_result;
}
- if (bufflen > 3) {
- lun_cnt = min((int)(bufflen / sizeof(ScsiLun)),
- (int)scsi_debug_max_luns);
+ if (bufflen > 8) { /* can produce response with up to 16k luns
+ (lun 0 to lun 16383) */
memset(buff, 0, bufflen);
- buff[3] = 8 * lun_cnt;
- one_lun = (ScsiLun*) &buff[0];
- for (i = 0; i < lun_cnt; i++)
- one_lun[i].scsi_lun[1] = i;
+ lun_cnt = scsi_debug_max_luns;
+ buff[2] = ((sizeof(ScsiLun) * lun_cnt) >> 8) & 0xff;
+ buff[3] = (sizeof(ScsiLun) * lun_cnt) & 0xff;
+ lun_cnt = min((int)((bufflen - 8) / sizeof(ScsiLun)),
+ lun_cnt);
+ one_lun = (ScsiLun*) &buff[8];
+ for (i = 0; i < lun_cnt; i++) {
+ upper = (i >> 8) & 0x3f;
+ if (upper)
+ one_lun[i].scsi_lun[0] =
+ (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
+ one_lun[i].scsi_lun[1] = i & 0xff;
+ }
}
return 0;
}
if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
printk(KERN_INFO "scsi_debug: cmd ");
for (k = 0, num = cmnd->cmd_len; k < num; ++k)
- printk("%02x ", (int)cmnd->cmnd[k]);
+ printk("%02x ", (int)cmnd->cmnd[k]);
printk("\n");
if (scsi_result) {
struct scsi_device * sdp = cmnd->device;
* of sysfs parameters (which module_param doesn't yet support).
* Sysfs parameters defined explicitly below.
*/
-module_param_named(num_devs, scsi_debug_num_devs, int, 0);
+module_param_named(num_tgts, scsi_debug_num_tgts, int, 0);
module_param_named(max_luns, scsi_debug_max_luns, int, 0);
module_param_named(scsi_level, scsi_debug_scsi_level, int, 0);
module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, 0);
MODULE_DESCRIPTION("SCSI debug adapter driver");
MODULE_LICENSE("GPL");
-MODULE_PARM_DESC(num_devs, "number of SCSI devices per host to simulate");
+MODULE_PARM_DESC(num_tgts, "number of SCSI targets per host to simulate");
MODULE_PARM_DESC(max_luns, "number of SCSI LUNs per target to simulate");
MODULE_PARM_DESC(scsi_level, "SCSI level to simulate");
MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs");
static const char * scsi_debug_info(struct Scsi_Host * shp)
{
- sprintf(sdebug_info, "scsi_debug, %s, num_devs=%d, "
+ sprintf(sdebug_info, "scsi_debug, %s, num_tgts=%d, "
"dev_size_mb=%d, opts=0x%x", scsi_debug_version_str,
- scsi_debug_num_devs, scsi_debug_dev_size_mb,
+ scsi_debug_num_tgts, scsi_debug_dev_size_mb,
scsi_debug_opts);
return sdebug_info;
}
}
begin = 0;
pos = len = sprintf(buffer, "scsi_debug adapter driver, %s\n"
- "num_devs=%d, shared (ram) size=%d MB, opts=0x%x, "
+ "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
"every_nth=%d(curr:%d)\n"
"delay=%d, max_luns=%d, scsi_level=%d\n"
"sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
"number of aborts=%d, device_reset=%d, bus_resets=%d, "
"host_resets=%d\n",
- scsi_debug_version_str, scsi_debug_num_devs,
+ scsi_debug_version_str, scsi_debug_num_tgts,
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,
DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
sdebug_opts_store)
-static ssize_t sdebug_num_devs_show(struct device_driver * ddp, char * buf)
+static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
{
- return snprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_devs);
+ return snprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
}
-static ssize_t sdebug_num_devs_store(struct device_driver * ddp,
+static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
const char * buf, size_t count)
{
int n;
if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
- scsi_debug_num_devs = n;
+ scsi_debug_num_tgts = n;
return count;
}
return -EINVAL;
}
-DRIVER_ATTR(num_devs, S_IRUGO | S_IWUSR, sdebug_num_devs_show,
- sdebug_num_devs_store)
+DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
+ sdebug_num_tgts_store)
static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
{
{
return snprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
}
-DRIVER_ATTR(max_luns, S_IRUGO, sdebug_max_luns_show, NULL)
+static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
+ const char * buf, size_t count)
+{
+ int n;
+
+ if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
+ scsi_debug_max_luns = n;
+ return count;
+ }
+ return -EINVAL;
+}
+DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
+ sdebug_max_luns_store)
static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
{
{
driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_devs);
+ driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
- driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_devs);
+ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
}
static int sdebug_driver_probe(struct device * dev)
{
- int k;
+ int k, devs_per_host;
int error = 0;
struct sdebug_host_info *sdbg_host;
struct sdebug_dev_info *sdbg_devinfo;
INIT_LIST_HEAD(&sdbg_host->dev_info_list);
- for (k = 0; k < scsi_debug_num_devs; k++) {
+ devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
+ for (k = 0; k < devs_per_host; k++) {
sdbg_devinfo = kmalloc(sizeof(*sdbg_devinfo),GFP_KERNEL);
if (NULL == sdbg_devinfo) {
printk(KERN_ERR "%s: out of memory at line %d\n",
sdbg_host->shost = hpnt;
sdbg_host->dev = dev;
- hpnt->max_lun = scsi_debug_max_luns;
+ 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 = scsi_debug_max_luns;
error = scsi_add_host(hpnt, sdbg_host->dev);
if (error) {