X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fscsi%2Fscsi_debug.c;h=27c633f557945f8cfb99ce433bcf53ca774f2df8;hb=c82dc88ddaf17112841dd3a6b08352968555ee08;hp=06229f225ee9723fce6b21aedfc099c06aa7d32d;hpb=e63340ae6b6205fef26b40a75673d1c9c0c8bb90;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 06229f2..27c633f 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -38,16 +38,19 @@ #include #include #include - +#include #include -#include "scsi.h" + +#include +#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"; @@ -91,6 +94,7 @@ static const char * scsi_debug_version_date = "20070104"; #define DEF_VIRTUAL_GB 0 #define DEF_FAKE_RW 0 #define DEF_VPD_USE_HOSTNO 1 +#define DEF_SECTOR_SIZE 512 /* bit mask values for scsi_debug_opts */ #define SCSI_DEBUG_OPT_NOISE 1 @@ -139,13 +143,13 @@ static int scsi_debug_no_lun_0 = DEF_NO_LUN_0; static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; static int scsi_debug_fake_rw = DEF_FAKE_RW; static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; +static int scsi_debug_sector_size = DEF_SECTOR_SIZE; static int scsi_debug_cmnd_count = 0; #define DEV_READONLY(TGT) (0) #define DEV_REMOVEABLE(TGT) (0) -static unsigned int sdebug_store_size; /* in bytes */ static unsigned int sdebug_store_sectors; static sector_t sdebug_capacity; /* in sectors */ @@ -155,15 +159,13 @@ static int sdebug_heads; /* heads per disk */ static int sdebug_cylinders_per; /* cylinders per surface */ static int sdebug_sectors_per; /* sectors per cylinder */ -/* default sector size is 512 bytes, 2**9 bytes */ -#define POW2_SECT_SIZE 9 -#define SECT_SIZE (1 << POW2_SECT_SIZE) -#define SECT_SIZE_PER(TGT) SECT_SIZE - #define SDEBUG_MAX_PARTS 4 #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 */ @@ -201,30 +203,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; @@ -237,8 +215,6 @@ static DEFINE_RWLOCK(atomic_rw); static char sdebug_proc_name[] = "scsi_debug"; -static int sdebug_driver_probe(struct device *); -static int sdebug_driver_remove(struct device *); static struct bus_type pseudo_lld_bus; static struct device_driver sdebug_driverfs_driver = { @@ -254,312 +230,82 @@ static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 0, 0, 0x0, 0x0}; -/* function declarations */ -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_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, - struct sdebug_dev_info * devip); -static int resp_mode_sense(struct scsi_cmnd * scp, int target, - struct sdebug_dev_info * devip); -static int resp_mode_select(struct scsi_cmnd * scp, int mselect6, - struct sdebug_dev_info * devip); -static int resp_log_sense(struct scsi_cmnd * scp, - struct sdebug_dev_info * devip); -static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba, - unsigned int num, struct sdebug_dev_info * devip); -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 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); -static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only, - struct sdebug_dev_info * devip); -static int schedule_resp(struct scsi_cmnd * cmnd, - struct sdebug_dev_info * devip, - done_funct_t done, int scsi_result, int delta_jiff); -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 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); - static int sdebug_add_adapter(void); static void sdebug_remove_adapter(void); -static void sdebug_max_tgts_luns(void); - -static struct device pseudo_primary; -static struct bus_type pseudo_lld_bus; - -static -int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) +static void sdebug_max_tgts_luns(void) { - unsigned char *cmd = (unsigned char *) SCpnt->cmnd; - int len, k, j; - unsigned int num; - unsigned long long lba; - int errsts = 0; - 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) - return 0; /* assume mid level reprocessing command */ + struct sdebug_host_info *sdbg_host; + struct Scsi_Host *hpnt; - SCpnt->resid = 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"); + spin_lock(&sdebug_host_list_lock); + list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { + hpnt = sdbg_host->shost; + if ((hpnt->this_id >= 0) && + (scsi_debug_num_tgts > hpnt->this_id)) + hpnt->max_id = scsi_debug_num_tgts + 1; + else + hpnt->max_id = scsi_debug_num_tgts; + /* scsi_debug_max_luns; */ + hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; } - if(target == sdebug_driver_template.this_id) { - printk(KERN_INFO "scsi_debug: initiator's id used as " - "target!\n"); - return schedule_resp(SCpnt, NULL, done, - DID_NO_CONNECT << 16, 0); - } + spin_unlock(&sdebug_host_list_lock); +} - if ((SCpnt->device->lun >= scsi_debug_max_luns) && - (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS)) - return schedule_resp(SCpnt, NULL, done, - DID_NO_CONNECT << 16, 0); - devip = devInfoReg(SCpnt->device); - if (NULL == devip) - return schedule_resp(SCpnt, NULL, done, - DID_NO_CONNECT << 16, 0); +static void mk_sense_buffer(struct sdebug_dev_info *devip, int key, + int asc, int asq) +{ + unsigned char *sbuff; - 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) - 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 */ - } + sbuff = devip->sense_buff; + memset(sbuff, 0, SDEBUG_SENSE_LEN); - if (devip->wlun) { - switch (*cmd) { - case INQUIRY: - case REQUEST_SENSE: - case TEST_UNIT_READY: - case REPORT_LUNS: - break; /* only allowable wlun commands */ - default: - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: Opcode: 0x%x " - "not supported for wlun\n", *cmd); - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_OPCODE, 0); - errsts = check_condition_result; - return schedule_resp(SCpnt, devip, done, errsts, - 0); - } - } + scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq); + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: " + "[0x%x,0x%x,0x%x]\n", key, asc, asq); +} + +static void get_data_transfer_info(unsigned char *cmd, + unsigned long long *lba, unsigned int *num) +{ switch (*cmd) { - case INQUIRY: /* mandatory, ignore unit attention */ - delay_override = 1; - errsts = resp_inquiry(SCpnt, target, devip); - break; - case REQUEST_SENSE: /* mandatory, ignore unit attention */ - delay_override = 1; - errsts = resp_requests(SCpnt, devip); - break; - case REZERO_UNIT: /* actually this is REWIND for SSC */ - case START_STOP: - errsts = resp_start_stop(SCpnt, devip); - break; - case ALLOW_MEDIUM_REMOVAL: - if ((errsts = check_readiness(SCpnt, 1, devip))) - break; - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: Medium removal %s\n", - cmd[4] ? "inhibited" : "enabled"); - break; - case SEND_DIAGNOSTIC: /* mandatory */ - errsts = check_readiness(SCpnt, 1, devip); - break; - case TEST_UNIT_READY: /* mandatory */ - delay_override = 1; - errsts = check_readiness(SCpnt, 0, devip); - break; - case RESERVE: - errsts = check_readiness(SCpnt, 1, devip); - break; - case RESERVE_10: - errsts = check_readiness(SCpnt, 1, devip); - break; - case RELEASE: - errsts = check_readiness(SCpnt, 1, devip); - break; - case RELEASE_10: - errsts = check_readiness(SCpnt, 1, devip); - break; - case READ_CAPACITY: - errsts = resp_readcap(SCpnt, devip); - break; - case SERVICE_ACTION_IN: - if (SAI_READ_CAPACITY_16 != cmd[1]) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_OPCODE, 0); - errsts = check_condition_result; - break; - } - 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 WRITE_16: case READ_16: - case READ_12: - case READ_10: - case READ_6: - if ((errsts = check_readiness(SCpnt, 0, devip))) - 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]; - } - errsts = resp_read(SCpnt, lba, num, devip); - if (inj_recovered && (0 == errsts)) { - 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; - errsts = resp_report_luns(SCpnt, devip); - break; - case VERIFY: /* 10 byte SBC-2 command */ - errsts = check_readiness(SCpnt, 0, devip); + *lba = (u64)cmd[9] | (u64)cmd[8] << 8 | + (u64)cmd[7] << 16 | (u64)cmd[6] << 24 | + (u64)cmd[5] << 32 | (u64)cmd[4] << 40 | + (u64)cmd[3] << 48 | (u64)cmd[2] << 56; + + *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 | + (u32)cmd[10] << 24; break; - case WRITE_16: case WRITE_12: - case WRITE_10: - case WRITE_6: - if ((errsts = check_readiness(SCpnt, 0, devip))) - 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]; - } - errsts = resp_write(SCpnt, lba, num, devip); - if (inj_recovered && (0 == errsts)) { - mk_sense_buffer(devip, RECOVERED_ERROR, - THRESHOLD_EXCEEDED, 0); - errsts = check_condition_result; - } - break; - case MODE_SENSE: - case MODE_SENSE_10: - errsts = resp_mode_sense(SCpnt, target, devip); - break; - case MODE_SELECT: - errsts = resp_mode_select(SCpnt, 1, devip); - break; - case MODE_SELECT_10: - errsts = resp_mode_select(SCpnt, 0, devip); - break; - case LOG_SENSE: - errsts = resp_log_sense(SCpnt, devip); + case READ_12: + *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 | + (u32)cmd[2] << 24; + + *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 | + (u32)cmd[6] << 24; break; - case SYNCHRONIZE_CACHE: - delay_override = 1; - errsts = check_readiness(SCpnt, 0, devip); + case WRITE_10: + case READ_10: + case XDWRITEREAD_10: + *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 | + (u32)cmd[2] << 24; + + *num = (u32)cmd[8] | (u32)cmd[7] << 8; break; - case WRITE_BUFFER: - errsts = check_readiness(SCpnt, 1, devip); + case WRITE_6: + case READ_6: + *lba = (u32)cmd[3] | (u32)cmd[2] << 8 | + (u32)(cmd[1] & 0x1f) << 16; + *num = (0 == cmd[4]) ? 256 : cmd[4]; break; default: - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " - "supported\n", *cmd); - if ((errsts = check_readiness(SCpnt, 1, devip))) - break; /* Unit attention takes precedence */ - mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0); - errsts = check_condition_result; break; } - return schedule_resp(SCpnt, devip, done, errsts, - (delay_override ? 0 : scsi_debug_delay)); } static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) @@ -594,98 +340,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 * 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) + 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; - } - 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) + if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE)) 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; + + return scsi_sg_copy_to_buffer(scp, arr, arr_len); } @@ -958,6 +643,14 @@ static int inquiry_evpd_b0(unsigned char * arr) return sizeof(vpdb0_data); } +static int inquiry_evpd_b1(unsigned char *arr) +{ + memset(arr, 0, 0x3c); + arr[0] = 0; + arr[1] = 1; + + return 0x3c; +} #define SDEBUG_LONG_INQ_SZ 96 #define SDEBUG_MAX_INQ_ARR_SZ 584 @@ -1013,6 +706,7 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, arr[n++] = 0x88; /* SCSI ports */ arr[n++] = 0x89; /* ATA information */ arr[n++] = 0xb0; /* Block limits (SBC) */ + arr[n++] = 0xb1; /* Block characteristics (SBC) */ arr[3] = n - 4; /* number of supported VPD pages */ } else if (0x80 == cmd[2]) { /* unit serial number */ arr[1] = cmd[2]; /*sanity */ @@ -1052,6 +746,9 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */ arr[1] = cmd[2]; /*sanity */ arr[3] = inquiry_evpd_b0(&arr[4]); + } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = inquiry_evpd_b1(&arr[4]); } else { /* Illegal request, invalid field in cdb */ mk_sense_buffer(devip, ILLEGAL_REQUEST, @@ -1157,6 +854,14 @@ static int resp_start_stop(struct scsi_cmnd * scp, return 0; } +static sector_t get_sdebug_capacity(void) +{ + if (scsi_debug_virtual_gb > 0) + return 2048 * 1024 * scsi_debug_virtual_gb; + else + return sdebug_store_sectors; +} + #define SDEBUG_READCAP_ARR_SZ 8 static int resp_readcap(struct scsi_cmnd * scp, struct sdebug_dev_info * devip) @@ -1168,11 +873,7 @@ static int resp_readcap(struct scsi_cmnd * scp, if ((errsts = check_readiness(scp, 1, devip))) return errsts; /* following just in case virtual_gb changed */ - if (scsi_debug_virtual_gb > 0) { - sdebug_capacity = 2048 * 1024; - sdebug_capacity *= scsi_debug_virtual_gb; - } else - sdebug_capacity = sdebug_store_sectors; + sdebug_capacity = get_sdebug_capacity(); memset(arr, 0, SDEBUG_READCAP_ARR_SZ); if (sdebug_capacity < 0xffffffff) { capac = (unsigned int)sdebug_capacity - 1; @@ -1186,8 +887,8 @@ static int resp_readcap(struct scsi_cmnd * scp, arr[2] = 0xff; arr[3] = 0xff; } - arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; - arr[7] = SECT_SIZE_PER(target) & 0xff; + arr[6] = (scsi_debug_sector_size >> 8) & 0xff; + arr[7] = scsi_debug_sector_size & 0xff; return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); } @@ -1205,19 +906,15 @@ static int resp_readcap16(struct scsi_cmnd * scp, alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8) + cmd[13]); /* following just in case virtual_gb changed */ - if (scsi_debug_virtual_gb > 0) { - sdebug_capacity = 2048 * 1024; - sdebug_capacity *= scsi_debug_virtual_gb; - } else - sdebug_capacity = sdebug_store_sectors; + sdebug_capacity = get_sdebug_capacity(); memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); capac = sdebug_capacity - 1; for (k = 0; k < 8; ++k, capac >>= 8) arr[7 - k] = capac & 0xff; - arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff; - arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff; - arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff; - arr[11] = SECT_SIZE_PER(target) & 0xff; + arr[8] = (scsi_debug_sector_size >> 24) & 0xff; + arr[9] = (scsi_debug_sector_size >> 16) & 0xff; + arr[10] = (scsi_debug_sector_size >> 8) & 0xff; + arr[11] = scsi_debug_sector_size & 0xff; return fill_from_dev_buffer(scp, arr, min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); } @@ -1331,20 +1028,20 @@ static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) static int resp_format_pg(unsigned char * p, int pcontrol, int target) { /* Format device page for mode_sense */ - unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0x40, 0, 0, 0}; - - memcpy(p, format_pg, sizeof(format_pg)); - p[10] = (sdebug_sectors_per >> 8) & 0xff; - p[11] = sdebug_sectors_per & 0xff; - p[12] = (SECT_SIZE >> 8) & 0xff; - p[13] = SECT_SIZE & 0xff; - if (DEV_REMOVEABLE(target)) - p[20] |= 0x20; /* should agree with INQUIRY */ - if (1 == pcontrol) - memset(p + 2, 0, sizeof(format_pg) - 2); - return sizeof(format_pg); + unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0x40, 0, 0, 0}; + + memcpy(p, format_pg, sizeof(format_pg)); + p[10] = (sdebug_sectors_per >> 8) & 0xff; + p[11] = sdebug_sectors_per & 0xff; + p[12] = (scsi_debug_sector_size >> 8) & 0xff; + p[13] = scsi_debug_sector_size & 0xff; + if (DEV_REMOVEABLE(target)) + p[20] |= 0x20; /* should agree with INQUIRY */ + if (1 == pcontrol) + memset(p + 2, 0, sizeof(format_pg) - 2); + return sizeof(format_pg); } static int resp_caching_pg(unsigned char * p, int pcontrol, int target) @@ -1503,13 +1200,9 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, offset = 8; } ap = arr + offset; - if ((bd_len > 0) && (0 == sdebug_capacity)) { - if (scsi_debug_virtual_gb > 0) { - sdebug_capacity = 2048 * 1024; - sdebug_capacity *= scsi_debug_virtual_gb; - } else - sdebug_capacity = sdebug_store_sectors; - } + if ((bd_len > 0) && (!sdebug_capacity)) + sdebug_capacity = get_sdebug_capacity(); + if (8 == bd_len) { if (sdebug_capacity > 0xfffffffe) { ap[0] = 0xff; @@ -1522,8 +1215,8 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, ap[2] = (sdebug_capacity >> 8) & 0xff; ap[3] = sdebug_capacity & 0xff; } - ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; - ap[7] = SECT_SIZE_PER(target) & 0xff; + ap[6] = (scsi_debug_sector_size >> 8) & 0xff; + ap[7] = scsi_debug_sector_size & 0xff; offset += bd_len; ap = arr + offset; } else if (16 == bd_len) { @@ -1531,10 +1224,10 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, for (k = 0; k < 8; ++k, capac >>= 8) ap[7 - k] = capac & 0xff; - ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff; - ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff; - ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff; - ap[15] = SECT_SIZE_PER(target) & 0xff; + ap[12] = (scsi_debug_sector_size >> 24) & 0xff; + ap[13] = (scsi_debug_sector_size >> 16) & 0xff; + ap[14] = (scsi_debug_sector_size >> 8) & 0xff; + ap[15] = scsi_debug_sector_size & 0xff; offset += bd_len; ap = arr + offset; } @@ -1806,25 +1499,53 @@ static int resp_log_sense(struct scsi_cmnd * scp, min(len, SDEBUG_MAX_INQ_ARR_SZ)); } -static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba, - unsigned int num, struct sdebug_dev_info * devip) +static int check_device_access_params(struct sdebug_dev_info *devi, + unsigned long long lba, unsigned int num) { - unsigned long iflags; - unsigned int block, from_bottom; - unsigned long long u; - int ret; - if (lba + num > sdebug_capacity) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, - 0); + mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0); return check_condition_result; } /* transfer length excessive (tie in to block limits VPD page) */ if (num > sdebug_store_sectors) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, - 0); + mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return check_condition_result; } + return 0; +} + +static int do_device_access(struct scsi_cmnd *scmd, + struct sdebug_dev_info *devi, + unsigned long long lba, unsigned int num, int write) +{ + int ret; + unsigned int block, rest = 0; + int (*func)(struct scsi_cmnd *, unsigned char *, int); + + func = write ? fetch_to_dev_buffer : fill_from_dev_buffer; + + block = do_div(lba, sdebug_store_sectors); + if (block + num > sdebug_store_sectors) + rest = block + num - sdebug_store_sectors; + + ret = func(scmd, fake_storep + (block * scsi_debug_sector_size), + (num - rest) * scsi_debug_sector_size); + if (!ret && rest) + ret = func(scmd, fake_storep, rest * scsi_debug_sector_size); + + return ret; +} + +static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba, + unsigned int num, struct sdebug_dev_info *devip) +{ + unsigned long iflags; + int ret; + + ret = check_device_access_params(devip, lba, num); + if (ret) + return ret; + if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && (lba <= OPT_MEDIUM_ERR_ADDR) && ((lba + num) > OPT_MEDIUM_ERR_ADDR)) { @@ -1843,74 +1564,30 @@ static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba, return check_condition_result; } read_lock_irqsave(&atomic_rw, iflags); - if ((lba + num) <= sdebug_store_sectors) - ret = fill_from_dev_buffer(SCpnt, - fake_storep + (lba * SECT_SIZE), - num * SECT_SIZE); - else { - /* modulo when one arg is 64 bits needs do_div() */ - u = lba; - block = do_div(u, sdebug_store_sectors); - from_bottom = 0; - if ((block + num) > sdebug_store_sectors) - from_bottom = (block + num) - sdebug_store_sectors; - ret = fill_from_dev_buffer(SCpnt, - fake_storep + (block * SECT_SIZE), - (num - from_bottom) * SECT_SIZE); - if ((0 == ret) && (from_bottom > 0)) - ret = fill_from_dev_buffer(SCpnt, fake_storep, - from_bottom * SECT_SIZE); - } + ret = do_device_access(SCpnt, devip, lba, num, 0); read_unlock_irqrestore(&atomic_rw, iflags); return ret; } -static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba, - unsigned int num, struct sdebug_dev_info * devip) +static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, + unsigned int num, struct sdebug_dev_info *devip) { unsigned long iflags; - unsigned int block, to_bottom; - unsigned long long u; - int res; + int ret; - if (lba + num > sdebug_capacity) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, - 0); - return check_condition_result; - } - /* transfer length excessive (tie in to block limits VPD page) */ - if (num > sdebug_store_sectors) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, - 0); - return check_condition_result; - } + ret = check_device_access_params(devip, lba, num); + if (ret) + return ret; write_lock_irqsave(&atomic_rw, iflags); - if ((lba + num) <= sdebug_store_sectors) - res = fetch_to_dev_buffer(SCpnt, - fake_storep + (lba * SECT_SIZE), - num * SECT_SIZE); - else { - /* modulo when one arg is 64 bits needs do_div() */ - u = lba; - block = do_div(u, sdebug_store_sectors); - to_bottom = 0; - if ((block + num) > sdebug_store_sectors) - to_bottom = (block + num) - sdebug_store_sectors; - res = fetch_to_dev_buffer(SCpnt, - fake_storep + (block * SECT_SIZE), - (num - to_bottom) * SECT_SIZE); - if ((0 == res) && (to_bottom > 0)) - res = fetch_to_dev_buffer(SCpnt, fake_storep, - to_bottom * SECT_SIZE); - } + ret = do_device_access(SCpnt, devip, lba, num, 1); write_unlock_irqrestore(&atomic_rw, iflags); - if (-1 == res) + if (-1 == ret) return (DID_ERROR << 16); - else if ((res < (num * SECT_SIZE)) && + else if ((ret < (num * scsi_debug_sector_size)) && (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " - " IO sent=%d bytes\n", num * SECT_SIZE, res); + " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret); return 0; } @@ -1971,6 +1648,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) { @@ -1999,17 +1711,84 @@ static void timer_intr_handler(unsigned long indx) spin_unlock_irqrestore(&queued_arr_lock, iflags); } -static int scsi_debug_slave_alloc(struct scsi_device * sdp) + +static struct sdebug_dev_info * +sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags) +{ + struct sdebug_dev_info *devip; + + devip = kzalloc(sizeof(*devip), flags); + if (devip) { + devip->sdbg_host = sdbg_host; + list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); + } + return devip; +} + +static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) +{ + struct sdebug_host_info * sdbg_host; + struct sdebug_dev_info * open_devip = NULL; + struct sdebug_dev_info * devip = + (struct sdebug_dev_info *)sdev->hostdata; + + if (devip) + return devip; + sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); + if (!sdbg_host) { + printk(KERN_ERR "Host info NULL\n"); + return NULL; + } + list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { + if ((devip->used) && (devip->channel == sdev->channel) && + (devip->target == sdev->id) && + (devip->lun == sdev->lun)) + return devip; + else { + if ((!devip->used) && (!open_devip)) + open_devip = devip; + } + } + if (!open_devip) { /* try and make a new one */ + open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); + if (!open_devip) { + printk(KERN_ERR "%s: out of memory at line %d\n", + __func__, __LINE__); + return NULL; + } + } + + open_devip->channel = sdev->channel; + open_devip->target = sdev->id; + open_devip->lun = sdev->lun; + open_devip->sdbg_host = sdbg_host; + open_devip->reset = 1; + open_devip->used = 1; + memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN); + if (scsi_debug_dsense) + open_devip->sense_buff[0] = 0x72; + else { + open_devip->sense_buff[0] = 0x70; + open_devip->sense_buff[7] = 0xa; + } + if (sdev->lun == SAM2_WLUN_REPORT_LUNS) + open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff; + + return open_devip; +} + +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); + queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue); return 0; } -static int scsi_debug_slave_configure(struct scsi_device * sdp) +static int scsi_debug_slave_configure(struct scsi_device *sdp) { - struct sdebug_dev_info * devip; + struct sdebug_dev_info *devip; if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n", @@ -2027,10 +1806,10 @@ static int scsi_debug_slave_configure(struct scsi_device * sdp) return 0; } -static void scsi_debug_slave_destroy(struct scsi_device * sdp) +static void scsi_debug_slave_destroy(struct scsi_device *sdp) { - struct sdebug_dev_info * devip = - (struct sdebug_dev_info *)sdp->hostdata; + struct sdebug_dev_info *devip = + (struct sdebug_dev_info *)sdp->hostdata; if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n", @@ -2042,84 +1821,44 @@ static void scsi_debug_slave_destroy(struct scsi_device * sdp) } } -static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) +/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */ +static int stop_queued_cmnd(struct scsi_cmnd *cmnd) { - struct sdebug_host_info * sdbg_host; - struct sdebug_dev_info * open_devip = NULL; - struct sdebug_dev_info * devip = - (struct sdebug_dev_info *)sdev->hostdata; + unsigned long iflags; + int k; + struct sdebug_queued_cmd *sqcp; - if (devip) - return devip; - sdbg_host = *(struct sdebug_host_info **) sdev->host->hostdata; - if(! sdbg_host) { - printk(KERN_ERR "Host info NULL\n"); - return NULL; - } - list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { - if ((devip->used) && (devip->channel == sdev->channel) && - (devip->target == sdev->id) && - (devip->lun == sdev->lun)) - return devip; - else { - if ((!devip->used) && (!open_devip)) - open_devip = devip; + spin_lock_irqsave(&queued_arr_lock, iflags); + for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { + sqcp = &queued_arr[k]; + if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) { + del_timer_sync(&sqcp->cmnd_timer); + sqcp->in_use = 0; + sqcp->a_cmnd = NULL; + break; } } - if (NULL == open_devip) { /* try and make a new one */ - 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__); - return NULL; - } - open_devip->sdbg_host = sdbg_host; - list_add_tail(&open_devip->dev_list, - &sdbg_host->dev_info_list); - } - if (open_devip) { - open_devip->channel = sdev->channel; - open_devip->target = sdev->id; - open_devip->lun = sdev->lun; - open_devip->sdbg_host = sdbg_host; - open_devip->reset = 1; - open_devip->used = 1; - memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN); - if (scsi_debug_dsense) - open_devip->sense_buff[0] = 0x72; - else { - open_devip->sense_buff[0] = 0x70; - open_devip->sense_buff[7] = 0xa; - } - if (sdev->lun == SAM2_WLUN_REPORT_LUNS) - open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff; - return open_devip; - } - return NULL; + spin_unlock_irqrestore(&queued_arr_lock, iflags); + return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0; } -static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, - int asc, int asq) +/* Deletes (stops) timers of all queued commands */ +static void stop_all_queued(void) { - unsigned char * sbuff; + unsigned long iflags; + int k; + struct sdebug_queued_cmd *sqcp; - sbuff = devip->sense_buff; - memset(sbuff, 0, SDEBUG_SENSE_LEN); - if (scsi_debug_dsense) { - sbuff[0] = 0x72; /* descriptor, current */ - sbuff[1] = key; - sbuff[2] = asc; - sbuff[3] = asq; - } else { - sbuff[0] = 0x70; /* fixed, current */ - sbuff[2] = key; - sbuff[7] = 0xa; /* implies 18 byte sense buffer */ - sbuff[12] = asc; - sbuff[13] = asq; + spin_lock_irqsave(&queued_arr_lock, iflags); + for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { + sqcp = &queued_arr[k]; + if (sqcp->in_use && sqcp->a_cmnd) { + del_timer_sync(&sqcp->cmnd_timer); + sqcp->in_use = 0; + sqcp->a_cmnd = NULL; + } } - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: " - "[0x%x,0x%x,0x%x]\n", key, asc, asq); + spin_unlock_irqrestore(&queued_arr_lock, iflags); } static int scsi_debug_abort(struct scsi_cmnd * SCpnt) @@ -2179,7 +1918,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, @@ -2209,46 +1948,6 @@ static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt) return SUCCESS; } -/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */ -static int stop_queued_cmnd(struct scsi_cmnd * cmnd) -{ - unsigned long iflags; - int k; - struct sdebug_queued_cmd * sqcp; - - spin_lock_irqsave(&queued_arr_lock, iflags); - for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { - sqcp = &queued_arr[k]; - if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) { - del_timer_sync(&sqcp->cmnd_timer); - sqcp->in_use = 0; - sqcp->a_cmnd = NULL; - break; - } - } - spin_unlock_irqrestore(&queued_arr_lock, iflags); - return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0; -} - -/* Deletes (stops) timers of all queued commands */ -static void stop_all_queued(void) -{ - unsigned long iflags; - int k; - struct sdebug_queued_cmd * sqcp; - - spin_lock_irqsave(&queued_arr_lock, iflags); - for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { - sqcp = &queued_arr[k]; - if (sqcp->in_use && sqcp->a_cmnd) { - del_timer_sync(&sqcp->cmnd_timer); - sqcp->in_use = 0; - sqcp->a_cmnd = NULL; - } - } - spin_unlock_irqrestore(&queued_arr_lock, iflags); -} - /* Initializes timers in queued array */ static void __init init_all_queued(void) { @@ -2266,7 +1965,8 @@ static void __init init_all_queued(void) spin_unlock_irqrestore(&queued_arr_lock, iflags); } -static void __init sdebug_build_parts(unsigned char * ramp) +static void __init sdebug_build_parts(unsigned char *ramp, + unsigned long store_size) { struct partition * pp; int starts[SDEBUG_MAX_PARTS + 2]; @@ -2274,7 +1974,7 @@ static void __init sdebug_build_parts(unsigned char * ramp) int heads_by_sects, start_sec, end_sec; /* assume partition table already zeroed */ - if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576)) + if ((scsi_debug_num_parts < 1) || (store_size < 1048576)) return; if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) { scsi_debug_num_parts = SDEBUG_MAX_PARTS; @@ -2372,7 +2072,6 @@ static int schedule_resp(struct scsi_cmnd * cmnd, return 0; } } - /* Note: The following macros create attribute files in the /sys/module/scsi_debug/parameters directory. Unfortunately this driver is unaware of a change and cannot trigger auxiliary actions @@ -2395,6 +2094,7 @@ module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO); module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, S_IRUGO | S_IWUSR); +module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO); MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); MODULE_DESCRIPTION("SCSI debug adapter driver"); @@ -2405,7 +2105,7 @@ MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)"); MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)"); MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); -MODULE_PARM_DESC(every_nth, "timeout every nth command(def=100)"); +MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 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)"); @@ -2416,6 +2116,7 @@ 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)"); MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); +MODULE_PARM_DESC(sector_size, "hardware sector size in bytes (def=512)"); static char sdebug_info[256]; @@ -2468,8 +2169,9 @@ static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **sta scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth, scsi_debug_cmnd_count, scsi_debug_delay, scsi_debug_max_luns, scsi_debug_scsi_level, - SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, - num_aborts, num_dev_resets, num_bus_resets, num_host_resets); + scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads, + sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets, + num_host_resets); if (pos < offset) { len = 0; begin = pos; @@ -2689,11 +2391,9 @@ static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp, if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { scsi_debug_virtual_gb = n; - if (scsi_debug_virtual_gb > 0) { - sdebug_capacity = 2048 * 1024; - sdebug_capacity *= scsi_debug_virtual_gb; - } else - sdebug_capacity = sdebug_store_sectors; + + sdebug_capacity = get_sdebug_capacity(); + return count; } return -EINVAL; @@ -2709,21 +2409,10 @@ static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf) static ssize_t sdebug_add_host_store(struct device_driver * ddp, const char * buf, size_t count) { - int delta_hosts; - char work[20]; + int delta_hosts; - if (1 != sscanf(buf, "%10s", work)) + if (sscanf(buf, "%d", &delta_hosts) != 1) return -EINVAL; - { /* temporary hack around sscanf() problem with -ve nums */ - int neg = 0; - - if ('-' == *work) - neg = 1; - if (1 != sscanf(work + neg, "%d", &delta_hosts)) - return -EINVAL; - if (neg) - delta_hosts = -delta_hosts; - } if (delta_hosts > 0) { do { sdebug_add_adapter(); @@ -2735,7 +2424,7 @@ static ssize_t sdebug_add_host_store(struct device_driver * ddp, } return count; } -DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, +DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, sdebug_add_host_store); static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp, @@ -2757,6 +2446,12 @@ static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp, DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show, sdebug_vpd_use_hostno_store); +static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf) +{ + return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size); +} +DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL); + /* Note: The following function creates attribute files in the /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these files (over those found in the /sys/module/scsi_debug/parameters @@ -2782,11 +2477,13 @@ static int do_create_driverfs_files(void) ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); + ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size); return ret; } static void do_remove_driverfs_files(void) { + driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); @@ -2804,22 +2501,41 @@ static void do_remove_driverfs_files(void) driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host); } +static void pseudo_0_release(struct device *dev) +{ + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n"); +} + +static struct device pseudo_primary = { + .bus_id = "pseudo_0", + .release = pseudo_0_release, +}; + static int __init scsi_debug_init(void) { - unsigned int sz; + unsigned long sz; int host_to_add; int k; int ret; + switch (scsi_debug_sector_size) { + case 512: + case 1024: + case 2048: + case 4096: + break; + default: + printk(KERN_ERR "scsi_debug_init: invalid sector_size %u\n", + scsi_debug_sector_size); + return -EINVAL; + } + if (scsi_debug_dev_size_mb < 1) scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ - sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576; - sdebug_store_sectors = sdebug_store_size / SECT_SIZE; - if (scsi_debug_virtual_gb > 0) { - sdebug_capacity = 2048 * 1024; - sdebug_capacity *= scsi_debug_virtual_gb; - } else - sdebug_capacity = sdebug_store_sectors; + sz = (unsigned long)scsi_debug_dev_size_mb * 1048576; + sdebug_store_sectors = sz / scsi_debug_sector_size; + sdebug_capacity = get_sdebug_capacity(); /* play around with geometry, don't waste too much on track 0 */ sdebug_heads = 8; @@ -2838,7 +2554,6 @@ static int __init scsi_debug_init(void) (sdebug_sectors_per * sdebug_heads); } - sz = sdebug_store_size; fake_storep = vmalloc(sz); if (NULL == fake_storep) { printk(KERN_ERR "scsi_debug_init: out of memory, 1\n"); @@ -2846,7 +2561,7 @@ static int __init scsi_debug_init(void) } memset(fake_storep, 0, sz); if (scsi_debug_num_parts > 0) - sdebug_build_parts(fake_storep); + sdebug_build_parts(fake_storep, sz); ret = device_register(&pseudo_primary); if (ret < 0) { @@ -2875,8 +2590,6 @@ static int __init scsi_debug_init(void) init_all_queued(); - sdebug_driver_template.proc_name = (char *)sdebug_proc_name; - host_to_add = scsi_debug_add_host; scsi_debug_add_host = 0; @@ -2925,30 +2638,6 @@ static void __exit scsi_debug_exit(void) device_initcall(scsi_debug_init); module_exit(scsi_debug_exit); -static void pseudo_0_release(struct device * dev) -{ - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n"); -} - -static struct device pseudo_primary = { - .bus_id = "pseudo_0", - .release = pseudo_0_release, -}; - -static int pseudo_lld_bus_match(struct device *dev, - struct device_driver *dev_driver) -{ - return 1; -} - -static struct bus_type pseudo_lld_bus = { - .name = "pseudo", - .match = pseudo_lld_bus_match, - .probe = sdebug_driver_probe, - .remove = sdebug_driver_remove, -}; - static void sdebug_release_adapter(struct device * dev) { struct sdebug_host_info *sdbg_host; @@ -2962,13 +2651,12 @@ static int sdebug_add_adapter(void) int k, devs_per_host; int error = 0; struct sdebug_host_info *sdbg_host; - struct sdebug_dev_info *sdbg_devinfo; - struct list_head *lh, *lh_sf; + struct sdebug_dev_info *sdbg_devinfo, *tmp; 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__); + __func__, __LINE__); return -ENOMEM; } @@ -2976,16 +2664,13 @@ static int sdebug_add_adapter(void) devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns; for (k = 0; k < devs_per_host; k++) { - sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo),GFP_KERNEL); - if (NULL == sdbg_devinfo) { + sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); + if (!sdbg_devinfo) { printk(KERN_ERR "%s: out of memory at line %d\n", - __FUNCTION__, __LINE__); + __func__, __LINE__); error = -ENOMEM; goto clean; } - sdbg_devinfo->sdbg_host = sdbg_host; - list_add_tail(&sdbg_devinfo->dev_list, - &sdbg_host->dev_info_list); } spin_lock(&sdebug_host_list_lock); @@ -3006,9 +2691,8 @@ static int sdebug_add_adapter(void) return error; clean: - list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) { - sdbg_devinfo = list_entry(lh, struct sdebug_dev_info, - dev_list); + list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, + dev_list) { list_del(&sdbg_devinfo->dev_list); kfree(sdbg_devinfo); } @@ -3036,6 +2720,263 @@ static void sdebug_remove_adapter(void) --scsi_debug_add_host; } +static +int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) +{ + unsigned char *cmd = (unsigned char *) SCpnt->cmnd; + int len, k; + unsigned int num; + unsigned long long lba; + int errsts = 0; + int target = SCpnt->device->id; + struct sdebug_dev_info *devip = NULL; + int inj_recovered = 0; + int inj_transport = 0; + int delay_override = 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 == SCpnt->device->host->hostt->this_id) { + printk(KERN_INFO "scsi_debug: initiator's id used as " + "target!\n"); + return schedule_resp(SCpnt, NULL, done, + DID_NO_CONNECT << 16, 0); + } + + if ((SCpnt->device->lun >= scsi_debug_max_luns) && + (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS)) + return schedule_resp(SCpnt, NULL, done, + DID_NO_CONNECT << 16, 0); + devip = devInfoReg(SCpnt->device); + if (NULL == devip) + return schedule_resp(SCpnt, NULL, done, + DID_NO_CONNECT << 16, 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) + 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) { + switch (*cmd) { + case INQUIRY: + case REQUEST_SENSE: + case TEST_UNIT_READY: + case REPORT_LUNS: + break; /* only allowable wlun commands */ + default: + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: Opcode: 0x%x " + "not supported for wlun\n", *cmd); + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_OPCODE, 0); + errsts = check_condition_result; + return schedule_resp(SCpnt, devip, done, errsts, + 0); + } + } + + switch (*cmd) { + case INQUIRY: /* mandatory, ignore unit attention */ + delay_override = 1; + errsts = resp_inquiry(SCpnt, target, devip); + break; + case REQUEST_SENSE: /* mandatory, ignore unit attention */ + delay_override = 1; + errsts = resp_requests(SCpnt, devip); + break; + case REZERO_UNIT: /* actually this is REWIND for SSC */ + case START_STOP: + errsts = resp_start_stop(SCpnt, devip); + break; + case ALLOW_MEDIUM_REMOVAL: + errsts = check_readiness(SCpnt, 1, devip); + if (errsts) + break; + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: Medium removal %s\n", + cmd[4] ? "inhibited" : "enabled"); + break; + case SEND_DIAGNOSTIC: /* mandatory */ + errsts = check_readiness(SCpnt, 1, devip); + break; + case TEST_UNIT_READY: /* mandatory */ + delay_override = 1; + errsts = check_readiness(SCpnt, 0, devip); + break; + case RESERVE: + errsts = check_readiness(SCpnt, 1, devip); + break; + case RESERVE_10: + errsts = check_readiness(SCpnt, 1, devip); + break; + case RELEASE: + errsts = check_readiness(SCpnt, 1, devip); + break; + case RELEASE_10: + errsts = check_readiness(SCpnt, 1, devip); + break; + case READ_CAPACITY: + errsts = resp_readcap(SCpnt, devip); + break; + case SERVICE_ACTION_IN: + if (SAI_READ_CAPACITY_16 != cmd[1]) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_OPCODE, 0); + errsts = check_condition_result; + break; + } + 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: + case READ_6: + 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 (inj_recovered && (0 == errsts)) { + 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; + errsts = resp_report_luns(SCpnt, devip); + break; + case VERIFY: /* 10 byte SBC-2 command */ + errsts = check_readiness(SCpnt, 0, devip); + break; + case WRITE_16: + case WRITE_12: + case WRITE_10: + case WRITE_6: + errsts = check_readiness(SCpnt, 0, devip); + if (errsts) + break; + if (scsi_debug_fake_rw) + break; + 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, + THRESHOLD_EXCEEDED, 0); + errsts = check_condition_result; + } + break; + case MODE_SENSE: + case MODE_SENSE_10: + errsts = resp_mode_sense(SCpnt, target, devip); + break; + case MODE_SELECT: + errsts = resp_mode_select(SCpnt, 1, devip); + break; + case MODE_SELECT_10: + errsts = resp_mode_select(SCpnt, 0, devip); + break; + case LOG_SENSE: + errsts = resp_log_sense(SCpnt, devip); + break; + case SYNCHRONIZE_CACHE: + delay_override = 1; + errsts = check_readiness(SCpnt, 0, devip); + break; + 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 " + "supported\n", *cmd); + errsts = check_readiness(SCpnt, 1, devip); + if (errsts) + break; /* Unit attention takes precedence */ + mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0); + errsts = check_condition_result; + break; + } + return schedule_resp(SCpnt, devip, done, errsts, + (delay_override ? 0 : scsi_debug_delay)); +} + +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; @@ -3046,7 +2987,7 @@ static int sdebug_driver_probe(struct device * dev) hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); if (NULL == hpnt) { - printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__); + printk(KERN_ERR "%s: scsi_register failed\n", __func__); error = -ENODEV; return error; } @@ -3061,7 +3002,7 @@ static int sdebug_driver_probe(struct device * dev) error = scsi_add_host(hpnt, &sdbg_host->dev); if (error) { - printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__); + printk(KERN_ERR "%s: scsi_add_host failed\n", __func__); error = -ENODEV; scsi_host_put(hpnt); } else @@ -3073,23 +3014,21 @@ static int sdebug_driver_probe(struct device * dev) static int sdebug_driver_remove(struct device * dev) { - struct list_head *lh, *lh_sf; struct sdebug_host_info *sdbg_host; - struct sdebug_dev_info *sdbg_devinfo; + struct sdebug_dev_info *sdbg_devinfo, *tmp; sdbg_host = to_sdebug_host(dev); if (!sdbg_host) { printk(KERN_ERR "%s: Unable to locate host info\n", - __FUNCTION__); + __func__); return -ENODEV; } scsi_remove_host(sdbg_host->shost); - list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) { - sdbg_devinfo = list_entry(lh, struct sdebug_dev_info, - dev_list); + list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, + dev_list) { list_del(&sdbg_devinfo->dev_list); kfree(sdbg_devinfo); } @@ -3098,20 +3037,15 @@ static int sdebug_driver_remove(struct device * dev) return 0; } -static void sdebug_max_tgts_luns(void) +static int pseudo_lld_bus_match(struct device *dev, + struct device_driver *dev_driver) { - struct sdebug_host_info * sdbg_host; - struct Scsi_Host *hpnt; - - spin_lock(&sdebug_host_list_lock); - list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { - hpnt = sdbg_host->shost; - if ((hpnt->this_id >= 0) && - (scsi_debug_num_tgts > hpnt->this_id)) - hpnt->max_id = scsi_debug_num_tgts + 1; - else - hpnt->max_id = scsi_debug_num_tgts; - hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */ - } - spin_unlock(&sdebug_host_list_lock); + return 1; } + +static struct bus_type pseudo_lld_bus = { + .name = "pseudo", + .match = pseudo_lld_bus_match, + .probe = sdebug_driver_probe, + .remove = sdebug_driver_remove, +};