mirror of
https://github.com/torvalds/linux.git
synced 2024-10-24 22:20:55 +00:00
[SCSI] scsi_debug: error processing
After discussions in the thread titled: [PATCH] scsi_debug: illegal blocking memory allocation here is a patch containing the discussed fix and some other fixes and additions. The patch is against lk 2.6.20-rc3 . The version is bumped to 1.81 . ChangeLog: - Change several GFP_KERNEL allocations to GFP_ATOMIC as they can be called from queuecommand() context - check above allocation returns and if out of memory report DID_REQUEUE in two cases, DID_NO_CONNECT in another, and fail slave configure() in another - add support for WRITE BUFFER command - add aborted_command error injection support (opts mask 0x10), similar mechanism to recovered_error injection. Signed-off-by: Douglas Gilbert <dougg@torque.net> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
This commit is contained in:
parent
d780c3bf21
commit
6f3cbf552e
|
@ -51,10 +51,10 @@
|
||||||
#include "scsi_logging.h"
|
#include "scsi_logging.h"
|
||||||
#include "scsi_debug.h"
|
#include "scsi_debug.h"
|
||||||
|
|
||||||
#define SCSI_DEBUG_VERSION "1.80"
|
#define SCSI_DEBUG_VERSION "1.81"
|
||||||
static const char * scsi_debug_version_date = "20061018";
|
static const char * scsi_debug_version_date = "20070104";
|
||||||
|
|
||||||
/* Additional Sense Code (ASC) used */
|
/* Additional Sense Code (ASC) */
|
||||||
#define NO_ADDITIONAL_SENSE 0x0
|
#define NO_ADDITIONAL_SENSE 0x0
|
||||||
#define LOGICAL_UNIT_NOT_READY 0x4
|
#define LOGICAL_UNIT_NOT_READY 0x4
|
||||||
#define UNRECOVERED_READ_ERR 0x11
|
#define UNRECOVERED_READ_ERR 0x11
|
||||||
|
@ -65,9 +65,13 @@ static const char * scsi_debug_version_date = "20061018";
|
||||||
#define INVALID_FIELD_IN_PARAM_LIST 0x26
|
#define INVALID_FIELD_IN_PARAM_LIST 0x26
|
||||||
#define POWERON_RESET 0x29
|
#define POWERON_RESET 0x29
|
||||||
#define SAVING_PARAMS_UNSUP 0x39
|
#define SAVING_PARAMS_UNSUP 0x39
|
||||||
|
#define TRANSPORT_PROBLEM 0x4b
|
||||||
#define THRESHOLD_EXCEEDED 0x5d
|
#define THRESHOLD_EXCEEDED 0x5d
|
||||||
#define LOW_POWER_COND_ON 0x5e
|
#define LOW_POWER_COND_ON 0x5e
|
||||||
|
|
||||||
|
/* Additional Sense Code Qualifier (ASCQ) */
|
||||||
|
#define ACK_NAK_TO 0x3
|
||||||
|
|
||||||
#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
|
#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
|
||||||
|
|
||||||
/* Default values for driver parameters */
|
/* Default values for driver parameters */
|
||||||
|
@ -95,15 +99,20 @@ static const char * scsi_debug_version_date = "20061018";
|
||||||
#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
|
#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
|
||||||
#define SCSI_DEBUG_OPT_TIMEOUT 4
|
#define SCSI_DEBUG_OPT_TIMEOUT 4
|
||||||
#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
|
#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
|
||||||
|
#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
|
||||||
/* When "every_nth" > 0 then modulo "every_nth" commands:
|
/* When "every_nth" > 0 then modulo "every_nth" commands:
|
||||||
* - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
|
* - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
|
||||||
* - a RECOVERED_ERROR is simulated on successful read and write
|
* - a RECOVERED_ERROR is simulated on successful read and write
|
||||||
* commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
|
* commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
|
||||||
|
* - a TRANSPORT_ERROR is simulated on successful read and write
|
||||||
|
* commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
|
||||||
*
|
*
|
||||||
* When "every_nth" < 0 then after "- every_nth" commands:
|
* When "every_nth" < 0 then after "- every_nth" commands:
|
||||||
* - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
|
* - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
|
||||||
* - a RECOVERED_ERROR is simulated on successful read and write
|
* - a RECOVERED_ERROR is simulated on successful read and write
|
||||||
* commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
|
* commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
|
||||||
|
* - a TRANSPORT_ERROR is simulated on successful read and write
|
||||||
|
* commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
|
||||||
* This will continue until some other action occurs (e.g. the user
|
* This will continue until some other action occurs (e.g. the user
|
||||||
* writing a new value (other than -1 or 1) to every_nth via sysfs).
|
* writing a new value (other than -1 or 1) to every_nth via sysfs).
|
||||||
*/
|
*/
|
||||||
|
@ -315,6 +324,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
|
||||||
int target = SCpnt->device->id;
|
int target = SCpnt->device->id;
|
||||||
struct sdebug_dev_info * devip = NULL;
|
struct sdebug_dev_info * devip = NULL;
|
||||||
int inj_recovered = 0;
|
int inj_recovered = 0;
|
||||||
|
int inj_transport = 0;
|
||||||
int delay_override = 0;
|
int delay_override = 0;
|
||||||
|
|
||||||
if (done == NULL)
|
if (done == NULL)
|
||||||
|
@ -352,6 +362,8 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
|
||||||
return 0; /* ignore command causing timeout */
|
return 0; /* ignore command causing timeout */
|
||||||
else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
|
else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
|
||||||
inj_recovered = 1; /* to reads and writes below */
|
inj_recovered = 1; /* to reads and writes below */
|
||||||
|
else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
|
||||||
|
inj_transport = 1; /* to reads and writes below */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (devip->wlun) {
|
if (devip->wlun) {
|
||||||
|
@ -468,7 +480,11 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
|
||||||
mk_sense_buffer(devip, RECOVERED_ERROR,
|
mk_sense_buffer(devip, RECOVERED_ERROR,
|
||||||
THRESHOLD_EXCEEDED, 0);
|
THRESHOLD_EXCEEDED, 0);
|
||||||
errsts = check_condition_result;
|
errsts = check_condition_result;
|
||||||
}
|
} else if (inj_transport && (0 == errsts)) {
|
||||||
|
mk_sense_buffer(devip, ABORTED_COMMAND,
|
||||||
|
TRANSPORT_PROBLEM, ACK_NAK_TO);
|
||||||
|
errsts = check_condition_result;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case REPORT_LUNS: /* mandatory, ignore unit attention */
|
case REPORT_LUNS: /* mandatory, ignore unit attention */
|
||||||
delay_override = 1;
|
delay_override = 1;
|
||||||
|
@ -531,6 +547,9 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
|
||||||
delay_override = 1;
|
delay_override = 1;
|
||||||
errsts = check_readiness(SCpnt, 0, devip);
|
errsts = check_readiness(SCpnt, 0, devip);
|
||||||
break;
|
break;
|
||||||
|
case WRITE_BUFFER:
|
||||||
|
errsts = check_readiness(SCpnt, 1, devip);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
|
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
|
||||||
printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
|
printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
|
||||||
|
@ -954,7 +973,9 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,
|
||||||
int alloc_len, n, ret;
|
int alloc_len, n, ret;
|
||||||
|
|
||||||
alloc_len = (cmd[3] << 8) + cmd[4];
|
alloc_len = (cmd[3] << 8) + cmd[4];
|
||||||
arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_KERNEL);
|
arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
|
||||||
|
if (! arr)
|
||||||
|
return DID_REQUEUE << 16;
|
||||||
if (devip->wlun)
|
if (devip->wlun)
|
||||||
pq_pdt = 0x1e; /* present, wlun */
|
pq_pdt = 0x1e; /* present, wlun */
|
||||||
else if (scsi_debug_no_lun_0 && (0 == devip->lun))
|
else if (scsi_debug_no_lun_0 && (0 == devip->lun))
|
||||||
|
@ -1217,7 +1238,9 @@ static int resp_report_tgtpgs(struct scsi_cmnd * scp,
|
||||||
alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
|
alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
|
||||||
+ cmd[9]);
|
+ cmd[9]);
|
||||||
|
|
||||||
arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_KERNEL);
|
arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
|
||||||
|
if (! arr)
|
||||||
|
return DID_REQUEUE << 16;
|
||||||
/*
|
/*
|
||||||
* EVPD page 0x88 states we have two ports, one
|
* EVPD page 0x88 states we have two ports, one
|
||||||
* real and a fake port with no device connected.
|
* real and a fake port with no device connected.
|
||||||
|
@ -1996,6 +2019,8 @@ static int scsi_debug_slave_configure(struct scsi_device * sdp)
|
||||||
if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
|
if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
|
||||||
sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
|
sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
|
||||||
devip = devInfoReg(sdp);
|
devip = devInfoReg(sdp);
|
||||||
|
if (NULL == devip)
|
||||||
|
return 1; /* no resources, will be marked offline */
|
||||||
sdp->hostdata = devip;
|
sdp->hostdata = devip;
|
||||||
if (sdp->host->cmd_per_lun)
|
if (sdp->host->cmd_per_lun)
|
||||||
scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
|
scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
|
||||||
|
@ -2044,7 +2069,7 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (NULL == open_devip) { /* try and make a new one */
|
if (NULL == open_devip) { /* try and make a new one */
|
||||||
open_devip = kzalloc(sizeof(*open_devip),GFP_KERNEL);
|
open_devip = kzalloc(sizeof(*open_devip),GFP_ATOMIC);
|
||||||
if (NULL == open_devip) {
|
if (NULL == open_devip) {
|
||||||
printk(KERN_ERR "%s: out of memory at line %d\n",
|
printk(KERN_ERR "%s: out of memory at line %d\n",
|
||||||
__FUNCTION__, __LINE__);
|
__FUNCTION__, __LINE__);
|
||||||
|
@ -2388,7 +2413,7 @@ MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
|
||||||
MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
|
MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
|
||||||
MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
|
MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
|
||||||
MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
|
MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
|
||||||
MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->... (def=0)");
|
MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
|
||||||
MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
|
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(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(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
|
||||||
|
@ -2943,7 +2968,6 @@ static int sdebug_add_adapter(void)
|
||||||
struct list_head *lh, *lh_sf;
|
struct list_head *lh, *lh_sf;
|
||||||
|
|
||||||
sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
|
sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
|
||||||
|
|
||||||
if (NULL == sdbg_host) {
|
if (NULL == sdbg_host) {
|
||||||
printk(KERN_ERR "%s: out of memory at line %d\n",
|
printk(KERN_ERR "%s: out of memory at line %d\n",
|
||||||
__FUNCTION__, __LINE__);
|
__FUNCTION__, __LINE__);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user