scsi.c 99.3 KB
Newer Older
1
/*
Linus Torvalds's avatar
Linus Torvalds committed
2 3
 *  scsi.c Copyright (C) 1992 Drew Eckhardt
 *         Copyright (C) 1993, 1994, 1995 Eric Youngdale
Linus Torvalds's avatar
Linus Torvalds committed
4
 *
Linus Torvalds's avatar
Linus Torvalds committed
5 6 7
 *  generic mid-level SCSI driver
 *      Initial versions: Drew Eckhardt
 *      Subsequent revisions: Eric Youngdale
8
 *
Linus Torvalds's avatar
Linus Torvalds committed
9
 *  <drew@colorado.edu>
10
 *
Linus Torvalds's avatar
Linus Torvalds committed
11 12 13 14
 *  Bug correction thanks go to :
 *      Rik Faith <faith@cs.unc.edu>
 *      Tommy Thorn <tthorn>
 *      Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
Linus Torvalds's avatar
Linus Torvalds committed
15
 *
Linus Torvalds's avatar
Linus Torvalds committed
16
 *  Modified by Eric Youngdale eric@aib.com to
Linus Torvalds's avatar
Linus Torvalds committed
17 18 19
 *  add scatter-gather, multiple outstanding request, and other
 *  enhancements.
 *
Linus Torvalds's avatar
Linus Torvalds committed
20
 *  Native multichannel, wide scsi, /proc/scsi and hot plugging
Linus Torvalds's avatar
Linus Torvalds committed
21
 *  support added by Michael Neuffer <mike@i-connect.net>
Linus Torvalds's avatar
Linus Torvalds committed
22 23 24 25
 *
 *  Added request_module("scsi_hostadapter") for kerneld:
 *  (Put an "alias scsi_hostadapter your_hostadapter" in /etc/conf.modules)
 *  Bjorn Ekwall  <bj0rn@blox.se>
Linus Torvalds's avatar
Linus Torvalds committed
26 27 28 29
 *
 *  Major improvements to the timeout, abort, and reset processing,
 *  as well as performance modifications for large queue depths by
 *  Leonard N. Zubkoff <lnz@dandelion.com>
30
 */
Linus Torvalds's avatar
Linus Torvalds committed
31

Linus Torvalds's avatar
Linus Torvalds committed
32 33 34 35 36
/*
 * Don't import our own symbols, as this would severely mess up our
 * symbol tables.
 */
#define _SCSI_SYMS_VER_
Linus Torvalds's avatar
Linus Torvalds committed
37 38

#include <linux/config.h>
Linus Torvalds's avatar
Linus Torvalds committed
39
#include <linux/module.h>
40 41 42 43

#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
Linus Torvalds's avatar
Linus Torvalds committed
44
#include <linux/malloc.h>
Linus Torvalds's avatar
Linus Torvalds committed
45
#include <linux/ioport.h>
Linus Torvalds's avatar
Linus Torvalds committed
46
#include <linux/kernel.h>
Linus Torvalds's avatar
Linus Torvalds committed
47
#include <linux/stat.h>
Linus Torvalds's avatar
Linus Torvalds committed
48
#include <linux/blk.h>
Linus Torvalds's avatar
Linus Torvalds committed
49
#include <linux/interrupt.h>
Linus Torvalds's avatar
Linus Torvalds committed
50
#include <linux/delay.h>
Linus Torvalds's avatar
Linus Torvalds committed
51
#include <linux/init.h>
Linus Torvalds's avatar
Linus Torvalds committed
52 53 54 55 56

#include <asm/system.h>
#include <asm/irq.h>
#include <asm/dma.h>

57 58
#include "scsi.h"
#include "hosts.h"
59
#include "constants.h"
60

Linus Torvalds's avatar
Linus Torvalds committed
61 62 63
#ifdef CONFIG_KERNELD
#include <linux/kerneld.h>
#endif
Linus Torvalds's avatar
Linus Torvalds committed
64

Linus Torvalds's avatar
Linus Torvalds committed
65 66
#undef USE_STATIC_SCSI_MEMORY

67
/*
Linus Torvalds's avatar
Linus Torvalds committed
68
static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/scsi.c,v 1.38 1997/01/19 23:07:18 davem Exp $";
69 70
*/

Linus Torvalds's avatar
Linus Torvalds committed
71

72 73 74
/* Command groups 3 and 4 are reserved and should never be used.  */
const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, 12, 12, 10, 10 };

Linus Torvalds's avatar
Linus Torvalds committed
75
#define INTERNAL_ERROR (panic ("Internal error in file %s, line %d.\n", __FILE__, __LINE__))
76

Linus Torvalds's avatar
Linus Torvalds committed
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
/*
 * PAGE_SIZE must be a multiple of the sector size (512).  True
 * for all reasonably recent architectures (even the VAX...).
 */
#define SECTOR_SIZE		512
#define SECTORS_PER_PAGE	(PAGE_SIZE/SECTOR_SIZE)

#if SECTORS_PER_PAGE <= 8
 typedef unsigned char	FreeSectorBitmap;
#elif SECTORS_PER_PAGE <= 32
 typedef unsigned int	FreeSectorBitmap;
#else
# error You lose.
#endif

92
static void scsi_done (Scsi_Cmnd *SCpnt);
Linus Torvalds's avatar
Linus Torvalds committed
93
int update_timeout (Scsi_Cmnd *, int);
94
static void print_inquiry(unsigned char *data);
Linus Torvalds's avatar
Linus Torvalds committed
95
static void scsi_times_out (Scsi_Cmnd * SCpnt);
Linus Torvalds's avatar
Linus Torvalds committed
96
static int scan_scsis_single (int channel,int dev,int lun,int * max_scsi_dev ,
Linus Torvalds's avatar
Linus Torvalds committed
97
                 int * sparse_lun, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt,
Linus Torvalds's avatar
Linus Torvalds committed
98
                 struct Scsi_Host *shpnt, char * scsi_result);
Linus Torvalds's avatar
Linus Torvalds committed
99
void scsi_build_commandblocks(Scsi_Device * SDpnt);
Linus Torvalds's avatar
Linus Torvalds committed
100

Linus Torvalds's avatar
Linus Torvalds committed
101
static FreeSectorBitmap * dma_malloc_freelist = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
102 103 104 105 106 107
static int scsi_need_isa_bounce_buffers;
static unsigned int dma_sectors = 0;
unsigned int dma_free_sectors = 0;
unsigned int need_isa_buffer = 0;
static unsigned char ** dma_malloc_pages = NULL;

108 109
static int time_start;
static int time_elapsed;
Linus Torvalds's avatar
Linus Torvalds committed
110 111
static volatile struct Scsi_Host * host_active = NULL;
#define SCSI_BLOCK(HOST) ((HOST->block && host_active && HOST != host_active) \
Linus Torvalds's avatar
Linus Torvalds committed
112
			  || (HOST->can_queue && HOST->host_busy >= HOST->can_queue))
113

Linus Torvalds's avatar
Linus Torvalds committed
114 115
const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
{
Linus Torvalds's avatar
Linus Torvalds committed
116 117 118 119 120 121 122 123 124 125
    "Direct-Access    ",
    "Sequential-Access",
    "Printer          ",
    "Processor        ",
    "WORM             ",
    "CD-ROM           ",
    "Scanner          ",
    "Optical Device   ",
    "Medium Changer   ",
    "Communications   "
Linus Torvalds's avatar
Linus Torvalds committed
126 127 128
};


129
/*
Linus Torvalds's avatar
Linus Torvalds committed
130 131 132 133
 * global variables :
 * scsi_devices an array of these specifying the address for each
 * (host, id, LUN)
 */
Linus Torvalds's avatar
Linus Torvalds committed
134

135 136
Scsi_Device * scsi_devices = NULL;

Linus Torvalds's avatar
Linus Torvalds committed
137 138 139
/* Process ID of SCSI commands */
unsigned long scsi_pid = 0;

Linus Torvalds's avatar
Linus Torvalds committed
140 141
static unsigned long serial_number = 0;

142
static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
Linus Torvalds's avatar
Linus Torvalds committed
143
static void resize_dma_pool(void);
144

Linus Torvalds's avatar
Linus Torvalds committed
145 146
/* This variable is merely a hook so that we can debug the kernel with gdb. */
Scsi_Cmnd * last_cmnd = NULL;
147

Linus Torvalds's avatar
Linus Torvalds committed
148 149 150 151 152 153 154 155
/* This is the pointer to the /proc/scsi code.
 * It is only initialized to !=0 if the scsi code is present
 */
#if CONFIG_PROC_FS
extern int (* dispatch_scsi_info_ptr)(int ino, char *buffer, char **start,
				      off_t offset, int length, int inout);
extern int dispatch_scsi_info(int ino, char *buffer, char **start,
			      off_t offset, int length, int inout);
Linus Torvalds's avatar
Linus Torvalds committed
156

Linus Torvalds's avatar
Linus Torvalds committed
157 158
struct proc_dir_entry proc_scsi_scsi = {
    PROC_SCSI_SCSI, 4, "scsi",
Linus Torvalds's avatar
Linus Torvalds committed
159
    S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0,
Linus Torvalds's avatar
Linus Torvalds committed
160 161 162 163
    NULL,
    NULL, NULL,
    NULL, NULL, NULL
};
Linus Torvalds's avatar
Linus Torvalds committed
164
#endif
Linus Torvalds's avatar
Linus Torvalds committed
165

166
/*
Linus Torvalds's avatar
Linus Torvalds committed
167 168 169 170
 *  This is the number  of clock ticks we should wait before we time out
 *  and abort the command.  This is for  where the scsi.c module generates
 *  the command, not where it originates from a higher level, in which
 *  case the timeout is specified there.
171
 *
Linus Torvalds's avatar
Linus Torvalds committed
172 173
 *  ABORT_TIMEOUT and RESET_TIMEOUT are the timeouts for RESET and ABORT
 *  respectively.
174 175
 */

Linus Torvalds's avatar
Linus Torvalds committed
176 177 178 179 180
#ifdef DEBUG_TIMEOUT
static void scsi_dump_status(void);
#endif


181
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
182
    #define SCSI_TIMEOUT (5*HZ)
183
#else
Linus Torvalds's avatar
Linus Torvalds committed
184
    #define SCSI_TIMEOUT (2*HZ)
185 186 187
#endif

#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
188 189 190
    #define SENSE_TIMEOUT SCSI_TIMEOUT
    #define ABORT_TIMEOUT SCSI_TIMEOUT
    #define RESET_TIMEOUT SCSI_TIMEOUT
191
#else
Linus Torvalds's avatar
Linus Torvalds committed
192 193 194
    #define SENSE_TIMEOUT (5*HZ/10)
    #define RESET_TIMEOUT (5*HZ/10)
    #define ABORT_TIMEOUT (5*HZ/10)
195 196
#endif

Linus Torvalds's avatar
Linus Torvalds committed
197
#define MIN_RESET_DELAY (2*HZ)
Linus Torvalds's avatar
Linus Torvalds committed
198

Linus Torvalds's avatar
Linus Torvalds committed
199
/* Do not call reset on error if we just did a reset within 15 sec. */
Linus Torvalds's avatar
Linus Torvalds committed
200
#define MIN_RESET_PERIOD (15*HZ)
Linus Torvalds's avatar
Linus Torvalds committed
201

202
/* The following devices are known not to tolerate a lun != 0 scan for
Linus Torvalds's avatar
Linus Torvalds committed
203
 * one reason or another.  Some will respond to all luns, others will
Linus Torvalds's avatar
Linus Torvalds committed
204
 * lock up.
Linus Torvalds's avatar
Linus Torvalds committed
205
 */
206

Linus Torvalds's avatar
Linus Torvalds committed
207 208 209 210 211
#define BLIST_NOLUN     0x01
#define BLIST_FORCELUN  0x02
#define BLIST_BORKEN    0x04
#define BLIST_KEY       0x08
#define BLIST_SINGLELUN 0x10
Linus Torvalds's avatar
Linus Torvalds committed
212
#define BLIST_NOTQ	0x20
Linus Torvalds's avatar
Linus Torvalds committed
213
#define BLIST_SPARSELUN 0x40
Linus Torvalds's avatar
Linus Torvalds committed
214 215

struct dev_info{
Linus Torvalds's avatar
Linus Torvalds committed
216 217 218
    const char * vendor;
    const char * model;
    const char * revision; /* Latest revision known to be bad.  Not used yet */
Linus Torvalds's avatar
Linus Torvalds committed
219
    unsigned flags;
Linus Torvalds's avatar
Linus Torvalds committed
220
};
221

Linus Torvalds's avatar
Linus Torvalds committed
222 223
/*
 * This is what was previously known as the blacklist.  The concept
Linus Torvalds's avatar
Linus Torvalds committed
224 225
 * has been expanded so that we can specify other types of things we
 * need to be aware of.
Linus Torvalds's avatar
Linus Torvalds committed
226 227
 */
static struct dev_info device_list[] =
Linus Torvalds's avatar
Linus Torvalds committed
228
{
Linus Torvalds's avatar
Linus Torvalds committed
229 230 231 232 233 234 235 236 237 238 239
{"CHINON","CD-ROM CDS-431","H42", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
{"CHINON","CD-ROM CDS-535","Q14", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
{"DENON","DRD-25X","V", BLIST_NOLUN},           /* Locks up if probed for lun != 0 */
{"HITACHI","DK312C","CM81", BLIST_NOLUN},       /* Responds to all lun - dtg */
{"HITACHI","DK314C","CR21" , BLIST_NOLUN},      /* responds to all lun */
{"IMS", "CDD521/10","2.06", BLIST_NOLUN},       /* Locks-up when LUN>0 polled. */
{"MAXTOR","XT-3280","PR02", BLIST_NOLUN},       /* Locks-up when LUN>0 polled. */
{"MAXTOR","XT-4380S","B3C", BLIST_NOLUN},       /* Locks-up when LUN>0 polled. */
{"MAXTOR","MXT-1240S","I1.2", BLIST_NOLUN},     /* Locks up when LUN>0 polled */
{"MAXTOR","XT-4170S","B5A", BLIST_NOLUN},       /* Locks-up sometimes when LUN>0 polled. */
{"MAXTOR","XT-8760S","B7B", BLIST_NOLUN},       /* guess what? */
Linus Torvalds's avatar
Linus Torvalds committed
240
{"MEDIAVIS","RENO CD-ROMX2A","2.03",BLIST_NOLUN},/*Responds to all lun */
Linus Torvalds's avatar
Linus Torvalds committed
241
{"MICROP", "4110", "*", BLIST_NOTQ},		/* Buggy Tagged Queuing */
Linus Torvalds's avatar
Linus Torvalds committed
242 243
{"NEC","CD-ROM DRIVE:841","1.0", BLIST_NOLUN},  /* Locks-up when LUN>0 polled. */
{"RODIME","RO3000S","2.33", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
Linus Torvalds's avatar
Linus Torvalds committed
244 245
{"SANYO", "CRD-250S", "1.20", BLIST_NOLUN},     /* causes failed REQUEST SENSE on lun 1
						 * for aha152x controller, which causes
Linus Torvalds's avatar
Linus Torvalds committed
246
						 * SCSI code to reset bus.*/
Linus Torvalds's avatar
Linus Torvalds committed
247 248
{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN},   /* causes failed REQUEST SENSE on lun 1
						 * for aha152x controller, which causes
Linus Torvalds's avatar
Linus Torvalds committed
249
						 * SCSI code to reset bus.*/
Linus Torvalds's avatar
Linus Torvalds committed
250
{"SEAGATE", "ST296","921", BLIST_NOLUN},        /* Responds to all lun */
Linus Torvalds's avatar
Linus Torvalds committed
251
{"SEAGATE","ST1581","6538",BLIST_NOLUN},	/* Responds to all lun */
Linus Torvalds's avatar
Linus Torvalds committed
252 253 254 255
{"SONY","CD-ROM CDU-541","4.3d", BLIST_NOLUN},
{"SONY","CD-ROM CDU-55S","1.0i", BLIST_NOLUN},
{"SONY","CD-ROM CDU-561","1.7x", BLIST_NOLUN},
{"TANDBERG","TDC 3600","U07", BLIST_NOLUN},     /* Locks up if polled for lun != 0 */
Linus Torvalds's avatar
Linus Torvalds committed
256 257
{"TEAC","CD-ROM","1.06", BLIST_NOLUN},          /* causes failed REQUEST SENSE on lun 1
						 * for seagate controller, which causes
Linus Torvalds's avatar
Linus Torvalds committed
258
						 * SCSI code to reset bus.*/
Linus Torvalds's avatar
Linus Torvalds committed
259 260
{"TEXEL","CD-ROM","1.06", BLIST_NOLUN},         /* causes failed REQUEST SENSE on lun 1
						 * for seagate controller, which causes
Linus Torvalds's avatar
Linus Torvalds committed
261
						 * SCSI code to reset bus.*/
Linus Torvalds's avatar
Linus Torvalds committed
262 263 264 265 266 267 268
{"QUANTUM","LPS525S","3110", BLIST_NOLUN},      /* Locks sometimes if polled for lun != 0 */
{"QUANTUM","PD1225S","3110", BLIST_NOLUN},      /* Locks sometimes if polled for lun != 0 */
{"MEDIAVIS","CDR-H93MV","1.31", BLIST_NOLUN},   /* Locks up if polled for lun != 0 */
{"SANKYO", "CP525","6.64", BLIST_NOLUN},        /* causes failed REQ SENSE, extra reset */
{"HP", "C1750A", "3226", BLIST_NOLUN},          /* scanjet iic */
{"HP", "C1790A", "", BLIST_NOLUN},              /* scanjet iip */
{"HP", "C2500A", "", BLIST_NOLUN},              /* scanjet iicx */
Linus Torvalds's avatar
Linus Torvalds committed
269
{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},	/* extra reset */
Linus Torvalds's avatar
Linus Torvalds committed
270 271 272 273 274 275

/*
 * Other types of devices that have special flags.
 */
{"SONY","CD-ROM CDU-8001","*", BLIST_BORKEN},
{"TEXEL","CD-ROM","1.06", BLIST_BORKEN},
Linus Torvalds's avatar
Linus Torvalds committed
276
{"IOMEGA","Io20S         *F","*", BLIST_KEY},
Linus Torvalds's avatar
Linus Torvalds committed
277 278
{"INSITE","Floptical   F*8I","*", BLIST_KEY},
{"INSITE","I325VM","*", BLIST_KEY},
Linus Torvalds's avatar
Linus Torvalds committed
279
{"NRC","MBR-7","*", BLIST_FORCELUN | BLIST_SINGLELUN},
Linus Torvalds's avatar
Linus Torvalds committed
280 281
{"NRC","MBR-7.4","*", BLIST_FORCELUN | BLIST_SINGLELUN},
{"NAKAMICH","MJ-4.8S","*", BLIST_FORCELUN | BLIST_SINGLELUN},
Linus Torvalds's avatar
Linus Torvalds committed
282 283
{"PIONEER","CD-ROM DRM-602X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
{"PIONEER","CD-ROM DRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
Linus Torvalds's avatar
Linus Torvalds committed
284 285
{"EMULEX","MD21/S2     ESDI","*", BLIST_SINGLELUN},
{"CANON","IPUBJD","*", BLIST_SPARSELUN},
Linus Torvalds's avatar
Linus Torvalds committed
286
{"MATSHITA","PD","*", BLIST_FORCELUN | BLIST_SINGLELUN},
Linus Torvalds's avatar
Linus Torvalds committed
287
{"YAMAHA","CDR100","1.00", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
Linus Torvalds's avatar
Linus Torvalds committed
288
{"YAMAHA","CDR102","1.00", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
Linus Torvalds's avatar
Linus Torvalds committed
289 290 291
/*
 * Must be at end of list...
 */
Linus Torvalds's avatar
Linus Torvalds committed
292 293
{NULL, NULL, NULL}
};
294

Linus Torvalds's avatar
Linus Torvalds committed
295
static int get_device_flags(unsigned char * response_data){
Linus Torvalds's avatar
Linus Torvalds committed
296 297 298
    int i = 0;
    unsigned char * pnt;
    for(i=0; 1; i++){
Linus Torvalds's avatar
Linus Torvalds committed
299
	if(device_list[i].vendor == NULL) return 0;
Linus Torvalds's avatar
Linus Torvalds committed
300 301
	pnt = &response_data[8];
	while(*pnt && *pnt == ' ') pnt++;
Linus Torvalds's avatar
Linus Torvalds committed
302 303
	if(memcmp(device_list[i].vendor, pnt,
		  strlen(device_list[i].vendor))) continue;
Linus Torvalds's avatar
Linus Torvalds committed
304 305
	pnt = &response_data[16];
	while(*pnt && *pnt == ' ') pnt++;
Linus Torvalds's avatar
Linus Torvalds committed
306 307 308
	if(memcmp(device_list[i].model, pnt,
		  strlen(device_list[i].model))) continue;
	return device_list[i].flags;
Linus Torvalds's avatar
Linus Torvalds committed
309
    }
Linus Torvalds's avatar
Linus Torvalds committed
310
    return 0;
Linus Torvalds's avatar
Linus Torvalds committed
311
}
312

Linus Torvalds's avatar
Linus Torvalds committed
313
void scsi_make_blocked_list(void)  {
Linus Torvalds's avatar
Linus Torvalds committed
314
    int block_count = 0, index;
Linus Torvalds's avatar
Linus Torvalds committed
315
    unsigned long flags;
Linus Torvalds's avatar
Linus Torvalds committed
316
    struct Scsi_Host * sh[128], * shpnt;
Linus Torvalds's avatar
Linus Torvalds committed
317

Linus Torvalds's avatar
Linus Torvalds committed
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
    /*
     * Create a circular linked list from the scsi hosts which have
     * the "wish_block" field in the Scsi_Host structure set.
     * The blocked list should include all the scsi hosts using ISA DMA.
     * In some systems, using two dma channels simultaneously causes
     * unpredictable results.
     * Among the scsi hosts in the blocked list, only one host at a time
     * is allowed to have active commands queued. The transition from
     * one active host to the next one is allowed only when host_busy == 0
     * for the active host (which implies host_busy == 0 for all the hosts
     * in the list). Moreover for block devices the transition to a new
     * active host is allowed only when a request is completed, since a
     * block device request can be divided into multiple scsi commands
     * (when there are few sg lists or clustering is disabled).
     *
     * (DB, 4 Feb 1995)
     */
Linus Torvalds's avatar
Linus Torvalds committed
335

Linus Torvalds's avatar
Linus Torvalds committed
336 337 338
    save_flags(flags);
    cli();
    host_active = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
339

Linus Torvalds's avatar
Linus Torvalds committed
340
    for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) {
Linus Torvalds's avatar
Linus Torvalds committed
341

Linus Torvalds's avatar
Linus Torvalds committed
342
#if 0
Linus Torvalds's avatar
Linus Torvalds committed
343 344 345 346 347 348
	/*
	 * Is this is a candidate for the blocked list?
	 * Useful to put into the blocked list all the hosts whose driver
	 * does not know about the host->block feature.
	 */
	if (shpnt->unchecked_isa_dma) shpnt->wish_block = 1;
Linus Torvalds's avatar
Linus Torvalds committed
349
#endif
Linus Torvalds's avatar
Linus Torvalds committed
350

Linus Torvalds's avatar
Linus Torvalds committed
351 352
	if (shpnt->wish_block) sh[block_count++] = shpnt;
    }
Linus Torvalds's avatar
Linus Torvalds committed
353

Linus Torvalds's avatar
Linus Torvalds committed
354
    if (block_count == 1) sh[0]->block = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
355

Linus Torvalds's avatar
Linus Torvalds committed
356 357 358 359 360 361 362
    else if (block_count > 1) {
	
	for(index = 0; index < block_count - 1; index++) {
	    sh[index]->block = sh[index + 1];
	    printk("scsi%d : added to blocked host list.\n",
		   sh[index]->host_no);
	}
Linus Torvalds's avatar
Linus Torvalds committed
363

Linus Torvalds's avatar
Linus Torvalds committed
364
	sh[block_count - 1]->block = sh[0];
Linus Torvalds's avatar
Linus Torvalds committed
365 366
	printk("scsi%d : added to blocked host list.\n",
	       sh[index]->host_no);
Linus Torvalds's avatar
Linus Torvalds committed
367
    }
Linus Torvalds's avatar
Linus Torvalds committed
368

Linus Torvalds's avatar
Linus Torvalds committed
369 370
    restore_flags(flags);
}
Linus Torvalds's avatar
Linus Torvalds committed
371

372
static void scan_scsis_done (Scsi_Cmnd * SCpnt)
Linus Torvalds's avatar
Linus Torvalds committed
373
{
Linus Torvalds's avatar
Linus Torvalds committed
374

375
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
376
    printk ("scan_scsis_done(%p, %06x)\n", SCpnt->host, SCpnt->result);
Linus Torvalds's avatar
Linus Torvalds committed
377
#endif
Linus Torvalds's avatar
Linus Torvalds committed
378
    SCpnt->request.rq_status = RQ_SCSI_DONE;
Linus Torvalds's avatar
Linus Torvalds committed
379

Linus Torvalds's avatar
Linus Torvalds committed
380 381 382
    if (SCpnt->request.sem != NULL)
	up(SCpnt->request.sem);
}
Linus Torvalds's avatar
Linus Torvalds committed
383

Linus Torvalds's avatar
Linus Torvalds committed
384
#ifdef CONFIG_SCSI_MULTI_LUN
Linus Torvalds's avatar
Linus Torvalds committed
385
static int max_scsi_luns = 8;
Linus Torvalds's avatar
Linus Torvalds committed
386 387
#else
static int max_scsi_luns = 1;
Linus Torvalds's avatar
Linus Torvalds committed
388 389 390
#endif

void scsi_luns_setup(char *str, int *ints) {
Linus Torvalds's avatar
Linus Torvalds committed
391
    if (ints[0] != 1)
Linus Torvalds's avatar
Linus Torvalds committed
392 393
	printk("scsi_luns_setup : usage max_scsi_luns=n (n should be between 1 and 8)\n");
    else
Linus Torvalds's avatar
Linus Torvalds committed
394
	max_scsi_luns = ints[1];
Linus Torvalds's avatar
Linus Torvalds committed
395 396
}

397
/*
Linus Torvalds's avatar
Linus Torvalds committed
398
 *  Detecting SCSI devices :
Linus Torvalds's avatar
Linus Torvalds committed
399
 *  We scan all present host adapter's busses,  from ID 0 to ID (max_id).
Linus Torvalds's avatar
Linus Torvalds committed
400 401 402
 *  We use the INQUIRY command, determine device type, and pass the ID /
 *  lun address of all sequential devices to the tape driver, all random
 *  devices to the disk driver.
403
 */
Linus Torvalds's avatar
Linus Torvalds committed
404 405
static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded,
                 unchar hchannel, unchar hid, unchar hlun)
406
{
Linus Torvalds's avatar
Linus Torvalds committed
407 408 409 410
  int dev, lun, channel;
  unsigned char scsi_result0[256];
  unsigned char *scsi_result;
  Scsi_Device *SDpnt;
Linus Torvalds's avatar
Linus Torvalds committed
411
  int max_dev_lun, sparse_lun;
Linus Torvalds's avatar
Linus Torvalds committed
412
  Scsi_Cmnd *SCpnt;
Linus Torvalds's avatar
Linus Torvalds committed
413

Linus Torvalds's avatar
Linus Torvalds committed
414 415
  SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), GFP_ATOMIC | GFP_DMA);
  SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
Linus Torvalds's avatar
Linus Torvalds committed
416 417
  memset (SCpnt, 0, sizeof (Scsi_Cmnd));

Linus Torvalds's avatar
Linus Torvalds committed
418 419

  /* Make sure we have something that is valid for DMA purposes */
Linus Torvalds's avatar
Linus Torvalds committed
420 421
  scsi_result = ( ( !shpnt->unchecked_isa_dma )
                 ? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA));
Linus Torvalds's avatar
Linus Torvalds committed
422 423 424 425 426 427

  if (scsi_result == NULL) {
    printk ("Unable to obtain scsi_result buffer\n");
    goto leave;
  }

Linus Torvalds's avatar
Linus Torvalds committed
428 429 430 431 432 433 434
  /* We must chain ourself in the host_queue, so commands can time out */
  if(shpnt->host_queue)
      shpnt->host_queue->prev = SCpnt;
  SCpnt->next = shpnt->host_queue;
  SCpnt->prev = NULL;
  shpnt->host_queue = SCpnt;

Linus Torvalds's avatar
Linus Torvalds committed
435 436

  if (hardcoded == 1) {
Linus Torvalds's avatar
Linus Torvalds committed
437 438
    Scsi_Device *oldSDpnt=SDpnt;
    struct Scsi_Device_Template * sdtpnt;
Linus Torvalds's avatar
Linus Torvalds committed
439 440 441 442 443 444
    channel = hchannel;
    if(channel > shpnt->max_channel) goto leave;
    dev = hid;
    if(dev >= shpnt->max_id) goto leave;
    lun = hlun;
    if(lun >= shpnt->max_lun) goto leave;
Linus Torvalds's avatar
Linus Torvalds committed
445 446
    scan_scsis_single (channel, dev, lun, &max_dev_lun, &sparse_lun,
		       &SDpnt, SCpnt, shpnt, scsi_result);
Linus Torvalds's avatar
Linus Torvalds committed
447 448 449 450 451 452 453 454 455 456 457 458
    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)();

            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();
Linus Torvalds's avatar
Linus Torvalds committed
459

Linus Torvalds's avatar
Linus Torvalds committed
460 461 462 463 464 465
        for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
            if(sdtpnt->finish && sdtpnt->nr_dev)
                {(*sdtpnt->finish)();}
	}
    }

Linus Torvalds's avatar
Linus Torvalds committed
466 467 468 469 470
  }
  else {
    for (channel = 0; channel <= shpnt->max_channel; channel++) {
      for (dev = 0; dev < shpnt->max_id; ++dev) {
        if (shpnt->this_id != dev) {
Linus Torvalds's avatar
Linus Torvalds committed
471

Linus Torvalds's avatar
Linus Torvalds committed
472 473 474 475 476 477 478
          /*
           * We need the for so our continue, etc. work fine. We put this in
           * a variable so that we can override it during the scan if we
           * detect a device *KNOWN* to have multiple logical units.
           */
          max_dev_lun = (max_scsi_luns < shpnt->max_lun ?
                         max_scsi_luns : shpnt->max_lun);
Linus Torvalds's avatar
Linus Torvalds committed
479
	  sparse_lun = 0;
Linus Torvalds's avatar
Linus Torvalds committed
480 481
          for (lun = 0; lun < max_dev_lun; ++lun) {
            if (!scan_scsis_single (channel, dev, lun, &max_dev_lun,
Linus Torvalds's avatar
Linus Torvalds committed
482 483 484
				    &sparse_lun, &SDpnt, SCpnt, shpnt,
				    scsi_result)
		&& !sparse_lun)
Linus Torvalds's avatar
Linus Torvalds committed
485
              break; /* break means don't probe further for luns!=0 */
Linus Torvalds's avatar
Linus Torvalds committed
486 487 488 489
          }                     /* for lun ends */
        }                       /* if this_id != id ends */
      }                         /* for dev ends */
    }                           /* for channel ends */
Linus Torvalds's avatar
Linus Torvalds committed
490 491 492 493 494
  } 				/* if/else hardcoded */

  leave:

  {/* Unchain SCpnt from host_queue */
Linus Torvalds's avatar
Linus Torvalds committed
495 496
    Scsi_Cmnd *prev, *next, *hqptr;
    for(hqptr = shpnt->host_queue; hqptr != SCpnt; hqptr = hqptr->next) ;
Linus Torvalds's avatar
Linus Torvalds committed
497
    if(hqptr) {
Linus Torvalds's avatar
Linus Torvalds committed
498 499
      prev = hqptr->prev;
      next = hqptr->next;
Linus Torvalds's avatar
Linus Torvalds committed
500
      if(prev)
Linus Torvalds's avatar
Linus Torvalds committed
501
     	prev->next = next;
Linus Torvalds's avatar
Linus Torvalds committed
502
      else
Linus Torvalds's avatar
Linus Torvalds committed
503 504
     	shpnt->host_queue = next;
      if(next) next->prev = prev;
Linus Torvalds's avatar
Linus Torvalds committed
505 506
    }
  }
Linus Torvalds's avatar
Linus Torvalds committed
507

Linus Torvalds's avatar
Linus Torvalds committed
508 509 510 511 512 513
     /* Last device block does not exist.  Free memory. */
    if (SDpnt != NULL)
      scsi_init_free ((char *) SDpnt, sizeof (Scsi_Device));

    if (SCpnt != NULL)
      scsi_init_free ((char *) SCpnt, sizeof (Scsi_Cmnd));
Linus Torvalds's avatar
Linus Torvalds committed
514

Linus Torvalds's avatar
Linus Torvalds committed
515 516
    /* If we allocated a buffer so we could do DMA, free it now */
    if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
Linus Torvalds's avatar
Linus Torvalds committed
517
      scsi_init_free (scsi_result, 512);
Linus Torvalds's avatar
Linus Torvalds committed
518

Linus Torvalds's avatar
Linus Torvalds committed
519
}
Linus Torvalds's avatar
Linus Torvalds committed
520

Linus Torvalds's avatar
Linus Torvalds committed
521 522 523
/*
 * The worker for scan_scsis.
 * Returning 0 means Please don't ask further for lun!=0, 1 means OK go on.
Linus Torvalds's avatar
Linus Torvalds committed
524
 * Global variables used : scsi_devices(linked list)
Linus Torvalds's avatar
Linus Torvalds committed
525 526
 */
int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
Linus Torvalds's avatar
Linus Torvalds committed
527 528
    int *sparse_lun, Scsi_Device **SDpnt2, Scsi_Cmnd * SCpnt,
    struct Scsi_Host * shpnt, char *scsi_result)
Linus Torvalds's avatar
Linus Torvalds committed
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
{
  unsigned char scsi_cmd[12];
  struct Scsi_Device_Template *sdtpnt;
  Scsi_Device * SDtail, *SDpnt=*SDpnt2;
  int bflags, type=-1;

  SDtail = scsi_devices;
  if (scsi_devices)
    while (SDtail->next)
      SDtail = SDtail->next;

  memset (SDpnt, 0, sizeof (Scsi_Device));
  SDpnt->host = shpnt;
  SDpnt->id = dev;
  SDpnt->lun = lun;
  SDpnt->channel = channel;

  /* Some low level driver could use device->type (DB) */
  SDpnt->type = -1;

  /*
   * Assume that the device will have handshaking problems, and then fix this
   * field later if it turns out it doesn't
   */
  SDpnt->borken = 1;
  SDpnt->was_reset = 0;
  SDpnt->expecting_cc_ua = 0;

  scsi_cmd[0] = TEST_UNIT_READY;
  scsi_cmd[1] = lun << 5;
  scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;

  SCpnt->host = SDpnt->host;
  SCpnt->device = SDpnt;
  SCpnt->target = SDpnt->id;
  SCpnt->lun = SDpnt->lun;
  SCpnt->channel = SDpnt->channel;
  {
    struct semaphore sem = MUTEX_LOCKED;
    SCpnt->request.sem = &sem;
    SCpnt->request.rq_status = RQ_SCSI_BUSY;
    scsi_do_cmd (SCpnt, (void *) scsi_cmd,
                 (void *) scsi_result,
                 256, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
    down (&sem);
  }
Linus Torvalds's avatar
Linus Torvalds committed
575

576
#if defined(DEBUG) || defined(DEBUG_INIT)
Linus Torvalds's avatar
Linus Torvalds committed
577
  printk ("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n",
Linus Torvalds's avatar
Linus Torvalds committed
578
          dev, lun, SCpnt->result);
Linus Torvalds's avatar
Linus Torvalds committed
579 580
  print_driverbyte(SCpnt->result); print_hostbyte(SCpnt->result);
  printk("\n");
581
#endif
Linus Torvalds's avatar
Linus Torvalds committed
582

Linus Torvalds's avatar
Linus Torvalds committed
583
  if (SCpnt->result) {
Linus Torvalds's avatar
Linus Torvalds committed
584 585 586 587
    if (((driver_byte (SCpnt->result) & DRIVER_SENSE) ||
         (status_byte (SCpnt->result) & CHECK_CONDITION)) &&
        ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) {
      if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
Linus Torvalds's avatar
Linus Torvalds committed
588
          ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) &&
Linus Torvalds's avatar
Linus Torvalds committed
589
          ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST || lun > 0))
Linus Torvalds's avatar
Linus Torvalds committed
590 591 592 593 594 595
        return 1;
    }
    else
      return 0;
  }

596
#if defined (DEBUG) || defined(DEBUG_INIT)
Linus Torvalds's avatar
Linus Torvalds committed
597
  printk ("scsi: performing INQUIRY\n");
Linus Torvalds's avatar
Linus Torvalds committed
598
#endif
Linus Torvalds's avatar
Linus Torvalds committed
599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618
  /*
   * Build an INQUIRY command block.
   */
  scsi_cmd[0] = INQUIRY;
  scsi_cmd[1] = (lun << 5) & 0xe0;
  scsi_cmd[2] = 0;
  scsi_cmd[3] = 0;
  scsi_cmd[4] = 255;
  scsi_cmd[5] = 0;
  SCpnt->cmd_len = 0;
  {
    struct semaphore sem = MUTEX_LOCKED;
    SCpnt->request.sem = &sem;
    SCpnt->request.rq_status = RQ_SCSI_BUSY;
    scsi_do_cmd (SCpnt, (void *) scsi_cmd,
                 (void *) scsi_result,
                 256, scan_scsis_done, SCSI_TIMEOUT, 3);
    down (&sem);
  }

Linus Torvalds's avatar
Linus Torvalds committed
619
#if defined(DEBUG) || defined(DEBUG_INIT)
Linus Torvalds's avatar
Linus Torvalds committed
620
  printk ("scsi: INQUIRY %s with code 0x%x\n",
Linus Torvalds's avatar
Linus Torvalds committed
621
          SCpnt->result ? "failed" : "successful", SCpnt->result);
Linus Torvalds's avatar
Linus Torvalds committed
622 623
#endif

Linus Torvalds's avatar
Linus Torvalds committed
624
  if (SCpnt->result)
Linus Torvalds's avatar
Linus Torvalds committed
625 626
    return 0;     /* assume no peripheral if any sort of error */

Linus Torvalds's avatar
Linus Torvalds committed
627 628 629 630 631 632 633 634 635
  /*
   * Check the peripheral qualifier field - this tells us whether LUNS
   * are supported here or not.
   */
  if( (scsi_result[0] >> 5) == 3 )
    {
      return 0;     /* assume no peripheral if any sort of error */
    }

Linus Torvalds's avatar
Linus Torvalds committed
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707
  /*
   * It would seem some TOSHIBA CDROM gets things wrong
   */
  if (!strncmp (scsi_result + 8, "TOSHIBA", 7) &&
      !strncmp (scsi_result + 16, "CD-ROM", 6) &&
      scsi_result[0] == TYPE_DISK) {
    scsi_result[0] = TYPE_ROM;
    scsi_result[1] |= 0x80;     /* removable */
  }

  memcpy (SDpnt->vendor, scsi_result + 8, 8);
  memcpy (SDpnt->model, scsi_result + 16, 16);
  memcpy (SDpnt->rev, scsi_result + 32, 4);

  SDpnt->removable = (0x80 & scsi_result[1]) >> 7;
  SDpnt->lockable = SDpnt->removable;
  SDpnt->changed = 0;
  SDpnt->access_count = 0;
  SDpnt->busy = 0;
  SDpnt->has_cmdblocks = 0;
  /*
   * Currently, all sequential devices are assumed to be tapes, all random
   * devices disk, with the appropriate read only flags set for ROM / WORM
   * treated as RO.
   */
  switch (type = (scsi_result[0] & 0x1f)) {
  case TYPE_TAPE:
  case TYPE_DISK:
  case TYPE_MOD:
  case TYPE_PROCESSOR:
  case TYPE_SCANNER:
    SDpnt->writeable = 1;
    break;
  case TYPE_WORM:
  case TYPE_ROM:
    SDpnt->writeable = 0;
    break;
  default:
    printk ("scsi: unknown type %d\n", type);
  }

  SDpnt->single_lun = 0;
  SDpnt->soft_reset =
    (scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2);
  SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;
  SDpnt->type = (type & 0x1f);

  print_inquiry (scsi_result);

  for (sdtpnt = scsi_devicelist; sdtpnt;
       sdtpnt = sdtpnt->next)
    if (sdtpnt->detect)
      SDpnt->attached +=
        (*sdtpnt->detect) (SDpnt);

  SDpnt->scsi_level = scsi_result[2] & 0x07;
  if (SDpnt->scsi_level >= 2 ||
      (SDpnt->scsi_level == 1 &&
       (scsi_result[3] & 0x0f) == 1))
    SDpnt->scsi_level++;

  /*
   * Accommodate drivers that want to sleep when they should be in a polling
   * loop.
   */
  SDpnt->disconnect = 0;

  /*
   * Get any flags for this device.
   */
  bflags = get_device_flags (scsi_result);

Linus Torvalds's avatar
Linus Torvalds committed
708 709 710 711 712 713 714 715 716 717 718 719
  /*
   * Set the tagged_queue flag for SCSI-II devices that purport to support
   * tagged queuing in the INQUIRY data.
   */
  SDpnt->tagged_queue = 0;
  if ((SDpnt->scsi_level >= SCSI_2) &&
      (scsi_result[7] & 2) &&
      !(bflags & BLIST_NOTQ)) {
    SDpnt->tagged_supported = 1;
    SDpnt->current_tag = 0;
  }

Linus Torvalds's avatar
Linus Torvalds committed
720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761
  /*
   * Some revisions of the Texel CD ROM drives have handshaking problems when
   * used with the Seagate controllers.  Before we know what type of device
   * we're talking to, we assume it's borken and then change it here if it
   * turns out that it isn't a TEXEL drive.
   */
  if ((bflags & BLIST_BORKEN) == 0)
    SDpnt->borken = 0;

  /*
   * These devices need this "key" to unlock the devices so we can use it
   */
  if ((bflags & BLIST_KEY) != 0) {
    printk ("Unlocked floptical drive.\n");
    SDpnt->lockable = 0;
    scsi_cmd[0] = MODE_SENSE;
    scsi_cmd[1] = (lun << 5) & 0xe0;
    scsi_cmd[2] = 0x2e;
    scsi_cmd[3] = 0;
    scsi_cmd[4] = 0x2a;
    scsi_cmd[5] = 0;
    SCpnt->cmd_len = 0;
    {
      struct semaphore sem = MUTEX_LOCKED;
      SCpnt->request.rq_status = RQ_SCSI_BUSY;
      SCpnt->request.sem = &sem;
      scsi_do_cmd (SCpnt, (void *) scsi_cmd,
                   (void *) scsi_result, 0x2a,
                   scan_scsis_done, SCSI_TIMEOUT, 3);
      down (&sem);
    }
  }
  /* Add this device to the linked list at the end */
  if (SDtail)
    SDtail->next = SDpnt;
  else
    scsi_devices = SDpnt;
  SDtail = SDpnt;

  SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
  *SDpnt2=SDpnt;
  if (!SDpnt)
Linus Torvalds's avatar
Linus Torvalds committed
762
    printk ("scsi: scan_scsis_single: Cannot malloc\n");
Linus Torvalds's avatar
Linus Torvalds committed
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777


  /*
   * Some scsi devices cannot be polled for lun != 0 due to firmware bugs
   */
  if (bflags & BLIST_NOLUN)
    return 0;                   /* break; */

  /*
   * If we want to only allow I/O to one of the luns attached to this device
   * at a time, then we set this flag.
   */
  if (bflags & BLIST_SINGLELUN)
    SDpnt->single_lun = 1;

Linus Torvalds's avatar
Linus Torvalds committed
778 779 780 781 782 783 784 785 786 787
  /*
   * If this device is known to support sparse multiple units, override the
   * other settings, and scan all of them.
   */
  if (bflags & BLIST_SPARSELUN) {
    *max_dev_lun = 8;
    *sparse_lun = 1;
    return 1;
  }

Linus Torvalds's avatar
Linus Torvalds committed
788 789 790 791
  /*
   * If this device is known to support multiple units, override the other
   * settings, and scan all of them.
   */
Linus Torvalds's avatar
Linus Torvalds committed
792
  if (bflags & BLIST_FORCELUN) {
Linus Torvalds's avatar
Linus Torvalds committed
793
    *max_dev_lun = 8;
Linus Torvalds's avatar
Linus Torvalds committed
794 795
    return 1;
  }
Linus Torvalds's avatar
Linus Torvalds committed
796 797 798 799 800 801 802 803 804 805 806 807
  /*
   * We assume the device can't handle lun!=0 if: - it reports scsi-0 (ANSI
   * SCSI Revision 0) (old drives like MAXTOR XT-3280) or - it reports scsi-1
   * (ANSI SCSI Revision 1) and Response Data Format 0
   */
  if (((scsi_result[2] & 0x07) == 0)
      ||
      ((scsi_result[2] & 0x07) == 1 &&
       (scsi_result[3] & 0x0f) == 0))
    return 0;
  return 1;
}
808 809

/*
Linus Torvalds's avatar
Linus Torvalds committed
810
 *  Flag bits for the internal_timeout array
811 812
 */
#define NORMAL_TIMEOUT 0
Linus Torvalds's avatar
Linus Torvalds committed
813 814
#define IN_ABORT  1
#define IN_RESET  2
Linus Torvalds's avatar
Linus Torvalds committed
815
#define IN_RESET2 4
Linus Torvalds's avatar
Linus Torvalds committed
816
#define IN_RESET3 8
Linus Torvalds's avatar
Linus Torvalds committed
817

818
/*
Linus Torvalds's avatar
Linus Torvalds committed
819 820 821 822
 * This is our time out function, called when the timer expires for a
 * given host adapter.  It will attempt to abort the currently executing
 * command, that failing perform a kernel panic.
 */
823

Linus Torvalds's avatar
Linus Torvalds committed
824
static void scsi_times_out (Scsi_Cmnd * SCpnt)
Linus Torvalds's avatar
Linus Torvalds committed
825
{
Linus Torvalds's avatar
Linus Torvalds committed
826

Linus Torvalds's avatar
Linus Torvalds committed
827
    switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3))
Linus Torvalds's avatar
Linus Torvalds committed
828 829
    {
    case NORMAL_TIMEOUT:
Linus Torvalds's avatar
Linus Torvalds committed
830
	{
Linus Torvalds's avatar
Linus Torvalds committed
831
#ifdef DEBUG_TIMEOUT
Linus Torvalds's avatar
Linus Torvalds committed
832
	    scsi_dump_status();
Linus Torvalds's avatar
Linus Torvalds committed
833
#endif
834
	}
Linus Torvalds's avatar
Linus Torvalds committed
835

Linus Torvalds's avatar
Linus Torvalds committed
836
	if (!scsi_abort (SCpnt, DID_TIME_OUT))
Linus Torvalds's avatar
Linus Torvalds committed
837 838
	    return;
    case IN_ABORT:
Linus Torvalds's avatar
Linus Torvalds committed
839 840
	printk("SCSI host %d abort (pid %ld) timed out - resetting\n",
	       SCpnt->host->host_no, SCpnt->pid);
Linus Torvalds's avatar
Linus Torvalds committed
841
	if (!scsi_reset (SCpnt, SCSI_RESET_ASYNCHRONOUS))
Linus Torvalds's avatar
Linus Torvalds committed
842 843 844 845 846
	    return;
    case IN_RESET:
    case (IN_ABORT | IN_RESET):
	/* This might be controversial, but if there is a bus hang,
	 * you might conceivably want the machine up and running
Linus Torvalds's avatar
Linus Torvalds committed
847
	 * esp if you have an ide disk.
Linus Torvalds's avatar
Linus Torvalds committed
848
	 */
Linus Torvalds's avatar
Linus Torvalds committed
849 850 851
	printk("SCSI host %d channel %d reset (pid %ld) timed out - "
               "trying harder\n",
	       SCpnt->host->host_no, SCpnt->channel, SCpnt->pid);
Linus Torvalds's avatar
Linus Torvalds committed
852
	SCpnt->internal_timeout &= ~IN_RESET;
Linus Torvalds's avatar
Linus Torvalds committed
853 854 855
	SCpnt->internal_timeout |= IN_RESET2;
        scsi_reset (SCpnt,
		    SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET);
Linus Torvalds's avatar
Linus Torvalds committed
856
        return;
Linus Torvalds's avatar
Linus Torvalds committed
857 858 859 860 861 862 863 864 865 866 867 868
    case (IN_ABORT | IN_RESET | IN_RESET2):
	/* Obviously the bus reset didn't work.
	 * Let's try even harder and call for an HBA reset.
         * Maybe the HBA itself crashed and this will shake it loose.
	 */
	printk("SCSI host %d reset (pid %ld) timed out - trying to shake it loose\n",
	       SCpnt->host->host_no, SCpnt->pid);
	SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2);
	SCpnt->internal_timeout |= IN_RESET3;
        scsi_reset (SCpnt,
		    SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_HOST_RESET);
	return;
Linus Torvalds's avatar
Linus Torvalds committed
869

Linus Torvalds's avatar
Linus Torvalds committed
870
    default:
Linus Torvalds's avatar
Linus Torvalds committed
871 872 873 874 875
	printk("SCSI host %d reset (pid %ld) timed out again -\n",
	       SCpnt->host->host_no, SCpnt->pid);
	printk("probably an unrecoverable SCSI bus or device hang.\n");
	return;

Linus Torvalds's avatar
Linus Torvalds committed
876
    }
Linus Torvalds's avatar
Linus Torvalds committed
877

Linus Torvalds's avatar
Linus Torvalds committed
878
}
879

880 881

/* This function takes a quick look at a request, and decides if it
Linus Torvalds's avatar
Linus Torvalds committed
882 883 884
 * can be queued now, or if there would be a stall while waiting for
 * something else to finish.  This routine assumes that interrupts are
 * turned off when entering the routine.  It is the responsibility
Linus Torvalds's avatar
Linus Torvalds committed
885
 * of the calling code to ensure that this is the case.
Linus Torvalds's avatar
Linus Torvalds committed
886
 */
887

Linus Torvalds's avatar
Linus Torvalds committed
888
Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
889
{
Linus Torvalds's avatar
Linus Torvalds committed
890 891
    Scsi_Cmnd * SCpnt = NULL;
    int tablesize;
Linus Torvalds's avatar
Linus Torvalds committed
892
    Scsi_Cmnd * found = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
893
    struct buffer_head * bh, *bhp;
Linus Torvalds's avatar
Linus Torvalds committed
894

Linus Torvalds's avatar
Linus Torvalds committed
895 896
    if (!device)
	panic ("No device passed to request_queueable().\n");
Linus Torvalds's avatar
Linus Torvalds committed
897

Linus Torvalds's avatar
Linus Torvalds committed
898 899
    if (req && req->rq_status == RQ_INACTIVE)
	panic("Inactive in request_queueable");
Linus Torvalds's avatar
Linus Torvalds committed
900 901 902

    /*
     * Look for a free command block.  If we have been instructed not to queue
Linus Torvalds's avatar
Linus Torvalds committed
903
     * multiple commands to multi-lun devices, then check to see what else is
Linus Torvalds's avatar
Linus Torvalds committed
904
     * going for this device first.
Linus Torvalds's avatar
Linus Torvalds committed
905
     */
Linus Torvalds's avatar
Linus Torvalds committed
906

Linus Torvalds's avatar
Linus Torvalds committed
907
    if (!device->single_lun) {
Linus Torvalds's avatar
Linus Torvalds committed
908
	SCpnt = device->device_queue;
Linus Torvalds's avatar
Linus Torvalds committed
909
	while(SCpnt){
Linus Torvalds's avatar
Linus Torvalds committed
910 911
	    if(SCpnt->request.rq_status == RQ_INACTIVE) break;
	    SCpnt = SCpnt->device_next;
Linus Torvalds's avatar
Linus Torvalds committed
912
	}
Linus Torvalds's avatar
Linus Torvalds committed
913
    } else {
Linus Torvalds's avatar
Linus Torvalds committed
914
	SCpnt = device->host->host_queue;
Linus Torvalds's avatar
Linus Torvalds committed
915
	while(SCpnt){
Linus Torvalds's avatar
Linus Torvalds committed
916
	    if(SCpnt->channel == device->channel
Linus Torvalds's avatar
Linus Torvalds committed
917
                && SCpnt->target == device->id) {
Linus Torvalds's avatar
Linus Torvalds committed
918
		if (SCpnt->lun == device->lun) {
Linus Torvalds's avatar
Linus Torvalds committed
919 920
		    if(found == NULL
		       && SCpnt->request.rq_status == RQ_INACTIVE)
Linus Torvalds's avatar
Linus Torvalds committed
921 922 923
		    {
			found=SCpnt;
		    }
Linus Torvalds's avatar
Linus Torvalds committed
924
		}
Linus Torvalds's avatar
Linus Torvalds committed
925
		if(SCpnt->request.rq_status != RQ_INACTIVE) {
Linus Torvalds's avatar
Linus Torvalds committed
926 927
		    /*
		     * I think that we should really limit things to one
Linus Torvalds's avatar
Linus Torvalds committed
928
		     * outstanding command per device - this is what tends
Linus Torvalds's avatar
Linus Torvalds committed
929
                     * to trip up buggy firmware.
Linus Torvalds's avatar
Linus Torvalds committed
930 931 932 933 934 935 936
		     */
		    return NULL;
		}
	    }
	    SCpnt = SCpnt->next;
	}
	SCpnt = found;
Linus Torvalds's avatar
Linus Torvalds committed
937
    }
Linus Torvalds's avatar
Linus Torvalds committed
938

Linus Torvalds's avatar
Linus Torvalds committed
939
    if (!SCpnt) return NULL;
Linus Torvalds's avatar
Linus Torvalds committed
940

Linus Torvalds's avatar
Linus Torvalds committed
941
    if (SCSI_BLOCK(device->host)) return NULL;
Linus Torvalds's avatar
Linus Torvalds committed
942

Linus Torvalds's avatar
Linus Torvalds committed
943 944 945 946 947
    if (req) {
	memcpy(&SCpnt->request, req, sizeof(struct request));
	tablesize = device->host->sg_tablesize;
	bhp = bh = req->bh;
	if(!tablesize) bh = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
948 949 950
	/* Take a quick look through the table to see how big it is.
	 * We already have our copy of req, so we can mess with that
	 * if we want to.
Linus Torvalds's avatar
Linus Torvalds committed
951 952
	 */
	while(req->nr_sectors && bh){
Linus Torvalds's avatar
Linus Torvalds committed
953 954
	    bhp = bhp->b_reqnext;
	    if(!bhp || !CONTIGUOUS_BUFFERS(bh,bhp)) tablesize--;
Linus Torvalds's avatar
Linus Torvalds committed
955 956 957
	    req->nr_sectors -= bh->b_size >> 9;
	    req->sector += bh->b_size >> 9;
	    if(!tablesize) break;
Linus Torvalds's avatar
Linus Torvalds committed
958
	    bh = bhp;
Linus Torvalds's avatar
Linus Torvalds committed
959 960 961 962 963 964
	}
	if(req->nr_sectors && bh && bh->b_reqnext){  /* Any leftovers? */
	    SCpnt->request.bhtail = bh;
	    req->bh = bh->b_reqnext; /* Divide request */
	    bh->b_reqnext = NULL;
	    bh = req->bh;
Linus Torvalds's avatar
Linus Torvalds committed
965

Linus Torvalds's avatar
Linus Torvalds committed
966 967 968 969 970 971
	    /* Now reset things so that req looks OK */
	    SCpnt->request.nr_sectors -= req->nr_sectors;
	    req->current_nr_sectors = bh->b_size >> 9;
	    req->buffer = bh->b_data;
	    SCpnt->request.sem = NULL; /* Wait until whole thing done */
	} else {
Linus Torvalds's avatar
Linus Torvalds committed
972
	    req->rq_status = RQ_INACTIVE;
Linus Torvalds's avatar
Linus Torvalds committed
973 974
	    wake_up(&wait_for_request);
	}
Linus Torvalds's avatar
Linus Torvalds committed
975
    } else {
Linus Torvalds's avatar
Linus Torvalds committed
976
	SCpnt->request.rq_status = RQ_SCSI_BUSY;  /* Busy, but no request */
Linus Torvalds's avatar
Linus Torvalds committed
977
	SCpnt->request.sem = NULL;   /* And no one is waiting for the device
Linus Torvalds's avatar
Linus Torvalds committed
978
				      * either */
Linus Torvalds's avatar
Linus Torvalds committed
979
    }
Linus Torvalds's avatar
Linus Torvalds committed
980

Linus Torvalds's avatar
Linus Torvalds committed
981 982 983 984 985
    SCpnt->use_sg = 0;               /* Reset the scatter-gather flag */
    SCpnt->old_use_sg  = 0;
    SCpnt->transfersize = 0;
    SCpnt->underflow = 0;
    SCpnt->cmd_len = 0;
Linus Torvalds's avatar
Linus Torvalds committed
986

Linus Torvalds's avatar
Linus Torvalds committed
987 988
/* Since not everyone seems to set the device info correctly
 * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
Linus Torvalds's avatar
Linus Torvalds committed
989
 */
Linus Torvalds's avatar
Linus Torvalds committed
990 991 992
    SCpnt->channel = device->channel;
    SCpnt->lun = device->lun;
    SCpnt->target = device->id;
Linus Torvalds's avatar
Linus Torvalds committed
993

Linus Torvalds's avatar
Linus Torvalds committed
994
    return SCpnt;
995 996 997
}

/* This function returns a structure pointer that will be valid for
Linus Torvalds's avatar
Linus Torvalds committed
998 999 1000 1001 1002 1003
 * the device.  The wait parameter tells us whether we should wait for
 * the unit to become free or not.  We are also able to tell this routine
 * not to return a descriptor if the host is unable to accept any more
 * commands for the time being.  We need to keep in mind that there is no
 * guarantee that the host remain not busy.  Keep in mind the
 * request_queueable function also knows the internal allocation scheme
Linus Torvalds's avatar
Linus Torvalds committed
1004
 * of the packets for each device
Linus Torvalds's avatar
Linus Torvalds committed
1005
 */
1006

Linus Torvalds's avatar
Linus Torvalds committed
1007 1008
Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
			     int wait)
1009
{
Linus Torvalds's avatar
Linus Torvalds committed
1010
    kdev_t dev;
Linus Torvalds's avatar
Linus Torvalds committed
1011 1012
    struct request * req = NULL;
    int tablesize;
Linus Torvalds's avatar
Linus Torvalds committed
1013
    unsigned long flags;
Linus Torvalds's avatar
Linus Torvalds committed
1014 1015 1016 1017
    struct buffer_head * bh, *bhp;
    struct Scsi_Host * host;
    Scsi_Cmnd * SCpnt = NULL;
    Scsi_Cmnd * SCwait = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
1018
    Scsi_Cmnd * found = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
1019

Linus Torvalds's avatar
Linus Torvalds committed
1020 1021
    if (!device)
	panic ("No device passed to allocate_device().\n");
Linus Torvalds's avatar
Linus Torvalds committed
1022

Linus Torvalds's avatar
Linus Torvalds committed
1023
    if (reqp) req = *reqp;
Linus Torvalds's avatar
Linus Torvalds committed
1024

1025
    /* See if this request has already been queued by an interrupt routine */
Linus Torvalds's avatar
Linus Torvalds committed
1026 1027 1028 1029 1030
    if (req) {
	if(req->rq_status == RQ_INACTIVE) return NULL;
	dev = req->rq_dev;
    } else
        dev = 0;		/* unused */
Linus Torvalds's avatar
Linus Torvalds committed
1031

Linus Torvalds's avatar
Linus Torvalds committed
1032
    host = device->host;
Linus Torvalds's avatar
Linus Torvalds committed
1033

Linus Torvalds's avatar
Linus Torvalds committed
1034
    if (in_interrupt() && SCSI_BLOCK(host)) return NULL;
Linus Torvalds's avatar
Linus Torvalds committed
1035

Linus Torvalds's avatar
Linus Torvalds committed
1036
    while (1==1){
Linus Torvalds's avatar
Linus Torvalds committed
1037
	if (!device->single_lun) {
Linus Torvalds's avatar
Linus Torvalds committed
1038
	    SCpnt = device->device_queue;
Linus Torvalds's avatar
Linus Torvalds committed
1039
	    while(SCpnt){
Linus Torvalds's avatar
Linus Torvalds committed
1040 1041 1042
		SCwait = SCpnt;
		if(SCpnt->request.rq_status == RQ_INACTIVE) break;
		SCpnt = SCpnt->device_next;
Linus Torvalds's avatar
Linus Torvalds committed
1043 1044
	    }
	} else {
Linus Torvalds's avatar
Linus Torvalds committed
1045
	    SCpnt = device->host->host_queue;
Linus Torvalds's avatar
Linus Torvalds committed
1046
	    while(SCpnt){
Linus Torvalds's avatar
Linus Torvalds committed
1047
		if(SCpnt->channel == device->channel
Linus Torvalds's avatar
Linus Torvalds committed
1048
                   && SCpnt->target == device->id) {
Linus Torvalds's avatar
Linus Torvalds committed
1049 1050
		    if (SCpnt->lun == device->lun) {
			SCwait = SCpnt;
Linus Torvalds's avatar
Linus Torvalds committed
1051 1052
			if(found == NULL
			   && SCpnt->request.rq_status == RQ_INACTIVE)
Linus Torvalds's avatar
Linus Torvalds committed
1053 1054 1055
			{
			    found=SCpnt;
			}
Linus Torvalds's avatar
Linus Torvalds committed
1056
		    }
Linus Torvalds's avatar
Linus Torvalds committed
1057
		    if(SCpnt->request.rq_status != RQ_INACTIVE) {
Linus Torvalds's avatar
Linus Torvalds committed
1058 1059
			/*
			 * I think that we should really limit things to one
Linus Torvalds's avatar
Linus Torvalds committed
1060 1061
			 * outstanding command per device - this is what tends
                         * to trip up buggy firmware.
Linus Torvalds's avatar
Linus Torvalds committed
1062 1063 1064 1065 1066 1067 1068 1069 1070
			 */
			found = NULL;
			break;
		    }
		}
		SCpnt = SCpnt->next;
	    }
	    SCpnt = found;
	}
Linus Torvalds's avatar
Linus Torvalds committed
1071

Linus Torvalds's avatar
Linus Torvalds committed
1072 1073 1074 1075
	save_flags(flags);
	cli();
	/* See if this request has already been queued by an interrupt routine
	 */
Linus Torvalds's avatar
Linus Torvalds committed
1076
	if (req && (req->rq_status == RQ_INACTIVE || req->rq_dev != dev)) {
Linus Torvalds's avatar
Linus Torvalds committed
1077 1078 1079
	    restore_flags(flags);
	    return NULL;
	}
Linus Torvalds's avatar
Linus Torvalds committed
1080
	if (!SCpnt || SCpnt->request.rq_status != RQ_INACTIVE)	/* Might have changed */
Linus Torvalds's avatar
Linus Torvalds committed
1081
	{
Linus Torvalds's avatar
Linus Torvalds committed
1082
#if 1	/* NEW CODE */
Linus Torvalds's avatar
Linus Torvalds committed
1083
		if (wait && SCwait && SCwait->request.rq_status != RQ_INACTIVE){
Linus Torvalds's avatar
Linus Torvalds committed
1084 1085 1086 1087 1088 1089
 			sleep_on(&device->device_wait);
 			restore_flags(flags);
	 	} else {
 			restore_flags(flags);
	 		if (!wait) return NULL;
 			if (!SCwait) {
Linus Torvalds's avatar
Linus Torvalds committed
1090 1091 1092
	 			printk("Attempt to allocate device channel %d,"
                                       " target %d, lun %d\n", device->channel,
                                       device->id, device->lun);
Linus Torvalds's avatar
Linus Torvalds committed
1093 1094 1095 1096 1097 1098 1099
 				panic("No device found in allocate_device\n");
	 		}
 		}
#else	/* ORIGINAL CODE */
		    restore_flags(flags);
		    if(!wait) return NULL;
		    if (!SCwait) {
Linus Torvalds's avatar
Linus Torvalds committed
1100
			printk("Attempt to allocate device channel %d, target"
Linus Torvalds's avatar
Linus Torvalds committed
1101
                               " %d, lun %d\n", device->channel, device->id,
Linus Torvalds's avatar
Linus Torvalds committed
1102
                               device->lun);
Linus Torvalds's avatar
Linus Torvalds committed
1103 1104 1105 1106 1107
			panic("No device found in allocate_device\n");
		    }
		    SCSI_SLEEP(&device->device_wait,
			       (SCwait->request.rq_status != RQ_INACTIVE));
#endif
1108
	} else {
Linus Torvalds's avatar
Linus Torvalds committed
1109 1110 1111 1112 1113
	    if (req) {
		memcpy(&SCpnt->request, req, sizeof(struct request));
		tablesize = device->host->sg_tablesize;
		bhp = bh = req->bh;
		if(!tablesize) bh = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
1114 1115 1116
		/* Take a quick look through the table to see how big it is.
		 * We already have our copy of req, so we can mess with that
		 * if we want to.
Linus Torvalds's avatar
Linus Torvalds committed
1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138
		 */
		while(req->nr_sectors && bh){
		    bhp = bhp->b_reqnext;
		    if(!bhp || !CONTIGUOUS_BUFFERS(bh,bhp)) tablesize--;
		    req->nr_sectors -= bh->b_size >> 9;
		    req->sector += bh->b_size >> 9;
		    if(!tablesize) break;
		    bh = bhp;
		}
		if(req->nr_sectors && bh && bh->b_reqnext){/* Any leftovers? */
		    SCpnt->request.bhtail = bh;
		    req->bh = bh->b_reqnext; /* Divide request */
		    bh->b_reqnext = NULL;
		    bh = req->bh;
		    /* Now reset things so that req looks OK */
		    SCpnt->request.nr_sectors -= req->nr_sectors;
		    req->current_nr_sectors = bh->b_size >> 9;
		    req->buffer = bh->b_data;
		    SCpnt->request.sem = NULL; /* Wait until whole thing done*/
		}
		else
		{
Linus Torvalds's avatar
Linus Torvalds committed
1139
		    req->rq_status = RQ_INACTIVE;
Linus Torvalds's avatar
Linus Torvalds committed
1140 1141 1142 1143
		    *reqp = req->next;
		    wake_up(&wait_for_request);
		}
	    } else {
Linus Torvalds's avatar
Linus Torvalds committed
1144
		SCpnt->request.rq_status = RQ_SCSI_BUSY;
Linus Torvalds's avatar
Linus Torvalds committed
1145
		SCpnt->request.sem = NULL;   /* And no one is waiting for this
Linus Torvalds's avatar
Linus Torvalds committed
1146 1147 1148 1149
					      * to complete */
	    }
	    restore_flags(flags);
	    break;
Linus Torvalds's avatar
Linus Torvalds committed
1150
	}
Linus Torvalds's avatar
Linus Torvalds committed
1151
    }
Linus Torvalds's avatar
Linus Torvalds committed
1152

Linus Torvalds's avatar
Linus Torvalds committed
1153 1154 1155 1156
    SCpnt->use_sg = 0;            /* Reset the scatter-gather flag */
    SCpnt->old_use_sg  = 0;
    SCpnt->transfersize = 0;      /* No default transfer size */
    SCpnt->cmd_len = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1157

Linus Torvalds's avatar
Linus Torvalds committed
1158
    SCpnt->underflow = 0;         /* Do not flag underflow conditions */
Linus Torvalds's avatar
Linus Torvalds committed
1159 1160 1161

    /* Since not everyone seems to set the device info correctly
     * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
Linus Torvalds's avatar
Linus Torvalds committed
1162
     */
Linus Torvalds's avatar
Linus Torvalds committed
1163 1164 1165
    SCpnt->channel = device->channel;
    SCpnt->lun = device->lun;
    SCpnt->target = device->id;
Linus Torvalds's avatar
Linus Torvalds committed
1166

Linus Torvalds's avatar
Linus Torvalds committed
1167
    return SCpnt;
1168 1169
}

1170
/*
Linus Torvalds's avatar
Linus Torvalds committed
1171 1172
 * This is inline because we have stack problemes if we recurse to deeply.
 */
Linus Torvalds's avatar
Linus Torvalds committed
1173

1174
inline void internal_cmnd (Scsi_Cmnd * SCpnt)
Linus Torvalds's avatar
Linus Torvalds committed
1175
{
Linus Torvalds's avatar
Linus Torvalds committed
1176
    unsigned long flags, timeout;
Linus Torvalds's avatar
Linus Torvalds committed
1177
    struct Scsi_Host * host;
Linus Torvalds's avatar
Linus Torvalds committed
1178
#ifdef DEBUG_DELAY
Linus Torvalds's avatar
Linus Torvalds committed
1179
    unsigned long clock;
1180
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1181 1182 1183 1184 1185 1186 1187 1188 1189

#if DEBUG
    unsigned long *ret = 0;
#ifdef __mips__
    __asm__ __volatile__ ("move\t%0,$31":"=r"(ret));
#else
   ret =  __builtin_return_address(0);
#endif
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1190

Linus Torvalds's avatar
Linus Torvalds committed
1191
    host = SCpnt->host;
Linus Torvalds's avatar
Linus Torvalds committed
1192

Linus Torvalds's avatar
Linus Torvalds committed
1193
    save_flags(flags);
Linus Torvalds's avatar
Linus Torvalds committed
1194 1195 1196 1197
    cli();
    /* Assign a unique nonzero serial_number. */
    if (++serial_number == 0) serial_number = 1;
    SCpnt->serial_number = serial_number;
Linus Torvalds's avatar
Linus Torvalds committed
1198 1199 1200 1201 1202 1203 1204

    /*
     * We will wait MIN_RESET_DELAY clock ticks after the last reset so
     * we can avoid the drive not being ready.
     */
    timeout = host->last_reset + MIN_RESET_DELAY;
    if (jiffies < timeout) {
Linus Torvalds's avatar
Linus Torvalds committed
1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217
	int ticks_remaining = timeout - jiffies;
	/*
	 * NOTE: This may be executed from within an interrupt
	 * handler!  This is bad, but for now, it'll do.  The irq
	 * level of the interrupt handler has been masked out by the
	 * platform dependent interrupt handling code already, so the
	 * sti() here will not cause another call to the SCSI host's
	 * interrupt handler (assuming there is one irq-level per
	 * host).
	 */
	sti();
	while (--ticks_remaining >= 0) udelay(1000000/HZ);
	host->last_reset = jiffies - MIN_RESET_DELAY;
Linus Torvalds's avatar
Linus Torvalds committed
1218
    }
Linus Torvalds's avatar
Linus Torvalds committed
1219
    restore_flags(flags);
Linus Torvalds's avatar
Linus Torvalds committed
1220

Linus Torvalds's avatar
Linus Torvalds committed
1221
    update_timeout(SCpnt, SCpnt->timeout_per_command);
Linus Torvalds's avatar
Linus Torvalds committed
1222

Linus Torvalds's avatar
Linus Torvalds committed
1223 1224 1225 1226
    /*
     * We will use a queued command if possible, otherwise we will emulate the
     * queuing and calling of completion function ourselves.
     */
1227
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
1228
    printk("internal_cmnd (host = %d, channel = %d, target = %d, "
Linus Torvalds's avatar
Linus Torvalds committed
1229 1230
	   "command = %p, buffer = %p, \nbufflen = %d, done = %p)\n",
	   SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->cmnd,
Linus Torvalds's avatar
Linus Torvalds committed
1231
	   SCpnt->buffer, SCpnt->bufflen, SCpnt->done);
1232
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1233

Linus Torvalds's avatar
Linus Torvalds committed
1234 1235
    if (host->can_queue)
    {
1236
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
1237
	printk("queuecommand : routine at %p\n",
Linus Torvalds's avatar
Linus Torvalds committed
1238
	       host->hostt->queuecommand);
1239
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1240 1241 1242 1243 1244 1245
	/* This locking tries to prevent all sorts of races between
	 * queuecommand and the interrupt code.  In effect,
	 * we are only allowed to be in queuecommand once at
	 * any given time, and we can only be in the interrupt
	 * handler and the queuecommand function at the same time
	 * when queuecommand is called while servicing the
Linus Torvalds's avatar
Linus Torvalds committed
1246
	 * interrupt.
Linus Torvalds's avatar
Linus Torvalds committed
1247
	 */
Linus Torvalds's avatar
Linus Torvalds committed
1248

Linus Torvalds's avatar
Linus Torvalds committed
1249
	if(!in_interrupt() && SCpnt->host->irq)
Linus Torvalds's avatar
Linus Torvalds committed
1250
	    disable_irq(SCpnt->host->irq);
Linus Torvalds's avatar
Linus Torvalds committed
1251

Linus Torvalds's avatar
Linus Torvalds committed
1252
	host->hostt->queuecommand (SCpnt, scsi_done);
Linus Torvalds's avatar
Linus Torvalds committed
1253

Linus Torvalds's avatar
Linus Torvalds committed
1254
	if(!in_interrupt() && SCpnt->host->irq)
Linus Torvalds's avatar
Linus Torvalds committed
1255 1256 1257 1258
	    enable_irq(SCpnt->host->irq);
    }
    else
    {
Linus Torvalds's avatar
Linus Torvalds committed
1259 1260
	int temp;

1261
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
1262
	printk("command() :  routine at %p\n", host->hostt->command);
1263
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1264
	temp = host->hostt->command (SCpnt);
Linus Torvalds's avatar
Linus Torvalds committed
1265
	SCpnt->result = temp;
1266
#ifdef DEBUG_DELAY
Linus Torvalds's avatar
Linus Torvalds committed
1267
	clock = jiffies + 4 * HZ;
Linus Torvalds's avatar
Linus Torvalds committed
1268
	while (jiffies < clock) barrier();
Linus Torvalds's avatar
Linus Torvalds committed
1269
	printk("done(host = %d, result = %04x) : routine at %p\n",
Linus Torvalds's avatar
Linus Torvalds committed
1270
	       host->host_no, temp, host->hostt->command);
1271
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1272 1273
	scsi_done(SCpnt);
    }
1274
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
1275
    printk("leaving internal_cmnd()\n");
1276
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1277
}
1278

1279
static void scsi_request_sense (Scsi_Cmnd * SCpnt)
Linus Torvalds's avatar
Linus Torvalds committed
1280
{
Linus Torvalds's avatar
Linus Torvalds committed
1281
    unsigned long flags;
Linus Torvalds's avatar
Linus Torvalds committed
1282

Linus Torvalds's avatar
Linus Torvalds committed
1283 1284 1285 1286 1287
    save_flags(flags);
    cli();
    SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;
    update_timeout(SCpnt, SENSE_TIMEOUT);
    restore_flags(flags);
Linus Torvalds's avatar
Linus Torvalds committed
1288 1289 1290


    memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
Linus Torvalds's avatar
Linus Torvalds committed
1291
	    sizeof(generic_sense));
Linus Torvalds's avatar
Linus Torvalds committed
1292

Linus Torvalds's avatar
Linus Torvalds committed
1293 1294
    SCpnt->cmnd[1] = SCpnt->lun << 5;
    SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
Linus Torvalds's avatar
Linus Torvalds committed
1295

Linus Torvalds's avatar
Linus Torvalds committed
1296 1297 1298 1299 1300 1301
    SCpnt->request_buffer = &SCpnt->sense_buffer;
    SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
    SCpnt->use_sg = 0;
    SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
    internal_cmnd (SCpnt);
}
1302 1303 1304 1305



/*
Linus Torvalds's avatar
Linus Torvalds committed
1306 1307 1308 1309 1310
 * scsi_do_cmd sends all the commands out to the low-level driver.  It
 * handles the specifics required for each low level driver - ie queued
 * or non queued.  It also prevents conflicts when different high level
 * drivers go for the same host at the same time.
 */
1311

Linus Torvalds's avatar
Linus Torvalds committed
1312
void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
1313
		  void *buffer, unsigned bufflen, void (*done)(Scsi_Cmnd *),
Linus Torvalds's avatar
Linus Torvalds committed
1314 1315 1316 1317
		  int timeout, int retries)
{
    unsigned long flags;
    struct Scsi_Host * host = SCpnt->host;
Linus Torvalds's avatar
Linus Torvalds committed
1318

1319
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
1320
    {
Linus Torvalds's avatar
Linus Torvalds committed
1321
	int i;
1322
	int target = SCpnt->target;
Linus Torvalds's avatar
Linus Torvalds committed
1323 1324 1325
	printk ("scsi_do_cmd (host = %d, channel = %d target = %d, "
		"buffer =%p, bufflen = %d, done = %p, timeout = %d, "
		"retries = %d)\n"
Linus Torvalds's avatar
Linus Torvalds committed
1326
		"command : " , host->host_no, SCpnt->channel, target, buffer,
Linus Torvalds's avatar
Linus Torvalds committed
1327
		bufflen, done, timeout, retries);
1328
	for (i = 0; i < 10; ++i)
Linus Torvalds's avatar
Linus Torvalds committed
1329
	    printk ("%02x  ", ((unsigned char *) cmnd)[i]);
1330
	printk("\n");
Linus Torvalds's avatar
Linus Torvalds committed
1331
    }
1332
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1333

Linus Torvalds's avatar
Linus Torvalds committed
1334 1335 1336 1337
    if (!host)
    {
	panic ("Invalid or not present host.\n");
    }
Linus Torvalds's avatar
Linus Torvalds committed
1338 1339


Linus Torvalds's avatar
Linus Torvalds committed
1340 1341 1342 1343 1344 1345 1346
    /*
     * We must prevent reentrancy to the lowlevel host driver.  This prevents
     * it - we enter a loop until the host we want to talk to is not busy.
     * Race conditions are prevented, as interrupts are disabled in between the
     * time we check for the host being not busy, and the time we mark it busy
     * ourselves.
     */
Linus Torvalds's avatar
Linus Torvalds committed
1347

Linus Torvalds's avatar
Linus Torvalds committed
1348 1349 1350
    save_flags(flags);
    cli();
    SCpnt->pid = scsi_pid++;
Linus Torvalds's avatar
Linus Torvalds committed
1351

Linus Torvalds's avatar
Linus Torvalds committed
1352
    while (SCSI_BLOCK(host)) {
Linus Torvalds's avatar
Linus Torvalds committed
1353
	restore_flags(flags);
Linus Torvalds's avatar
Linus Torvalds committed
1354 1355 1356
	SCSI_SLEEP(&host->host_wait, SCSI_BLOCK(host));
	cli();
    }
Linus Torvalds's avatar
Linus Torvalds committed
1357

Linus Torvalds's avatar
Linus Torvalds committed
1358
    if (host->block) host_active = host;
Linus Torvalds's avatar
Linus Torvalds committed
1359

Linus Torvalds's avatar
Linus Torvalds committed
1360 1361
    host->host_busy++;
    restore_flags(flags);
Linus Torvalds's avatar
Linus Torvalds committed
1362

Linus Torvalds's avatar
Linus Torvalds committed
1363 1364 1365 1366 1367 1368
    /*
     * Our own function scsi_done (which marks the host as not busy, disables
     * the timeout counter, etc) will be called by us or by the
     * scsi_hosts[host].queuecommand() function needs to also call
     * the completion function for the high level driver.
     */
Linus Torvalds's avatar
Linus Torvalds committed
1369

Linus Torvalds's avatar
Linus Torvalds committed
1370
    memcpy ((void *) SCpnt->data_cmnd , (const void *) cmnd, 12);
1371
#if 0
Linus Torvalds's avatar
Linus Torvalds committed
1372 1373 1374 1375
    SCpnt->host = host;
    SCpnt->channel = channel;
    SCpnt->target = target;
    SCpnt->lun = (SCpnt->data_cmnd[1] >> 5);
1376
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1377 1378
    SCpnt->reset_chain = NULL;
    SCpnt->serial_number = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1379 1380
    SCpnt->bufflen = bufflen;
    SCpnt->buffer = buffer;
Linus Torvalds's avatar
Linus Torvalds committed
1381 1382 1383
    SCpnt->flags = 0;
    SCpnt->retries = 0;
    SCpnt->allowed = retries;
Linus Torvalds's avatar
Linus Torvalds committed
1384 1385 1386
    SCpnt->done = done;
    SCpnt->timeout_per_command = timeout;

Linus Torvalds's avatar
Linus Torvalds committed
1387
    memcpy ((void *) SCpnt->cmnd , (const void *) cmnd, 12);
Linus Torvalds's avatar
Linus Torvalds committed
1388
    /* Zero the sense buffer.  Some host adapters automatically request
Linus Torvalds's avatar
Linus Torvalds committed
1389
     * sense on error.  0 is not a valid sense code.
Linus Torvalds's avatar
Linus Torvalds committed
1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400
     */
    memset ((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);
    SCpnt->request_buffer = buffer;
    SCpnt->request_bufflen = bufflen;
    SCpnt->old_use_sg = SCpnt->use_sg;
    if (SCpnt->cmd_len == 0)
	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
    SCpnt->old_cmd_len = SCpnt->cmd_len;

    /* Start the timer ticking.  */

Linus Torvalds's avatar
Linus Torvalds committed
1401
    SCpnt->internal_timeout = NORMAL_TIMEOUT;
Linus Torvalds's avatar
Linus Torvalds committed
1402 1403
    SCpnt->abort_reason = 0;
    internal_cmnd (SCpnt);
1404 1405

#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
1406
    printk ("Leaving scsi_do_cmd()\n");
1407
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1408
}
1409

1410
static int check_sense (Scsi_Cmnd * SCpnt)
Linus Torvalds's avatar
Linus Torvalds committed
1411 1412 1413
{
    /* If there is no sense information, request it.  If we have already
     * requested it, there is no point in asking again - the firmware must
Linus Torvalds's avatar
Linus Torvalds committed
1414
     * be confused.
Linus Torvalds's avatar
Linus Torvalds committed
1415 1416 1417 1418 1419 1420 1421
     */
    if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) {
	if(!(SCpnt->flags & ASKED_FOR_SENSE))
	    return SUGGEST_SENSE;
	else
	    return SUGGEST_RETRY;
    }
Linus Torvalds's avatar
Linus Torvalds committed
1422

Linus Torvalds's avatar
Linus Torvalds committed
1423
    SCpnt->flags &= ~ASKED_FOR_SENSE;
Linus Torvalds's avatar
Linus Torvalds committed
1424

1425
#ifdef DEBUG_INIT
Linus Torvalds's avatar
Linus Torvalds committed
1426 1427 1428
    printk("scsi%d, channel%d : ", SCpnt->host->host_no, SCpnt->channel);
    print_sense("", SCpnt);
    printk("\n");
1429
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1430 1431
    if (SCpnt->sense_buffer[2] & 0xe0)
	return SUGGEST_ABORT;
Linus Torvalds's avatar
Linus Torvalds committed
1432

Linus Torvalds's avatar
Linus Torvalds committed
1433 1434 1435 1436 1437 1438
    switch (SCpnt->sense_buffer[2] & 0xf)
    {
    case NO_SENSE:
	return 0;
    case RECOVERED_ERROR:
	return SUGGEST_IS_OK;
Linus Torvalds's avatar
Linus Torvalds committed
1439

Linus Torvalds's avatar
Linus Torvalds committed
1440 1441 1442 1443
    case ABORTED_COMMAND:
	return SUGGEST_RETRY;
    case NOT_READY:
    case UNIT_ATTENTION:
Linus Torvalds's avatar
Linus Torvalds committed
1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454
        /*
         * If we are expecting a CC/UA because of a bus reset that we
         * performed, treat this just as a retry.  Otherwise this is
         * information that we should pass up to the upper-level driver
         * so that we can deal with it there.
         */
        if( SCpnt->device->expecting_cc_ua )
        {
            SCpnt->device->expecting_cc_ua = 0;
            return SUGGEST_RETRY;
        }
Linus Torvalds's avatar
Linus Torvalds committed
1455
	return SUGGEST_ABORT;
Linus Torvalds's avatar
Linus Torvalds committed
1456

Linus Torvalds's avatar
Linus Torvalds committed
1457 1458 1459 1460
    /* these three are not supported */
    case COPY_ABORTED:
    case VOLUME_OVERFLOW:
    case MISCOMPARE:
Linus Torvalds's avatar
Linus Torvalds committed
1461

Linus Torvalds's avatar
Linus Torvalds committed
1462 1463 1464 1465 1466 1467 1468 1469 1470 1471
    case MEDIUM_ERROR:
	return SUGGEST_REMAP;
    case BLANK_CHECK:
    case DATA_PROTECT:
    case HARDWARE_ERROR:
    case ILLEGAL_REQUEST:
    default:
	return SUGGEST_ABORT;
    }
}
1472

1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490
/* This function is the mid-level interrupt routine, which decides how
 *  to handle error conditions.  Each invocation of this function must
 *  do one and *only* one of the following:
 *
 *  (1) Call last_cmnd[host].done.  This is done for fatal errors and
 *      normal completion, and indicates that the handling for this
 *      request is complete.
 *  (2) Call internal_cmnd to requeue the command.  This will result in
 *      scsi_done being called again when the retry is complete.
 *  (3) Call scsi_request_sense.  This asks the host adapter/drive for
 *      more information about the error condition.  When the information
 *      is available, scsi_done will be called again.
 *  (4) Call reset().  This is sort of a last resort, and the idea is that
 *      this may kick things loose and get the drive working again.  reset()
 *      automatically calls scsi_request_sense, and thus scsi_done will be
 *      called again once the reset is complete.
 *
 *      If none of the above actions are taken, the drive in question
Linus Torvalds's avatar
Linus Torvalds committed
1491 1492
 *      will hang. If more than one of the above actions are taken by
 *      scsi_done, then unpredictable behavior will result.
1493
 */
1494
static void scsi_done (Scsi_Cmnd * SCpnt)
Linus Torvalds's avatar
Linus Torvalds committed
1495 1496 1497 1498 1499 1500 1501
{
    int status=0;
    int exit=0;
    int checked;
    int oldto;
    struct Scsi_Host * host = SCpnt->host;
    int result = SCpnt->result;
Linus Torvalds's avatar
Linus Torvalds committed
1502
    SCpnt->serial_number = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1503
    oldto = update_timeout(SCpnt, 0);
Linus Torvalds's avatar
Linus Torvalds committed
1504

Linus Torvalds's avatar
Linus Torvalds committed
1505
#ifdef DEBUG_TIMEOUT
Linus Torvalds's avatar
Linus Torvalds committed
1506 1507
    if(result) printk("Non-zero result in scsi_done %x %d:%d\n",
		      result, SCpnt->target, SCpnt->lun);
Linus Torvalds's avatar
Linus Torvalds committed
1508
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1509

Linus Torvalds's avatar
Linus Torvalds committed
1510
    /* If we requested an abort, (and we got it) then fix up the return
Linus Torvalds's avatar
Linus Torvalds committed
1511
     *  status to say why
Linus Torvalds's avatar
Linus Torvalds committed
1512 1513 1514
     */
    if(host_byte(result) == DID_ABORT && SCpnt->abort_reason)
	SCpnt->result = result = (result & 0xff00ffff) |
Linus Torvalds's avatar
Linus Torvalds committed
1515 1516 1517
	    (SCpnt->abort_reason << 16);


1518 1519
#define FINISHED 0
#define MAYREDO  1
Linus Torvalds's avatar
Linus Torvalds committed
1520
#define REDO     3
1521
#define PENDING  4
1522 1523

#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
1524
    printk("In scsi_done(host = %d, result = %06x)\n", host->host_no, result);
1525
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1526

Linus Torvalds's avatar
Linus Torvalds committed
1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537
    if(SCpnt->flags & WAS_SENSE)
    {
	SCpnt->use_sg = SCpnt->old_use_sg;
	SCpnt->cmd_len = SCpnt->old_cmd_len;
    }

    switch (host_byte(result))
    {
    case DID_OK:
	if (status_byte(result) && (SCpnt->flags & WAS_SENSE))
	    /* Failed to obtain sense information */
Linus Torvalds's avatar
Linus Torvalds committed
1538
	{
Linus Torvalds's avatar
Linus Torvalds committed
1539
	    SCpnt->flags &= ~WAS_SENSE;
Linus Torvalds's avatar
Linus Torvalds committed
1540
#if 0	/* This cannot possibly be correct. */
Linus Torvalds's avatar
Linus Torvalds committed
1541
	    SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
Linus Torvalds's avatar
Linus Torvalds committed
1542
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1543

Linus Torvalds's avatar
Linus Torvalds committed
1544 1545 1546 1547
	    if (!(SCpnt->flags & WAS_RESET))
	    {
		printk("scsi%d : channel %d target %d lun %d request sense"
		       " failed, performing reset.\n",
Linus Torvalds's avatar
Linus Torvalds committed
1548
		       SCpnt->host->host_no, SCpnt->channel, SCpnt->target,
Linus Torvalds's avatar
Linus Torvalds committed
1549
		       SCpnt->lun);
Linus Torvalds's avatar
Linus Torvalds committed
1550
		scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
Linus Torvalds's avatar
Linus Torvalds committed
1551 1552 1553 1554 1555 1556 1557
		return;
	    }
	    else
	    {
		exit = (DRIVER_HARD | SUGGEST_ABORT);
		status = FINISHED;
	    }
Linus Torvalds's avatar
Linus Torvalds committed
1558
	}
Linus Torvalds's avatar
Linus Torvalds committed
1559
	else switch(msg_byte(result))
1560
	{
Linus Torvalds's avatar
Linus Torvalds committed
1561 1562 1563 1564 1565 1566
	case COMMAND_COMPLETE:
	    switch (status_byte(result))
	    {
	    case GOOD:
		if (SCpnt->flags & WAS_SENSE)
		{
1567
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
1568 1569
		    printk ("In scsi_done, GOOD status, COMMAND COMPLETE, "
                            "parsing sense information.\n");
1570
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1571
		    SCpnt->flags &= ~WAS_SENSE;
Linus Torvalds's avatar
Linus Torvalds committed
1572
#if 0	/* This cannot possibly be correct. */
Linus Torvalds's avatar
Linus Torvalds committed
1573
		    SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
Linus Torvalds's avatar
Linus Torvalds committed
1574
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1575

Linus Torvalds's avatar
Linus Torvalds committed
1576 1577 1578 1579
		    switch (checked = check_sense(SCpnt))
		    {
		    case SUGGEST_SENSE:
		    case 0:
1580
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
1581
			printk("NO SENSE.  status = REDO\n");
1582
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1583 1584 1585 1586 1587 1588
			update_timeout(SCpnt, oldto);
			status = REDO;
			break;
		    case SUGGEST_IS_OK:
			break;
		    case SUGGEST_REMAP:
Linus Torvalds's avatar
Linus Torvalds committed
1589 1590 1591 1592 1593 1594
#ifdef DEBUG
			printk("SENSE SUGGEST REMAP - status = FINISHED\n");
#endif
			status = FINISHED;
			exit = DRIVER_SENSE | SUGGEST_ABORT;
			break;
Linus Torvalds's avatar
Linus Torvalds committed
1595
		    case SUGGEST_RETRY:
1596
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
1597
			printk("SENSE SUGGEST RETRY - status = MAYREDO\n");
1598
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1599 1600 1601 1602
			status = MAYREDO;
			exit = DRIVER_SENSE | SUGGEST_RETRY;
			break;
		    case SUGGEST_ABORT:
1603
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
1604
			printk("SENSE SUGGEST ABORT - status = FINISHED");
1605
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1606 1607 1608 1609 1610 1611 1612
			status = FINISHED;
			exit =  DRIVER_SENSE | SUGGEST_ABORT;
			break;
		    default:
			printk ("Internal error %s %d \n", __FILE__,
				__LINE__);
		    }
Linus Torvalds's avatar
Linus Torvalds committed
1613
		} /* end WAS_SENSE */
Linus Torvalds's avatar
Linus Torvalds committed
1614 1615
		else
		{
1616
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
1617 1618
		    printk("COMMAND COMPLETE message returned, "
                           "status = FINISHED. \n");
1619
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1620 1621 1622 1623
		    exit =  DRIVER_OK;
		    status = FINISHED;
		}
		break;
Linus Torvalds's avatar
Linus Torvalds committed
1624

Linus Torvalds's avatar
Linus Torvalds committed
1625
	    case CHECK_CONDITION:
Linus Torvalds's avatar
Linus Torvalds committed
1626
	    case COMMAND_TERMINATED:
Linus Torvalds's avatar
Linus Torvalds committed
1627 1628 1629 1630 1631 1632 1633
		switch (check_sense(SCpnt))
		{
		case 0:
		    update_timeout(SCpnt, oldto);
		    status = REDO;
		    break;
		case SUGGEST_REMAP:
Linus Torvalds's avatar
Linus Torvalds committed
1634 1635 1636
		    status = FINISHED;
		    exit =  DRIVER_SENSE | SUGGEST_ABORT;
		    break;
Linus Torvalds's avatar
Linus Torvalds committed
1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650
		case SUGGEST_RETRY:
		    status = MAYREDO;
		    exit = DRIVER_SENSE | SUGGEST_RETRY;
		    break;
		case SUGGEST_ABORT:
		    status = FINISHED;
		    exit =  DRIVER_SENSE | SUGGEST_ABORT;
		    break;
		case SUGGEST_SENSE:
		    scsi_request_sense (SCpnt);
		    status = PENDING;
		    break;
		}
		break;
Linus Torvalds's avatar
Linus Torvalds committed
1651

Linus Torvalds's avatar
Linus Torvalds committed
1652 1653 1654 1655
	    case CONDITION_GOOD:
	    case INTERMEDIATE_GOOD:
	    case INTERMEDIATE_C_GOOD:
		break;
Linus Torvalds's avatar
Linus Torvalds committed
1656

Linus Torvalds's avatar
Linus Torvalds committed
1657
	    case BUSY:
Linus Torvalds's avatar
Linus Torvalds committed
1658
	    case QUEUE_FULL:
Linus Torvalds's avatar
Linus Torvalds committed
1659 1660 1661
		update_timeout(SCpnt, oldto);
		status = REDO;
		break;
Linus Torvalds's avatar
Linus Torvalds committed
1662

Linus Torvalds's avatar
Linus Torvalds committed
1663 1664 1665
	    case RESERVATION_CONFLICT:
		printk("scsi%d, channel %d : RESERVATION CONFLICT performing"
		       " reset.\n", SCpnt->host->host_no, SCpnt->channel);
Linus Torvalds's avatar
Linus Torvalds committed
1666
		scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
Linus Torvalds's avatar
Linus Torvalds committed
1667
		return;
1668
#if 0
Linus Torvalds's avatar
Linus Torvalds committed
1669 1670 1671
		exit = DRIVER_SOFT | SUGGEST_ABORT;
		status = MAYREDO;
		break;
1672
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1673 1674 1675 1676
	    default:
		printk ("Internal error %s %d \n"
			"status byte = %d \n", __FILE__,
			__LINE__, status_byte(result));
Linus Torvalds's avatar
Linus Torvalds committed
1677

Linus Torvalds's avatar
Linus Torvalds committed
1678 1679 1680
	    }
	    break;
	default:
Linus Torvalds's avatar
Linus Torvalds committed
1681
	    panic("scsi: unsupported message byte %d received\n",
Linus Torvalds's avatar
Linus Torvalds committed
1682 1683 1684 1685
		  msg_byte(result));
	}
	break;
    case DID_TIME_OUT:
1686 1687 1688
#ifdef DEBUG
	printk("Host returned DID_TIME_OUT - ");
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1689

Linus Torvalds's avatar
Linus Torvalds committed
1690 1691
	if (SCpnt->flags & WAS_TIMEDOUT)
	{
1692
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
1693
	    printk("Aborting\n");
Linus Torvalds's avatar
Linus Torvalds committed
1694
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1695 1696 1697 1698 1699 1700 1701
	    /*
	      Allow TEST_UNIT_READY and INQUIRY commands to timeout early
	      without causing resets.  All other commands should be retried.
	    */
	    if (SCpnt->cmnd[0] != TEST_UNIT_READY &&
		SCpnt->cmnd[0] != INQUIRY)
		    status = MAYREDO;
Linus Torvalds's avatar
Linus Torvalds committed
1702 1703 1704 1705
	    exit = (DRIVER_TIMEOUT | SUGGEST_ABORT);
	}
	else
	{
1706
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
1707
	    printk ("Retrying.\n");
1708
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1709 1710 1711 1712 1713 1714 1715 1716 1717 1718
	    SCpnt->flags  |= WAS_TIMEDOUT;
	    SCpnt->internal_timeout &= ~IN_ABORT;
	    status = REDO;
	}
	break;
    case DID_BUS_BUSY:
    case DID_PARITY:
	status = REDO;
	break;
    case DID_NO_CONNECT:
1719
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
1720
	printk("Couldn't connect.\n");
1721
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738
	exit  = (DRIVER_HARD | SUGGEST_ABORT);
	break;
    case DID_ERROR:
	status = MAYREDO;
	exit = (DRIVER_HARD | SUGGEST_ABORT);
	break;
    case DID_BAD_TARGET:
    case DID_ABORT:
	exit = (DRIVER_INVALID | SUGGEST_ABORT);
	break;
    case DID_RESET:
	if (SCpnt->flags & IS_RESETTING)
	{
	    SCpnt->flags &= ~IS_RESETTING;
	    status = REDO;
	    break;
	}
Linus Torvalds's avatar
Linus Torvalds committed
1739

Linus Torvalds's avatar
Linus Torvalds committed
1740 1741 1742 1743 1744 1745
	if(msg_byte(result) == GOOD &&
	   status_byte(result) == CHECK_CONDITION) {
	    switch (check_sense(SCpnt)) {
	    case 0:
		update_timeout(SCpnt, oldto);
		status = REDO;
1746
		break;
Linus Torvalds's avatar
Linus Torvalds committed
1747 1748
	    case SUGGEST_REMAP:
	    case SUGGEST_RETRY:
1749
		status = MAYREDO;
Linus Torvalds's avatar
Linus Torvalds committed
1750
		exit = DRIVER_SENSE | SUGGEST_RETRY;
1751
		break;
Linus Torvalds's avatar
Linus Torvalds committed
1752 1753 1754
	    case SUGGEST_ABORT:
		status = FINISHED;
		exit =  DRIVER_SENSE | SUGGEST_ABORT;
Linus Torvalds's avatar
Linus Torvalds committed
1755
		break;
Linus Torvalds's avatar
Linus Torvalds committed
1756 1757 1758
	    case SUGGEST_SENSE:
		scsi_request_sense (SCpnt);
		status = PENDING;
Linus Torvalds's avatar
Linus Torvalds committed
1759
		break;
Linus Torvalds's avatar
Linus Torvalds committed
1760 1761 1762 1763
	    }
	} else {
	    status=REDO;
	    exit = SUGGEST_RETRY;
1764
	}
Linus Torvalds's avatar
Linus Torvalds committed
1765 1766 1767 1768
	break;
    default :
	exit = (DRIVER_ERROR | SUGGEST_DIE);
    }
Linus Torvalds's avatar
Linus Torvalds committed
1769

Linus Torvalds's avatar
Linus Torvalds committed
1770 1771 1772 1773 1774 1775
    switch (status)
    {
    case FINISHED:
    case PENDING:
	break;
    case MAYREDO:
1776
#ifdef DEBUG
1777
	printk("In MAYREDO, allowing %d retries, have %d\n",
1778
	       SCpnt->allowed, SCpnt->retries);
1779
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1780 1781 1782
	if ((++SCpnt->retries) < SCpnt->allowed)
	{
	    if ((SCpnt->retries >= (SCpnt->allowed >> 1))
Linus Torvalds's avatar
Linus Torvalds committed
1783 1784
		&& !(SCpnt->host->last_reset > 0 &&
		     jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD)
Linus Torvalds's avatar
Linus Torvalds committed
1785 1786 1787 1788
		&& !(SCpnt->flags & WAS_RESET))
	    {
		printk("scsi%d channel %d : resetting for second half of retries.\n",
		       SCpnt->host->host_no, SCpnt->channel);
Linus Torvalds's avatar
Linus Torvalds committed
1789
		scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
Linus Torvalds's avatar
Linus Torvalds committed
1790 1791
		break;
	    }
Linus Torvalds's avatar
Linus Torvalds committed
1792

Linus Torvalds's avatar
Linus Torvalds committed
1793 1794 1795 1796 1797 1798 1799
	}
	else
	{
	    status = FINISHED;
	    break;
	}
	/* fall through to REDO */
Linus Torvalds's avatar
Linus Torvalds committed
1800

Linus Torvalds's avatar
Linus Torvalds committed
1801
    case REDO:
Linus Torvalds's avatar
Linus Torvalds committed
1802

Linus Torvalds's avatar
Linus Torvalds committed
1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819
	if (SCpnt->flags & WAS_SENSE)
	    scsi_request_sense(SCpnt);
	else
	{
	    memcpy ((void *) SCpnt->cmnd,
		    (void*) SCpnt->data_cmnd,
		    sizeof(SCpnt->data_cmnd));
	    SCpnt->request_buffer = SCpnt->buffer;
	    SCpnt->request_bufflen = SCpnt->bufflen;
	    SCpnt->use_sg = SCpnt->old_use_sg;
	    SCpnt->cmd_len = SCpnt->old_cmd_len;
	    internal_cmnd (SCpnt);
	}
	break;
    default:
	INTERNAL_ERROR;
    }
Linus Torvalds's avatar
Linus Torvalds committed
1820

Linus Torvalds's avatar
Linus Torvalds committed
1821
    if (status == FINISHED) {
Linus Torvalds's avatar
Linus Torvalds committed
1822
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
1823
	printk("Calling done function - at address %p\n", SCpnt->done);
Linus Torvalds's avatar
Linus Torvalds committed
1824
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1825
	host->host_busy--; /* Indicate that we are free */
Linus Torvalds's avatar
Linus Torvalds committed
1826

Linus Torvalds's avatar
Linus Torvalds committed
1827 1828
	if (host->block && host->host_busy == 0) {
	    host_active = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
1829

Linus Torvalds's avatar
Linus Torvalds committed
1830
	    /* For block devices "wake_up" is done in end_scsi_request */
Linus Torvalds's avatar
Linus Torvalds committed
1831 1832
	    if (MAJOR(SCpnt->request.rq_dev) != SCSI_DISK_MAJOR &&
		MAJOR(SCpnt->request.rq_dev) != SCSI_CDROM_MAJOR) {
Linus Torvalds's avatar
Linus Torvalds committed
1833
		struct Scsi_Host * next;
Linus Torvalds's avatar
Linus Torvalds committed
1834

Linus Torvalds's avatar
Linus Torvalds committed
1835
		for (next = host->block; next != host; next = next->block)
Linus Torvalds's avatar
Linus Torvalds committed
1836
		    wake_up(&next->host_wait);
Linus Torvalds's avatar
Linus Torvalds committed
1837
	    }
Linus Torvalds's avatar
Linus Torvalds committed
1838

Linus Torvalds's avatar
Linus Torvalds committed
1839
	}
Linus Torvalds's avatar
Linus Torvalds committed
1840

Linus Torvalds's avatar
Linus Torvalds committed
1841 1842 1843 1844 1845 1846
	wake_up(&host->host_wait);
	SCpnt->result = result | ((exit & 0xff) << 24);
	SCpnt->use_sg = SCpnt->old_use_sg;
	SCpnt->cmd_len = SCpnt->old_cmd_len;
	SCpnt->done (SCpnt);
    }
Linus Torvalds's avatar
Linus Torvalds committed
1847

1848 1849 1850
#undef FINISHED
#undef REDO
#undef MAYREDO
1851
#undef PENDING
Linus Torvalds's avatar
Linus Torvalds committed
1852
}
1853 1854

/*
Linus Torvalds's avatar
Linus Torvalds committed
1855 1856 1857 1858
 * The scsi_abort function interfaces with the abort() function of the host
 * we are aborting, and causes the current command to not complete.  The
 * caller should deal with any error messages or status returned on the
 * next call.
Linus Torvalds's avatar
Linus Torvalds committed
1859
 *
Linus Torvalds's avatar
Linus Torvalds committed
1860 1861
 * This will not be called reentrantly for a given host.
 */
Linus Torvalds's avatar
Linus Torvalds committed
1862

1863
/*
Linus Torvalds's avatar
Linus Torvalds committed
1864 1865 1866 1867
 * Since we're nice guys and specified that abort() and reset()
 * can be non-reentrant.  The internal_timeout flags are used for
 * this.
 */
1868 1869


Linus Torvalds's avatar
Linus Torvalds committed
1870
int scsi_abort (Scsi_Cmnd * SCpnt, int why)
Linus Torvalds's avatar
Linus Torvalds committed
1871 1872 1873 1874
{
    int oldto;
    unsigned long flags;
    struct Scsi_Host * host = SCpnt->host;
Linus Torvalds's avatar
Linus Torvalds committed
1875

Linus Torvalds's avatar
Linus Torvalds committed
1876 1877 1878 1879
    while(1)
    {
	save_flags(flags);
	cli();
Linus Torvalds's avatar
Linus Torvalds committed
1880

Linus Torvalds's avatar
Linus Torvalds committed
1881 1882 1883 1884
	/*
	 * Protect against races here.  If the command is done, or we are
	 * on a different command forget it.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
1885
	if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
Linus Torvalds's avatar
Linus Torvalds committed
1886 1887 1888
	    restore_flags(flags);
	    return 0;
	}
Linus Torvalds's avatar
Linus Torvalds committed
1889

Linus Torvalds's avatar
Linus Torvalds committed
1890 1891 1892 1893 1894 1895 1896 1897 1898 1899
	if (SCpnt->internal_timeout & IN_ABORT)
	{
	    restore_flags(flags);
	    while (SCpnt->internal_timeout & IN_ABORT)
		barrier();
	}
	else
	{
	    SCpnt->internal_timeout |= IN_ABORT;
	    oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
Linus Torvalds's avatar
Linus Torvalds committed
1900

Linus Torvalds's avatar
Linus Torvalds committed
1901
	    if ((SCpnt->flags & IS_RESETTING) && SCpnt->device->soft_reset) {
Linus Torvalds's avatar
Linus Torvalds committed
1902
		/* OK, this command must have died when we did the
Linus Torvalds's avatar
Linus Torvalds committed
1903
		 *  reset.  The device itself must have lied.
Linus Torvalds's avatar
Linus Torvalds committed
1904
		 */
Linus Torvalds's avatar
Linus Torvalds committed
1905
		printk("Stale command on %d %d:%d appears to have died when"
Linus Torvalds's avatar
Linus Torvalds committed
1906
		       " the bus was reset\n",
Linus Torvalds's avatar
Linus Torvalds committed
1907 1908
		       SCpnt->channel, SCpnt->target, SCpnt->lun);
	    }
Linus Torvalds's avatar
Linus Torvalds committed
1909

Linus Torvalds's avatar
Linus Torvalds committed
1910 1911 1912 1913 1914 1915 1916 1917
	    restore_flags(flags);
	    if (!host->host_busy) {
		SCpnt->internal_timeout &= ~IN_ABORT;
		update_timeout(SCpnt, oldto);
		return 0;
	    }
	    printk("scsi : aborting command due to timeout : pid %lu, scsi%d,"
		   " channel %d, id %d, lun %d ",
Linus Torvalds's avatar
Linus Torvalds committed
1918
		   SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->channel,
Linus Torvalds's avatar
Linus Torvalds committed
1919 1920
		   (int) SCpnt->target, (int) SCpnt->lun);
	    print_command (SCpnt->cmnd);
Linus Torvalds's avatar
Linus Torvalds committed
1921
	    if (SCpnt->serial_number != SCpnt->serial_number_at_timeout)
Linus Torvalds's avatar
Linus Torvalds committed
1922 1923 1924 1925 1926 1927 1928 1929
		return 0;
	    SCpnt->abort_reason = why;
	    switch(host->hostt->abort(SCpnt)) {
		/* We do not know how to abort.  Try waiting another
		 * time increment and see if this helps. Set the
		 * WAS_TIMEDOUT flag set so we do not try this twice
		 */
	    case SCSI_ABORT_BUSY: /* Tough call - returning 1 from
Linus Torvalds's avatar
Linus Torvalds committed
1930
				   * this is too severe
Linus Torvalds's avatar
Linus Torvalds committed
1931 1932 1933 1934 1935 1936 1937
				   */
	    case SCSI_ABORT_SNOOZE:
		if(why == DID_TIME_OUT) {
		    save_flags(flags);
		    cli();
		    SCpnt->internal_timeout &= ~IN_ABORT;
		    if(SCpnt->flags & WAS_TIMEDOUT) {
Linus Torvalds's avatar
Linus Torvalds committed
1938
			restore_flags(flags);
Linus Torvalds's avatar
Linus Torvalds committed
1939 1940
			return 1; /* Indicate we cannot handle this.
				   * We drop down into the reset handler
Linus Torvalds's avatar
Linus Torvalds committed
1941
				   * and try again
Linus Torvalds's avatar
Linus Torvalds committed
1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960
				   */
		    } else {
			SCpnt->flags |= WAS_TIMEDOUT;
			oldto = SCpnt->timeout_per_command;
			update_timeout(SCpnt, oldto);
		    }
		    restore_flags(flags);
		}
		return 0;
	    case SCSI_ABORT_PENDING:
		if(why != DID_TIME_OUT) {
		    save_flags(flags);
		    cli();
		    update_timeout(SCpnt, oldto);
		    restore_flags(flags);
		}
		return 0;
	    case SCSI_ABORT_SUCCESS:
		/* We should have already aborted this one.  No
Linus Torvalds's avatar
Linus Torvalds committed
1961
		 * need to adjust timeout
Linus Torvalds's avatar
Linus Torvalds committed
1962
		 */
Linus Torvalds's avatar
Linus Torvalds committed
1963 1964
                 SCpnt->internal_timeout &= ~IN_ABORT;
                 return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976
	    case SCSI_ABORT_NOT_RUNNING:
		SCpnt->internal_timeout &= ~IN_ABORT;
		update_timeout(SCpnt, 0);
		return 0;
	    case SCSI_ABORT_ERROR:
	    default:
		SCpnt->internal_timeout &= ~IN_ABORT;
		return 1;
	    }
	}
    }
}
Linus Torvalds's avatar
Linus Torvalds committed
1977

Linus Torvalds's avatar
Linus Torvalds committed
1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989

/* Mark a single SCSI Device as having been reset. */

static inline void scsi_mark_device_reset(Scsi_Device *Device)
{
  Device->was_reset = 1;
  Device->expecting_cc_ua = 1;
}


/* Mark all SCSI Devices on a specific Host as having been reset. */

Linus Torvalds's avatar
Linus Torvalds committed
1990
void scsi_mark_host_reset(struct Scsi_Host *Host)
Linus Torvalds's avatar
Linus Torvalds committed
1991 1992
{
  Scsi_Cmnd *SCpnt;
Linus Torvalds's avatar
Linus Torvalds committed
1993
  for (SCpnt = Host->host_queue; SCpnt; SCpnt = SCpnt->next)
Linus Torvalds's avatar
Linus Torvalds committed
1994
      scsi_mark_device_reset(SCpnt->device);
Linus Torvalds's avatar
Linus Torvalds committed
1995 1996 1997
}


Linus Torvalds's avatar
Linus Torvalds committed
1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008
/* Mark all SCSI Devices on a specific Host Bus as having been reset. */

void scsi_mark_bus_reset(struct Scsi_Host *Host, int channel)
{
  Scsi_Cmnd *SCpnt;
  for (SCpnt = Host->host_queue; SCpnt; SCpnt = SCpnt->next)
      if (SCpnt->channel == channel)
	  scsi_mark_device_reset(SCpnt->device);
}


Linus Torvalds's avatar
Linus Torvalds committed
2009
int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
Linus Torvalds's avatar
Linus Torvalds committed
2010
{
Linus Torvalds's avatar
Linus Torvalds committed
2011
    int temp;
Linus Torvalds's avatar
Linus Torvalds committed
2012 2013 2014
    unsigned long flags;
    Scsi_Cmnd * SCpnt1;
    struct Scsi_Host * host = SCpnt->host;
Linus Torvalds's avatar
Linus Torvalds committed
2015

Linus Torvalds's avatar
Linus Torvalds committed
2016 2017
    printk("SCSI bus is being reset for host %d channel %d.\n",
	   host->host_no, SCpnt->channel);
Linus Torvalds's avatar
Linus Torvalds committed
2018

Linus Torvalds's avatar
Linus Torvalds committed
2019
#if 0
Linus Torvalds's avatar
Linus Torvalds committed
2020 2021 2022 2023 2024 2025 2026 2027
    /*
     * First of all, we need to make a recommendation to the low-level
     * driver as to whether a BUS_DEVICE_RESET should be performed,
     * or whether we should do a full BUS_RESET.  There is no simple
     * algorithm here - we basically use a series of heuristics
     * to determine what we should do.
     */
    SCpnt->host->suggest_bus_reset = FALSE;
Linus Torvalds's avatar
Linus Torvalds committed
2028

Linus Torvalds's avatar
Linus Torvalds committed
2029 2030 2031 2032 2033 2034 2035
    /*
     * First see if all of the active devices on the bus have
     * been jammed up so that we are attempting resets.  If so,
     * then suggest a bus reset.  Forcing a bus reset could
     * result in some race conditions, but no more than
     * you would usually get with timeouts.  We will cross
     * that bridge when we come to it.
Linus Torvalds's avatar
Linus Torvalds committed
2036 2037 2038 2039 2040 2041 2042
     *
     * This is actually a pretty bad idea, since a sequence of
     * commands will often timeout together and this will cause a
     * Bus Device Reset followed immediately by a SCSI Bus Reset.
     * If all of the active devices really are jammed up, the
     * Bus Device Reset will quickly timeout and scsi_times_out
     * will follow up with a SCSI Bus Reset anyway.
Linus Torvalds's avatar
Linus Torvalds committed
2043 2044 2045
     */
    SCpnt1 = host->host_queue;
    while(SCpnt1) {
Linus Torvalds's avatar
Linus Torvalds committed
2046
	if( SCpnt1->request.rq_status != RQ_INACTIVE
Linus Torvalds's avatar
Linus Torvalds committed
2047 2048
	    && (SCpnt1->flags & (WAS_RESET | IS_RESETTING)) == 0 )
            	break;
Linus Torvalds's avatar
Linus Torvalds committed
2049 2050
        SCpnt1 = SCpnt1->next;
 	}
Linus Torvalds's avatar
Linus Torvalds committed
2051
    if( SCpnt1 == NULL ) {
Linus Torvalds's avatar
Linus Torvalds committed
2052
        reset_flags |= SCSI_RESET_SUGGEST_BUS_RESET;
Linus Torvalds's avatar
Linus Torvalds committed
2053
    }
Linus Torvalds's avatar
Linus Torvalds committed
2054

Linus Torvalds's avatar
Linus Torvalds committed
2055 2056 2057 2058
    /*
     * If the code that called us is suggesting a hard reset, then
     * definitely request it.  This usually occurs because a
     * BUS_DEVICE_RESET times out.
Linus Torvalds's avatar
Linus Torvalds committed
2059 2060
     *
     * Passing reset_flags along takes care of this automatically.
Linus Torvalds's avatar
Linus Torvalds committed
2061
     */
Linus Torvalds's avatar
Linus Torvalds committed
2062
    if( reset_flags & SCSI_RESET_SUGGEST_BUS_RESET ) {
Linus Torvalds's avatar
Linus Torvalds committed
2063
        SCpnt->host->suggest_bus_reset = TRUE;
Linus Torvalds's avatar
Linus Torvalds committed
2064
    }
Linus Torvalds's avatar
Linus Torvalds committed
2065
#endif
Linus Torvalds's avatar
Linus Torvalds committed
2066

Linus Torvalds's avatar
Linus Torvalds committed
2067 2068 2069
    while (1) {
	save_flags(flags);
	cli();
Linus Torvalds's avatar
Linus Torvalds committed
2070 2071 2072 2073 2074

	/*
	 * Protect against races here.  If the command is done, or we are
	 * on a different command forget it.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
2075 2076
	if (reset_flags & SCSI_RESET_ASYNCHRONOUS)
	  if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
Linus Torvalds's avatar
Linus Torvalds committed
2077 2078
	    restore_flags(flags);
	    return 0;
Linus Torvalds's avatar
Linus Torvalds committed
2079
	  }
Linus Torvalds's avatar
Linus Torvalds committed
2080

Linus Torvalds's avatar
Linus Torvalds committed
2081 2082 2083 2084 2085 2086 2087 2088 2089
	if (SCpnt->internal_timeout & IN_RESET)
	{
	    restore_flags(flags);
	    while (SCpnt->internal_timeout & IN_RESET)
		barrier();
	}
	else
	{
	    SCpnt->internal_timeout |= IN_RESET;
Linus Torvalds's avatar
Linus Torvalds committed
2090
	    update_timeout(SCpnt, RESET_TIMEOUT);
Linus Torvalds's avatar
Linus Torvalds committed
2091

Linus Torvalds's avatar
Linus Torvalds committed
2092 2093 2094 2095 2096
	    if (host->host_busy)
	    {
		restore_flags(flags);
		SCpnt1 = host->host_queue;
		while(SCpnt1) {
Linus Torvalds's avatar
Linus Torvalds committed
2097
		    if (SCpnt1->request.rq_status != RQ_INACTIVE) {
Linus Torvalds's avatar
Linus Torvalds committed
2098
#if 0
Linus Torvalds's avatar
Linus Torvalds committed
2099 2100
			if (!(SCpnt1->flags & IS_RESETTING) &&
			    !(SCpnt1->internal_timeout & IN_ABORT))
Linus Torvalds's avatar
Linus Torvalds committed
2101
			    scsi_abort(SCpnt1, DID_RESET);
Linus Torvalds's avatar
Linus Torvalds committed
2102
#endif
Linus Torvalds's avatar
Linus Torvalds committed
2103
			SCpnt1->flags |= (WAS_RESET | IS_RESETTING);
Linus Torvalds's avatar
Linus Torvalds committed
2104 2105 2106
		    }
		    SCpnt1 = SCpnt1->next;
		}
Linus Torvalds's avatar
Linus Torvalds committed
2107

Linus Torvalds's avatar
Linus Torvalds committed
2108
		host->last_reset = jiffies;
Linus Torvalds's avatar
Linus Torvalds committed
2109
		temp = host->hostt->reset(SCpnt, reset_flags);
Linus Torvalds's avatar
Linus Torvalds committed
2110 2111 2112 2113 2114 2115 2116 2117 2118 2119
		/*
		  This test allows the driver to introduce an additional bus
		  settle time delay by setting last_reset up to 20 seconds in
		  the future.  In the normal case where the driver does not
		  modify last_reset, it must be assumed that the actual bus
		  reset occurred immediately prior to the return to this code,
		  and so last_reset must be updated to the current time, so
		  that the delay in internal_cmnd will guarantee at least a
		  MIN_RESET_DELAY bus settle time.
		*/
Linus Torvalds's avatar
Linus Torvalds committed
2120
		if (host->last_reset - jiffies > 20UL * HZ)
Linus Torvalds's avatar
Linus Torvalds committed
2121
		  host->last_reset = jiffies;
Linus Torvalds's avatar
Linus Torvalds committed
2122 2123 2124 2125 2126 2127
	    }
	    else
	    {
		if (!host->block) host->host_busy++;
		restore_flags(flags);
		host->last_reset = jiffies;
Linus Torvalds's avatar
Linus Torvalds committed
2128
	        SCpnt->flags |= (WAS_RESET | IS_RESETTING);
Linus Torvalds's avatar
Linus Torvalds committed
2129
		temp = host->hostt->reset(SCpnt, reset_flags);
Linus Torvalds's avatar
Linus Torvalds committed
2130
		if ((host->last_reset < jiffies) ||
Linus Torvalds's avatar
Linus Torvalds committed
2131 2132
		    (host->last_reset > (jiffies + 20 * HZ)))
		  host->last_reset = jiffies;
Linus Torvalds's avatar
Linus Torvalds committed
2133 2134
		if (!host->block) host->host_busy--;
	    }
Linus Torvalds's avatar
Linus Torvalds committed
2135

Linus Torvalds's avatar
Linus Torvalds committed
2136
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
2137
	    printk("scsi reset function returned %d\n", temp);
Linus Torvalds's avatar
Linus Torvalds committed
2138
#endif
Linus Torvalds's avatar
Linus Torvalds committed
2139

Linus Torvalds's avatar
Linus Torvalds committed
2140 2141 2142
            /*
             * Now figure out what we need to do, based upon
             * what the low level driver said that it did.
Linus Torvalds's avatar
Linus Torvalds committed
2143 2144 2145 2146 2147
	     * If the result is SCSI_RESET_SUCCESS, SCSI_RESET_PENDING,
	     * or SCSI_RESET_WAKEUP, then the low level driver did a
	     * bus device reset or bus reset, so we should go through
	     * and mark one or all of the devices on that bus
	     * as having been reset.
Linus Torvalds's avatar
Linus Torvalds committed
2148 2149
             */
            switch(temp & SCSI_RESET_ACTION) {
Linus Torvalds's avatar
Linus Torvalds committed
2150
	    case SCSI_RESET_SUCCESS:
Linus Torvalds's avatar
Linus Torvalds committed
2151 2152 2153 2154
	        if (temp & SCSI_RESET_HOST_RESET)
		  scsi_mark_host_reset(host);
	        else if (temp & SCSI_RESET_BUS_RESET)
		  scsi_mark_bus_reset(host, SCpnt->channel);
Linus Torvalds's avatar
Linus Torvalds committed
2155
		else scsi_mark_device_reset(SCpnt->device);
Linus Torvalds's avatar
Linus Torvalds committed
2156 2157
		save_flags(flags);
		cli();
Linus Torvalds's avatar
Linus Torvalds committed
2158
		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
Linus Torvalds's avatar
Linus Torvalds committed
2159 2160 2161
		restore_flags(flags);
		return 0;
	    case SCSI_RESET_PENDING:
Linus Torvalds's avatar
Linus Torvalds committed
2162 2163 2164 2165
	        if (temp & SCSI_RESET_HOST_RESET)
		  scsi_mark_host_reset(host);
	        else if (temp & SCSI_RESET_BUS_RESET)
		  scsi_mark_bus_reset(host, SCpnt->channel);
Linus Torvalds's avatar
Linus Torvalds committed
2166
		else scsi_mark_device_reset(SCpnt->device);
Linus Torvalds's avatar
Linus Torvalds committed
2167
	    case SCSI_RESET_NOT_RUNNING:
Linus Torvalds's avatar
Linus Torvalds committed
2168 2169
		return 0;
	    case SCSI_RESET_PUNT:
Linus Torvalds's avatar
Linus Torvalds committed
2170
		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
Linus Torvalds's avatar
Linus Torvalds committed
2171 2172
                scsi_request_sense (SCpnt);
                return 0;
Linus Torvalds's avatar
Linus Torvalds committed
2173
	    case SCSI_RESET_WAKEUP:
Linus Torvalds's avatar
Linus Torvalds committed
2174 2175 2176 2177
	        if (temp & SCSI_RESET_HOST_RESET)
		  scsi_mark_host_reset(host);
	        else if (temp & SCSI_RESET_BUS_RESET)
		  scsi_mark_bus_reset(host, SCpnt->channel);
Linus Torvalds's avatar
Linus Torvalds committed
2178
		else scsi_mark_device_reset(SCpnt->device);
Linus Torvalds's avatar
Linus Torvalds committed
2179
		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
Linus Torvalds's avatar
Linus Torvalds committed
2180
		scsi_request_sense (SCpnt);
Linus Torvalds's avatar
Linus Torvalds committed
2181
                /*
Linus Torvalds's avatar
Linus Torvalds committed
2182
                 * If a bus reset was performed, we
Linus Torvalds's avatar
Linus Torvalds committed
2183
                 * need to wake up each and every command
Linus Torvalds's avatar
Linus Torvalds committed
2184 2185
                 * that was active on the bus or if it was a HBA
                 * reset all active commands on all channels
Linus Torvalds's avatar
Linus Torvalds committed
2186
                 */
Linus Torvalds's avatar
Linus Torvalds committed
2187
                if( temp & SCSI_RESET_HOST_RESET )
Linus Torvalds's avatar
Linus Torvalds committed
2188
                {
Linus Torvalds's avatar
Linus Torvalds committed
2189 2190 2191 2192 2193 2194
		    SCpnt1 = host->host_queue;
		    while(SCpnt1) {
			if (SCpnt1->request.rq_status != RQ_INACTIVE
			    && SCpnt1 != SCpnt)
			    scsi_request_sense (SCpnt1);
			SCpnt1 = SCpnt1->next;
Linus Torvalds's avatar
Linus Torvalds committed
2195
                    }
Linus Torvalds's avatar
Linus Torvalds committed
2196 2197 2198 2199
                } else if( temp & SCSI_RESET_BUS_RESET ) {
                    SCpnt1 = host->host_queue;
                    while(SCpnt1) {
                        if(SCpnt1->request.rq_status != RQ_INACTIVE
Linus Torvalds's avatar
Linus Torvalds committed
2200
                           && SCpnt1 != SCpnt
Linus Torvalds's avatar
Linus Torvalds committed
2201 2202 2203 2204
                           && SCpnt1->channel == SCpnt->channel)
                            scsi_request_sense (SCpnt);
                        SCpnt1 = SCpnt1->next;
                    }
Linus Torvalds's avatar
Linus Torvalds committed
2205
                }
Linus Torvalds's avatar
Linus Torvalds committed
2206 2207 2208 2209 2210
		return 0;
	    case SCSI_RESET_SNOOZE:
		/* In this case, we set the timeout field to 0
		 * so that this command does not time out any more,
		 * and we return 1 so that we get a message on the
Linus Torvalds's avatar
Linus Torvalds committed
2211
		 * screen.
Linus Torvalds's avatar
Linus Torvalds committed
2212 2213 2214
		 */
		save_flags(flags);
		cli();
Linus Torvalds's avatar
Linus Torvalds committed
2215
		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
Linus Torvalds's avatar
Linus Torvalds committed
2216 2217 2218 2219 2220 2221 2222
		update_timeout(SCpnt, 0);
		restore_flags(flags);
		/* If you snooze, you lose... */
	    case SCSI_RESET_ERROR:
	    default:
		return 1;
	    }
Linus Torvalds's avatar
Linus Torvalds committed
2223

Linus Torvalds's avatar
Linus Torvalds committed
2224
	    return temp;
2225
	}
Linus Torvalds's avatar
Linus Torvalds committed
2226 2227
    }
}
Linus Torvalds's avatar
Linus Torvalds committed
2228

2229 2230

static void scsi_main_timeout(void)
Linus Torvalds's avatar
Linus Torvalds committed
2231 2232 2233 2234
{
    /*
     * We must not enter update_timeout with a timeout condition still pending.
     */
Linus Torvalds's avatar
Linus Torvalds committed
2235

Linus Torvalds's avatar
Linus Torvalds committed
2236
    int timed_out;
Linus Torvalds's avatar
Linus Torvalds committed
2237 2238 2239
    unsigned long flags;
    struct Scsi_Host * host;
    Scsi_Cmnd * SCpnt = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
2240

Linus Torvalds's avatar
Linus Torvalds committed
2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265
    save_flags(flags);
    cli();

    update_timeout(NULL, 0);

    /*
     * Find all timers such that they have 0 or negative (shouldn't happen)
     * time remaining on them.
     */
    timed_out = 0;
    for (host = scsi_hostlist; host; host = host->next) {
	for (SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
	    if (SCpnt->timeout == -1)
	      {
		SCpnt->timeout = 0;
		SCpnt->serial_number_at_timeout = SCpnt->serial_number;
		++timed_out;
	      }
    }
    if (timed_out > 0) {
	for (host = scsi_hostlist; host; host = host->next) {
	    for (SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
		if (SCpnt->serial_number_at_timeout > 0 &&
		    SCpnt->serial_number_at_timeout == SCpnt->serial_number)
		  {
Linus Torvalds's avatar
Linus Torvalds committed
2266
		    restore_flags(flags);
Linus Torvalds's avatar
Linus Torvalds committed
2267 2268
		    scsi_times_out(SCpnt);
		    SCpnt->serial_number_at_timeout = 0;
Linus Torvalds's avatar
Linus Torvalds committed
2269
		    cli();
Linus Torvalds's avatar
Linus Torvalds committed
2270 2271 2272
		  }
	  }
    }
Linus Torvalds's avatar
Linus Torvalds committed
2273 2274
    restore_flags(flags);
}
2275 2276

/*
Linus Torvalds's avatar
Linus Torvalds committed
2277 2278 2279 2280 2281 2282
 * The strategy is to cause the timer code to call scsi_times_out()
 * when the soonest timeout is pending.
 * The arguments are used when we are queueing a new command, because
 * we do not want to subtract the time used from this time, but when we
 * set the timer, we want to take this value into account.
 */
Linus Torvalds's avatar
Linus Torvalds committed
2283

Linus Torvalds's avatar
Linus Torvalds committed
2284
int update_timeout(Scsi_Cmnd * SCset, int timeout)
Linus Torvalds's avatar
Linus Torvalds committed
2285 2286 2287 2288 2289 2290
{
    unsigned int least, used;
    unsigned int oldto;
    unsigned long flags;
    struct Scsi_Host * host;
    Scsi_Cmnd * SCpnt = NULL;
2291

Linus Torvalds's avatar
Linus Torvalds committed
2292 2293
    save_flags(flags);
    cli();
Linus Torvalds's avatar
Linus Torvalds committed
2294

Linus Torvalds's avatar
Linus Torvalds committed
2295 2296 2297 2298 2299 2300 2301
    oldto = 0;

    /*
     * This routine can be a performance bottleneck under high loads, since
     * it is called twice per SCSI operation: once when internal_cmnd is
     * called, and again when scsi_done completes the command.  To limit
     * the load this routine can cause, we shortcut processing if no clock
Linus Torvalds's avatar
Linus Torvalds committed
2302
     * ticks have occurred since the last time it was called.
Linus Torvalds's avatar
Linus Torvalds committed
2303 2304 2305 2306 2307 2308
     */

    if (jiffies == time_start && timer_table[SCSI_TIMER].expires > 0) {
	if(SCset){
	    oldto = SCset->timeout;
	    SCset->timeout = timeout;
Linus Torvalds's avatar
Linus Torvalds committed
2309 2310 2311
	    if (timeout > 0 &&
		jiffies + timeout < timer_table[SCSI_TIMER].expires)
		    timer_table[SCSI_TIMER].expires = jiffies + timeout;
Linus Torvalds's avatar
Linus Torvalds committed
2312 2313 2314 2315 2316
	}
	restore_flags(flags);
	return oldto;
    }

Linus Torvalds's avatar
Linus Torvalds committed
2317 2318 2319 2320 2321
    /*
     * Figure out how much time has passed since the last time the timeouts
     * were updated
     */
    used = (time_start) ? (jiffies - time_start) : 0;
2322

Linus Torvalds's avatar
Linus Torvalds committed
2323 2324 2325 2326 2327
    /*
     * Find out what is due to timeout soonest, and adjust all timeouts for
     * the amount of time that has passed since the last time we called
     * update_timeout.
     */
2328

Linus Torvalds's avatar
Linus Torvalds committed
2329
    oldto = 0;
Linus Torvalds's avatar
Linus Torvalds committed
2330

Linus Torvalds's avatar
Linus Torvalds committed
2331 2332
    if(SCset){
	oldto = SCset->timeout - used;
Linus Torvalds's avatar
Linus Torvalds committed
2333
	SCset->timeout = timeout;
Linus Torvalds's avatar
Linus Torvalds committed
2334
    }
2335

Linus Torvalds's avatar
Linus Torvalds committed
2336
    least = 0xffffffff;
Linus Torvalds's avatar
Linus Torvalds committed
2337

Linus Torvalds's avatar
Linus Torvalds committed
2338 2339
    for(host = scsi_hostlist; host; host = host->next)
	for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
Linus Torvalds's avatar
Linus Torvalds committed
2340
	    if (SCpnt->timeout > 0) {
Linus Torvalds's avatar
Linus Torvalds committed
2341
	        if (SCpnt != SCset)
Linus Torvalds's avatar
Linus Torvalds committed
2342
		    SCpnt->timeout -= used;
Linus Torvalds's avatar
Linus Torvalds committed
2343 2344 2345
		if(SCpnt->timeout <= 0) SCpnt->timeout = -1;
		if(SCpnt->timeout > 0 && SCpnt->timeout < least)
		    least = SCpnt->timeout;
Linus Torvalds's avatar
Linus Torvalds committed
2346
	    }
Linus Torvalds's avatar
Linus Torvalds committed
2347

Linus Torvalds's avatar
Linus Torvalds committed
2348 2349 2350 2351
    /*
     * If something is due to timeout again, then we will set the next timeout
     * interrupt to occur.  Otherwise, timeouts are disabled.
     */
Linus Torvalds's avatar
Linus Torvalds committed
2352

Linus Torvalds's avatar
Linus Torvalds committed
2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366
    if (least != 0xffffffff)
    {
	time_start = jiffies;
	timer_table[SCSI_TIMER].expires = (time_elapsed = least) + jiffies;
	timer_active |= 1 << SCSI_TIMER;
    }
    else
    {
	timer_table[SCSI_TIMER].expires = time_start = time_elapsed = 0;
	timer_active &= ~(1 << SCSI_TIMER);
    }
    restore_flags(flags);
    return oldto;
}
2367

Linus Torvalds's avatar
Linus Torvalds committed
2368
#ifdef CONFIG_MODULES
Linus Torvalds's avatar
Linus Torvalds committed
2369 2370
static int scsi_register_host(Scsi_Host_Template *);
static void scsi_unregister_host(Scsi_Host_Template *);
Linus Torvalds's avatar
Linus Torvalds committed
2371
#endif
2372

2373
void *scsi_malloc(unsigned int len)
2374
{
Linus Torvalds's avatar
Linus Torvalds committed
2375 2376 2377
    unsigned int nbits, mask;
    unsigned long flags;
    int i, j;
Linus Torvalds's avatar
Linus Torvalds committed
2378
    if(len % SECTOR_SIZE != 0 || len > PAGE_SIZE)
Linus Torvalds's avatar
Linus Torvalds committed
2379
	return NULL;
Linus Torvalds's avatar
Linus Torvalds committed
2380

Linus Torvalds's avatar
Linus Torvalds committed
2381 2382 2383 2384
    save_flags(flags);
    cli();
    nbits = len >> 9;
    mask = (1 << nbits) - 1;
Linus Torvalds's avatar
Linus Torvalds committed
2385

Linus Torvalds's avatar
Linus Torvalds committed
2386 2387
    for(i=0;i < dma_sectors / SECTORS_PER_PAGE; i++)
	for(j=0; j<=SECTORS_PER_PAGE - nbits; j++){
Linus Torvalds's avatar
Linus Torvalds committed
2388 2389 2390 2391
	    if ((dma_malloc_freelist[i] & (mask << j)) == 0){
		dma_malloc_freelist[i] |= (mask << j);
		restore_flags(flags);
		dma_free_sectors -= nbits;
2392
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
2393
		printk("SMalloc: %d %p\n",len, dma_malloc_pages[i] + (j << 9));
2394
#endif
Linus Torvalds's avatar
Linus Torvalds committed
2395 2396 2397 2398 2399
		return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9));
	    }
	}
    restore_flags(flags);
    return NULL;  /* Nope.  No more */
2400 2401
}

2402
int scsi_free(void *obj, unsigned int len)
2403
{
Linus Torvalds's avatar
Linus Torvalds committed
2404
    unsigned int page, sector, nbits, mask;
Linus Torvalds's avatar
Linus Torvalds committed
2405
    unsigned long flags;
Linus Torvalds's avatar
Linus Torvalds committed
2406

2407
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
2408 2409 2410 2411 2412 2413 2414
    unsigned long ret = 0;

#ifdef __mips__
    __asm__ __volatile__ ("move\t%0,$31":"=r"(ret));
#else
   ret = __builtin_return_address(0);
#endif
Linus Torvalds's avatar
Linus Torvalds committed
2415
    printk("scsi_free %p %d\n",obj, len);
2416
#endif
Linus Torvalds's avatar
Linus Torvalds committed
2417

Linus Torvalds's avatar
Linus Torvalds committed
2418 2419 2420 2421
    for (page = 0; page < dma_sectors / SECTORS_PER_PAGE; page++) {
        unsigned long page_addr = (unsigned long) dma_malloc_pages[page];
        if ((unsigned long) obj >= page_addr &&
	    (unsigned long) obj <  page_addr + PAGE_SIZE)
Linus Torvalds's avatar
Linus Torvalds committed
2422
	{
Linus Torvalds's avatar
Linus Torvalds committed
2423 2424 2425 2426 2427 2428 2429 2430 2431 2432
	    sector = (((unsigned long) obj) - page_addr) >> 9;

            nbits = len >> 9;
            mask = (1 << nbits) - 1;

            if ((mask << sector) >= (1 << SECTORS_PER_PAGE))
                panic ("scsi_free:Bad memory alignment");

            save_flags(flags);
            cli();
Linus Torvalds's avatar
Linus Torvalds committed
2433
            if((dma_malloc_freelist[page] &
Linus Torvalds's avatar
Linus Torvalds committed
2434 2435
                (mask << sector)) != (mask<<sector)){
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
2436
		printk("scsi_free(obj=%p, len=%d) called from %08lx\n",
Linus Torvalds's avatar
Linus Torvalds committed
2437 2438
                       obj, len, ret);
#endif
Linus Torvalds's avatar
Linus Torvalds committed
2439
                panic("scsi_free:Trying to free unused memory");
Linus Torvalds's avatar
Linus Torvalds committed
2440
            }
Linus Torvalds's avatar
Linus Torvalds committed
2441 2442 2443 2444
            dma_free_sectors += nbits;
            dma_malloc_freelist[page] &= ~(mask << sector);
            restore_flags(flags);
            return 0;
Linus Torvalds's avatar
Linus Torvalds committed
2445
	}
Linus Torvalds's avatar
Linus Torvalds committed
2446 2447
    }
    panic("scsi_free:Bad offset");
2448 2449
}

Linus Torvalds's avatar
Linus Torvalds committed
2450

Linus Torvalds's avatar
Linus Torvalds committed
2451 2452
int scsi_loadable_module_flag; /* Set after we scan builtin drivers */

Linus Torvalds's avatar
Linus Torvalds committed
2453
void * scsi_init_malloc(unsigned int size, int priority)
Linus Torvalds's avatar
Linus Torvalds committed
2454
{
Linus Torvalds's avatar
Linus Torvalds committed
2455
    void * retval;
Linus Torvalds's avatar
Linus Torvalds committed
2456

Linus Torvalds's avatar
Linus Torvalds committed
2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469
    /*
     * For buffers used by the DMA pool, we assume page aligned 
     * structures.
     */
    if ((size % PAGE_SIZE) == 0) {
	int order, a_size;
	for (order = 0, a_size = PAGE_SIZE;
             a_size < size; order++, a_size <<= 1)
            ;
        retval = (void *) __get_dma_pages(priority & GFP_LEVEL_MASK,
	                                            order);
    } else
        retval = kmalloc(size, priority);
Linus Torvalds's avatar
Linus Torvalds committed
2470

Linus Torvalds's avatar
Linus Torvalds committed
2471
    if (retval)
Linus Torvalds's avatar
Linus Torvalds committed
2472 2473
	memset(retval, 0, size);
    return retval;
Linus Torvalds's avatar
Linus Torvalds committed
2474 2475 2476 2477
}


void scsi_init_free(char * ptr, unsigned int size)
Linus Torvalds's avatar
Linus Torvalds committed
2478
{
Linus Torvalds's avatar
Linus Torvalds committed
2479 2480 2481 2482 2483 2484 2485
    /*
     * We need this special code here because the DMA pool assumes
     * page aligned data.  Besides, it is wasteful to allocate
     * page sized chunks with kmalloc.
     */
    if ((size % PAGE_SIZE) == 0) {
    	int order, a_size;
Linus Torvalds's avatar
Linus Torvalds committed
2486

Linus Torvalds's avatar
Linus Torvalds committed
2487 2488 2489 2490 2491 2492
	for (order = 0, a_size = PAGE_SIZE;
	     a_size < size; order++, a_size <<= 1)
	    ;
	free_pages((unsigned long)ptr, order);
    } else
	kfree(ptr);
Linus Torvalds's avatar
Linus Torvalds committed
2493
}
Linus Torvalds's avatar
Linus Torvalds committed
2494

Linus Torvalds's avatar
Linus Torvalds committed
2495 2496
void scsi_build_commandblocks(Scsi_Device * SDpnt)
{
Linus Torvalds's avatar
Linus Torvalds committed
2497
    struct Scsi_Host *host = SDpnt->host;
Linus Torvalds's avatar
Linus Torvalds committed
2498
    int j;
Linus Torvalds's avatar
Linus Torvalds committed
2499
    Scsi_Cmnd * SCpnt;
Linus Torvalds's avatar
Linus Torvalds committed
2500 2501 2502 2503

    if (SDpnt->queue_depth == 0)
        SDpnt->queue_depth = host->cmd_per_lun;
    SDpnt->device_queue = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
2504

Linus Torvalds's avatar
Linus Torvalds committed
2505 2506 2507 2508 2509
    for(j=0;j<SDpnt->queue_depth;j++){
      SCpnt = (Scsi_Cmnd *)
              scsi_init_malloc(sizeof(Scsi_Cmnd),
                               GFP_ATOMIC |
                               (host->unchecked_isa_dma ? GFP_DMA : 0));
Linus Torvalds's avatar
Linus Torvalds committed
2510
	SCpnt->host = host;
Linus Torvalds's avatar
Linus Torvalds committed
2511 2512 2513 2514
	SCpnt->device = SDpnt;
	SCpnt->target = SDpnt->id;
	SCpnt->lun = SDpnt->lun;
	SCpnt->channel = SDpnt->channel;
Linus Torvalds's avatar
Linus Torvalds committed
2515
	SCpnt->request.rq_status = RQ_INACTIVE;
Linus Torvalds's avatar
Linus Torvalds committed
2516 2517 2518 2519 2520 2521
	SCpnt->use_sg = 0;
	SCpnt->old_use_sg = 0;
	SCpnt->old_cmd_len = 0;
	SCpnt->timeout = 0;
	SCpnt->underflow = 0;
	SCpnt->transfersize = 0;
Linus Torvalds's avatar
Linus Torvalds committed
2522 2523
	SCpnt->serial_number = 0;
	SCpnt->serial_number_at_timeout = 0;
Linus Torvalds's avatar
Linus Torvalds committed
2524 2525 2526 2527 2528 2529
	SCpnt->host_scribble = NULL;
	if(host->host_queue)
	    host->host_queue->prev = SCpnt;
	SCpnt->next = host->host_queue;
	SCpnt->prev = NULL;
	host->host_queue = SCpnt;
Linus Torvalds's avatar
Linus Torvalds committed
2530 2531
	SCpnt->device_next = SDpnt->device_queue;
	SDpnt->device_queue = SCpnt;
Linus Torvalds's avatar
Linus Torvalds committed
2532
    }
Linus Torvalds's avatar
Linus Torvalds committed
2533
    SDpnt->has_cmdblocks = 1;
Linus Torvalds's avatar
Linus Torvalds committed
2534 2535
}

2536
/*
Linus Torvalds's avatar
Linus Torvalds committed
2537
 * scsi_dev_init() is our initialization routine, which in turn calls host
Linus Torvalds's avatar
Linus Torvalds committed
2538
 * initialization, bus scanning, and sd/st initialization routines.
Linus Torvalds's avatar
Linus Torvalds committed
2539
 */
2540

Linus Torvalds's avatar
Linus Torvalds committed
2541
__initfunc(int scsi_dev_init(void))
Linus Torvalds's avatar
Linus Torvalds committed
2542 2543 2544 2545
{
    Scsi_Device * SDpnt;
    struct Scsi_Host * shpnt;
    struct Scsi_Device_Template * sdtpnt;
2546
#ifdef FOO_ON_YOU
Linus Torvalds's avatar
Linus Torvalds committed
2547
    return;
Linus Torvalds's avatar
Linus Torvalds committed
2548
#endif
Linus Torvalds's avatar
Linus Torvalds committed
2549

Linus Torvalds's avatar
Linus Torvalds committed
2550
    /* Yes we're here... */
Linus Torvalds's avatar
Linus Torvalds committed
2551
#if CONFIG_PROC_FS
Linus Torvalds's avatar
Linus Torvalds committed
2552
    dispatch_scsi_info_ptr = dispatch_scsi_info;
Linus Torvalds's avatar
Linus Torvalds committed
2553
#endif
Linus Torvalds's avatar
Linus Torvalds committed
2554

Linus Torvalds's avatar
Linus Torvalds committed
2555 2556
    /* Init a few things so we can "malloc" memory. */
    scsi_loadable_module_flag = 0;
Linus Torvalds's avatar
Linus Torvalds committed
2557

Linus Torvalds's avatar
Linus Torvalds committed
2558 2559
    timer_table[SCSI_TIMER].fn = scsi_main_timeout;
    timer_table[SCSI_TIMER].expires = 0;
2560

Linus Torvalds's avatar
Linus Torvalds committed
2561
    /* Register the /proc/scsi/scsi entry */
Linus Torvalds's avatar
Linus Torvalds committed
2562 2563
#if CONFIG_PROC_FS
    proc_scsi_register(0, &proc_scsi_scsi);
Linus Torvalds's avatar
Linus Torvalds committed
2564 2565
#endif

Linus Torvalds's avatar
Linus Torvalds committed
2566 2567
    /* initialize all hosts */
    scsi_init();
Linus Torvalds's avatar
Linus Torvalds committed
2568

Linus Torvalds's avatar
Linus Torvalds committed
2569
    scsi_devices = (Scsi_Device *) NULL;
2570

Linus Torvalds's avatar
Linus Torvalds committed
2571
    for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
Linus Torvalds's avatar
Linus Torvalds committed
2572
	scan_scsis(shpnt,0,0,0,0);           /* scan for scsi devices */
Linus Torvalds's avatar
Linus Torvalds committed
2573 2574 2575
	if (shpnt->select_queue_depths != NULL)
	    (shpnt->select_queue_depths)(shpnt, scsi_devices);
    }
2576

Linus Torvalds's avatar
Linus Torvalds committed
2577 2578 2579
    printk("scsi : detected ");
    for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
	if (sdtpnt->dev_noticed && sdtpnt->name)
Linus Torvalds's avatar
Linus Torvalds committed
2580
	    printk("%d SCSI %s%s ", sdtpnt->dev_noticed, sdtpnt->name,
Linus Torvalds's avatar
Linus Torvalds committed
2581 2582
		   (sdtpnt->dev_noticed != 1) ? "s" : "");
    printk("total.\n");
Linus Torvalds's avatar
Linus Torvalds committed
2583

Linus Torvalds's avatar
Linus Torvalds committed
2584 2585
    for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
	if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
Linus Torvalds's avatar
Linus Torvalds committed
2586

Linus Torvalds's avatar
Linus Torvalds committed
2587 2588
    for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
	SDpnt->scsi_request_fn = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
2589
	for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
Linus Torvalds's avatar
Linus Torvalds committed
2590 2591 2592
	    if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
	if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
    }
Linus Torvalds's avatar
Linus Torvalds committed
2593

Linus Torvalds's avatar
Linus Torvalds committed
2594

Linus Torvalds's avatar
Linus Torvalds committed
2595 2596 2597 2598
    /*
     * This should build the DMA pool.
     */
    resize_dma_pool();
Linus Torvalds's avatar
Linus Torvalds committed
2599

Linus Torvalds's avatar
Linus Torvalds committed
2600 2601
    /*
     * OK, now we finish the initialization by doing spin-up, read
Linus Torvalds's avatar
Linus Torvalds committed
2602
     * capacity, etc, etc
Linus Torvalds's avatar
Linus Torvalds committed
2603 2604 2605
     */
    for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
	if(sdtpnt->finish && sdtpnt->nr_dev)
Linus Torvalds's avatar
Linus Torvalds committed
2606
	    (*sdtpnt->finish)();
Linus Torvalds's avatar
Linus Torvalds committed
2607

Linus Torvalds's avatar
Linus Torvalds committed
2608 2609
    scsi_loadable_module_flag = 1;

Linus Torvalds's avatar
Linus Torvalds committed
2610
    return 0;
Linus Torvalds's avatar
Linus Torvalds committed
2611
}
2612 2613 2614

static void print_inquiry(unsigned char *data)
{
Linus Torvalds's avatar
Linus Torvalds committed
2615
    int i;
Linus Torvalds's avatar
Linus Torvalds committed
2616

Linus Torvalds's avatar
Linus Torvalds committed
2617 2618 2619 2620 2621 2622 2623 2624
    printk("  Vendor: ");
    for (i = 8; i < 16; i++)
    {
	if (data[i] >= 0x20 && i < data[4] + 5)
	    printk("%c", data[i]);
	else
	    printk(" ");
    }
Linus Torvalds's avatar
Linus Torvalds committed
2625

Linus Torvalds's avatar
Linus Torvalds committed
2626 2627 2628 2629 2630 2631 2632 2633
    printk("  Model: ");
    for (i = 16; i < 32; i++)
    {
	if (data[i] >= 0x20 && i < data[4] + 5)
	    printk("%c", data[i]);
	else
	    printk(" ");
    }
Linus Torvalds's avatar
Linus Torvalds committed
2634

Linus Torvalds's avatar
Linus Torvalds committed
2635 2636 2637 2638 2639 2640 2641 2642
    printk("  Rev: ");
    for (i = 32; i < 36; i++)
    {
	if (data[i] >= 0x20 && i < data[4] + 5)
	    printk("%c", data[i]);
	else
	    printk(" ");
    }
Linus Torvalds's avatar
Linus Torvalds committed
2643

Linus Torvalds's avatar
Linus Torvalds committed
2644
    printk("\n");
Linus Torvalds's avatar
Linus Torvalds committed
2645

Linus Torvalds's avatar
Linus Torvalds committed
2646
    i = data[0] & 0x1f;
Linus Torvalds's avatar
Linus Torvalds committed
2647

Linus Torvalds's avatar
Linus Torvalds committed
2648 2649 2650 2651 2652 2653 2654 2655
    printk("  Type:   %s ",
	   i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] : "Unknown          " );
    printk("                 ANSI SCSI revision: %02x", data[2] & 0x07);
    if ((data[2] & 0x07) == 1 && (data[3] & 0x0f) == 1)
	printk(" CCS\n");
    else
	printk("\n");
}
2656 2657


Linus Torvalds's avatar
Linus Torvalds committed
2658
#ifdef CONFIG_PROC_FS
Linus Torvalds's avatar
Linus Torvalds committed
2659
int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
Linus Torvalds's avatar
Linus Torvalds committed
2660 2661
		    int hostno, int inout)
{
Linus Torvalds's avatar
Linus Torvalds committed
2662 2663 2664
    Scsi_Cmnd *SCpnt;
    struct Scsi_Device_Template *SDTpnt;
    Scsi_Device *scd, *scd_h = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
2665 2666
    struct Scsi_Host *HBA_ptr;
    char *p;
Linus Torvalds's avatar
Linus Torvalds committed
2667 2668
    int   host, channel, id, lun;
    int	  size, len = 0;
Linus Torvalds's avatar
Linus Torvalds committed
2669 2670
    off_t begin = 0;
    off_t pos = 0;
2671

Linus Torvalds's avatar
Linus Torvalds committed
2672 2673
    scd = scsi_devices;
    HBA_ptr = scsi_hostlist;
2674

Linus Torvalds's avatar
Linus Torvalds committed
2675
    if(inout == 0) {
Linus Torvalds's avatar
Linus Torvalds committed
2676
	size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none");
Linus Torvalds's avatar
Linus Torvalds committed
2677
	len += size;
Linus Torvalds's avatar
Linus Torvalds committed
2678 2679
	pos = begin + len;
	while (HBA_ptr) {
Linus Torvalds's avatar
Linus Torvalds committed
2680
#if 0
Linus Torvalds's avatar
Linus Torvalds committed
2681
	    size += sprintf(buffer+len,"scsi%2d: %s\n", (int) HBA_ptr->host_no,
Linus Torvalds's avatar
Linus Torvalds committed
2682
	                    HBA_ptr->hostt->procname);
Linus Torvalds's avatar
Linus Torvalds committed
2683
	    len += size;
Linus Torvalds's avatar
Linus Torvalds committed
2684
	    pos = begin + len;
Linus Torvalds's avatar
Linus Torvalds committed
2685
#endif
Linus Torvalds's avatar
Linus Torvalds committed
2686 2687 2688 2689
	    scd = scsi_devices;
	    while (scd) {
		if (scd->host == HBA_ptr) {
		    proc_print_scsidevice(scd, buffer, &size, len);
Linus Torvalds's avatar
Linus Torvalds committed
2690
		    len += size;
Linus Torvalds's avatar
Linus Torvalds committed
2691
		    pos = begin + len;
Linus Torvalds's avatar
Linus Torvalds committed
2692

Linus Torvalds's avatar
Linus Torvalds committed
2693 2694 2695 2696 2697 2698 2699 2700 2701
		    if (pos < offset) {
			len = 0;
			begin = pos;
		    }
		    if (pos > offset + length)
			goto stop_output;
		}
		scd = scd->next;
	    }
Linus Torvalds's avatar
Linus Torvalds committed
2702
	    HBA_ptr = HBA_ptr->next;
Linus Torvalds's avatar
Linus Torvalds committed
2703
	}
Linus Torvalds's avatar
Linus Torvalds committed
2704

Linus Torvalds's avatar
Linus Torvalds committed
2705
    stop_output:
Linus Torvalds's avatar
Linus Torvalds committed
2706
	*start=buffer+(offset-begin);   /* Start of wanted data */
Linus Torvalds's avatar
Linus Torvalds committed
2707
	len-=(offset-begin);	        /* Start slop */
Linus Torvalds's avatar
Linus Torvalds committed
2708
	if(len>length)
Linus Torvalds's avatar
Linus Torvalds committed
2709
	    len = length;		/* Ending slop */
Linus Torvalds's avatar
Linus Torvalds committed
2710
	return (len);
Linus Torvalds's avatar
Linus Torvalds committed
2711
    }
2712

Linus Torvalds's avatar
Linus Torvalds committed
2713 2714 2715
    if(!buffer || length < 25 || strncmp("scsi", buffer, 4))
	return(-EINVAL);

Linus Torvalds's avatar
Linus Torvalds committed
2716
    /*
Linus Torvalds's avatar
Linus Torvalds committed
2717
     * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi
Linus Torvalds's avatar
Linus Torvalds committed
2718
     * with  "0 1 2 3" replaced by your "Host Channel Id Lun".
Linus Torvalds's avatar
Linus Torvalds committed
2719 2720 2721
     * Consider this feature BETA.
     *     CAUTION: This is not for hotplugging your peripherals. As
     *     SCSI was not designed for this you could damage your
Linus Torvalds's avatar
Linus Torvalds committed
2722
     *     hardware !
Linus Torvalds's avatar
Linus Torvalds committed
2723
     * However perhaps it is legal to switch on an
Linus Torvalds's avatar
Linus Torvalds committed
2724
     * already connected device. It is perhaps not
Linus Torvalds's avatar
Linus Torvalds committed
2725
     * guaranteed this device doesn't corrupt an ongoing data transfer.
Linus Torvalds's avatar
Linus Torvalds committed
2726
     */
Linus Torvalds's avatar
Linus Torvalds committed
2727 2728
    if(!strncmp("add-single-device", buffer + 5, 17)) {
	p = buffer + 23;
2729

Linus Torvalds's avatar
Linus Torvalds committed
2730 2731 2732 2733
        host    = simple_strtoul(p, &p, 0);
        channel = simple_strtoul(p+1, &p, 0);
        id      = simple_strtoul(p+1, &p, 0);
        lun     = simple_strtoul(p+1, &p, 0);
Linus Torvalds's avatar
Linus Torvalds committed
2734

Linus Torvalds's avatar
Linus Torvalds committed
2735 2736
	printk("scsi singledevice %d %d %d %d\n", host, channel,
			id, lun);
Linus Torvalds's avatar
Linus Torvalds committed
2737

Linus Torvalds's avatar
Linus Torvalds committed
2738 2739 2740
	while(scd && (scd->host->host_no != host
	      || scd->channel != channel
	      || scd->id != id
Linus Torvalds's avatar
Linus Torvalds committed
2741
	      || scd->lun != lun)) {
Linus Torvalds's avatar
Linus Torvalds committed
2742 2743 2744 2745
	    scd = scd->next;
	}
	if(scd)
	    return(-ENOSYS);  /* We do not yet support unplugging */
Linus Torvalds's avatar
Linus Torvalds committed
2746
	while(HBA_ptr && HBA_ptr->host_no != host)
Linus Torvalds's avatar
Linus Torvalds committed
2747 2748 2749 2750 2751
	    HBA_ptr = HBA_ptr->next;

	if(!HBA_ptr)
	    return(-ENXIO);

Linus Torvalds's avatar
Linus Torvalds committed
2752
	scan_scsis (HBA_ptr, 1, channel, id, lun);
Linus Torvalds's avatar
Linus Torvalds committed
2753
	return(length);
Linus Torvalds's avatar
Linus Torvalds committed
2754 2755

    }
Linus Torvalds's avatar
Linus Torvalds committed
2756 2757 2758 2759 2760 2761 2762 2763 2764

    /*
     * Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi
     * with  "0 1 2 3" replaced by your "Host Channel Id Lun".
     *
     * Consider this feature pre-BETA.
     *
     *     CAUTION: This is not for hotplugging your peripherals. As
     *     SCSI was not designed for this you could damage your
Linus Torvalds's avatar
Linus Torvalds committed
2765
     *     hardware and thoroughly confuse the SCSI subsystem.
Linus Torvalds's avatar
Linus Torvalds committed
2766 2767 2768 2769
     *
     */
    else if(!strncmp("remove-single-device", buffer + 5, 20)) {
        p = buffer + 26;
Linus Torvalds's avatar
Linus Torvalds committed
2770

Linus Torvalds's avatar
Linus Torvalds committed
2771 2772 2773 2774
        host    = simple_strtoul(p, &p, 0);
        channel = simple_strtoul(p+1, &p, 0);
        id      = simple_strtoul(p+1, &p, 0);
        lun     = simple_strtoul(p+1, &p, 0);
Linus Torvalds's avatar
Linus Torvalds committed
2775

Linus Torvalds's avatar
Linus Torvalds committed
2776
        while(scd != NULL) {
Linus Torvalds's avatar
Linus Torvalds committed
2777 2778 2779
            if(scd->host->host_no == host
               && scd->channel == channel
               && scd->id == id
Linus Torvalds's avatar
Linus Torvalds committed
2780
               && scd->lun == lun){
Linus Torvalds's avatar
Linus Torvalds committed
2781
                break;
Linus Torvalds's avatar
Linus Torvalds committed
2782 2783 2784 2785
            }
            scd_h = scd;
            scd = scd->next;
        }
Linus Torvalds's avatar
Linus Torvalds committed
2786

Linus Torvalds's avatar
Linus Torvalds committed
2787 2788
        if(scd == NULL)
            return(-ENODEV);  /* there is no such device attached */
Linus Torvalds's avatar
Linus Torvalds committed
2789

Linus Torvalds's avatar
Linus Torvalds committed
2790 2791
        if(scd->access_count)
            return(-EBUSY);
Linus Torvalds's avatar
Linus Torvalds committed
2792

Linus Torvalds's avatar
Linus Torvalds committed
2793 2794 2795 2796 2797
        SDTpnt = scsi_devicelist;
        while(SDTpnt != NULL) {
            if(SDTpnt->detach) (*SDTpnt->detach)(scd);
            SDTpnt = SDTpnt->next;
        }
Linus Torvalds's avatar
Linus Torvalds committed
2798

Linus Torvalds's avatar
Linus Torvalds committed
2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820
        if(scd->attached == 0) {
            /*
             * Nobody is using this device any more.
             * Free all of the command structures.
             */
            for(SCpnt=scd->host->host_queue; SCpnt; SCpnt = SCpnt->next){
                if(SCpnt->device == scd) {
                    if(SCpnt->prev != NULL)
                        SCpnt->prev->next = SCpnt->next;
                    if(SCpnt->next != NULL)
                        SCpnt->next->prev = SCpnt->prev;
                    if(SCpnt == scd->host->host_queue)
                        scd->host->host_queue = SCpnt->next;
                    scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
                }
            }
            /* Now we can remove the device structure */
            if(scd_h != NULL) {
                scd_h->next = scd->next;
            } else if (scsi_devices == scd) {
                /* We had a hit on the first entry of the device list */
                scsi_devices = scd->next;
Linus Torvalds's avatar
Linus Torvalds committed
2821
            }
Linus Torvalds's avatar
Linus Torvalds committed
2822 2823 2824 2825 2826
            scsi_init_free((char *) scd, sizeof(Scsi_Device));
        } else {
            return(-EBUSY);
        }
        return(0);
Linus Torvalds's avatar
Linus Torvalds committed
2827 2828
    }
    return(-EINVAL);
2829
}
Linus Torvalds's avatar
Linus Torvalds committed
2830 2831
#endif

Linus Torvalds's avatar
Linus Torvalds committed
2832 2833 2834 2835 2836 2837 2838
/*
 * Go through the device list and recompute the most appropriate size
 * for the dma pool.  Then grab more memory (as required).
 */
static void resize_dma_pool(void)
{
    int i;
Linus Torvalds's avatar
Linus Torvalds committed
2839
    unsigned long size;
Linus Torvalds's avatar
Linus Torvalds committed
2840 2841 2842 2843
    struct Scsi_Host * shpnt;
    struct Scsi_Host * host = NULL;
    Scsi_Device * SDpnt;
    unsigned long flags;
Linus Torvalds's avatar
Linus Torvalds committed
2844
    FreeSectorBitmap * new_dma_malloc_freelist = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
2845 2846 2847 2848 2849 2850 2851 2852 2853 2854
    unsigned int new_dma_sectors = 0;
    unsigned int new_need_isa_buffer = 0;
    unsigned char ** new_dma_malloc_pages = NULL;

    if( !scsi_devices )
    {
	/*
	 * Free up the DMA pool.
	 */
	if( dma_free_sectors != dma_sectors )
Linus Torvalds's avatar
Linus Torvalds committed
2855
	    panic("SCSI DMA pool memory leak %d %d\n",dma_free_sectors,dma_sectors);
Linus Torvalds's avatar
Linus Torvalds committed
2856

Linus Torvalds's avatar
Linus Torvalds committed
2857
	for(i=0; i < dma_sectors / SECTORS_PER_PAGE; i++)
Linus Torvalds's avatar
Linus Torvalds committed
2858 2859
	    scsi_init_free(dma_malloc_pages[i], PAGE_SIZE);
	if (dma_malloc_pages)
Linus Torvalds's avatar
Linus Torvalds committed
2860
	    scsi_init_free((char *) dma_malloc_pages,
Linus Torvalds's avatar
Linus Torvalds committed
2861
                           (dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_pages));
Linus Torvalds's avatar
Linus Torvalds committed
2862 2863
	dma_malloc_pages = NULL;
	if (dma_malloc_freelist)
Linus Torvalds's avatar
Linus Torvalds committed
2864 2865
	    scsi_init_free((char *) dma_malloc_freelist,
                           (dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_freelist));
Linus Torvalds's avatar
Linus Torvalds committed
2866 2867 2868 2869 2870 2871
	dma_malloc_freelist = NULL;
	dma_sectors = 0;
	dma_free_sectors = 0;
	return;
    }
    /* Next, check to see if we need to extend the DMA buffer pool */
Linus Torvalds's avatar
Linus Torvalds committed
2872

Linus Torvalds's avatar
Linus Torvalds committed
2873
    new_dma_sectors = 2*SECTORS_PER_PAGE;		/* Base value we use */
Linus Torvalds's avatar
Linus Torvalds committed
2874

Linus Torvalds's avatar
Linus Torvalds committed
2875
    if (__pa(high_memory)-1 > ISA_DMA_THRESHOLD)
Linus Torvalds's avatar
Linus Torvalds committed
2876 2877 2878
	scsi_need_isa_bounce_buffers = 1;
    else
	scsi_need_isa_bounce_buffers = 0;
Linus Torvalds's avatar
Linus Torvalds committed
2879

Linus Torvalds's avatar
Linus Torvalds committed
2880 2881
    if (scsi_devicelist)
	for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
Linus Torvalds's avatar
Linus Torvalds committed
2882
	    new_dma_sectors += SECTORS_PER_PAGE;	/* Increment for each host */
Linus Torvalds's avatar
Linus Torvalds committed
2883

Linus Torvalds's avatar
Linus Torvalds committed
2884 2885
    for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
	host = SDpnt->host;
Linus Torvalds's avatar
Linus Torvalds committed
2886

Linus Torvalds's avatar
Linus Torvalds committed
2887 2888
	/*
	 * sd and sr drivers allocate scatterlists.
Linus Torvalds's avatar
Linus Torvalds committed
2889
	 * sr drivers may allocate for each command 1x2048 or 2x1024 extra
Linus Torvalds's avatar
Linus Torvalds committed
2890 2891 2892 2893 2894 2895 2896
	 * buffers for 2k sector size and 1k fs.
	 * sg driver allocates buffers < 4k.
	 * st driver does not need buffers from the dma pool.
	 * estimate 4k buffer/command for devices of unknown type (should panic).
	 */
	if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM ||
	    SDpnt->type == TYPE_DISK || SDpnt->type == TYPE_MOD) {
Linus Torvalds's avatar
Linus Torvalds committed
2897 2898
	    new_dma_sectors += ((host->sg_tablesize *
	                         sizeof(struct scatterlist) + 511) >> 9) *
Linus Torvalds's avatar
Linus Torvalds committed
2899
	                       SDpnt->queue_depth;
Linus Torvalds's avatar
Linus Torvalds committed
2900 2901 2902
	    if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM)
	        new_dma_sectors += (2048 >> 9) * SDpnt->queue_depth;
	}
Linus Torvalds's avatar
Linus Torvalds committed
2903 2904 2905
	else if (SDpnt->type == TYPE_SCANNER ||
		 SDpnt->type == TYPE_PROCESSOR ||
		 SDpnt->type == TYPE_MEDIUM_CHANGER) {
Linus Torvalds's avatar
Linus Torvalds committed
2906 2907 2908 2909 2910 2911 2912 2913 2914
	    new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
	}
	else {
	    if (SDpnt->type != TYPE_TAPE) {
	        printk("resize_dma_pool: unknown device type %d\n", SDpnt->type);
	        new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
	    }
        }

Linus Torvalds's avatar
Linus Torvalds committed
2915 2916 2917 2918
	if(host->unchecked_isa_dma &&
	   scsi_need_isa_bounce_buffers &&
	   SDpnt->type != TYPE_TAPE) {
	    new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
Linus Torvalds's avatar
Linus Torvalds committed
2919
						  SDpnt->queue_depth;
Linus Torvalds's avatar
Linus Torvalds committed
2920 2921 2922
	    new_need_isa_buffer++;
	}
    }
Linus Torvalds's avatar
Linus Torvalds committed
2923 2924 2925 2926 2927

#ifdef DEBUG_INIT
    printk("resize_dma_pool: needed dma sectors = %d\n", new_dma_sectors);
#endif

Linus Torvalds's avatar
Linus Torvalds committed
2928
    /* limit DMA memory to 32MB: */
Linus Torvalds's avatar
Linus Torvalds committed
2929
    new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
Linus Torvalds's avatar
Linus Torvalds committed
2930

Linus Torvalds's avatar
Linus Torvalds committed
2931 2932 2933 2934 2935 2936 2937
    /*
     * We never shrink the buffers - this leads to
     * race conditions that I would rather not even think
     * about right now.
     */
    if( new_dma_sectors < dma_sectors )
	new_dma_sectors = dma_sectors;
Linus Torvalds's avatar
Linus Torvalds committed
2938

Linus Torvalds's avatar
Linus Torvalds committed
2939 2940
    if (new_dma_sectors)
    {
Linus Torvalds's avatar
Linus Torvalds committed
2941 2942 2943 2944 2945 2946 2947
        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);
Linus Torvalds's avatar
Linus Torvalds committed
2948
    }
Linus Torvalds's avatar
Linus Torvalds committed
2949

Linus Torvalds's avatar
Linus Torvalds committed
2950 2951 2952 2953
    /*
     * If we need more buffers, expand the list.
     */
    if( new_dma_sectors > dma_sectors ) { 
Linus Torvalds's avatar
Linus Torvalds committed
2954
	for(i=dma_sectors / SECTORS_PER_PAGE; i< new_dma_sectors / SECTORS_PER_PAGE; i++)
Linus Torvalds's avatar
Linus Torvalds committed
2955 2956 2957
	    new_dma_malloc_pages[i] = (unsigned char *)
	        scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
    }
Linus Torvalds's avatar
Linus Torvalds committed
2958 2959 2960

    /* When we dick with the actual DMA list, we need to
     * protect things
Linus Torvalds's avatar
Linus Torvalds committed
2961 2962 2963 2964 2965
     */
    save_flags(flags);
    cli();
    if (dma_malloc_freelist)
    {
Linus Torvalds's avatar
Linus Torvalds committed
2966 2967 2968
        size = (dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap);
	memcpy(new_dma_malloc_freelist, dma_malloc_freelist, size);
	scsi_init_free((char *) dma_malloc_freelist, size);
Linus Torvalds's avatar
Linus Torvalds committed
2969 2970
    }
    dma_malloc_freelist = new_dma_malloc_freelist;
Linus Torvalds's avatar
Linus Torvalds committed
2971

Linus Torvalds's avatar
Linus Torvalds committed
2972 2973
    if (dma_malloc_pages)
    {
Linus Torvalds's avatar
Linus Torvalds committed
2974 2975 2976
        size = (dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_pages);
	memcpy(new_dma_malloc_pages, dma_malloc_pages, size);
	scsi_init_free((char *) dma_malloc_pages, size);
Linus Torvalds's avatar
Linus Torvalds committed
2977
    }
Linus Torvalds's avatar
Linus Torvalds committed
2978

Linus Torvalds's avatar
Linus Torvalds committed
2979 2980 2981 2982 2983
    dma_free_sectors += new_dma_sectors - dma_sectors;
    dma_malloc_pages = new_dma_malloc_pages;
    dma_sectors = new_dma_sectors;
    need_isa_buffer = new_need_isa_buffer;
    restore_flags(flags);
Linus Torvalds's avatar
Linus Torvalds committed
2984 2985 2986 2987 2988 2989

#ifdef DEBUG_INIT
    printk("resize_dma_pool: dma free sectors   = %d\n", dma_free_sectors);
    printk("resize_dma_pool: dma sectors        = %d\n", dma_sectors);
    printk("resize_dma_pool: need isa buffers   = %d\n", need_isa_buffer);
#endif
Linus Torvalds's avatar
Linus Torvalds committed
2990
}
Linus Torvalds's avatar
Linus Torvalds committed
2991

Linus Torvalds's avatar
Linus Torvalds committed
2992 2993
#ifdef CONFIG_MODULES		/* a big #ifdef block... */

Linus Torvalds's avatar
Linus Torvalds committed
2994 2995 2996 2997 2998 2999
/*
 * This entry point should be called by a loadable module if it is trying
 * add a low level scsi driver to the system.
 */
static int scsi_register_host(Scsi_Host_Template * tpnt)
{
Linus Torvalds's avatar
Linus Torvalds committed
3000 3001 3002 3003 3004
    int pcount;
    struct Scsi_Host * shpnt;
    Scsi_Device * SDpnt;
    struct Scsi_Device_Template * sdtpnt;
    const char * name;
Linus Torvalds's avatar
Linus Torvalds committed
3005

Linus Torvalds's avatar
Linus Torvalds committed
3006
    if (tpnt->next || !tpnt->detect) return 1;/* Must be already loaded, or
Linus Torvalds's avatar
Linus Torvalds committed
3007
					       * no detect routine available
Linus Torvalds's avatar
Linus Torvalds committed
3008 3009 3010
					       */
    pcount = next_scsi_host;
    if ((tpnt->present = tpnt->detect(tpnt)))
Linus Torvalds's avatar
Linus Torvalds committed
3011
    {
Linus Torvalds's avatar
Linus Torvalds committed
3012 3013 3014 3015 3016 3017 3018
	if(pcount == next_scsi_host) {
	    if(tpnt->present > 1) {
		printk("Failure to register low-level scsi driver");
		scsi_unregister_host(tpnt);
		return 1;
	    }
	    /* The low-level driver failed to register a driver.  We
Linus Torvalds's avatar
Linus Torvalds committed
3019
	     *  can do this now.
Linus Torvalds's avatar
Linus Torvalds committed
3020 3021
	     */
	    scsi_register(tpnt,0);
Linus Torvalds's avatar
Linus Torvalds committed
3022
	}
Linus Torvalds's avatar
Linus Torvalds committed
3023 3024
	tpnt->next = scsi_hosts; /* Add to the linked list */
	scsi_hosts = tpnt;
Linus Torvalds's avatar
Linus Torvalds committed
3025

Linus Torvalds's avatar
Linus Torvalds committed
3026
	/* Add the new driver to /proc/scsi */
Linus Torvalds's avatar
Linus Torvalds committed
3027
#if CONFIG_PROC_FS
Linus Torvalds's avatar
Linus Torvalds committed
3028
	build_proc_dir_entries(tpnt);
Linus Torvalds's avatar
Linus Torvalds committed
3029
#endif
Linus Torvalds's avatar
Linus Torvalds committed
3030

Linus Torvalds's avatar
Linus Torvalds committed
3031 3032 3033 3034 3035 3036 3037 3038 3039 3040
	for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
	    if(shpnt->hostt == tpnt)
	    {
		if(tpnt->info)
		    name = tpnt->info(shpnt);
		else
		    name = tpnt->name;
		printk ("scsi%d : %s\n", /* And print a little message */
			shpnt->host_no, name);
	    }
Linus Torvalds's avatar
Linus Torvalds committed
3041

Linus Torvalds's avatar
Linus Torvalds committed
3042
	printk ("scsi : %d host%s.\n", next_scsi_host,
Linus Torvalds's avatar
Linus Torvalds committed
3043
		(next_scsi_host == 1) ? "" : "s");
Linus Torvalds's avatar
Linus Torvalds committed
3044

Linus Torvalds's avatar
Linus Torvalds committed
3045
	scsi_make_blocked_list();
Linus Torvalds's avatar
Linus Torvalds committed
3046

Linus Torvalds's avatar
Linus Torvalds committed
3047
	/* The next step is to call scan_scsis here.  This generates the
Linus Torvalds's avatar
Linus Torvalds committed
3048
	 * Scsi_Devices entries
Linus Torvalds's avatar
Linus Torvalds committed
3049
	 */
Linus Torvalds's avatar
Linus Torvalds committed
3050

Linus Torvalds's avatar
Linus Torvalds committed
3051
	for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
Linus Torvalds's avatar
Linus Torvalds committed
3052 3053 3054 3055 3056
	    if(shpnt->hostt == tpnt) {
	      scan_scsis(shpnt,0,0,0,0);
	      if (shpnt->select_queue_depths != NULL)
		  (shpnt->select_queue_depths)(shpnt, scsi_devices);
	    }
Linus Torvalds's avatar
Linus Torvalds committed
3057

Linus Torvalds's avatar
Linus Torvalds committed
3058 3059
	for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
	    if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
Linus Torvalds's avatar
Linus Torvalds committed
3060

Linus Torvalds's avatar
Linus Torvalds committed
3061
	/* Next we create the Scsi_Cmnd structures for this host */
Linus Torvalds's avatar
Linus Torvalds committed
3062

Linus Torvalds's avatar
Linus Torvalds committed
3063 3064 3065 3066 3067 3068
	for(SDpnt = scsi_devices; 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);
Linus Torvalds's avatar
Linus Torvalds committed
3069
	    }
Linus Torvalds's avatar
Linus Torvalds committed
3070

Linus Torvalds's avatar
Linus Torvalds committed
3071
	/*
Linus Torvalds's avatar
Linus Torvalds committed
3072 3073 3074
	 * Now that we have all of the devices, resize the DMA pool,
	 * as required.  */
	resize_dma_pool();
Linus Torvalds's avatar
Linus Torvalds committed
3075 3076


Linus Torvalds's avatar
Linus Torvalds committed
3077 3078 3079 3080 3081
	/* This does any final handling that is required. */
	for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
	    if(sdtpnt->finish && sdtpnt->nr_dev)
		(*sdtpnt->finish)();
    }
Linus Torvalds's avatar
Linus Torvalds committed
3082

Linus Torvalds's avatar
Linus Torvalds committed
3083
#if defined(USE_STATIC_SCSI_MEMORY)
Linus Torvalds's avatar
Linus Torvalds committed
3084 3085 3086 3087
    printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
	    (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
	    (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
	    (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
Linus Torvalds's avatar
Linus Torvalds committed
3088
#endif
Linus Torvalds's avatar
Linus Torvalds committed
3089

Linus Torvalds's avatar
Linus Torvalds committed
3090 3091
    MOD_INC_USE_COUNT;
    return 0;
Linus Torvalds's avatar
Linus Torvalds committed
3092 3093 3094
}

/*
Linus Torvalds's avatar
Linus Torvalds committed
3095
 * Similarly, this entry point should be called by a loadable module if it
Linus Torvalds's avatar
Linus Torvalds committed
3096 3097 3098
 * is trying to remove a low level scsi driver from the system.
 */
static void scsi_unregister_host(Scsi_Host_Template * tpnt)
Linus Torvalds's avatar
Linus Torvalds committed
3099
{
Linus Torvalds's avatar
Linus Torvalds committed
3100 3101 3102 3103 3104 3105 3106
    Scsi_Host_Template * SHT, *SHTp;
    Scsi_Device *sdpnt, * sdppnt, * sdpnt1;
    Scsi_Cmnd * SCpnt;
    unsigned long flags;
    struct Scsi_Device_Template * sdtpnt;
    struct Scsi_Host * shpnt, *sh1;
    int pcount;
Linus Torvalds's avatar
Linus Torvalds committed
3107

Linus Torvalds's avatar
Linus Torvalds committed
3108 3109
    /* First verify that this host adapter is completely free with no pending
     * commands */
Linus Torvalds's avatar
Linus Torvalds committed
3110

Linus Torvalds's avatar
Linus Torvalds committed
3111
    for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
Linus Torvalds's avatar
Linus Torvalds committed
3112 3113 3114
	if(sdpnt->host->hostt == tpnt && sdpnt->host->hostt->module
	   && sdpnt->host->hostt->module->usecount) return;

Linus Torvalds's avatar
Linus Torvalds committed
3115
    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
Linus Torvalds's avatar
Linus Torvalds committed
3116
    {
Linus Torvalds's avatar
Linus Torvalds committed
3117 3118
	if (shpnt->hostt != tpnt) continue;
	for(SCpnt = shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
Linus Torvalds's avatar
Linus Torvalds committed
3119
	{
Linus Torvalds's avatar
Linus Torvalds committed
3120 3121
	    save_flags(flags);
	    cli();
Linus Torvalds's avatar
Linus Torvalds committed
3122
	    if(SCpnt->request.rq_status != RQ_INACTIVE) {
Linus Torvalds's avatar
Linus Torvalds committed
3123 3124
		restore_flags(flags);
		for(SCpnt = shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
Linus Torvalds's avatar
Linus Torvalds committed
3125 3126
		    if(SCpnt->request.rq_status == RQ_SCSI_DISCONNECTING)
			SCpnt->request.rq_status = RQ_INACTIVE;
Linus Torvalds's avatar
Linus Torvalds committed
3127 3128 3129
		printk("Device busy???\n");
		return;
	    }
Linus Torvalds's avatar
Linus Torvalds committed
3130
	    SCpnt->request.rq_status = RQ_SCSI_DISCONNECTING;  /* Mark as busy */
Linus Torvalds's avatar
Linus Torvalds committed
3131
	    restore_flags(flags);
Linus Torvalds's avatar
Linus Torvalds committed
3132 3133
	}
    }
Linus Torvalds's avatar
Linus Torvalds committed
3134
    /* Next we detach the high level drivers from the Scsi_Device structures */
Linus Torvalds's avatar
Linus Torvalds committed
3135

Linus Torvalds's avatar
Linus Torvalds committed
3136 3137 3138 3139 3140 3141 3142 3143 3144 3145
    for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
	if(sdpnt->host->hostt == tpnt)
	{
	    for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
		if(sdtpnt->detach) (*sdtpnt->detach)(sdpnt);
	    /* If something still attached, punt */
	    if (sdpnt->attached) {
		printk("Attached usage count = %d\n", sdpnt->attached);
		return;
	    }
Linus Torvalds's avatar
Linus Torvalds committed
3146
	}
Linus Torvalds's avatar
Linus Torvalds committed
3147

Linus Torvalds's avatar
Linus Torvalds committed
3148
    /* Next we free up the Scsi_Cmnd structures for this host */
Linus Torvalds's avatar
Linus Torvalds committed
3149

Linus Torvalds's avatar
Linus Torvalds committed
3150 3151 3152 3153 3154 3155 3156
    for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
	if(sdpnt->host->hostt == tpnt)
	    while (sdpnt->host->host_queue) {
		SCpnt = sdpnt->host->host_queue->next;
		scsi_init_free((char *) sdpnt->host->host_queue, sizeof(Scsi_Cmnd));
		sdpnt->host->host_queue = SCpnt;
		if (SCpnt) SCpnt->prev = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
3157
		sdpnt->has_cmdblocks = 0;
Linus Torvalds's avatar
Linus Torvalds committed
3158
	    }
Linus Torvalds's avatar
Linus Torvalds committed
3159

Linus Torvalds's avatar
Linus Torvalds committed
3160
    /* Next free up the Scsi_Device structures for this host */
Linus Torvalds's avatar
Linus Torvalds committed
3161

Linus Torvalds's avatar
Linus Torvalds committed
3162 3163
    sdppnt = NULL;
    for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt1)
Linus Torvalds's avatar
Linus Torvalds committed
3164
    {
Linus Torvalds's avatar
Linus Torvalds committed
3165 3166 3167 3168 3169 3170 3171 3172 3173
	sdpnt1 = sdpnt->next;
	if (sdpnt->host->hostt == tpnt) {
	    if (sdppnt)
		sdppnt->next = sdpnt->next;
	    else
		scsi_devices = sdpnt->next;
	    scsi_init_free((char *) sdpnt, sizeof (Scsi_Device));
	} else
	    sdppnt = sdpnt;
Linus Torvalds's avatar
Linus Torvalds committed
3174
    }
Linus Torvalds's avatar
Linus Torvalds committed
3175

Linus Torvalds's avatar
Linus Torvalds committed
3176 3177
    /* Next we go through and remove the instances of the individual hosts
     * that were detected */
Linus Torvalds's avatar
Linus Torvalds committed
3178

Linus Torvalds's avatar
Linus Torvalds committed
3179 3180 3181 3182 3183 3184
    shpnt = scsi_hostlist;
    while(shpnt) {
	sh1 = shpnt->next;
	if(shpnt->hostt == tpnt) {
	    if(shpnt->loaded_as_module) {
		pcount = next_scsi_host;
Linus Torvalds's avatar
Linus Torvalds committed
3185
	        /* Remove the /proc/scsi directory entry */
Linus Torvalds's avatar
Linus Torvalds committed
3186 3187
#if CONFIG_PROC_FS
	        proc_scsi_unregister(tpnt->proc_dir,
Linus Torvalds's avatar
Linus Torvalds committed
3188
	                             shpnt->host_no + PROC_SCSI_FILE);
Linus Torvalds's avatar
Linus Torvalds committed
3189
#endif
Linus Torvalds's avatar
Linus Torvalds committed
3190 3191 3192
		if(tpnt->release)
		    (*tpnt->release)(shpnt);
		else {
Linus Torvalds's avatar
Linus Torvalds committed
3193 3194 3195
		    /* This is the default case for the release function.
		     * It should do the right thing for most correctly
		     * written host adapters.
Linus Torvalds's avatar
Linus Torvalds committed
3196
		     */
Linus Torvalds's avatar
Linus Torvalds committed
3197
		    if (shpnt->irq) free_irq(shpnt->irq, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
3198 3199 3200 3201 3202 3203 3204
		    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--;
	    }
Linus Torvalds's avatar
Linus Torvalds committed
3205
	}
Linus Torvalds's avatar
Linus Torvalds committed
3206
	shpnt = sh1;
Linus Torvalds's avatar
Linus Torvalds committed
3207
    }
Linus Torvalds's avatar
Linus Torvalds committed
3208

Linus Torvalds's avatar
Linus Torvalds committed
3209 3210 3211 3212 3213 3214 3215 3216
    /*
     * If there are absolutely no more hosts left, it is safe
     * to completely nuke the DMA pool.  The resize operation will
     * do the right thing and free everything.
     */
    if( !scsi_devices )
	resize_dma_pool();

Linus Torvalds's avatar
Linus Torvalds committed
3217 3218
    printk ("scsi : %d host%s.\n", next_scsi_host,
	    (next_scsi_host == 1) ? "" : "s");
Linus Torvalds's avatar
Linus Torvalds committed
3219

Linus Torvalds's avatar
Linus Torvalds committed
3220
#if defined(USE_STATIC_SCSI_MEMORY)
Linus Torvalds's avatar
Linus Torvalds committed
3221 3222 3223 3224 3225
    printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
	    (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
	    (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
	    (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
#endif
Linus Torvalds's avatar
Linus Torvalds committed
3226

Linus Torvalds's avatar
Linus Torvalds committed
3227
    scsi_make_blocked_list();
Linus Torvalds's avatar
Linus Torvalds committed
3228

Linus Torvalds's avatar
Linus Torvalds committed
3229 3230 3231
    /* There were some hosts that were loaded at boot time, so we cannot
       do any more than this */
    if (tpnt->present) return;
Linus Torvalds's avatar
Linus Torvalds committed
3232

Linus Torvalds's avatar
Linus Torvalds committed
3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243
    /* OK, this is the very last step.  Remove this host adapter from the
       linked list. */
    for(SHTp=NULL, SHT=scsi_hosts; SHT; SHTp=SHT, SHT=SHT->next)
	if(SHT == tpnt) {
	    if(SHTp)
		SHTp->next = SHT->next;
	    else
		scsi_hosts = SHT->next;
	    SHT->next = NULL;
	    break;
	}
Linus Torvalds's avatar
Linus Torvalds committed
3244

Linus Torvalds's avatar
Linus Torvalds committed
3245
    /* Rebuild the /proc/scsi directory entries */
Linus Torvalds's avatar
Linus Torvalds committed
3246
#if CONFIG_PROC_FS
Linus Torvalds's avatar
Linus Torvalds committed
3247
    proc_scsi_unregister(tpnt->proc_dir, tpnt->proc_dir->low_ino);
Linus Torvalds's avatar
Linus Torvalds committed
3248
#endif
Linus Torvalds's avatar
Linus Torvalds committed
3249 3250 3251 3252 3253 3254 3255 3256 3257 3258
    MOD_DEC_USE_COUNT;
}

/*
 * This entry point should be called by a loadable module if it is trying
 * add a high level scsi driver to the system.
 */
static int scsi_register_device_module(struct Scsi_Device_Template * tpnt)
{
    Scsi_Device * SDpnt;
Linus Torvalds's avatar
Linus Torvalds committed
3259

Linus Torvalds's avatar
Linus Torvalds committed
3260
    if (tpnt->next) return 1;
Linus Torvalds's avatar
Linus Torvalds committed
3261

Linus Torvalds's avatar
Linus Torvalds committed
3262 3263 3264 3265
    scsi_register_device(tpnt);
    /*
     * First scan the devices that we know about, and see if we notice them.
     */
Linus Torvalds's avatar
Linus Torvalds committed
3266

Linus Torvalds's avatar
Linus Torvalds committed
3267 3268
    for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
	if(tpnt->detect) SDpnt->attached += (*tpnt->detect)(SDpnt);
Linus Torvalds's avatar
Linus Torvalds committed
3269

Linus Torvalds's avatar
Linus Torvalds committed
3270 3271
    /*
     * If any of the devices would match this driver, then perform the
Linus Torvalds's avatar
Linus Torvalds committed
3272
     * init function.
Linus Torvalds's avatar
Linus Torvalds committed
3273
     */
Linus Torvalds's avatar
Linus Torvalds committed
3274
    if(tpnt->init && tpnt->dev_noticed)
Linus Torvalds's avatar
Linus Torvalds committed
3275
	if ((*tpnt->init)()) return 1;
Linus Torvalds's avatar
Linus Torvalds committed
3276

Linus Torvalds's avatar
Linus Torvalds committed
3277 3278 3279 3280 3281 3282 3283 3284
    /*
     * Now actually connect the devices to the new driver.
     */
    for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
    {
	if(tpnt->attach)  (*tpnt->attach)(SDpnt);
	/*
	 * If this driver attached to the device, and we no longer
Linus Torvalds's avatar
Linus Torvalds committed
3285
	 * have anything attached, release the scsi command blocks.
Linus Torvalds's avatar
Linus Torvalds committed
3286
	 */
Linus Torvalds's avatar
Linus Torvalds committed
3287
	if(SDpnt->attached && SDpnt->has_cmdblocks == 0)
Linus Torvalds's avatar
Linus Torvalds committed
3288 3289
	    scsi_build_commandblocks(SDpnt);
    }
Linus Torvalds's avatar
Linus Torvalds committed
3290

Linus Torvalds's avatar
Linus Torvalds committed
3291
    /*
Linus Torvalds's avatar
Linus Torvalds committed
3292
     * This does any final handling that is required.
Linus Torvalds's avatar
Linus Torvalds committed
3293 3294 3295 3296 3297
     */
    if(tpnt->finish && tpnt->nr_dev)  (*tpnt->finish)();
    MOD_INC_USE_COUNT;
    return 0;
}
Linus Torvalds's avatar
Linus Torvalds committed
3298

Linus Torvalds's avatar
Linus Torvalds committed
3299 3300 3301 3302 3303 3304
static int scsi_unregister_device(struct Scsi_Device_Template * tpnt)
{
    Scsi_Device * SDpnt;
    Scsi_Cmnd * SCpnt;
    struct Scsi_Device_Template * spnt;
    struct Scsi_Device_Template * prev_spnt;
Linus Torvalds's avatar
Linus Torvalds committed
3305

Linus Torvalds's avatar
Linus Torvalds committed
3306 3307 3308
    /*
     * If we are busy, this is not going to fly.
     */
Linus Torvalds's avatar
Linus Torvalds committed
3309 3310
    if(tpnt->module->usecount != 0) return 0;

Linus Torvalds's avatar
Linus Torvalds committed
3311 3312 3313
    /*
     * Next, detach the devices from the driver.
     */
Linus Torvalds's avatar
Linus Torvalds committed
3314

Linus Torvalds's avatar
Linus Torvalds committed
3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336
    for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
    {
	if(tpnt->detach) (*tpnt->detach)(SDpnt);
	if(SDpnt->attached == 0)
	{
	    /*
	     * Nobody is using this device any more.  Free all of the
	     * command structures.
	     */
	    for(SCpnt = SDpnt->host->host_queue; SCpnt; SCpnt = SCpnt->next)
	    {
		if(SCpnt->device == SDpnt)
		{
		    if(SCpnt->prev != NULL)
			SCpnt->prev->next = SCpnt->next;
		    if(SCpnt->next != NULL)
			SCpnt->next->prev = SCpnt->prev;
		    if(SCpnt == SDpnt->host->host_queue)
			SDpnt->host->host_queue = SCpnt->next;
		    scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
		}
	    }
Linus Torvalds's avatar
Linus Torvalds committed
3337
	    SDpnt->has_cmdblocks = 0;
Linus Torvalds's avatar
Linus Torvalds committed
3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348
	}
    }
    /*
     * Extract the template from the linked list.
     */
    spnt = scsi_devicelist;
    prev_spnt = NULL;
    while(spnt != tpnt)
    {
	prev_spnt = spnt;
	spnt = spnt->next;
Linus Torvalds's avatar
Linus Torvalds committed
3349
    }
Linus Torvalds's avatar
Linus Torvalds committed
3350 3351 3352 3353
    if(prev_spnt == NULL)
	scsi_devicelist = tpnt->next;
    else
	prev_spnt->next = spnt->next;
Linus Torvalds's avatar
Linus Torvalds committed
3354

Linus Torvalds's avatar
Linus Torvalds committed
3355 3356
    MOD_DEC_USE_COUNT;
    /*
Linus Torvalds's avatar
Linus Torvalds committed
3357
     * Final cleanup for the driver is done in the driver sources in the
Linus Torvalds's avatar
Linus Torvalds committed
3358 3359 3360
     * cleanup function.
     */
    return 0;
Linus Torvalds's avatar
Linus Torvalds committed
3361 3362
}

Linus Torvalds's avatar
Linus Torvalds committed
3363

Linus Torvalds's avatar
Linus Torvalds committed
3364 3365
int scsi_register_module(int module_type, void * ptr)
{
Linus Torvalds's avatar
Linus Torvalds committed
3366 3367 3368
    switch(module_type){
    case MODULE_SCSI_HA:
	return scsi_register_host((Scsi_Host_Template *) ptr);
Linus Torvalds's avatar
Linus Torvalds committed
3369

Linus Torvalds's avatar
Linus Torvalds committed
3370 3371
	/* Load upper level device handler of some kind */
    case MODULE_SCSI_DEV:
Linus Torvalds's avatar
Linus Torvalds committed
3372 3373 3374 3375
#ifdef CONFIG_KERNELD
	if (scsi_hosts == NULL)
		request_module("scsi_hostadapter");
#endif
Linus Torvalds's avatar
Linus Torvalds committed
3376 3377
	return scsi_register_device_module((struct Scsi_Device_Template *) ptr);
	/* The rest of these are not yet implemented */
Linus Torvalds's avatar
Linus Torvalds committed
3378

Linus Torvalds's avatar
Linus Torvalds committed
3379 3380
	/* Load constants.o */
    case MODULE_SCSI_CONST:
Linus Torvalds's avatar
Linus Torvalds committed
3381 3382

	/* Load specialized ioctl handler for some device.  Intended for
Linus Torvalds's avatar
Linus Torvalds committed
3383 3384
	 * cdroms that have non-SCSI2 audio command sets. */
    case MODULE_SCSI_IOCTL:
Linus Torvalds's avatar
Linus Torvalds committed
3385

Linus Torvalds's avatar
Linus Torvalds committed
3386 3387 3388
    default:
	return 1;
    }
Linus Torvalds's avatar
Linus Torvalds committed
3389 3390 3391 3392
}

void scsi_unregister_module(int module_type, void * ptr)
{
Linus Torvalds's avatar
Linus Torvalds committed
3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406
    switch(module_type) {
    case MODULE_SCSI_HA:
	scsi_unregister_host((Scsi_Host_Template *) ptr);
	break;
    case MODULE_SCSI_DEV:
	scsi_unregister_device((struct Scsi_Device_Template *) ptr);
	break;
	/* The rest of these are not yet implemented. */
    case MODULE_SCSI_CONST:
    case MODULE_SCSI_IOCTL:
	break;
    default:
    }
    return;
Linus Torvalds's avatar
Linus Torvalds committed
3407 3408
}

Linus Torvalds's avatar
Linus Torvalds committed
3409 3410
#endif		/* CONFIG_MODULES */

Linus Torvalds's avatar
Linus Torvalds committed
3411
#ifdef DEBUG_TIMEOUT
Linus Torvalds's avatar
Linus Torvalds committed
3412
static void
Linus Torvalds's avatar
Linus Torvalds committed
3413 3414
scsi_dump_status(void)
{
Linus Torvalds's avatar
Linus Torvalds committed
3415 3416 3417 3418 3419 3420 3421 3422 3423
    int i;
    struct Scsi_Host * shpnt;
    Scsi_Cmnd * SCpnt;
    printk("Dump of scsi parameters:\n");
    i = 0;
    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
	for(SCpnt=shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
	{
	    /*  (0) 0:0:0:0 (802 123434 8 8 0) (3 3 2) (%d %d %d) %d %x      */
Linus Torvalds's avatar
Linus Torvalds committed
3424
	    printk("(%d) %d:%d:%d:%d (%s %ld %ld %ld %d) (%d %d %x) (%d %d %d) %x %x %x\n",
Linus Torvalds's avatar
Linus Torvalds committed
3425 3426 3427 3428
		   i++, SCpnt->host->host_no,
		   SCpnt->channel,
		   SCpnt->target,
		   SCpnt->lun,
Linus Torvalds's avatar
Linus Torvalds committed
3429
		   kdevname(SCpnt->request.rq_dev),
Linus Torvalds's avatar
Linus Torvalds committed
3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453
		   SCpnt->request.sector,
		   SCpnt->request.nr_sectors,
		   SCpnt->request.current_nr_sectors,
		   SCpnt->use_sg,
		   SCpnt->retries,
		   SCpnt->allowed,
		   SCpnt->flags,
		   SCpnt->timeout_per_command,
		   SCpnt->timeout,
		   SCpnt->internal_timeout,
		   SCpnt->cmnd[0],
		   SCpnt->sense_buffer[2],
		   SCpnt->result);
	}
    printk("wait_for_request = %p\n", wait_for_request);
    /* Now dump the request lists for each block device */
    printk("Dump of pending block device requests\n");
    for(i=0; i<MAX_BLKDEV; i++)
	if(blk_dev[i].current_request)
	{
	    struct request * req;
	    printk("%d: ", i);
	    req = blk_dev[i].current_request;
	    while(req) {
Linus Torvalds's avatar
Linus Torvalds committed
3454 3455
		printk("(%s %d %ld %ld %ld) ",
		       kdevname(req->rq_dev),
Linus Torvalds's avatar
Linus Torvalds committed
3456 3457 3458 3459 3460 3461 3462
		       req->cmd,
		       req->sector,
		       req->nr_sectors,
		       req->current_nr_sectors);
		req = req->next;
	    }
	    printk("\n");
Linus Torvalds's avatar
Linus Torvalds committed
3463 3464 3465
	}
}
#endif
Linus Torvalds's avatar
Linus Torvalds committed
3466

Linus Torvalds's avatar
Linus Torvalds committed
3467 3468
#ifdef MODULE

Linus Torvalds's avatar
Linus Torvalds committed
3469
int init_module(void) {
Linus Torvalds's avatar
Linus Torvalds committed
3470 3471
    unsigned long size;

Linus Torvalds's avatar
Linus Torvalds committed
3472
    /*
Linus Torvalds's avatar
Linus Torvalds committed
3473
     * This makes /proc/scsi visible.
Linus Torvalds's avatar
Linus Torvalds committed
3474
     */
Linus Torvalds's avatar
Linus Torvalds committed
3475
#if CONFIG_PROC_FS
Linus Torvalds's avatar
Linus Torvalds committed
3476
    dispatch_scsi_info_ptr = dispatch_scsi_info;
Linus Torvalds's avatar
Linus Torvalds committed
3477
#endif
Linus Torvalds's avatar
Linus Torvalds committed
3478

Linus Torvalds's avatar
Linus Torvalds committed
3479 3480 3481
    timer_table[SCSI_TIMER].fn = scsi_main_timeout;
    timer_table[SCSI_TIMER].expires = 0;
    scsi_loadable_module_flag = 1;
Linus Torvalds's avatar
Linus Torvalds committed
3482 3483 3484 3485 3486 3487

    /* Register the /proc/scsi/scsi entry */
#if CONFIG_PROC_FS
    proc_scsi_register(0, &proc_scsi_scsi);
#endif

Linus Torvalds's avatar
Linus Torvalds committed
3488

Linus Torvalds's avatar
Linus Torvalds committed
3489
    dma_sectors = PAGE_SIZE / SECTOR_SIZE;
Linus Torvalds's avatar
Linus Torvalds committed
3490
    dma_free_sectors= dma_sectors;
Linus Torvalds's avatar
Linus Torvalds committed
3491 3492 3493 3494
    /*
     * Set up a minimal DMA buffer list - this will be used during scan_scsis
     * in some cases.
     */
Linus Torvalds's avatar
Linus Torvalds committed
3495

Linus Torvalds's avatar
Linus Torvalds committed
3496
    /* One bit per sector to indicate free/busy */
Linus Torvalds's avatar
Linus Torvalds committed
3497 3498 3499 3500
    size = (dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap);
    dma_malloc_freelist = (unsigned char *) scsi_init_malloc(size, GFP_ATOMIC);
    memset(dma_malloc_freelist, 0, size);

Linus Torvalds's avatar
Linus Torvalds committed
3501 3502
    /* One pointer per page for the page list */
    dma_malloc_pages = (unsigned char **)
Linus Torvalds's avatar
Linus Torvalds committed
3503
	scsi_init_malloc((dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_pages), GFP_ATOMIC);
Linus Torvalds's avatar
Linus Torvalds committed
3504 3505 3506 3507 3508
    dma_malloc_pages[0] = (unsigned char *)
	scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
    return 0;
}

Linus Torvalds's avatar
Linus Torvalds committed
3509
void cleanup_module( void)
Linus Torvalds's avatar
Linus Torvalds committed
3510
{
Linus Torvalds's avatar
Linus Torvalds committed
3511 3512 3513
#if CONFIG_PROC_FS
    proc_scsi_unregister(0, PROC_SCSI_SCSI);

Linus Torvalds's avatar
Linus Torvalds committed
3514 3515
    /* No, we're not here anymore. Don't show the /proc/scsi files. */
    dispatch_scsi_info_ptr = 0L;
Linus Torvalds's avatar
Linus Torvalds committed
3516
#endif
Linus Torvalds's avatar
Linus Torvalds committed
3517 3518 3519 3520

    /*
     * Free up the DMA pool.
     */
Linus Torvalds's avatar
Linus Torvalds committed
3521 3522
    resize_dma_pool();

Linus Torvalds's avatar
Linus Torvalds committed
3523 3524 3525 3526 3527
    timer_table[SCSI_TIMER].fn = NULL;
    timer_table[SCSI_TIMER].expires = 0;
}
#endif /* MODULE */

Linus Torvalds's avatar
Linus Torvalds committed
3528 3529 3530 3531 3532 3533 3534
/*
 * Overrides for Emacs so that we follow Linus's tabbing style.
 * Emacs will notice this stuff at the end of the file and automatically
 * adjust the settings for this buffer only.  This must remain at the end
 * of the file.
 * ---------------------------------------------------------------------------
 * Local variables:
Linus Torvalds's avatar
Linus Torvalds committed
3535
 * c-indent-level: 4
Linus Torvalds's avatar
Linus Torvalds committed
3536
 * c-brace-imaginary-offset: 0
Linus Torvalds's avatar
Linus Torvalds committed
3537 3538 3539 3540
 * c-brace-offset: -4
 * c-argdecl-indent: 4
 * c-label-offset: -4
 * c-continued-statement-offset: 4
Linus Torvalds's avatar
Linus Torvalds committed
3541
 * c-continued-brace-offset: 0
Linus Torvalds's avatar
Linus Torvalds committed
3542 3543
 * indent-tabs-mode: nil
 * tab-width: 8
Linus Torvalds's avatar
Linus Torvalds committed
3544 3545
 * End:
 */