X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fscsi%2Fscsi_debug.c;h=f6600bfb5bde71ffc244260ec6aa1aec4cf59469;hb=b8a0b6ccf2ba2519ace65d782b41ee91bf3c3778;hp=161af1ded8880400855ee341ec4fbc225c95b2df;hpb=5cb2fc06107fe343a9488b32ddf3d9b4596b7090;p=linux-2.6 diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 161af1ded8..f6600bfb5b 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -46,6 +46,7 @@ #include #include #include +#include #include @@ -147,7 +148,6 @@ 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 */ @@ -218,8 +218,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 = { @@ -235,94 +233,77 @@ 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 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, - 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 void sdebug_max_tgts_luns(void) +{ + 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; + /* scsi_debug_max_luns; */ + hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; + } + spin_unlock(&sdebug_host_list_lock); +} + +static void mk_sense_buffer(struct sdebug_dev_info *devip, int key, + int asc, int asq) +{ + unsigned char *sbuff; + + sbuff = devip->sense_buff; + memset(sbuff, 0, SDEBUG_SENSE_LEN); + + 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) { - 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); + *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_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); + *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 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); + *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_6: case READ_6: - *lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); + *lba = (u32)cmd[3] | (u32)cmd[2] << 8 | + (u32)(cmd[1] & 0x1f) << 16; *num = (0 == cmd[4]) ? 256 : cmd[4]; break; default: @@ -330,235 +311,6 @@ static void get_data_transfer_info(unsigned char *cmd, } } -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: - 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 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; - 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: - if ((errsts = check_readiness(SCpnt, 0, devip))) - 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); - 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) { if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { @@ -1093,6 +845,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) @@ -1104,11 +864,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; @@ -1141,11 +897,7 @@ 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) @@ -1439,13 +1191,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; @@ -1742,25 +1490,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 * SECT_SIZE), + (num - rest) * SECT_SIZE); + if (!ret && rest) + ret = func(scmd, fake_storep, rest * SECT_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)) { @@ -1779,74 +1555,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 * SECT_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 * SECT_SIZE, ret); return 0; } @@ -1970,52 +1702,9 @@ 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) -{ - 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; -} -static int scsi_debug_slave_configure(struct scsi_device * sdp) -{ - 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", - sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); - if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) - sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; - devip = devInfoReg(sdp); - if (NULL == devip) - return 1; /* no resources, will be marked offline */ - sdp->hostdata = devip; - if (sdp->host->cmd_per_lun) - scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING, - sdp->host->cmd_per_lun); - blk_queue_max_segment_size(sdp->request_queue, 256 * 1024); - return 0; -} - -static void scsi_debug_slave_destroy(struct scsi_device * sdp) -{ - 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", - sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); - if (devip) { - /* make this slot avaliable for re-use */ - devip->used = 0; - sdp->hostdata = NULL; - } -} - -struct sdebug_dev_info *sdebug_device_create(struct sdebug_host_info *sdbg_host, - gfp_t flags) +static struct sdebug_dev_info * +sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags) { struct sdebug_dev_info *devip; @@ -2059,49 +1748,108 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) return NULL; } } - 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; + + 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) +{ + 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", + sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); + if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) + sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; + devip = devInfoReg(sdp); + if (NULL == devip) + return 1; /* no resources, will be marked offline */ + sdp->hostdata = devip; + if (sdp->host->cmd_per_lun) + scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING, + sdp->host->cmd_per_lun); + blk_queue_max_segment_size(sdp->request_queue, 256 * 1024); + return 0; +} + +static void scsi_debug_slave_destroy(struct scsi_device *sdp) +{ + 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", + sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); + if (devip) { + /* make this slot avaliable for re-use */ + devip->used = 0; + sdp->hostdata = NULL; + } +} + +/* 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; } - 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) @@ -2191,46 +1939,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) { @@ -2248,7 +1956,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]; @@ -2256,7 +1965,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; @@ -2354,7 +2063,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 @@ -2671,11 +2379,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; @@ -2775,22 +2481,29 @@ 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; 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 / SECT_SIZE; + sdebug_capacity = get_sdebug_capacity(); /* play around with geometry, don't waste too much on track 0 */ sdebug_heads = 8; @@ -2809,7 +2522,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"); @@ -2817,7 +2529,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) { @@ -2882,41 +2594,17 @@ static void __exit scsi_debug_exit(void) stop_all_queued(); for (; k; k--) - sdebug_remove_adapter(); - do_remove_driverfs_files(); - driver_unregister(&sdebug_driverfs_driver); - bus_unregister(&pseudo_lld_bus); - device_unregister(&pseudo_primary); - - vfree(fake_storep); -} - -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, -}; + sdebug_remove_adapter(); + do_remove_driverfs_files(); + driver_unregister(&sdebug_driverfs_driver); + bus_unregister(&pseudo_lld_bus); + device_unregister(&pseudo_primary); -static int pseudo_lld_bus_match(struct device *dev, - struct device_driver *dev_driver) -{ - return 1; + vfree(fake_storep); } -static struct bus_type pseudo_lld_bus = { - .name = "pseudo", - .match = pseudo_lld_bus_match, - .probe = sdebug_driver_probe, - .remove = sdebug_driver_remove, -}; +device_initcall(scsi_debug_init); +module_exit(scsi_debug_exit); static void sdebug_release_adapter(struct device * dev) { @@ -2931,8 +2619,7 @@ 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) { @@ -2972,9 +2659,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); } @@ -3002,6 +2688,239 @@ 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, @@ -3063,9 +2982,8 @@ 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); @@ -3077,9 +2995,8 @@ static int sdebug_driver_remove(struct device * dev) 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); } @@ -3088,20 +3005,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, +};