patch-2.3.13 linux/drivers/scsi/scsi.c
Next file: linux/drivers/scsi/sr.c
Previous file: linux/drivers/scsi/qlogicisp.c
Back to the patch index
Back to the overall index
- Lines: 448
- Date:
Fri Aug 6 11:43:09 1999
- Orig file:
v2.3.12/linux/drivers/scsi/scsi.c
- Orig date:
Tue Jun 8 10:41:03 1999
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
@@ -32,6 +32,8 @@
* Converted cli() code to spinlocks, Ingo Molnar
*
* Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli
+ *
+ * out_of_space hacks, D. Gilbert (dpg) 990608
*/
#include <linux/config.h>
@@ -180,6 +182,7 @@
int * sparse_lun, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt,
struct Scsi_Host *shpnt, char * scsi_result);
void scsi_build_commandblocks(Scsi_Device * SDpnt);
+static int scsi_unregister_device(struct Scsi_Device_Template * tpnt);
/*
* These are the interface to the old error handling code. It should go away
@@ -403,30 +406,43 @@
up(SCpnt->request.sem);
}
-__initfunc(void scsi_logging_setup(char *str, int *ints))
+static int __init scsi_logging_setup (char *str)
{
- if (ints[0] != 1) {
- printk("scsi_logging_setup : usage scsi_logging_level=n "
+ int tmp;
+
+ if (get_option(&str, &tmp)==1) {
+ scsi_logging_level = (tmp ? ~0 : 0);
+ return 1;
+ } else {
+ printk("scsi_logging_setup : usage scsi_logging_level=n "
"(n should be 0 or non-zero)\n");
- } else {
- scsi_logging_level = (ints[1])? ~0 : 0;
+ return 0;
}
}
+__setup("scsi_logging=", scsi_logging_setup);
+
#ifdef CONFIG_SCSI_MULTI_LUN
static int max_scsi_luns = 8;
#else
static int max_scsi_luns = 1;
#endif
-__initfunc(void scsi_luns_setup(char *str, int *ints))
+static int __init scsi_luns_setup (char *str)
{
- if (ints[0] != 1)
- printk("scsi_luns_setup : usage max_scsi_luns=n (n should be between 1 and 8)\n");
- else
- max_scsi_luns = ints[1];
+ int tmp;
+
+ if (get_option(&str, &tmp)==1) {
+ max_scsi_luns = tmp;
+ return 1;
+ } else {
+ printk("scsi_luns_setup : usage max_scsi_luns=n "
+ "(n should be between 1 and 8)\n");
+ return 0;
+ }
}
+__setup("max_scsi_luns=", scsi_luns_setup);
/*
* Detecting SCSI devices :
* We scan all present host adapter's busses, from ID 0 to ID (max_id).
@@ -451,16 +467,18 @@
Scsi_Device * SDtail;
int sparse_lun;
- SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), GFP_ATOMIC | GFP_DMA);
- memset (SCpnt, 0, sizeof (Scsi_Cmnd));
-
- SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
- memset (SDpnt, 0, sizeof (Scsi_Device));
-
-
- /* Make sure we have something that is valid for DMA purposes */
- scsi_result = ( ( !shpnt->unchecked_isa_dma )
- ? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA));
+ scsi_result = NULL;
+ SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd),
+ GFP_ATOMIC | GFP_DMA);
+ if (SCpnt) {
+ SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device),
+ GFP_ATOMIC);
+ if (SDpnt) {
+ /* Make sure we have something that is valid for DMA purposes */
+ scsi_result = ( ( !shpnt->unchecked_isa_dma )
+ ? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA));
+ }
+ }
if (scsi_result == NULL)
{
@@ -517,15 +535,23 @@
if(SDpnt!=oldSDpnt) {
/* it could happen the blockdevice hasn't yet been inited */
- for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
- if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
+ for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+ if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
- oldSDpnt->scsi_request_fn = NULL;
- for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
- if(sdtpnt->attach) {
- (*sdtpnt->attach)(oldSDpnt);
- if(oldSDpnt->attached) scsi_build_commandblocks(oldSDpnt);}
- resize_dma_pool();
+ oldSDpnt->scsi_request_fn = NULL;
+ for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
+ if(sdtpnt->attach) {
+ (*sdtpnt->attach)(oldSDpnt);
+ if(oldSDpnt->attached) {
+ scsi_build_commandblocks(oldSDpnt);
+ if (0 == oldSDpnt->has_cmdblocks) {
+ printk("scan_scsis: DANGER, no command blocks\n");
+ /* What to do now ?? */
+ }
+ }
+ }
+ }
+ resize_dma_pool();
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
if(sdtpnt->finish && sdtpnt->nr_dev)
@@ -886,8 +912,6 @@
return 0;
}
- memset (SDpnt, 0, sizeof (Scsi_Device));
-
/*
* And hook up our command block to the new device we will be testing
* for.
@@ -1903,9 +1927,9 @@
for (order = 0, a_size = PAGE_SIZE;
a_size < size; order++, a_size <<= 1)
;
- retval = (void *) __get_free_pages(gfp_mask | GFP_DMA, order);
+ retval = (void *) __get_free_pages(gfp_mask | GFP_DMA, order);
} else
- retval = kmalloc(size, gfp_mask);
+ retval = kmalloc(size, gfp_mask);
if (retval)
memset(retval, 0, size);
@@ -1974,9 +1998,10 @@
printk("scsi_build_commandblocks: want=%d, space for=%d blocks\n",
SDpnt->queue_depth, j);
SDpnt->queue_depth = j;
- /* Still problem if 0==j , continue anyway ... */
+ SDpnt->has_cmdblocks = (0 != j);
}
- SDpnt->has_cmdblocks = 1;
+ else
+ SDpnt->has_cmdblocks = 1;
}
#ifndef MODULE /* { */
@@ -1985,7 +2010,7 @@
* initialization, bus scanning, and sd/st initialization routines.
* This is only used at boot time.
*/
-__initfunc(int scsi_dev_init(void))
+int __init scsi_dev_init(void)
{
Scsi_Device * SDpnt;
struct Scsi_Host * shpnt;
@@ -2040,7 +2065,13 @@
/* SDpnt->scsi_request_fn = NULL; */
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
- if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
+ if(SDpnt->attached) {
+ scsi_build_commandblocks(SDpnt);
+ if (0 == SDpnt->has_cmdblocks) {
+ printk("scsi_dev_init: DANGER, no command blocks\n");
+ /* What to do now ?? */
+ }
+ }
}
}
@@ -2433,7 +2464,7 @@
*/
static void resize_dma_pool(void)
{
- int i;
+ int i, k;
unsigned long size;
struct Scsi_Host * shpnt;
struct Scsi_Host * host = NULL;
@@ -2442,6 +2473,7 @@
unsigned int new_dma_sectors = 0;
unsigned int new_need_isa_buffer = 0;
unsigned char ** new_dma_malloc_pages = NULL;
+ int out_of_space = 0;
if( !scsi_hostlist )
{
@@ -2533,27 +2565,67 @@
* race conditions that I would rather not even think
* about right now.
*/
- if( new_dma_sectors < dma_sectors )
+#if 0 /* Why do this? No gain and risks out_of_space */
+ if( new_dma_sectors < dma_sectors )
new_dma_sectors = dma_sectors;
+#endif
+ if( new_dma_sectors <= dma_sectors )
+ return; /* best to quit while we are in front */
- if (new_dma_sectors)
- {
- size = (new_dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap);
- new_dma_malloc_freelist = (FreeSectorBitmap *) scsi_init_malloc(size, GFP_ATOMIC);
- memset(new_dma_malloc_freelist, 0, size);
-
- size = (new_dma_sectors / SECTORS_PER_PAGE)*sizeof(*new_dma_malloc_pages);
- new_dma_malloc_pages = (unsigned char **) scsi_init_malloc(size, GFP_ATOMIC);
- memset(new_dma_malloc_pages, 0, size);
- }
+ for (k = 0; k < 20; ++k) { /* just in case */
+ out_of_space = 0;
+ size = (new_dma_sectors / SECTORS_PER_PAGE) *
+ sizeof(FreeSectorBitmap);
+ new_dma_malloc_freelist = (FreeSectorBitmap *)
+ scsi_init_malloc(size, GFP_ATOMIC);
+ if (new_dma_malloc_freelist) {
+ size = (new_dma_sectors / SECTORS_PER_PAGE) *
+ sizeof(*new_dma_malloc_pages);
+ new_dma_malloc_pages = (unsigned char **)
+ scsi_init_malloc(size, GFP_ATOMIC);
+ if (! new_dma_malloc_pages) {
+ size = (new_dma_sectors / SECTORS_PER_PAGE) *
+ sizeof(FreeSectorBitmap);
+ scsi_init_free((char *)new_dma_malloc_freelist, size);
+ out_of_space = 1;
+ }
+ }
+ else
+ out_of_space = 1;
+
+ if ((! out_of_space) && (new_dma_sectors > dma_sectors)) {
+ for(i = dma_sectors / SECTORS_PER_PAGE;
+ i < new_dma_sectors / SECTORS_PER_PAGE; i++) {
+ new_dma_malloc_pages[i] = (unsigned char *)
+ scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
+ if (! new_dma_malloc_pages[i])
+ break;
+ }
+ if (i != new_dma_sectors / SECTORS_PER_PAGE) { /* clean up */
+ int k = i;
- /*
- * If we need more buffers, expand the list.
- */
- if( new_dma_sectors > dma_sectors ) {
- for(i=dma_sectors / SECTORS_PER_PAGE; i< new_dma_sectors / SECTORS_PER_PAGE; i++)
- new_dma_malloc_pages[i] = (unsigned char *)
- scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
+ out_of_space = 1;
+ for (i = 0; i < k; ++i)
+ scsi_init_free(new_dma_malloc_pages[i], PAGE_SIZE);
+ }
+ }
+ if (out_of_space) { /* try scaling down new_dma_sectors request */
+ printk("scsi::resize_dma_pool: WARNING, dma_sectors=%u, "
+ "wanted=%u, scaling\n", dma_sectors, new_dma_sectors);
+ if (new_dma_sectors < (8 * SECTORS_PER_PAGE))
+ break; /* pretty well hopeless ... */
+ new_dma_sectors = (new_dma_sectors * 3) / 4;
+ new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
+ if (new_dma_sectors <= dma_sectors)
+ break; /* stick with what we have got */
+ }
+ else
+ break; /* found space ... */
+ } /* end of for loop */
+ if (out_of_space) {
+ scsi_need_isa_buffer = new_need_isa_buffer; /* some useful info */
+ printk(" WARNING, not enough memory, pool not expanded\n");
+ return;
}
/* When we dick with the actual DMA list, we need to
@@ -2600,6 +2672,7 @@
struct Scsi_Device_Template * sdtpnt;
const char * name;
unsigned long flags;
+ int out_of_space = 0;
if (tpnt->next || !tpnt->detect) return 1;/* Must be already loaded, or
* no detect routine available
@@ -2699,11 +2772,11 @@
{
if(shpnt->hostt == tpnt)
{
- scan_scsis(shpnt,0,0,0,0);
- if (shpnt->select_queue_depths != NULL)
- {
- (shpnt->select_queue_depths)(shpnt, shpnt->host_queue);
- }
+ scan_scsis(shpnt,0,0,0,0);
+ if (shpnt->select_queue_depths != NULL)
+ {
+ (shpnt->select_queue_depths)(shpnt, shpnt->host_queue);
+ }
}
}
@@ -2722,14 +2795,19 @@
{
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
- if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
+ if(SDpnt->attached) {
+ scsi_build_commandblocks(SDpnt);
+ if (0 == SDpnt->has_cmdblocks)
+ out_of_space = 1;
+ }
}
}
/*
* Now that we have all of the devices, resize the DMA pool,
* as required. */
- resize_dma_pool();
+ if (! out_of_space)
+ resize_dma_pool();
/* This does any final handling that is required. */
@@ -2750,7 +2828,13 @@
#endif
MOD_INC_USE_COUNT;
- return 0;
+
+ if (out_of_space) {
+ scsi_unregister_host(tpnt); /* easiest way to clean up?? */
+ return 1;
+ }
+ else
+ return 0;
}
/*
@@ -3011,6 +3095,7 @@
{
Scsi_Device * SDpnt;
struct Scsi_Host * shpnt;
+ int out_of_space = 0;
if (tpnt->next) return 1;
@@ -3052,6 +3137,8 @@
{
SDpnt->online = TRUE;
scsi_build_commandblocks(SDpnt);
+ if (0 == SDpnt->has_cmdblocks)
+ out_of_space = 1;
}
}
}
@@ -3060,9 +3147,16 @@
* This does any final handling that is required.
*/
if(tpnt->finish && tpnt->nr_dev) (*tpnt->finish)();
- resize_dma_pool();
+ if (! out_of_space)
+ resize_dma_pool();
MOD_INC_USE_COUNT;
- return 0;
+
+ if (out_of_space) {
+ scsi_unregister_device(tpnt); /* easiest way to clean up?? */
+ return 1;
+ }
+ else
+ return 0;
}
static int scsi_unregister_device(struct Scsi_Device_Template * tpnt)
@@ -3298,6 +3392,7 @@
int init_module(void)
{
unsigned long size;
+ int has_space = 0;
/*
* This makes /proc/scsi visible.
@@ -3313,7 +3408,6 @@
proc_scsi_register(0, &proc_scsi_scsi);
#endif
-
dma_sectors = PAGE_SIZE / SECTOR_SIZE;
scsi_dma_free_sectors= dma_sectors;
/*
@@ -3322,15 +3416,31 @@
*/
/* One bit per sector to indicate free/busy */
- size = (dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap);
- dma_malloc_freelist = (FreeSectorBitmap *) scsi_init_malloc(size, GFP_ATOMIC);
- memset(dma_malloc_freelist, 0, size);
-
- /* One pointer per page for the page list */
- dma_malloc_pages = (unsigned char **)
- scsi_init_malloc((dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_pages), GFP_ATOMIC);
- dma_malloc_pages[0] = (unsigned char *)
- scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
+ size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(FreeSectorBitmap);
+ dma_malloc_freelist = (FreeSectorBitmap *)
+ scsi_init_malloc(size, GFP_ATOMIC);
+ if (dma_malloc_freelist) {
+ /* One pointer per page for the page list */
+ dma_malloc_pages = (unsigned char **)scsi_init_malloc(
+ (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages),
+ GFP_ATOMIC);
+ if (dma_malloc_pages) {
+ dma_malloc_pages[0] = (unsigned char *)
+ scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
+ if (dma_malloc_pages[0])
+ has_space = 1;
+ }
+ }
+ if (! has_space) {
+ if (dma_malloc_freelist) {
+ scsi_init_free((char *)dma_malloc_freelist, size);
+ if (dma_malloc_pages)
+ scsi_init_free((char *)dma_malloc_pages,
+ (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages));
+ }
+ printk("scsi::init_module: failed, out of memory\n");
+ return 1;
+ }
/*
* This is where the processing takes place for most everything
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)