⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsi_debug.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
字号:
/* $Id: scsi_debug.c,v 1.1 1992/07/24 06:27:38 root Exp root $ *  linux/kernel/scsi_debug.c * *  Copyright (C) 1992  Eric Youngdale *  Simulate a host adapter with 2 disks attached.  Do a lot of checking *  to make sure that we are not getting blocks mixed up, and panic if *  anything out of the ordinary is seen. */#include <linux/kernel.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/head.h>#include <linux/types.h>#include <linux/string.h>#include <linux/genhd.h>#include <linux/fs.h>#include <asm/system.h>#include <asm/io.h>#include "../block/blk.h"#include "scsi.h"#include "hosts.h"/* Number of real scsi disks that will be detected ahead of time */static int NR_REAL=-1;#define MAJOR_NR SCSI_DISK_MAJOR#define START_PARTITION 4#define SCSI_DEBUG_TIMER 20/* Number of jiffies to wait before completing a command */#define DISK_SPEED     10#define CAPACITY (0x80000)static int starts[] = {4, 1000, 50000, CAPACITY, 0};static int npart = 0;#include "scsi_debug.h"#ifdef DEBUG#define DEB(x) x#else#define DEB(x)#endif#define VERIFY1_DEBUG(RW)			       			\      if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");};			\      start = 0;							\      if ((SCpnt->request.dev & 0xf) != 0) start = starts[(SCpnt->request.dev & 0xf) - 1];		\      if (bh){							\	if (bh->b_size != 1024) panic ("Wrong bh size");	\	if ((bh->b_blocknr << 1) + start != block)	       	\	  {  printk("Wrong bh block# %d %d ",bh->b_blocknr, block);  \	  panic ("Wrong bh block#");};  \	if (bh->b_dev != SCpnt->request.dev) panic ("Bad bh target");\      };#if 0/* This had been in the VERIFY_DEBUG macro, but it fails if there is already   a disk on the system */      if ((SCpnt->request.dev & 0xfff0) != ((target + NR_REAL) << 4) +(MAJOR_NR << 8)){	\	printk("Dev #s %x %x ",SCpnt->request.dev, target);			\	panic ("Bad target");};						\#endif#define VERIFY_DEBUG(RW)			       			\      if (bufflen != 1024 && (!SCpnt->use_sg)) {printk("%x %d\n ",bufflen, SCpnt->use_sg); panic("Bad bufflen");};   	\      start = 0;							\      if ((SCpnt->request.dev & 0xf) > npart) panic ("Bad partition");	\      if ((SCpnt->request.dev & 0xf) != 0) start = starts[(SCpnt->request.dev & 0xf) - 1];		\      if (SCpnt->request.cmd != RW) panic ("Wrong  operation");		\      if (SCpnt->request.sector + start != block) panic("Wrong block.");	\      if (SCpnt->request.current_nr_sectors != 2 && (!SCpnt->use_sg)) panic ("Wrong # blocks");	\      if (SCpnt->request.bh){							\	if (SCpnt->request.bh->b_size != 1024) panic ("Wrong bh size");	\	if ((SCpnt->request.bh->b_blocknr << 1) + start != block)	       	\	  {  printk("Wrong bh block# %d %d ",SCpnt->request.bh->b_blocknr, block);  \	  panic ("Wrong bh block#");};  \	if (SCpnt->request.bh->b_dev != SCpnt->request.dev) panic ("Bad bh target");\      };static volatile void (*do_done[SCSI_DEBUG_MAILBOXES])(Scsi_Cmnd *) = {NULL, };static int scsi_debug_host = 0;extern void scsi_debug_interrupt();volatile Scsi_Cmnd * SCint[SCSI_DEBUG_MAILBOXES] = {NULL,};static volatile unsigned int timeout[SCSI_DEBUG_MAILBOXES] ={0,};static char sense_buffer[128] = {0,};static void scsi_dump(Scsi_Cmnd * SCpnt, int flag){  int i;#if 0  unsigned char * pnt;#endif  unsigned int * lpnt;  struct scatterlist * sgpnt = NULL;  printk("use_sg: %d",SCpnt->use_sg);  if (SCpnt->use_sg){    sgpnt = (struct scatterlist *) SCpnt->buffer;    for(i=0; i<SCpnt->use_sg; i++) {      lpnt = (int *) sgpnt[i].alt_address;      printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);      if (lpnt) printk(" (Alt %x) ",lpnt[15]);    };  } else {    printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,	   SCpnt->bufflen);    lpnt = (int *) SCpnt->request.buffer;    if (lpnt) printk(" (Alt %x) ",lpnt[15]);  };  lpnt = (unsigned int *) SCpnt;  for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {    if ((i & 7) == 0) printk("\n");    printk("%x ",*lpnt++);  };  printk("\n");  if (flag == 0) return;  lpnt = (unsigned int *) sgpnt[0].alt_address;  for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {    if ((i & 7) == 0) printk("\n");    printk("%x ",*lpnt++);  };#if 0  printk("\n");  lpnt = (unsigned int *) sgpnt[0].address;  for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {    if ((i & 7) == 0) printk("\n");    printk("%x ",*lpnt++);  };  printk("\n");#endif  printk("DMA free %d sectors.\n", dma_free_sectors);}int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)){    unchar *cmd = (unchar *) SCpnt->cmnd;    struct partition * p;    int block, start;    struct buffer_head * bh = NULL;    unsigned char * buff;    int nbytes, sgcount;    int scsi_debug_errsts;    struct scatterlist * sgpnt;    int target = SCpnt->target;    int bufflen = SCpnt->request_bufflen;    int i;    sgcount = 0;    sgpnt = NULL;    DEB(if (target > 1) { SCpnt->result = DID_TIME_OUT << 16;done(SCpnt);return 0;});        buff = (unsigned char *) SCpnt->request_buffer;    if(target>=2 || SCpnt->lun != 0) {      SCpnt->result =  DID_NO_CONNECT << 16;      done(SCpnt);      return 0;    };        switch(*cmd){    case REQUEST_SENSE:      printk("Request sense...\n");#ifndef DEBUG      { int i;	printk("scsi_debug: Requesting sense buffer (%x %x %x %d):", SCpnt, buff, done, bufflen);	for(i=0;i<12;i++) printk("%d ",sense_buffer[i]);	printk("\n");      };#endif      memset(buff, 0, bufflen);      memcpy(buff, sense_buffer, bufflen);      memset(sense_buffer, 0, sizeof(sense_buffer));      SCpnt->result = 0;      done(SCpnt);       return 0;    case ALLOW_MEDIUM_REMOVAL:      if(cmd[4]) printk("Medium removal inhibited...");      else printk("Medium removal enabled...");      scsi_debug_errsts = 0;      break;    case INQUIRY:      printk("Inquiry...(%x %d)\n", buff, bufflen);      memset(buff, 0, bufflen);      buff[0] = TYPE_DISK;      buff[1] = 0x80;  /* Removable disk */      buff[2] = 1;      memcpy(&buff[8],"Foo Inc",7);      memcpy(&buff[16],"XYZZY",5);      memcpy(&buff[32],"1",1);      scsi_debug_errsts = 0;      break;    case TEST_UNIT_READY:      printk("Test unit ready.\n");      if (buff)	memset(buff, 0, bufflen);      scsi_debug_errsts = 0;      break;    case READ_CAPACITY:      printk("Read Capacity\n");      if(NR_REAL < 0) NR_REAL = (SCpnt->request.dev >> 4) & 0x0f;      memset(buff, 0, bufflen);      buff[0] = (CAPACITY >> 24);      buff[1] = (CAPACITY >> 16) & 0xff;      buff[2] = (CAPACITY >> 8) & 0xff;      buff[3] = CAPACITY & 0xff;      buff[6] = 2; /* 512 byte sectors */      scsi_debug_errsts = 0;      break;    case READ_10:    case READ_6:#ifdef DEBUG      printk("Read...");#endif      if ((*cmd) == READ_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(READ);      printk("(r%d)",SCpnt->request.nr_sectors);      nbytes = bufflen;      if(SCpnt->use_sg){	sgcount = 0;	sgpnt = (struct scatterlist *) buff;	buff = sgpnt[sgcount].address;	bufflen = sgpnt[sgcount].length;	bh = SCpnt->request.bh;      };      scsi_debug_errsts = 0;      do{	VERIFY1_DEBUG(READ);	memset(buff, 0, bufflen);/* If this is block 0, then we want to read the partition table for this   device.  Let's make one up */	if(block == 0 && target == 0) {	  *((unsigned short *) (buff+510)) = 0xAA55;	  p = (struct partition* ) (buff + 0x1be);	  npart = 0;	  while(starts[npart+1]){	    p->start_sect = starts[npart];	    p->nr_sects = starts[npart+1] - starts [npart];	    p->sys_ind = 0x81;  /* Linux partition */	    p++;	    npart++;	  };	  scsi_debug_errsts = 0;	  break;	};#ifdef DEBUG	if (SCpnt->use_sg) printk("Block %x (%d %d)\n",block, SCpnt->request.nr_sectors,	       SCpnt->request.current_nr_sectors);#endif	/* 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 */	memset(buff, 0, bufflen);	memcpy(buff, &target, sizeof(target));	memcpy(buff+sizeof(target), cmd, 24);	memcpy(buff+60, &block, sizeof(block));	memcpy(buff+64, SCpnt, sizeof(Scsi_Cmnd));	nbytes -= bufflen;	if(SCpnt->use_sg){	  memcpy(buff+128, bh, sizeof(struct buffer_head));	  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);      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;     default:      printk("Unknown command %d\n",*cmd);      SCpnt->result =  DID_NO_CONNECT << 16;      done(SCpnt);      return 0;    };    cli();    for(i=0;i<SCSI_DEBUG_MAILBOXES; i++){      if (SCint[i] == 0) break;    };    if (i >= SCSI_DEBUG_MAILBOXES || SCint[i] != 0)       panic("Unable to find empty SCSI_DEBUG command slot.\n");    SCint[i] = SCpnt;    if (done) {	DEB(printk("scsi_debug_queuecommand: now waiting for interrupt "););	if (do_done[i])	  printk("scsi_debug_queuecommand: Two concurrent queuecommand?\n");	else	  do_done[i] = done;    }    else      printk("scsi_debug_queuecommand: done cant be NULL\n");    timeout[i] = jiffies+DISK_SPEED;/* If no timers active, then set this one */    if ((timer_active & (1 << SCSI_DEBUG_TIMER)) == 0) {      timer_table[SCSI_DEBUG_TIMER].expires = timeout[i];      timer_active |= 1 << SCSI_DEBUG_TIMER;    };    SCpnt->result = scsi_debug_errsts;    sti();#if 0    printk("Sending command (%d %x %d %d)...", i, done, timeout[i],jiffies);#endif    return 0;}volatile static int internal_done_flag = 0;volatile static int internal_done_errcode = 0;static void internal_done(Scsi_Cmnd * SCpnt){    internal_done_errcode = SCpnt->result;    ++internal_done_flag;}int scsi_debug_command(Scsi_Cmnd * SCpnt){    DEB(printk("scsi_debug_command: ..calling scsi_debug_queuecommand\n"));    scsi_debug_queuecommand(SCpnt, internal_done);    while (!internal_done_flag);    internal_done_flag = 0;    return internal_done_errcode;}/* 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(void){    Scsi_Cmnd * SCtmp;    int i, pending;    void (*my_done)(Scsi_Cmnd *);    int to;    timer_table[SCSI_DEBUG_TIMER].expires = 0;    timer_active &= ~(1 << SCSI_DEBUG_TIMER);  repeat:    cli();    for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {      if (SCint[i] == 0) continue;      if (timeout[i] == 0) continue;      if (timeout[i] <= jiffies) break;    };    if(i == SCSI_DEBUG_MAILBOXES){      pending = INT_MAX;      for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {	if (SCint[i] == 0) continue;	if (timeout[i] == 0) continue;	if (timeout[i] <= jiffies) {sti(); goto repeat;};	if (timeout[i] > jiffies) {	  if (pending > timeout[i]) pending = timeout[i];	  continue;	};      };      if (pending && pending != INT_MAX) {	timer_table[SCSI_DEBUG_TIMER].expires = 	  (pending <= jiffies ? jiffies+1 : pending);	timer_active |= 1 << SCSI_DEBUG_TIMER;      };      sti();      return;    };    if(i < SCSI_DEBUG_MAILBOXES){      timeout[i] = 0;      my_done = do_done[i];      do_done[i] = NULL;      to = timeout[i];      timeout[i] = 0;      SCtmp = (Scsi_Cmnd *) SCint[i];      SCint[i] = NULL;      sti();      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    };    goto repeat;}int scsi_debug_detect(int hostnum){    scsi_debug_host = hostnum;    timer_table[SCSI_DEBUG_TIMER].fn = scsi_debug_intr_handle;    timer_table[SCSI_DEBUG_TIMER].expires = 0;    return 1;}int scsi_debug_abort(Scsi_Cmnd * SCpnt,int i){    int j;    void (*my_done)(Scsi_Cmnd *);    DEB(printk("scsi_debug_abort\n"));    SCpnt->result = i << 16;    for(j=0;j<SCSI_DEBUG_MAILBOXES; j++) {      if(SCpnt == SCint[j]) {	my_done = do_done[j];	my_done(SCpnt);	cli();	timeout[j] = 0;	SCint[j] = NULL;	do_done[j] = NULL;	sti();      };    };    return 0;}int scsi_debug_biosparam(int size, int* info){  info[0] = 32;  info[1] = 64;  info[2] = (size + 2047) >> 11;  if (info[2] >= 1024) info[2] = 1024;  return 0;}int scsi_debug_reset(Scsi_Cmnd * SCpnt){    int i;    void (*my_done)(Scsi_Cmnd *);    DEB(printk("scsi_debug_reset called\n"));    for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {      if (SCint[i] == NULL) continue;      SCint[i]->result = DID_ABORT << 16;      my_done = do_done[i];      my_done(SCint[i]);      cli();      SCint[i] = NULL;      do_done[i] = NULL;      timeout[i] = 0;      sti();    };    return 0;}char *scsi_debug_info(void){    static char buffer[] = " ";			/* looks nicer without anything here */    return buffer;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -