?? scsi.c
字號:
/*
* 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 + -