X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fscsi%2Fscsi_debug.c;h=7a2a3edcc723bbcda2621e341669b782ec78be25;hb=e507e30b803fb56d768ed9a597e7609b74d2db21;hp=46cae5a212ded1df5e85b607119335065206dc98;hpb=527da38d33f16da4c245da3a5a3858193f8a0261;p=linux-2.6-omap-h63xx.git diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 46cae5a212d..7a2a3edcc72 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -39,16 +39,17 @@ #include #include #include - #include -#include "scsi.h" + +#include +#include +#include #include #include #include #include "scsi_logging.h" -#include "scsi_debug.h" #define SCSI_DEBUG_VERSION "1.81" static const char * scsi_debug_version_date = "20070104"; @@ -165,6 +166,9 @@ static int sdebug_sectors_per; /* sectors per cylinder */ #define SDEBUG_SENSE_LEN 32 +#define SCSI_DEBUG_CANQUEUE 255 +#define SCSI_DEBUG_MAX_CMD_LEN 16 + struct sdebug_dev_info { struct list_head dev_list; unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */ @@ -202,30 +206,6 @@ struct sdebug_queued_cmd { }; static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; -static struct scsi_host_template sdebug_driver_template = { - .proc_info = scsi_debug_proc_info, - .name = "SCSI DEBUG", - .info = scsi_debug_info, - .slave_alloc = scsi_debug_slave_alloc, - .slave_configure = scsi_debug_slave_configure, - .slave_destroy = scsi_debug_slave_destroy, - .ioctl = scsi_debug_ioctl, - .queuecommand = scsi_debug_queuecommand, - .eh_abort_handler = scsi_debug_abort, - .eh_bus_reset_handler = scsi_debug_bus_reset, - .eh_device_reset_handler = scsi_debug_device_reset, - .eh_host_reset_handler = scsi_debug_host_reset, - .bios_param = scsi_debug_biosparam, - .can_queue = SCSI_DEBUG_CANQUEUE, - .this_id = 7, - .sg_tablesize = 256, - .cmd_per_lun = 16, - .max_sectors = 0xffff, - .unchecked_isa_dma = 0, - .use_clustering = ENABLE_CLUSTERING, - .module = THIS_MODULE, -}; - static unsigned char * fake_storep; /* ramdisk storage */ static int num_aborts = 0; @@ -280,6 +260,8 @@ static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba, unsigned int num, struct sdebug_dev_info * devip); static int resp_report_luns(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip); +static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, + unsigned int num, 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, @@ -311,12 +293,48 @@ static void sdebug_max_tgts_luns(void); static struct device pseudo_primary; static struct bus_type pseudo_lld_bus; +static void get_data_transfer_info(unsigned char *cmd, + unsigned long long *lba, unsigned int *num) +{ + int i; + + switch (*cmd) { + case WRITE_16: + case READ_16: + for (*lba = 0, i = 0; i < 8; ++i) { + if (i > 0) + *lba <<= 8; + *lba += cmd[2 + i]; + } + *num = cmd[13] + (cmd[12] << 8) + + (cmd[11] << 16) + (cmd[10] << 24); + break; + case WRITE_12: + case READ_12: + *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); + *num = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); + break; + case WRITE_10: + case READ_10: + case XDWRITEREAD_10: + *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); + *num = cmd[8] + (cmd[7] << 8); + break; + case WRITE_6: + case READ_6: + *lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); + *num = (0 == cmd[4]) ? 256 : cmd[4]; + break; + default: + break; + } +} static int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) { unsigned char *cmd = (unsigned char *) SCpnt->cmnd; - int len, k, j; + int len, k; unsigned int num; unsigned long long lba; int errsts = 0; @@ -326,17 +344,15 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) int inj_transport = 0; int delay_override = 0; - if (done == NULL) - return 0; /* assume mid level reprocessing command */ - - SCpnt->resid = 0; + scsi_set_resid(SCpnt, 0); if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { printk(KERN_INFO "scsi_debug: cmd "); for (k = 0, len = SCpnt->cmd_len; k < len; ++k) printk("%02x ", (int)cmd[k]); printk("\n"); } - if(target == sdebug_driver_template.this_id) { + + if (target == SCpnt->device->host->hostt->this_id) { printk(KERN_INFO "scsi_debug: initiator's id used as " "target!\n"); return schedule_resp(SCpnt, NULL, done, @@ -452,28 +468,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) break; if (scsi_debug_fake_rw) break; - if ((*cmd) == READ_16) { - for (lba = 0, j = 0; j < 8; ++j) { - if (j > 0) - lba <<= 8; - lba += cmd[2 + j]; - } - num = cmd[13] + (cmd[12] << 8) + - (cmd[11] << 16) + (cmd[10] << 24); - } else if ((*cmd) == READ_12) { - lba = cmd[5] + (cmd[4] << 8) + - (cmd[3] << 16) + (cmd[2] << 24); - num = cmd[9] + (cmd[8] << 8) + - (cmd[7] << 16) + (cmd[6] << 24); - } else if ((*cmd) == READ_10) { - lba = cmd[5] + (cmd[4] << 8) + - (cmd[3] << 16) + (cmd[2] << 24); - num = cmd[8] + (cmd[7] << 8); - } else { /* READ (6) */ - lba = cmd[3] + (cmd[2] << 8) + - ((cmd[1] & 0x1f) << 16); - num = (0 == cmd[4]) ? 256 : cmd[4]; - } + get_data_transfer_info(cmd, &lba, &num); errsts = resp_read(SCpnt, lba, num, devip); if (inj_recovered && (0 == errsts)) { mk_sense_buffer(devip, RECOVERED_ERROR, @@ -500,28 +495,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) break; if (scsi_debug_fake_rw) break; - if ((*cmd) == WRITE_16) { - for (lba = 0, j = 0; j < 8; ++j) { - if (j > 0) - lba <<= 8; - lba += cmd[2 + j]; - } - num = cmd[13] + (cmd[12] << 8) + - (cmd[11] << 16) + (cmd[10] << 24); - } else if ((*cmd) == WRITE_12) { - lba = cmd[5] + (cmd[4] << 8) + - (cmd[3] << 16) + (cmd[2] << 24); - num = cmd[9] + (cmd[8] << 8) + - (cmd[7] << 16) + (cmd[6] << 24); - } else if ((*cmd) == WRITE_10) { - lba = cmd[5] + (cmd[4] << 8) + - (cmd[3] << 16) + (cmd[2] << 24); - num = cmd[8] + (cmd[7] << 8); - } else { /* WRITE (6) */ - lba = cmd[3] + (cmd[2] << 8) + - ((cmd[1] & 0x1f) << 16); - num = (0 == cmd[4]) ? 256 : cmd[4]; - } + get_data_transfer_info(cmd, &lba, &num); errsts = resp_write(SCpnt, lba, num, devip); if (inj_recovered && (0 == errsts)) { mk_sense_buffer(devip, RECOVERED_ERROR, @@ -549,6 +523,28 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) case WRITE_BUFFER: errsts = check_readiness(SCpnt, 1, devip); break; + case XDWRITEREAD_10: + if (!scsi_bidi_cmnd(SCpnt)) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + errsts = check_condition_result; + break; + } + + errsts = check_readiness(SCpnt, 0, devip); + if (errsts) + break; + if (scsi_debug_fake_rw) + break; + get_data_transfer_info(cmd, &lba, &num); + errsts = resp_read(SCpnt, lba, num, devip); + if (errsts) + break; + errsts = resp_write(SCpnt, lba, num, devip); + if (errsts) + break; + errsts = resp_xdwriteread(SCpnt, lba, num, devip); + break; default: if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " @@ -595,99 +591,37 @@ static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only, } /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ -static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, +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 * sg; + int act_len; + struct scsi_data_buffer *sdb = scsi_in(scp); - if (0 == scp->request_bufflen) + if (!sdb->length) return 0; - if (NULL == scp->request_buffer) + if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) 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); - if (scp->resid) - scp->resid -= act_len; - else - scp->resid = req_len - act_len; - return 0; - } - active = 1; - req_len = act_len = 0; - scsi_for_each_sg(scp, sg, scp->use_sg, k) { - if (active) { - kaddr = (unsigned char *) - kmap_atomic(sg_page(sg), KM_USER0); - if (NULL == kaddr) - return (DID_ERROR << 16); - kaddr_off = (unsigned char *)kaddr + sg->offset; - len = sg->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 += sg->length; - } - if (scp->resid) - scp->resid -= act_len; + + act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, + arr, arr_len); + if (sdb->resid) + sdb->resid -= act_len; else - scp->resid = req_len - act_len; + sdb->resid = scsi_bufflen(scp) - act_len; + return 0; } /* 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) +static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, + int arr_len) { - int k, req_len, len, fin; - void * kaddr; - void * kaddr_off; - struct scatterlist * sg; - - if (0 == scp->request_bufflen) + if (!scsi_bufflen(scp)) return 0; - if (NULL == scp->request_buffer) - return -1; - if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) || - (scp->sc_data_direction == DMA_TO_DEVICE))) + if (!(scsi_bidi_cmnd(scp) || 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; - } - sg = scsi_sglist(scp); - req_len = fin = 0; - for (k = 0; k < scp->use_sg; ++k, sg = sg_next(sg)) { - kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0); - if (NULL == kaddr) - return -1; - kaddr_off = (unsigned char *)kaddr + sg->offset; - len = sg->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 += sg->length; - } - return req_len; + + return scsi_sg_copy_to_buffer(scp, arr, arr_len); } @@ -1973,6 +1907,41 @@ static int resp_report_luns(struct scsi_cmnd * scp, min((int)alloc_len, SDEBUG_RLUN_ARR_SZ)); } +static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, + unsigned int num, struct sdebug_dev_info *devip) +{ + int i, j, ret = -1; + unsigned char *kaddr, *buf; + unsigned int offset; + struct scatterlist *sg; + struct scsi_data_buffer *sdb = scsi_in(scp); + + /* better not to use temporary buffer. */ + buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC); + if (!buf) + return ret; + + scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); + + offset = 0; + for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) { + kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0); + if (!kaddr) + goto out; + + for (j = 0; j < sg->length; j++) + *(kaddr + sg->offset + j) ^= *(buf + offset + j); + + offset += sg->length; + kunmap_atomic(kaddr, KM_USER0); + } + ret = 0; +out: + kfree(buf); + + return ret; +} + /* When timer goes off this function is called. */ static void timer_intr_handler(unsigned long indx) { @@ -2006,6 +1975,7 @@ static int scsi_debug_slave_alloc(struct scsi_device * sdp) if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n", sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); + set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags); return 0; } @@ -2053,8 +2023,8 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) if (devip) return devip; - sdbg_host = *(struct sdebug_host_info **) sdev->host->hostdata; - if(! sdbg_host) { + sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); + if (!sdbg_host) { printk(KERN_ERR "Host info NULL\n"); return NULL; } @@ -2181,7 +2151,7 @@ static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt) printk(KERN_INFO "scsi_debug: bus_reset\n"); ++num_bus_resets; if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) { - sdbg_host = *(struct sdebug_host_info **) hp->hostdata; + sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); if (sdbg_host) { list_for_each_entry(dev_info, &sdbg_host->dev_info_list, @@ -2877,8 +2847,6 @@ static int __init scsi_debug_init(void) init_all_queued(); - sdebug_driver_template.proc_name = sdebug_proc_name; - host_to_add = scsi_debug_add_host; scsi_debug_add_host = 0; @@ -3038,6 +3006,30 @@ static void sdebug_remove_adapter(void) --scsi_debug_add_host; } +static struct scsi_host_template sdebug_driver_template = { + .proc_info = scsi_debug_proc_info, + .proc_name = sdebug_proc_name, + .name = "SCSI DEBUG", + .info = scsi_debug_info, + .slave_alloc = scsi_debug_slave_alloc, + .slave_configure = scsi_debug_slave_configure, + .slave_destroy = scsi_debug_slave_destroy, + .ioctl = scsi_debug_ioctl, + .queuecommand = scsi_debug_queuecommand, + .eh_abort_handler = scsi_debug_abort, + .eh_bus_reset_handler = scsi_debug_bus_reset, + .eh_device_reset_handler = scsi_debug_device_reset, + .eh_host_reset_handler = scsi_debug_host_reset, + .bios_param = scsi_debug_biosparam, + .can_queue = SCSI_DEBUG_CANQUEUE, + .this_id = 7, + .sg_tablesize = 256, + .cmd_per_lun = 16, + .max_sectors = 0xffff, + .use_clustering = DISABLE_CLUSTERING, + .module = THIS_MODULE, +}; + static int sdebug_driver_probe(struct device * dev) { int error = 0;