305 lines
6.8 KiB
C
305 lines
6.8 KiB
C
|
/*
|
||
|
* hosts.c Copyright (C) 1992 Drew Eckhardt
|
||
|
* mid to lowlevel SCSI driver interface by
|
||
|
* Drew Eckhardt
|
||
|
*
|
||
|
* <drew@colorado.edu>
|
||
|
*/
|
||
|
|
||
|
|
||
|
/*
|
||
|
* This file contains the medium level SCSI
|
||
|
* host interface initialization, as well as the scsi_hosts array of SCSI
|
||
|
* hosts currently present in the system.
|
||
|
*/
|
||
|
|
||
|
#include <linux/config.h>
|
||
|
#include "../block/blk.h"
|
||
|
#include <linux/kernel.h>
|
||
|
#include <linux/string.h>
|
||
|
#include "scsi.h"
|
||
|
|
||
|
#ifndef NULL
|
||
|
#define NULL 0L
|
||
|
#endif
|
||
|
|
||
|
#define HOSTS_C
|
||
|
|
||
|
#include "hosts.h"
|
||
|
|
||
|
#ifdef CONFIG_SCSI_AHA152X
|
||
|
#include "aha152x.h"
|
||
|
#endif
|
||
|
|
||
|
#ifdef CONFIG_SCSI_AHA1542
|
||
|
#include "aha1542.h"
|
||
|
#endif
|
||
|
|
||
|
#ifdef CONFIG_SCSI_AHA1740
|
||
|
#include "aha1740.h"
|
||
|
#endif
|
||
|
|
||
|
#ifdef CONFIG_SCSI_FUTURE_DOMAIN
|
||
|
#include "fdomain.h"
|
||
|
#endif
|
||
|
|
||
|
#ifdef CONFIG_SCSI_GENERIC_NCR5380
|
||
|
#include "g_NCR5380.h"
|
||
|
#endif
|
||
|
|
||
|
#ifdef CONFIG_SCSI_PAS16
|
||
|
#include "pas16.h"
|
||
|
#endif
|
||
|
|
||
|
#ifdef CONFIG_SCSI_SEAGATE
|
||
|
#include "seagate.h"
|
||
|
#endif
|
||
|
|
||
|
#ifdef CONFIG_SCSI_T128
|
||
|
#include "t128.h"
|
||
|
#endif
|
||
|
|
||
|
#ifdef CONFIG_SCSI_ULTRASTOR
|
||
|
#include "ultrastor.h"
|
||
|
#endif
|
||
|
|
||
|
#ifdef CONFIG_SCSI_7000FASST
|
||
|
#include "wd7000.h"
|
||
|
#endif
|
||
|
|
||
|
#ifdef CONFIG_SCSI_DEBUG
|
||
|
#include "scsi_debug.h"
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hosts.c,v 1.3 1993/09/24 12:21:00 drew Exp drew $";
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* The scsi host entries should be in the order you wish the
|
||
|
* cards to be detected. A driver may appear more than once IFF
|
||
|
* it can deal with being detected (and therefore initialized)
|
||
|
* with more than one simulatenous host number, can handle being
|
||
|
* rentrant, etc.
|
||
|
*
|
||
|
* They may appear in any order, as each SCSI host is told which host number it is
|
||
|
* during detection.
|
||
|
*/
|
||
|
|
||
|
/* This is a placeholder for controllers that are not configured into
|
||
|
the system - we do this to ensure that the controller numbering is
|
||
|
always consistent, no matter how the kernel is configured. */
|
||
|
|
||
|
#define NO_CONTROLLER {NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
|
||
|
NULL, NULL, 0, 0, 0, 0, 0, 0}
|
||
|
|
||
|
/*
|
||
|
* When figure is run, we don't want to link to any object code. Since
|
||
|
* the macro for each host will contain function pointers, we cannot
|
||
|
* use it and instead must use a "blank" that does no such
|
||
|
* idiocy.
|
||
|
*/
|
||
|
|
||
|
Scsi_Host_Template scsi_hosts[] =
|
||
|
{
|
||
|
#ifdef CONFIG_SCSI_AHA152X
|
||
|
AHA152X,
|
||
|
#endif
|
||
|
#ifdef CONFIG_SCSI_AHA1542
|
||
|
AHA1542,
|
||
|
#endif
|
||
|
#ifdef CONFIG_SCSI_AHA1740
|
||
|
AHA1740,
|
||
|
#endif
|
||
|
#ifdef CONFIG_SCSI_FUTURE_DOMAIN
|
||
|
FDOMAIN_16X0,
|
||
|
#endif
|
||
|
#ifdef CONFIG_SCSI_GENERIC_NCR5380
|
||
|
GENERIC_NCR5380,
|
||
|
#endif
|
||
|
#ifdef CONFIG_SCSI_PAS16
|
||
|
MV_PAS16,
|
||
|
#endif
|
||
|
#ifdef CONFIG_SCSI_SEAGATE
|
||
|
SEAGATE_ST0X,
|
||
|
#endif
|
||
|
#ifdef CONFIG_SCSI_T128
|
||
|
TRANTOR_T128,
|
||
|
#endif
|
||
|
#ifdef CONFIG_SCSI_ULTRASTOR
|
||
|
ULTRASTOR_14F,
|
||
|
#endif
|
||
|
#ifdef CONFIG_SCSI_7000FASST
|
||
|
WD7000,
|
||
|
#endif
|
||
|
#ifdef CONFIG_SCSI_DEBUG
|
||
|
SCSI_DEBUG,
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
#define MAX_SCSI_HOSTS (sizeof(scsi_hosts) / sizeof(Scsi_Host_Template))
|
||
|
|
||
|
/*
|
||
|
* Our semaphores and timeout counters, where size depends on MAX_SCSI_HOSTS here.
|
||
|
*/
|
||
|
|
||
|
struct Scsi_Host * scsi_hostlist = NULL;
|
||
|
|
||
|
static int scsi_init_memory_start = 0;
|
||
|
|
||
|
int max_scsi_hosts = 0;
|
||
|
static int next_host = 0;
|
||
|
|
||
|
void
|
||
|
scsi_unregister(struct Scsi_Host * sh, int j){
|
||
|
struct Scsi_Host * shpnt;
|
||
|
|
||
|
if(((unsigned int) sh) + sizeof(struct Scsi_Host) + j != scsi_init_memory_start)
|
||
|
panic("Unable to unregister scsi host");
|
||
|
if(scsi_hostlist == sh)
|
||
|
scsi_hostlist = NULL;
|
||
|
else {
|
||
|
shpnt = scsi_hostlist;
|
||
|
while(shpnt->next != sh) shpnt = shpnt->next;
|
||
|
shpnt->next = shpnt->next->next;
|
||
|
|
||
|
};
|
||
|
next_host--;
|
||
|
scsi_init_memory_start = (unsigned int) sh;
|
||
|
}
|
||
|
|
||
|
/* We call this when we come across a new host adapter. We only do this
|
||
|
once we are 100% sure that we want to use this host adapter - it is a
|
||
|
pain to reverse this, so we try and avoid it */
|
||
|
|
||
|
struct Scsi_Host * scsi_register(int i, int j){
|
||
|
struct Scsi_Host * retval, *shpnt;
|
||
|
retval = (struct Scsi_Host*) scsi_init_memory_start;
|
||
|
scsi_init_memory_start += sizeof(struct Scsi_Host) + j;
|
||
|
retval->host_busy = 0;
|
||
|
retval->host_no = next_host++;
|
||
|
retval->host_queue = NULL;
|
||
|
retval->host_wait = NULL;
|
||
|
retval->last_reset = 0;
|
||
|
retval->hostt = &scsi_hosts[i];
|
||
|
retval->next = NULL;
|
||
|
#ifdef DEBUG
|
||
|
printk("Register %x %x: %d %d\n", retval, retval->hostt, i, j);
|
||
|
#endif
|
||
|
|
||
|
/* The next three are the default values which can be overridden
|
||
|
if need be */
|
||
|
retval->this_id = scsi_hosts[i].this_id;
|
||
|
retval->sg_tablesize = scsi_hosts[i].sg_tablesize;
|
||
|
retval->unchecked_isa_dma = scsi_hosts[i].unchecked_isa_dma;
|
||
|
|
||
|
if(!scsi_hostlist)
|
||
|
scsi_hostlist = retval;
|
||
|
else
|
||
|
{
|
||
|
shpnt = scsi_hostlist;
|
||
|
while(shpnt->next) shpnt = shpnt->next;
|
||
|
shpnt->next = retval;
|
||
|
}
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
unsigned int
|
||
|
scsi_init(unsigned long memory_start,unsigned long memory_end)
|
||
|
{
|
||
|
static int called = 0;
|
||
|
int i, j, count, pcount;
|
||
|
|
||
|
count = 0;
|
||
|
|
||
|
if(called) return memory_start;
|
||
|
|
||
|
scsi_init_memory_start = memory_start;
|
||
|
called = 1;
|
||
|
for (i = 0; i < MAX_SCSI_HOSTS; ++i)
|
||
|
{
|
||
|
/*
|
||
|
* Initialize our semaphores. -1 is interpreted to mean
|
||
|
* "inactive" - where as 0 will indicate a time out condition.
|
||
|
*/
|
||
|
|
||
|
pcount = next_host;
|
||
|
if ((scsi_hosts[i].detect) &&
|
||
|
(scsi_hosts[i].present =
|
||
|
scsi_hosts[i].detect(i)))
|
||
|
{
|
||
|
/* The only time this should come up is when people use
|
||
|
some kind of patched driver of some kind or another. */
|
||
|
if(pcount == next_host) {
|
||
|
if(scsi_hosts[i].present > 1)
|
||
|
panic("Failure to register low-level scsi driver");
|
||
|
/* The low-level driver failed to register a driver. We
|
||
|
can do this now. */
|
||
|
scsi_register(i,0);
|
||
|
};
|
||
|
for(j = 0; j < scsi_hosts[i].present; j++)
|
||
|
printk ("scsi%d : %s\n",
|
||
|
count++, scsi_hosts[i].name);
|
||
|
}
|
||
|
}
|
||
|
printk ("scsi : %d hosts.\n", count);
|
||
|
|
||
|
max_scsi_hosts = count;
|
||
|
return scsi_init_memory_start;
|
||
|
}
|
||
|
|
||
|
#ifndef CONFIG_BLK_DEV_SD
|
||
|
unsigned long sd_init(unsigned long memory_start, unsigned long memory_end){
|
||
|
return memory_start;
|
||
|
};
|
||
|
unsigned long sd_init1(unsigned long memory_start, unsigned long memory_end){
|
||
|
return memory_start;
|
||
|
};
|
||
|
void sd_attach(Scsi_Device * SDp){
|
||
|
};
|
||
|
int NR_SD=-1;
|
||
|
int MAX_SD=0;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#ifndef CONFIG_BLK_DEV_SR
|
||
|
unsigned long sr_init(unsigned long memory_start, unsigned long memory_end){
|
||
|
return memory_start;
|
||
|
};
|
||
|
unsigned long sr_init1(unsigned long memory_start, unsigned long memory_end){
|
||
|
return memory_start;
|
||
|
};
|
||
|
void sr_attach(Scsi_Device * SDp){
|
||
|
};
|
||
|
int NR_SR=-1;
|
||
|
int MAX_SR=0;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#ifndef CONFIG_CHR_DEV_ST
|
||
|
unsigned long st_init(unsigned long memory_start, unsigned long memory_end){
|
||
|
return memory_start;
|
||
|
};
|
||
|
unsigned long st_init1(unsigned long memory_start, unsigned long memory_end){
|
||
|
return memory_start;
|
||
|
};
|
||
|
void st_attach(Scsi_Device * SDp){
|
||
|
};
|
||
|
int NR_ST=-1;
|
||
|
int MAX_ST=0;
|
||
|
#endif
|
||
|
|
||
|
#ifndef CONFIG_CHR_DEV_SG
|
||
|
unsigned long sg_init(unsigned long memory_start, unsigned long memory_end){
|
||
|
return memory_start;
|
||
|
};
|
||
|
unsigned long sg_init1(unsigned long memory_start, unsigned long memory_end){
|
||
|
return memory_start;
|
||
|
};
|
||
|
void sg_attach(Scsi_Device * SDp){
|
||
|
};
|
||
|
int NR_SG=-1;
|
||
|
int MAX_SG=0;
|
||
|
#endif
|