bk://linux-scsi.bkbits.net/scsi-misc-2.6 jejb@mulgrave.(none)|ChangeSet|20041024214801|61319 jejb # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/11/14 21:35:57-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-scsi # # drivers/scsi/qla1280.c # 2004/11/14 21:35:54-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/11/11 15:07:32-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-scsi # # drivers/scsi/qla1280.c # 2004/11/11 15:07:28-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/10/24 22:09:45-07:00 akpm@bix.(none) # Merge bk://linux-scsi.bkbits.net/scsi-misc-2.6 # into bix.(none):/usr/src/bk-scsi # # drivers/scsi/megaraid/megaraid_mbox.c # 2004/10/24 22:09:40-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/10/24 16:48:01-05:00 jejb@mulgrave.(none) # scsi_debug v 1.75 # # From: Douglas Gilbert # # - fix highmem data transfers # - fix kunmap_atomic() argument # - disable clustering # - allow every_nth < 0 for error continuously once # count is reached # - minor sense buffer handling cleanup # # Signed-off-by: James Bottomley # # drivers/scsi/scsi_debug.c # 2004/10/24 16:47:49-05:00 jejb@mulgrave.(none) +265 -214 # scsi_debug v 1.75 # # ChangeSet # 2004/10/21 00:22:42-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-scsi # # drivers/scsi/megaraid/megaraid_mbox.h # 2004/10/21 00:22:38-07:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/scsi/megaraid/megaraid_mbox.c # 2004/10/21 00:22:38-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/10/19 22:12:26-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-scsi # # drivers/scsi/megaraid/megaraid_mbox.c # 2004/10/19 22:12:23-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/10/15 22:40:42-07:00 akpm@bix.(none) # Merge bk://linux-scsi.bkbits.net/scsi-misc-2.6 # into bix.(none):/usr/src/bk-scsi # # drivers/scsi/megaraid/megaraid_mbox.h # 2004/10/15 22:40:38-07:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/scsi/megaraid/megaraid_mbox.c # 2004/10/15 22:40:38-07:00 akpm@bix.(none) +0 -0 # Auto merged # # Documentation/scsi/ChangeLog.megaraid # 2004/10/15 22:40:38-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/10/13 13:38:51-07:00 akpm@bix.(none) # foo # # Documentation/scsi/ChangeLog.megaraid # 2004/10/13 13:38:44-07:00 akpm@bix.(none) +0 -8 # foo # # drivers/scsi/megaraid/megaraid_mbox.h # 2004/10/13 13:32:32-07:00 akpm@bix.(none) +0 -2 # Auto merged # # drivers/scsi/megaraid/megaraid_mbox.c # 2004/10/13 13:32:32-07:00 akpm@bix.(none) +0 -3 # Auto merged # diff -Nru a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c --- a/drivers/scsi/scsi_debug.c 2004-11-15 21:14:47 -08:00 +++ b/drivers/scsi/scsi_debug.c 2004-11-15 21:14:47 -08:00 @@ -55,8 +55,8 @@ #include "scsi_logging.h" #include "scsi_debug.h" -#define SCSI_DEBUG_VERSION "1.74" -static const char * scsi_debug_version_date = "20040829"; +#define SCSI_DEBUG_VERSION "1.75" +static const char * scsi_debug_version_date = "20041023"; /* Additional Sense Code (ASC) used */ #define NO_ADDED_SENSE 0x0 @@ -82,7 +82,7 @@ #define DEF_EVERY_NTH 0 #define DEF_NUM_PARTS 0 #define DEF_OPTS 0 -#define DEF_SCSI_LEVEL 4 /* SPC-2 */ +#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */ #define DEF_PTYPE 0 #define DEF_D_SENSE 0 @@ -95,6 +95,13 @@ * - 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. + * + * 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. + * 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). */ /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this @@ -195,14 +202,12 @@ .cmd_per_lun = 3, .max_sectors = 4096, .unchecked_isa_dma = 0, - .use_clustering = ENABLE_CLUSTERING, + .use_clustering = DISABLE_CLUSTERING, .module = THIS_MODULE, }; static unsigned char * fake_storep; /* ramdisk storage */ -static unsigned char spare_buff[SDEBUG_SENSE_LEN]; - static int num_aborts = 0; static int num_dev_resets = 0; static int num_bus_resets = 0; @@ -228,21 +233,28 @@ (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; /* function declarations */ -static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff, - int bufflen, struct sdebug_dev_info * devip); -static int resp_mode_sense(unsigned char * cmd, int target, - unsigned char * buff, int bufflen, +static int resp_inquiry(struct scsi_cmnd * SCpnt, int target, + struct sdebug_dev_info * devip); +static int resp_requests(struct scsi_cmnd * SCpnt, + struct sdebug_dev_info * devip); +static int resp_readcap(struct scsi_cmnd * SCpnt, + struct sdebug_dev_info * devip); +static int resp_mode_sense(struct scsi_cmnd * SCpnt, int target, struct sdebug_dev_info * devip); static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block, int num, struct sdebug_dev_info * devip); static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block, int num, struct sdebug_dev_info * devip); -static int resp_report_luns(unsigned char * cmd, unsigned char * buff, - int bufflen, struct sdebug_dev_info * devip); +static int resp_report_luns(struct scsi_cmnd * SCpnt, + struct sdebug_dev_info * devip); +static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, + int arr_len); +static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, + int max_arr_len); static void timer_intr_handler(unsigned long); 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, int inbandLen); + int asc, int asq); static int check_reset(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip); static int schedule_resp(struct scsi_cmnd * cmnd, @@ -264,49 +276,20 @@ static struct device pseudo_primary; static struct bus_type pseudo_lld_bus; -static unsigned char * scatg2virt(const struct scatterlist * sclp) -{ - if (NULL == sclp) - return NULL; - else if (sclp->page) - return (unsigned char *)page_address(sclp->page) + - sclp->offset; - else - return NULL; -} static int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) { unsigned char *cmd = (unsigned char *) SCpnt->cmnd; int block, upper_blk, num, k; - unsigned char *buff; int errsts = 0; int target = SCpnt->device->id; - int bufflen = SCpnt->request_bufflen; - unsigned long capac; struct sdebug_dev_info * devip = NULL; - unsigned char * sbuff; int inj_recovered = 0; if (done == NULL) return 0; /* assume mid level reprocessing command */ - if (SCpnt->use_sg) { /* just use first element */ - struct scatterlist *sgpnt = (struct scatterlist *) - SCpnt->request_buffer; - - buff = scatg2virt(&sgpnt[0]); - bufflen = sgpnt[0].length; - /* READ and WRITE process scatterlist themselves */ - } - else - buff = (unsigned char *) SCpnt->request_buffer; - if (NULL == buff) { - buff = spare_buff; /* assume cmd moves no data */ - bufflen = SDEBUG_SENSE_LEN; - } - if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { printk(KERN_INFO "scsi_debug: cmd "); for (k = 0, num = SCpnt->cmd_len; k < num; ++k) @@ -328,9 +311,11 @@ return schedule_resp(SCpnt, NULL, done, DID_NO_CONNECT << 16, 0); - if ((scsi_debug_every_nth > 0) && - (++scsi_debug_cmnd_count >= scsi_debug_every_nth)) { - scsi_debug_cmnd_count =0; + if ((scsi_debug_every_nth != 0) && + (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) { + scsi_debug_cmnd_count = 0; + if (scsi_debug_every_nth < -1) + scsi_debug_every_nth = -1; if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts) return 0; /* ignore command causing timeout */ else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts) @@ -339,23 +324,14 @@ switch (*cmd) { case INQUIRY: /* mandatory, ignore unit attention */ - errsts = resp_inquiry(cmd, target, buff, bufflen, devip); + errsts = resp_inquiry(SCpnt, target, devip); break; case REQUEST_SENSE: /* mandatory, ignore unit attention */ - if (devip) { - sbuff = devip->sense_buff; - memcpy(buff, sbuff, (bufflen < SDEBUG_SENSE_LEN) ? - bufflen : SDEBUG_SENSE_LEN); - mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0, 7); - } else { - memset(buff, 0, bufflen); - buff[0] = 0x70; - } + errsts = resp_requests(SCpnt, devip); break; case REZERO_UNIT: /* actually this is REWIND for SSC */ case START_STOP: errsts = check_reset(SCpnt, devip); - memset(buff, 0, bufflen); break; case ALLOW_MEDIUM_REMOVAL: if ((errsts = check_reset(SCpnt, devip))) @@ -366,40 +342,24 @@ break; case SEND_DIAGNOSTIC: /* mandatory */ errsts = check_reset(SCpnt, devip); - memset(buff, 0, bufflen); break; case TEST_UNIT_READY: /* mandatory */ errsts = check_reset(SCpnt, devip); - memset(buff, 0, bufflen); break; case RESERVE: errsts = check_reset(SCpnt, devip); - memset(buff, 0, bufflen); break; case RESERVE_10: errsts = check_reset(SCpnt, devip); - memset(buff, 0, bufflen); break; case RELEASE: errsts = check_reset(SCpnt, devip); - memset(buff, 0, bufflen); break; case RELEASE_10: errsts = check_reset(SCpnt, devip); - memset(buff, 0, bufflen); break; case READ_CAPACITY: - errsts = check_reset(SCpnt, devip); - memset(buff, 0, bufflen); - if (bufflen > 7) { - capac = (unsigned long)sdebug_capacity - 1; - buff[0] = (capac >> 24); - buff[1] = (capac >> 16) & 0xff; - buff[2] = (capac >> 8) & 0xff; - buff[3] = capac & 0xff; - buff[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; - buff[7] = SECT_SIZE_PER(target) & 0xff; - } + errsts = resp_readcap(SCpnt, devip); break; case READ_16: case READ_12: @@ -432,12 +392,15 @@ errsts = resp_read(SCpnt, upper_blk, block, num, devip); if (inj_recovered && (0 == errsts)) { mk_sense_buffer(devip, RECOVERED_ERROR, - THRESHHOLD_EXCEEDED, 0, 18); + THRESHHOLD_EXCEEDED, 0); errsts = check_condition_result; } break; case REPORT_LUNS: /* mandatory, ignore unit attention */ - errsts = resp_report_luns(cmd, buff, bufflen, devip); + errsts = resp_report_luns(SCpnt, devip); + break; + case VERIFY: /* 10 byte SBC-2 command */ + errsts = check_reset(SCpnt, devip); break; case WRITE_16: case WRITE_12: @@ -470,19 +433,16 @@ errsts = resp_write(SCpnt, upper_blk, block, num, devip); if (inj_recovered && (0 == errsts)) { mk_sense_buffer(devip, RECOVERED_ERROR, - THRESHHOLD_EXCEEDED, 0, 18); + THRESHHOLD_EXCEEDED, 0); errsts = check_condition_result; } break; case MODE_SENSE: case MODE_SENSE_10: - if ((errsts = check_reset(SCpnt, devip))) - break; - errsts = resp_mode_sense(cmd, target, buff, bufflen, devip); + errsts = resp_mode_sense(SCpnt, target, devip); break; case SYNCHRONIZE_CACHE: errsts = check_reset(SCpnt, devip); - memset(buff, 0, bufflen); break; default: if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) @@ -490,7 +450,7 @@ "supported\n", *cmd); if ((errsts = check_reset(SCpnt, devip))) break; /* Unit attention takes precedence */ - mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0, 18); + mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0); errsts = check_condition_result; break; } @@ -513,18 +473,105 @@ printk(KERN_INFO "scsi_debug: Reporting Unit " "attention: power on reset\n"); devip->reset = 0; - mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0, 18); + mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0); return check_condition_result; } return 0; } -#define SDEBUG_LONG_INQ_SZ 96 -#define SDEBUG_MAX_INQ_ARR_SZ 128 +/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ +static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, + int arr_len) +{ + int k, req_len, act_len, len, active; + void * kaddr; + void * kaddr_off; + struct scatterlist * sgpnt; + + if (0 == scp->request_bufflen) + return 0; + if (NULL == scp->request_buffer) + return (DID_ERROR << 16); + if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) || + (scp->sc_data_direction == DMA_FROM_DEVICE))) + return (DID_ERROR << 16); + if (0 == scp->use_sg) { + req_len = scp->request_bufflen; + act_len = (req_len < arr_len) ? req_len : arr_len; + memcpy(scp->request_buffer, arr, act_len); + scp->resid = req_len - act_len; + return 0; + } + sgpnt = (struct scatterlist *)scp->request_buffer; + active = 1; + for (k = 0, req_len = 0, act_len = 0; k < scp->use_sg; ++k, ++sgpnt) { + if (active) { + kaddr = (unsigned char *) + kmap_atomic(sgpnt->page, KM_USER0); + if (NULL == kaddr) + return (DID_ERROR << 16); + kaddr_off = (unsigned char *)kaddr + sgpnt->offset; + len = sgpnt->length; + if ((req_len + len) > arr_len) { + active = 0; + len = arr_len - req_len; + } + memcpy(kaddr_off, arr + req_len, len); + kunmap_atomic(kaddr, KM_USER0); + act_len += len; + } + req_len += sgpnt->length; + } + scp->resid = req_len - act_len; + return 0; +} -static const char * vendor_id = "Linux "; -static const char * product_id = "scsi_debug "; -static const char * product_rev = "0004"; +/* Returns number of bytes fetched into 'arr' or -1 if error. */ +static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, + int max_arr_len) +{ + int k, req_len, len, fin; + void * kaddr; + void * kaddr_off; + struct scatterlist * sgpnt; + + if (0 == scp->request_bufflen) + return 0; + if (NULL == scp->request_buffer) + return -1; + if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) || + (scp->sc_data_direction == DMA_TO_DEVICE))) + return -1; + if (0 == scp->use_sg) { + req_len = scp->request_bufflen; + len = (req_len < max_arr_len) ? req_len : max_arr_len; + memcpy(arr, scp->request_buffer, len); + return len; + } + sgpnt = (struct scatterlist *)scp->request_buffer; + for (k = 0, req_len = 0, fin = 0; k < scp->use_sg; ++k, ++sgpnt) { + kaddr = (unsigned char *)kmap_atomic(sgpnt->page, KM_USER0); + if (NULL == kaddr) + return -1; + kaddr_off = (unsigned char *)kaddr + sgpnt->offset; + len = sgpnt->length; + if ((req_len + len) > max_arr_len) { + len = max_arr_len - req_len; + fin = 1; + } + memcpy(arr + req_len, kaddr_off, len); + kunmap_atomic(kaddr, KM_USER0); + if (fin) + return req_len + len; + req_len += sgpnt->length; + } + return req_len; +} + + +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 dev_id_num, const char * dev_id_str, int dev_id_str_len) @@ -536,8 +583,8 @@ arr[0] = 0x2; /* ASCII */ arr[1] = 0x1; arr[2] = 0x0; - memcpy(&arr[4], vendor_id, 8); - memcpy(&arr[12], product_id, 16); + memcpy(&arr[4], inq_vendor_id, 8); + memcpy(&arr[12], inq_product_id, 16); memcpy(&arr[28], dev_id_str, dev_id_str_len); num = 8 + 16 + dev_id_str_len; arr[3] = num; @@ -558,24 +605,25 @@ return num + 12; } -static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff, - int bufflen, struct sdebug_dev_info * devip) + +#define SDEBUG_LONG_INQ_SZ 96 +#define SDEBUG_MAX_INQ_ARR_SZ 128 + +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]; - int min_len = bufflen > SDEBUG_MAX_INQ_ARR_SZ ? - SDEBUG_MAX_INQ_ARR_SZ : bufflen; + unsigned char *cmd = (unsigned char *)scp->cmnd; + int alloc_len; - if (bufflen < cmd[4]) - printk(KERN_INFO "scsi_debug: inquiry: bufflen=%d " - "< alloc_length=%d\n", bufflen, (int)cmd[4]); - memset(buff, 0, bufflen); + alloc_len = (cmd[3] << 8) + cmd[4]; memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ); pq_pdt = (scsi_debug_ptype & 0x1f); arr[0] = pq_pdt; if (0x2 & cmd[1]) { /* CMDDT bit set */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, - 0, 18); + 0); return check_condition_result; } else if (0x1 & cmd[1]) { /* EVPD bit set */ int dev_id_num, len; @@ -600,11 +648,11 @@ } else { /* Illegal request, invalid field in cdb */ mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_FIELD_IN_CDB, 0, 18); + INVALID_FIELD_IN_CDB, 0); return check_condition_result; } - memcpy(buff, arr, min_len); - return 0; + return fill_from_dev_buffer(scp, arr, + min(alloc_len, SDEBUG_MAX_INQ_ARR_SZ)); } /* drops through here for a standard inquiry */ arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ @@ -612,20 +660,67 @@ arr[3] = 2; /* response_data_format==2 */ arr[4] = SDEBUG_LONG_INQ_SZ - 5; arr[6] = 0x1; /* claim: ADDR16 */ + /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */ - memcpy(&arr[8], vendor_id, 8); - memcpy(&arr[16], product_id, 16); - memcpy(&arr[32], product_rev, 4); + memcpy(&arr[8], inq_vendor_id, 8); + memcpy(&arr[16], inq_product_id, 16); + memcpy(&arr[32], inq_product_rev, 4); /* version descriptors (2 bytes each) follow */ arr[58] = 0x0; arr[59] = 0x40; /* SAM-2 */ - arr[60] = 0x2; arr[61] = 0x60; /* SPC-2 */ + arr[60] = 0x3; arr[61] = 0x0; /* SPC-3 */ if (scsi_debug_ptype == 0) { - arr[62] = 0x1; arr[63] = 0x80; /* SBC */ + arr[62] = 0x1; arr[63] = 0x80; /* SBC */ } else if (scsi_debug_ptype == 1) { - arr[62] = 0x2; arr[63] = 0x00; /* SSC */ + arr[62] = 0x2; arr[63] = 0x00; /* SSC */ } - memcpy(buff, arr, min_len); - return 0; + return fill_from_dev_buffer(scp, arr, + min(alloc_len, SDEBUG_LONG_INQ_SZ)); +} + +static int resp_requests(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip) +{ + unsigned char * sbuff; + unsigned char *cmd = (unsigned char *)scp->cmnd; + unsigned char arr[SDEBUG_SENSE_LEN]; + int len = 18; + + memset(arr, 0, SDEBUG_SENSE_LEN); + if (devip->reset == 1) + mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0); + sbuff = devip->sense_buff; + if ((cmd[1] & 1) && (! scsi_debug_dsense)) { + /* DESC bit set and sense_buff in fixed format */ + arr[0] = 0x72; + arr[1] = sbuff[2]; /* sense key */ + arr[2] = sbuff[12]; /* asc */ + arr[3] = sbuff[13]; /* ascq */ + len = 8; + } else + memcpy(arr, sbuff, SDEBUG_SENSE_LEN); + mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0); + return fill_from_dev_buffer(scp, arr, len); +} + +#define SDEBUG_READCAP_ARR_SZ 8 +static int resp_readcap(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip) +{ + unsigned char arr[SDEBUG_READCAP_ARR_SZ]; + unsigned long capac; + int errsts; + + if ((errsts = check_reset(scp, devip))) + return errsts; + memset(arr, 0, SDEBUG_READCAP_ARR_SZ); + capac = (unsigned long)sdebug_capacity - 1; + arr[0] = (capac >> 24); + arr[1] = (capac >> 16) & 0xff; + arr[2] = (capac >> 8) & 0xff; + arr[3] = capac & 0xff; + arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; + arr[7] = SECT_SIZE_PER(target) & 0xff; + return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); } /* <> */ @@ -706,34 +801,29 @@ #define SDEBUG_MAX_MSENSE_SZ 256 -static int resp_mode_sense(unsigned char * cmd, int target, - unsigned char * buff, int bufflen, +static int resp_mode_sense(struct scsi_cmnd * scp, int target, struct sdebug_dev_info * devip) { unsigned char dbd; int pcontrol, pcode, subpcode; unsigned char dev_spec; - int alloc_len, msense_6, offset, len; + int alloc_len, msense_6, offset, len, errsts; unsigned char * ap; unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; - int min_len = bufflen > SDEBUG_MAX_MSENSE_SZ ? - SDEBUG_MAX_MSENSE_SZ : bufflen; + unsigned char *cmd = (unsigned char *)scp->cmnd; - SCSI_LOG_LLQUEUE(3, printk("Mode sense ...(%p %d)\n", buff, bufflen)); + if ((errsts = check_reset(scp, devip))) + return errsts; dbd = cmd[1] & 0x8; pcontrol = (cmd[2] & 0xc0) >> 6; pcode = cmd[2] & 0x3f; subpcode = cmd[3]; msense_6 = (MODE_SENSE == cmd[0]); alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]); - if (bufflen < alloc_len) - printk(KERN_INFO "scsi_debug: mode_sense: bufflen=%d " - "< alloc_length=%d\n", bufflen, alloc_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, SAVING_PARAMS_UNSUP, - 0, 18); + 0); return check_condition_result; } dev_spec = DEV_READONLY(target) ? 0x80 : 0x0; @@ -748,7 +838,7 @@ if (0 != subpcode) { /* TODO: Control Extension page */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, - 0, 18); + 0); return check_condition_result; } switch (pcode) { @@ -787,146 +877,104 @@ break; default: mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, - 0, 18); + 0); return check_condition_result; } if (msense_6) arr[0] = offset - 1; else { - offset -= 2; - arr[0] = (offset >> 8) & 0xff; - arr[1] = offset & 0xff; + arr[0] = ((offset - 2) >> 8) & 0xff; + arr[1] = (offset - 2) & 0xff; } - memcpy(buff, arr, min_len); - return 0; + return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); } static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block, int num, struct sdebug_dev_info * devip) { - unsigned char *buff = (unsigned char *) SCpnt->request_buffer; - int nbytes, sgcount; - struct scatterlist *sgpnt = NULL; - int bufflen = SCpnt->request_bufflen; unsigned long iflags; + int ret; if (upper_blk || (block + num > sdebug_capacity)) { mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, - 0, 18); + 0); 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, UNRECOVERED_READ_ERR, - 0, 18); + 0); /* claim unrecoverable read error */ return check_condition_result; } read_lock_irqsave(&atomic_rw, iflags); - sgcount = 0; - nbytes = bufflen; - /* printk(KERN_INFO "scsi_debug_read: block=%d, tot_bufflen=%d\n", - block, bufflen); */ - if (SCpnt->use_sg) { - sgcount = 0; - sgpnt = (struct scatterlist *) buff; - buff = scatg2virt(&sgpnt[sgcount]); - bufflen = sgpnt[sgcount].length; - } - do { - memcpy(buff, fake_storep + (block * SECT_SIZE), bufflen); - nbytes -= bufflen; - if (SCpnt->use_sg) { - block += bufflen >> POW2_SECT_SIZE; - sgcount++; - if (nbytes) { - buff = scatg2virt(&sgpnt[sgcount]); - bufflen = sgpnt[sgcount].length; - } - } else if (nbytes > 0) - printk(KERN_WARNING "scsi_debug:resp_read: unexpected " - "nbytes=%d\n", nbytes); - } while (nbytes); + ret = fill_from_dev_buffer(SCpnt, fake_storep + (block * SECT_SIZE), + num * SECT_SIZE); read_unlock_irqrestore(&atomic_rw, iflags); - return 0; + return ret; } static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block, int num, struct sdebug_dev_info * devip) { - unsigned char *buff = (unsigned char *) SCpnt->request_buffer; - int nbytes, sgcount; - struct scatterlist *sgpnt = NULL; - int bufflen = SCpnt->request_bufflen; unsigned long iflags; + int res; if (upper_blk || (block + num > sdebug_capacity)) { mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, - 0, 18); + 0); return check_condition_result; } write_lock_irqsave(&atomic_rw, iflags); - sgcount = 0; - nbytes = bufflen; - if (SCpnt->use_sg) { - sgcount = 0; - sgpnt = (struct scatterlist *) buff; - buff = scatg2virt(&sgpnt[sgcount]); - bufflen = sgpnt[sgcount].length; - } - do { - memcpy(fake_storep + (block * SECT_SIZE), buff, bufflen); - - nbytes -= bufflen; - if (SCpnt->use_sg) { - block += bufflen >> POW2_SECT_SIZE; - sgcount++; - if (nbytes) { - buff = scatg2virt(&sgpnt[sgcount]); - bufflen = sgpnt[sgcount].length; - } - } else if (nbytes > 0) - printk(KERN_WARNING "scsi_debug:resp_write: " - "unexpected nbytes=%d\n", nbytes); - } while (nbytes); + res = fetch_to_dev_buffer(SCpnt, fake_storep + (block * SECT_SIZE), + num * SECT_SIZE); write_unlock_irqrestore(&atomic_rw, iflags); + if (-1 == res) + return (DID_ERROR << 16); + else if ((res < (num * SECT_SIZE)) && + (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) + printk(KERN_INFO "scsi_debug: write: cdb indicated=%d, " + " IO sent=%d bytes\n", num * SECT_SIZE, res); return 0; } -static int resp_report_luns(unsigned char * cmd, unsigned char * buff, - int bufflen, struct sdebug_dev_info * devip) +#define SDEBUG_RLUN_ARR_SZ 128 + +static int resp_report_luns(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip) { unsigned int alloc_len; int lun_cnt, i, upper; + unsigned char *cmd = (unsigned char *)scp->cmnd; int select_report = (int)cmd[2]; struct scsi_lun *one_lun; + unsigned char arr[SDEBUG_RLUN_ARR_SZ]; 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, INVALID_FIELD_IN_CDB, - 0, 18); + 0); return check_condition_result; } - if (bufflen > 8) { /* can produce response with up to 16k luns - (lun 0 to lun 16383) */ - memset(buff, 0, bufflen); - lun_cnt = scsi_debug_max_luns; - buff[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff; - buff[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff; - lun_cnt = min((int)((bufflen - 8) / sizeof(struct scsi_lun)), - lun_cnt); - one_lun = (struct scsi_lun *) &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; - } + /* can produce response with up to 16k luns (lun 0 to lun 16383) */ + memset(arr, 0, SDEBUG_RLUN_ARR_SZ); + lun_cnt = scsi_debug_max_luns; + arr[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff; + arr[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff; + lun_cnt = min((int)((SDEBUG_RLUN_ARR_SZ - 8) / + sizeof(struct scsi_lun)), lun_cnt); + one_lun = (struct scsi_lun *) &arr[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; + return fill_from_dev_buffer(scp, arr, + min((int)alloc_len, SDEBUG_RLUN_ARR_SZ)); } /* When timer goes off this function is called. */ @@ -1041,14 +1089,19 @@ open_devip->reset = 1; open_devip->used = 1; memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN); - open_devip->sense_buff[0] = 0x70; + if (scsi_debug_dsense) + open_devip->sense_buff[0] = 0x72; + else { + open_devip->sense_buff[0] = 0x70; + open_devip->sense_buff[7] = 0xa; + } return open_devip; } return NULL; } static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, - int asc, int asq, int inbandLen) + int asc, int asq) { unsigned char * sbuff; @@ -1060,11 +1113,9 @@ sbuff[2] = asc; sbuff[3] = asq; } else { - if (inbandLen > SDEBUG_SENSE_LEN) - inbandLen = SDEBUG_SENSE_LEN; sbuff[0] = 0x70; /* fixed, current */ sbuff[2] = key; - sbuff[7] = (inbandLen > 7) ? (inbandLen - 8) : 0; + sbuff[7] = 0xa; /* implies 18 byte sense buffer */ sbuff[12] = asc; sbuff[13] = asq; } @@ -1355,7 +1406,7 @@ MODULE_PARM_DESC(num_tgts, "number of SCSI targets per host to simulate"); MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->..."); MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); -MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=4[SPC-2])"); +MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); static char sdebug_info[256]; @@ -1391,7 +1442,7 @@ if (1 != sscanf(arr, "%d", &pos)) return -EINVAL; scsi_debug_opts = pos; - if (scsi_debug_every_nth > 0) + if (scsi_debug_every_nth != 0) scsi_debug_cmnd_count = 0; return length; } @@ -1547,7 +1598,7 @@ { int nth; - if ((count > 0) && (1 == sscanf(buf, "%d", &nth)) && (nth >= 0)) { + if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { scsi_debug_every_nth = nth; scsi_debug_cmnd_count = 0; return count;