📄 scsi_debug.c
字号:
#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;#ifdef DEBUG { int i; printk("scsi_debug: Filling sense buffer:"); for (i = 0; i < 12; i++) printk("%d ", sense_buffer[i]); printk("\n"); };#endif scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); break; } /* End phony disk change code */#endif#ifdef CLEAR memcpy(buff, &target, sizeof(target)); memcpy(buff + sizeof(target), cmd, 24); memcpy(buff + 60, &block, sizeof(block)); memcpy(buff + 64, SCpnt, sizeof(Scsi_Cmnd));#endif nbytes -= bufflen; if (SCpnt->use_sg) {#ifdef CLEAR memcpy(buff + 128, bh, sizeof(struct buffer_head));#endif block += bufflen >> 9; bh = bh->b_reqnext; sgcount++; if (nbytes) { if (!bh) panic("Too few blocks for linked request."); buff = sgpnt[sgcount].address; bufflen = sgpnt[sgcount].length; }; } } while (nbytes); SCpnt->result = 0; (done) (SCpnt); return 0; if (SCpnt->use_sg && !scsi_debug_errsts) if (bh) scsi_dump(SCpnt, 0); break; case WRITE_10: case WRITE_6:#ifdef DEBUG printk("Write\n");#endif if ((*cmd) == WRITE_10) block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); else block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); VERIFY_DEBUG(WRITE); /* printk("(w%d)",SCpnt->request.nr_sectors); */ if (SCpnt->use_sg) { if ((bufflen >> 9) != SCpnt->request.nr_sectors) panic("Trying to write wrong number of blocks\n"); sgpnt = (struct scatterlist *) buff; buff = sgpnt[sgcount].address; };#if 0 if (block != *((unsigned long *) (buff + 60))) { printk("%x %x :", block, *((unsigned long *) (buff + 60))); scsi_dump(SCpnt, 1); panic("Bad block written.\n"); };#endif scsi_debug_errsts = 0; break; case MODE_SENSE: /* * Used to detect write protected status. */ scsi_debug_errsts = 0; memset(buff, 0, 6); break; default: SCSI_LOG_LLQUEUE(3, printk("Unknown command %d\n", *cmd)); SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; }; save_flags(flags); cli(); for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) { if (timeout[i].function == NULL) break; }; /* * If all of the slots are full, just return 1. The new error handling scheme * allows this, and the mid-level should queue things. */ if (i >= SCSI_DEBUG_MAILBOXES || timeout[i].function != 0) { SCSI_LOG_LLQUEUE(1, printk("Command rejected - host busy\n")); restore_flags(flags); return 1; } SCSI_LOG_LLQUEUE(1, printk("Command accepted - slot %d\n", i));#ifdef IMMEDIATE if (!scsi_debug_lockup) { SCpnt->result = scsi_debug_errsts; SCint[i] = SCpnt; do_done[i] = done; scsi_debug_intr_handle(i); /* No timer - do this one right away */ } restore_flags(flags);#else SCpnt->result = scsi_debug_errsts; timeout[i].function = scsi_debug_intr_handle; timeout[i].data = i; timeout[i].expires = jiffies + DISK_SPEED; SCint[i] = SCpnt; do_done[i] = done; restore_flags(flags); add_timer(&timeout[i]); if (!done) panic("scsi_debug_queuecommand: done can't be NULL\n");#if 0 printk("Sending command (%d %x %d %d)...", i, done, timeout[i].expires, jiffies);#endif#endif 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 *);#ifdef DEBUG int to;#endif#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; }#ifdef DEBUG 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);#ifdef DEBUG printk("Called done.\n");#endif}int scsi_debug_detect(Scsi_Host_Template * tpnt){ int i; for (i = 0; i < NR_HOSTS_PRESENT; i++) { tpnt->proc_name = "scsi_debug"; /* Huh? In the loop??? */ scsi_register(tpnt, 0); } return NR_HOSTS_PRESENT;}int scsi_debug_abort(Scsi_Cmnd * SCpnt){#if 0 int j; void (*my_done) (Scsi_Cmnd *); unsigned long flags;#endif DEB(printk("scsi_debug_abort\n"));#if 0 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); save_flags(flags); cli(); timeout[j] = 0; SCint[j] = NULL; do_done[j] = NULL; restore_flags(flags); }; };#endif return SCSI_ABORT_SNOOZE;}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;}int scsi_debug_reset(Scsi_Cmnd * SCpnt, unsigned int why){ int i; unsigned long flags; void (*my_done) (Scsi_Cmnd *); printk("Bus unlocked by reset - %d\n", why); scsi_debug_lockup = 0; DEB(printk("scsi_debug_reset called\n")); 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]); save_flags(flags); cli(); SCint[i] = NULL; do_done[i] = NULL; timeout[i].function = NULL; restore_flags(flags); } return SCSI_RESET_SUCCESS;}const char *scsi_debug_info(void){ static char buffer[] = " "; /* looks nicer without anything here */ return buffer;}/* 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, "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"); 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);}#ifdef CONFIG_USER_DEBUG/* * This is a hack for the user space emulator. It allows us to * "insert" arbitrary numbers of additional drivers. */void *scsi_debug_get_handle(void){ static Scsi_Host_Template driver_copy = SCSI_DEBUG; void *rtn; rtn = kmalloc(sizeof(driver_copy), GFP_ATOMIC); if(rtn==NULL) return NULL; memcpy(rtn, (void *) &driver_copy, sizeof(driver_copy)); return rtn;}#endif/* Eventually this will go into an include file, but this will be later */static Scsi_Host_Template driver_template = SCSI_DEBUG;#include "scsi_module.c"/* * Overrides for Emacs so that we almost follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only. This must remain at the end * of the file. * --------------------------------------------------------------------------- * Local variables: * c-indent-level: 4 * c-brace-imaginary-offset: 0 * c-brace-offset: -4 * c-argdecl-indent: 4 * c-label-offset: -4 * c-continued-statement-offset: 4 * c-continued-brace-offset: 0 * indent-tabs-mode: nil * tab-width: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -