📄 scsi_debug.c
字号:
} *errstsp = 0; do { int resid, k, off, len, rem, blk; unsigned char * bp; /* If this is block 0, then we want to read the partition * table for this device. Let's make one up */ if (scsi_debug_fake_blk0 && (block == 0) && (! made_block0)) { scsi_debug_mkblock0(buff, bufflen, SCpnt); *errstsp = 0; break; } bp = buff; blk = block; for (resid = bufflen; resid > 0; resid -= len) { k = blk / SECT_PER_ELEM; off = (blk % SECT_PER_ELEM) * SECT_SIZE; rem = STORE_ELEM_SIZE - off; len = (resid > rem) ? rem : resid;/* printk("sdr: blk=%d k=%d off=%d rem=%d resid" "=%d len=%d sgcount=%d\n", blk, k, off, rem, resid, len, sgcount); */ memcpy(bp, store_arr[k].p + off, len); bp += len; blk += len / SECT_SIZE; }#if 0 /* Simulate a disk change */ if (block == 0xfff0) { sense_buffer[0] = 0x70; sense_buffer[2] = UNIT_ATTENTION; starts[0] += 10; starts[1] += 10; starts[2] += 10; *errstsp = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); read_unlock_irqrestore(&sdebug_atomic_rw, iflags); return 1; } /* End phony disk change code */#endif nbytes -= bufflen; if (SCpnt->use_sg) { block += bufflen >> POW2_SECT_SIZE; sgcount++; if (nbytes) { buff = sgpnt[sgcount].address; bufflen = sgpnt[sgcount].length; } } else if (nbytes > 0) printk("sdebug_read: unexpected nbytes=%d\n", nbytes); } while (nbytes); read_unlock_irqrestore(&sdebug_atomic_rw, iflags); return 0;}static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num, int * errstsp, Sdebug_dev_info * devip){ unsigned char *buff = (unsigned char *) SCpnt->request_buffer; int nbytes, sgcount; struct scatterlist *sgpnt = NULL; int bufflen = SCpnt->request_bufflen; unsigned long iflags; if (upper_blk || (block + num > CAPACITY)) { *errstsp = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14); return 1; } write_lock_irqsave(&sdebug_atomic_rw, iflags); sgcount = 0;#ifdef SCSI_DUMP if (block != *((unsigned long *) (buff + 60))) { printk("%x %x :", block, *((unsigned long *) (buff + 60))); scsi_dump(SCpnt, 1); printk("Bad block written.\n"); }#endif nbytes = bufflen; if (SCpnt->use_sg) { sgcount = 0; sgpnt = (struct scatterlist *) buff; buff = sgpnt[sgcount].address; bufflen = sgpnt[sgcount].length; } *errstsp = 0; do { int resid, k, off, len, rem, blk; unsigned char * bp; bp = buff; blk = block; for (resid = bufflen; resid > 0; resid -= len) { k = blk / SECT_PER_ELEM; off = (blk % SECT_PER_ELEM) * SECT_SIZE; rem = STORE_ELEM_SIZE - off; len = (resid > rem) ? rem : resid; memcpy(store_arr[k].p + off, bp, len); bp += len; blk += len / SECT_SIZE; } nbytes -= bufflen; if (SCpnt->use_sg) { block += bufflen >> POW2_SECT_SIZE; sgcount++; if (nbytes) { buff = sgpnt[sgcount].address; bufflen = sgpnt[sgcount].length; } } else if (nbytes > 0) printk("sdebug_write: unexpected nbytes=%d\n", nbytes); } while (nbytes); write_unlock_irqrestore(&sdebug_atomic_rw, iflags); return 0;}static void scsi_debug_send_self_command(struct Scsi_Host * shpnt){ static unsigned char cmd[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0}; Scsi_Request * scp; Scsi_Device * sdev; printk("Allocating host dev\n"); sdev = scsi_get_host_dev(shpnt); if(sdev==NULL) { printk("Out of memory.\n"); return; } printk("Got %p. Allocating command block\n", sdev); scp = scsi_allocate_request(sdev); printk("Got %p\n", scp); if(scp==NULL) { printk("Out of memory.\n"); goto bail; } scp->sr_cmd_len = 6; scp->sr_use_sg = 0; printk("Sending command\n"); scsi_wait_req (scp, (void *) cmd, (void *) NULL, 0, 100, 3); printk("Releasing command\n"); scsi_release_request(scp);bail: printk("Freeing device\n"); scsi_free_host_dev(sdev);}/* A "high" level interrupt handler. This should be called once per jiffy * to simulate a regular scsi disk. We use a timer to do this. */static void scsi_debug_intr_handle(unsigned long indx){ Scsi_Cmnd *SCtmp; void (*my_done) (Scsi_Cmnd *);#if 0 del_timer(&timeout[indx]);#endif SCtmp = (Scsi_Cmnd *) SCint[indx]; my_done = do_done[indx]; do_done[indx] = NULL; timeout[indx].function = NULL; SCint[indx] = NULL; if (!my_done) { printk("scsi_debug_intr_handle: Unexpected interrupt\n"); return; }#if 0 printk("In intr_handle..."); printk("...done %d %x %d %d\n", i, my_done, to, jiffies); printk("In intr_handle: %d %x %x\n", i, SCtmp, my_done);#endif my_done(SCtmp);#if 0 printk("Called done.\n");#endif}static int initialized = 0;static int do_init(void){ int sz; starts[3] = CAPACITY; sz = sizeof(Sd_store_elem) * STORE_ELEMENTS; store_arr = kmalloc(sz, GFP_ATOMIC); if (NULL == store_arr) return 1; memset(store_arr, 0, sz); sz = sizeof(done_fct_t) * SCSI_DEBUG_MAILBOXES; do_done = kmalloc(sz, GFP_ATOMIC); if (NULL == do_done) { kfree(store_arr); return 1; } memset((void *)do_done, 0, sz); sz = sizeof(struct timer_list) * SCSI_DEBUG_MAILBOXES; timeout = kmalloc(sz, GFP_ATOMIC); if (NULL == timeout) { kfree((void *)do_done); kfree(store_arr); return 1; } memset(timeout, 0, sz); sz = sizeof(Scsi_Cmnd *) * SCSI_DEBUG_MAILBOXES; SCint = kmalloc(sz, GFP_ATOMIC); if (NULL == SCint) { kfree(timeout); kfree((void *)do_done); kfree(store_arr); return 1; } memset(SCint, 0, sz); return 0;}static void do_end(void){ kfree(SCint); kfree(timeout); kfree((void *)do_done); kfree(store_arr);}int scsi_debug_detect(Scsi_Host_Template * tpnt){ int k, num, sz; if (0 == initialized) { ++initialized; sz = sizeof(Sdebug_dev_info) * scsi_debug_num_devs; devInfop = kmalloc(sz, GFP_ATOMIC); if (NULL == devInfop) { printk("scsi_debug_detect: out of memory, 0.5\n"); return 0; } memset(devInfop, 0, sz); if (do_init()) { printk("scsi_debug_detect: out of memory, 0\n"); return 0; } for (k = 0; k < STORE_ELEMENTS; ++k) { store_arr[k].p = (unsigned char *) __get_free_pages(GFP_ATOMIC, STORE_ELEM_ORDER); if (0 == store_arr[k].p) goto detect_err; memset(store_arr[k].p, 0, STORE_ELEM_SIZE); } for (k = 0; k < NUM_SENSE_BUFFS; ++k) sense_buffers[k][0] = 0x70; for (k = 0; k < NR_HOSTS_PRESENT; k++) { tpnt->proc_name = "scsi_debug"; /* In the loop??? */ scsi_register(tpnt, 0); } return NR_HOSTS_PRESENT; } else { printk("scsi_debug_detect: called again\n"); return 0; }detect_err: num = k; for (k = 0; k < STORE_ELEMENTS; ++k) { if (0 != store_arr[k].p) { free_pages((unsigned long)store_arr[k].p, STORE_ELEM_ORDER); store_arr[k].p = NULL; } } printk("scsi_debug_detect: out of memory: %d out of %d bytes\n", (int)(num * STORE_ELEM_SIZE), (int)(scsi_debug_dev_size_mb * 1024 * 1024)); return 0;}static int num_releases = 0;int scsi_debug_release(struct Scsi_Host * hpnt){ int k; scsi_unregister(hpnt); if (++num_releases != NR_HOSTS_PRESENT) return 0; for (k = 0; k < STORE_ELEMENTS; ++k) { if (0 != store_arr[k].p) { free_pages((unsigned long)store_arr[k].p, STORE_ELEM_ORDER); store_arr[k].p = NULL; } } do_end(); kfree(devInfop); return 0;}static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp){ int k; unsigned short host_no, id; Sdebug_dev_info * devip; host_no = sdp->host->host_no; id = (unsigned short)sdp->id; for (k = 0; k < scsi_debug_num_devs; ++k) { devip = &devInfop[k]; if (devip->sdp && (host_no == devip->host_no) && (id == devip->id)) { devip->sdp = sdp; /* overwrite previous sdp */ return devip; } if (NULL == devip->sdp) { devip->sdp = sdp; devip->host_no = host_no; devip->id = id; devip->reset = 1; devip->sb_index = 0; return devip; } } return NULL;}static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, int asc, int asq, int inbandLen){ char * sbuff; if ((index < 0) || (index >= NUM_SENSE_BUFFS)) return; if (devip) devip->sb_index = index; sbuff = &sense_buffers[index][0]; memset(sbuff, 0, SENSE_BUFF_LEN); sbuff[0] = 0x70; sbuff[2] = key; sbuff[7] = (inbandLen > 7) ? (inbandLen - 8) : 0; sbuff[12] = asc; sbuff[13] = asq;}int scsi_debug_abort(Scsi_Cmnd * SCpnt){#if 1 ++num_aborts; return SUCCESS;#else int j; void (*my_done) (Scsi_Cmnd *); unsigned long iflags; SCpnt->result = SCpnt->abort_reason << 16; for (j = 0; j < SCSI_DEBUG_MAILBOXES; j++) { if (SCpnt == SCint[j]) { my_done = do_done[j]; my_done(SCpnt); spin_lock_irqsave(&mailbox_lock, iflags); timeout[j] = 0; SCint[j] = NULL; do_done[j] = NULL; spin_unlock_irqrestore(&mailbox_lock, iflags); } } return SCSI_ABORT_SNOOZE;#endif}int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info){ /* int size = disk->capacity; */ info[0] = N_HEAD; info[1] = N_SECTOR; info[2] = N_CYLINDER; if (info[2] >= 1024) info[2] = 1024; return 0;}#if 0int scsi_debug_reset(Scsi_Cmnd * SCpnt, unsigned int why){ int i; unsigned long iflags; void (*my_done) (Scsi_Cmnd *); printk("Bus unlocked by reset - %d\n", why); scsi_debug_lockup = 0; for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) { if (SCint[i] == NULL) continue; SCint[i]->result = DID_RESET << 16; my_done = do_done[i]; my_done(SCint[i]); spin_lock_irqsave(&mailbox_lock, iflags); SCint[i] = NULL; do_done[i] = NULL; timeout[i].function = NULL; spin_unlock_irqrestore(&mailbox_lock, iflags); } return SCSI_RESET_SUCCESS;}#endifint scsi_debug_device_reset(Scsi_Cmnd * SCpnt){ Scsi_Device * sdp; int k; ++num_dev_resets; if (SCpnt && ((sdp = SCpnt->device))) { for (k = 0; k < scsi_debug_num_devs; ++k) { if (sdp->hostdata == (devInfop + k)) break; } if (k < scsi_debug_num_devs) devInfop[k].reset = 1; } return SUCCESS;}int scsi_debug_bus_reset(Scsi_Cmnd * SCpnt){ Scsi_Device * sdp; struct Scsi_Host * hp; int k; ++num_bus_resets; if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) { for (k = 0; k < scsi_debug_num_devs; ++k) { if (hp == devInfop[k].sdp->host) devInfop[k].reset = 1; } } return SUCCESS;}int scsi_debug_host_reset(Scsi_Cmnd * SCpnt){ int k; ++num_host_resets; for (k = 0; k < scsi_debug_num_devs; ++k) devInfop[k].reset = 1; return SUCCESS;}#ifndef MODULEstatic int __init scsi_debug_num_devs_setup(char *str){ int tmp; if (get_option(&str, &tmp) == 1) { if (tmp > 0) scsi_debug_num_devs = tmp; return 1; } else { printk("scsi_debug_num_devs: usage scsi_debug_num_devs=<n> " "(<n> can be from 1 to around 2000)\n"); return 0; }}__setup("scsi_debug_num_devs=", scsi_debug_num_devs_setup);static int __init scsi_debug_dev_size_mb_setup(char *str){ int tmp; if (get_option(&str, &tmp) == 1) { if (tmp > 0) scsi_debug_dev_size_mb = tmp; return 1; } else { printk("scsi_debug_dev_size_mb: usage scsi_debug_dev_size_mb=<n>\n" " (<n> is number of MB ram shared by all devs\n"); return 0; }}__setup("scsi_debug_dev_size_mb=", scsi_debug_dev_size_mb_setup);#endifMODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");MODULE_DESCRIPTION("SCSI debug adapter driver");MODULE_PARM(scsi_debug_num_devs, "i");MODULE_PARM_DESC(scsi_debug_num_devs, "number of SCSI devices to simulate");MODULE_PARM(scsi_debug_dev_size_mb, "i");MODULE_PARM_DESC(scsi_debug_dev_size_mb, "size in MB of ram shared by devs");#ifdef MODULE_LICENSEMODULE_LICENSE("GPL");#endifstatic char sdebug_info[256];const char * scsi_debug_info(struct Scsi_Host * shp){ sprintf(sdebug_info, "scsi_debug, %s, num_devs=%d, " "dev_size_mb=%d\n", scsi_debug_version_str, scsi_debug_num_devs, scsi_debug_dev_size_mb); return sdebug_info;}/* scsi_debug_proc_info * Used if the driver currently has no own support for /proc/scsi */int scsi_debug_proc_info(char *buffer, char **start, off_t offset, int length, int inode, int inout){ int len, pos, begin; int orig_length; orig_length = length; if (inout == 1) { /* First check for the Signature */ if (length >= 10 && strncmp(buffer, "scsi_debug", 10) == 0) { buffer += 11; length -= 11; if (buffer[length - 1] == '\n') { buffer[length - 1] = '\0'; length--; } /* * OK, we are getting some kind of command. Figure out * what we are supposed to do here. Simulate bus lockups * to test our reset capability. */ if (length == 4 && strncmp(buffer, "test", length) == 0) { printk("Testing send self command %p\n", SHpnt); scsi_debug_send_self_command(SHpnt); return orig_length; } if (length == 6 && strncmp(buffer, "lockup", length) == 0) { scsi_debug_lockup = 1; return orig_length; } if (length == 6 && strncmp(buffer, "unlock", length) == 0) { scsi_debug_lockup = 0; return orig_length; } printk("Unknown command:%s (%d)\n", buffer, length); } else printk("Wrong Signature:%10s\n", (char *) buffer); return -EINVAL; } begin = 0; pos = len = sprintf(buffer, "scsi_debug adapter driver, %s\n" "num_devs=%d, shared (ram) size=%d MB, sector_size=%d bytes\n" "cylinders=%d, heads=%d, sectors=%d\n" "number of aborts=%d, device_reset=%d, bus_resets=%d, " "host_resets=%d\n", scsi_debug_version_str, scsi_debug_num_devs, scsi_debug_dev_size_mb, SECT_SIZE, N_CYLINDER, N_HEAD, N_SECTOR, num_aborts, num_dev_resets, num_bus_resets, num_host_resets);#if 0 "This driver is not a real scsi driver, but it plays one on TV.\n" "It is very handy for debugging specific problems because you\n" "can simulate a variety of error conditions\n");#endif 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);}/* Eventually this will go into an include file, but this will be later */static Scsi_Host_Template driver_template = SCSI_DEBUG_TEMPLATE;#include "scsi_module.c"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -