diff options
author | Douglas Gilbert <dougg@torque.net> | 2006-09-16 20:30:47 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-09-23 18:37:44 -0400 |
commit | 231839102b54512ced7d3ee7fc9b8bcf5e3b583b (patch) | |
tree | 0136daa29d7f67c17da2dc02780a6dadcd4fb615 | |
parent | c9802cd9574a80444e689c7525627b40d7dc3a06 (diff) |
[SCSI] scsi_debug version 1.80
See http://www.torque.net/sg/sdebug26.html for more
information on the scsi_debug driver.
ChangeLog:
- add 'vpd_use_hostno' parameter to allow simulated hosts
to see the same set of targets (and luns). For testing
multipath software.
- add 'fake_rw' parameter to ignore the data in READ and
WRITE commands
- add support for log subpages (new in SPC-4)
- yield appropriate block descriptor for MODE SENSE
commands (only for pdt=0 (i.e. disks))
- REQUEST SENSE response no longer shows the stopped
power condition (SAT changed to agree with SPC-3)
Signed-off-by: Douglas Gilbert <dougg@torque.net>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r-- | drivers/scsi/scsi_debug.c | 230 |
1 files changed, 189 insertions, 41 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index a80303c6b3fd..9c0f35820e3e 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c | |||
@@ -1,5 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * linux/kernel/scsi_debug.c | ||
3 | * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv | 2 | * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv |
4 | * Copyright (C) 1992 Eric Youngdale | 3 | * Copyright (C) 1992 Eric Youngdale |
5 | * Simulate a host adapter with 2 disks attached. Do a lot of checking | 4 | * Simulate a host adapter with 2 disks attached. Do a lot of checking |
@@ -8,7 +7,9 @@ | |||
8 | * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | 7 | * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
9 | * | 8 | * |
10 | * This version is more generic, simulating a variable number of disk | 9 | * This version is more generic, simulating a variable number of disk |
11 | * (or disk like devices) sharing a common amount of RAM | 10 | * (or disk like devices) sharing a common amount of RAM. To be more |
11 | * realistic, the simulated devices have the transport attributes of | ||
12 | * SAS disks. | ||
12 | * | 13 | * |
13 | * | 14 | * |
14 | * For documentation see http://www.torque.net/sg/sdebug26.html | 15 | * For documentation see http://www.torque.net/sg/sdebug26.html |
@@ -50,8 +51,8 @@ | |||
50 | #include "scsi_logging.h" | 51 | #include "scsi_logging.h" |
51 | #include "scsi_debug.h" | 52 | #include "scsi_debug.h" |
52 | 53 | ||
53 | #define SCSI_DEBUG_VERSION "1.79" | 54 | #define SCSI_DEBUG_VERSION "1.80" |
54 | static const char * scsi_debug_version_date = "20060604"; | 55 | static const char * scsi_debug_version_date = "20060914"; |
55 | 56 | ||
56 | /* Additional Sense Code (ASC) used */ | 57 | /* Additional Sense Code (ASC) used */ |
57 | #define NO_ADDITIONAL_SENSE 0x0 | 58 | #define NO_ADDITIONAL_SENSE 0x0 |
@@ -86,6 +87,8 @@ static const char * scsi_debug_version_date = "20060604"; | |||
86 | #define DEF_D_SENSE 0 | 87 | #define DEF_D_SENSE 0 |
87 | #define DEF_NO_LUN_0 0 | 88 | #define DEF_NO_LUN_0 0 |
88 | #define DEF_VIRTUAL_GB 0 | 89 | #define DEF_VIRTUAL_GB 0 |
90 | #define DEF_FAKE_RW 0 | ||
91 | #define DEF_VPD_USE_HOSTNO 1 | ||
89 | 92 | ||
90 | /* bit mask values for scsi_debug_opts */ | 93 | /* bit mask values for scsi_debug_opts */ |
91 | #define SCSI_DEBUG_OPT_NOISE 1 | 94 | #define SCSI_DEBUG_OPT_NOISE 1 |
@@ -127,6 +130,8 @@ static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */ | |||
127 | static int scsi_debug_dsense = DEF_D_SENSE; | 130 | static int scsi_debug_dsense = DEF_D_SENSE; |
128 | static int scsi_debug_no_lun_0 = DEF_NO_LUN_0; | 131 | static int scsi_debug_no_lun_0 = DEF_NO_LUN_0; |
129 | static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; | 132 | static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; |
133 | static int scsi_debug_fake_rw = DEF_FAKE_RW; | ||
134 | static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; | ||
130 | 135 | ||
131 | static int scsi_debug_cmnd_count = 0; | 136 | static int scsi_debug_cmnd_count = 0; |
132 | 137 | ||
@@ -423,6 +428,8 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) | |||
423 | case READ_6: | 428 | case READ_6: |
424 | if ((errsts = check_readiness(SCpnt, 0, devip))) | 429 | if ((errsts = check_readiness(SCpnt, 0, devip))) |
425 | break; | 430 | break; |
431 | if (scsi_debug_fake_rw) | ||
432 | break; | ||
426 | if ((*cmd) == READ_16) { | 433 | if ((*cmd) == READ_16) { |
427 | for (lba = 0, j = 0; j < 8; ++j) { | 434 | for (lba = 0, j = 0; j < 8; ++j) { |
428 | if (j > 0) | 435 | if (j > 0) |
@@ -465,6 +472,8 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) | |||
465 | case WRITE_6: | 472 | case WRITE_6: |
466 | if ((errsts = check_readiness(SCpnt, 0, devip))) | 473 | if ((errsts = check_readiness(SCpnt, 0, devip))) |
467 | break; | 474 | break; |
475 | if (scsi_debug_fake_rw) | ||
476 | break; | ||
468 | if ((*cmd) == WRITE_16) { | 477 | if ((*cmd) == WRITE_16) { |
469 | for (lba = 0, j = 0; j < 8; ++j) { | 478 | for (lba = 0, j = 0; j < 8; ++j) { |
470 | if (j > 0) | 479 | if (j > 0) |
@@ -941,6 +950,8 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, | |||
941 | char lu_id_str[6]; | 950 | char lu_id_str[6]; |
942 | int host_no = devip->sdbg_host->shost->host_no; | 951 | int host_no = devip->sdbg_host->shost->host_no; |
943 | 952 | ||
953 | if (0 == scsi_debug_vpd_use_hostno) | ||
954 | host_no = 0; | ||
944 | lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) + | 955 | lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) + |
945 | (devip->target * 1000) + devip->lun); | 956 | (devip->target * 1000) + devip->lun); |
946 | target_dev_id = ((host_no + 1) * 2000) + | 957 | target_dev_id = ((host_no + 1) * 2000) + |
@@ -1059,19 +1070,6 @@ static int resp_requests(struct scsi_cmnd * scp, | |||
1059 | arr[12] = THRESHOLD_EXCEEDED; | 1070 | arr[12] = THRESHOLD_EXCEEDED; |
1060 | arr[13] = 0xff; /* TEST set and MRIE==6 */ | 1071 | arr[13] = 0xff; /* TEST set and MRIE==6 */ |
1061 | } | 1072 | } |
1062 | } else if (devip->stopped) { | ||
1063 | if (want_dsense) { | ||
1064 | arr[0] = 0x72; | ||
1065 | arr[1] = 0x0; /* NO_SENSE in sense_key */ | ||
1066 | arr[2] = LOW_POWER_COND_ON; | ||
1067 | arr[3] = 0x0; /* TEST set and MRIE==6 */ | ||
1068 | } else { | ||
1069 | arr[0] = 0x70; | ||
1070 | arr[2] = 0x0; /* NO_SENSE in sense_key */ | ||
1071 | arr[7] = 0xa; /* 18 byte sense buffer */ | ||
1072 | arr[12] = LOW_POWER_COND_ON; | ||
1073 | arr[13] = 0x0; /* TEST set and MRIE==6 */ | ||
1074 | } | ||
1075 | } else { | 1073 | } else { |
1076 | memcpy(arr, sbuff, SDEBUG_SENSE_LEN); | 1074 | memcpy(arr, sbuff, SDEBUG_SENSE_LEN); |
1077 | if ((cmd[1] & 1) && (! scsi_debug_dsense)) { | 1075 | if ((cmd[1] & 1) && (! scsi_debug_dsense)) { |
@@ -1325,21 +1323,26 @@ static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) | |||
1325 | static int resp_mode_sense(struct scsi_cmnd * scp, int target, | 1323 | static int resp_mode_sense(struct scsi_cmnd * scp, int target, |
1326 | struct sdebug_dev_info * devip) | 1324 | struct sdebug_dev_info * devip) |
1327 | { | 1325 | { |
1328 | unsigned char dbd; | 1326 | unsigned char dbd, llbaa; |
1329 | int pcontrol, pcode, subpcode; | 1327 | int pcontrol, pcode, subpcode, bd_len; |
1330 | unsigned char dev_spec; | 1328 | unsigned char dev_spec; |
1331 | int alloc_len, msense_6, offset, len, errsts, target_dev_id; | 1329 | int k, alloc_len, msense_6, offset, len, errsts, target_dev_id; |
1332 | unsigned char * ap; | 1330 | unsigned char * ap; |
1333 | unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; | 1331 | unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; |
1334 | unsigned char *cmd = (unsigned char *)scp->cmnd; | 1332 | unsigned char *cmd = (unsigned char *)scp->cmnd; |
1335 | 1333 | ||
1336 | if ((errsts = check_readiness(scp, 1, devip))) | 1334 | if ((errsts = check_readiness(scp, 1, devip))) |
1337 | return errsts; | 1335 | return errsts; |
1338 | dbd = cmd[1] & 0x8; | 1336 | dbd = !!(cmd[1] & 0x8); |
1339 | pcontrol = (cmd[2] & 0xc0) >> 6; | 1337 | pcontrol = (cmd[2] & 0xc0) >> 6; |
1340 | pcode = cmd[2] & 0x3f; | 1338 | pcode = cmd[2] & 0x3f; |
1341 | subpcode = cmd[3]; | 1339 | subpcode = cmd[3]; |
1342 | msense_6 = (MODE_SENSE == cmd[0]); | 1340 | msense_6 = (MODE_SENSE == cmd[0]); |
1341 | llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10); | ||
1342 | if ((0 == scsi_debug_ptype) && (0 == dbd)) | ||
1343 | bd_len = llbaa ? 16 : 8; | ||
1344 | else | ||
1345 | bd_len = 0; | ||
1343 | alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]); | 1346 | alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]); |
1344 | memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); | 1347 | memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); |
1345 | if (0x3 == pcontrol) { /* Saving values not supported */ | 1348 | if (0x3 == pcontrol) { /* Saving values not supported */ |
@@ -1349,15 +1352,58 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, | |||
1349 | } | 1352 | } |
1350 | target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + | 1353 | target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + |
1351 | (devip->target * 1000) - 3; | 1354 | (devip->target * 1000) - 3; |
1352 | dev_spec = DEV_READONLY(target) ? 0x80 : 0x0; | 1355 | /* set DPOFUA bit for disks */ |
1356 | if (0 == scsi_debug_ptype) | ||
1357 | dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10; | ||
1358 | else | ||
1359 | dev_spec = 0x0; | ||
1353 | if (msense_6) { | 1360 | if (msense_6) { |
1354 | arr[2] = dev_spec; | 1361 | arr[2] = dev_spec; |
1362 | arr[3] = bd_len; | ||
1355 | offset = 4; | 1363 | offset = 4; |
1356 | } else { | 1364 | } else { |
1357 | arr[3] = dev_spec; | 1365 | arr[3] = dev_spec; |
1366 | if (16 == bd_len) | ||
1367 | arr[4] = 0x1; /* set LONGLBA bit */ | ||
1368 | arr[7] = bd_len; /* assume 255 or less */ | ||
1358 | offset = 8; | 1369 | offset = 8; |
1359 | } | 1370 | } |
1360 | ap = arr + offset; | 1371 | ap = arr + offset; |
1372 | if ((bd_len > 0) && (0 == sdebug_capacity)) { | ||
1373 | if (scsi_debug_virtual_gb > 0) { | ||
1374 | sdebug_capacity = 2048 * 1024; | ||
1375 | sdebug_capacity *= scsi_debug_virtual_gb; | ||
1376 | } else | ||
1377 | sdebug_capacity = sdebug_store_sectors; | ||
1378 | } | ||
1379 | if (8 == bd_len) { | ||
1380 | if (sdebug_capacity > 0xfffffffe) { | ||
1381 | ap[0] = 0xff; | ||
1382 | ap[1] = 0xff; | ||
1383 | ap[2] = 0xff; | ||
1384 | ap[3] = 0xff; | ||
1385 | } else { | ||
1386 | ap[0] = (sdebug_capacity >> 24) & 0xff; | ||
1387 | ap[1] = (sdebug_capacity >> 16) & 0xff; | ||
1388 | ap[2] = (sdebug_capacity >> 8) & 0xff; | ||
1389 | ap[3] = sdebug_capacity & 0xff; | ||
1390 | } | ||
1391 | ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; | ||
1392 | ap[7] = SECT_SIZE_PER(target) & 0xff; | ||
1393 | offset += bd_len; | ||
1394 | ap = arr + offset; | ||
1395 | } else if (16 == bd_len) { | ||
1396 | unsigned long long capac = sdebug_capacity; | ||
1397 | |||
1398 | for (k = 0; k < 8; ++k, capac >>= 8) | ||
1399 | ap[7 - k] = capac & 0xff; | ||
1400 | ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff; | ||
1401 | ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff; | ||
1402 | ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff; | ||
1403 | ap[15] = SECT_SIZE_PER(target) & 0xff; | ||
1404 | offset += bd_len; | ||
1405 | ap = arr + offset; | ||
1406 | } | ||
1361 | 1407 | ||
1362 | if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { | 1408 | if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { |
1363 | /* TODO: Control Extension page */ | 1409 | /* TODO: Control Extension page */ |
@@ -1471,7 +1517,7 @@ static int resp_mode_select(struct scsi_cmnd * scp, int mselect6, | |||
1471 | " IO sent=%d bytes\n", param_len, res); | 1517 | " IO sent=%d bytes\n", param_len, res); |
1472 | md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2); | 1518 | md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2); |
1473 | bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]); | 1519 | bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]); |
1474 | if ((md_len > 2) || (0 != bd_len)) { | 1520 | if (md_len > 2) { |
1475 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | 1521 | mk_sense_buffer(devip, ILLEGAL_REQUEST, |
1476 | INVALID_FIELD_IN_PARAM_LIST, 0); | 1522 | INVALID_FIELD_IN_PARAM_LIST, 0); |
1477 | return check_condition_result; | 1523 | return check_condition_result; |
@@ -1544,7 +1590,7 @@ static int resp_ie_l_pg(unsigned char * arr) | |||
1544 | static int resp_log_sense(struct scsi_cmnd * scp, | 1590 | static int resp_log_sense(struct scsi_cmnd * scp, |
1545 | struct sdebug_dev_info * devip) | 1591 | struct sdebug_dev_info * devip) |
1546 | { | 1592 | { |
1547 | int ppc, sp, pcontrol, pcode, alloc_len, errsts, len, n; | 1593 | int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n; |
1548 | unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; | 1594 | unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; |
1549 | unsigned char *cmd = (unsigned char *)scp->cmnd; | 1595 | unsigned char *cmd = (unsigned char *)scp->cmnd; |
1550 | 1596 | ||
@@ -1560,23 +1606,63 @@ static int resp_log_sense(struct scsi_cmnd * scp, | |||
1560 | } | 1606 | } |
1561 | pcontrol = (cmd[2] & 0xc0) >> 6; | 1607 | pcontrol = (cmd[2] & 0xc0) >> 6; |
1562 | pcode = cmd[2] & 0x3f; | 1608 | pcode = cmd[2] & 0x3f; |
1609 | subpcode = cmd[3] & 0xff; | ||
1563 | alloc_len = (cmd[7] << 8) + cmd[8]; | 1610 | alloc_len = (cmd[7] << 8) + cmd[8]; |
1564 | arr[0] = pcode; | 1611 | arr[0] = pcode; |
1565 | switch (pcode) { | 1612 | if (0 == subpcode) { |
1566 | case 0x0: /* Supported log pages log page */ | 1613 | switch (pcode) { |
1567 | n = 4; | 1614 | case 0x0: /* Supported log pages log page */ |
1568 | arr[n++] = 0x0; /* this page */ | 1615 | n = 4; |
1569 | arr[n++] = 0xd; /* Temperature */ | 1616 | arr[n++] = 0x0; /* this page */ |
1570 | arr[n++] = 0x2f; /* Informational exceptions */ | 1617 | arr[n++] = 0xd; /* Temperature */ |
1571 | arr[3] = n - 4; | 1618 | arr[n++] = 0x2f; /* Informational exceptions */ |
1572 | break; | 1619 | arr[3] = n - 4; |
1573 | case 0xd: /* Temperature log page */ | 1620 | break; |
1574 | arr[3] = resp_temp_l_pg(arr + 4); | 1621 | case 0xd: /* Temperature log page */ |
1575 | break; | 1622 | arr[3] = resp_temp_l_pg(arr + 4); |
1576 | case 0x2f: /* Informational exceptions log page */ | 1623 | break; |
1577 | arr[3] = resp_ie_l_pg(arr + 4); | 1624 | case 0x2f: /* Informational exceptions log page */ |
1578 | break; | 1625 | arr[3] = resp_ie_l_pg(arr + 4); |
1579 | default: | 1626 | break; |
1627 | default: | ||
1628 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | ||
1629 | INVALID_FIELD_IN_CDB, 0); | ||
1630 | return check_condition_result; | ||
1631 | } | ||
1632 | } else if (0xff == subpcode) { | ||
1633 | arr[0] |= 0x40; | ||
1634 | arr[1] = subpcode; | ||
1635 | switch (pcode) { | ||
1636 | case 0x0: /* Supported log pages and subpages log page */ | ||
1637 | n = 4; | ||
1638 | arr[n++] = 0x0; | ||
1639 | arr[n++] = 0x0; /* 0,0 page */ | ||
1640 | arr[n++] = 0x0; | ||
1641 | arr[n++] = 0xff; /* this page */ | ||
1642 | arr[n++] = 0xd; | ||
1643 | arr[n++] = 0x0; /* Temperature */ | ||
1644 | arr[n++] = 0x2f; | ||
1645 | arr[n++] = 0x0; /* Informational exceptions */ | ||
1646 | arr[3] = n - 4; | ||
1647 | break; | ||
1648 | case 0xd: /* Temperature subpages */ | ||
1649 | n = 4; | ||
1650 | arr[n++] = 0xd; | ||
1651 | arr[n++] = 0x0; /* Temperature */ | ||
1652 | arr[3] = n - 4; | ||
1653 | break; | ||
1654 | case 0x2f: /* Informational exceptions subpages */ | ||
1655 | n = 4; | ||
1656 | arr[n++] = 0x2f; | ||
1657 | arr[n++] = 0x0; /* Informational exceptions */ | ||
1658 | arr[3] = n - 4; | ||
1659 | break; | ||
1660 | default: | ||
1661 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | ||
1662 | INVALID_FIELD_IN_CDB, 0); | ||
1663 | return check_condition_result; | ||
1664 | } | ||
1665 | } else { | ||
1580 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | 1666 | mk_sense_buffer(devip, ILLEGAL_REQUEST, |
1581 | INVALID_FIELD_IN_CDB, 0); | 1667 | INVALID_FIELD_IN_CDB, 0); |
1582 | return check_condition_result; | 1668 | return check_condition_result; |
@@ -2151,11 +2237,18 @@ static int schedule_resp(struct scsi_cmnd * cmnd, | |||
2151 | } | 2237 | } |
2152 | } | 2238 | } |
2153 | 2239 | ||
2240 | /* Note: The following macros create attribute files in the | ||
2241 | /sys/module/scsi_debug/parameters directory. Unfortunately this | ||
2242 | driver is unaware of a change and cannot trigger auxiliary actions | ||
2243 | as it can when the corresponding attribute in the | ||
2244 | /sys/bus/pseudo/drivers/scsi_debug directory is changed. | ||
2245 | */ | ||
2154 | module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR); | 2246 | module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR); |
2155 | module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR); | 2247 | module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR); |
2156 | module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO); | 2248 | module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO); |
2157 | module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR); | 2249 | module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR); |
2158 | module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR); | 2250 | module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR); |
2251 | module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR); | ||
2159 | module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR); | 2252 | module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR); |
2160 | module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR); | 2253 | module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR); |
2161 | module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO); | 2254 | module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO); |
@@ -2164,6 +2257,8 @@ module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR); | |||
2164 | module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR); | 2257 | module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR); |
2165 | module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO); | 2258 | module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO); |
2166 | module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); | 2259 | module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); |
2260 | module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, | ||
2261 | S_IRUGO | S_IWUSR); | ||
2167 | 2262 | ||
2168 | MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); | 2263 | MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); |
2169 | MODULE_DESCRIPTION("SCSI debug adapter driver"); | 2264 | MODULE_DESCRIPTION("SCSI debug adapter driver"); |
@@ -2175,6 +2270,7 @@ MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)"); | |||
2175 | MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)"); | 2270 | MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)"); |
2176 | MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); | 2271 | MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); |
2177 | MODULE_PARM_DESC(every_nth, "timeout every nth command(def=100)"); | 2272 | MODULE_PARM_DESC(every_nth, "timeout every nth command(def=100)"); |
2273 | MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); | ||
2178 | MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); | 2274 | MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); |
2179 | MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); | 2275 | MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); |
2180 | MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); | 2276 | MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); |
@@ -2183,6 +2279,7 @@ MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->... (def=0)"); | |||
2183 | MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); | 2279 | MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); |
2184 | MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); | 2280 | MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); |
2185 | MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); | 2281 | MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); |
2282 | MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); | ||
2186 | 2283 | ||
2187 | 2284 | ||
2188 | static char sdebug_info[256]; | 2285 | static char sdebug_info[256]; |
@@ -2334,6 +2431,24 @@ static ssize_t sdebug_dsense_store(struct device_driver * ddp, | |||
2334 | DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show, | 2431 | DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show, |
2335 | sdebug_dsense_store); | 2432 | sdebug_dsense_store); |
2336 | 2433 | ||
2434 | static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf) | ||
2435 | { | ||
2436 | return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw); | ||
2437 | } | ||
2438 | static ssize_t sdebug_fake_rw_store(struct device_driver * ddp, | ||
2439 | const char * buf, size_t count) | ||
2440 | { | ||
2441 | int n; | ||
2442 | |||
2443 | if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { | ||
2444 | scsi_debug_fake_rw = n; | ||
2445 | return count; | ||
2446 | } | ||
2447 | return -EINVAL; | ||
2448 | } | ||
2449 | DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show, | ||
2450 | sdebug_fake_rw_store); | ||
2451 | |||
2337 | static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf) | 2452 | static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf) |
2338 | { | 2453 | { |
2339 | return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0); | 2454 | return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0); |
@@ -2487,6 +2602,31 @@ static ssize_t sdebug_add_host_store(struct device_driver * ddp, | |||
2487 | DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, | 2602 | DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, |
2488 | sdebug_add_host_store); | 2603 | sdebug_add_host_store); |
2489 | 2604 | ||
2605 | static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp, | ||
2606 | char * buf) | ||
2607 | { | ||
2608 | return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno); | ||
2609 | } | ||
2610 | static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp, | ||
2611 | const char * buf, size_t count) | ||
2612 | { | ||
2613 | int n; | ||
2614 | |||
2615 | if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { | ||
2616 | scsi_debug_vpd_use_hostno = n; | ||
2617 | return count; | ||
2618 | } | ||
2619 | return -EINVAL; | ||
2620 | } | ||
2621 | DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show, | ||
2622 | sdebug_vpd_use_hostno_store); | ||
2623 | |||
2624 | /* Note: The following function creates attribute files in the | ||
2625 | /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these | ||
2626 | files (over those found in the /sys/module/scsi_debug/parameters | ||
2627 | directory) is that auxiliary actions can be triggered when an attribute | ||
2628 | is changed. For example see: sdebug_add_host_store() above. | ||
2629 | */ | ||
2490 | static int do_create_driverfs_files(void) | 2630 | static int do_create_driverfs_files(void) |
2491 | { | 2631 | { |
2492 | int ret; | 2632 | int ret; |
@@ -2496,23 +2636,31 @@ static int do_create_driverfs_files(void) | |||
2496 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); | 2636 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); |
2497 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense); | 2637 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense); |
2498 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth); | 2638 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth); |
2639 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw); | ||
2499 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns); | 2640 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns); |
2500 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); | 2641 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0); |
2501 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts); | 2642 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts); |
2643 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); | ||
2502 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype); | 2644 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype); |
2503 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts); | 2645 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts); |
2504 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); | 2646 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); |
2647 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); | ||
2648 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); | ||
2505 | return ret; | 2649 | return ret; |
2506 | } | 2650 | } |
2507 | 2651 | ||
2508 | static void do_remove_driverfs_files(void) | 2652 | static void do_remove_driverfs_files(void) |
2509 | { | 2653 | { |
2654 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); | ||
2655 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); | ||
2510 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); | 2656 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); |
2511 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts); | 2657 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts); |
2512 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype); | 2658 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype); |
2513 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts); | ||
2514 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); | 2659 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); |
2660 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts); | ||
2661 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0); | ||
2515 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns); | 2662 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns); |
2663 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw); | ||
2516 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth); | 2664 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth); |
2517 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense); | 2665 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense); |
2518 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); | 2666 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); |