#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
#include <linux/moduleparam.h>
-
+#include <linux/scatterlist.h>
#include <linux/blkdev.h>
-#include "scsi.h"
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsicam.h>
#include <linux/stat.h>
#include "scsi_logging.h"
-#include "scsi_debug.h"
#define SCSI_DEBUG_VERSION "1.81"
static const char * scsi_debug_version_date = "20070104";
#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 */
};
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;
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,
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;
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,
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,
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,
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 "
}
/* 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 * sgpnt;
+ 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)
- return (DID_ERROR << 16);
- if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
- (scp->sc_data_direction == DMA_FROM_DEVICE)))
+ if (!(scsi_bidi_cmnd(scp) || 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;
- }
- 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;
- }
- 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 * sgpnt;
-
- 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;
- }
- 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;
+
+ return scsi_sg_copy_to_buffer(scp, arr, arr_len);
}
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)
{
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;
}
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;
}
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,
init_all_queued();
- sdebug_driver_template.proc_name = (char *)sdebug_proc_name;
-
host_to_add = scsi_debug_add_host;
scsi_debug_add_host = 0;
--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;