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

📄 scsi.c

📁 LINUX 1.0 内核c源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
 *	scsi.c Copyright (C) 1992 Drew Eckhardt 
 *	generic mid-level SCSI driver by
 *		Drew Eckhardt 
 *
 *	<drew@colorado.edu>
 *
 *	Bug correction thanks go to : 
 *		Rik Faith <faith@cs.unc.edu>
 *		Tommy Thorn <tthorn>
 *		Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
 * 
 *       Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to
 *       add scatter-gather, multiple outstanding request, and other
 *       enhancements.
 */

#include <asm/system.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>

#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
#include "constants.h"

/*
static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/scsi.c,v 1.5 1993/09/24 12:45:18 drew Exp drew $";
*/

/* Command groups 3 and 4 are reserved and should never be used.  */
const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, 12, 12, 10, 10 };

#define INTERNAL_ERROR (panic ("Internal error in file %s, line %d.\n", __FILE__, __LINE__))

static void scsi_done (Scsi_Cmnd *SCpnt);
static int update_timeout (Scsi_Cmnd *, int);
static void print_inquiry(unsigned char *data);
static void scsi_times_out (Scsi_Cmnd * SCpnt);

static int time_start;
static int time_elapsed;

#define MAX_SCSI_DEVICE_CODE 10
const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
{
 "Direct-Access    ",
 "Sequential-Access",
 "Printer          ",
 "Processor        ",
 "WORM             ",
 "CD-ROM           ",
 "Scanner          ",
 "Optical Device   ",
 "Medium Changer   ",
 "Communications   "
};


/*
	global variables : 
	NR_SCSI_DEVICES is the number of SCSI devices we have detected, 
	scsi_devices an array of these specifing the address for each 
	(host, id, LUN)
*/
	
int NR_SCSI_DEVICES=0;

Scsi_Device * scsi_devices = NULL;

static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};

/* We make this not static so that we can read the array with gdb. */
/* static */ Scsi_Cmnd * last_cmnd = NULL;

/*
 *	As the scsi do command functions are inteligent, and may need to 
 *	redo a command, we need to keep track of the last command 
 *	executed on each one.
 */

#define WAS_RESET 	0x01
#define WAS_TIMEDOUT 	0x02
#define WAS_SENSE	0x04
#define IS_RESETTING	0x08
#define ASKED_FOR_SENSE 0x10
/* #define NEEDS_JUMPSTART 0x20  defined in hosts.h */

/*
 *	This is the number  of clock ticks we should wait before we time out 
 *	and abort the command.  This is for  where the scsi.c module generates 
 *	the command, not where it originates from a higher level, in which
 *	case the timeout is specified there.
 *
 *	ABORT_TIMEOUT and RESET_TIMEOUT are the timeouts for RESET and ABORT
 *	respectively.
 */

#ifdef DEBUG
	#define SCSI_TIMEOUT 500
#else
	#define SCSI_TIMEOUT 100
#endif

#ifdef DEBUG
	#define SENSE_TIMEOUT SCSI_TIMEOUT
	#define ABORT_TIMEOUT SCSI_TIMEOUT
	#define RESET_TIMEOUT SCSI_TIMEOUT
#else
	#define SENSE_TIMEOUT 50
	#define RESET_TIMEOUT 50
	#define ABORT_TIMEOUT 50
	#define MIN_RESET_DELAY 100
#endif

/* The following devices are known not to tolerate a lun != 0 scan for
   one reason or another.  Some will respond to all luns, others will
   lock up. */

     struct blist{
       char * vendor;
       char * model;
       char * revision; /* Latest revision known to be bad.  Not used yet */
     };

static struct blist blacklist[] = 
{
   {"DENON","DRD-25X","V"},   /* A cdrom that locks up when probed at lun != 0 */
   {"IMS", "CDD521/10","2.06"},   /* Locks-up when LUN>0 polled. */
   {"MAXTOR","XT-3280","PR02"},   /* Locks-up when LUN>0 polled. */
   {"MAXTOR","XT-4380S","B3C"},   /* Locks-up when LUN>0 polled. */
   {"MAXTOR","MXT-1240S","I1.2"}, /* Locks up when LUN > 0 polled */
   {"MAXTOR","XT-4170S","B5A"},   /* Locks-up sometimes when LUN>0 polled. */
   {"MAXTOR","XT-8760S","B7B"},   /* guess what? */
   {"NEC","CD-ROM DRIVE:841","1.0"},  /* Locks-up when LUN>0 polled. */
   {"RODIME","RO3000S","2.33"},  /* Locks up if polled for lun != 0 */
   {"SEAGATE", "ST157N", "\004|j"}, /* causes failed REQUEST SENSE on lun 1 for aha152x
				     * controller, which causes SCSI code to reset bus.*/
   {"SEAGATE", "ST296","921"},   /* Responds to all lun */
   {"SONY","CD-ROM CDU-541","4.3d"},
   {"TANDBERG","TDC 3600","U07"},  /* Locks up if polled for lun != 0 */
   {"TEAC","CD-ROM","1.06"},	/* causes failed REQUEST SENSE on lun 1 for seagate
				 * controller, which causes SCSI code to reset bus.*/
   {"TEXEL","CD-ROM","1.06"},   /* causes failed REQUEST SENSE on lun 1 for seagate
				 * controller, which causes SCSI code to reset bus.*/
   {NULL, NULL, NULL}};	

static int blacklisted(unsigned char * response_data){
  int i = 0;
  unsigned char * pnt;
  for(i=0; 1; i++){
    if(blacklist[i].vendor == NULL) return 0;
    pnt = &response_data[8];
    while(*pnt && *pnt == ' ') pnt++;
    if(memcmp(blacklist[i].vendor, pnt,
	       strlen(blacklist[i].vendor))) continue;
    pnt = &response_data[16];
    while(*pnt && *pnt == ' ') pnt++;
    if(memcmp(blacklist[i].model, pnt,
	       strlen(blacklist[i].model))) continue;
    return 1;
  };	
};

/*
 *	As the actual SCSI command runs in the background, we must set up a 
 *	flag that tells scan_scsis() when the result it has is valid.  
 *	scan_scsis can set the_result to -1, and watch for it to become the 
 *	actual return code for that call.  the scan_scsis_done function() is 
 *	our user specified completion function that is passed on to the  
 *	scsi_do_cmd() function.
 */

static volatile int in_scan = 0;
static int the_result;
static void scan_scsis_done (Scsi_Cmnd * SCpnt)
	{
	
#ifdef DEBUG
	printk ("scan_scsis_done(%d, %06x)\n", SCpnt->host, SCpnt->result);
#endif	
	SCpnt->request.dev = 0xfffe;
	}
/*
 *	Detecting SCSI devices :	
 *	We scan all present host adapter's busses,  from ID 0 to ID 6.  
 *	We use the INQUIRY command, determine device type, and pass the ID / 
 *	lun address of all sequential devices to the tape driver, all random 
 *	devices to the disk driver.
 */

static void scan_scsis (void)
{
  int dev, lun, type;
  unsigned char scsi_cmd [12];
  unsigned char scsi_result [256];
  struct Scsi_Host * shpnt;
  Scsi_Cmnd  SCmd;
  
  ++in_scan;
  lun = 0;
  
  SCmd.next = NULL;
  SCmd.prev = NULL;
  for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
      {
	shpnt->host_queue = &SCmd;  /* We need this so that
					 commands can time out */
	for (dev = 0; dev < 8; ++dev)
	  if (shpnt->this_id != dev)
/*
 * We need the for so our continue, etc. work fine.
 */

#ifdef NO_MULTI_LUN
	    for (lun = 0; lun < 1; ++lun)
#else
	    for (lun = 0; lun < 8; ++lun)
#endif
	      {
		scsi_devices[NR_SCSI_DEVICES].host = shpnt;
		scsi_devices[NR_SCSI_DEVICES].id = dev;
		scsi_devices[NR_SCSI_DEVICES].lun = lun;
		scsi_devices[NR_SCSI_DEVICES].index = NR_SCSI_DEVICES;
		scsi_devices[NR_SCSI_DEVICES].device_wait = NULL;
/*
 * Assume that the device will have handshaking problems, and then 
 * fix this field later if it turns out it doesn't.
 */
		scsi_devices[NR_SCSI_DEVICES].borken = 1;
		
		scsi_cmd[0] = TEST_UNIT_READY;
		scsi_cmd[1] = lun << 5;
		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
		scsi_cmd[4] = 0;

		SCmd.host = shpnt;
		SCmd.target = dev;
		SCmd.lun = lun;

		SCmd.request.dev = 0xffff; /* Mark not busy */
		SCmd.use_sg  = 0;
		SCmd.old_use_sg  = 0;
		SCmd.transfersize = 0;
		SCmd.underflow = 0;
		SCmd.index = NR_SCSI_DEVICES;

		scsi_do_cmd (&SCmd,
			     (void *)  scsi_cmd, (void *) 
			     scsi_result, 256,  scan_scsis_done, 
			     SCSI_TIMEOUT + 400, 5);
		
		while (SCmd.request.dev != 0xfffe);
#if defined(DEBUG) || defined(DEBUG_INIT)
		printk("scsi: scan SCSIS id %d lun %d\n", dev, lun);
		printk("scsi: return code %08x\n", SCmd.result);
#endif


		if(SCmd.result) {
		  if ((driver_byte(SCmd.result)  & DRIVER_SENSE) &&
		      ((SCmd.sense_buffer[0] & 0x70) >> 4) == 7) {
		    if (SCmd.sense_buffer[2] &0xe0)
		      continue; /* No devices here... */
		    if(((SCmd.sense_buffer[2] & 0xf) != NOT_READY) &&
		       ((SCmd.sense_buffer[2] & 0xf) != UNIT_ATTENTION))
		      continue;
		  }
		  else
		    break;
		};

#if defined (DEBUG) || defined(DEBUG_INIT)
		printk("scsi: performing INQUIRY\n");
#endif

		/*
		 * Build an INQUIRY command block.  
		 */
		
		scsi_cmd[0] = INQUIRY;
		scsi_cmd[1] = (lun << 5) & 0xe0;
		scsi_cmd[2] = 0;
		scsi_cmd[3] = 0;
		scsi_cmd[4] = 255;
		scsi_cmd[5] = 0;
		
		SCmd.request.dev = 0xffff; /* Mark not busy */
		
		scsi_do_cmd (&SCmd,
			     (void *)  scsi_cmd, (void *) 
			     scsi_result, 256,  scan_scsis_done, 
			     SCSI_TIMEOUT, 3);
		
		while (SCmd.request.dev != 0xfffe);
		
		the_result = SCmd.result;
		
#if defined(DEBUG) || defined(DEBUG_INIT)
		if (!the_result)
			printk("scsi: INQUIRY successful\n");
		else
			printk("scsi: INQUIRY failed with code %08x\n");
#endif

		if(the_result) break; 

		/* skip other luns on this device */
		
		if (!the_result)
		  {
		    scsi_devices[NR_SCSI_DEVICES].
		      removable = (0x80 & 
				   scsi_result[1]) >> 7;
		    scsi_devices[NR_SCSI_DEVICES].lockable =
		      scsi_devices[NR_SCSI_DEVICES].removable;
		    scsi_devices[NR_SCSI_DEVICES].
		      changed = 0;
		    scsi_devices[NR_SCSI_DEVICES].
		      access_count = 0;
		    scsi_devices[NR_SCSI_DEVICES].
		      busy = 0;
/* 
 *	Currently, all sequential devices are assumed to be tapes,
 *	all random devices disk, with the appropriate read only 
 *	flags set for ROM / WORM treated as RO.
 */ 

		    switch (type = scsi_result[0])
		      {
		      case TYPE_TAPE :
		      case TYPE_DISK :
		      case TYPE_MOD :
			scsi_devices[NR_SCSI_DEVICES].writeable = 1;
			break;
		      case TYPE_WORM :
		      case TYPE_ROM :
			scsi_devices[NR_SCSI_DEVICES].writeable = 0;
			break;
			default :
#if 0
#ifdef DEBUG
			printk("scsi: unknown type %d\n", type);
			print_inquiry(scsi_result);
#endif
#endif
			  type = -1;
		      }

		    scsi_devices[NR_SCSI_DEVICES].random = 
		      (type == TYPE_TAPE) ? 0 : 1;
		    scsi_devices[NR_SCSI_DEVICES].type = type;

		    if (type != -1)
		      {
			print_inquiry(scsi_result);
			switch(type){
			case TYPE_TAPE:
			  printk("Detected scsi tape st%d at scsi%d, id %d, lun %d\n", MAX_ST,
				 shpnt->host_no , dev, lun); 
			  if(NR_ST != -1) ++MAX_ST;
			  break;
			case TYPE_ROM:
			  printk("Detected scsi CD-ROM sr%d at scsi%d, id %d, lun %d\n", MAX_SR,
				 shpnt->host_no , dev, lun); 
			  if(NR_SR != -1) ++MAX_SR;
			  break;
			case TYPE_DISK:
			case TYPE_MOD:
			  printk("Detected scsi disk sd%c at scsi%d, id %d, lun %d\n", 'a'+MAX_SD,
				 shpnt->host_no , dev, lun); 
			  if(NR_SD != -1) ++MAX_SD;
			  break;
			default:
			  break;
			};

			if(NR_SG != -1) ++MAX_SG;

			scsi_devices[NR_SCSI_DEVICES].scsi_level =
			  scsi_result[2] & 0x07;
			if (scsi_devices[NR_SCSI_DEVICES].scsi_level >= 2 ||
			    (scsi_devices[NR_SCSI_DEVICES].scsi_level == 1 &&
			     (scsi_result[3] & 0x0f) == 1))
			  scsi_devices[NR_SCSI_DEVICES].scsi_level++;
/* 
 * Set the tagged_queue flag for SCSI-II devices that purport to support
 * tagged queuing in the INQUIRY data.
 */

			scsi_devices[NR_SCSI_DEVICES].tagged_queue = 0;

			if ((scsi_devices[NR_SCSI_DEVICES].scsi_level >= SCSI_2) &&
			    (scsi_result[7] & 2)) {
			    scsi_devices[NR_SCSI_DEVICES].tagged_supported = 1;
			    scsi_devices[NR_SCSI_DEVICES].current_tag = 0;
			}

/*
 * Accomodate drivers that want to sleep when they should be in a polling
 * loop.
 */

			scsi_devices[NR_SCSI_DEVICES].disconnect = 0;

/*
 * Some revisions of the Texel CD ROM drives have handshaking
 * problems when used with the Seagate controllers.  Before we
 * know what type of device we're talking to, we assume it's 
 * borken and then change it here if it turns out that it isn't
 * a TEXEL drive.
 */

			if(strncmp("TEXEL", (char *) &scsi_result[8], 5) != 0 ||
			  strncmp("CD-ROM", (char *) &scsi_result[16], 6) != 0 
/* 
 * XXX 1.06 has problems, some one should figure out the others too so
 * ALL TEXEL drives don't suffer in performance, especially when I finish
 * integrating my seagate patches which do multiple I_T_L nexuses.
 */

#ifdef notyet
			   || (strncmp("1.06", (char *) &scsi_result[[, 4) != 0)
#endif
			   )
			   scsi_devices[NR_SCSI_DEVICES].borken = 0;


			/* These devices need this "key" to unlock the device

⌨️ 快捷键说明

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