Commit 8428b10d authored by James Bottomley's avatar James Bottomley

Merge mulgrave.(none):/home/jejb/BK/scsi-host-list-2.5

into mulgrave.(none):/home/jejb/BK/scsi-for-linus-2.5
parents 40ea4c83 209287fb
......@@ -3010,14 +3010,12 @@ int acornscsi_proc_info(char *buffer, char **start, off_t offset,
int length, int host_no, int inout)
{
int pos, begin = 0, devidx;
struct Scsi_Host *instance = scsi_hostlist;
struct Scsi_Host *instance;
Scsi_Device *scd;
AS_Host *host;
char *p = buffer;
for (instance = scsi_hostlist;
instance && instance->host_no != host_no;
instance = instance->next);
instance = scsi_host_hn_get(host_no);
if (inout == 1 || !instance)
return -EINVAL;
......
......@@ -384,15 +384,11 @@ int arxescsi_proc_info(char *buffer, char **start, off_t offset,
int length, int host_no, int inout)
{
int pos, begin;
struct Scsi_Host *host = scsi_hostlist;
struct Scsi_Host *host;
ARXEScsi_Info *info;
Scsi_Device *scd;
while (host) {
if (host->host_no == host_no)
break;
host = host->next;
}
host = scsi_host_hn_get(host_no);
if (!host)
return 0;
......
......@@ -498,15 +498,11 @@ int cumanascsi_2_proc_info (char *buffer, char **start, off_t offset,
int length, int host_no, int inout)
{
int pos, begin;
struct Scsi_Host *host = scsi_hostlist;
struct Scsi_Host *host;
CumanaScsi2_Info *info;
Scsi_Device *scd;
while (host) {
if (host->host_no == host_no)
break;
host = host->next;
}
host = scsi_host_hn_get(host_no);
if (!host)
return 0;
......
......@@ -499,15 +499,11 @@ int eesoxscsi_proc_info(char *buffer, char **start, off_t offset,
int length, int host_no, int inout)
{
int pos, begin;
struct Scsi_Host *host = scsi_hostlist;
struct Scsi_Host *host;
EESOXScsi_Info *info;
Scsi_Device *scd;
while (host) {
if (host->host_no == host_no)
break;
host = host->next;
}
host = scsi_host_hn_get(host_no);
if (!host)
return 0;
......
......@@ -404,15 +404,11 @@ int powertecscsi_proc_info(char *buffer, char **start, off_t offset,
int length, int host_no, int inout)
{
int pos, begin;
struct Scsi_Host *host = scsi_hostlist;
struct Scsi_Host *host;
PowerTecScsi_Info *info;
Scsi_Device *scd;
while (host) {
if (host->host_no == host_no)
break;
host = host->next;
}
host = scsi_host_hn_get(host_no);
if (!host)
return 0;
......
......@@ -1250,8 +1250,6 @@ cciss_scsi_user_command(int ctlr, int hostno, char *buffer, int length)
return length;
}
/* It's a pity that we need this, but, we do... */
extern struct Scsi_Host *scsi_hostlist; /* from ../scsi/hosts.c */
int
cciss_scsi_proc_info(char *buffer, /* data buffer */
......@@ -1268,24 +1266,9 @@ cciss_scsi_proc_info(char *buffer, /* data buffer */
ctlr_info_t *ci;
int cntl_num;
/* Lets see if we can find our Scsi_Host...
this might be kind of "bad", searching scis_hostlist this way
but how else can we find the scsi host? I think I've seen
this coded both ways, (circular list and null terminated list)
I coded it to work either way, since I wasn't sure. */
sh = scsi_hostlist;
found=0;
do {
if (sh == NULL) break;
if (sh->host_no == hostnum) {
found++;
break;
}
sh = sh->next;
} while (sh != scsi_hostlist && sh != NULL);
if (sh == NULL || found == 0) /* This really shouldn't ever happen. */
sh = scsi_host_hn_get(hostnum);
if (sh == NULL) /* This really shouldn't ever happen. */
return -EINVAL;
ci = (ctlr_info_t *) sh->hostdata[0];
......
......@@ -1723,13 +1723,11 @@ NCR_700_proc_directory_info(char *proc_buf, char **startp,
{
static char buf[4096]; /* 1 page should be sufficient */
int len = 0;
struct Scsi_Host *host = scsi_hostlist;
struct Scsi_Host *host;
struct NCR_700_Host_Parameters *hostdata;
Scsi_Device *SDp;
while(host != NULL && host->host_no != host_no)
host = host->next;
host = scsi_host_hn_get(host_no);
if(host == NULL)
return 0;
......
......@@ -63,7 +63,6 @@ int ahc_linux_abort(Scsi_Cmnd *);
* to do with card config are filled in after the card is detected.
*/
#define AIC7XXX { \
next: NULL, \
module: NULL, \
proc_dir: NULL, \
proc_info: ahc_linux_proc_info, \
......
......@@ -938,9 +938,7 @@ int cpqfcTS_proc_info (char *buffer, char **start, off_t offset, int length,
char buf[81];
// Search the Scsi host list for our controller
for (host=scsi_hostlist; host; host=host->next)
if (host->host_no == hostno)
break;
host = scsi_host_hn_get(hostno);
if (!host) return -ESRCH;
......
......@@ -213,9 +213,7 @@ int fcal_proc_info (char *buffer, char **start, off_t offset, int length, int ho
char *pos = buffer;
int i, j;
for (host=scsi_hostlist; host; host=host->next)
if (host->host_no == hostno)
break;
host = scsi_host_hn_get(hostno);
if (!host) return -ESRCH;
......
......@@ -15,12 +15,15 @@
* Updated to reflect the new initialization scheme for the higher
* level of scsi drivers (sd/sr/st)
* September 17, 2000 Torben Mathiasen <tmm@image.dk>
*
* Restructured scsi_host lists and associated functions.
* September 04, 2002 Mike Anderson (andmike@us.ibm.com)
*/
/*
* This file contains the medium level SCSI
* host interface initialization, as well as the scsi_hosts array of SCSI
* host interface initialization, as well as the scsi_hosts list of SCSI
* hosts currently present in the system.
*/
......@@ -31,232 +34,711 @@
#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/smp_lock.h>
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
#include <asm/dma.h>
#include "scsi.h"
#include "hosts.h"
/*
static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/hosts.c,v 1.20 1996/12/12 19:18:32 davem Exp $";
*/
LIST_HEAD(scsi_host_tmpl_list);
LIST_HEAD(scsi_host_hn_list);
/*
* 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 simultaneous host number, can handle being
* reentrant, etc.
LIST_HEAD(scsi_host_list);
spinlock_t scsi_host_list_lock = SPIN_LOCK_UNLOCKED;
struct Scsi_Device_Template * scsi_devicelist;
static int scsi_host_next_hn; /* host_no for next new host */
static int scsi_hosts_registered; /* cnt of registered scsi hosts */
/**
* scsi_tp_for_each_host - call function for each scsi host off a template
* @shost_tp: a pointer to a scsi host template
* @callback: a pointer to callback function
*
* They may appear in any order, as each SCSI host is told which host
* number it is during detection.
*/
* Return value:
* 0 on Success / 1 on Failure
**/
int scsi_tp_for_each_host(Scsi_Host_Template *shost_tp, int
(*callback)(struct Scsi_Host *shost))
{
struct list_head *lh, *lh_sf;
struct Scsi_Host *shost;
/*
* 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.
spin_lock(&scsi_host_list_lock);
list_for_each_safe(lh, lh_sf, &scsi_host_list) {
shost = list_entry(lh, struct Scsi_Host, sh_list);
if (shost->hostt == shost_tp) {
spin_unlock(&scsi_host_list_lock);
callback(shost);
spin_lock(&scsi_host_list_lock);
}
}
spin_unlock(&scsi_host_list_lock);
return 0;
}
/**
* scsi_host_generic_release - default release function for hosts
* @shost:
*
* Description:
* This is the default case for the release function. It should do
* the right thing for most correctly written host adapters.
**/
static void scsi_host_generic_release(struct Scsi_Host *shost)
{
if (shost->irq)
free_irq(shost->irq, NULL);
if (shost->dma_channel != 0xff)
free_dma(shost->dma_channel);
if (shost->io_port && shost->n_io_port)
release_region(shost->io_port, shost->n_io_port);
}
/**
* scsi_host_chk_and_release - check a scsi host for release and release
* @shost: a pointer to a scsi host to release
*
* Return value:
* 0 on Success / 1 on Failure
**/
int scsi_host_chk_and_release(struct Scsi_Host *shost)
{
int pcount;
Scsi_Device *sdev;
struct Scsi_Device_Template *sdev_tp;
Scsi_Cmnd *scmd;
/*
* Current policy is all shosts go away on unregister.
*/
if (shost->hostt->module && GET_USE_COUNT(shost->hostt->module))
return 1;
Scsi_Host_Template * scsi_hosts;
/*
* FIXME Do ref counting. We force all of the devices offline to
* help prevent race conditions where other hosts/processors could
* try and get in and queue a command.
*/
for (sdev = shost->host_queue; sdev; sdev = sdev->next)
sdev->online = FALSE;
for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
/*
* Loop over all of the commands associated with the
* device. If any of them are busy, then set the state
* back to inactive and bail.
*/
for (scmd = sdev->device_queue; scmd; scmd = scmd->next) {
if (scmd->request && scmd->request->rq_status !=
RQ_INACTIVE) {
printk(KERN_ERR "SCSI device not inactive"
"- rq_status=%d, target=%d, pid=%ld,"
"state=%d, owner=%d.\n",
scmd->request->rq_status,
scmd->target, scmd->pid,
scmd->state, scmd->owner);
for (sdev = shost->host_queue; sdev;
sdev = sdev->next) {
for (scmd = sdev->device_queue; scmd;
scmd = scmd->next)
if (scmd->request->rq_status ==
RQ_SCSI_DISCONNECTING)
scmd->request->rq_status = RQ_INACTIVE;
}
printk(KERN_ERR "Device busy???\n");
return 1;
}
/*
* No, this device is really free. Mark it as such, and
* continue on.
*/
scmd->state = SCSI_STATE_DISCONNECTING;
if (scmd->request)
scmd->request->rq_status =
RQ_SCSI_DISCONNECTING; /* Mark as
busy */
}
}
/*
* Our semaphores and timeout counters, where size depends on
* MAX_SCSI_HOSTS here.
/*
* Next we detach the high level drivers from the Scsi_Device
* structures
*/
for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
for (sdev_tp = scsi_devicelist; sdev_tp;
sdev_tp = sdev_tp->next)
if (sdev_tp->detach)
(*sdev_tp->detach) (sdev);
/* If something still attached, punt */
if (sdev->attached) {
printk(KERN_ERR "Attached usage count = %d\n",
sdev->attached);
return 1;
}
Scsi_Host_Name * scsi_host_no_list;
struct Scsi_Host * scsi_hostlist;
struct Scsi_Device_Template * scsi_devicelist;
if (shost->hostt->slave_detach)
(*shost->hostt->slave_detach) (sdev);
int max_scsi_hosts;
int next_scsi_host;
devfs_unregister(sdev->de);
device_unregister(&sdev->sdev_driverfs_dev);
}
void
scsi_unregister(struct Scsi_Host * sh){
struct Scsi_Host * shpnt;
Scsi_Host_Name *shn;
/* Next we free up the Scsi_Cmnd structures for this host */
for (sdev = shost->host_queue; sdev;
sdev = shost->host_queue) {
scsi_release_commandblocks(sdev);
blk_cleanup_queue(&sdev->request_queue);
/* Next free up the Scsi_Device structures for this host */
shost->host_queue = sdev->next;
if (sdev->inquiry)
kfree(sdev->inquiry);
kfree(sdev);
}
if(scsi_hostlist == sh)
scsi_hostlist = sh->next;
/* Remove the instance of the individual hosts */
pcount = scsi_hosts_registered;
if (shost->hostt->release)
(*shost->hostt->release) (shost);
else {
shpnt = scsi_hostlist;
while(shpnt->next != sh) shpnt = shpnt->next;
shpnt->next = shpnt->next->next;
scsi_host_generic_release(shost);
}
if (pcount == scsi_hosts_registered)
scsi_unregister(shost);
return 0;
}
/**
* scsi_unregister - unregister a scsi host
* @shost: scsi host to be unregistered
**/
void scsi_unregister(struct Scsi_Host *shost)
{
struct list_head *lh;
Scsi_Host_Name *shost_name;
/* Remove shost from scsi_host_list */
spin_lock(&scsi_host_list_lock);
list_del(&shost->sh_list);
spin_unlock(&scsi_host_list_lock);
/* Unregister from scsi_host_hn_list */
list_for_each(lh, &scsi_host_hn_list) {
shost_name = list_entry(lh, Scsi_Host_Name, shn_list);
if (shost->host_no == shost_name->host_no)
shost_name->host_registered = 0;
}
/*
* We have to unregister the host from the scsi_host_no_list as well.
* Decide by the host_no not by the name because most host drivers are
* able to handle more than one adapters from the same kind (or family).
*/
for ( shn=scsi_host_no_list; shn && (sh->host_no != shn->host_no);
shn=shn->next);
if (shn) shn->host_registered = 0;
/* else {} : This should not happen, we should panic here... */
/* If we are removing the last host registered, it is safe to reuse
* its host number (this avoids "holes" at boot time) (DB)
* It is also safe to reuse those of numbers directly below which have
* been released earlier (to avoid some holes in numbering).
* Next, kill the kernel error recovery thread for this host.
*/
if(sh->host_no == max_scsi_hosts - 1) {
while(--max_scsi_hosts >= next_scsi_host) {
shpnt = scsi_hostlist;
while(shpnt && shpnt->host_no != max_scsi_hosts - 1)
shpnt = shpnt->next;
if(shpnt)
break;
if (shost->ehandler) {
DECLARE_MUTEX_LOCKED(sem);
shost->eh_notify = &sem;
send_sig(SIGHUP, shost->ehandler, 1);
down(&sem);
shost->eh_notify = NULL;
}
scsi_hosts_registered--;
shost->hostt->present--;
/* Cleanup proc and driverfs */
#ifdef CONFIG_PROC_FS
scsi_proc_host_rm(shost);
if (!shost->hostt->present)
remove_proc_entry(shost->hostt->proc_name, proc_scsi);
#endif
device_unregister(&shost->host_driverfs_dev);
kfree(shost);
}
/**
* scsi_host_hn_add - allocate and add new Scsi_Host_Name
* @name: String to store in name field
*
* Return value:
* Pointer to a new Scsi_Host_Name
**/
Scsi_Host_Name *scsi_host_hn_add(char *name)
{
Scsi_Host_Name *shost_name;
int len;
len = strlen(name);
shost_name = kmalloc(sizeof(*shost_name), GFP_KERNEL);
if (!shost_name) {
printk(KERN_ERR "%s: out of memory at line %d.\n",
__FUNCTION__, __LINE__);
return NULL;
}
shost_name->name = kmalloc(len + 1, GFP_KERNEL);
if (!shost_name->name) {
kfree(shost_name);
printk(KERN_ERR "%s: out of memory at line %d.\n",
__FUNCTION__, __LINE__);
return NULL;
}
next_scsi_host--;
kfree((char *) sh);
if (len)
strncpy(shost_name->name, name, len);
shost_name->name[len] = 0;
shost_name->host_no = scsi_host_next_hn++;
shost_name->host_registered = 0;
list_add_tail(&shost_name->shn_list, &scsi_host_hn_list);
return shost_name;
}
/* 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 to avoid it
*/
/**
* scsi_register - register a scsi host adapter instance.
* @shost_tp: pointer to scsi host template
* @xtr_bytes: extra bytes to allocate for driver
*
* Note:
* 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 to avoid it
*
* Return value:
* Pointer to a new Scsi_Host
**/
extern int blk_nohighio;
struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j)
struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes)
{
struct Scsi_Host * retval, *shpnt, *o_shp;
Scsi_Host_Name *shn, *shn2;
int flag_new = 1;
const char * hname;
struct Scsi_Host *shost, *shost_scr;
Scsi_Host_Name *shost_name = NULL;
Scsi_Host_Name *shn = NULL;
char *hname;
size_t hname_len;
retval = (struct Scsi_Host *)kmalloc(sizeof(struct Scsi_Host) + j,
(tpnt->unchecked_isa_dma && j ?
GFP_DMA : 0) | GFP_ATOMIC);
if(retval == NULL)
{
printk("scsi: out of memory in scsi_register.\n");
struct list_head *lh;
int gfp_mask;
DECLARE_MUTEX_LOCKED(sem);
gfp_mask = GFP_KERNEL;
if (shost_tp->unchecked_isa_dma && xtr_bytes)
gfp_mask |= __GFP_DMA;
shost = kmalloc(sizeof(struct Scsi_Host) + xtr_bytes, gfp_mask);
if (!shost) {
printk(KERN_ERR "%s: out of memory.\n", __FUNCTION__);
return NULL;
}
memset(retval, 0, sizeof(struct Scsi_Host) + j);
memset(shost, 0, sizeof(struct Scsi_Host) + xtr_bytes);
/* trying to find a reserved entry (host_no) */
hname = (tpnt->proc_name) ? tpnt->proc_name : "";
/*
* Determine host number. Check reserved first before allocating
* new one
*/
hname = (shost_tp->proc_name) ? shost_tp->proc_name : "";
hname_len = strlen(hname);
for (shn = scsi_host_no_list;shn;shn = shn->next) {
if (hname_len)
list_for_each(lh, &scsi_host_hn_list) {
shn = list_entry(lh, Scsi_Host_Name, shn_list);
if (!(shn->host_registered) &&
(hname_len > 0) && (0 == strncmp(hname, shn->name, hname_len))) {
flag_new = 0;
retval->host_no = shn->host_no;
shn->host_registered = 1;
!strncmp(hname, shn->name, hname_len)) {
shost_name = shn;
break;
}
}
spin_lock_init(&retval->default_lock);
scsi_assign_lock(retval, &retval->default_lock);
atomic_set(&retval->host_active,0);
retval->host_busy = 0;
retval->host_failed = 0;
if (flag_new) {
shn = (Scsi_Host_Name *) kmalloc(sizeof(Scsi_Host_Name), GFP_ATOMIC);
if (!shn) {
kfree(retval);
printk(KERN_ERR "scsi: out of memory(2) in scsi_register.\n");
if (!shost_name) {
shost_name = scsi_host_hn_add(hname);
if (!shost_name) {
kfree(shost);
return NULL;
}
shn->name = kmalloc(hname_len + 1, GFP_ATOMIC);
if (hname_len > 0)
strncpy(shn->name, hname, hname_len);
shn->name[hname_len] = 0;
shn->host_no = max_scsi_hosts++;
shn->host_registered = 1;
shn->next = NULL;
if (scsi_host_no_list) {
for (shn2 = scsi_host_no_list;shn2->next;shn2 = shn2->next)
;
shn2->next = shn;
}
else
scsi_host_no_list = shn;
retval->host_no = shn->host_no;
}
next_scsi_host++;
retval->host_queue = NULL;
init_waitqueue_head(&retval->host_wait);
retval->resetting = 0;
retval->last_reset = 0;
retval->irq = 0;
retval->dma_channel = 0xff;
shost->host_no = shost_name->host_no;
shost_name->host_registered = 1;
scsi_hosts_registered++;
spin_lock_init(&shost->default_lock);
scsi_assign_lock(shost, &shost->default_lock);
atomic_set(&shost->host_active,0);
init_waitqueue_head(&shost->host_wait);
shost->dma_channel = 0xff;
/* These three are default values which can be overridden */
retval->max_channel = 0;
retval->max_id = 8;
retval->max_lun = 8;
shost->max_channel = 0;
shost->max_id = 8;
shost->max_lun = 8;
/*
* All drivers right now should be able to handle 12 byte commands.
* Every so often there are requests for 16 byte commands, but individual
* low-level drivers need to certify that they actually do something
* sensible with such commands.
* All drivers right now should be able to handle 12 byte
* commands. Every so often there are requests for 16 byte
* commands, but individual low-level drivers need to certify that
* they actually do something sensible with such commands.
*/
retval->max_cmd_len = 12;
shost->max_cmd_len = 12;
shost->hostt = shost_tp;
shost->host_blocked = FALSE;
shost->host_self_blocked = FALSE;
retval->unique_id = 0;
retval->io_port = 0;
retval->hostt = tpnt;
retval->next = NULL;
retval->in_recovery = 0;
retval->ehandler = NULL; /* Initial value until the thing starts up. */
retval->eh_notify = NULL; /* Who we notify when we exit. */
#ifdef DEBUG
printk("%s: %x %x: %d\n", __FUNCTION_ (int)shost,
(int)shost->hostt, xtr_bytes);
#endif
retval->max_host_blocked = tpnt->max_host_blocked ? tpnt->max_host_blocked : SCSI_DEFAULT_HOST_BLOCKED;
/*
* The next six are the default values which can be overridden if
* need be
*/
shost->this_id = shost_tp->this_id;
shost->can_queue = shost_tp->can_queue;
shost->sg_tablesize = shost_tp->sg_tablesize;
shost->cmd_per_lun = shost_tp->cmd_per_lun;
shost->unchecked_isa_dma = shost_tp->unchecked_isa_dma;
shost->use_clustering = shost_tp->use_clustering;
if (!blk_nohighio)
shost->highmem_io = shost_tp->highmem_io;
retval->host_blocked = 0;
retval->host_self_blocked = FALSE;
shost->max_sectors = shost_tp->max_sectors;
shost->use_blk_tcq = shost_tp->use_blk_tcq;
#ifdef DEBUG
printk("Register %x %x: %d\n", (int)retval, (int)retval->hostt, j);
spin_lock(&scsi_host_list_lock);
/*
* FIXME When device naming is complete remove this step that
* orders the scsi_host_list by host number and just do a
* list_add_tail.
*/
list_for_each(lh, &scsi_host_list) {
shost_scr = list_entry(lh, struct Scsi_Host, sh_list);
if (shost->host_no < shost_scr->host_no) {
__list_add(&shost->sh_list, shost_scr->sh_list.prev,
&shost_scr->sh_list);
goto found;
}
}
list_add_tail(&shost->sh_list, &scsi_host_list);
found:
spin_unlock(&scsi_host_list_lock);
#ifdef CONFIG_PROC_FS
/* Add the new driver to /proc/scsi if not already there */
if (!shost_tp->proc_dir)
scsi_proc_host_mkdir(shost_tp);
scsi_proc_host_add(shost);
#endif
/* The next six are the default values which can be overridden
* if need be */
retval->this_id = tpnt->this_id;
retval->can_queue = tpnt->can_queue;
retval->sg_tablesize = tpnt->sg_tablesize;
retval->cmd_per_lun = tpnt->cmd_per_lun;
retval->unchecked_isa_dma = tpnt->unchecked_isa_dma;
retval->use_clustering = tpnt->use_clustering;
if (!blk_nohighio)
retval->highmem_io = tpnt->highmem_io;
strncpy(shost->host_driverfs_dev.name, shost_tp->proc_name,
DEVICE_NAME_SIZE-1);
sprintf(shost->host_driverfs_dev.bus_id, "scsi%d",
shost->host_no);
retval->max_sectors = tpnt->max_sectors;
retval->use_blk_tcq = tpnt->use_blk_tcq;
shost->eh_notify = &sem;
kernel_thread((int (*)(void *)) scsi_error_handler, (void *) shost, 0);
/*
* Now wait for the kernel error thread to initialize itself
* as it might be needed when we scan the bus.
*/
down(&sem);
shost->eh_notify = NULL;
if(!scsi_hostlist)
scsi_hostlist = retval;
else {
shpnt = scsi_hostlist;
if (retval->host_no < shpnt->host_no) {
retval->next = shpnt;
wmb(); /* want all to see these writes in this order */
scsi_hostlist = retval;
shost->hostt->present++;
return shost;
}
/**
* scsi_register_host - register a low level host driver
* @shost_tp: pointer to a scsi host driver template
*
* Return value:
* 0 on Success / 1 on Failure.
**/
int scsi_register_host(Scsi_Host_Template *shost_tp)
{
int cur_cnt;
Scsi_Device *sdev;
struct Scsi_Device_Template *sdev_tp;
struct list_head *lh;
struct Scsi_Host *shost;
/*
* Check no detect routine.
*/
if (!shost_tp->detect)
return 1;
/* If max_sectors isn't set, default to max */
if (!shost_tp->max_sectors)
shost_tp->max_sectors = 1024;
cur_cnt = scsi_hosts_registered;
MOD_INC_USE_COUNT;
/*
* The detect routine must carefully spinunlock/spinlock if it
* enables interrupts, since all interrupt handlers do spinlock as
* well.
*/
/*
* detect should do its own locking
* FIXME present is now set is scsi_register which breaks manual
* registration code below.
*/
shost_tp->detect(shost_tp);
if (shost_tp->present) {
/*
* FIXME Who needs manual registration and why???
*/
if (cur_cnt == scsi_hosts_registered) {
if (shost_tp->present > 1) {
printk(KERN_ERR "scsi: Failure to register"
"low-level scsi driver");
scsi_unregister_host(shost_tp);
return 1;
}
else {
for (o_shp = shpnt, shpnt = shpnt->next; shpnt;
o_shp = shpnt, shpnt = shpnt->next) {
if (retval->host_no < shpnt->host_no) {
retval->next = shpnt;
wmb();
o_shp->next = retval;
break;
/*
* The low-level driver failed to register a driver.
* We can do this now.
*/
if(scsi_register(shost_tp, 0)==NULL) {
printk(KERN_ERR "scsi: register failed.\n");
scsi_unregister_host(shost_tp);
return 1;
}
}
list_add_tail(&shost_tp->shtp_list, &scsi_host_tmpl_list);
/* The next step is to call scan_scsis here. This generates the
* Scsi_Devices entries
*/
list_for_each(lh, &scsi_host_list) {
shost = list_entry(lh, struct Scsi_Host, sh_list);
if (shost->hostt == shost_tp) {
const char *dm_name;
if (shost_tp->info) {
dm_name = shost_tp->info(shost);
} else {
dm_name = shost_tp->name;
}
printk(KERN_INFO "scsi%d : %s\n",
shost->host_no, dm_name);
/* first register parent with driverfs */
device_register(&shost->host_driverfs_dev);
scan_scsis(shost, 0, 0, 0, 0);
}
if (! shpnt)
o_shp->next = retval;
}
for (sdev_tp = scsi_devicelist; sdev_tp;
sdev_tp = sdev_tp->next) {
if (sdev_tp->init && sdev_tp->dev_noticed)
(*sdev_tp->init) ();
}
return retval;
/*
* Next we create the Scsi_Cmnd structures for this host
*/
list_for_each(lh, &scsi_host_list) {
shost = list_entry(lh, struct Scsi_Host, sh_list);
for (sdev = shost->host_queue; sdev; sdev = sdev->next)
if (sdev->host->hostt == shost_tp) {
for (sdev_tp = scsi_devicelist;
sdev_tp;
sdev_tp = sdev_tp->next)
if (sdev_tp->attach)
(*sdev_tp->attach) (sdev);
if (sdev->attached) {
scsi_build_commandblocks(sdev);
if (sdev->current_queue_depth == 0)
goto out_of_space;
}
}
}
/* This does any final handling that is required. */
for (sdev_tp = scsi_devicelist; sdev_tp;
sdev_tp = sdev_tp->next) {
if (sdev_tp->finish && sdev_tp->nr_dev) {
(*sdev_tp->finish) ();
}
}
}
return 0;
out_of_space:
scsi_unregister_host(shost_tp); /* easiest way to clean up?? */
return 1;
}
/**
* scsi_unregister_host - unregister a low level host adapter driver
* @shost_tp: scsi host template to unregister.
*
* Description:
* Similarly, this entry point should be called by a loadable module
* if it is trying to remove a low level scsi driver from the system.
*
* Return value:
* 0 on Success / 1 on Failure
*
* Notes:
* rmmod does not care what we return here the module will be
* removed.
**/
int scsi_unregister_host(Scsi_Host_Template *shost_tp)
{
int pcount;
/* get the big kernel lock, so we don't race with open() */
lock_kernel();
pcount = scsi_hosts_registered;
scsi_tp_for_each_host(shost_tp, scsi_host_chk_and_release);
if (pcount != scsi_hosts_registered)
printk(KERN_INFO "scsi : %d host%s left.\n", scsi_hosts_registered,
(scsi_hosts_registered == 1) ? "" : "s");
/*
* Remove it from the list if all
* hosts were successfully removed (ie preset == 0)
*/
if (!shost_tp->present) {
list_del(&shost_tp->shtp_list);
}
MOD_DEC_USE_COUNT;
unlock_kernel();
return 0;
}
/**
* *scsi_host_get_next - get scsi host and inc ref count
* @shost: pointer to a Scsi_Host or NULL to start.
*
* Return value:
* A pointer to next Scsi_Host in list or NULL.
**/
struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *shost)
{
struct list_head *lh = NULL;
spin_lock(&scsi_host_list_lock);
if (shost) {
/* XXX Dec ref on cur shost */
lh = shost->sh_list.next;
} else {
lh = scsi_host_list.next;
}
if (lh == &scsi_host_list) {
shost = (struct Scsi_Host *)NULL;
goto done;
}
shost = list_entry(lh, struct Scsi_Host, sh_list);
/* XXX Inc ref count */
done:
spin_unlock(&scsi_host_list_lock);
return shost;
}
/**
* scsi_host_hn_get - get a Scsi_Host by host no and inc ref count
* @host_no: host number to locate
*
* Return value:
* A pointer to located Scsi_Host or NULL.
**/
struct Scsi_Host *scsi_host_hn_get(unsigned short host_no)
{
struct list_head *lh;
struct Scsi_Host *shost;
spin_lock(&scsi_host_list_lock);
list_for_each(lh, &scsi_host_list) {
shost = list_entry(lh, struct Scsi_Host, sh_list);
if (shost->host_no == host_no) {
/* XXX Inc ref count */
goto done;
}
}
shost = (struct Scsi_Host *)NULL;
done:
spin_unlock(&scsi_host_list_lock);
return shost;
}
/**
* *scsi_host_put - dec a Scsi_Host ref count
* @shost: Pointer to Scsi_Host to dec.
**/
void scsi_host_put(struct Scsi_Host *shost)
{
/* XXX Get list lock */
/* XXX dec ref count */
/* XXX Release list lock */
return;
}
/**
* scsi_host_hn_init - init scsi host number list from string
* @shost_hn: string of scsi host driver names.
**/
void __init scsi_host_hn_init(char *shost_hn)
{
char *temp = shost_hn;
while (temp) {
while (*temp && (*temp != ':') && (*temp != ','))
temp++;
if (!*temp)
temp = NULL;
else
*temp++ = 0;
(void)scsi_host_hn_add(shost_hn);
shost_hn = temp;
}
}
/**
* scsi_host_no_release - free all entries in scsi host number list
**/
void __exit scsi_host_hn_release()
{
struct list_head *lh, *next;
Scsi_Host_Name *shn;
list_for_each_safe(lh, next, &scsi_host_hn_list) {
shn = list_entry(lh, Scsi_Host_Name, shn_list);
if (shn->name)
kfree(shn->name);
kfree(shn);
}
}
void scsi_host_busy_inc(struct Scsi_Host *shost, Scsi_Device *sdev)
......@@ -279,8 +761,7 @@ void scsi_host_busy_dec_and_test(struct Scsi_Host *shost, Scsi_Device *sdev)
if (shost->in_recovery && (shost->host_busy == shost->host_failed)) {
up(shost->eh_wait);
SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler"
"thread (%d)\n",
atomic_read(&shost->eh_wait->count)));
" thread\n"));
}
spin_unlock_irqrestore(shost->host_lock, flags);
}
......@@ -295,8 +776,7 @@ void scsi_host_failed_inc_and_test(struct Scsi_Host *shost)
if (shost->host_busy == shost->host_failed) {
up(shost->eh_wait);
SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler"
"thread (%d)\n",
atomic_read(&shost->eh_wait->count)));
" thread\n"));
}
spin_unlock_irqrestore(shost->host_lock, flags);
}
......
......@@ -16,15 +16,14 @@
* of the same type.
*
* Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli
*
* Restructured scsi_host lists and associated functions.
* September 04, 2002 Mike Anderson (andmike@us.ibm.com)
*/
#ifndef _HOSTS_H
#define _HOSTS_H
/*
$Header: /vger/u4/cvs/linux/drivers/scsi/hosts.h,v 1.6 1997/01/19 23:07:13 davem Exp $
*/
#include <linux/config.h>
#include <linux/proc_fs.h>
#include <linux/pci.h>
......@@ -58,8 +57,7 @@ typedef struct scsi_disk Disk;
typedef struct SHT
{
/* Used with loadable modules so we can construct a linked list. */
struct SHT * next;
struct list_head shtp_list;
/* Used with loadable modules so that we know when it is safe to unload */
struct module * module;
......@@ -374,7 +372,7 @@ struct Scsi_Host
* This information is private to the scsi mid-layer. Wrapping it in a
* struct private is a way of marking it in a sort of C++ type of way.
*/
struct Scsi_Host * next;
struct list_head sh_list;
Scsi_Device * host_queue;
struct list_head all_scsi_hosts;
struct list_head my_devices;
......@@ -510,28 +508,26 @@ struct Scsi_Host
* thing. This physical pseudo-device isn't real and won't be available
* from any high-level drivers.
*/
extern void scsi_free_host_dev(Scsi_Device * SDpnt);
extern Scsi_Device * scsi_get_host_dev(struct Scsi_Host * SHpnt);
extern void scsi_free_host_dev(Scsi_Device *);
extern Scsi_Device * scsi_get_host_dev(struct Scsi_Host *);
extern void scsi_unblock_requests(struct Scsi_Host * SHpnt);
extern void scsi_block_requests(struct Scsi_Host * SHpnt);
extern void scsi_report_bus_reset(struct Scsi_Host * SHpnt, int channel);
extern void scsi_unblock_requests(struct Scsi_Host *);
extern void scsi_block_requests(struct Scsi_Host *);
extern void scsi_report_bus_reset(struct Scsi_Host *, int);
typedef struct SHN
{
struct SHN * next;
char * name;
{
struct list_head shn_list;
char *name;
unsigned short host_no;
unsigned short host_registered;
} Scsi_Host_Name;
} Scsi_Host_Name;
extern Scsi_Host_Name * scsi_host_no_list;
extern struct Scsi_Host * scsi_hostlist;
extern struct Scsi_Device_Template * scsi_devicelist;
extern Scsi_Host_Template * scsi_hosts;
extern void build_proc_dir_entries(Scsi_Host_Template *);
extern void scsi_proc_host_mkdir(Scsi_Host_Template *);
extern void scsi_proc_host_add(struct Scsi_Host *);
extern void scsi_proc_host_rm(struct Scsi_Host *);
/*
* scsi_init initializes the scsi hosts.
......@@ -540,34 +536,33 @@ extern void build_proc_dir_entries(Scsi_Host_Template *);
extern int next_scsi_host;
unsigned int scsi_init(void);
extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int j);
extern void scsi_unregister(struct Scsi_Host * i);
extern void scsi_register_blocked_host(struct Scsi_Host * SHpnt);
extern void scsi_deregister_blocked_host(struct Scsi_Host * SHpnt);
extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int);
extern void scsi_unregister(struct Scsi_Host *);
extern void scsi_register_blocked_host(struct Scsi_Host *);
extern void scsi_deregister_blocked_host(struct Scsi_Host *);
static inline void scsi_assign_lock(struct Scsi_Host *host, spinlock_t *lock)
static inline void scsi_assign_lock(struct Scsi_Host *shost, spinlock_t *lock)
{
host->host_lock = lock;
shost->host_lock = lock;
}
static inline void scsi_set_pci_device(struct Scsi_Host *SHpnt,
static inline void scsi_set_pci_device(struct Scsi_Host *shost,
struct pci_dev *pdev)
{
SHpnt->pci_dev = pdev;
SHpnt->host_driverfs_dev.parent=&pdev->dev;
shost->pci_dev = pdev;
shost->host_driverfs_dev.parent=&pdev->dev;
/* register parent with driverfs */
device_register(&shost->host_driverfs_dev);
}
/*
* Prototypes for functions/data in scsi_scan.c
*/
extern void scan_scsis(struct Scsi_Host *shpnt,
uint hardcoded,
uint hchannel,
uint hid,
uint hlun);
extern void scan_scsis(struct Scsi_Host *, uint, uint, uint, uint);
extern void scsi_mark_host_reset(struct Scsi_Host *Host);
extern void scsi_mark_host_reset(struct Scsi_Host *);
#define BLANK_HOST {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
......@@ -596,7 +591,7 @@ struct Scsi_Device_Template
struct device_driver scsi_driverfs_driver;
};
void scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt);
void scsi_initialize_queue(Scsi_Device *, struct Scsi_Host *);
/*
......@@ -607,6 +602,12 @@ extern int scsi_unregister_device(struct Scsi_Device_Template *);
extern int scsi_register_host(Scsi_Host_Template *);
extern int scsi_unregister_host(Scsi_Host_Template *);
extern struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *);
extern struct Scsi_Host *scsi_host_hn_get(unsigned short);
extern void scsi_host_put(struct Scsi_Host *);
extern void scsi_host_hn_init(char *);
extern void scsi_host_hn_release(void);
/*
* host_busy inc/dec/test functions
*/
......@@ -614,7 +615,6 @@ extern void scsi_host_busy_inc(struct Scsi_Host *, Scsi_Device *);
extern void scsi_host_busy_dec_and_test(struct Scsi_Host *, Scsi_Device *);
extern void scsi_host_failed_inc_and_test(struct Scsi_Host *);
/*
* This is an ugly hack. If we expect to be able to load devices at run time,
* we need to leave extra room in some of the data structures. Doing a
......@@ -643,21 +643,22 @@ extern void scsi_host_failed_inc_and_test(struct Scsi_Host *);
/**
* scsi_find_device - find a device given the host
* @shost: SCSI host pointer
* @channel: SCSI channel (zero if only one channel)
* @pun: SCSI target number (physical unit number)
* @lun: SCSI Logical Unit Number
**/
static inline Scsi_Device *scsi_find_device(struct Scsi_Host *host,
static inline Scsi_Device *scsi_find_device(struct Scsi_Host *shost,
int channel, int pun, int lun) {
Scsi_Device *SDpnt;
Scsi_Device *sdev;
for(SDpnt = host->host_queue;
SDpnt != NULL;
SDpnt = SDpnt->next)
if(SDpnt->channel == channel && SDpnt->id == pun
&& SDpnt->lun ==lun)
for (sdev = shost->host_queue;
sdev != NULL;
sdev = sdev->next)
if (sdev->channel == channel && sdev->id == pun
&& sdev->lun ==lun)
break;
return SDpnt;
return sdev;
}
#endif
......
......@@ -407,7 +407,6 @@
*/
#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
#define IPS { \
next : NULL, \
module : NULL, \
proc_info : NULL, \
proc_dir : NULL, \
......@@ -437,7 +436,6 @@
}
#elif LINUX_VERSION_CODE < LinuxVersionCode(2,5,0)
#define IPS { \
next : NULL, \
module : NULL, \
proc_info : NULL, \
name : NULL, \
......@@ -466,7 +464,6 @@
}
#else
#define IPS { \
next : NULL, \
module : NULL, \
proc_info : NULL, \
name : NULL, \
......
......@@ -294,7 +294,8 @@ static void aha152x_config_cs(dev_link_t *link)
tail = &link->dev;
info->ndev = 0;
for (host = scsi_hostlist; host; host = host->next)
for (host = scsi_host_get_next(NULL); host;
host = scsi_host_get_next(host))
if (host->hostt == &driver_template)
for (dev = host->host_queue; dev; dev = dev->next) {
u_long arg[2], id;
......
......@@ -258,7 +258,8 @@ static void fdomain_config(dev_link_t *link)
tail = &link->dev;
info->ndev = 0;
for (host = scsi_hostlist; host; host = host->next)
for (host = scsi_host_get_next(NULL); host;
host = scsi_host_get_next(host))
if (host->hostt == &driver_template)
for (dev = host->host_queue; dev; dev = dev->next) {
u_long arg[2], id;
......
......@@ -1520,7 +1520,8 @@ static void nsp_cs_config(dev_link_t *link)
DEBUG(0, "GET_SCSI_INFO\n");
tail = &link->dev;
info->ndev = 0;
for (host = scsi_hostlist; host != NULL; host = host->next) {
for (host = scsi_host_get_next(NULL); host;
host = scsi_host_get_next(host))
if (host->hostt == &driver_template) {
for (dev = host->host_queue; dev != NULL; dev = dev->next) {
u_long arg[2], id;
......
......@@ -281,7 +281,8 @@ static void qlogic_config(dev_link_t *link)
tail = &link->dev;
info->ndev = 0;
for (host = scsi_hostlist; host; host = host->next)
for (host = scsi_host_get_next(NULL); host;
host = scsi_host_get_next(host))
if (host->hostt == &driver_template)
for (dev = host->host_queue; dev; dev = dev->next) {
u_long arg[2], id;
......
......@@ -1659,33 +1659,6 @@ void scsi_adjust_queue_depth(Scsi_Device *SDpnt, int tagged, int tags)
}
}
void __init scsi_host_no_insert(char *str, int n)
{
Scsi_Host_Name *shn, *shn2;
int len;
len = strlen(str);
if (len && (shn = (Scsi_Host_Name *) kmalloc(sizeof(Scsi_Host_Name), GFP_ATOMIC))) {
if ((shn->name = kmalloc(len+1, GFP_ATOMIC))) {
strncpy(shn->name, str, len);
shn->name[len] = 0;
shn->host_no = n;
shn->host_registered = 0;
shn->next = NULL;
if (scsi_host_no_list) {
for (shn2 = scsi_host_no_list;shn2->next;shn2 = shn2->next)
;
shn2->next = shn;
}
else
scsi_host_no_list = shn;
max_scsi_hosts = n+1;
}
else
kfree((char *) shn);
}
}
#ifdef CONFIG_PROC_FS
static int scsi_proc_info(char *buffer, char **start, off_t offset, int length)
{
......@@ -1698,7 +1671,8 @@ static int scsi_proc_info(char *buffer, char **start, off_t offset, int length)
/*
* First, see if there are any attached devices or not.
*/
for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) {
for (HBA_ptr = scsi_host_get_next(NULL); HBA_ptr;
HBA_ptr = scsi_host_get_next(HBA_ptr)) {
if (HBA_ptr->host_queue != NULL) {
break;
}
......@@ -1706,7 +1680,8 @@ static int scsi_proc_info(char *buffer, char **start, off_t offset, int length)
size = sprintf(buffer + len, "Attached devices: %s\n", (HBA_ptr) ? "" : "none");
len += size;
pos = begin + len;
for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) {
for (HBA_ptr = scsi_host_get_next(NULL); HBA_ptr;
HBA_ptr = scsi_host_get_next(HBA_ptr)) {
#if 0
size += sprintf(buffer + len, "scsi%2d: %s\n", (int) HBA_ptr->host_no,
HBA_ptr->hostt->procname);
......@@ -1873,7 +1848,8 @@ static int proc_scsi_gen_write(struct file * file, const char * buf,
printk(KERN_INFO "scsi singledevice %d %d %d %d\n", host, channel,
id, lun);
for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) {
for (HBA_ptr = scsi_host_get_next(NULL); HBA_ptr;
HBA_ptr = scsi_host_get_next(HBA_ptr)) {
if (HBA_ptr->host_no == host) {
break;
}
......@@ -1918,7 +1894,8 @@ static int proc_scsi_gen_write(struct file * file, const char * buf,
lun = simple_strtoul(p + 1, &p, 0);
for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) {
for (HBA_ptr = scsi_host_get_next(NULL); HBA_ptr;
HBA_ptr = scsi_host_get_next(HBA_ptr)) {
if (HBA_ptr->host_no == host) {
break;
}
......@@ -1987,369 +1964,6 @@ static int proc_scsi_gen_write(struct file * file, const char * buf,
}
#endif
/*
* This entry point should be called by a driver if it is trying
* to add a low level scsi driver to the system.
*/
int scsi_register_host(Scsi_Host_Template * tpnt)
{
int pcount;
struct Scsi_Host *shpnt;
Scsi_Device *SDpnt;
struct Scsi_Device_Template *sdtpnt;
const char *name;
int out_of_space = 0;
if (tpnt->next || !tpnt->detect)
return 1; /* Must be already loaded, or
* no detect routine available
*/
/* If max_sectors isn't set, default to max */
if (!tpnt->max_sectors)
tpnt->max_sectors = 1024;
pcount = next_scsi_host;
MOD_INC_USE_COUNT;
/* The detect routine must carefully spinunlock/spinlock if
it enables interrupts, since all interrupt handlers do
spinlock as well. */
/*
* detect should do its own locking
*/
tpnt->present = tpnt->detect(tpnt);
if (tpnt->present) {
if (pcount == next_scsi_host) {
if (tpnt->present > 1) {
printk(KERN_ERR "scsi: Failure to register low-level scsi driver");
scsi_unregister_host(tpnt);
return 1;
}
/*
* The low-level driver failed to register a driver.
* We can do this now.
*/
if(scsi_register(tpnt, 0)==NULL)
{
printk(KERN_ERR "scsi: register failed.\n");
scsi_unregister_host(tpnt);
return 1;
}
}
tpnt->next = scsi_hosts; /* Add to the linked list */
scsi_hosts = tpnt;
/* Add the new driver to /proc/scsi */
#ifdef CONFIG_PROC_FS
build_proc_dir_entries(tpnt);
#endif
/*
* Add the kernel threads for each host adapter that will
* handle error correction.
*/
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
if (shpnt->hostt == tpnt) {
DECLARE_MUTEX_LOCKED(sem);
shpnt->eh_notify = &sem;
kernel_thread((int (*)(void *)) scsi_error_handler,
(void *) shpnt, 0);
/*
* Now wait for the kernel error thread to initialize itself
* as it might be needed when we scan the bus.
*/
down(&sem);
shpnt->eh_notify = NULL;
}
}
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
if (shpnt->hostt == tpnt) {
if (tpnt->info) {
name = tpnt->info(shpnt);
} else {
name = tpnt->name;
}
printk(KERN_INFO "scsi%d : %s\n", /* And print a little message */
shpnt->host_no, name);
strncpy(shpnt->host_driverfs_dev.name,name,
DEVICE_NAME_SIZE-1);
sprintf(shpnt->host_driverfs_dev.bus_id,
"scsi%d",
shpnt->host_no);
}
}
/* The next step is to call scan_scsis here. This generates the
* Scsi_Devices entries
*/
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
if (shpnt->hostt == tpnt) {
/* first register parent with driverfs */
device_register(&shpnt->host_driverfs_dev);
scan_scsis(shpnt, 0, 0, 0, 0);
}
}
for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
if (sdtpnt->init && sdtpnt->dev_noticed)
(*sdtpnt->init) ();
}
/*
* Next we create the Scsi_Cmnd structures for this host
*/
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next)
if (SDpnt->host->hostt == tpnt) {
for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
if (sdtpnt->attach)
(*sdtpnt->attach) (SDpnt);
if (SDpnt->attached) {
scsi_build_commandblocks(SDpnt);
if (SDpnt->current_queue_depth == 0)
out_of_space = 1;
}
}
}
/* This does any final handling that is required. */
for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
if (sdtpnt->finish && sdtpnt->nr_dev) {
(*sdtpnt->finish) ();
}
}
}
if (out_of_space) {
scsi_unregister_host(tpnt); /* easiest way to clean up?? */
return 1;
} else
return 0;
}
/*
* Similarly, this entry point should be called by a loadable module if it
* is trying to remove a low level scsi driver from the system.
*/
int scsi_unregister_host(Scsi_Host_Template * tpnt)
{
int online_status;
int pcount0, pcount;
Scsi_Cmnd *SCpnt;
Scsi_Device *SDpnt;
Scsi_Device *SDpnt1;
struct Scsi_Device_Template *sdtpnt;
struct Scsi_Host *sh1;
struct Scsi_Host *shpnt;
char name[10]; /* host_no>=10^9? I don't think so. */
/* get the big kernel lock, so we don't race with open() */
lock_kernel();
/*
* First verify that this host adapter is completely free with no pending
* commands
*/
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
for (SDpnt = shpnt->host_queue; SDpnt;
SDpnt = SDpnt->next) {
if (SDpnt->host->hostt == tpnt
&& SDpnt->host->hostt->module
&& GET_USE_COUNT(SDpnt->host->hostt->module))
goto err_out;
/*
* FIXME(eric) - We need to find a way to notify the
* low level driver that we are shutting down - via the
* special device entry that still needs to get added.
*
* Is detach interface below good enough for this?
*/
}
}
/*
* FIXME(eric) put a spinlock on this. We force all of the devices offline
* to help prevent race conditions where other hosts/processors could try and
* get in and queue a command.
*/
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
for (SDpnt = shpnt->host_queue; SDpnt;
SDpnt = SDpnt->next) {
if (SDpnt->host->hostt == tpnt)
SDpnt->online = FALSE;
}
}
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
if (shpnt->hostt != tpnt) {
continue;
}
for (SDpnt = shpnt->host_queue; SDpnt;
SDpnt = SDpnt->next) {
/*
* Loop over all of the commands associated with the device. If any of
* them are busy, then set the state back to inactive and bail.
*/
for (SCpnt = SDpnt->device_queue; SCpnt;
SCpnt = SCpnt->next) {
online_status = SDpnt->online;
SDpnt->online = FALSE;
if (SCpnt->request && SCpnt->request->rq_status != RQ_INACTIVE) {
printk(KERN_ERR "SCSI device not inactive - rq_status=%d, target=%d, pid=%ld, state=%d, owner=%d.\n",
SCpnt->request->rq_status, SCpnt->target, SCpnt->pid,
SCpnt->state, SCpnt->owner);
for (SDpnt1 = shpnt->host_queue; SDpnt1;
SDpnt1 = SDpnt1->next) {
for (SCpnt = SDpnt1->device_queue; SCpnt;
SCpnt = SCpnt->next)
if (SCpnt->request->rq_status == RQ_SCSI_DISCONNECTING)
SCpnt->request->rq_status = RQ_INACTIVE;
}
SDpnt->online = online_status;
printk(KERN_ERR "Device busy???\n");
goto err_out;
}
/*
* No, this device is really free. Mark it as such, and
* continue on.
*/
SCpnt->state = SCSI_STATE_DISCONNECTING;
if(SCpnt->request)
SCpnt->request->rq_status = RQ_SCSI_DISCONNECTING; /* Mark as busy */
}
}
}
/* Next we detach the high level drivers from the Scsi_Device structures */
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
if (shpnt->hostt != tpnt) {
continue;
}
for (SDpnt = shpnt->host_queue; SDpnt;
SDpnt = SDpnt->next) {
for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
if (sdtpnt->detach)
(*sdtpnt->detach) (SDpnt);
/* If something still attached, punt */
if (SDpnt->attached) {
printk(KERN_ERR "Attached usage count = %d\n", SDpnt->attached);
goto err_out;
}
if (shpnt->hostt->slave_detach)
(*shpnt->hostt->slave_detach) (SDpnt);
devfs_unregister (SDpnt->de);
put_device(&SDpnt->sdev_driverfs_dev);
}
}
/*
* Next, kill the kernel error recovery thread for this host.
*/
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
if (shpnt->hostt == tpnt
&& shpnt->ehandler != NULL) {
DECLARE_MUTEX_LOCKED(sem);
shpnt->eh_notify = &sem;
send_sig(SIGHUP, shpnt->ehandler, 1);
down(&sem);
shpnt->eh_notify = NULL;
}
}
/* Next we free up the Scsi_Cmnd structures for this host */
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
if (shpnt->hostt != tpnt) {
continue;
}
for (SDpnt = shpnt->host_queue; SDpnt;
SDpnt = shpnt->host_queue) {
scsi_release_commandblocks(SDpnt);
blk_cleanup_queue(&SDpnt->request_queue);
/* Next free up the Scsi_Device structures for this host */
shpnt->host_queue = SDpnt->next;
if (SDpnt->inquiry)
kfree(SDpnt->inquiry);
kfree((char *) SDpnt);
}
}
/* Next we go through and remove the instances of the individual hosts
* that were detected */
pcount0 = next_scsi_host;
for (shpnt = scsi_hostlist; shpnt; shpnt = sh1) {
sh1 = shpnt->next;
if (shpnt->hostt != tpnt)
continue;
pcount = next_scsi_host;
/* Remove the /proc/scsi directory entry */
sprintf(name,"%d",shpnt->host_no);
remove_proc_entry(name, tpnt->proc_dir);
put_device(&shpnt->host_driverfs_dev);
if (tpnt->release)
(*tpnt->release) (shpnt);
else {
/* This is the default case for the release function.
* It should do the right thing for most correctly
* written host adapters.
*/
if (shpnt->irq)
free_irq(shpnt->irq, NULL);
if (shpnt->dma_channel != 0xff)
free_dma(shpnt->dma_channel);
if (shpnt->io_port && shpnt->n_io_port)
release_region(shpnt->io_port, shpnt->n_io_port);
}
if (pcount == next_scsi_host)
scsi_unregister(shpnt);
tpnt->present--;
}
if (pcount0 != next_scsi_host)
printk(KERN_INFO "scsi : %d host%s left.\n", next_scsi_host,
(next_scsi_host == 1) ? "" : "s");
/*
* Remove it from the linked list and /proc if all
* hosts were successfully removed (ie preset == 0)
*/
if (!tpnt->present) {
Scsi_Host_Template **SHTp = &scsi_hosts;
Scsi_Host_Template *SHT;
while ((SHT = *SHTp) != NULL) {
if (SHT == tpnt) {
*SHTp = SHT->next;
remove_proc_entry(tpnt->proc_name, proc_scsi);
break;
}
SHTp = &SHT->next;
}
}
MOD_DEC_USE_COUNT;
unlock_kernel();
return 0;
err_out:
unlock_kernel();
return -1;
}
/*
* This entry point should be called by a loadable module if it is trying
* add a high level scsi driver to the system.
......@@ -2361,7 +1975,7 @@ int scsi_register_device(struct Scsi_Device_Template *tpnt)
int out_of_space = 0;
#ifdef CONFIG_KMOD
if (scsi_hosts == NULL)
if (scsi_host_get_next(NULL) == NULL)
request_module("scsi_hostadapter");
#endif
......@@ -2375,7 +1989,8 @@ int scsi_register_device(struct Scsi_Device_Template *tpnt)
* First scan the devices that we know about, and see if we notice them.
*/
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
for (shpnt = scsi_host_get_next(NULL); shpnt;
shpnt = scsi_host_get_next(shpnt)) {
for (SDpnt = shpnt->host_queue; SDpnt;
SDpnt = SDpnt->next) {
if (tpnt->detect)
......@@ -2394,7 +2009,8 @@ int scsi_register_device(struct Scsi_Device_Template *tpnt)
/*
* Now actually connect the devices to the new driver.
*/
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
for (shpnt = scsi_host_get_next(NULL); shpnt;
shpnt = scsi_host_get_next(shpnt)) {
for (SDpnt = shpnt->host_queue; SDpnt;
SDpnt = SDpnt->next) {
if (tpnt->attach)
......@@ -2444,7 +2060,8 @@ int scsi_unregister_device(struct Scsi_Device_Template *tpnt)
* Next, detach the devices from the driver.
*/
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
for (shpnt = scsi_host_get_next(NULL); shpnt;
shpnt = scsi_host_get_next(shpnt)) {
for (SDpnt = shpnt->host_queue; SDpnt;
SDpnt = SDpnt->next) {
if (tpnt->detach)
......@@ -2516,7 +2133,8 @@ static void scsi_dump_status(int level)
Scsi_Device *SDpnt;
printk(KERN_INFO "Dump of scsi host parameters:\n");
i = 0;
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
for (shpnt = scsi_host_get_next(NULL); shpnt;
shpnt = scsi_host_get_next(shpnt)) {
printk(KERN_INFO " %d %d %d : %d %d\n",
shpnt->host_failed,
shpnt->host_busy,
......@@ -2527,7 +2145,8 @@ static void scsi_dump_status(int level)
printk(KERN_INFO "\n\n");
printk(KERN_INFO "Dump of scsi command parameters:\n");
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
for (shpnt = scsi_host_get_next(NULL); shpnt;
shpnt = scsi_host_get_next(shpnt)) {
printk(KERN_INFO "h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result\n");
for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
......@@ -2565,26 +2184,6 @@ static void scsi_dump_status(int level)
}
#endif /* CONFIG_PROC_FS */
static int __init scsi_host_no_init (char *str)
{
static int next_no = 0;
char *temp;
while (str) {
temp = str;
while (*temp && (*temp != ':') && (*temp != ','))
temp++;
if (!*temp)
temp = NULL;
else
*temp++ = 0;
scsi_host_no_insert(str, next_no);
str = temp;
next_no++;
}
return 1;
}
static char *scsihosts;
MODULE_PARM(scsihosts, "s");
......@@ -2724,9 +2323,8 @@ static int __init init_scsi(void)
#endif
scsi_devfs_handle = devfs_mk_dir (NULL, "scsi", NULL);
if (scsihosts)
printk(KERN_INFO "scsi: host order: %s\n", scsihosts);
scsi_host_no_init (scsihosts);
scsi_host_hn_init(scsihosts);
bus_register(&scsi_driverfs_bus_type);
......@@ -2738,19 +2336,11 @@ static int __init init_scsi(void)
static void __exit exit_scsi(void)
{
Scsi_Host_Name *shn, *shn2 = NULL;
int i;
devfs_unregister (scsi_devfs_handle);
for (shn = scsi_host_no_list;shn;shn = shn->next) {
if (shn->name)
kfree(shn->name);
if (shn2)
kfree (shn2);
shn2 = shn;
}
if (shn2)
kfree (shn2);
scsi_host_hn_release();
#ifdef CONFIG_PROC_FS
/* No, we're not here anymore. Don't show the /proc/scsi files. */
......
......@@ -119,35 +119,44 @@ static int proc_scsi_write(struct file * file, const char * buf,
return(ret);
}
void build_proc_dir_entries(Scsi_Host_Template * tpnt)
void scsi_proc_host_mkdir(Scsi_Host_Template *shost_tp)
{
struct Scsi_Host *hpnt;
char name[10]; /* see scsi_unregister_host() */
tpnt->proc_dir = proc_mkdir(tpnt->proc_name, proc_scsi);
if (!tpnt->proc_dir) {
printk(KERN_ERR "Unable to proc_mkdir in scsi.c/build_proc_dir_entries");
shost_tp->proc_dir = proc_mkdir(shost_tp->proc_name, proc_scsi);
if (!shost_tp->proc_dir) {
printk(KERN_ERR "%s: proc_mkdir failed for %s\n",
__FUNCTION__, shost_tp->proc_name);
return;
}
tpnt->proc_dir->owner = tpnt->module;
shost_tp->proc_dir->owner = shost_tp->module;
}
hpnt = scsi_hostlist;
while (hpnt) {
if (tpnt == hpnt->hostt) {
void scsi_proc_host_add(struct Scsi_Host *shost)
{
char name[10];
struct proc_dir_entry *p;
sprintf(name,"%d",hpnt->host_no);
sprintf(name,"%d",shost->host_no);
p = create_proc_read_entry(name,
S_IFREG | S_IRUGO | S_IWUSR,
tpnt->proc_dir,
shost->hostt->proc_dir,
proc_scsi_read,
(void *)hpnt);
if (!p)
panic("Not enough memory to register SCSI HBA in /proc/scsi !\n");
(void *)shost);
if (!p) {
printk(KERN_ERR "%s: Failed to register host %d in"
"%s\n", __FUNCTION__, shost->host_no,
shost->hostt->proc_name);
} else {
p->write_proc=proc_scsi_write;
p->owner = tpnt->module;
}
hpnt = hpnt->next;
p->owner = shost->hostt->module;
}
}
void scsi_proc_host_rm(struct Scsi_Host *shost)
{
char name[10];
sprintf(name,"%d",shost->host_no);
remove_proc_entry(name, shost->hostt->proc_dir);
}
/*
......
......@@ -91,8 +91,9 @@ EXPORT_SYMBOL(scsi_reset_provider);
/*
* These are here only while I debug the rest of the scsi stuff.
*/
EXPORT_SYMBOL(scsi_hostlist);
EXPORT_SYMBOL(scsi_hosts);
EXPORT_SYMBOL(scsi_host_get_next);
EXPORT_SYMBOL(scsi_host_hn_get);
EXPORT_SYMBOL(scsi_host_put);
EXPORT_SYMBOL(scsi_devicelist);
EXPORT_SYMBOL(scsi_device_types);
......
......@@ -3103,7 +3103,8 @@ sg_proc_host_info(char *buffer, int *len, off_t * begin, off_t offset, int size)
struct Scsi_Host *shp;
int k;
for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) {
for (k = 0, shp = scsi_host_get_next(NULL); shp;
shp = scsi_host_get_next(shp), ++k) {
for (; k < shp->host_no; ++k)
PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\n");
PRINT_PROC("%u\t%hu\t%hd\t%hu\t%d\t%d\n",
......@@ -3147,7 +3148,8 @@ sg_proc_hoststrs_info(char *buffer, int *len, off_t * begin,
char buff[SG_MAX_HOST_STR_LEN];
char *cp;
for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) {
for (k = 0, shp = scsi_host_get_next(NULL); shp;
shp = scsi_host_get_next(shp), ++k) {
for (; k < shp->host_no; ++k)
PRINT_PROC("<no active host>\n");
strncpy(buff, shp->hostt->info ? shp->hostt->info(shp) :
......
......@@ -1871,10 +1871,7 @@ Scsi_Cmnd *cmd;
int x,i;
static int stop = 0;
for (instance=scsi_hostlist; instance; instance=instance->next) {
if (instance->host_no == hn)
break;
}
instance = scsi_host_hn_get(hn);
if (!instance) {
printk("*** Hmm... Can't find host #%d!\n",hn);
return (-ESRCH);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment