X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fscsi%2Fscsi_debug.c;h=06229f225ee9723fce6b21aedfc099c06aa7d32d;hb=0ab598099c18affd73a21482274c00e8119236be;hp=9c0f35820e3e3a3c5ca797ee4c57752b22f3ba79;hpb=12e36b2f41b6cbc67386fcb9c59c32a3e2033905;p=linux-2.6-omap-h63xx.git diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 9c0f35820e3..06229f225ee 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -28,7 +28,6 @@ #include #include -#include #include #include #include @@ -37,7 +36,6 @@ #include #include #include -#include #include #include @@ -51,10 +49,10 @@ #include "scsi_logging.h" #include "scsi_debug.h" -#define SCSI_DEBUG_VERSION "1.80" -static const char * scsi_debug_version_date = "20060914"; +#define SCSI_DEBUG_VERSION "1.81" +static const char * scsi_debug_version_date = "20070104"; -/* Additional Sense Code (ASC) used */ +/* Additional Sense Code (ASC) */ #define NO_ADDITIONAL_SENSE 0x0 #define LOGICAL_UNIT_NOT_READY 0x4 #define UNRECOVERED_READ_ERR 0x11 @@ -65,9 +63,13 @@ static const char * scsi_debug_version_date = "20060914"; #define INVALID_FIELD_IN_PARAM_LIST 0x26 #define POWERON_RESET 0x29 #define SAVING_PARAMS_UNSUP 0x39 +#define TRANSPORT_PROBLEM 0x4b #define THRESHOLD_EXCEEDED 0x5d #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 */ /* Default values for driver parameters */ @@ -95,15 +97,20 @@ static const char * scsi_debug_version_date = "20060914"; #define SCSI_DEBUG_OPT_MEDIUM_ERR 2 #define SCSI_DEBUG_OPT_TIMEOUT 4 #define SCSI_DEBUG_OPT_RECOVERED_ERR 8 +#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16 /* When "every_nth" > 0 then modulo "every_nth" commands: * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set * - a RECOVERED_ERROR is simulated on successful read and write * 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: * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set * - a RECOVERED_ERROR is simulated on successful read and write * 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 * writing a new value (other than -1 or 1) to every_nth via sysfs). */ @@ -254,6 +261,8 @@ static int resp_requests(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip); static int resp_start_stop(struct scsi_cmnd * scp, struct sdebug_dev_info * devip); +static int resp_report_tgtpgs(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip); static int resp_readcap(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip); static int resp_readcap16(struct scsi_cmnd * SCpnt, @@ -287,9 +296,9 @@ static void __init sdebug_build_parts(unsigned char * ramp); static void __init init_all_queued(void); static void stop_all_queued(void); static int stop_queued_cmnd(struct scsi_cmnd * cmnd); -static int inquiry_evpd_83(unsigned char * arr, int target_dev_id, - int dev_id_num, const char * dev_id_str, - int dev_id_str_len); +static int inquiry_evpd_83(unsigned char * arr, int port_group_id, + int target_dev_id, int dev_id_num, + const char * dev_id_str, int dev_id_str_len); static int inquiry_evpd_88(unsigned char * arr, int target_dev_id); static int do_create_driverfs_files(void); static void do_remove_driverfs_files(void); @@ -313,6 +322,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) int target = SCpnt->device->id; struct sdebug_dev_info * devip = NULL; int inj_recovered = 0; + int inj_transport = 0; int delay_override = 0; if (done == NULL) @@ -350,6 +360,8 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) return 0; /* ignore command causing timeout */ else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts) 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) { @@ -422,6 +434,15 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) } errsts = resp_readcap16(SCpnt, devip); break; + case MAINTENANCE_IN: + if (MI_REPORT_TARGET_PGS != cmd[1]) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_OPCODE, 0); + errsts = check_condition_result; + break; + } + errsts = resp_report_tgtpgs(SCpnt, devip); + break; case READ_16: case READ_12: case READ_10: @@ -457,7 +478,11 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) mk_sense_buffer(devip, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); 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; case REPORT_LUNS: /* mandatory, ignore unit attention */ delay_override = 1; @@ -520,6 +545,9 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) delay_override = 1; errsts = check_readiness(SCpnt, 0, devip); break; + case WRITE_BUFFER: + errsts = check_readiness(SCpnt, 1, devip); + break; default: if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " @@ -665,8 +693,9 @@ static const char * inq_vendor_id = "Linux "; static const char * inq_product_id = "scsi_debug "; static const char * inq_product_rev = "0004"; -static int inquiry_evpd_83(unsigned char * arr, int target_dev_id, - int dev_id_num, const char * dev_id_str, +static int inquiry_evpd_83(unsigned char * arr, int port_group_id, + int target_dev_id, int dev_id_num, + const char * dev_id_str, int dev_id_str_len) { int num, port_a; @@ -720,6 +749,15 @@ static int inquiry_evpd_83(unsigned char * arr, int target_dev_id, arr[num++] = (port_a >> 16) & 0xff; arr[num++] = (port_a >> 8) & 0xff; arr[num++] = port_a & 0xff; + /* NAA-5, Target port group identifier */ + arr[num++] = 0x61; /* proto=sas, binary */ + arr[num++] = 0x95; /* piv=1, target port group id */ + arr[num++] = 0x0; + arr[num++] = 0x4; + arr[num++] = 0; + arr[num++] = 0; + arr[num++] = (port_group_id >> 8) & 0xff; + arr[num++] = port_group_id & 0xff; /* NAA-5, Target device identifier */ arr[num++] = 0x61; /* proto=sas, binary */ arr[num++] = 0xa3; /* piv=1, target device, naa */ @@ -928,12 +966,14 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, struct sdebug_dev_info * devip) { unsigned char pq_pdt; - unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ]; + unsigned char * arr; unsigned char *cmd = (unsigned char *)scp->cmnd; - int alloc_len, n; + int alloc_len, n, ret; alloc_len = (cmd[3] << 8) + cmd[4]; - memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ); + arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); + if (! arr) + return DID_REQUEUE << 16; if (devip->wlun) pq_pdt = 0x1e; /* present, wlun */ else if (scsi_debug_no_lun_0 && (0 == devip->lun)) @@ -944,12 +984,15 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, if (0x2 & cmd[1]) { /* CMDDT bit set */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); + kfree(arr); return check_condition_result; } else if (0x1 & cmd[1]) { /* EVPD bit set */ - int lu_id_num, target_dev_id, len; + int lu_id_num, port_group_id, target_dev_id, len; char lu_id_str[6]; int host_no = devip->sdbg_host->shost->host_no; + port_group_id = (((host_no + 1) & 0x7f) << 8) + + (devip->channel & 0x7f); if (0 == scsi_debug_vpd_use_hostno) host_no = 0; lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) + @@ -977,8 +1020,9 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, memcpy(&arr[4], lu_id_str, len); } else if (0x83 == cmd[2]) { /* device identification */ arr[1] = cmd[2]; /*sanity */ - arr[3] = inquiry_evpd_83(&arr[4], target_dev_id, - lu_id_num, lu_id_str, len); + arr[3] = inquiry_evpd_83(&arr[4], port_group_id, + target_dev_id, lu_id_num, + lu_id_str, len); } else if (0x84 == cmd[2]) { /* Software interface ident. */ arr[1] = cmd[2]; /*sanity */ arr[3] = inquiry_evpd_84(&arr[4]); @@ -1012,17 +1056,22 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, /* Illegal request, invalid field in cdb */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); + kfree(arr); return check_condition_result; } len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); - return fill_from_dev_buffer(scp, arr, + ret = fill_from_dev_buffer(scp, arr, min(len, SDEBUG_MAX_INQ_ARR_SZ)); + kfree(arr); + return ret; } /* drops through here for a standard inquiry */ arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ arr[2] = scsi_debug_scsi_level; arr[3] = 2; /* response_data_format==2 */ arr[4] = SDEBUG_LONG_INQ_SZ - 5; + if (0 == scsi_debug_vpd_use_hostno) + arr[5] = 0x10; /* claim: implicit TGPS */ arr[6] = 0x10; /* claim: MultiP */ /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ arr[7] = 0xa; /* claim: LINKED + CMDQUE */ @@ -1039,8 +1088,10 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */ } arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */ - return fill_from_dev_buffer(scp, arr, + ret = fill_from_dev_buffer(scp, arr, min(alloc_len, SDEBUG_LONG_INQ_SZ)); + kfree(arr); + return ret; } static int resp_requests(struct scsi_cmnd * scp, @@ -1171,6 +1222,89 @@ static int resp_readcap16(struct scsi_cmnd * scp, min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); } +#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 + +static int resp_report_tgtpgs(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip) +{ + unsigned char *cmd = (unsigned char *)scp->cmnd; + unsigned char * arr; + int host_no = devip->sdbg_host->shost->host_no; + int n, ret, alen, rlen; + int port_group_a, port_group_b, port_a, port_b; + + alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8) + + cmd[9]); + + arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); + if (! arr) + return DID_REQUEUE << 16; + /* + * EVPD page 0x88 states we have two ports, one + * real and a fake port with no device connected. + * So we create two port groups with one port each + * and set the group with port B to unavailable. + */ + port_a = 0x1; /* relative port A */ + port_b = 0x2; /* relative port B */ + port_group_a = (((host_no + 1) & 0x7f) << 8) + + (devip->channel & 0x7f); + port_group_b = (((host_no + 1) & 0x7f) << 8) + + (devip->channel & 0x7f) + 0x80; + + /* + * The asymmetric access state is cycled according to the host_id. + */ + n = 4; + if (0 == scsi_debug_vpd_use_hostno) { + arr[n++] = host_no % 3; /* Asymm access state */ + arr[n++] = 0x0F; /* claim: all states are supported */ + } else { + arr[n++] = 0x0; /* Active/Optimized path */ + arr[n++] = 0x01; /* claim: only support active/optimized paths */ + } + arr[n++] = (port_group_a >> 8) & 0xff; + arr[n++] = port_group_a & 0xff; + arr[n++] = 0; /* Reserved */ + arr[n++] = 0; /* Status code */ + arr[n++] = 0; /* Vendor unique */ + arr[n++] = 0x1; /* One port per group */ + arr[n++] = 0; /* Reserved */ + arr[n++] = 0; /* Reserved */ + arr[n++] = (port_a >> 8) & 0xff; + arr[n++] = port_a & 0xff; + arr[n++] = 3; /* Port unavailable */ + arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ + arr[n++] = (port_group_b >> 8) & 0xff; + arr[n++] = port_group_b & 0xff; + arr[n++] = 0; /* Reserved */ + arr[n++] = 0; /* Status code */ + arr[n++] = 0; /* Vendor unique */ + arr[n++] = 0x1; /* One port per group */ + arr[n++] = 0; /* Reserved */ + arr[n++] = 0; /* Reserved */ + arr[n++] = (port_b >> 8) & 0xff; + arr[n++] = port_b & 0xff; + + rlen = n - 4; + arr[0] = (rlen >> 24) & 0xff; + arr[1] = (rlen >> 16) & 0xff; + arr[2] = (rlen >> 8) & 0xff; + arr[3] = rlen & 0xff; + + /* + * Return the smallest value of either + * - The allocated length + * - The constructed command length + * - The maximum array size + */ + rlen = min(alen,n); + ret = fill_from_dev_buffer(scp, arr, + min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); + kfree(arr); + return ret; +} + /* <> */ static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) @@ -1883,6 +2017,8 @@ static int scsi_debug_slave_configure(struct scsi_device * sdp) 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, @@ -1931,7 +2067,7 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) } } 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) { printk(KERN_ERR "%s: out of memory at line %d\n", __FUNCTION__, __LINE__); @@ -2275,7 +2411,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(num_parts, "number of partitions(def=0)"); 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(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); @@ -2830,7 +2966,6 @@ static int sdebug_add_adapter(void) struct list_head *lh, *lh_sf; 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__);