scsi_debug.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,869 行 · 第 1/4 页
C
1,869 行
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); sdp->hostdata = devip; if (sdp->host->cmd_per_lun) scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING, sdp->host->cmd_per_lun); 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; }}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 **) 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; } } if (NULL == open_devip) { /* try and make a new one */ open_devip = kmalloc(sizeof(*open_devip),GFP_KERNEL); if (NULL == open_devip) { printk(KERN_ERR "%s: out of memory at line %d\n", __FUNCTION__, __LINE__); return NULL; } memset(open_devip, 0, sizeof(*open_devip)); 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); open_devip->sense_buff[0] = 0x70; return open_devip; } return NULL;}static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, int asc, int asq, int inbandLen){ unsigned char * sbuff; sbuff = devip->sense_buff; memset(sbuff, 0, SDEBUG_SENSE_LEN); if (inbandLen > SDEBUG_SENSE_LEN) inbandLen = SDEBUG_SENSE_LEN; sbuff[0] = 0x70; sbuff[2] = key; sbuff[7] = (inbandLen > 7) ? (inbandLen - 8) : 0; sbuff[12] = asc; sbuff[13] = asq;}static int scsi_debug_abort(struct scsi_cmnd * SCpnt){ if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: abort\n"); ++num_aborts; stop_queued_cmnd(SCpnt); return SUCCESS;}static int scsi_debug_biosparam(struct scsi_device *sdev, struct block_device * bdev, sector_t capacity, int *info){ int res; unsigned char *buf; if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: biosparam\n"); buf = scsi_bios_ptable(bdev); if (buf) { res = scsi_partsize(buf, capacity, &info[2], &info[0], &info[1]); kfree(buf); if (! res) return res; } info[0] = sdebug_heads; info[1] = sdebug_sectors_per; info[2] = sdebug_cylinders_per; return 0;}static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt){ struct sdebug_dev_info * devip; if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: device_reset\n"); ++num_dev_resets; if (SCpnt) { devip = devInfoReg(SCpnt->device); if (devip) devip->reset = 1; } return SUCCESS;}static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt){ struct sdebug_host_info *sdbg_host; struct sdebug_dev_info * dev_info; struct scsi_device * sdp; struct Scsi_Host * hp; if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 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; if (sdbg_host) { list_for_each_entry(dev_info, &sdbg_host->dev_info_list, dev_list) dev_info->reset = 1; } } return SUCCESS;}static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt){ struct sdebug_host_info * sdbg_host; struct sdebug_dev_info * dev_info; if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: host_reset\n"); ++num_host_resets; spin_lock(&sdebug_host_list_lock); list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { list_for_each_entry(dev_info, &sdbg_host->dev_info_list, dev_list) dev_info->reset = 1; } spin_unlock(&sdebug_host_list_lock); stop_all_queued(); 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){ 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]; init_timer(&sqcp->cmnd_timer); sqcp->in_use = 0; sqcp->a_cmnd = NULL; } spin_unlock_irqrestore(&queued_arr_lock, iflags);}static void __init sdebug_build_parts(unsigned char * ramp){ struct partition * pp; int starts[SDEBUG_MAX_PARTS + 2]; int sectors_per_part, num_sectors, k; int heads_by_sects, start_sec, end_sec; /* assume partition table already zeroed */ if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576)) return; if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) { scsi_debug_num_parts = SDEBUG_MAX_PARTS; printk(KERN_WARNING "scsi_debug:build_parts: reducing " "partitions to %d\n", SDEBUG_MAX_PARTS); } num_sectors = (int)(sdebug_store_size / SECT_SIZE); sectors_per_part = (num_sectors - sdebug_sectors_per) / scsi_debug_num_parts; heads_by_sects = sdebug_heads * sdebug_sectors_per; starts[0] = sdebug_sectors_per; for (k = 1; k < scsi_debug_num_parts; ++k) starts[k] = ((k * sectors_per_part) / heads_by_sects) * heads_by_sects; starts[scsi_debug_num_parts] = num_sectors; starts[scsi_debug_num_parts + 1] = 0; ramp[510] = 0x55; /* magic partition markings */ ramp[511] = 0xAA; pp = (struct partition *)(ramp + 0x1be); for (k = 0; starts[k + 1]; ++k, ++pp) { start_sec = starts[k]; end_sec = starts[k + 1] - 1; pp->boot_ind = 0; pp->cyl = start_sec / heads_by_sects; pp->head = (start_sec - (pp->cyl * heads_by_sects)) / sdebug_sectors_per; pp->sector = (start_sec % sdebug_sectors_per) + 1; pp->end_cyl = end_sec / heads_by_sects; pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) / sdebug_sectors_per; pp->end_sector = (end_sec % sdebug_sectors_per) + 1; pp->start_sect = start_sec; pp->nr_sects = end_sec - start_sec + 1; pp->sys_ind = 0x83; /* plain Linux partition */ }}static int schedule_resp(struct scsi_cmnd * cmnd, struct sdebug_dev_info * devip, done_funct_t done, int scsi_result, int delta_jiff){ int k, num; if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) { printk(KERN_INFO "scsi_debug: cmd "); for (k = 0, num = cmnd->cmd_len; k < num; ++k) printk("%02x ", (int)cmnd->cmnd[k]); printk("\n"); if (scsi_result) { struct scsi_device * sdp = cmnd->device; printk(KERN_INFO "scsi_debug: ... <%u %u %u %u> " "non-zero result=0x%x\n", sdp->host->host_no, sdp->channel, sdp->id, sdp->lun, scsi_result); } } if (cmnd && devip) { /* simulate autosense by this driver */ if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff)) memcpy(cmnd->sense_buffer, devip->sense_buff, (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ? SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE); } if (delta_jiff <= 0) { if (cmnd) cmnd->result = scsi_result; if (done) done(cmnd); return 0; } else { unsigned long iflags; int k; struct sdebug_queued_cmd * sqcp = NULL; spin_lock_irqsave(&queued_arr_lock, iflags); for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { sqcp = &queued_arr[k]; if (! sqcp->in_use) break; } if (k >= SCSI_DEBUG_CANQUEUE) { spin_unlock_irqrestore(&queued_arr_lock, iflags); printk(KERN_WARNING "scsi_debug: can_queue exceeded\n"); return 1; /* report busy to mid level */ } sqcp->in_use = 1; sqcp->a_cmnd = cmnd; sqcp->scsi_result = scsi_result; sqcp->done_funct = done; sqcp->cmnd_timer.function = timer_intr_handler; sqcp->cmnd_timer.data = k; sqcp->cmnd_timer.expires = jiffies + delta_jiff; add_timer(&sqcp->cmnd_timer); spin_unlock_irqrestore(&queued_arr_lock, iflags); if (cmnd) cmnd->result = 0; return 0; }}/* Set 'perm' (4th argument) to 0 to disable module_param's definition * of sysfs parameters (which module_param doesn't yet support). * Sysfs parameters defined explicitly below. */module_param_named(add_host, scsi_debug_add_host, int, 0); /* perm=0644 */module_param_named(delay, scsi_debug_delay, int, 0); /* perm=0644 */module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, 0);module_param_named(every_nth, scsi_debug_every_nth, int, 0);module_param_named(max_luns, scsi_debug_max_luns, int, 0);module_param_named(num_parts, scsi_debug_num_parts, int, 0);module_param_named(num_tgts, scsi_debug_num_tgts, int, 0);module_param_named(opts, scsi_debug_opts, int, 0); /* perm=0644 */module_param_named(ptype, scsi_debug_ptype, int, 0);module_param_named(scsi_level, scsi_debug_scsi_level, int, 0);MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");MODULE_DESCRIPTION("SCSI debug adapter driver");MODULE_LICENSE("GPL");MODULE_VERSION(SCSI_DEBUG_VERSION);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");MODULE_PARM_DESC(every_nth, "timeout every nth command(def=100)");MODULE_PARM_DESC(max_luns, "number of SCSI LUNs per target to simulate");MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");MODULE_PARM_DESC(num_tgts, "number of SCSI targets per host to simulate");MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->...");MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");MODULE_PARM_DESC(scsi_level, "SCSI level to simulate");static char sdebug_info[256];static const char * scsi_debug_info(struct Scsi_Host * shp){ sprintf(sdebug_info, "scsi_debug, version %s [%s], " "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_dev_size_mb, scsi_debug_opts); return sdebug_info;}/* scsi_debug_proc_info * Used if the driver currently has no own support for /proc/scsi */static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout){ int len, pos, begin; int orig_length; orig_length = length; if (inout == 1) { char arr[16]; int minLen = length > 15 ? 15 : length; if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; memcpy(arr, buffer, minLen); arr[minLen] = '\0'; if (1 != sscanf(arr, "%d", &pos)) return -EINVAL; scsi_debug_opts = pos; if (scsi_debug_every_nth > 0) scsi_debug_cmnd_count = 0; return length; } begin = 0; pos = len = sprintf(buffer, "scsi_debug adapter driver, version " "%s [%s]\n" "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, " "every_nth=%d(curr:%d)\n" "delay=%d, max_luns=%d, scsi_level=%d\n" "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n" "number of aborts=%d, device_reset=%d, bus_resets=%d, " "host_resets=%d\n", SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts, 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); if (pos < offset) { len = 0; begin = pos; } *start = buffer + (offset - begin); /* Start of wanted data */ len -= (offset - begin); if (len > length) len = length; return len;}static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf){ return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);}static ssize_t sdebug_delay_store(struct device_driver * ddp, const char * buf, size_t count){ int delay; char work[20]; if (1 == sscanf(buf, "%10s", work)) { if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) { scsi_debug_delay = delay; return count; } } return -EINVAL;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?