Commit 68fe1e0f authored by Mike Anderson's avatar Mike Anderson Committed by James Bottomley

[PATCH] scsi host cleanup 2/3 (mid lvl changes)

This is a resend of my previous patch clean ups to the scsi_host lists.

	* Made function naming consistent with rest of SCSI
	* Corrected a problem with driverfs registration to early. Also
	  changed from put_device to device_unregister.
        * Fixed a regression in my previous patch that the scsi_host
          list was not sorted by host number. When we get some device
          naming this hack can be removed.
        * Switch scsi host template, name, host lists to struct
          list_head's.
        * Moved all scsi_host related register / unregister functions
          into hosts.c
        * Added list accessor interface and created a function similar
          to driverfs bus_for_each_dev.

The full patch is available at:
http://www-124.ibm.com/storageio/patches/2.5/scsi-host

-andmike
--
Michael Anderson
andmike@us.ibm.com

 scsi.c      |  456 +++---------------------------------------------------------
 scsi_proc.c |   57 ++++---
 scsi_syms.c |    5
 sg.c        |    6
 4 files changed, 63 insertions(+), 461 deletions(-)
parent 728df29f
......@@ -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) :
......
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