summaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-03-19 01:28:40 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-03-19 01:28:40 +0000
commit8abb719409c9060a7c0676f76e9182c1e0b8ca46 (patch)
treeb88cc5a6cd513a04a512b7e6215c873c90a1c5dd /drivers/scsi
parentf01bd7aeafd95a08aafc9e3636bb26974df69d82 (diff)
Merge with 2.3.99-pre1.
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/ChangeLog.ncr53c8xx17
-rw-r--r--drivers/scsi/ChangeLog.sym53c8xx9
-rw-r--r--drivers/scsi/Config.in4
-rw-r--r--drivers/scsi/README.st8
-rw-r--r--drivers/scsi/atp870u.c5
-rw-r--r--drivers/scsi/constants.c563
-rw-r--r--drivers/scsi/eata_dma_proc.c18
-rw-r--r--drivers/scsi/hosts.h28
-rw-r--r--drivers/scsi/ncr53c8xx.c2600
-rw-r--r--drivers/scsi/scsi.c18
-rw-r--r--drivers/scsi/scsi.h11
-rw-r--r--drivers/scsi/scsi_debug.c12
-rw-r--r--drivers/scsi/scsi_ioctl.c64
-rw-r--r--drivers/scsi/scsi_lib.c9
-rw-r--r--drivers/scsi/scsi_merge.c8
-rw-r--r--drivers/scsi/scsi_scan.c80
-rw-r--r--drivers/scsi/scsi_syms.c1
-rw-r--r--drivers/scsi/sd.c74
-rw-r--r--drivers/scsi/sr.c4
-rw-r--r--drivers/scsi/st.c738
-rw-r--r--drivers/scsi/st.h11
-rw-r--r--drivers/scsi/st_options.h9
-rw-r--r--drivers/scsi/sym53c8xx.c175
-rw-r--r--drivers/scsi/sym53c8xx_comm.h2863
24 files changed, 4262 insertions, 3067 deletions
diff --git a/drivers/scsi/ChangeLog.ncr53c8xx b/drivers/scsi/ChangeLog.ncr53c8xx
index f884dfb1e..8f4d4f19c 100644
--- a/drivers/scsi/ChangeLog.ncr53c8xx
+++ b/drivers/scsi/ChangeLog.ncr53c8xx
@@ -1,3 +1,20 @@
+Mon March 6 23:15 2000 Gerard Roudier (groudier@club-internet.fr)
+ * revision 3.2g
+ - Add the file sym53c8xx_comm.h that collects code that should
+ be shared by sym53c8xx and ncr53c8xx drivers. For now, it is
+ a header file that is only included by the ncr53c8xx driver,
+ but things will be cleaned up later. This code addresses
+ notably:
+ * Chip detection and PCI related initialisations
+ * NVRAM detection and reading
+ * DMA mapping
+ * Boot setup command
+ * And some other ...
+ - Add support for the new dynamic dma mapping kernel interface.
+ Requires Linux-2.3.47 (tested with pre-2.3.47-6).
+ - Get data transfer direction from the scsi command structure
+ (Scsi_Cmnd) when this information is available.
+
Sat Jan 8 22:00 2000 Gerard Roudier (groudier@club-internet.fr)
* revision 3.2e
- Add year 2000 copyright.
diff --git a/drivers/scsi/ChangeLog.sym53c8xx b/drivers/scsi/ChangeLog.sym53c8xx
index 4abf98759..47448ec71 100644
--- a/drivers/scsi/ChangeLog.sym53c8xx
+++ b/drivers/scsi/ChangeLog.sym53c8xx
@@ -1,3 +1,12 @@
+Mon Mar 6 23:30 2000 Gerard Roudier (groudier@club-internet.fr)
+ * version sym53c8xx-1.5k
+ - Test against expected data transfer direction from SCRIPTS.
+ - Revert the change in 'ncr_flush_done_cmds()' but unmap the
+ scsi dma buffer prior to queueing the command to our done
+ list.
+ - Miscellaneous (minor) fixes in the code added in driver
+ version 1.5j.
+
Sun Feb 20 11:00 2000 Gerard Roudier (groudier@club-internet.fr)
* version sym53c8xx-1.5j
- Add support for the new dynamic dma mapping kernel interface.
diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in
index 4b68450e4..6eee76033 100644
--- a/drivers/scsi/Config.in
+++ b/drivers/scsi/Config.in
@@ -8,10 +8,6 @@ fi
dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
-if [ "$CONFIG_CHR_DEV_ST" != "n" ]; then
- int 'Maximum number of SCSI tapes that can be loaded as modules' CONFIG_ST_EXTRA_DEVS 2
-fi
-
dep_tristate ' SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then
diff --git a/drivers/scsi/README.st b/drivers/scsi/README.st
index b1b6362f3..77121aa0b 100644
--- a/drivers/scsi/README.st
+++ b/drivers/scsi/README.st
@@ -2,7 +2,7 @@ This file contains brief information about the SCSI tape driver.
The driver is currently maintained by Kai M{kisara (email
Kai.Makisara@metla.fi)
-Last modified: Sat Aug 7 13:52:16 1999 by makisara@kai.makisara.local
+Last modified: Sat Mar 11 10:34:44 2000 by makisara@kai.makisara.local
BASICS
@@ -134,11 +134,7 @@ A small number of buffers are allocated at driver initialisation. The
maximum number of these buffers is defined by ST_MAX_BUFFERS. The
maximum can be changed with kernel or module startup options. One
buffer is allocated for each drive detected when the driver is
-initialized up to the maximum. The minimum number of allocated buffers
-is ST_EXTRA_DEVS (in hosts.h) (unless this number exceeds the defined
-maximum). This ensures some functionality also for the drives found
-after tape driver initialization (a SCSI adapter driver is loaded as a
-module). The default for ST_EXTRA_DEVS is two.
+initialized up to the maximum.
The driver tries to allocate new buffers at run-time if
necessary. These buffers are freed after use. If the maximum number of
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index c0b3f3a62..6c92531fc 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -105,6 +105,11 @@ irq_numok:
{
tmport += 0x1f;
j = inb(tmport);
+ if((j&0x80)==0)
+ {
+ dev->in_int=0;
+ return;
+ }
tmpcip = dev->pciport;
if ((inb(tmpcip) & 0x08) != 0)
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index 849ce76c9..5a74bc2df 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -158,16 +158,20 @@ void print_status (int status) {
}
#if (CONSTANTS & CONST_XSENSE)
-#define D 0x001 /* DIRECT ACCESS DEVICE (disk) */
-#define T 0x002 /* SEQUENTIAL ACCESS DEVICE (tape) */
-#define L 0x004 /* PRINTER DEVICE */
-#define P 0x008 /* PROCESSOR DEVICE */
-#define W 0x010 /* WRITE ONCE READ MULTIPLE DEVICE */
-#define R 0x020 /* READ ONLY (CD-ROM) DEVICE */
-#define S 0x040 /* SCANNER DEVICE */
-#define O 0x080 /* OPTICAL MEMORY DEVICE */
-#define M 0x100 /* MEDIA CHANGER DEVICE */
-#define C 0x200 /* COMMUNICATION DEVICE */
+#define D 0x0001 /* DIRECT ACCESS DEVICE (disk) */
+#define T 0x0002 /* SEQUENTIAL ACCESS DEVICE (tape) */
+#define L 0x0004 /* PRINTER DEVICE */
+#define P 0x0008 /* PROCESSOR DEVICE */
+#define W 0x0010 /* WRITE ONCE READ MULTIPLE DEVICE */
+#define R 0x0020 /* READ ONLY (CD-ROM) DEVICE */
+#define S 0x0040 /* SCANNER DEVICE */
+#define O 0x0080 /* OPTICAL MEMORY DEVICE */
+#define M 0x0100 /* MEDIA CHANGER DEVICE */
+#define C 0x0200 /* COMMUNICATION DEVICE */
+#define A 0x0400 /* ARRAY STORAGE */
+#define E 0x0800 /* ENCLOSURE SERVICES DEVICE */
+#define B 0x1000 /* SIMPLIFIED DIRECT ACCESS DEVICE */
+#define K 0x2000 /* OPTICAL CARD READER/WRITER DEVICE */
struct error_info{
unsigned char code1, code2;
@@ -192,131 +196,213 @@ static struct error_info2 additional2[] =
static struct error_info additional[] =
{
+ {0x00,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"No additional sense information"},
{0x00,0x01,T,"Filemark detected"},
{0x00,0x02,T|S,"End-of-partition/medium detected"},
{0x00,0x03,T,"Setmark detected"},
{0x00,0x04,T|S,"Beginning-of-partition/medium detected"},
- {0x00,0x05,T|S,"End-of-data detected"},
- {0x00,0x06,D|T|L|P|W|R|S|O|M|C,"I/O process terminated"},
+ {0x00,0x05,T|L|S,"End-of-data detected"},
+ {0x00,0x06,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"I/O process terminated"},
{0x00,0x11,R,"Audio play operation in progress"},
{0x00,0x12,R,"Audio play operation paused"},
{0x00,0x13,R,"Audio play operation successfully completed"},
{0x00,0x14,R,"Audio play operation stopped due to error"},
{0x00,0x15,R,"No current audio status to return"},
- {0x01,0x00,D|W|O,"No index/sector signal"},
- {0x02,0x00,D|W|R|O|M,"No seek complete"},
- {0x03,0x00,D|T|L|W|S|O,"Peripheral device write fault"},
+ {0x00,0x16,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Operation in progress"},
+ {0x00,0x17,D|T|L|W|R|S|O|M|A|E|B|K,"Cleaning requested"},
+ {0x01,0x00,D|W|O|B|K,"No index/sector signal"},
+ {0x02,0x00,D|W|R|O|M|B|K,"No seek complete"},
+ {0x03,0x00,D|T|L|W|S|O|B|K,"Peripheral device write fault"},
{0x03,0x01,T,"No write current"},
{0x03,0x02,T,"Excessive write errors"},
- {0x04,0x00,D|T|L|P|W|R|S|O|M|C,
- "Logical unit not ready, cause not reportable"},
- {0x04,0x01,D|T|L|P|W|R|S|O|M|C,
- "Logical unit is in process of becoming ready"},
- {0x04,0x02,D|T|L|P|W|R|S|O|M|C,
- "Logical unit not ready, initializing command required"},
- {0x04,0x03,D|T|L|P|W|R|S|O|M|C,
- "Logical unit not ready, manual intervention required"},
- {0x04,0x04,D|T|L|O,"Logical unit not ready, format in progress"},
- {0x05,0x00,D|T|L|W|R|S|O|M|C,"Logical unit does not respond to selection"},
- {0x06,0x00,D|W|R|O|M,"No reference position found"},
- {0x07,0x00,D|T|L|W|R|S|O|M,"Multiple peripheral devices selected"},
- {0x08,0x00,D|T|L|W|R|S|O|M|C,"Logical unit communication failure"},
- {0x08,0x01,D|T|L|W|R|S|O|M|C,"Logical unit communication time-out"},
- {0x08,0x02,D|T|L|W|R|S|O|M|C,"Logical unit communication parity error"},
- {0x09,0x00,D|T|W|R|O,"Track following error"},
- {0x09,0x01,W|R|O,"Tracking servo failure"},
- {0x09,0x02,W|R|O,"Focus servo failure"},
+ {0x04,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Logical unit not ready,cause not reportable"},
+ {0x04,0x01,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Logical unit is in process of becoming ready"},
+ {0x04,0x02,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Logical unit not ready,initializing cmd. required"},
+ {0x04,0x03,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Logical unit not ready,manual intervention required"},
+ {0x04,0x04,D|T|L|R|O|B,"Logical unit not ready,format in progress"},
+ {0x04,0x05,D|T|W|O|M|C|A|B|K,"Logical unit not ready,rebuild in progress"},
+ {0x04,0x06,D|T|W|O|M|C|A|B|K,"Logical unit not ready,recalculation in progress"},
+ {0x04,0x07,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Logical unit not ready,operation in progress"},
+ {0x04,0x08,R,"Logical unit not ready,long write in progress"},
+ {0x04,0x09,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Logical unit not ready,self-test in progress"},
+ {0x05,0x00,D|T|L|W|R|S|O|M|C|A|E|B|K,"Logical unit does not respond to selection"},
+ {0x06,0x00,D|W|R|O|M|B|K,"No reference position found"},
+ {0x07,0x00,D|T|L|W|R|S|O|M|B|K,"Multiple peripheral devices selected"},
+ {0x08,0x00,D|T|L|W|R|S|O|M|C|A|E|B|K,"Logical unit communication failure"},
+ {0x08,0x01,D|T|L|W|R|S|O|M|C|A|E|B|K,"Logical unit communication time-out"},
+ {0x08,0x02,D|T|L|W|R|S|O|M|C|A|E|B|K,"Logical unit communication parity error"},
+ {0x08,0x03,D|T|R|O|M|B|K,"Logical unit communication CRC error (Ultra-DMA/32)"},
+ {0x08,0x04,D|T|L|P|W|R|S|O|C|K,"Unreachable copy target"},
+ {0x09,0x00,D|T|W|R|O|B,"Track following error"},
+ {0x09,0x01,W|R|O|K,"Tracking servo failure"},
+ {0x09,0x02,W|R|O|K,"Focus servo failure"},
{0x09,0x03,W|R|O,"Spindle servo failure"},
- {0x0A,0x00,D|T|L|P|W|R|S|O|M|C,"Error log overflow"},
- {0x0C,0x00,T|S,"Write error"},
- {0x0C,0x01,D|W|O,"Write error recovered with auto reallocation"},
- {0x0C,0x02,D|W|O,"Write error - auto reallocation failed"},
- {0x10,0x00,D|W|O,"Id crc or ecc error"},
- {0x11,0x00,D|T|W|R|S|O,"Unrecovered read error"},
- {0x11,0x01,D|T|W|S|O,"Read retries exhausted"},
- {0x11,0x02,D|T|W|S|O,"Error too long to correct"},
- {0x11,0x03,D|T|W|S|O,"Multiple read errors"},
- {0x11,0x04,D|W|O,"Unrecovered read error - auto reallocate failed"},
- {0x11,0x05,W|R|O,"L-ec uncorrectable error"},
- {0x11,0x06,W|R|O,"Circ unrecovered error"},
- {0x11,0x07,W|O,"Data resynchronization error"},
+ {0x09,0x04,D|T|W|R|O|B,"Head select fault"},
+ {0x0A,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Error log overflow"},
+ {0x0B,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Warning"},
+ {0x0B,0x01,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Warning - specified temperature exceeded"},
+ {0x0B,0x02,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Warning - enclosure degraded"},
+ {0x0C,0x00,T|R|S,"Write error"},
+ {0x0C,0x01,K,"Write error - recovered with auto reallocation"},
+ {0x0C,0x02,D|W|O|B|K,"Write error - auto reallocation failed"},
+ {0x0C,0x03,D|W|O|B|K,"Write error - recommend reassignment"},
+ {0x0C,0x04,D|T|W|O|B,"Compression check miscompare error"},
+ {0x0C,0x05,D|T|W|O|B,"Data expansion occurred during compression"},
+ {0x0C,0x06,D|T|W|O|B,"Block not compressible"},
+ {0x0C,0x07,R,"Write error - recovery needed"},
+ {0x0C,0x08,R,"Write error - recovery failed"},
+ {0x0C,0x09,R,"Write error - loss of streaming"},
+ {0x0C,0x0A,R,"Write error - padding blocks added"},
+ {0x10,0x00,D|W|O|B|K,"Id CRC or ECC error"},
+ {0x11,0x00,D|T|W|R|S|O|B|K,"Unrecovered read error"},
+ {0x11,0x01,D|T|W|R|S|O|B|K,"Read retries exhausted"},
+ {0x11,0x02,D|T|W|R|S|O|B|K,"Error too long to correct"},
+ {0x11,0x03,D|T|W|S|O|B|K,"Multiple read errors"},
+ {0x11,0x04,D|W|O|B|K,"Unrecovered read error - auto reallocate failed"},
+ {0x11,0x05,W|R|O|B,"L-EC uncorrectable error"},
+ {0x11,0x06,W|R|O|B,"CIRC unrecovered error"},
+ {0x11,0x07,W|O|B,"Data re-synchronization error"},
{0x11,0x08,T,"Incomplete block read"},
{0x11,0x09,T,"No gap found"},
- {0x11,0x0A,D|T|O,"Miscorrected error"},
- {0x11,0x0B,D|W|O,"Unrecovered read error - recommend reassignment"},
- {0x11,0x0C,D|W|O,"Unrecovered read error - recommend rewrite the data"},
- {0x12,0x00,D|W|O,"Address mark not found for id field"},
- {0x13,0x00,D|W|O,"Address mark not found for data field"},
- {0x14,0x00,D|T|L|W|R|S|O,"Recorded entity not found"},
- {0x14,0x01,D|T|W|R|O,"Record not found"},
+ {0x11,0x0A,D|T|O|B|K,"Miscorrected error"},
+ {0x11,0x0B,D|W|O|B|K,"Unrecovered read error - recommend reassignment"},
+ {0x11,0x0C,D|W|O|B|K,"Unrecovered read error - recommend rewrite the data"},
+ {0x11,0x0D,D|T|W|R|O|B,"De-compression CRC error"},
+ {0x11,0x0E,D|T|W|R|O|B,"Cannot decompress using declared algorithm"},
+ {0x11,0x0F,R,"Error reading UPC/EAN number"},
+ {0x11,0x10,R,"Error reading ISRC number"},
+ {0x11,0x11,R,"Read error - loss of streaming"},
+ {0x12,0x00,D|W|O|B|K,"Address mark not found for id field"},
+ {0x13,0x00,D|W|O|B|K,"Address mark not found for data field"},
+ {0x14,0x00,D|T|L|W|R|S|O|B|K,"Recorded entity not found"},
+ {0x14,0x01,D|T|W|R|O|B|K,"Record not found"},
{0x14,0x02,T,"Filemark or setmark not found"},
{0x14,0x03,T,"End-of-data not found"},
{0x14,0x04,T,"Block sequence error"},
- {0x15,0x00,D|T|L|W|R|S|O|M,"Random positioning error"},
- {0x15,0x01,D|T|L|W|R|S|O|M,"Mechanical positioning error"},
- {0x15,0x02,D|T|W|R|O,"Positioning error detected by read of medium"},
- {0x16,0x00,D|W|O,"Data synchronization mark error"},
- {0x17,0x00,D|T|W|R|S|O,"Recovered data with no error correction applied"},
- {0x17,0x01,D|T|W|R|S|O,"Recovered data with retries"},
- {0x17,0x02,D|T|W|R|O,"Recovered data with positive head offset"},
- {0x17,0x03,D|T|W|R|O,"Recovered data with negative head offset"},
- {0x17,0x04,W|R|O,"Recovered data with retries and/or circ applied"},
- {0x17,0x05,D|W|R|O,"Recovered data using previous sector id"},
- {0x17,0x06,D|W|O,"Recovered data without ecc - data auto-reallocated"},
- {0x17,0x07,D|W|O,"Recovered data without ecc - recommend reassignment"},
- {0x18,0x00,D|T|W|R|O,"Recovered data with error correction applied"},
- {0x18,0x01,D|W|R|O,"Recovered data with error correction and retries applied"},
- {0x18,0x02,D|W|R|O,"Recovered data - data auto-reallocated"},
- {0x18,0x03,R,"Recovered data with circ"},
- {0x18,0x04,R,"Recovered data with lec"},
- {0x18,0x05,D|W|R|O,"Recovered data - recommend reassignment"},
- {0x19,0x00,D|O,"Defect list error"},
- {0x19,0x01,D|O,"Defect list not available"},
- {0x19,0x02,D|O,"Defect list error in primary list"},
- {0x19,0x03,D|O,"Defect list error in grown list"},
- {0x1A,0x00,D|T|L|P|W|R|S|O|M|C,"Parameter list length error"},
- {0x1B,0x00,D|T|L|P|W|R|S|O|M|C,"Synchronous data transfer error"},
- {0x1C,0x00,D|O,"Defect list not found"},
- {0x1C,0x01,D|O,"Primary defect list not found"},
- {0x1C,0x02,D|O,"Grown defect list not found"},
- {0x1D,0x00,D|W|O,"Miscompare during verify operation"},
- {0x1E,0x00,D|W|O,"Recovered id with ecc correction"},
- {0x20,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid command operation code"},
- {0x21,0x00,D|T|W|R|O|M,"Logical block address out of range"},
- {0x21,0x01,M,"Invalid element address"},
- {0x22,0x00,D,"Illegal function (should use 20 00, 24 00, or 26 00)"},
- {0x24,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid field in cdb"},
- {0x25,0x00,D|T|L|P|W|R|S|O|M|C,"Logical unit not supported"},
- {0x26,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid field in parameter list"},
- {0x26,0x01,D|T|L|P|W|R|S|O|M|C,"Parameter not supported"},
- {0x26,0x02,D|T|L|P|W|R|S|O|M|C,"Parameter value invalid"},
- {0x26,0x03,D|T|L|P|W|R|S|O|M|C,"Threshold parameters not supported"},
- {0x27,0x00,D|T|W|O,"Write protected"},
- {0x28,0x00,D|T|L|P|W|R|S|O|M|C,"Not ready to ready transition (medium may have changed)"},
- {0x28,0x01,M,"Import or export element accessed"},
- {0x29,0x00,D|T|L|P|W|R|S|O|M|C,"Power on, reset, or bus device reset occurred"},
- {0x2A,0x00,D|T|L|W|R|S|O|M|C,"Parameters changed"},
- {0x2A,0x01,D|T|L|W|R|S|O|M|C,"Mode parameters changed"},
- {0x2A,0x02,D|T|L|W|R|S|O|M|C,"Log parameters changed"},
- {0x2B,0x00,D|T|L|P|W|R|S|O|C,"Copy cannot execute since host cannot disconnect"},
- {0x2C,0x00,D|T|L|P|W|R|S|O|M|C,"Command sequence error"},
+ {0x14,0x05,D|T|W|O|B|K,"Record not found - recommend reassignment"},
+ {0x14,0x06,D|T|W|O|B|K,"Record not found - data auto-reallocated"},
+ {0x15,0x00,D|T|L|W|R|S|O|M|B|K,"Random positioning error"},
+ {0x15,0x01,D|T|L|W|R|S|O|M|B|K,"Mechanical positioning error"},
+ {0x15,0x02,D|T|W|R|O|B|K,"Positioning error detected by read of medium"},
+ {0x16,0x00,D|W|O|B|K,"Data synchronization mark error"},
+ {0x16,0x01,D|W|O|B|K,"Data sync error - data rewritten"},
+ {0x16,0x02,D|W|O|B|K,"Data sync error - recommend rewrite"},
+ {0x16,0x03,D|W|O|B|K,"Data sync error - data auto-reallocated"},
+ {0x16,0x04,D|W|O|B|K,"Data sync error - recommend reassignment"},
+ {0x17,0x00,D|T|W|R|S|O|B|K,"Recovered data with no error correction applied"},
+ {0x17,0x01,D|T|W|R|S|O|B|K,"Recovered data with retries"},
+ {0x17,0x02,D|T|W|R|O|B|K,"Recovered data with positive head offset"},
+ {0x17,0x03,D|T|W|R|O|B|K,"Recovered data with negative head offset"},
+ {0x17,0x04,W|R|O|B,"Recovered data with retries and/or circ applied"},
+ {0x17,0x05,D|W|R|O|B|K,"Recovered data using previous sector id"},
+ {0x17,0x06,D|W|O|B|K,"Recovered data without ecc - data auto-reallocated"},
+ {0x17,0x07,D|W|R|O|B|K,"Recovered data without ecc - recommend reassignment"},
+ {0x17,0x08,D|W|R|O|B|K,"Recovered data without ecc - recommend rewrite"},
+ {0x17,0x09,D|W|R|O|B|K,"Recovered data without ecc - data rewritten"},
+ {0x18,0x00,D|T|W|R|O|B|K,"Recovered data with error correction applied"},
+ {0x18,0x01,D|W|R|O|B|K,"Recovered data with error corr. & retries applied"},
+ {0x18,0x02,D|W|R|O|B|K,"Recovered data - data auto-reallocated"},
+ {0x18,0x03,R,"Recovered data with CIRC"},
+ {0x18,0x04,R,"Recovered data with L-EC"},
+ {0x18,0x05,D|W|R|O|B|K,"Recovered data - recommend reassignment"},
+ {0x18,0x06,D|W|R|O|B|K,"Recovered data - recommend rewrite"},
+ {0x18,0x07,D|W|O|B|K,"Recovered data with ecc - data rewritten"},
+ {0x19,0x00,D|O|K,"Defect list error"},
+ {0x19,0x01,D|O|K,"Defect list not available"},
+ {0x19,0x02,D|O|K,"Defect list error in primary list"},
+ {0x19,0x03,D|O|K,"Defect list error in grown list"},
+ {0x1A,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Parameter list length error"},
+ {0x1B,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Synchronous data transfer error"},
+ {0x1C,0x00,D|O|B|K,"Defect list not found"},
+ {0x1C,0x01,D|O|B|K,"Primary defect list not found"},
+ {0x1C,0x02,D|O|B|K,"Grown defect list not found"},
+ {0x1D,0x00,D|T|W|R|O|B|K,"Miscompare during verify operation"},
+ {0x1E,0x00,D|W|O|B|K,"Recovered id with ecc correction"},
+ {0x1F,0x00,D|O|K,"Partial defect list transfer"},
+ {0x20,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Invalid command operation code"},
+ {0x21,0x00,D|T|W|R|O|M|B|K,"Logical block address out of range"},
+ {0x21,0x01,D|T|W|R|O|M|B|K,"Invalid element address"},
+ {0x22,0x00,D,"Illegal function (use 20 00,24 00,or 26 00)"},
+ {0x24,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Invalid field in cdb"},
+ {0x24,0x01,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"CDB decryption error"},
+ {0x25,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Logical unit not supported"},
+ {0x26,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Invalid field in parameter list"},
+ {0x26,0x01,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Parameter not supported"},
+ {0x26,0x02,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Parameter value invalid"},
+ {0x26,0x03,D|T|L|P|W|R|S|O|M|C|A|E|K,"Threshold parameters not supported"},
+ {0x26,0x04,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Invalid release of persistent reservation"},
+ {0x26,0x05,D|T|L|P|W|R|S|O|M|C|A|B|K,"Data decryption error"},
+ {0x26,0x06,D|T|L|P|W|R|S|O|C|K,"Too many target descriptors"},
+ {0x26,0x07,D|T|L|P|W|R|S|O|C|K,"Unsupported target descriptor type code"},
+ {0x26,0x08,D|T|L|P|W|R|S|O|C|K,"Too many segment descriptors"},
+ {0x26,0x09,D|T|L|P|W|R|S|O|C|K,"Unsupported segment descriptor type code"},
+ {0x26,0x0A,D|T|L|P|W|R|S|O|C|K,"Unexpected inexact segment"},
+ {0x26,0x0B,D|T|L|P|W|R|S|O|C|K,"Inline data length exceeded"},
+ {0x26,0x0C,D|T|L|P|W|R|S|O|C|K,"Invalid operation for copy source or destination"},
+ {0x26,0x0D,D|T|L|P|W|R|S|O|C|K,"Copy segment granularity violation"},
+ {0x27,0x00,D|T|W|R|O|B|K,"Write protected"},
+ {0x27,0x01,D|T|W|R|O|B|K,"Hardware write protected"},
+ {0x27,0x02,D|T|W|R|O|B|K,"Logical unit software write protected"},
+ {0x27,0x03,T|R,"Associated write protect"},
+ {0x27,0x04,T|R,"Persistent write protect"},
+ {0x27,0x05,T|R,"Permanent write protect"},
+ {0x28,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Not ready to ready change,medium may have changed"},
+ {0x28,0x01,D|T|W|R|O|M|B,"Import or export element accessed"},
+ {0x29,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Power on,reset,or bus device reset occurred"},
+ {0x29,0x01,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Power on occurred"},
+ {0x29,0x02,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Scsi bus reset occurred"},
+ {0x29,0x03,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Bus device reset function occurred"},
+ {0x29,0x04,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Device internal reset"},
+ {0x29,0x05,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Transceiver mode changed to single-ended"},
+ {0x29,0x06,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Transceiver mode changed to lvd"},
+ {0x2A,0x00,D|T|L|W|R|S|O|M|C|A|E|B|K,"Parameters changed"},
+ {0x2A,0x01,D|T|L|W|R|S|O|M|C|A|E|B|K,"Mode parameters changed"},
+ {0x2A,0x02,D|T|L|W|R|S|O|M|C|A|E|K,"Log parameters changed"},
+ {0x2A,0x03,D|T|L|P|W|R|S|O|M|C|A|E|K,"Reservations preempted"},
+ {0x2A,0x04,D|T|L|P|W|R|S|O|M|C|A|E,"Reservations released"},
+ {0x2A,0x05,D|T|L|P|W|R|S|O|M|C|A|E,"Registrations preempted"},
+ {0x2B,0x00,D|T|L|P|W|R|S|O|C|K,"Copy cannot execute since host cannot disconnect"},
+ {0x2C,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Command sequence error"},
{0x2C,0x01,S,"Too many windows specified"},
{0x2C,0x02,S,"Invalid combination of windows specified"},
+ {0x2C,0x03,R,"Current program area is not empty"},
+ {0x2C,0x04,R,"Current program area is empty"},
+ {0x2C,0x05,B,"Illegal power condition request"},
{0x2D,0x00,T,"Overwrite error on update in place"},
- {0x2F,0x00,D|T|L|P|W|R|S|O|M|C,"Commands cleared by another initiator"},
- {0x30,0x00,D|T|W|R|O|M,"Incompatible medium installed"},
- {0x30,0x01,D|T|W|R|O,"Cannot read medium - unknown format"},
- {0x30,0x02,D|T|W|R|O,"Cannot read medium - incompatible format"},
- {0x30,0x03,D|T,"Cleaning cartridge installed"},
- {0x31,0x00,D|T|W|O,"Medium format corrupted"},
- {0x31,0x01,D|L|O,"Format command failed"},
- {0x32,0x00,D|W|O,"No defect spare location available"},
- {0x32,0x01,D|W|O,"Defect list update failure"},
+ {0x2F,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Commands cleared by another initiator"},
+ {0x30,0x00,D|T|W|R|O|M|B|K,"Incompatible medium installed"},
+ {0x30,0x01,D|T|W|R|O|B|K,"Cannot read medium - unknown format"},
+ {0x30,0x02,D|T|W|R|O|B|K,"Cannot read medium - incompatible format"},
+ {0x30,0x03,D|T|R|K,"Cleaning cartridge installed"},
+ {0x30,0x04,D|T|W|R|O|B|K,"Cannot write medium - unknown format"},
+ {0x30,0x05,D|T|W|R|O|B|K,"Cannot write medium - incompatible format"},
+ {0x30,0x06,D|T|W|R|O|B,"Cannot format medium - incompatible medium"},
+ {0x30,0x07,D|T|L|W|R|S|O|M|A|E|B|K,"Cleaning failure"},
+ {0x30,0x08,R,"Cannot write - application code mismatch"},
+ {0x30,0x09,R,"Current session not fixated for append"},
+ {0x31,0x00,D|T|W|R|O|B|K,"Medium format corrupted"},
+ {0x31,0x01,D|L|R|O|B,"Format command failed"},
+ {0x32,0x00,D|W|O|B|K,"No defect spare location available"},
+ {0x32,0x01,D|W|O|B|K,"Defect list update failure"},
{0x33,0x00,T,"Tape length error"},
- {0x36,0x00,L,"Ribbon, ink, or toner failure"},
- {0x37,0x00,D|T|L|W|R|S|O|M|C,"Rounded parameter"},
- {0x39,0x00,D|T|L|W|R|S|O|M|C,"Saving parameters not supported"},
- {0x3A,0x00,D|T|L|W|R|S|O|M,"Medium not present"},
+ {0x34,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Enclosure failure"},
+ {0x35,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Enclosure services failure"},
+ {0x35,0x01,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Unsupported enclosure function"},
+ {0x35,0x02,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Enclosure services unavailable"},
+ {0x35,0x03,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Enclosure services transfer failure"},
+ {0x35,0x04,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Enclosure services transfer refused"},
+ {0x36,0x00,L,"Ribbon,ink,or toner failure"},
+ {0x37,0x00,D|T|L|W|R|S|O|M|C|A|E|B|K,"Rounded parameter"},
+ {0x38,0x00,B,"Event status notification"},
+ {0x38,0x02,B,"Esn - power management class event"},
+ {0x38,0x04,B,"Esn - media class event"},
+ {0x38,0x06,B,"Esn - device busy class event"},
+ {0x39,0x00,D|T|L|W|R|S|O|M|C|A|E|K,"Saving parameters not supported"},
+ {0x3A,0x00,D|T|L|W|R|S|O|M|B|K,"Medium not present"},
+ {0x3A,0x01,D|T|W|R|O|M|B|K,"Medium not present - tray closed"},
+ {0x3A,0x02,D|T|W|R|O|M|B|K,"Medium not present - tray open"},
+ {0x3A,0x03,D|T|W|R|O|M|B,"Medium not present - loadable"},
+ {0x3A,0x04,D|T|W|R|O|M|B,"Medium not present - medium auxiliary memory accessible"},
{0x3B,0x00,T|L,"Sequential positioning error"},
{0x3B,0x01,T,"Tape position error at beginning-of-medium"},
{0x3B,0x02,T,"Tape position error at end-of-medium"},
@@ -329,57 +415,244 @@ static struct error_info additional[] =
{0x3B,0x09,S,"Read past end of medium"},
{0x3B,0x0A,S,"Read past beginning of medium"},
{0x3B,0x0B,S,"Position past end of medium"},
- {0x3B,0x0C,S,"Position past beginning of medium"},
- {0x3B,0x0D,M,"Medium destination element full"},
- {0x3B,0x0E,M,"Medium source element empty"},
- {0x3D,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid bits in identify message"},
- {0x3E,0x00,D|T|L|P|W|R|S|O|M|C,"Logical unit has not self-configured yet"},
- {0x3F,0x00,D|T|L|P|W|R|S|O|M|C,"Target operating conditions have changed"},
- {0x3F,0x01,D|T|L|P|W|R|S|O|M|C,"Microcode has been changed"},
- {0x3F,0x02,D|T|L|P|W|R|S|O|M|C,"Changed operating definition"},
- {0x3F,0x03,D|T|L|P|W|R|S|O|M|C,"Inquiry data has changed"},
- {0x43,0x00,D|T|L|P|W|R|S|O|M|C,"Message error"},
- {0x44,0x00,D|T|L|P|W|R|S|O|M|C,"Internal target failure"},
- {0x45,0x00,D|T|L|P|W|R|S|O|M|C,"Select or reselect failure"},
- {0x46,0x00,D|T|L|P|W|R|S|O|M|C,"Unsuccessful soft reset"},
- {0x47,0x00,D|T|L|P|W|R|S|O|M|C,"Scsi parity error"},
- {0x48,0x00,D|T|L|P|W|R|S|O|M|C,"Initiator detected error message received"},
- {0x49,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid message error"},
- {0x4A,0x00,D|T|L|P|W|R|S|O|M|C,"Command phase error"},
- {0x4B,0x00,D|T|L|P|W|R|S|O|M|C,"Data phase error"},
- {0x4C,0x00,D|T|L|P|W|R|S|O|M|C,"Logical unit failed self-configuration"},
- {0x4E,0x00,D|T|L|P|W|R|S|O|M|C,"Overlapped commands attempted"},
+ {0x3B,0x0C,T|S,"Position past beginning of medium"},
+ {0x3B,0x0D,D|T|W|R|O|M|B|K,"Medium destination element full"},
+ {0x3B,0x0E,D|T|W|R|O|M|B|K,"Medium source element empty"},
+ {0x3B,0x0F,R,"End of medium reached"},
+ {0x3B,0x11,D|T|W|R|O|M|B|K,"Medium magazine not accessible"},
+ {0x3B,0x12,D|T|W|R|O|M|B|K,"Medium magazine removed"},
+ {0x3B,0x13,D|T|W|R|O|M|B|K,"Medium magazine inserted"},
+ {0x3B,0x14,D|T|W|R|O|M|B|K,"Medium magazine locked"},
+ {0x3B,0x15,D|T|W|R|O|M|B|K,"Medium magazine unlocked"},
+ {0x3B,0x16,R,"Mechanical positioning or changer error"},
+ {0x3D,0x00,D|T|L|P|W|R|S|O|M|C|A|E|K,"Invalid bits in identify message"},
+ {0x3E,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Logical unit has not self-configured yet"},
+ {0x3E,0x01,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Logical unit failure"},
+ {0x3E,0x02,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Timeout on logical unit"},
+ {0x3E,0x03,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Logical unit failed self-test"},
+ {0x3E,0x04,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Logical unit unable to update self-test log"},
+ {0x3F,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Target operating conditions have changed"},
+ {0x3F,0x01,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Microcode has been changed"},
+ {0x3F,0x02,D|T|L|P|W|R|S|O|M|C|B|K,"Changed operating definition"},
+ {0x3F,0x03,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Inquiry data has changed"},
+ {0x3F,0x04,D|T|W|R|O|M|C|A|E|B|K,"Component device attached"},
+ {0x3F,0x05,D|T|W|R|O|M|C|A|E|B|K,"Device identifier changed"},
+ {0x3F,0x06,D|T|W|R|O|M|C|A|E|B,"Redundancy group created or modified"},
+ {0x3F,0x07,D|T|W|R|O|M|C|A|E|B,"Redundancy group deleted"},
+ {0x3F,0x08,D|T|W|R|O|M|C|A|E|B,"Spare created or modified"},
+ {0x3F,0x09,D|T|W|R|O|M|C|A|E|B,"Spare deleted"},
+ {0x3F,0x0A,D|T|W|R|O|M|C|A|E|B|K,"Volume set created or modified"},
+ {0x3F,0x0B,D|T|W|R|O|M|C|A|E|B|K,"Volume set deleted"},
+ {0x3F,0x0C,D|T|W|R|O|M|C|A|E|B|K,"Volume set deassigned"},
+ {0x3F,0x0D,D|T|W|R|O|M|C|A|E|B|K,"Volume set reassigned"},
+ {0x3F,0x0E,D|T|L|P|W|R|S|O|M|C|A|E,"Reported luns data has changed"},
+ {0x3F,0x10,D|T|W|R|O|M|B,"Medium loadable"},
+ {0x3F,0x11,D|T|W|R|O|M|B,"Medium auxiliary memory accessible"},
+ {0x40,0x00,D,"Ram failure (should use 40 nn)"},
+ /*
+ * FIXME(eric) - need a way to represent wildcards here.
+ */
+ {0x40,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Diagnostic failure on component nn (80h-ffh)"},
+ {0x41,0x00,D,"Data path failure (should use 40 nn)"},
+ {0x42,0x00,D,"Power-on or self-test failure (should use 40 nn)"},
+ {0x43,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Message error"},
+ {0x44,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Internal target failure"},
+ {0x45,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Select or reselect failure"},
+ {0x46,0x00,D|T|L|P|W|R|S|O|M|C|B|K,"Unsuccessful soft reset"},
+ {0x47,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Scsi parity error"},
+ {0x47,0x01,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Data phase CRC error detected"},
+ {0x47,0x02,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Scsi parity error detected during st data phase"},
+ {0x47,0x03,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Information unit CRC error detected"},
+ {0x47,0x04,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Asynchronous information protection error detected"},
+ {0x48,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Initiator detected error message received"},
+ {0x49,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Invalid message error"},
+ {0x4A,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Command phase error"},
+ {0x4B,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Data phase error"},
+ {0x4C,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Logical unit failed self-configuration"},
+ /*
+ * FIXME(eric) - need a way to represent wildcards here.
+ */
+ {0x4D,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Tagged overlapped commands (nn = queue tag)"},
+ {0x4E,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Overlapped commands attempted"},
{0x50,0x00,T,"Write append error"},
{0x50,0x01,T,"Write append position error"},
{0x50,0x02,T,"Position error related to timing"},
- {0x51,0x00,T|O,"Erase failure"},
+ {0x51,0x00,T|R|O,"Erase failure"},
{0x52,0x00,T,"Cartridge fault"},
- {0x53,0x00,D|T|L|W|R|S|O|M,"Media load or eject failed"},
+ {0x53,0x00,D|T|L|W|R|S|O|M|B|K,"Media load or eject failed"},
{0x53,0x01,T,"Unload tape failure"},
- {0x53,0x02,D|T|W|R|O|M,"Medium removal prevented"},
+ {0x53,0x02,D|T|W|R|O|M|B|K,"Medium removal prevented"},
{0x54,0x00,P,"Scsi to host system interface failure"},
{0x55,0x00,P,"System resource failure"},
+ {0x55,0x01,D|O|B|K,"System buffer full"},
+ {0x55,0x02,D|T|L|P|W|R|S|O|M|A|E|K,"Insufficient reservation resources"},
+ {0x55,0x03,D|T|L|P|W|R|S|O|M|C|A|E,"Insufficient resources"},
+ {0x55,0x04,D|T|L|P|W|R|S|O|M|A|E,"Insufficient registration resources"},
{0x57,0x00,R,"Unable to recover table-of-contents"},
{0x58,0x00,O,"Generation does not exist"},
{0x59,0x00,O,"Updated block read"},
- {0x5A,0x00,D|T|L|P|W|R|S|O|M,"Operator request or state change input (unspecified)"},
- {0x5A,0x01,D|T|W|R|O|M,"Operator medium removal request"},
- {0x5A,0x02,D|T|W|O,"Operator selected write protect"},
- {0x5A,0x03,D|T|W|O,"Operator selected write permit"},
- {0x5B,0x00,D|T|L|P|W|R|S|O|M,"Log exception"},
- {0x5B,0x01,D|T|L|P|W|R|S|O|M,"Threshold condition met"},
- {0x5B,0x02,D|T|L|P|W|R|S|O|M,"Log counter at maximum"},
- {0x5B,0x03,D|T|L|P|W|R|S|O|M,"Log list codes exhausted"},
+ {0x5A,0x00,D|T|L|P|W|R|S|O|M|B|K,"Operator request or state change input"},
+ {0x5A,0x01,D|T|W|R|O|M|B|K,"Operator medium removal request"},
+ {0x5A,0x02,D|T|W|R|O|A|B|K,"Operator selected write protect"},
+ {0x5A,0x03,D|T|W|R|O|A|B|K,"Operator selected write permit"},
+ {0x5B,0x00,D|T|L|P|W|R|S|O|M|K,"Log exception"},
+ {0x5B,0x01,D|T|L|P|W|R|S|O|M|K,"Threshold condition met"},
+ {0x5B,0x02,D|T|L|P|W|R|S|O|M|K,"Log counter at maximum"},
+ {0x5B,0x03,D|T|L|P|W|R|S|O|M|K,"Log list codes exhausted"},
{0x5C,0x00,D|O,"Rpl status change"},
{0x5C,0x01,D|O,"Spindles synchronized"},
{0x5C,0x02,D|O,"Spindles not synchronized"},
+ {0x5D,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Failure prediction threshold exceeded"},
+ {0x5D,0x01,R|B,"Media failure prediction threshold exceeded"},
+ {0x5D,0x02,R,"Logical unit failure prediction threshold exceeded"},
+ {0x5D,0x10,D|B,"Hardware impending failure general hard drive failure"},
+ {0x5D,0x11,D|B,"Hardware impending failure drive error rate too high"},
+ {0x5D,0x12,D|B,"Hardware impending failure data error rate too high"},
+ {0x5D,0x13,D|B,"Hardware impending failure seek error rate too high"},
+ {0x5D,0x14,D|B,"Hardware impending failure too many block reassigns"},
+ {0x5D,0x15,D|B,"Hardware impending failure access times too high"},
+ {0x5D,0x16,D|B,"Hardware impending failure start unit times too high"},
+ {0x5D,0x17,D|B,"Hardware impending failure channel parametrics"},
+ {0x5D,0x18,D|B,"Hardware impending failure controller detected"},
+ {0x5D,0x19,D|B,"Hardware impending failure throughput performance"},
+ {0x5D,0x1A,D|B,"Hardware impending failure seek time performance"},
+ {0x5D,0x1B,D|B,"Hardware impending failure spin-up retry count"},
+ {0x5D,0x1C,D|B,"Hardware impending failure drive calibration retry count"},
+ {0x5D,0x20,D|B,"Controller impending failure general hard drive failure"},
+ {0x5D,0x21,D|B,"Controller impending failure drive error rate too high"},
+ {0x5D,0x22,D|B,"Controller impending failure data error rate too high"},
+ {0x5D,0x23,D|B,"Controller impending failure seek error rate too high"},
+ {0x5D,0x24,D|B,"Controller impending failure too many block reassigns"},
+ {0x5D,0x25,D|B,"Controller impending failure access times too high"},
+ {0x5D,0x26,D|B,"Controller impending failure start unit times too high"},
+ {0x5D,0x27,D|B,"Controller impending failure channel parametrics"},
+ {0x5D,0x28,D|B,"Controller impending failure controller detected"},
+ {0x5D,0x29,D|B,"Controller impending failure throughput performance"},
+ {0x5D,0x2A,D|B,"Controller impending failure seek time performance"},
+ {0x5D,0x2B,D|B,"Controller impending failure spin-up retry count"},
+ {0x5D,0x2C,D|B,"Controller impending failure drive calibration retry count"},
+ {0x5D,0x30,D|B,"Data channel impending failure general hard drive failure"},
+ {0x5D,0x31,D|B,"Data channel impending failure drive error rate too high"},
+ {0x5D,0x32,D|B,"Data channel impending failure data error rate too high"},
+ {0x5D,0x33,D|B,"Data channel impending failure seek error rate too high"},
+ {0x5D,0x34,D|B,"Data channel impending failure too many block reassigns"},
+ {0x5D,0x35,D|B,"Data channel impending failure access times too high"},
+ {0x5D,0x36,D|B,"Data channel impending failure start unit times too high"},
+ {0x5D,0x37,D|B,"Data channel impending failure channel parametrics"},
+ {0x5D,0x38,D|B,"Data channel impending failure controller detected"},
+ {0x5D,0x39,D|B,"Data channel impending failure throughput performance"},
+ {0x5D,0x3A,D|B,"Data channel impending failure seek time performance"},
+ {0x5D,0x3B,D|B,"Data channel impending failure spin-up retry count"},
+ {0x5D,0x3C,D|B,"Data channel impending failure drive calibration retry count"},
+ {0x5D,0x40,D|B,"Servo impending failure general hard drive failure"},
+ {0x5D,0x41,D|B,"Servo impending failure drive error rate too high"},
+ {0x5D,0x42,D|B,"Servo impending failure data error rate too high"},
+ {0x5D,0x43,D|B,"Servo impending failure seek error rate too high"},
+ {0x5D,0x44,D|B,"Servo impending failure too many block reassigns"},
+ {0x5D,0x45,D|B,"Servo impending failure access times too high"},
+ {0x5D,0x46,D|B,"Servo impending failure start unit times too high"},
+ {0x5D,0x47,D|B,"Servo impending failure channel parametrics"},
+ {0x5D,0x48,D|B,"Servo impending failure controller detected"},
+ {0x5D,0x49,D|B,"Servo impending failure throughput performance"},
+ {0x5D,0x4A,D|B,"Servo impending failure seek time performance"},
+ {0x5D,0x4B,D|B,"Servo impending failure spin-up retry count"},
+ {0x5D,0x4C,D|B,"Servo impending failure drive calibration retry count"},
+ {0x5D,0x50,D|B,"Spindle impending failure general hard drive failure"},
+ {0x5D,0x51,D|B,"Spindle impending failure drive error rate too high"},
+ {0x5D,0x52,D|B,"Spindle impending failure data error rate too high"},
+ {0x5D,0x53,D|B,"Spindle impending failure seek error rate too high"},
+ {0x5D,0x54,D|B,"Spindle impending failure too many block reassigns"},
+ {0x5D,0x55,D|B,"Spindle impending failure access times too high"},
+ {0x5D,0x56,D|B,"Spindle impending failure start unit times too high"},
+ {0x5D,0x57,D|B,"Spindle impending failure channel parametrics"},
+ {0x5D,0x58,D|B,"Spindle impending failure controller detected"},
+ {0x5D,0x59,D|B,"Spindle impending failure throughput performance"},
+ {0x5D,0x5A,D|B,"Spindle impending failure seek time performance"},
+ {0x5D,0x5B,D|B,"Spindle impending failure spin-up retry count"},
+ {0x5D,0x5C,D|B,"Spindle impending failure drive calibration retry count"},
+ {0x5D,0x60,D|B,"Firmware impending failure general hard drive failure"},
+ {0x5D,0x61,D|B,"Firmware impending failure drive error rate too high"},
+ {0x5D,0x62,D|B,"Firmware impending failure data error rate too high"},
+ {0x5D,0x63,D|B,"Firmware impending failure seek error rate too high"},
+ {0x5D,0x64,D|B,"Firmware impending failure too many block reassigns"},
+ {0x5D,0x65,D|B,"Firmware impending failure access times too high"},
+ {0x5D,0x66,D|B,"Firmware impending failure start unit times too high"},
+ {0x5D,0x67,D|B,"Firmware impending failure channel parametrics"},
+ {0x5D,0x68,D|B,"Firmware impending failure controller detected"},
+ {0x5D,0x69,D|B,"Firmware impending failure throughput performance"},
+ {0x5D,0x6A,D|B,"Firmware impending failure seek time performance"},
+ {0x5D,0x6B,D|B,"Firmware impending failure spin-up retry count"},
+ {0x5D,0x6C,D|B,"Firmware impending failure drive calibration retry count"},
+ {0x5D,0xFF,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Failure prediction threshold exceeded (false)"},
+ {0x5E,0x00,D|T|L|P|W|R|S|O|C|A|K,"Low power condition on"},
+ {0x5E,0x01,D|T|L|P|W|R|S|O|C|A|K,"Idle condition activated by timer"},
+ {0x5E,0x02,D|T|L|P|W|R|S|O|C|A|K,"Standby condition activated by timer"},
+ {0x5E,0x03,D|T|L|P|W|R|S|O|C|A|K,"Idle condition activated by command"},
+ {0x5E,0x04,D|T|L|P|W|R|S|O|C|A|K,"Standby condition activated by command"},
+ {0x5E,0x41,B,"Power state change to active"},
+ {0x5E,0x42,B,"Power state change to idle"},
+ {0x5E,0x43,B,"Power state change to standby"},
+ {0x5E,0x45,B,"Power state change to sleep"},
+ {0x5E,0x47,B|K,"Power state change to device control"},
{0x60,0x00,S,"Lamp failure"},
{0x61,0x00,S,"Video acquisition error"},
{0x61,0x01,S,"Unable to acquire video"},
{0x61,0x02,S,"Out of focus"},
{0x62,0x00,S,"Scan head positioning error"},
{0x63,0x00,R,"End of user area encountered on this track"},
+ {0x63,0x01,R,"Packet does not fit in available space"},
{0x64,0x00,R,"Illegal mode for this track"},
+ {0x64,0x01,R,"Invalid packet size"},
+ {0x65,0x00,D|T|L|P|W|R|S|O|M|C|A|E|B|K,"Voltage fault"},
+ {0x66,0x00,S,"Automatic document feeder cover up"},
+ {0x66,0x01,S,"Automatic document feeder lift up"},
+ {0x66,0x02,S,"Document jam in automatic document feeder"},
+ {0x66,0x03,S,"Document miss feed automatic in document feeder"},
+ {0x67,0x00,A,"Configuration failure"},
+ {0x67,0x01,A,"Configuration of incapable logical units failed"},
+ {0x67,0x02,A,"Add logical unit failed"},
+ {0x67,0x03,A,"Modification of logical unit failed"},
+ {0x67,0x04,A,"Exchange of logical unit failed"},
+ {0x67,0x05,A,"Remove of logical unit failed"},
+ {0x67,0x06,A,"Attachment of logical unit failed"},
+ {0x67,0x07,A,"Creation of logical unit failed"},
+ {0x67,0x08,A,"Assign failure occurred"},
+ {0x67,0x09,A,"Multiply assigned logical unit"},
+ {0x68,0x00,A,"Logical unit not configured"},
+ {0x69,0x00,A,"Data loss on logical unit"},
+ {0x69,0x01,A,"Multiple logical unit failures"},
+ {0x69,0x02,A,"Parity/data mismatch"},
+ {0x6A,0x00,A,"Informational,refer to log"},
+ {0x6B,0x00,A,"State change has occurred"},
+ {0x6B,0x01,A,"Redundancy level got better"},
+ {0x6B,0x02,A,"Redundancy level got worse"},
+ {0x6C,0x00,A,"Rebuild failure occurred"},
+ {0x6D,0x00,A,"Recalculate failure occurred"},
+ {0x6E,0x00,A,"Command to logical unit failed"},
+ {0x6F,0x00,R,"Copy protection key exchange failure - authentication failure"},
+ {0x6F,0x01,R,"Copy protection key exchange failure - key not present"},
+ {0x6F,0x02,R,"Copy protection key exchange failure - key not established"},
+ {0x6F,0x03,R,"Read of scrambled sector without authentication"},
+ {0x6F,0x04,R,"Media region code is mismatched to logical unit region"},
+ {0x6F,0x05,R,"Drive region must be permanent/region reset count error"},
+ /*
+ * FIXME(eric) - need a way to represent wildcards here.
+ */
+ {0x70,0x00,T,"Decompression exception short algorithm id of nn"},
+ {0x71,0x00,T,"Decompression exception long algorithm id"},
+ {0x72,0x00,R,"Session fixation error"},
+ {0x72,0x01,R,"Session fixation error writing lead-in"},
+ {0x72,0x02,R,"Session fixation error writing lead-out"},
+ {0x72,0x03,R,"Session fixation error - incomplete track in session"},
+ {0x72,0x04,R,"Empty or partially written reserved track"},
+ {0x72,0x05,R,"No more track reservations allowed"},
+ {0x73,0x00,R,"Cd control error"},
+ {0x73,0x01,R,"Power calibration area almost full"},
+ {0x73,0x02,R,"Power calibration area is full"},
+ {0x73,0x03,R,"Power calibration area error"},
+ {0x73,0x04,R,"Program memory area update failure"},
+ {0x73,0x05,R,"Program memory area is full"},
+ {0x73,0x06,R,"RMA/PMA is full"},
{0, 0, 0, NULL}
};
#endif
diff --git a/drivers/scsi/eata_dma_proc.c b/drivers/scsi/eata_dma_proc.c
index 8768db48c..7961483e1 100644
--- a/drivers/scsi/eata_dma_proc.c
+++ b/drivers/scsi/eata_dma_proc.c
@@ -69,7 +69,7 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
Scsi_Device *scd, *SDev;
struct Scsi_Host *HBA_ptr;
- Scsi_Cmnd * scmd;
+ Scsi_Request * scmd;
char cmnd[MAX_COMMAND_SIZE];
static u8 buff[512];
static u8 buff2[512];
@@ -153,7 +153,7 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
} else {
SDev = scsi_get_host_dev(HBA_ptr);
- scmd = scsi_allocate_device(SDev, 1, FALSE);
+ scmd = scsi_allocate_request(SDev);
cmnd[0] = LOG_SENSE;
cmnd[1] = 0;
@@ -166,13 +166,13 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
cmnd[8] = 0x66;
cmnd[9] = 0;
- scmd->cmd_len = 10;
- scmd->sc_data_direction = SCSI_DATA_READ;
+ scmd->sr_cmd_len = 10;
+ scmd->sr_data_direction = SCSI_DATA_READ;
/*
* Do the command and wait for it to finish.
*/
- scsi_wait_cmd (scmd, cmnd, buff + 0x144, 0x66,
+ scsi_wait_req (scmd, cmnd, buff + 0x144, 0x66,
1 * HZ, 1);
size = sprintf(buffer + len, "IRQ: %2d, %s triggered\n", cc->interrupt,
@@ -291,13 +291,13 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
cmnd[8] = 0x44;
cmnd[9] = 0;
- scmd->cmd_len = 10;
- scmd->sc_data_direction = SCSI_DATA_READ;
+ scmd->sr_cmd_len = 10;
+ scmd->sr_data_direction = SCSI_DATA_READ;
/*
* Do the command and wait for it to finish.
*/
- scsi_wait_cmd (scmd, cmnd, buff2, 0x144,
+ scsi_wait_req (scmd, cmnd, buff2, 0x144,
1 * HZ, 1);
swap_statistics(buff2);
@@ -333,7 +333,7 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
pos = begin + len;
}
- scsi_release_command(scmd);
+ scsi_release_request(scmd);
scsi_free_host_dev(SDev);
}
diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
index f1b82a5a1..685925e7d 100644
--- a/drivers/scsi/hosts.h
+++ b/drivers/scsi/hosts.h
@@ -469,10 +469,10 @@ extern void scsi_deregister_blocked_host(struct Scsi_Host * SHpnt);
* Prototypes for functions/data in scsi_scan.c
*/
extern void scan_scsis(struct Scsi_Host *shpnt,
- unchar hardcoded,
- unchar hchannel,
- unchar hid,
- unchar hlun);
+ uint hardcoded,
+ uint hchannel,
+ uint hid,
+ uint hlun);
extern void scsi_mark_host_reset(struct Scsi_Host *Host);
@@ -485,12 +485,12 @@ struct Scsi_Device_Template
const char * tag;
struct module * module; /* Used for loadable modules */
unsigned char scsi_type;
- unsigned char major;
- unsigned char min_major; /* Minimum major in range. */
- unsigned char max_major; /* Maximum major in range. */
- unsigned char nr_dev; /* Number currently attached */
- unsigned char dev_noticed; /* Number of devices detected. */
- unsigned char dev_max; /* Current size of arrays */
+ unsigned int major;
+ unsigned int min_major; /* Minimum major in range. */
+ unsigned int max_major; /* Maximum major in range. */
+ unsigned int nr_dev; /* Number currently attached */
+ unsigned int dev_noticed; /* Number of devices detected. */
+ unsigned int dev_max; /* Current size of arrays */
unsigned blk:1; /* 0 if character device */
int (*detect)(Scsi_Device *); /* Returns 1 if we can attach this device */
int (*init)(void); /* Sizes arrays based upon number of devices
@@ -534,20 +534,18 @@ extern void scsi_unregister_module(int, void *);
* Note: These things are all evil and all need to go away. My plan is to
* tackle the character devices first, as there aren't any locking implications
* in the block device layer. The block devices will require more work.
+ *
+ * The generics driver has been updated to resize as required. So as the tape
+ * driver. Two down, two more to go.
*/
#ifndef CONFIG_SD_EXTRA_DEVS
#define CONFIG_SD_EXTRA_DEVS 2
#endif
-#ifndef CONFIG_ST_EXTRA_DEVS
-#define CONFIG_ST_EXTRA_DEVS 2
-#endif
#ifndef CONFIG_SR_EXTRA_DEVS
#define CONFIG_SR_EXTRA_DEVS 2
#endif
#define SD_EXTRA_DEVS CONFIG_SD_EXTRA_DEVS
-#define ST_EXTRA_DEVS CONFIG_ST_EXTRA_DEVS
#define SR_EXTRA_DEVS CONFIG_SR_EXTRA_DEVS
-#define SG_EXTRA_DEVS (SD_EXTRA_DEVS + SR_EXTRA_DEVS + ST_EXTRA_DEVS)
#endif
/*
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index d2943f103..5fc1bfaab 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -73,7 +73,7 @@
*/
/*
-** January 8 2000, version 3.2e
+** March 6 2000, version 3.2g
**
** Supported SCSI-II features:
** Synchronous negotiation
@@ -104,7 +104,7 @@
/*
** Name and version of the driver
*/
-#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - version 3.2e"
+#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - version 3.2g"
#define SCSI_NCR_DEBUG_FLAGS (0)
@@ -141,11 +141,6 @@
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/stat.h>
-#ifdef __mips__
-#include <asm/bootinfo.h>
-#include <asm/pgtable.h>
-#include <asm/sni.h>
-#endif /* __mips__ */
#include <linux/version.h>
#include <linux/blk.h>
@@ -189,98 +184,14 @@
*/
typedef u32 u_int32;
typedef u64 u_int64;
-
+typedef u_long vm_offset_t;
#include "ncr53c8xx.h"
-/*==========================================================
-**
-** A la VMS/CAM-3 queue management.
-** Implemented from linux list management.
-**
-**==========================================================
-*/
-
-typedef struct xpt_quehead {
- struct xpt_quehead *flink; /* Forward pointer */
- struct xpt_quehead *blink; /* Backward pointer */
-} XPT_QUEHEAD;
-
-#define xpt_que_init(ptr) do { \
- (ptr)->flink = (ptr); (ptr)->blink = (ptr); \
-} while (0)
-
-static inline void __xpt_que_add(struct xpt_quehead * new,
- struct xpt_quehead * blink,
- struct xpt_quehead * flink)
-{
- flink->blink = new;
- new->flink = flink;
- new->blink = blink;
- blink->flink = new;
-}
-
-static inline void __xpt_que_del(struct xpt_quehead * blink,
- struct xpt_quehead * flink)
-{
- flink->blink = blink;
- blink->flink = flink;
-}
-
-static inline int xpt_que_empty(struct xpt_quehead *head)
-{
- return head->flink == head;
-}
-
-static inline void xpt_que_splice(struct xpt_quehead *list,
- struct xpt_quehead *head)
-{
- struct xpt_quehead *first = list->flink;
-
- if (first != list) {
- struct xpt_quehead *last = list->blink;
- struct xpt_quehead *at = head->flink;
+#define NAME53C "ncr53c"
+#define NAME53C8XX "ncr53c8xx"
+#define DRIVER_SMP_LOCK ncr53c8xx_lock
- first->blink = head;
- head->flink = first;
-
- last->flink = at;
- at->blink = last;
- }
-}
-
-#define xpt_que_entry(ptr, type, member) \
- ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
-
-
-#define xpt_insque(new, pos) __xpt_que_add(new, pos, (pos)->flink)
-
-#define xpt_remque(el) __xpt_que_del((el)->blink, (el)->flink)
-
-#define xpt_insque_head(new, head) __xpt_que_add(new, head, (head)->flink)
-
-static inline struct xpt_quehead *xpt_remque_head(struct xpt_quehead *head)
-{
- struct xpt_quehead *elem = head->flink;
-
- if (elem != head)
- __xpt_que_del(head, elem->flink);
- else
- elem = 0;
- return elem;
-}
-
-#define xpt_insque_tail(new, head) __xpt_que_add(new, (head)->blink, head)
-
-static inline struct xpt_quehead *xpt_remque_tail(struct xpt_quehead *head)
-{
- struct xpt_quehead *elem = head->blink;
-
- if (elem != head)
- __xpt_que_del(elem->blink, head);
- else
- elem = 0;
- return elem;
-}
+#include "sym53c8xx_comm.h"
/*==========================================================
**
@@ -320,33 +231,6 @@ static inline struct xpt_quehead *xpt_remque_tail(struct xpt_quehead *head)
/*==========================================================
**
-** On x86 architecture, write buffers management does
-** not reorder writes to memory. So, using compiler
-** optimization barriers is enough to guarantee some
-** ordering when the CPU is writing data accessed by
-** the NCR.
-** On Alpha architecture, explicit memory barriers have
-** to be used.
-** Other architectures are defaulted to mb() macro if
-** defined, otherwise use compiler barrier.
-**
-**==========================================================
-*/
-
-#if defined(__i386__)
-#define MEMORY_BARRIER() barrier()
-#elif defined(__alpha__)
-#define MEMORY_BARRIER() mb()
-#else
-# ifdef mb
-# define MEMORY_BARRIER() mb()
-# else
-# define MEMORY_BARRIER() barrier()
-# endif
-#endif
-
-/*==========================================================
-**
** Configuration and Debugging
**
**==========================================================
@@ -469,381 +353,11 @@ typedef u_int32 tagmap_t;
#endif
/*
-** Io mapped or memory mapped.
-*/
-
-#if defined(SCSI_NCR_IOMAPPED)
-#define NCR_IOMAPPED
-#endif
-
-/*
** other
*/
#define NCR_SNOOP_TIMEOUT (1000000)
-/*==========================================================
-**
-** Defines for Linux.
-**
-** Linux and Bsd kernel functions are quite different.
-** These defines allow a minimum change of the original
-** code.
-**
-**==========================================================
-*/
-
- /*
- ** Obvious definitions
- */
-
-#define u_char unsigned char
-#define u_short unsigned short
-#define u_int unsigned int
-#define u_long unsigned long
-
-typedef u_long vm_offset_t;
-typedef int vm_size_t;
-
-#ifndef bcopy
-#define bcopy(s, d, n) memcpy((d), (s), (n))
-#endif
-#ifndef bzero
-#define bzero(d, n) memset((d), 0, (n))
-#endif
-
-#ifndef offsetof
-#define offsetof(t, m) ((size_t) (&((t *)0)->m))
-#endif
-
-/*
-** Simple Wrapper to kernel PCI bus interface.
-**
-** This wrapper allows to get rid of old kernel PCI interface
-** and still allows to preserve linux-2.0 compatibilty.
-** In fact, it is mostly an incomplete emulation of the new
-** PCI code for pre-2.2 kernels. When kernel-2.0 support
-** will be dropped, we will just have to remove most of this
-** code.
-*/
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,2,0)
-
-typedef struct pci_dev *pcidev_t;
-#define PCIDEV_NULL (0)
-#define PciBusNumber(d) (d)->bus->number
-#define PciDeviceFn(d) (d)->devfn
-#define PciVendorId(d) (d)->vendor
-#define PciDeviceId(d) (d)->device
-#define PciIrqLine(d) (d)->irq
-
-#if LINUX_VERSION_CODE > LinuxVersionCode(2,3,12)
-
-static int __init
-pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
-{
- *base = pdev->resource[index].start;
- if ((pdev->resource[index].flags & 0x7) == 0x4)
- ++index;
- return ++index;
-}
-#else
-static int __init
-pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
-{
- *base = pdev->base_address[index++];
- if ((*base & 0x7) == 0x4) {
-#if BITS_PER_LONG > 32
- *base |= (((u_long)pdev->base_address[index]) << 32);
-#endif
- ++index;
- }
- return index;
-}
-#endif
-
-#else /* Incomplete emulation of current PCI code for pre-2.2 kernels */
-
-typedef unsigned int pcidev_t;
-#define PCIDEV_NULL (~0u)
-#define PciBusNumber(d) ((d)>>8)
-#define PciDeviceFn(n) ((d)&0xff)
-#define __PciDev(busn, devfn) (((busn)<<8)+(devfn))
-
-#define pci_present pcibios_present
-
-#define pci_read_config_byte(d, w, v) \
- pcibios_read_config_byte(PciBusNumber(d), PciDeviceFn(d), w, v)
-#define pci_read_config_word(d, w, v) \
- pcibios_read_config_word(PciBusNumber(d), PciDeviceFn(d), w, v)
-#define pci_read_config_dword(d, w, v) \
- pcibios_read_config_dword(PciBusNumber(d), PciDeviceFn(d), w, v)
-
-
-#define pci_write_config_byte(d, w, v) \
- pcibios_write_config_byte(PciBusNumber(d), PciDeviceFn(d), w, v)
-#define pci_write_config_word(d, w, v) \
- pcibios_write_config_word(PciBusNumber(d), PciDeviceFn(d), w, v)
-#define pci_write_config_dword(d, w, v) \
- pcibios_write_config_dword(PciBusNumber(d), PciDeviceFn(d), w, v)
-
-static pcidev_t __init
-pci_find_device(unsigned int vendor, unsigned int device, pcidev_t prev)
-{
- static unsigned short pci_index;
- int retv;
- unsigned char bus_number, device_fn;
-
- if (prev == PCIDEV_NULL)
- pci_index = 0;
- else
- ++pci_index;
- retv = pcibios_find_device (vendor, device, pci_index,
- &bus_number, &device_fn);
- return retv ? PCIDEV_NULL : __PciDev(bus_number, device_fn);
-}
-
-static u_short __init PciVendorId(pcidev_t dev)
-{
- u_short vendor_id;
- pcibios_read_config_word(dev, PCI_VENDOR_ID, &vendor_id);
- return vendor_id;
-}
-
-static u_short __init PciDeviceId(pcidev_t dev)
-{
- u_short device_id;
- pci_read_config_word(dev, PCI_DEVICE_ID, &device_id);
- return device_id;
-}
-
-static u_int __init PciIrqLine(pcidev_t dev)
-{
- u_short irq;
- pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
- return irq;
-}
-
-static int __init
-pci_get_base_address(pcidev_t dev, int offset, u_long *base)
-{
- u_int32 tmp;
-
- pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + offset, &tmp);
- *base = tmp;
- offset += sizeof(u_int32);
- if ((tmp & 0x7) == 0x4) {
-#if BITS_PER_LONG > 32
- pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + offset, &tmp);
- *base |= (((u_long)tmp) << 32);
-#endif
- offset += sizeof(u_int32);
- }
- return offset;
-}
-
-#endif /* LINUX_VERSION_CODE >= LinuxVersionCode(2,2,0) */
-
-/*
-** SMP threading.
-**
-** Assuming that SMP systems are generally high end systems and may
-** use several SCSI adapters, we are using one lock per controller
-** instead of some global one. For the moment (linux-2.1.95), driver's
-** entry points are called with the 'io_request_lock' lock held, so:
-** - We are uselessly loosing a couple of micro-seconds to lock the
-** controller data structure.
-** - But the driver is not broken by design for SMP and so can be
-** more resistant to bugs or bad changes in the IO sub-system code.
-** - A small advantage could be that the interrupt code is grained as
-** wished (e.g.: threaded by controller).
-*/
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
-
-#if 0 /* not yet needed */
-static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED;
-#define NCR_LOCK_DRIVER(flags) spin_lock_irqsave(&driver_lock, flags)
-#define NCR_UNLOCK_DRIVER(flags) spin_unlock_irqrestore(&driver_lock, flags)
-#endif
-
-#define NCR_INIT_LOCK_NCB(np) spin_lock_init(&np->smp_lock);
-#define NCR_LOCK_NCB(np, flags) spin_lock_irqsave(&np->smp_lock, flags)
-#define NCR_UNLOCK_NCB(np, flags) spin_unlock_irqrestore(&np->smp_lock, flags)
-
-#define NCR_LOCK_SCSI_DONE(np, flags) \
- spin_lock_irqsave(&io_request_lock, flags)
-#define NCR_UNLOCK_SCSI_DONE(np, flags) \
- spin_unlock_irqrestore(&io_request_lock, flags)
-
-#else
-
-#if 0 /* not yet needed */
-#define NCR_LOCK_DRIVER(flags) do {;} while (0)
-#define NCR_UNLOCK_DRIVER(flags) do {;} while (0)
-#endif
-
-#define NCR_INIT_LOCK_NCB(np) do { } while (0)
-#define NCR_LOCK_NCB(np, flags) do { save_flags(flags); cli(); } while (0)
-#define NCR_UNLOCK_NCB(np, flags) do { restore_flags(flags); } while (0)
-
-#define NCR_LOCK_SCSI_DONE(np, flags) do {;} while (0)
-#define NCR_UNLOCK_SCSI_DONE(np, flags) do {;} while (0)
-
-#endif
-
-/*
-** Address translation
-**
-** The driver has to provide physical memory addresses to
-** the script processor. Because some architectures use
-** different physical addresses from the PCI BUS, we must
-** use virt_to_bus instead of virt_to_phys.
-**
-** FIXME: Bus addresses are _not_ physical addresses.
-*/
-
-#define vtophys(p) virt_to_bus(p)
-
-/*
-** Memory mapped IO
-**
-** Since linux-2.1, we must use ioremap() to map the io memory space.
-** iounmap() to unmap it. That allows portability.
-** Linux 1.3.X and 2.0.X allow to remap physical pages addresses greater
-** than the highest physical memory address to kernel virtual pages with
-** vremap() / vfree(). That was not portable but worked with i386
-** architecture.
-*/
-
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,0)
-#define ioremap vremap
-#define iounmap vfree
-#endif
-
-#if defined (__sparc__)
-#include <asm/irq.h>
-#elif defined (__alpha__)
-#define bus_dvma_to_mem(p) ((p) & 0xfffffffful)
-#else
-#define bus_dvma_to_mem(p) (p)
-#endif
-
-#if defined(__i386__) || !defined(NCR_IOMAPPED)
-static vm_offset_t __init remap_pci_mem(u_long base, u_long size)
-{
- u_long page_base = ((u_long) base) & PAGE_MASK;
- u_long page_offs = ((u_long) base) - page_base;
- u_long page_remapped = (u_long) ioremap(page_base, page_offs+size);
-
- return (vm_offset_t) (page_remapped? (page_remapped + page_offs) : 0UL);
-}
-
-static void __init unmap_pci_mem(vm_offset_t vaddr, u_long size)
-{
- if (vaddr)
- iounmap((void *) (vaddr & PAGE_MASK));
-}
-#endif /* __i386__ || !NCR_IOMAPPED */
-
-/*
-** Insert a delay in micro-seconds and milli-seconds.
-** -------------------------------------------------
-** Under Linux, udelay() is restricted to delay < 1 milli-second.
-** In fact, it generally works for up to 1 second delay.
-** Since 2.1.105, the mdelay() function is provided for delays
-** in milli-seconds.
-** Under 2.0 kernels, udelay() is an inline function that is very
-** inaccurate on Pentium processors.
-*/
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,105)
-#define UDELAY udelay
-#define MDELAY mdelay
-#else
-static void UDELAY(long us) { udelay(us); }
-static void MDELAY(long ms) { while (ms--) UDELAY(1000); }
-#endif
-
-/*
-** Internal data structure allocation.
-**
-** Linux scsi memory poor pool is adjusted for the need of
-** middle-level scsi driver.
-** We allocate our control blocks in the kernel memory pool
-** to avoid scsi pool shortage.
-**
-** kmalloc() only ensures 8 bytes boundary alignment.
-** The NCR need better alignment for cache line bursting.
-** The global header is moved between the NCB and CCBs and needs
-** origin and destination addresses to have same lower four bits.
-**
-** We use 32 boundary alignment for NCB and CCBs and offset multiple
-** of 32 for global header fields. That's too much but at least enough.
-*/
-
-#define ALIGN_SIZE(shift) (1UL << shift)
-#define ALIGN_MASK(shift) (~(ALIGN_SIZE(shift)-1))
-
-#define CACHE_LINE_SHIFT 5
-#define CACHE_LINE_SIZE ALIGN_SIZE(CACHE_LINE_SHIFT)
-#define CACHE_LINE_MASK ALIGN_MASK(CACHE_LINE_SHIFT)
-
-static void *m_alloc(int size, int a_shift)
-{
- u_long addr;
- void *ptr;
- u_long a_size, a_mask;
-
- if (a_shift < 3)
- a_shift = 3;
-
- a_size = ALIGN_SIZE(a_shift);
- a_mask = ALIGN_MASK(a_shift);
-
- ptr = (void *) kmalloc(size + a_size, GFP_UNCACHED | GFP_ATOMIC);
- if (ptr) {
- addr = (((u_long) ptr) + a_size) & a_mask;
- *((void **) (addr - sizeof(void *))) = ptr;
- ptr = (void *) addr;
- }
-
- return ptr;
-}
-
-#ifdef MODULE
-static void m_free(void *ptr, int size)
-{
- u_long addr;
-
- if (ptr) {
- addr = (u_long) ptr;
- ptr = *((void **) (addr - sizeof(void *)));
-
- kfree(ptr);
- }
-}
-#endif
-
-/*
-** Transfer direction
-**
-** Low-level scsi drivers under Linux do not receive the expected
-** data transfer direction from upper scsi drivers.
-** The driver will only check actual data direction for common
-** scsi opcodes. Other ones may cause problem, since they may
-** depend on device type or be vendor specific.
-** I would prefer to never trust the device for data direction,
-** but that is not possible.
-**
-** The original driver requires the expected direction to be known.
-** The Linux version of the driver has been enhanced in order to
-** be able to transfer data in the direction choosen by the target.
-*/
-
-#define XFER_IN (1)
-#define XFER_OUT (2)
-
/*
** Head of list of NCR boards
**
@@ -855,44 +369,8 @@ static void m_free(void *ptr, int size)
static struct Scsi_Host *first_host = NULL;
static Scsi_Host_Template *the_template = NULL;
-
-/*
-** /proc directory entry and proc_info function
-*/
-
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
-static struct proc_dir_entry proc_scsi_ncr53c8xx = {
- PROC_SCSI_NCR53C8XX, 9, "ncr53c8xx",
- S_IFDIR | S_IRUGO | S_IXUGO, 2
-};
-#endif
-#ifdef SCSI_NCR_PROC_INFO_SUPPORT
-static int ncr53c8xx_proc_info(char *buffer, char **start, off_t offset,
- int length, int hostno, int func);
-#endif
-
/*
-** Driver setup.
-**
-** This structure is initialized from linux config options.
-** It can be overridden at boot-up by the boot command line.
-*/
-static struct ncr_driver_setup
- driver_setup = SCSI_NCR_DRIVER_SETUP;
-
-#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
-static struct ncr_driver_setup
- driver_safe_setup __initdata = SCSI_NCR_DRIVER_SAFE_SETUP;
-# ifdef MODULE
-char *ncr53c8xx = 0; /* command line passed by insmod */
-# if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
-MODULE_PARM(ncr53c8xx, "s");
-# endif
-# endif
-#endif
-
-/*
-** Other Linux definitions
+** Other definitions
*/
#define ScsiResult(host_code, scsi_code) (((host_code) << 16) + ((scsi_code) & 0x7f))
@@ -903,273 +381,13 @@ static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
static void ncr53c8xx_timeout(unsigned long np);
#define initverbose (driver_setup.verbose)
-#define bootverbose (driver_setup.verbose)
+#define bootverbose (np->verbose)
#ifdef SCSI_NCR_NVRAM_SUPPORT
static u_char Tekram_sync[16] __initdata =
{25,31,37,43, 50,62,75,125, 12,15,18,21, 6,7,9,10};
#endif /* SCSI_NCR_NVRAM_SUPPORT */
-/*
-** Structures used by ncr53c8xx_detect/ncr53c8xx_pci_init to
-** transmit device configuration to the ncr_attach() function.
-*/
-typedef struct {
- int bus;
- u_char device_fn;
- u_long base;
- u_long base_2;
- u_long io_port;
- int irq;
-/* port and reg fields to use INB, OUTB macros */
- u_long port;
- volatile struct ncr_reg *reg;
-} ncr_slot;
-
-typedef struct {
- int type;
-#define SCSI_NCR_SYMBIOS_NVRAM (1)
-#define SCSI_NCR_TEKRAM_NVRAM (2)
-#ifdef SCSI_NCR_NVRAM_SUPPORT
- union {
- Symbios_nvram Symbios;
- Tekram_nvram Tekram;
- } data;
-#endif
-} ncr_nvram;
-
-/*
-** Structure used by ncr53c8xx_detect/ncr53c8xx_pci_init
-** to save data on each detected board for ncr_attach().
-*/
-typedef struct {
- ncr_slot slot;
- ncr_chip chip;
- ncr_nvram *nvram;
- u_char host_id;
- int attach_done;
-} ncr_device;
-
-/*==========================================================
-**
-** Debugging tags
-**
-**==========================================================
-*/
-
-#define DEBUG_ALLOC (0x0001)
-#define DEBUG_PHASE (0x0002)
-#define DEBUG_QUEUE (0x0008)
-#define DEBUG_RESULT (0x0010)
-#define DEBUG_SCATTER (0x0020)
-#define DEBUG_SCRIPT (0x0040)
-#define DEBUG_TINY (0x0080)
-#define DEBUG_TIMING (0x0100)
-#define DEBUG_NEGO (0x0200)
-#define DEBUG_TAGS (0x0400)
-
-/*
-** Enable/Disable debug messages.
-** Can be changed at runtime too.
-*/
-
-#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
- #define DEBUG_FLAGS ncr_debug
-#else
- #define DEBUG_FLAGS SCSI_NCR_DEBUG_FLAGS
-#endif
-
-
-
-/*==========================================================
-**
-** assert ()
-**
-**==========================================================
-**
-** modified copy from 386bsd:/usr/include/sys/assert.h
-**
-**----------------------------------------------------------
-*/
-
-#define assert(expression) { \
- if (!(expression)) { \
- (void)printk(KERN_ERR \
- "assertion \"%s\" failed: file \"%s\", line %d\n", \
- #expression, \
- __FILE__, __LINE__); \
- } \
-}
-
-/*==========================================================
-**
-** Big/Little endian support.
-**
-**==========================================================
-*/
-
-/*
-** If the NCR uses big endian addressing mode over the
-** PCI, actual io register addresses for byte and word
-** accesses must be changed according to lane routing.
-** Btw, ncr_offb() and ncr_offw() macros only apply to
-** constants and so donnot generate bloated code.
-*/
-
-#if defined(SCSI_NCR_BIG_ENDIAN)
-
-#define ncr_offb(o) (((o)&~3)+((~((o)&3))&3))
-#define ncr_offw(o) (((o)&~3)+((~((o)&3))&2))
-
-#else
-
-#define ncr_offb(o) (o)
-#define ncr_offw(o) (o)
-
-#endif
-
-/*
-** If the CPU and the NCR use same endian-ness addressing,
-** no byte reordering is needed for script patching.
-** Macro cpu_to_scr() is to be used for script patching.
-** Macro scr_to_cpu() is to be used for getting a DWORD
-** from the script.
-*/
-
-#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
-
-#define cpu_to_scr(dw) cpu_to_le32(dw)
-#define scr_to_cpu(dw) le32_to_cpu(dw)
-
-#elif defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
-
-#define cpu_to_scr(dw) cpu_to_be32(dw)
-#define scr_to_cpu(dw) be32_to_cpu(dw)
-
-#else
-
-#define cpu_to_scr(dw) (dw)
-#define scr_to_cpu(dw) (dw)
-
-#endif
-
-/*==========================================================
-**
-** Access to the controller chip.
-**
-** If NCR_IOMAPPED is defined, the driver will use
-** normal IOs instead of the MEMORY MAPPED IO method
-** recommended by PCI specifications.
-** If all PCI bridges, host brigdes and architectures
-** would have been correctly designed for PCI, this
-** option would be useless.
-**
-**==========================================================
-*/
-
-/*
-** If the CPU and the NCR use same endian-ness addressing,
-** no byte reordering is needed for accessing chip io
-** registers. Functions suffixed by '_raw' are assumed
-** to access the chip over the PCI without doing byte
-** reordering. Functions suffixed by '_l2b' are
-** assumed to perform little-endian to big-endian byte
-** reordering, those suffixed by '_b2l' blah, blah,
-** blah, ...
-*/
-
-#if defined(NCR_IOMAPPED)
-
-/*
-** IO mapped only input / ouput
-*/
-
-#define INB_OFF(o) inb (np->port + ncr_offb(o))
-#define OUTB_OFF(o, val) outb ((val), np->port + ncr_offb(o))
-
-#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
-
-#define INW_OFF(o) inw_l2b (np->port + ncr_offw(o))
-#define INL_OFF(o) inl_l2b (np->port + (o))
-
-#define OUTW_OFF(o, val) outw_b2l ((val), np->port + ncr_offw(o))
-#define OUTL_OFF(o, val) outl_b2l ((val), np->port + (o))
-
-#elif defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
-
-#define INW_OFF(o) inw_b2l (np->port + ncr_offw(o))
-#define INL_OFF(o) inl_b2l (np->port + (o))
-
-#define OUTW_OFF(o, val) outw_l2b ((val), np->port + ncr_offw(o))
-#define OUTL_OFF(o, val) outl_l2b ((val), np->port + (o))
-
-#else
-
-#define INW_OFF(o) inw_raw (np->port + ncr_offw(o))
-#define INL_OFF(o) inl_raw (np->port + (o))
-
-#define OUTW_OFF(o, val) outw_raw ((val), np->port + ncr_offw(o))
-#define OUTL_OFF(o, val) outl_raw ((val), np->port + (o))
-
-#endif /* ENDIANs */
-
-#else /* defined NCR_IOMAPPED */
-
-/*
-** MEMORY mapped IO input / output
-*/
-
-#define INB_OFF(o) readb((char *)np->reg + ncr_offb(o))
-#define OUTB_OFF(o, val) writeb((val), (char *)np->reg + ncr_offb(o))
-
-#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
-
-#define INW_OFF(o) readw_l2b((char *)np->reg + ncr_offw(o))
-#define INL_OFF(o) readl_l2b((char *)np->reg + (o))
-
-#define OUTW_OFF(o, val) writew_b2l((val), (char *)np->reg + ncr_offw(o))
-#define OUTL_OFF(o, val) writel_b2l((val), (char *)np->reg + (o))
-
-#elif defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
-
-#define INW_OFF(o) readw_b2l((char *)np->reg + ncr_offw(o))
-#define INL_OFF(o) readl_b2l((char *)np->reg + (o))
-
-#define OUTW_OFF(o, val) writew_l2b((val), (char *)np->reg + ncr_offw(o))
-#define OUTL_OFF(o, val) writel_l2b((val), (char *)np->reg + (o))
-
-#else
-
-#define INW_OFF(o) readw_raw((char *)np->reg + ncr_offw(o))
-#define INL_OFF(o) readl_raw((char *)np->reg + (o))
-
-#define OUTW_OFF(o, val) writew_raw((val), (char *)np->reg + ncr_offw(o))
-#define OUTL_OFF(o, val) writel_raw((val), (char *)np->reg + (o))
-
-#endif
-
-#endif /* defined NCR_IOMAPPED */
-
-#define INB(r) INB_OFF (offsetof(struct ncr_reg,r))
-#define INW(r) INW_OFF (offsetof(struct ncr_reg,r))
-#define INL(r) INL_OFF (offsetof(struct ncr_reg,r))
-
-#define OUTB(r, val) OUTB_OFF (offsetof(struct ncr_reg,r), (val))
-#define OUTW(r, val) OUTW_OFF (offsetof(struct ncr_reg,r), (val))
-#define OUTL(r, val) OUTL_OFF (offsetof(struct ncr_reg,r), (val))
-
-/*
-** Set bit field ON, OFF
-*/
-
-#define OUTONB(r, m) OUTB(r, INB(r) | (m))
-#define OUTOFFB(r, m) OUTB(r, INB(r) & ~(m))
-#define OUTONW(r, m) OUTW(r, INW(r) | (m))
-#define OUTOFFW(r, m) OUTW(r, INW(r) & ~(m))
-#define OUTONL(r, m) OUTL(r, INL(r) | (m))
-#define OUTOFFL(r, m) OUTL(r, INL(r) & ~(m))
-
-
/*==========================================================
**
** Command control block states.
@@ -1765,6 +983,8 @@ struct ccb {
**----------------------------------------------------------------
*/
Scsi_Cmnd *cmd; /* SCSI command */
+ u_char cdb_buf[16]; /* Copy of CDB */
+ u_char sense_buf[64];
int data_len; /* Total data length */
/*----------------------------------------------------------------
@@ -1895,6 +1115,7 @@ struct ncb {
** General controller parameters and configuration.
**----------------------------------------------------------------
*/
+ pcidev_t pdev;
u_short device_id; /* PCI device id */
u_char revision_id; /* PCI device revision id */
u_char bus; /* PCI BUS number */
@@ -1963,6 +1184,7 @@ struct ncb {
u_char order; /* Tag order to use */
u_char verbose; /* Verbosity for this controller*/
int ncr_cache; /* Used for cache test at init. */
+ u_long p_ncb; /* BUS address of this NCB */
/*----------------------------------------------------------------
** Command completion handling.
@@ -1976,6 +1198,9 @@ struct ncb {
** Fields that should be removed or changed.
**----------------------------------------------------------------
*/
+#ifdef SCSI_NCR_PROFILE_SUPPORT
+ u_long ktime; /* Copy of kernel time */
+#endif
struct ccb *ccb; /* Global CCB */
struct usrcmd user; /* Command from user */
u_char release_stage; /* Synchronisation stage on release */
@@ -2165,7 +1390,7 @@ static void ncb_profile (ncb_p np, ccb_p cp);
static void ncr_script_copy_and_bind
(ncb_p np, ncrcmd *src, ncrcmd *dst, int len);
static void ncr_script_fill (struct script * scr, struct scripth * scripth);
-static int ncr_scatter (ccb_p cp, Scsi_Cmnd *cmd);
+static int ncr_scatter (ncb_p np, ccb_p cp, Scsi_Cmnd *cmd);
static void ncr_getsync (ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p);
static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer);
static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln);
@@ -2195,25 +1420,6 @@ static void process_waiting_list(ncb_p np, int sts);
#define requeue_waiting_list(np) process_waiting_list((np), DID_OK)
#define reset_waiting_list(np) process_waiting_list((np), DID_RESET)
-#ifdef SCSI_NCR_NVRAM_SUPPORT
-static void ncr_get_nvram (ncr_device *devp, ncr_nvram *nvp);
-static int ncr_get_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram);
-static int ncr_get_Tekram_nvram (ncr_slot *np, Tekram_nvram *nvram);
-#endif
-
-/*==========================================================
-**
-**
-** Global static data.
-**
-**
-**==========================================================
-*/
-
-#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
-static int ncr_debug = SCSI_NCR_DEBUG_FLAGS;
-#endif
-
static inline char *ncr_name (ncb_p np)
{
return np->inst_name;
@@ -2242,7 +1448,9 @@ static inline char *ncr_name (ncb_p np)
#define RELOC_SOFTC 0x40000000
#define RELOC_LABEL 0x50000000
#define RELOC_REGISTER 0x60000000
+#if 0
#define RELOC_KVAR 0x70000000
+#endif
#define RELOC_LABELH 0x80000000
#define RELOC_MASK 0xf0000000
@@ -2251,19 +1459,21 @@ static inline char *ncr_name (ncb_p np)
#define PADDRH(label) (RELOC_LABELH | offsetof(struct scripth, label))
#define RADDR(label) (RELOC_REGISTER | REG(label))
#define FADDR(label,ofs)(RELOC_REGISTER | ((REG(label))+(ofs)))
+#if 0
#define KVAR(which) (RELOC_KVAR | (which))
+#endif
+#if 0
#define SCRIPT_KVAR_JIFFIES (0)
-
#define SCRIPT_KVAR_FIRST SCRIPT_KVAR_JIFFIES
#define SCRIPT_KVAR_LAST SCRIPT_KVAR_JIFFIES
-
/*
* Kernel variables referenced in the scripts.
* THESE MUST ALL BE ALIGNED TO A 4-BYTE BOUNDARY.
*/
static void *script_kvars[] __initdata =
{ (void *)&jiffies };
+#endif
static struct script script0 __initdata = {
/*--------------------------< START >-----------------------*/ {
@@ -2434,7 +1644,7 @@ static struct script script0 __initdata = {
** ... set a timestamp ...
*/
SCR_COPY (sizeof (u_long)),
- KVAR(SCRIPT_KVAR_JIFFIES),
+ NADDR (ktime),
NADDR (header.stamp.command),
#endif
/*
@@ -2547,7 +1757,7 @@ static struct script script0 __initdata = {
** set the timestamp.
*/
SCR_COPY (sizeof (u_long)),
- KVAR(SCRIPT_KVAR_JIFFIES),
+ NADDR (ktime),
NADDR (header.stamp.status),
#endif
/*
@@ -2783,7 +1993,7 @@ static struct script script0 __initdata = {
** and count the disconnects.
*/
SCR_COPY (sizeof (u_long)),
- KVAR(SCRIPT_KVAR_JIFFIES),
+ NADDR (ktime),
NADDR (header.stamp.disconnect),
SCR_COPY (4),
NADDR (disc_phys),
@@ -2939,7 +2149,7 @@ static struct script script0 __initdata = {
** Set a time stamp for this reselection
*/
SCR_COPY (sizeof (u_long)),
- KVAR(SCRIPT_KVAR_JIFFIES),
+ NADDR (ktime),
NADDR (header.stamp.reselect),
#endif
/*
@@ -3777,7 +2987,6 @@ void __init ncr_script_fill (struct script * scr, struct scripth * scrh)
};
assert ((u_long)p == (u_long)&scr->data_out + sizeof (scr->data_out));
-flush_cache_all();
}
/*==========================================================
@@ -3833,11 +3042,15 @@ ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len)
*/
relocs = 2;
tmp1 = src[0];
+#ifdef RELOC_KVAR
if ((tmp1 & RELOC_MASK) == RELOC_KVAR)
tmp1 = 0;
+#endif
tmp2 = src[1];
+#ifdef RELOC_KVAR
if ((tmp2 & RELOC_MASK) == RELOC_KVAR)
tmp2 = 0;
+#endif
if ((tmp1 ^ tmp2) & 3) {
printk (KERN_ERR"%s: ERROR1 IN SCRIPT at %d.\n",
ncr_name(np), (int) (src-start-1));
@@ -3890,7 +3103,7 @@ ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len)
switch (old & RELOC_MASK) {
case RELOC_REGISTER:
new = (old & ~RELOC_MASK)
- + bus_dvma_to_mem(np->paddr);
+ + pcivtobus(np->paddr);
break;
case RELOC_LABEL:
new = (old & ~RELOC_MASK) + np->p_script;
@@ -3899,8 +3112,9 @@ ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len)
new = (old & ~RELOC_MASK) + np->p_scripth;
break;
case RELOC_SOFTC:
- new = (old & ~RELOC_MASK) + vtophys(np);
+ new = (old & ~RELOC_MASK) + np->p_ncb;
break;
+#ifdef RELOC_KVAR
case RELOC_KVAR:
if (((old & ~RELOC_MASK) <
SCRIPT_KVAR_FIRST) ||
@@ -3910,6 +3124,7 @@ ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len)
new = vtophys(script_kvars[old &
~RELOC_MASK]);
break;
+#endif
case 0:
/* Don't relocate a 0 address. */
if (old == 0) {
@@ -3928,7 +3143,6 @@ ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len)
*dst++ = cpu_to_scr(*src++);
};
-flush_cache_all();
}
/*==========================================================
@@ -3950,17 +3164,6 @@ flush_cache_all();
struct host_data {
struct ncb *ncb;
-
- char ncb_align[CACHE_LINE_SIZE-1]; /* Filler for alignment */
- struct ncb _ncb_data;
-
- char ccb_align[CACHE_LINE_SIZE-1]; /* Filler for alignment */
- struct ccb _ccb_data;
-
- char scr_align[CACHE_LINE_SIZE-1]; /* Filler for alignment */
- struct script script_data;
-
- struct scripth scripth_data;
};
/*
@@ -4399,88 +3602,6 @@ static int __init ncr_prepare_setting(ncb_p np, ncr_nvram *nvram)
return 0;
}
-
-#ifdef SCSI_NCR_DEBUG_NVRAM
-
-void __init ncr_display_Symbios_nvram(ncb_p np, Symbios_nvram *nvram)
-{
- int i;
-
- /* display Symbios nvram host data */
- printk(KERN_DEBUG "%s: HOST ID=%d%s%s%s%s%s\n",
- ncr_name(np), nvram->host_id & 0x0f,
- (nvram->flags & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"",
- (nvram->flags & SYMBIOS_PARITY_ENABLE) ? " PARITY" :"",
- (nvram->flags & SYMBIOS_VERBOSE_MSGS) ? " VERBOSE" :"",
- (nvram->flags & SYMBIOS_CHS_MAPPING) ? " CHS_ALT" :"",
- (nvram->flags1 & SYMBIOS_SCAN_HI_LO) ? " HI_LO" :"");
-
- /* display Symbios nvram drive data */
- for (i = 0 ; i < 15 ; i++) {
- struct Symbios_target *tn = &nvram->target[i];
- printk(KERN_DEBUG "%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n",
- ncr_name(np), i,
- (tn->flags & SYMBIOS_DISCONNECT_ENABLE) ? " DISC" : "",
- (tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME) ? " SCAN_BOOT" : "",
- (tn->flags & SYMBIOS_SCAN_LUNS) ? " SCAN_LUNS" : "",
- (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ" : "",
- tn->bus_width,
- tn->sync_period / 4,
- tn->timeout);
- }
-}
-
-static u_char Tekram_boot_delay[7] __initdata = {3, 5, 10, 20, 30, 60, 120};
-
-void __init ncr_display_Tekram_nvram(ncb_p np, Tekram_nvram *nvram)
-{
- int i, tags, boot_delay;
- char *rem;
-
- /* display Tekram nvram host data */
- tags = 2 << nvram->max_tags_index;
- boot_delay = 0;
- if (nvram->boot_delay_index < 6)
- boot_delay = Tekram_boot_delay[nvram->boot_delay_index];
- switch((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) {
- default:
- case 0: rem = ""; break;
- case 1: rem = " REMOVABLE=boot device"; break;
- case 2: rem = " REMOVABLE=all"; break;
- }
-
- printk(KERN_DEBUG
- "%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n",
- ncr_name(np), nvram->host_id & 0x0f,
- (nvram->flags1 & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"",
- (nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES" :"",
- (nvram->flags & TEKRAM_DRIVES_SUP_1GB) ? " >1GB" :"",
- (nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET" :"",
- (nvram->flags & TEKRAM_ACTIVE_NEGATION) ? " ACT_NEG" :"",
- (nvram->flags & TEKRAM_IMMEDIATE_SEEK) ? " IMM_SEEK" :"",
- (nvram->flags & TEKRAM_SCAN_LUNS) ? " SCAN_LUNS" :"",
- (nvram->flags1 & TEKRAM_F2_F6_ENABLED) ? " F2_F6" :"",
- rem, boot_delay, tags);
-
- /* display Tekram nvram drive data */
- for (i = 0; i <= 15; i++) {
- int sync, j;
- struct Tekram_target *tn = &nvram->target[i];
- j = tn->sync_index & 0xf;
- sync = Tekram_sync[j];
- printk(KERN_DEBUG "%s-%d:%s%s%s%s%s%s PERIOD=%d\n",
- ncr_name(np), i,
- (tn->flags & TEKRAM_PARITY_CHECK) ? " PARITY" : "",
- (tn->flags & TEKRAM_SYNC_NEGO) ? " SYNC" : "",
- (tn->flags & TEKRAM_DISCONNECT_ENABLE) ? " DISC" : "",
- (tn->flags & TEKRAM_START_CMD) ? " START" : "",
- (tn->flags & TEKRAM_TAGGED_COMMANDS) ? " TCQ" : "",
- (tn->flags & TEKRAM_WIDE_NEGO) ? " WIDE" : "",
- sync);
- }
-}
-#endif /* SCSI_NCR_DEBUG_NVRAM */
-
/*
** Host attach and initialisations.
**
@@ -4495,7 +3616,7 @@ static int __init
ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
{
struct host_data *host_data;
- ncb_p np;
+ ncb_p np = 0;
struct Scsi_Host *instance = 0;
u_long flags = 0;
ncr_nvram *nvram = device->nvram;
@@ -4521,21 +3642,25 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
*/
if (!(instance = scsi_register(tpnt, sizeof(*host_data))))
goto attach_error;
-
- /*
- ** Initialize structure.
- */
host_data = (struct host_data *) instance->hostdata;
- bzero (host_data, sizeof(*host_data));
/*
- ** Align np and first ccb to 32 boundary for cache line
- ** bursting when copying the global header.
+ ** Allocate the host control block.
*/
- np = (ncb_p) (((u_long) &host_data->_ncb_data) & CACHE_LINE_MASK);
+ np = __m_calloc_dma(device->pdev, sizeof(struct ncb), "NCB");
+ if (!np)
+ goto attach_error;
NCR_INIT_LOCK_NCB(np);
+ np->pdev = device->pdev;
+ np->p_ncb = vtobus(np);
host_data->ncb = np;
- np->ccb = (ccb_p) (((u_long) &host_data->_ccb_data) & CACHE_LINE_MASK);
+
+ /*
+ ** Allocate the default CCB.
+ */
+ np->ccb = (ccb_p) m_calloc_dma(sizeof(struct ccb), "CCB");
+ if (!np->ccb)
+ goto attach_error;
/*
** Store input informations in the host data structure.
@@ -4554,9 +3679,17 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
np->maxburst = device->chip.burst_max;
np->myaddr = device->host_id;
+ /*
+ ** Allocate SCRIPTS areas.
+ */
np->script0 = (struct script *)
- (((u_long) &host_data->script_data) & CACHE_LINE_MASK);
- np->scripth0 = &host_data->scripth_data;
+ m_calloc_dma(sizeof(struct script), "SCRIPT");
+ if (!np->script0)
+ goto attach_error;
+ np->scripth0 = (struct scripth *)
+ m_calloc_dma(sizeof(struct scripth), "SCRIPTH");
+ if (!np->scripth0)
+ goto attach_error;
/*
** Initialize timer structure
@@ -4592,7 +3725,7 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
** can be used safely.
*/
- np->reg = virt_to_bus((struct ncr_reg*) np->vaddr);
+ np->reg = (struct ncr_reg*) np->vaddr;
#endif /* !defined NCR_IOMAPPED */
@@ -4608,12 +3741,12 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
switch(nvram->type) {
case SCSI_NCR_SYMBIOS_NVRAM:
#ifdef SCSI_NCR_DEBUG_NVRAM
- ncr_display_Symbios_nvram(np, &nvram->data.Symbios);
+ ncr_display_Symbios_nvram(&nvram->data.Symbios);
#endif
break;
case SCSI_NCR_TEKRAM_NVRAM:
#ifdef SCSI_NCR_DEBUG_NVRAM
- ncr_display_Tekram_nvram(np, &nvram->data.Tekram);
+ ncr_display_Tekram_nvram(&nvram->data.Tekram);
#endif
break;
default:
@@ -4665,13 +3798,14 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
ncr_script_fill (&script0, &scripth0);
np->scripth = np->scripth0;
- np->p_scripth = vtophys(np->scripth);
+ np->p_scripth = vtobus(np->scripth);
- np->p_script = (np->paddr2) ? bus_dvma_to_mem(np->paddr2) : vtophys(np->script0);
+ np->p_script = (np->paddr2) ?
+ pcivtobus(np->paddr2) : vtobus(np->script0);
ncr_script_copy_and_bind (np, (ncrcmd *) &script0, (ncrcmd *) np->script0, sizeof(struct script));
ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth));
- np->ccb->p_ccb = vtophys (np->ccb);
+ np->ccb->p_ccb = vtobus (np->ccb);
/*
** Patch the script for LED support.
@@ -4807,6 +3941,8 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
attach_error:
if (!instance) return -1;
printk(KERN_INFO "%s: detaching...\n", ncr_name(np));
+ if (!np)
+ goto unregister;
#ifndef NCR_IOMAPPED
if (np->vaddr) {
#ifdef DEBUG_NCR53C8XX
@@ -4832,6 +3968,15 @@ attach_error:
#endif
free_irq(np->irq, np);
}
+ if (np->scripth0)
+ m_free_dma(np->scripth0, sizeof(struct scripth), "SCRIPTH");
+ if (np->script0)
+ m_free_dma(np->script0, sizeof(struct script), "SCRIPT");
+ if (np->ccb)
+ m_free_dma(np->ccb, sizeof(struct ccb), "CCB");
+ m_free_dma(np, sizeof(struct ncb), "NCB");
+
+unregister:
scsi_unregister(instance);
return -1;
@@ -4859,6 +4004,7 @@ attach_error:
*/
static inline void ncr_queue_done_cmd(ncb_p np, Scsi_Cmnd *cmd)
{
+ unmap_scsi_data(np, cmd);
cmd->host_scribble = (char *) np->done_list;
np->done_list = cmd;
}
@@ -5114,7 +4260,7 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
**----------------------------------------------------
*/
- segments = ncr_scatter (cp, cp->cmd);
+ segments = ncr_scatter (np, cp, cp->cmd);
if (segments < 0) {
ncr_free_ccb(np, cp);
@@ -5123,47 +4269,24 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
/*----------------------------------------------------
**
- ** Guess xfer direction.
- ** Spare some CPU by testing here frequently opcode.
+ ** Determine xfer direction.
**
**----------------------------------------------------
*/
if (!cp->data_len)
- direction = 0;
- else {
- switch((int) cmd->cmnd[0]) {
- case 0x08: /* READ(6) 08 */
- case 0x28: /* READ(10) 28 */
- case 0xA8: /* READ(12) A8 */
- direction = XFER_IN;
- break;
- case 0x0A: /* WRITE(6) 0A */
- case 0x2A: /* WRITE(10) 2A */
- case 0xAA: /* WRITE(12) AA */
- direction = XFER_OUT;
- break;
- default:
- direction = (XFER_IN|XFER_OUT);
- break;
- }
- }
-
- /*----------------------------------------------------
- **
- ** Set the SAVED_POINTER.
- **
- **----------------------------------------------------
- */
-
- /*
- ** Default to no data transfer.
- */
- lastp = goalp = NCB_SCRIPT_PHYS (np, no_data);
+ direction = SCSI_DATA_NONE;
+ else
+ direction = scsi_data_direction(cmd);
/*
- ** Compute data out pointers, if needed.
+ ** If data direction is UNKNOWN, speculate DATA_READ
+ ** but prepare alternate pointers for WRITE in case
+ ** of our speculation will be just wrong.
+ ** SCRIPTS will swap values if needed.
*/
- if (direction & XFER_OUT) {
+ switch(direction) {
+ case SCSI_DATA_UNKNOWN:
+ case SCSI_DATA_WRITE:
goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8;
if (segments <= MAX_SCATTERL)
lastp = goalp - 8 - (segments * 16);
@@ -5171,21 +4294,12 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
lastp = NCB_SCRIPTH_PHYS (np, hdata_out2);
lastp -= (segments - MAX_SCATTERL) * 16;
}
- /*
- ** If actual data direction is unknown, save pointers
- ** in header. The SCRIPTS will swap them to current
- ** if target decision will be data out.
- */
- if (direction & XFER_IN) {
- cp->phys.header.wgoalp = cpu_to_scr(goalp);
- cp->phys.header.wlastp = cpu_to_scr(lastp);
- }
- }
-
- /*
- ** Compute data in pointers, if needed.
- */
- if (direction & XFER_IN) {
+ if (direction != SCSI_DATA_UNKNOWN)
+ break;
+ cp->phys.header.wgoalp = cpu_to_scr(goalp);
+ cp->phys.header.wlastp = cpu_to_scr(lastp);
+ /* fall through */
+ case SCSI_DATA_READ:
goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8;
if (segments <= MAX_SCATTERL)
lastp = goalp - 8 - (segments * 16);
@@ -5193,6 +4307,11 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
lastp = NCB_SCRIPTH_PHYS (np, hdata_in2);
lastp -= (segments - MAX_SCATTERL) * 16;
}
+ break;
+ default:
+ case SCSI_DATA_NONE:
+ lastp = goalp = NCB_SCRIPT_PHYS (np, no_data);
+ break;
}
/*
@@ -5202,7 +4321,7 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
cp->phys.header.lastp = cpu_to_scr(lastp);
cp->phys.header.goalp = cpu_to_scr(goalp);
- if ((direction & (XFER_IN|XFER_OUT)) == (XFER_IN|XFER_OUT))
+ if (direction == SCSI_DATA_UNKNOWN)
cp->phys.header.savep =
cpu_to_scr(NCB_SCRIPTH_PHYS (np, data_io));
else
@@ -5241,14 +4360,13 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
*/
cp->phys.smsg.addr = cpu_to_scr(CCB_PHYS (cp, scsi_smsg));
cp->phys.smsg.size = cpu_to_scr(msglen);
-flush_cache_all();
/*
** command
*/
- cp->phys.cmd.addr = cpu_to_scr(vtophys (&cmd->cmnd[0]));
+ memcpy(cp->cdb_buf, cmd->cmnd, MIN(cmd->cmd_len, sizeof(cp->cdb_buf)));
+ cp->phys.cmd.addr = cpu_to_scr(CCB_PHYS (cp, cdb_buf[0]));
cp->phys.cmd.size = cpu_to_scr(cmd->cmd_len);
- dma_cache_wback_inv((unsigned long)cmd->cmnd, cmd->cmd_len);
/*
** status
@@ -5276,9 +4394,6 @@ flush_cache_all();
** activate this job.
*/
cp->magic = CCB_MAGIC;
-//printk("cp == %08lx\n", cp);
- dma_cache_wback_inv((unsigned long)cp, sizeof(*cp));
-flush_cache_all();
/*
** insert next CCBs into start queue.
@@ -5350,7 +4465,6 @@ static void ncr_put_start_queue(ncb_p np, ccb_p cp)
if (DEBUG_FLAGS & DEBUG_QUEUE)
printk ("%s: queuepos=%d.\n", ncr_name (np), np->squeueput);
- dma_cache_wback_inv((unsigned long)np, sizeof(*np));
/*
** Script processor may be waiting for reselect.
@@ -5699,7 +4813,7 @@ static int ncr_detach(ncb_p np)
#ifdef DEBUG_NCR53C8XX
printk("%s: freeing ccb (%lx)\n", ncr_name(np), (u_long) cp);
#endif
- m_free(cp, sizeof(*cp));
+ m_free_dma(cp, sizeof(*cp), "CCB");
}
/*
@@ -5715,12 +4829,20 @@ static int ncr_detach(ncb_p np)
printk("%s: freeing lp (%lx)\n", ncr_name(np), (u_long) lp);
#endif
if (lp->jump_ccb != &lp->jump_ccb_0)
- m_free(lp->jump_ccb, 256);
- m_free(lp, sizeof(*lp));
+ m_free_dma(lp->jump_ccb,256,"JUMP_CCB");
+ m_free_dma(lp, sizeof(*lp), "LCB");
}
}
}
+ if (np->scripth0)
+ m_free_dma(np->scripth0, sizeof(struct scripth), "SCRIPTH");
+ if (np->script0)
+ m_free_dma(np->script0, sizeof(struct script), "SCRIPT");
+ if (np->ccb)
+ m_free_dma(np->ccb, sizeof(struct ccb), "CCB");
+ m_free_dma(np, sizeof(struct ncb), "NCB");
+
printk("%s: host resources successfully released\n", ncr_name(np));
return 1;
@@ -5874,6 +4996,7 @@ void ncr_complete (ncb_p np, ccb_p cp)
*/
if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) &&
cmd->cmnd[4] >= 7 && !cmd->use_sg) {
+ sync_scsi_data(np, cmd); /* SYNC the data */
ncr_setup_lcb (np, cmd->target, cmd->lun,
(char *) cmd->request_buffer);
}
@@ -5900,6 +5023,12 @@ void ncr_complete (ncb_p np, ccb_p cp)
*/
cmd->result = ScsiResult(DID_OK, S_CHECK_COND);
+ /*
+ ** Copy back sense data to caller's buffer.
+ */
+ memcpy(cmd->sense_buffer, cp->sense_buf,
+ MIN(sizeof(cmd->sense_buffer), sizeof(cp->sense_buf)));
+
if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
u_char * p = (u_char*) & cmd->sense_buffer;
int i;
@@ -6263,11 +5392,9 @@ void ncr_init (ncb_p np, int reset, char * msg, u_long code)
if (tp->usrwide > np->maxwide)
tp->usrwide = np->maxwide;
- dma_cache_wback_inv((unsigned long) tp, sizeof(*tp));
ncr_negotiate (np, tp);
}
- dma_cache_wback_inv((unsigned long) np, sizeof(*np));
/*
** Start script processor.
@@ -6277,7 +5404,7 @@ void ncr_init (ncb_p np, int reset, char * msg, u_long code)
if (bootverbose)
printk ("%s: Downloading SCSI SCRIPTS.\n",
ncr_name(np));
- OUTL (nc_scratcha, vtophys(np->script0));
+ OUTL (nc_scratcha, vtobus(np->script0));
OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, start_ram));
}
else
@@ -6661,7 +5788,6 @@ static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln)
lp->jump_tag.l_paddr = lp->usetags?
cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_tag)) :
cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_notag));
-flush_cache_all();
/*
** Announce change to user.
@@ -6792,7 +5918,12 @@ static void ncr_timeout (ncb_p np)
return;
}
+#ifdef SCSI_NCR_PROFILE_SUPPORT
+ np->ktime = thistime;
+ np->timer.expires = ktime_get(1);
+#else
np->timer.expires = ktime_get(SCSI_NCR_TIMER_INTERVAL);
+#endif
add_timer(&np->timer);
/*
@@ -6959,7 +6090,6 @@ void ncr_exception (ncb_p np)
u_char istat, dstat;
u_short sist;
int i;
-flush_cache_all();
/*
** interrupt on the fly ?
@@ -7117,7 +6247,6 @@ flush_cache_all();
if (sist & UDC) {
printk ("%s: unexpected disconnect\n", ncr_name(np));
OUTB (HS_PRT, HS_UNEXPECTED);
-//flush_cache_all(); // ???
OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
return;
};
@@ -7170,7 +6299,6 @@ void ncr_int_sto (ncb_p np)
** repair start queue and jump to start point.
*/
-flush_cache_all();
OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sto_restart));
return;
}
@@ -7310,6 +6438,7 @@ static void ncr_int_ma (ncb_p np)
u_int32 dsp;
u_int32 dsa;
u_int32 nxtdsp;
+ u_int32 newtmp;
u_int32 *vdsp;
u_int32 oadr, olen;
u_int32 *tblp;
@@ -7404,11 +6533,11 @@ static void ncr_int_ma (ncb_p np)
nxtdsp = dsp;
}
else if (cp) {
- if (dsp == vtophys (&cp->patch[2])) {
+ if (dsp == CCB_PHYS (cp, patch[2])) {
vdsp = &cp->patch[0];
nxtdsp = scr_to_cpu(vdsp[3]);
}
- else if (dsp == vtophys (&cp->patch[6])) {
+ else if (dsp == CCB_PHYS (cp, patch[6])) {
vdsp = &cp->patch[4];
nxtdsp = scr_to_cpu(vdsp[3]);
}
@@ -7503,7 +6632,11 @@ static void ncr_int_ma (ncb_p np)
*/
newcmd = cp->patch;
- if (cp->phys.header.savep == cpu_to_scr(vtophys (newcmd))) newcmd+=4;
+ newtmp = CCB_PHYS (cp, patch);
+ if (newtmp == scr_to_cpu(cp->phys.header.savep)) {
+ newcmd = &cp->patch[4];
+ newtmp = CCB_PHYS (cp, patch[4]);
+ }
/*
** fillin the commands
@@ -7530,7 +6663,7 @@ static void ncr_int_ma (ncb_p np)
#ifdef SCSI_NCR_PROFILE_SUPPORT
np->profile.num_break++;
#endif
- OUTL (nc_temp, vtophys (newcmd));
+ OUTL (nc_temp, newtmp);
OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
return;
@@ -7699,19 +6832,14 @@ static void ncr_sir_to_redo(ncb_p np, int num, ccb_p cp)
*/
cp->sensecmd[0] = 0x03;
cp->sensecmd[1] = cmd->lun << 5;
- cp->sensecmd[4] = sizeof(cmd->sense_buffer);
- dma_cache_wback_inv((unsigned long)cmd->sense_buffer,
- sizeof(cmd->sense_buffer));
+ cp->sensecmd[4] = sizeof(cp->sense_buf);
/*
** sense data
*/
- cp->phys.sense.addr =
- cpu_to_scr(vtophys (&cmd->sense_buffer[0]));
- cp->phys.sense.size =
- cpu_to_scr(sizeof(cmd->sense_buffer));
- dma_cache_wback_inv((unsigned long)cmd->sense_buffer,
- sizeof(cmd->sense_buffer));
+ bzero(cp->sense_buf, sizeof(cp->sense_buf));
+ cp->phys.sense.addr = cpu_to_scr(CCB_PHYS(cp,sense_buf[0]));
+ cp->phys.sense.size = cpu_to_scr(sizeof(cp->sense_buf));
/*
** requeue the command.
@@ -7745,8 +6873,6 @@ static void ncr_sir_to_redo(ncb_p np, int num, ccb_p cp)
}
out:
-flush_cache_all(); // ???
-//dma_cache_wback_inv((unsigned long)cmd->cmnd, cmd->cmd_len);
OUTONB (nc_dcntl, (STD|NOCOM));
return;
}
@@ -7837,7 +6963,6 @@ void ncr_int_sir (ncb_p np)
}
switch (num) {
-flush_cache_all(); // ???
/*-----------------------------------------------------------------------------
**
** Was Sie schon immer ueber transfermode negotiation wissen wollten ...
@@ -7943,7 +7068,6 @@ flush_cache_all(); // ???
np->msgin [0] = M_NOOP;
np->msgout[0] = M_NOOP;
cp->nego_status = 0;
-flush_cache_all();
break;
case SIR_NEGO_SYNC:
@@ -8024,14 +7148,12 @@ flush_cache_all();
** Answer wasn't acceptable.
*/
ncr_setsync (np, cp, 0, 0xe0);
-flush_cache_all();
OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
} else {
/*
** Answer is ok.
*/
ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
-flush_cache_all();
OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
};
return;
@@ -8065,7 +7187,6 @@ flush_cache_all();
}
if (!ofs) {
-flush_cache_all();
OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
return;
}
@@ -8124,14 +7245,12 @@ flush_cache_all();
** Answer wasn't acceptable.
*/
ncr_setwide (np, cp, 0, 1);
-flush_cache_all();
OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
} else {
/*
** Answer is ok.
*/
ncr_setwide (np, cp, wide, 1);
-flush_cache_all();
OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
};
return;
@@ -8429,7 +7548,7 @@ static void ncr_free_ccb (ncb_p np, ccb_p cp)
#define ncr_reg_bus_addr(r) \
- (bus_dvma_to_mem(np->paddr) + offsetof (struct ncr_reg, r))
+ (pcivtobus(np->paddr) + offsetof (struct ncr_reg, r))
/*------------------------------------------------------------------------
** Initialize the fixed part of a CCB structure.
@@ -8443,7 +7562,7 @@ static void ncr_init_ccb(ncb_p np, ccb_p cp)
/*
** Remember virtual and bus address of this ccb.
*/
- cp->p_ccb = vtophys(cp);
+ cp->p_ccb = vtobus(cp);
cp->phys.header.cp = cp;
/*
@@ -8458,10 +7577,10 @@ static void ncr_init_ccb(ncb_p np, ccb_p cp)
** JUMP @(sched_point)
*/
cp->start.setup_dsa[0] = cpu_to_scr(copy_4);
- cp->start.setup_dsa[1] = cpu_to_scr(vtophys(&cp->start.p_phys));
+ cp->start.setup_dsa[1] = cpu_to_scr(CCB_PHYS(cp, start.p_phys));
cp->start.setup_dsa[2] = cpu_to_scr(ncr_reg_bus_addr(nc_dsa));
cp->start.schedule.l_cmd = cpu_to_scr(SCR_JUMP);
- cp->start.p_phys = cpu_to_scr(vtophys(&cp->phys));
+ cp->start.p_phys = cpu_to_scr(CCB_PHYS(cp, phys));
bcopy(&cp->start, &cp->restart, sizeof(cp->restart));
@@ -8484,15 +7603,10 @@ static void ncr_alloc_ccb(ncb_p np, u_char tn, u_char ln)
/*
** Allocate memory for this CCB.
*/
- cp = m_alloc(sizeof(struct ccb), 5);
+ cp = m_calloc_dma(sizeof(struct ccb), "CCB");
if (!cp)
return;
- if (DEBUG_FLAGS & DEBUG_ALLOC) {
- PRINT_LUN(np, tn, ln);
- printk ("new ccb @%p.\n", cp);
- }
-
/*
** Count it and initialyze it.
*/
@@ -8510,7 +7624,6 @@ static void ncr_alloc_ccb(ncb_p np, u_char tn, u_char ln)
xpt_insque_head(&cp->link_ccbq, &lp->free_ccbq);
ncr_setup_tags (np, tn, ln);
-flush_cache_all();
}
/*==========================================================
@@ -8551,7 +7664,7 @@ static void ncr_init_tcb (ncb_p np, u_char tn)
** COPY @(tp->sval), @(sxfer)
*/
tp->getscr[0] = cpu_to_scr(copy_1);
- tp->getscr[1] = cpu_to_scr(vtophys (&tp->sval));
+ tp->getscr[1] = cpu_to_scr(vtobus (&tp->sval));
tp->getscr[2] = cpu_to_scr(ncr_reg_bus_addr(nc_sxfer));
/*
@@ -8559,7 +7672,7 @@ static void ncr_init_tcb (ncb_p np, u_char tn)
** COPY @(tp->wval), @(scntl3)
*/
tp->getscr[3] = cpu_to_scr(copy_1);
- tp->getscr[4] = cpu_to_scr(vtophys (&tp->wval));
+ tp->getscr[4] = cpu_to_scr(vtobus (&tp->wval));
tp->getscr[5] = cpu_to_scr(ncr_reg_bus_addr(nc_scntl3));
/*
@@ -8584,7 +7697,7 @@ static void ncr_init_tcb (ncb_p np, u_char tn)
/*
** Link this target control block to the JUMP chain.
*/
- np->jump_tcb[th].l_paddr = cpu_to_scr(vtophys (&tp->jump_tcb));
+ np->jump_tcb[th].l_paddr = cpu_to_scr(vtobus (&tp->jump_tcb));
/*
** These assert's should be moved at driver initialisations.
@@ -8619,17 +7732,12 @@ static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln)
/*
** Allocate the lcb.
*/
- lp = m_alloc(sizeof(struct lcb), 3);
+ lp = m_calloc_dma(sizeof(struct lcb), "LCB");
if (!lp)
goto fail;
bzero(lp, sizeof(*lp));
tp->lp[ln] = lp;
- if (DEBUG_FLAGS & DEBUG_ALLOC) {
- PRINT_LUN(np, tn, ln);
- printk ("new lcb @%p.\n", lp);
- }
-
/*
** Initialize the target control block if not yet.
*/
@@ -8650,7 +7758,7 @@ static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln)
*/
lp->maxnxs = 1;
lp->jump_ccb = &lp->jump_ccb_0;
- lp->p_jump_ccb = cpu_to_scr(vtophys(lp->jump_ccb));
+ lp->p_jump_ccb = cpu_to_scr(vtobus(lp->jump_ccb));
/*
** Initilialyze the reselect script:
@@ -8668,7 +7776,7 @@ static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln)
lp->jump_lcb.l_paddr = tp->jump_lcb[lh].l_paddr;
lp->load_jump_ccb[0] = cpu_to_scr(copy_4);
- lp->load_jump_ccb[1] = cpu_to_scr(vtophys (&lp->p_jump_ccb));
+ lp->load_jump_ccb[1] = cpu_to_scr(vtobus (&lp->p_jump_ccb));
lp->load_jump_ccb[2] = cpu_to_scr(ncr_reg_bus_addr(nc_temp));
lp->jump_tag.l_cmd = cpu_to_scr(SCR_JUMP);
@@ -8677,7 +7785,7 @@ static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln)
/*
** Link this lun control block to the JUMP chain.
*/
- tp->jump_lcb[lh].l_paddr = cpu_to_scr(vtophys (&lp->jump_lcb));
+ tp->jump_lcb[lh].l_paddr = cpu_to_scr(vtobus (&lp->jump_lcb));
/*
** Initialize command queuing control.
@@ -8761,12 +7869,12 @@ static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, u_char *inq_data)
*/
if ((inq_byte7 & INQ7_QUEUE) && lp->jump_ccb == &lp->jump_ccb_0) {
int i;
- lp->jump_ccb = m_alloc(256, 8);
+ lp->jump_ccb = m_calloc_dma(256, "JUMP_CCB");
if (!lp->jump_ccb) {
lp->jump_ccb = &lp->jump_ccb_0;
goto fail;
}
- lp->p_jump_ccb = cpu_to_scr(vtophys(lp->jump_ccb));
+ lp->p_jump_ccb = cpu_to_scr(vtobus(lp->jump_ccb));
for (i = 0 ; i < 64 ; i++)
lp->jump_ccb[i] =
cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l_q));
@@ -8818,7 +7926,7 @@ fail:
** sizes to the data segment array.
*/
-static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd)
+static int ncr_scatter(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd)
{
struct scr_tblmove *data;
int segment = 0;
@@ -8829,32 +7937,28 @@ static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd)
if (!use_sg) {
if (cmd->request_bufflen) {
- unsigned long addr, len;
+ u_long baddr = map_scsi_single_data(np, cmd);
- addr = cmd->request_buffer;
- len = cmd->request_bufflen;
data = &data[MAX_SCATTER - 1];
- data[0].addr = cpu_to_scr(vtophys(addr));
- data[0].size = cpu_to_scr(len);
- if (addr)
- dma_cache_wback_inv(addr, len);
- cp->data_len = len;
+ data[0].addr = cpu_to_scr(baddr);
+ data[0].size = cpu_to_scr(cmd->request_bufflen);
+ cp->data_len = cmd->request_bufflen;
segment = 1;
}
}
else if (use_sg <= MAX_SCATTER) {
struct scatterlist *scatter = (struct scatterlist *)cmd->buffer;
+ use_sg = map_scsi_sg_data(np, cmd);
data = &data[MAX_SCATTER - use_sg];
+
while (segment < use_sg) {
- unsigned long addr, len;
+ u_long baddr = scsi_sg_dma_address(&scatter[segment]);
+ unsigned int len = scsi_sg_dma_len(&scatter[segment]);
- addr = scatter[segment].address;
- len = scatter[segment].length;
- data[segment].addr = cpu_to_scr(vtophys(addr));
+ data[segment].addr = cpu_to_scr(baddr);
data[segment].size = cpu_to_scr(len);
- dma_cache_wback_inv(addr, len);
- cp->data_len += len;
+ cp->data_len += len;
++segment;
}
}
@@ -8862,7 +7966,6 @@ static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd)
return -1;
}
- dma_cache_wback_inv(data, sizeof(*data) * segment);
return segment;
}
@@ -8922,7 +8025,6 @@ static int __init ncr_snooptest (struct ncb* np)
** Set memory and register.
*/
np->ncr_cache = cpu_to_scr(host_wr);
- dma_cache_wback_inv((unsigned long)np, sizeof(*np));
OUTL (nc_temp, ncr_wr);
/*
** Start script (exchange values)
@@ -9277,833 +8379,10 @@ static void __init ncr_getclock (ncb_p np, int mult)
/*===================== LINUX ENTRY POINTS SECTION ==========================*/
-#ifndef uchar
-#define uchar unsigned char
-#endif
-
-#ifndef ushort
-#define ushort unsigned short
-#endif
-
-#ifndef ulong
-#define ulong unsigned long
-#endif
-
-/* ---------------------------------------------------------------------
-**
-** Driver setup from the boot command line
-**
-** ---------------------------------------------------------------------
-*/
-
-#ifdef MODULE
-#define ARG_SEP ' '
-#else
-#define ARG_SEP ','
-#endif
-
-int __init ncr53c8xx_setup(char *str)
-{
-#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
- char *cur = str;
- char *pc, *pv;
- int val;
- int base;
- int c;
- int xi = 0;
-
- while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
- char *pe;
-
- val = 0;
- pv = pc;
- c = *++pv;
-
- if (c == 'n')
- val = 0;
- else if (c == 'y')
- val = 1;
- else {
- base = 0;
- val = (int) simple_strtoul(pv, &pe, base);
- }
- if (!strncmp(cur, "tags:", 5)) {
- int i;
- driver_setup.default_tags = val;
- if (pe && *pe == '/') {
- i = 0;
- while (*pe && *pe != ARG_SEP &&
- i < sizeof(driver_setup.tag_ctrl)-1) {
- driver_setup.tag_ctrl[i++] = *pe++;
- }
- driver_setup.tag_ctrl[i] = '\0';
- }
- }
- else if (!strncmp(cur, "mpar:", 5))
- driver_setup.master_parity = val;
- else if (!strncmp(cur, "spar:", 5))
- driver_setup.scsi_parity = val;
- else if (!strncmp(cur, "disc:", 5))
- driver_setup.disconnection = val;
- else if (!strncmp(cur, "specf:", 6))
- driver_setup.special_features = val;
- else if (!strncmp(cur, "ultra:", 6))
- driver_setup.ultra_scsi = val;
- else if (!strncmp(cur, "fsn:", 4))
- driver_setup.force_sync_nego = val;
- else if (!strncmp(cur, "revprob:", 8))
- driver_setup.reverse_probe = val;
- else if (!strncmp(cur, "sync:", 5))
- driver_setup.default_sync = val;
- else if (!strncmp(cur, "verb:", 5))
- driver_setup.verbose = val;
- else if (!strncmp(cur, "debug:", 6))
- driver_setup.debug = val;
- else if (!strncmp(cur, "burst:", 6))
- driver_setup.burst_max = val;
- else if (!strncmp(cur, "led:", 4))
- driver_setup.led_pin = val;
- else if (!strncmp(cur, "wide:", 5))
- driver_setup.max_wide = val? 1:0;
- else if (!strncmp(cur, "settle:", 7))
- driver_setup.settle_delay= val;
- else if (!strncmp(cur, "diff:", 5))
- driver_setup.diff_support= val;
- else if (!strncmp(cur, "irqm:", 5))
- driver_setup.irqm = val;
- else if (!strncmp(cur, "pcifix:", 7))
- driver_setup.pci_fix_up = val;
- else if (!strncmp(cur, "buschk:", 7))
- driver_setup.bus_check = val;
-#ifdef SCSI_NCR_NVRAM_SUPPORT
- else if (!strncmp(cur, "nvram:", 6))
- driver_setup.use_nvram = val;
-#endif
-
- else if (!strncmp(cur, "safe:", 5) && val)
- memcpy(&driver_setup, &driver_safe_setup, sizeof(driver_setup));
- else if (!strncmp(cur, "excl:", 5)) {
- if (xi < SCSI_NCR_MAX_EXCLUDES)
- driver_setup.excludes[xi++] = val;
- }
- else if (!strncmp(cur, "hostid:", 7))
- driver_setup.host_id = val;
- else
- printk("ncr53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
-
- if ((cur = strchr(cur, ARG_SEP)) != NULL)
- ++cur;
- }
-#endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
- return 0;
-}
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
-#ifndef MODULE
-__setup("ncr53c8xx=", ncr53c8xx_setup);
-#endif
-#endif
-
-static int
-ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, ncr_device *device);
-
-/*
-** Linux entry point for NCR53C8XX devices detection routine.
-**
-** Called by the middle-level scsi drivers at initialization time,
-** or at module installation.
-**
-** Read the PCI configuration and try to attach each
-** detected NCR board.
-**
-** If NVRAM is present, try to attach boards according to
-** the used defined boot order.
-**
-** Returns the number of boards successfully attached.
-*/
-
-static void __init ncr_print_driver_setup(void)
-{
-#define YesNo(y) y ? 'y' : 'n'
- printk ("ncr53c8xx: setup=disc:%c,specf:%d,ultra:%d,tags:%d,sync:%d,"
- "burst:%d,wide:%c,diff:%d,revprob:%c,buschk:0x%x\n",
- YesNo(driver_setup.disconnection),
- driver_setup.special_features,
- driver_setup.ultra_scsi,
- driver_setup.default_tags,
- driver_setup.default_sync,
- driver_setup.burst_max,
- YesNo(driver_setup.max_wide),
- driver_setup.diff_support,
- YesNo(driver_setup.reverse_probe),
- driver_setup.bus_check);
-
- printk ("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,"
- "led:%c,settle:%d,irqm:%d,nvram:0x%x,pcifix:0x%x\n",
- YesNo(driver_setup.master_parity),
- YesNo(driver_setup.scsi_parity),
- YesNo(driver_setup.force_sync_nego),
- driver_setup.verbose,
- driver_setup.debug,
- YesNo(driver_setup.led_pin),
- driver_setup.settle_delay,
- driver_setup.irqm,
- driver_setup.use_nvram,
- driver_setup.pci_fix_up);
-#undef YesNo
-}
-
-/*
-** NCR53C8XX devices description table and chip ids list.
-*/
-
-static ncr_chip ncr_chip_table[] __initdata = SCSI_NCR_CHIP_TABLE;
-static ushort ncr_chip_ids[] __initdata = SCSI_NCR_CHIP_IDS;
-
-
-/*===================================================================
-** Detect all 53c8xx hosts and then attach them.
-**
-** If we are using NVRAM, once all hosts are detected, we need to
-** check any NVRAM for boot order in case detect and boot order
-** differ and attach them using the order in the NVRAM.
-**
-** If no NVRAM is found or data appears invalid attach boards in
-** the the order they are detected.
-**===================================================================
-*/
-int __init ncr53c8xx_detect(Scsi_Host_Template *tpnt)
-{
- pcidev_t pcidev;
- int i, j, chips, hosts, count;
- int attach_count = 0;
- ncr_device *devtbl, *devp;
-#ifdef SCSI_NCR_NVRAM_SUPPORT
- ncr_nvram nvram0, nvram, *nvp;
-#endif
-
- /*
- ** PCI is required.
- */
- if (!pci_present())
- return 0;
-
- /*
- ** Initialize driver general stuff.
- */
-#ifdef SCSI_NCR_PROC_INFO_SUPPORT
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
- tpnt->proc_dir = &proc_scsi_ncr53c8xx;
-#else
- tpnt->proc_name = "ncr53c8xx";
-#endif
- tpnt->proc_info = ncr53c8xx_proc_info;
-#endif
-
-#if defined(SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT) && defined(MODULE)
-if (ncr53c8xx)
- ncr53c8xx_setup(ncr53c8xx);
-#endif
-#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
- ncr_debug = driver_setup.debug;
-#endif
-
- if (initverbose >= 2)
- ncr_print_driver_setup();
-
- /*
- ** Allocate the device table since we donnot want to
- ** overflow the kernel stack.
- ** 1 x 4K PAGE is enough for more than 40 devices for i386.
- */
- devtbl = kmalloc(4000, GFP_ATOMIC);
- if (!devtbl)
- return 0;
-
- /*
- ** Detect all 53c8xx hosts.
- ** Save the first Symbios NVRAM content if any
- ** for the boot order.
- */
- chips = sizeof(ncr_chip_ids) / sizeof(ncr_chip_ids[0]);
- hosts = 4000 / sizeof(*devtbl);
-#ifdef SCSI_NCR_NVRAM_SUPPORT
- nvp = (driver_setup.use_nvram & 0x1) ? &nvram0 : 0;
-#endif
- j = 0;
- count = 0;
- pcidev = PCIDEV_NULL;
- while (1) {
- char *msg = "";
- if (count >= hosts)
- break;
- if (j >= chips)
- break;
- i = driver_setup.reverse_probe ? chips - 1 - j : j;
- pcidev = pci_find_device(PCI_VENDOR_ID_NCR, ncr_chip_ids[i],
- pcidev);
- if (pcidev == PCIDEV_NULL) {
- ++j;
- continue;
- }
- /* Some HW as the HP LH4 may report twice PCI devices */
- for (i = 0; i < count ; i++) {
- if (devtbl[i].slot.bus == PciBusNumber(pcidev) &&
- devtbl[i].slot.device_fn == PciDeviceFn(pcidev))
- break;
- }
- if (i != count) /* Ignore this device if we already have it */
- continue;
- devp = &devtbl[count];
- devp->host_id = driver_setup.host_id;
- devp->attach_done = 0;
- if (ncr53c8xx_pci_init(tpnt, pcidev, devp)) {
- continue;
- }
- ++count;
-#ifdef SCSI_NCR_NVRAM_SUPPORT
- if (nvp) {
- ncr_get_nvram(devp, nvp);
- switch(nvp->type) {
- case SCSI_NCR_SYMBIOS_NVRAM:
- /*
- * Switch to the other nvram buffer, so that
- * nvram0 will contain the first Symbios
- * format NVRAM content with boot order.
- */
- nvp = &nvram;
- msg = "with Symbios NVRAM";
- break;
- case SCSI_NCR_TEKRAM_NVRAM:
- msg = "with Tekram NVRAM";
- break;
- }
- }
-#endif
- printk(KERN_INFO "ncr53c8xx: 53c%s detected %s\n",
- devp->chip.name, msg);
- }
-
- /*
- ** If we have found a SYMBIOS NVRAM, use first the NVRAM boot
- ** sequence as device boot order.
- ** check devices in the boot record against devices detected.
- ** attach devices if we find a match. boot table records that
- ** do not match any detected devices will be ignored.
- ** devices that do not match any boot table will not be attached
- ** here but will attempt to be attached during the device table
- ** rescan.
- */
-#ifdef SCSI_NCR_NVRAM_SUPPORT
- if (!nvp || nvram0.type != SCSI_NCR_SYMBIOS_NVRAM)
- goto next;
- for (i = 0; i < 4; i++) {
- Symbios_host *h = &nvram0.data.Symbios.host[i];
- for (j = 0 ; j < count ; j++) {
- devp = &devtbl[j];
- if (h->device_fn != devp->slot.device_fn ||
- h->bus_nr != devp->slot.bus ||
- h->device_id != devp->chip.device_id)
- continue;
- if (devp->attach_done)
- continue;
- ncr_get_nvram(devp, nvp);
- if (!ncr_attach (tpnt, attach_count, devp))
- attach_count++;
- devp->attach_done = 1;
- break;
- }
- }
-next:
-#endif
-
- /*
- ** Rescan device list to make sure all boards attached.
- ** Devices without boot records will not be attached yet
- ** so try to attach them here.
- */
- for (i= 0; i < count; i++) {
- devp = &devtbl[i];
- if (!devp->attach_done) {
-#ifdef SCSI_NCR_NVRAM_SUPPORT
- ncr_get_nvram(devp, nvp);
-#endif
- if (!ncr_attach (tpnt, attach_count, devp))
- attach_count++;
- }
- }
-
- kfree(devtbl);
-
- return attach_count;
-}
-
-/*===================================================================
-** Detect and try to read SYMBIOS and TEKRAM NVRAM.
-**
-** Data can be used to order booting of boards.
-**
-** Data is saved in ncr_device structure if NVRAM found. This
-** is then used to find drive boot order for ncr_attach().
-**
-** NVRAM data is passed to Scsi_Host_Template later during
-** ncr_attach() for any device set up.
-*===================================================================
-*/
-#ifdef SCSI_NCR_NVRAM_SUPPORT
-static void __init ncr_get_nvram(ncr_device *devp, ncr_nvram *nvp)
-{
- devp->nvram = nvp;
- if (!nvp)
- return;
- /*
- ** Get access to chip IO registers
- */
-#ifdef NCR_IOMAPPED
- request_region(devp->slot.io_port, 128, "ncr53c8xx");
- devp->slot.port = devp->slot.io_port;
-#else
- devp->slot.reg = (struct ncr_reg *) remap_pci_mem(devp->slot.base, 128);
- if (!devp->slot.reg)
- return;
-#endif
-
- /*
- ** Try to read SYMBIOS nvram.
- ** Try to read TEKRAM nvram if Symbios nvram not found.
- */
- if (!ncr_get_Symbios_nvram(&devp->slot, &nvp->data.Symbios))
- nvp->type = SCSI_NCR_SYMBIOS_NVRAM;
- else if (!ncr_get_Tekram_nvram(&devp->slot, &nvp->data.Tekram))
- nvp->type = SCSI_NCR_TEKRAM_NVRAM;
- else {
- nvp->type = 0;
- devp->nvram = 0;
- }
-
- /*
- ** Release access to chip IO registers
- */
-#ifdef NCR_IOMAPPED
- release_region(devp->slot.port, 128);
-#else
- unmap_pci_mem((u_long) devp->slot.reg, 128ul);
-#endif
-
-}
-#endif /* SCSI_NCR_NVRAM_SUPPORT */
-
-/*
-** Read and check the PCI configuration for any detected NCR
-** boards and save data for attaching after all boards have
-** been detected.
-*/
-
-static int __init
-ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, ncr_device *device)
-{
- ushort vendor_id, device_id, command;
- uchar cache_line_size, latency_timer;
- uchar revision;
- uint irq;
- ulong base, base_2, io_port;
- int i;
- ncr_chip *chip;
-
- /*
- ** Read info from the PCI config space.
- ** pci_read_config_xxx() functions are assumed to be used for
- ** successfully detected PCI devices.
- */
- vendor_id = PciVendorId(pdev);
- device_id = PciDeviceId(pdev);
- irq = PciIrqLine(pdev);
- i = 0;
- i = pci_get_base_address(pdev, i, &io_port);
- i = pci_get_base_address(pdev, i, &base);
- (void) pci_get_base_address(pdev, i, &base_2);
- pci_read_config_word(pdev, PCI_COMMAND, &command);
- pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
- pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line_size);
- pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_timer);
-
- /*
- ** If user excludes this chip, donnot initialize it.
- */
- for (i = 0 ; i < SCSI_NCR_MAX_EXCLUDES ; i++) {
- if (driver_setup.excludes[i] ==
- (io_port & PCI_BASE_ADDRESS_IO_MASK))
- return -1;
- }
- /*
- * Check if the chip is supported
- */
- chip = 0;
- for (i = 0; i < sizeof(ncr_chip_table)/sizeof(ncr_chip_table[0]); i++) {
- if (device_id != ncr_chip_table[i].device_id)
- continue;
- if (revision > ncr_chip_table[i].revision_id)
- continue;
- chip = &device->chip;
- memcpy(chip, &ncr_chip_table[i], sizeof(*chip));
- chip->revision_id = revision;
- break;
- }
-
-#if defined(__i386__)
- /*
- * Ignore Symbios chips controlled by SISL RAID controller.
- */
- if (chip && (base_2 & PCI_BASE_ADDRESS_MEM_MASK)) {
- unsigned int ScriptsSize, MagicValue;
- vm_offset_t ScriptsRAM;
-
- if (chip->features & FE_RAM8K)
- ScriptsSize = 8192;
- else
- ScriptsSize = 4096;
-
- ScriptsRAM = remap_pci_mem(base_2 & PCI_BASE_ADDRESS_MEM_MASK,
- ScriptsSize);
- if (ScriptsRAM) {
- MagicValue = readl(ScriptsRAM + ScriptsSize - 16);
- unmap_pci_mem(ScriptsRAM, ScriptsSize);
- if (MagicValue == 0x52414944)
- return -1;
- }
- }
-#endif
-
- printk(KERN_INFO "ncr53c8xx: at PCI bus %d, device %d, function %d\n",
- PciBusNumber(pdev),
- (int) (PciDeviceFn(pdev) & 0xf8) >> 3,
- (int) (PciDeviceFn(pdev) & 0x7));
-
- if (!chip) {
- printk("ncr53c8xx: not initializing, device not supported\n");
- return -1;
- }
-
-#ifdef __powerpc__
- /*
- * Several fix-up for power/pc.
- * Should not be performed by the driver.
- */
- if (!(command & PCI_COMMAND_MASTER)) {
- printk("ncr53c8xx: attempting to force PCI_COMMAND_MASTER...");
- command |= PCI_COMMAND_MASTER;
- pci_write_config_word(pdev, PCI_COMMAND, command);
- pci_read_config_word(pdev, PCI_COMMAND, &command);
- if (!(command & PCI_COMMAND_MASTER)) {
- printk("failed!\n");
- } else {
- printk("succeeded.\n");
- }
- }
-
- if (!(command & PCI_COMMAND_IO)) {
- printk("ncr53c8xx: attempting to force PCI_COMMAND_IO...");
- command |= PCI_COMMAND_IO;
- pci_write_config_word(pdev, PCI_COMMAND, command);
- pci_read_config_word(pdev, PCI_COMMAND, &command);
- if (!(command & PCI_COMMAND_IO)) {
- printk("failed!\n");
- } else {
- printk("succeeded.\n");
- }
- }
-
- if (!(command & PCI_COMMAND_MEMORY)) {
- printk("ncr53c8xx: attempting to force PCI_COMMAND_MEMORY...");
- command |= PCI_COMMAND_MEMORY;
- pci_write_config_word(pdev, PCI_COMMAND, command);
- pci_read_config_word(pdev, PCI_COMMAND, &command);
- if (!(command & PCI_COMMAND_MEMORY)) {
- printk("failed!\n");
- } else {
- printk("succeeded.\n");
- }
- }
-
-
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,140)
- if ( is_prep ) {
- if (io_port >= 0x10000000) {
- printk("ncr53c8xx: reallocating io_port (Wacky IBM)");
- io_port = (io_port & 0x00FFFFFF) | 0x01000000;
- pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, io_port);
- }
- if (base >= 0x10000000) {
- printk("ncr53c8xx: reallocating base (Wacky IBM)");
- base = (base & 0x00FFFFFF) | 0x01000000;
- pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, base);
- }
- if (base_2 >= 0x10000000) {
- printk("ncr53c8xx: reallocating base2 (Wacky IBM)");
- base_2 = (base_2 & 0x00FFFFFF) | 0x01000000;
- pci_write_config_dword(pdev, PCI_BASE_ADDRESS_2, base_2);
- }
- }
-#endif
-#endif /* __powerpc__ */
-
-#ifdef __sparc__
- /*
- * Severall fix-ups for sparc.
- *
- * Should not be performed by the driver, but how can OBP know
- * each and every PCI card, if they don't use Fcode?
- */
-
- base = __pa(base);
- base_2 = __pa(base_2);
-
- if (!(command & PCI_COMMAND_MASTER)) {
- if (initverbose >= 2)
- printk("ncr53c8xx: setting PCI_COMMAND_MASTER bit (fixup)\n");
- command |= PCI_COMMAND_MASTER;
- pci_write_config_word(pdev, PCI_COMMAND, command);
- pci_read_config_word(pdev, PCI_COMMAND, &command);
- }
-
- if ((chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
- if (initverbose >= 2)
- printk("ncr53c8xx: setting PCI_COMMAND_INVALIDATE bit (fixup)\n");
- command |= PCI_COMMAND_INVALIDATE;
- pci_write_config_word(pdev, PCI_COMMAND, command);
- pci_read_config_word(pdev, PCI_COMMAND, &command);
- }
-
- if ((chip->features & FE_CLSE) && !cache_line_size) {
- /* PCI_CACHE_LINE_SIZE value is in 32-bit words. */
- cache_line_size = 64 / sizeof(u_int32);
- if (initverbose >= 2)
- printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fixup)\n", cache_line_size);
- pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, cache_line_size);
- pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line_size);
- }
-
- if (!latency_timer) {
- latency_timer = 128;
- if (initverbose >= 2)
- printk("ncr53c8xx: setting PCI_LATENCY_TIMER to %d bus clocks (fixup)\n", latency_timer);
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, latency_timer);
- pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_timer);
- }
-#endif /* __sparc__ */
-
- /*
- * Check availability of IO space, memory space and master capability.
- */
- if (command & PCI_COMMAND_IO)
- io_port &= PCI_BASE_ADDRESS_IO_MASK;
- else
- io_port = 0;
-
- if (command & PCI_COMMAND_MEMORY)
- base &= PCI_BASE_ADDRESS_MEM_MASK;
- else
- base = 0;
-
- if (!io_port && !base) {
- printk("ncr53c8xx: not initializing, both I/O and memory mappings disabled\n");
- return -1;
- }
-
- base_2 &= PCI_BASE_ADDRESS_MEM_MASK;
-
- if (io_port && check_region (io_port, 128)) {
-#ifdef __sparc__
- printk("ncr53c8xx: IO region 0x%lx to 0x%lx is in use\n",
- io_port, (io_port + 127));
-#else
- printk("ncr53c8xx: IO region 0x%x to 0x%x is in use\n",
- (int) io_port, (int) (io_port + 127));
-#endif
- return -1;
- }
-
- if (!(command & PCI_COMMAND_MASTER)) {
- printk("ncr53c8xx: not initializing, BUS MASTERING was disabled\n");
- return -1;
- }
-
- /*
- * Fix some features according to driver setup.
- */
- if (!(driver_setup.special_features & 1))
- chip->features &= ~FE_SPECIAL_SET;
- else {
- if (driver_setup.special_features & 2)
- chip->features &= ~FE_WRIE;
- }
- if (driver_setup.ultra_scsi < 2 && (chip->features & FE_ULTRA2)) {
- chip->features |= FE_ULTRA;
- chip->features &= ~FE_ULTRA2;
- }
- if (driver_setup.ultra_scsi < 1)
- chip->features &= ~FE_ULTRA;
- if (!driver_setup.max_wide)
- chip->features &= ~FE_WIDE;
-
-
-#ifdef SCSI_NCR_PCI_FIX_UP_SUPPORT
-
- /*
- * Try to fix up PCI config according to wished features.
- */
-#if defined(__i386__) && !defined(MODULE)
- if ((driver_setup.pci_fix_up & 1) &&
- (chip->features & FE_CLSE) && cache_line_size == 0) {
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,75)
- extern char x86;
- switch(x86) {
-#else
- switch(boot_cpu_data.x86) {
-#endif
- case 4: cache_line_size = 4; break;
- case 6:
- case 5: cache_line_size = 8; break;
- }
- if (cache_line_size)
- (void) pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, cache_line_size);
- if (initverbose)
- printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fix-up).\n", cache_line_size);
- }
-
- if ((driver_setup.pci_fix_up & 2) && cache_line_size &&
- (chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
- command |= PCI_COMMAND_INVALIDATE;
- (void) pci_write_config_word(pdev, PCI_COMMAND, command);
- if (initverbose)
- printk("ncr53c8xx: setting PCI_COMMAND_INVALIDATE bit (fix-up).\n");
- }
-#endif
- /*
- * Fix up for old chips that support READ LINE but not CACHE LINE SIZE.
- * - If CACHE LINE SIZE is unknown, set burst max to 32 bytes = 8 dwords
- * and donnot enable READ LINE.
- * - Otherwise set it to the CACHE LINE SIZE (power of 2 assumed).
- */
-
- if (!(chip->features & FE_CLSE)) {
- int burst_max = chip->burst_max;
- if (cache_line_size == 0) {
- chip->features &= ~FE_ERL;
- if (burst_max > 3)
- burst_max = 3;
- }
- else {
- while (cache_line_size < (1 << burst_max))
- --burst_max;
- }
- chip->burst_max = burst_max;
- }
-
- /*
- * Tune PCI LATENCY TIMER according to burst max length transfer.
- * (latency timer >= burst length + 6, we add 10 to be quite sure)
- * If current value is zero, the device has probably been configured
- * for no bursting due to some broken hardware.
- */
-
- if (latency_timer == 0 && chip->burst_max)
- printk("ncr53c8xx: PCI_LATENCY_TIMER=0, bursting should'nt be allowed.\n");
-
- if ((driver_setup.pci_fix_up & 4) && chip->burst_max) {
- uchar lt = (1 << chip->burst_max) + 6 + 10;
- if (latency_timer < lt) {
- latency_timer = lt;
- if (initverbose)
- printk("ncr53c8xx: setting PCI_LATENCY_TIMER to %d bus clocks (fix-up).\n", latency_timer);
- (void) pci_write_config_byte(pdev, PCI_LATENCY_TIMER, latency_timer);
- }
- }
-
- /*
- * Fix up for recent chips that support CACHE LINE SIZE.
- * If PCI config space is not OK, remove features that shall not be
- * used by the chip. No need to trigger possible chip bugs.
- */
-
- if ((chip->features & FE_CLSE) && cache_line_size == 0) {
- chip->features &= ~FE_CACHE_SET;
- printk("ncr53c8xx: PCI_CACHE_LINE_SIZE not set, features based on CACHE LINE SIZE not used.\n");
- }
-
- if ((chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
- chip->features &= ~FE_WRIE;
- printk("ncr53c8xx: PCI_COMMAND_INVALIDATE not set, WRITE AND INVALIDATE not used\n");
- }
-
-#endif /* SCSI_NCR_PCI_FIX_UP_SUPPORT */
-
- /* initialise ncr_device structure with items required by ncr_attach */
- device->slot.bus = PciBusNumber(pdev);
- device->slot.device_fn = PciDeviceFn(pdev);
- device->slot.base = base;
- device->slot.base_2 = base_2;
- device->slot.io_port = io_port;
- device->slot.irq = irq;
- device->attach_done = 0;
-
- return 0;
-}
-
/*
** Linux select queue depths function
*/
-#define DEF_DEPTH (driver_setup.default_tags)
-#define ALL_TARGETS -2
-#define NO_TARGET -1
-#define ALL_LUNS -2
-#define NO_LUN -1
-
-static int device_queue_depth(ncb_p np, int target, int lun)
-{
- int c, h, t, u, v;
- char *p = driver_setup.tag_ctrl;
- char *ep;
-
- h = -1;
- t = NO_TARGET;
- u = NO_LUN;
- while ((c = *p++) != 0) {
- v = simple_strtoul(p, &ep, 0);
- switch(c) {
- case '/':
- ++h;
- t = ALL_TARGETS;
- u = ALL_LUNS;
- break;
- case 't':
- if (t != target)
- t = (target == v) ? v : NO_TARGET;
- u = ALL_LUNS;
- break;
- case 'u':
- if (u != lun)
- u = (lun == v) ? v : NO_LUN;
- break;
- case 'q':
- if (h == np->unit &&
- (t == ALL_TARGETS || t == target) &&
- (u == ALL_LUNS || u == lun))
- return v;
- break;
- case '-':
- t = ALL_TARGETS;
- u = ALL_LUNS;
- break;
- default:
- break;
- }
- p = ep;
- }
- return DEF_DEPTH;
-}
-
static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_device *devlist)
{
struct scsi_device *device;
@@ -10127,7 +8406,7 @@ static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_de
** Use at least 2.
** Donnot use more than our maximum.
*/
- numtags = device_queue_depth(np, device->id, device->lun);
+ numtags = device_queue_depth(np->unit, device->id, device->lun);
if (numtags > tp->usrtags)
numtags = tp->usrtags;
if (!device->tagged_supported)
@@ -10157,14 +8436,6 @@ printk("ncr53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n",
}
/*
-** Linux entry point for info() function
-*/
-const char *ncr53c8xx_info (struct Scsi_Host *host)
-{
- return SCSI_NCR_DRIVER_NAME;
-}
-
-/*
** Linux entry point of queuecommand() function
*/
@@ -10180,6 +8451,10 @@ printk("ncr53c8xx_queue_command\n");
cmd->scsi_done = done;
cmd->host_scribble = NULL;
+#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING
+ cmd->__data_mapped = 0;
+ cmd->__data_mapping = 0;
+#endif
NCR_LOCK_NCB(np, flags);
@@ -10196,8 +8471,10 @@ printk("ncr53c8xx : command successfully queued\n");
NCR_UNLOCK_NCB(np, flags);
- if (sts != DID_OK)
+ if (sts != DID_OK) {
+ unmap_scsi_data(np, cmd);
done(cmd);
+ }
return sts;
}
@@ -10208,11 +8485,9 @@ printk("ncr53c8xx : command successfully queued\n");
** passing the internal host descriptor as 'dev_id'.
** Otherwise, we scan the host list and call the interrupt
** routine for each host that uses this IRQ.
-**
-** Exported for certain MIPS machines with a dedicated NCR interrupt.
*/
-void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
+static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
{
unsigned long flags;
ncb_p np = (ncb_p) dev_id;
@@ -10458,7 +8733,6 @@ static void process_waiting_list(ncb_p np, int sts)
printk("%s: cmd %lx done forced sts=%d\n", ncr_name(np), (u_long) wcmd, sts);
#endif
wcmd->result = ScsiResult(sts, 0);
-//flush_cache_all();
ncr_queue_done_cmd(np, wcmd);
}
}
@@ -10676,50 +8950,8 @@ printk("ncr_user_command: data=%ld\n", uc->data);
#endif /* SCSI_NCR_USER_COMMAND_SUPPORT */
-#ifdef SCSI_NCR_USER_INFO_SUPPORT
-
-struct info_str
-{
- char *buffer;
- int length;
- int offset;
- int pos;
-};
-
-static void copy_mem_info(struct info_str *info, char *data, int len)
-{
- if (info->pos + len > info->length)
- len = info->length - info->pos;
-
- if (info->pos + len < info->offset) {
- info->pos += len;
- return;
- }
- if (info->pos < info->offset) {
- data += (info->offset - info->pos);
- len -= (info->offset - info->pos);
- }
-
- if (len > 0) {
- memcpy(info->buffer + info->pos, data, len);
- info->pos += len;
- }
-}
-
-static int copy_info(struct info_str *info, char *fmt, ...)
-{
- va_list args;
- char buf[81];
- int len;
-
- va_start(args, fmt);
- len = vsprintf(buf, fmt, args);
- va_end(args);
-
- copy_mem_info(info, buf, len);
- return len;
-}
+#ifdef SCSI_NCR_USER_INFO_SUPPORT
/*
** Copy formatted profile information into the input buffer.
*/
@@ -10827,7 +9059,6 @@ printk("ncr53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func);
return retv;
}
-
/*=========================================================================
** End of proc file system stuff
**=========================================================================
@@ -10835,432 +9066,105 @@ printk("ncr53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func);
#endif
-#ifdef SCSI_NCR_NVRAM_SUPPORT
-
-/* ---------------------------------------------------------------------
+/*==========================================================
**
-** Try reading Symbios format nvram
+** /proc directory entry.
**
-** ---------------------------------------------------------------------
+**==========================================================
+*/
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
+static struct proc_dir_entry proc_scsi_ncr53c8xx = {
+ PROC_SCSI_NCR53C8XX, 9, NAME53C8XX,
+ S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+#endif
+
+/*==========================================================
**
-** GPOI0 - data in/data out
-** GPIO1 - clock
+** Boot command line.
**
-** return 0 if NVRAM data OK, 1 if NVRAM data not OK
-** ---------------------------------------------------------------------
+**==========================================================
*/
+#ifdef MODULE
+char *ncr53c8xx = 0; /* command line passed by insmod */
+# if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+MODULE_PARM(ncr53c8xx, "s");
+# endif
+#endif
-#define SET_BIT 0
-#define CLR_BIT 1
-#define SET_CLK 2
-#define CLR_CLK 3
-
-static u_short nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl);
-static void nvram_start(ncr_slot *np, u_char *gpreg);
-static void nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl);
-static void nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl);
-static void nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl);
-static void nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl);
-static void nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg);
-static void nvram_stop(ncr_slot *np, u_char *gpreg);
-static void nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode);
-
-static int __init ncr_get_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram)
-{
- static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0};
- u_char gpcntl, gpreg;
- u_char old_gpcntl, old_gpreg;
- u_short csum;
- u_char ack_data;
- int retv = 1;
-
- /* save current state of GPCNTL and GPREG */
- old_gpreg = INB (nc_gpreg);
- old_gpcntl = INB (nc_gpcntl);
- gpcntl = old_gpcntl & 0xfc;
-
- /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
- OUTB (nc_gpreg, old_gpreg);
- OUTB (nc_gpcntl, gpcntl);
-
- /* this is to set NVRAM into a known state with GPIO0/1 both low */
- gpreg = old_gpreg;
- nvram_setBit(np, 0, &gpreg, CLR_CLK);
- nvram_setBit(np, 0, &gpreg, CLR_BIT);
-
- /* now set NVRAM inactive with GPIO0/1 both high */
- nvram_stop(np, &gpreg);
-
- /* activate NVRAM */
- nvram_start(np, &gpreg);
-
- /* write device code and random address MSB */
- nvram_write_byte(np, &ack_data,
- 0xa0 | ((SYMBIOS_NVRAM_ADDRESS >> 7) & 0x0e), &gpreg, &gpcntl);
- if (ack_data & 0x01)
- goto out;
-
- /* write random address LSB */
- nvram_write_byte(np, &ack_data,
- (SYMBIOS_NVRAM_ADDRESS & 0x7f) << 1, &gpreg, &gpcntl);
- if (ack_data & 0x01)
- goto out;
-
- /* regenerate START state to set up for reading */
- nvram_start(np, &gpreg);
-
- /* rewrite device code and address MSB with read bit set (lsb = 0x01) */
- nvram_write_byte(np, &ack_data,
- 0xa1 | ((SYMBIOS_NVRAM_ADDRESS >> 7) & 0x0e), &gpreg, &gpcntl);
- if (ack_data & 0x01)
- goto out;
-
- /* now set up GPIO0 for inputting data */
- gpcntl |= 0x01;
- OUTB (nc_gpcntl, gpcntl);
-
- /* input all active data - only part of total NVRAM */
- csum = nvram_read_data(np,
- (u_char *) nvram, sizeof(*nvram), &gpreg, &gpcntl);
-
- /* finally put NVRAM back in inactive mode */
- gpcntl &= 0xfe;
- OUTB (nc_gpcntl, gpcntl);
- nvram_stop(np, &gpreg);
-
-#ifdef SCSI_NCR_DEBUG_NVRAM
-printk("ncr53c8xx: NvRAM type=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n",
- nvram->type,
- nvram->trailer[0], nvram->trailer[1], nvram->trailer[2],
- nvram->trailer[3], nvram->trailer[4], nvram->trailer[5],
- nvram->byte_count, sizeof(*nvram) - 12,
- nvram->checksum, csum);
-#endif
-
- /* check valid NVRAM signature, verify byte count and checksum */
- if (nvram->type == 0 &&
- !memcmp(nvram->trailer, Symbios_trailer, 6) &&
- nvram->byte_count == sizeof(*nvram) - 12 &&
- csum == nvram->checksum)
- retv = 0;
-out:
- /* return GPIO0/1 to original states after having accessed NVRAM */
- OUTB (nc_gpcntl, old_gpcntl);
- OUTB (nc_gpreg, old_gpreg);
-
- return retv;
-}
-
-/*
- * Read Symbios NvRAM data and compute checksum.
- */
-static u_short __init
-nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl)
-{
- int x;
- u_short csum;
-
- for (x = 0; x < len; x++)
- nvram_read_byte(np, &data[x], (x == (len - 1)), gpreg, gpcntl);
-
- for (x = 6, csum = 0; x < len - 6; x++)
- csum += data[x];
-
- return csum;
-}
-
-/*
- * Send START condition to NVRAM to wake it up.
- */
-static void __init nvram_start(ncr_slot *np, u_char *gpreg)
-{
- nvram_setBit(np, 1, gpreg, SET_BIT);
- nvram_setBit(np, 0, gpreg, SET_CLK);
- nvram_setBit(np, 0, gpreg, CLR_BIT);
- nvram_setBit(np, 0, gpreg, CLR_CLK);
-}
-
-/*
- * WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK,
- * GPIO0 must already be set as an output
- */
-static void __init
-nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl)
-{
- int x;
-
- for (x = 0; x < 8; x++)
- nvram_doBit(np, 0, (write_data >> (7 - x)) & 0x01, gpreg);
-
- nvram_readAck(np, ack_data, gpreg, gpcntl);
-}
-
-/*
- * READ a byte from the NVRAM and then send an ACK to say we have got it,
- * GPIO0 must already be set as an input
- */
-static void __init
-nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl)
-{
- int x;
- u_char read_bit;
-
- *read_data = 0;
- for (x = 0; x < 8; x++) {
- nvram_doBit(np, &read_bit, 1, gpreg);
- *read_data |= ((read_bit & 0x01) << (7 - x));
- }
-
- nvram_writeAck(np, ack_data, gpreg, gpcntl);
-}
-
-/*
- * Output an ACK to the NVRAM after reading,
- * change GPIO0 to output and when done back to an input
- */
-static void __init
-nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl)
-{
- OUTB (nc_gpcntl, *gpcntl & 0xfe);
- nvram_doBit(np, 0, write_bit, gpreg);
- OUTB (nc_gpcntl, *gpcntl);
-}
-
-/*
- * Input an ACK from NVRAM after writing,
- * change GPIO0 to input and when done back to an output
- */
-static void __init
-nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl)
-{
- OUTB (nc_gpcntl, *gpcntl | 0x01);
- nvram_doBit(np, read_bit, 1, gpreg);
- OUTB (nc_gpcntl, *gpcntl);
-}
-
-/*
- * Read or write a bit to the NVRAM,
- * read if GPIO0 input else write if GPIO0 output
- */
-static void __init nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg)
-{
- nvram_setBit(np, write_bit, gpreg, SET_BIT);
- nvram_setBit(np, 0, gpreg, SET_CLK);
- if (read_bit)
- *read_bit = INB (nc_gpreg);
- nvram_setBit(np, 0, gpreg, CLR_CLK);
- nvram_setBit(np, 0, gpreg, CLR_BIT);
-}
-
-/*
- * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!!
- */
-static void __init nvram_stop(ncr_slot *np, u_char *gpreg)
-{
- nvram_setBit(np, 0, gpreg, SET_CLK);
- nvram_setBit(np, 1, gpreg, SET_BIT);
-}
-
-/*
- * Set/clear data/clock bit in GPIO0
- */
-static void __init
-nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode)
+int __init ncr53c8xx_setup(char *str)
{
- UDELAY (5);
- switch (bit_mode){
- case SET_BIT:
- *gpreg |= write_bit;
- break;
- case CLR_BIT:
- *gpreg &= 0xfe;
- break;
- case SET_CLK:
- *gpreg |= 0x02;
- break;
- case CLR_CLK:
- *gpreg &= 0xfd;
- break;
-
- }
- OUTB (nc_gpreg, *gpreg);
- UDELAY (5);
+ return sym53c8xx__setup(str);
}
-#undef SET_BIT 0
-#undef CLR_BIT 1
-#undef SET_CLK 2
-#undef CLR_CLK 3
-
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
+#ifndef MODULE
+__setup("ncr53c8xx=", ncr53c8xx_setup);
+#endif
+#endif
-/* ---------------------------------------------------------------------
-**
-** Try reading Tekram format nvram
-**
-** ---------------------------------------------------------------------
+/*===================================================================
**
-** GPOI0 - data in
-** GPIO1 - data out
-** GPIO2 - clock
-** GPIO4 - chip select
+** SYM53C8XX supported device list
**
-** return 0 if NVRAM data OK, 1 if NVRAM data not OK
-** ---------------------------------------------------------------------
+**===================================================================
*/
-static u_short Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg);
-static void Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg);
-static void Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg);
-static void Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg);
-static void Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg);
-static void Tnvram_Stop(ncr_slot *np, u_char *gpreg);
-static void Tnvram_Clk(ncr_slot *np, u_char *gpreg);
-
-static int __init ncr_get_Tekram_nvram (ncr_slot *np, Tekram_nvram *nvram)
-{
- u_char gpcntl, gpreg;
- u_char old_gpcntl, old_gpreg;
- u_short csum;
-
- /* save current state of GPCNTL and GPREG */
- old_gpreg = INB (nc_gpreg);
- old_gpcntl = INB (nc_gpcntl);
-
- /* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in,
- 1/2/4 out */
- gpreg = old_gpreg & 0xe9;
- OUTB (nc_gpreg, gpreg);
- gpcntl = (old_gpcntl & 0xe9) | 0x09;
- OUTB (nc_gpcntl, gpcntl);
-
- /* input all of NVRAM, 64 words */
- csum = Tnvram_read_data(np, (u_short *) nvram,
- sizeof(*nvram) / sizeof(short), &gpreg);
-
- /* return GPIO0/1/2/4 to original states after having accessed NVRAM */
- OUTB (nc_gpcntl, old_gpcntl);
- OUTB (nc_gpreg, old_gpreg);
-
- /* check data valid */
- if (csum != 0x1234)
- return 1;
-
- return 0;
-}
-
-/*
- * Read Tekram NvRAM data and compute checksum.
- */
-static u_short __init
-Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg)
-{
- u_char read_bit;
- u_short csum;
- int x;
-
- for (x = 0, csum = 0; x < len; x++) {
-
- /* output read command and address */
- Tnvram_Send_Command(np, 0x180 | x, &read_bit, gpreg);
- if (read_bit & 0x01)
- return 0; /* Force bad checksum */
-
- Tnvram_Read_Word(np, &data[x], gpreg);
- csum += data[x];
-
- Tnvram_Stop(np, gpreg);
- }
-
- return csum;
-}
-
-/*
- * Send read command and address to NVRAM
- */
-static void __init Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg)
-{
- int x;
-
- /* send 9 bits, start bit (1), command (2), address (6) */
- for (x = 0; x < 9; x++)
- Tnvram_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg);
-
- *read_bit = INB (nc_gpreg);
-}
-
-/*
- * READ a byte from the NVRAM
- */
-static void __init Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg)
-{
- int x;
- u_char read_bit;
-
- *nvram_data = 0;
- for (x = 0; x < 16; x++) {
- Tnvram_Read_Bit(np, &read_bit, gpreg);
-
- if (read_bit & 0x01)
- *nvram_data |= (0x01 << (15 - x));
- else
- *nvram_data &= ~(0x01 << (15 - x));
- }
-}
-
-/*
- * Read bit from NVRAM
- */
-static void __init
-Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
-{
- UDELAY (2);
- Tnvram_Clk(np, gpreg);
- *read_bit = INB (nc_gpreg);
-}
+static u_short ncr_chip_ids[] __initdata = {
+ PCI_DEVICE_ID_NCR_53C810,
+ PCI_DEVICE_ID_NCR_53C815,
+ PCI_DEVICE_ID_NCR_53C820,
+ PCI_DEVICE_ID_NCR_53C825,
+ PCI_DEVICE_ID_NCR_53C860,
+ PCI_DEVICE_ID_NCR_53C875,
+ PCI_DEVICE_ID_NCR_53C875J,
+ PCI_DEVICE_ID_NCR_53C885,
+ PCI_DEVICE_ID_NCR_53C895,
+ PCI_DEVICE_ID_NCR_53C896,
+ PCI_DEVICE_ID_NCR_53C895A,
+ PCI_DEVICE_ID_NCR_53C1510D
+};
-/*
- * Write bit to GPIO0
- */
-static void __init
-Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg)
+/*==========================================================
+**
+** Chip detection entry point.
+**
+**==========================================================
+*/
+int __init ncr53c8xx_detect(Scsi_Host_Template *tpnt)
{
- if (write_bit & 0x01)
- *gpreg |= 0x02;
- else
- *gpreg &= 0xfd;
-
- *gpreg |= 0x10;
-
- OUTB (nc_gpreg, *gpreg);
- UDELAY (2);
-
- Tnvram_Clk(np, gpreg);
-}
+ /*
+ ** Initialize driver general stuff.
+ */
+#ifdef SCSI_NCR_PROC_INFO_SUPPORT
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
+ tpnt->proc_dir = &proc_scsi_ncr53c8xx;
+#else
+ tpnt->proc_name = NAME53C8XX;
+#endif
+ tpnt->proc_info = ncr53c8xx_proc_info;
+#endif
-/*
- * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!!
- */
-static void __init Tnvram_Stop(ncr_slot *np, u_char *gpreg)
-{
- *gpreg &= 0xef;
- OUTB (nc_gpreg, *gpreg);
- UDELAY (2);
+#if defined(SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT) && defined(MODULE)
+if (ncr53c8xx)
+ ncr53c8xx_setup(ncr53c8xx);
+#endif
- Tnvram_Clk(np, gpreg);
+ return sym53c8xx__detect(tpnt, ncr_chip_ids,
+ sizeof(ncr_chip_ids)/sizeof(ncr_chip_ids[0]));
}
-/*
- * Pulse clock bit in GPIO0
- */
-static void __init Tnvram_Clk(ncr_slot *np, u_char *gpreg)
+/*==========================================================
+**
+** Entry point for info() function
+**
+**==========================================================
+*/
+const char *ncr53c8xx_info (struct Scsi_Host *host)
{
- OUTB (nc_gpreg, *gpreg | 0x04);
- UDELAY (2);
- OUTB (nc_gpreg, *gpreg);
+ return SCSI_NCR_DRIVER_NAME;
}
-#endif /* SCSI_NCR_NVRAM_SUPPORT */
-
/*
** Module stuff
*/
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index a6e2c14d9..21cb989ca 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -218,23 +218,6 @@ static void scsi_wait_done(Scsi_Cmnd * SCpnt)
}
}
-void scsi_wait_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
- void *buffer, unsigned bufflen,
- int timeout, int retries)
-{
- DECLARE_MUTEX_LOCKED(sem);
-
- if (buffer != NULL && SCpnt->sc_data_direction == SCSI_DATA_NONE)
- BUG();
- SCpnt->request.sem = &sem;
- SCpnt->request.rq_status = RQ_SCSI_BUSY;
- scsi_do_cmd (SCpnt, (void *) cmnd,
- buffer, bufflen, scsi_wait_done, timeout, retries);
- down (&sem);
- SCpnt->request.sem = NULL;
-}
-
-
/*
* This lock protects the freelist for all devices on the system.
* We could make this finer grained by having a single lock per
@@ -2499,7 +2482,6 @@ static void scsi_dump_status(int level)
atomic_read(&shpnt->host_active),
shpnt->host_blocked,
shpnt->host_self_blocked);
-
}
printk("\n\n");
diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
index 7a073f86e..677d21410 100644
--- a/drivers/scsi/scsi.h
+++ b/drivers/scsi/scsi.h
@@ -497,9 +497,6 @@ extern void scsi_do_cmd(Scsi_Cmnd *, const void *cmnd,
void *buffer, unsigned bufflen,
void (*done) (struct scsi_cmnd *),
int timeout, int retries);
-extern void scsi_wait_cmd(Scsi_Cmnd *, const void *cmnd,
- void *buffer, unsigned bufflen,
- int timeout, int retries);
extern int scsi_dev_init(void);
/*
@@ -571,7 +568,7 @@ struct scsi_device {
Scsi_Cmnd *device_queue; /* queue of SCSI Command structures */
/* public: */
- unsigned char id, lun, channel;
+ unsigned int id, lun, channel;
unsigned int manufacturer; /* Manufacturer of device, for using
* vendor-specific cmd's */
@@ -731,9 +728,9 @@ struct scsi_cmnd {
/* public: */
- unsigned char target;
- unsigned char lun;
- unsigned char channel;
+ unsigned int target;
+ unsigned int lun;
+ unsigned int channel;
unsigned char cmd_len;
unsigned char old_cmd_len;
unsigned char sc_data_direction;
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 9f36d08c5..4bed377ed 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -549,24 +549,24 @@ static void scsi_debug_send_self_command(struct Scsi_Host * shpnt)
static unsigned char cmd[6] =
{TEST_UNIT_READY, 0, 0, 0, 0, 0};
- Scsi_Cmnd * scp;
+ Scsi_Request * scp;
Scsi_Device * sdev;
printk("Allocating host dev\n");
sdev = scsi_get_host_dev(shpnt);
printk("Got %p. Allocating command block\n", sdev);
- scp = scsi_allocate_device(sdev, 1, FALSE);
+ scp = scsi_allocate_request(sdev);
printk("Got %p\n", scp);
- scp->cmd_len = 6;
- scp->use_sg = 0;
+ scp->sr_cmd_len = 6;
+ scp->sr_use_sg = 0;
printk("Sending command\n");
- scsi_wait_cmd (scp, (void *) cmd, (void *) NULL,
+ scsi_wait_req (scp, (void *) cmd, (void *) NULL,
0, 100, 3);
printk("Releasing command\n");
- scsi_release_command(scp);
+ scsi_release_request(scp);
printk("Freeing device\n");
scsi_free_host_dev(sdev);
}
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index abdef85ef..a211980a5 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -94,24 +94,20 @@ static int ioctl_internal_command(Scsi_Device * dev, char *cmd,
int timeout, int retries)
{
int result;
- Scsi_Cmnd *SCpnt;
+ Scsi_Request *SRpnt;
Scsi_Device *SDpnt;
SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", cmd[0]));
- SCpnt = scsi_allocate_device(dev, TRUE, TRUE);
- if( SCpnt == NULL )
- {
- return -EINTR;
- }
+ SRpnt = scsi_allocate_request(dev);
- SCpnt->sc_data_direction = SCSI_DATA_NONE;
- scsi_wait_cmd(SCpnt, cmd, NULL, 0, timeout, retries);
+ SRpnt->sr_data_direction = SCSI_DATA_NONE;
+ scsi_wait_req(SRpnt, cmd, NULL, 0, timeout, retries);
- SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", SCpnt->result));
+ SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", SRpnt->sr_result));
- if (driver_byte(SCpnt->result) != 0)
- switch (SCpnt->sense_buffer[2] & 0xf) {
+ if (driver_byte(SRpnt->sr_result) != 0)
+ switch (SRpnt->sr_sense_buffer[2] & 0xf) {
case ILLEGAL_REQUEST:
if (cmd[0] == ALLOW_MEDIUM_REMOVAL)
dev->lockable = 0;
@@ -126,7 +122,7 @@ static int ioctl_internal_command(Scsi_Device * dev, char *cmd,
case UNIT_ATTENTION:
if (dev->removable) {
dev->changed = 1;
- SCpnt->result = 0; /* This is no longer considered an error */
+ SRpnt->sr_result = 0; /* This is no longer considered an error */
/* gag this error, VFS will log it anyway /axboe */
/* printk(KERN_INFO "Disc change detected.\n"); */
break;
@@ -136,20 +132,20 @@ static int ioctl_internal_command(Scsi_Device * dev, char *cmd,
dev->host->host_no,
dev->id,
dev->lun,
- SCpnt->result);
+ SRpnt->sr_result);
printk("\tSense class %x, sense error %x, extended sense %x\n",
- sense_class(SCpnt->sense_buffer[0]),
- sense_error(SCpnt->sense_buffer[0]),
- SCpnt->sense_buffer[2] & 0xf);
+ sense_class(SRpnt->sr_sense_buffer[0]),
+ sense_error(SRpnt->sr_sense_buffer[0]),
+ SRpnt->sr_sense_buffer[2] & 0xf);
};
- result = SCpnt->result;
+ result = SRpnt->sr_result;
SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n"));
- SDpnt = SCpnt->device;
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ SDpnt = SRpnt->sr_device;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
return result;
}
@@ -192,7 +188,7 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
char *buf;
unsigned char cmd[MAX_COMMAND_SIZE];
char *cmd_in;
- Scsi_Cmnd *SCpnt;
+ Scsi_Request *SRpnt;
Scsi_Device *SDpnt;
unsigned char opcode;
int inlen, outlen, cmdlen;
@@ -235,9 +231,9 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
return -ENOMEM;
memset(buf, 0, buf_needed);
if( inlen == 0 ) {
- data_direction = SCSI_DATA_WRITE;
- } else if (outlen == 0 ) {
data_direction = SCSI_DATA_READ;
+ } else if (outlen == 0 ) {
+ data_direction = SCSI_DATA_WRITE;
} else {
/*
* Can this ever happen?
@@ -297,38 +293,38 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
#ifndef DEBUG_NO_CMD
- SCpnt = scsi_allocate_device(dev, TRUE, TRUE);
- if( SCpnt == NULL )
+ SRpnt = scsi_allocate_request(dev);
+ if( SRpnt == NULL )
{
return -EINTR;
}
- SCpnt->sc_data_direction = data_direction;
- scsi_wait_cmd(SCpnt, cmd, buf, needed, timeout, retries);
+ SRpnt->sr_data_direction = data_direction;
+ scsi_wait_req(SRpnt, cmd, buf, needed, timeout, retries);
/*
* If there was an error condition, pass the info back to the user.
*/
- if (SCpnt->result) {
- int sb_len = sizeof(SCpnt->sense_buffer);
+ if (SRpnt->sr_result) {
+ int sb_len = sizeof(SRpnt->sr_sense_buffer);
sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len;
result = verify_area(VERIFY_WRITE, cmd_in, sb_len);
if (result)
return result;
- copy_to_user(cmd_in, SCpnt->sense_buffer, sb_len);
+ copy_to_user(cmd_in, SRpnt->sr_sense_buffer, sb_len);
} else {
result = verify_area(VERIFY_WRITE, cmd_in, outlen);
if (result)
return result;
copy_to_user(cmd_in, buf, outlen);
}
- result = SCpnt->result;
+ result = SRpnt->sr_result;
- SDpnt = SCpnt->device;
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ SDpnt = SRpnt->sr_device;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
if (buf)
scsi_free(buf, buf_needed);
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 2438aecc6..74ac6d245 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -87,6 +87,7 @@ int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int at_head)
SCpnt->request.cmd = SPECIAL;
SCpnt->request.special = (void *) SCpnt;
SCpnt->request.q = NULL;
+ SCpnt->request.nr_segments = 0;
/*
* We have the option of inserting the head or the tail of the queue.
@@ -155,6 +156,8 @@ int scsi_insert_special_req(Scsi_Request * SRpnt, int at_head)
q = &SRpnt->sr_device->request_queue;
SRpnt->sr_request.cmd = SPECIAL;
SRpnt->sr_request.special = (void *) SRpnt;
+ SRpnt->sr_request.q = NULL;
+ SRpnt->sr_request.nr_segments = 0;
/*
* We have the option of inserting the head or the tail of the queue.
@@ -909,6 +912,9 @@ void scsi_request_fn(request_queue_t * q)
* be in an interrupt handler. Only do this
* from user space, since we do not want to
* sleep from an interrupt.
+ *
+ * FIXME(eric) - have the error handler thread do
+ * this work.
*/
SDpnt->was_reset = 0;
if (SDpnt->removable && !in_interrupt()) {
@@ -950,6 +956,9 @@ void scsi_request_fn(request_queue_t * q)
if( SRpnt->sr_magic == SCSI_REQ_MAGIC ) {
SCpnt = scsi_allocate_device(SRpnt->sr_device,
FALSE, FALSE);
+ if( !SCpnt ) {
+ break;
+ }
scsi_init_cmd_from_req(SCpnt, SRpnt);
}
diff --git a/drivers/scsi/scsi_merge.c b/drivers/scsi/scsi_merge.c
index d917d9306..84f29ce74 100644
--- a/drivers/scsi/scsi_merge.c
+++ b/drivers/scsi/scsi_merge.c
@@ -324,7 +324,7 @@ static inline int scsi_new_mergeable(request_queue_t * q,
req->nr_segments >= SHpnt->sg_tablesize)
return 0;
req->nr_segments++;
- q->nr_segments++;
+ q->elevator.nr_segments++;
return 1;
}
@@ -346,7 +346,7 @@ static inline int scsi_new_segment(request_queue_t * q,
return 0;
req->nr_hw_segments++;
req->nr_segments++;
- q->nr_segments++;
+ q->elevator.nr_segments++;
return 1;
}
#else
@@ -362,7 +362,7 @@ static inline int scsi_new_segment(request_queue_t * q,
* counter.
*/
req->nr_segments++;
- q->nr_segments++;
+ q->elevator.nr_segments++;
return 1;
} else {
return 0;
@@ -665,7 +665,7 @@ __inline static int __scsi_merge_requests_fn(request_queue_t * q,
* This one is OK. Let it go.
*/
req->nr_segments += next->nr_segments - 1;
- q->nr_segments--;
+ q->elevator.nr_segments--;
#ifdef DMA_CHUNK_SIZE
req->nr_hw_segments += next->nr_hw_segments - 1;
#endif
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 4060872bf..a43f2988c 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -252,12 +252,12 @@ static int get_device_flags(unsigned char *response_data)
* devices to the disk driver.
*/
void scan_scsis(struct Scsi_Host *shpnt,
- unchar hardcoded,
- unchar hchannel,
- unchar hid,
- unchar hlun)
+ uint hardcoded,
+ uint hchannel,
+ uint hid,
+ uint hlun)
{
- int channel;
+ uint channel;
int dev;
int lun;
int max_dev_lun;
@@ -299,8 +299,6 @@ void scan_scsis(struct Scsi_Host *shpnt,
SDpnt->host = shpnt;
SDpnt->online = TRUE;
- scsi_build_commandblocks(SDpnt);
-
initialize_merge_fn(SDpnt);
/*
@@ -405,7 +403,7 @@ void scan_scsis(struct Scsi_Host *shpnt,
leave:
- { /* Unchain SCpnt from host_queue */
+ { /* Unchain SRpnt from host_queue */
Scsi_Device *prev, *next;
Scsi_Device *dqptr;
@@ -423,8 +421,6 @@ void scan_scsis(struct Scsi_Host *shpnt,
}
}
- scsi_release_commandblocks(SDpnt);
-
/* Last device block does not exist. Free memory. */
if (SDpnt != NULL)
kfree((char *) SDpnt);
@@ -460,7 +456,7 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
unsigned char scsi_cmd[MAX_COMMAND_SIZE];
struct Scsi_Device_Template *sdtpnt;
Scsi_Device *SDtail, *SDpnt = *SDpnt2;
- Scsi_Cmnd * SCpnt;
+ Scsi_Request * SRpnt;
int bflags, type = -1;
static int ghost_channel=-1, ghost_dev=-1;
int org_lun = lun;
@@ -472,6 +468,7 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
SDpnt->channel = channel;
SDpnt->online = TRUE;
+ scsi_build_commandblocks(SDpnt);
if ((channel == ghost_channel) && (dev == ghost_dev) && (lun == 1)) {
SDpnt->lun = 0;
@@ -496,37 +493,32 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
scsi_cmd[1] = lun << 5;
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
- SCpnt = scsi_allocate_device(SDpnt, 0, 0);
+ SRpnt = scsi_allocate_request(SDpnt);
- SCpnt->host = SDpnt->host;
- SCpnt->device = SDpnt;
- SCpnt->target = SDpnt->id;
- SCpnt->lun = SDpnt->lun;
- SCpnt->channel = SDpnt->channel;
- SCpnt->sc_data_direction = SCSI_DATA_NONE;
+ SRpnt->sr_data_direction = SCSI_DATA_NONE;
- scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
+ scsi_wait_req (SRpnt, (void *) scsi_cmd,
(void *) NULL,
0, SCSI_TIMEOUT + 4 * HZ, 5);
SCSI_LOG_SCAN_BUS(3, printk("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n",
- dev, lun, SCpnt->result));
- SCSI_LOG_SCAN_BUS(3, print_driverbyte(SCpnt->result));
- SCSI_LOG_SCAN_BUS(3, print_hostbyte(SCpnt->result));
+ dev, lun, SRpnt->sr_result));
+ SCSI_LOG_SCAN_BUS(3, print_driverbyte(SRpnt->sr_result));
+ SCSI_LOG_SCAN_BUS(3, print_hostbyte(SRpnt->sr_result));
SCSI_LOG_SCAN_BUS(3, printk("\n"));
- if (SCpnt->result) {
- 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) &&
- ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) &&
- ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST || lun > 0)) {
- scsi_release_command(SCpnt);
+ if (SRpnt->sr_result) {
+ if (((driver_byte(SRpnt->sr_result) & DRIVER_SENSE) ||
+ (status_byte(SRpnt->sr_result) & CHECK_CONDITION)) &&
+ ((SRpnt->sr_sense_buffer[0] & 0x70) >> 4) == 7) {
+ if (((SRpnt->sr_sense_buffer[2] & 0xf) != NOT_READY) &&
+ ((SRpnt->sr_sense_buffer[2] & 0xf) != UNIT_ATTENTION) &&
+ ((SRpnt->sr_sense_buffer[2] & 0xf) != ILLEGAL_REQUEST || lun > 0)) {
+ scsi_release_request(SRpnt);
return 1;
}
} else {
- scsi_release_command(SCpnt);
+ scsi_release_request(SRpnt);
return 0;
}
}
@@ -540,18 +532,18 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
scsi_cmd[3] = 0;
scsi_cmd[4] = 255;
scsi_cmd[5] = 0;
- SCpnt->cmd_len = 0;
- SCpnt->sc_data_direction = SCSI_DATA_READ;
+ SRpnt->sr_cmd_len = 0;
+ SRpnt->sr_data_direction = SCSI_DATA_READ;
- scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
+ scsi_wait_req (SRpnt, (void *) scsi_cmd,
(void *) scsi_result,
256, SCSI_TIMEOUT, 3);
SCSI_LOG_SCAN_BUS(3, printk("scsi: INQUIRY %s with code 0x%x\n",
- SCpnt->result ? "failed" : "successful", SCpnt->result));
+ SRpnt->sr_result ? "failed" : "successful", SRpnt->sr_result));
- if (SCpnt->result) {
- scsi_release_command(SCpnt);
+ if (SRpnt->sr_result) {
+ scsi_release_request(SRpnt);
return 0; /* assume no peripheral if any sort of error */
}
@@ -560,7 +552,7 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
* are supported here or not.
*/
if ((scsi_result[0] >> 5) == 3) {
- scsi_release_command(SCpnt);
+ scsi_release_request(SRpnt);
return 0; /* assume no peripheral if any sort of error */
}
@@ -705,15 +697,15 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
scsi_cmd[3] = 0;
scsi_cmd[4] = 0x2a;
scsi_cmd[5] = 0;
- SCpnt->cmd_len = 0;
- SCpnt->sc_data_direction = SCSI_DATA_READ;
- scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
+ SRpnt->sr_cmd_len = 0;
+ SRpnt->sr_data_direction = SCSI_DATA_READ;
+ scsi_wait_req (SRpnt, (void *) scsi_cmd,
(void *) scsi_result, 0x2a,
SCSI_TIMEOUT, 3);
}
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
scsi_release_commandblocks(SDpnt);
@@ -734,8 +726,6 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
SDpnt->host = shpnt;
SDpnt->online = TRUE;
- scsi_build_commandblocks(SDpnt);
-
/*
* Register the queue for the device. All I/O requests will come
* in through here. We also need to register a pointer to
diff --git a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c
index f6e8939a6..94820f5db 100644
--- a/drivers/scsi/scsi_syms.c
+++ b/drivers/scsi/scsi_syms.c
@@ -43,7 +43,6 @@ EXPORT_SYMBOL(scsicam_bios_param);
EXPORT_SYMBOL(scsi_partsize);
EXPORT_SYMBOL(scsi_allocate_device);
EXPORT_SYMBOL(scsi_do_cmd);
-EXPORT_SYMBOL(scsi_wait_cmd);
EXPORT_SYMBOL(scsi_command_size);
EXPORT_SYMBOL(scsi_ioctl);
EXPORT_SYMBOL(print_command);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 43187600b..584a84905 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -176,6 +176,8 @@ static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd,
case BLKFLSBUF:
case BLKSSZGET:
case BLKPG:
+ case BLKELVGET:
+ case BLKELVSET:
return blk_ioctl(inode->i_rdev, cmd, arg);
case BLKRRPART: /* Re-read partition tables */
@@ -660,7 +662,7 @@ static int sd_init_onedisk(int i)
unsigned long spintime_value = 0;
int the_result, retries, spintime;
int sector_size;
- Scsi_Cmnd *SCpnt;
+ Scsi_Request *SRpnt;
/*
* Get the name of the disk, in case we need to log it somewhere.
@@ -679,7 +681,7 @@ static int sd_init_onedisk(int i)
* just after a scsi bus reset.
*/
- SCpnt = scsi_allocate_device(rscsi_disks[i].device, 1, FALSE);
+ SRpnt = scsi_allocate_request(rscsi_disks[i].device);
buffer = (unsigned char *) scsi_malloc(512);
@@ -694,18 +696,18 @@ static int sd_init_onedisk(int i)
cmd[0] = TEST_UNIT_READY;
cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
memset((void *) &cmd[2], 0, 8);
- SCpnt->cmd_len = 0;
- SCpnt->sense_buffer[0] = 0;
- SCpnt->sense_buffer[2] = 0;
- SCpnt->sc_data_direction = SCSI_DATA_READ;
+ SRpnt->sr_cmd_len = 0;
+ SRpnt->sr_sense_buffer[0] = 0;
+ SRpnt->sr_sense_buffer[2] = 0;
+ SRpnt->sr_data_direction = SCSI_DATA_READ;
- scsi_wait_cmd (SCpnt, (void *) cmd, (void *) buffer,
+ scsi_wait_req (SRpnt, (void *) cmd, (void *) buffer,
0/*512*/, SD_TIMEOUT, MAX_RETRIES);
- the_result = SCpnt->result;
+ the_result = SRpnt->sr_result;
retries++;
if (the_result == 0
- || SCpnt->sense_buffer[2] != UNIT_ATTENTION)
+ || SRpnt->sr_sense_buffer[2] != UNIT_ATTENTION)
break;
}
@@ -716,8 +718,8 @@ static int sd_init_onedisk(int i)
*/
if( the_result != 0
&& ((driver_byte(the_result) & DRIVER_SENSE) != 0)
- && SCpnt->sense_buffer[2] == UNIT_ATTENTION
- && SCpnt->sense_buffer[12] == 0x3A ) {
+ && SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION
+ && SRpnt->sr_sense_buffer[12] == 0x3A ) {
rscsi_disks[i].capacity = 0x1fffff;
sector_size = 512;
rscsi_disks[i].device->changed = 1;
@@ -728,7 +730,7 @@ static int sd_init_onedisk(int i)
/* Look for non-removable devices that return NOT_READY.
* Issue command to spin up drive for these cases. */
if (the_result && !rscsi_disks[i].device->removable &&
- SCpnt->sense_buffer[2] == NOT_READY) {
+ SRpnt->sr_sense_buffer[2] == NOT_READY) {
unsigned long time1;
if (!spintime) {
printk("%s: Spinning up disk...", nbuff);
@@ -737,12 +739,12 @@ static int sd_init_onedisk(int i)
cmd[1] |= 1; /* Return immediately */
memset((void *) &cmd[2], 0, 8);
cmd[4] = 1; /* Start spin cycle */
- SCpnt->cmd_len = 0;
- SCpnt->sense_buffer[0] = 0;
- SCpnt->sense_buffer[2] = 0;
+ SRpnt->sr_cmd_len = 0;
+ SRpnt->sr_sense_buffer[0] = 0;
+ SRpnt->sr_sense_buffer[2] = 0;
- SCpnt->sc_data_direction = SCSI_DATA_READ;
- scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
+ SRpnt->sr_data_direction = SCSI_DATA_READ;
+ scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
0/*512*/, SD_TIMEOUT, MAX_RETRIES);
}
spintime = 1;
@@ -768,15 +770,15 @@ static int sd_init_onedisk(int i)
cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
memset((void *) &cmd[2], 0, 8);
memset((void *) buffer, 0, 8);
- SCpnt->cmd_len = 0;
- SCpnt->sense_buffer[0] = 0;
- SCpnt->sense_buffer[2] = 0;
+ SRpnt->sr_cmd_len = 0;
+ SRpnt->sr_sense_buffer[0] = 0;
+ SRpnt->sr_sense_buffer[2] = 0;
- SCpnt->sc_data_direction = SCSI_DATA_READ;
- scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
+ SRpnt->sr_data_direction = SCSI_DATA_READ;
+ scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
8, SD_TIMEOUT, MAX_RETRIES);
- the_result = SCpnt->result;
+ the_result = SRpnt->sr_result;
retries--;
} while (the_result && retries);
@@ -806,7 +808,7 @@ static int sd_init_onedisk(int i)
);
if (driver_byte(the_result) & DRIVER_SENSE)
printk("%s : extended sense code = %1x \n",
- nbuff, SCpnt->sense_buffer[2] & 0xf);
+ nbuff, SRpnt->sr_sense_buffer[2] & 0xf);
else
printk("%s : sense not available. \n", nbuff);
@@ -818,7 +820,7 @@ static int sd_init_onedisk(int i)
/* Set dirty bit for removable devices if not ready - sometimes drives
* will not report this properly. */
if (rscsi_disks[i].device->removable &&
- SCpnt->sense_buffer[2] == NOT_READY)
+ SRpnt->sr_sense_buffer[2] == NOT_READY)
rscsi_disks[i].device->changed = 1;
} else {
@@ -919,16 +921,16 @@ static int sd_init_onedisk(int i)
cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
cmd[2] = 1; /* page code 1 ?? */
cmd[4] = 12;
- SCpnt->cmd_len = 0;
- SCpnt->sense_buffer[0] = 0;
- SCpnt->sense_buffer[2] = 0;
+ SRpnt->sr_cmd_len = 0;
+ SRpnt->sr_sense_buffer[0] = 0;
+ SRpnt->sr_sense_buffer[2] = 0;
/* same code as READCAPA !! */
- SCpnt->sc_data_direction = SCSI_DATA_READ;
- scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
+ SRpnt->sr_data_direction = SCSI_DATA_READ;
+ scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
512, SD_TIMEOUT, MAX_RETRIES);
- the_result = SCpnt->result;
+ the_result = SRpnt->sr_result;
if (the_result) {
printk("%s: test WP failed, assume Write Protected\n", nbuff);
@@ -940,12 +942,12 @@ static int sd_init_onedisk(int i)
}
} /* check for write protect */
- SCpnt->device->ten = 1;
- SCpnt->device->remap = 1;
- SCpnt->device->sector_size = sector_size;
+ SRpnt->sr_device->ten = 1;
+ SRpnt->sr_device->remap = 1;
+ SRpnt->sr_device->sector_size = sector_size;
/* Wake up a process waiting for device */
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
scsi_free(buffer, 512);
return i;
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 781cde85a..dc6712247 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -486,7 +486,7 @@ void get_sectorsize(int i)
SRpnt->sr_data_direction = SCSI_DATA_READ;
scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
- 512, SR_TIMEOUT, MAX_RETRIES);
+ 8, SR_TIMEOUT, MAX_RETRIES);
the_result = SRpnt->sr_result;
retries--;
@@ -663,7 +663,7 @@ static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command
/* do the locking and issue the command */
SRpnt->sr_request.rq_dev = cdi->dev;
- /* scsi_wait_cmd sets the command length */
+ /* scsi_wait_req sets the command length */
SRpnt->sr_cmd_len = 0;
SRpnt->sr_data_direction = cgc->data_direction;
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 1de7686dc..8df062781 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -6,12 +6,13 @@
Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
Contribution and ideas from several people including (in alphabetical
order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer,
- Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale.
+ Michael Leodolter, Eyal Lebedinsky, Michael Schaefer, J"org Weule, and
+ Eric Youngdale.
Copyright 1992 - 2000 Kai Makisara
email Kai.Makisara@metla.fi
- Last modified: Tue Feb 29 20:47:03 2000 by makisara@kai.makisara.local
+ Last modified: Mon Mar 13 21:15:29 2000 by makisara@kai.makisara.local
Some small formal changes - aeb, 950809
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
@@ -125,14 +126,17 @@ DEB( static int debugging = DEBUG; )
24 bits) */
#define SET_DENS_AND_BLK 0x10001
+#define ST_DEV_ARR_LUMP 6
+static rwlock_t st_dev_arr_lock = RW_LOCK_UNLOCKED;
+
static int st_nbr_buffers;
-static ST_buffer **st_buffers;
+static ST_buffer **st_buffers = NULL;
static int st_buffer_size = ST_BUFFER_SIZE;
static int st_write_threshold = ST_WRITE_THRESHOLD;
static int st_max_buffers = ST_MAX_BUFFERS;
static int st_max_sg_segs = ST_MAX_SG;
-static Scsi_Tape *scsi_tapes = NULL;
+static Scsi_Tape **scsi_tapes = NULL;
static int modes_defined = FALSE;
@@ -161,16 +165,14 @@ struct Scsi_Device_Template st_template =
static int st_compression(Scsi_Tape *, int);
-static int find_partition(struct inode *);
-static int update_partition(struct inode *);
+static int find_partition(Scsi_Tape *);
+static int update_partition(Scsi_Tape *);
-static int st_int_ioctl(struct inode *inode, unsigned int cmd_in,
- unsigned long arg);
+static int st_int_ioctl(Scsi_Tape *, unsigned int, unsigned long);
-
/* Convert the result to success code */
-static int st_chk_result(Scsi_Request * SRpnt)
+static int st_chk_result(Scsi_Tape *STp, Scsi_Request * SRpnt)
{
int dev;
int result = SRpnt->sr_result;
@@ -184,8 +186,10 @@ static int st_chk_result(Scsi_Request * SRpnt)
if (driver_byte(result) & DRIVER_SENSE)
scode = sense[2] & 0x0f;
- else
+ else {
+ sense[0] = 0;
scode = 0;
+ }
dev = TAPE_NR(SRpnt->sr_request.rq_dev);
DEB(
@@ -224,8 +228,8 @@ static int st_chk_result(Scsi_Request * SRpnt)
&& SRpnt->sr_cmnd[0] != WRITE_FILEMARKS
#endif
) {
- scsi_tapes[dev].recover_count++;
- scsi_tapes[dev].mt_status->mt_erreg += (1 << MT_ST_SOFTERR_SHIFT);
+ STp->recover_count++;
+ STp->recover_reg++;
DEB(
if (debugging) {
@@ -236,7 +240,7 @@ static int st_chk_result(Scsi_Request * SRpnt)
else
stp = "ioctl";
printk(ST_DEB_MSG "st%d: Recovered %s error (%d).\n", dev, stp,
- scsi_tapes[dev].recover_count);
+ STp->recover_count);
} ) /* end DEB */
if ((sense[2] & 0xe0) == 0)
@@ -254,7 +258,9 @@ static void st_sleep_done(Scsi_Cmnd * SCpnt)
Scsi_Tape *STp;
if ((st_nbr = TAPE_NR(SCpnt->request.rq_dev)) < st_template.nr_dev) {
- STp = &(scsi_tapes[st_nbr]);
+ read_lock(&st_dev_arr_lock);
+ STp = scsi_tapes[st_nbr];
+ read_unlock(&st_dev_arr_lock);
if ((STp->buffer)->writing &&
(SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
(SCpnt->sense_buffer[2] & 0x40)) {
@@ -330,7 +336,7 @@ static Scsi_Request *
if (do_wait) {
down(SRpnt->sr_request.sem);
SRpnt->sr_request.sem = NULL;
- (STp->buffer)->syscall_result = st_chk_result(SRpnt);
+ (STp->buffer)->syscall_result = st_chk_result(STp, SRpnt);
}
return SRpnt;
}
@@ -354,7 +360,7 @@ static void write_behind_check(Scsi_Tape * STp)
down(&(STp->sem));
(STp->buffer)->last_SRpnt->sr_request.sem = NULL;
- (STp->buffer)->syscall_result = st_chk_result((STp->buffer)->last_SRpnt);
+ (STp->buffer)->syscall_result = st_chk_result(STp, (STp->buffer)->last_SRpnt);
scsi_release_request((STp->buffer)->last_SRpnt);
if (STbuffer->writing < STbuffer->buffer_bytes)
@@ -491,15 +497,12 @@ static int flush_write_buffer(Scsi_Tape * STp)
/* Flush the tape buffer. The tape will be positioned correctly unless
seek_next is true. */
-static int flush_buffer(struct inode *inode, struct file *filp, int seek_next)
+static int flush_buffer(Scsi_Tape *STp, int seek_next)
{
int backspace, result;
- Scsi_Tape *STp;
ST_buffer *STbuffer;
ST_partstat *STps;
- int dev = TAPE_NR(inode->i_rdev);
- STp = &(scsi_tapes[dev]);
STbuffer = STp->buffer;
/*
@@ -538,7 +541,7 @@ static int flush_buffer(struct inode *inode, struct file *filp, int seek_next)
}
}
if (!result && backspace > 0)
- result = st_int_ioctl(inode, MTBSR, backspace);
+ result = st_int_ioctl(STp, MTBSR, backspace);
} else if (STps->eof == ST_FM_HIT) {
if (STps->drv_file >= 0)
STps->drv_file++;
@@ -550,11 +553,11 @@ static int flush_buffer(struct inode *inode, struct file *filp, int seek_next)
}
/* Set the mode parameters */
-static int set_mode_densblk(struct inode *inode, Scsi_Tape * STp, ST_mode * STm)
+static int set_mode_densblk(Scsi_Tape * STp, ST_mode * STm)
{
int set_it = FALSE;
unsigned long arg;
- int dev = TAPE_NR(inode->i_rdev);
+ int dev = TAPE_NR(STp->devt);
if (!STp->density_changed &&
STm->default_density >= 0 &&
@@ -572,7 +575,7 @@ static int set_mode_densblk(struct inode *inode, Scsi_Tape * STp, ST_mode * STm)
} else
arg |= STp->block_size;
if (set_it &&
- st_int_ioctl(inode, SET_DENS_AND_BLK, arg)) {
+ st_int_ioctl(STp, SET_DENS_AND_BLK, arg)) {
printk(KERN_WARNING
"st%d: Can't set default block size to %d bytes and density %x.\n",
dev, STm->default_blksize, STm->default_density);
@@ -597,22 +600,26 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
int dev = TAPE_NR(inode->i_rdev);
int mode = TAPE_MODE(inode->i_rdev);
- if (dev >= st_template.dev_max || !scsi_tapes[dev].device)
+ read_lock(&st_dev_arr_lock);
+ STp = scsi_tapes[dev];
+ if (dev >= st_template.dev_max || STp == NULL) {
+ read_unlock(&st_dev_arr_lock);
return (-ENXIO);
+ }
+ read_unlock(&st_dev_arr_lock);
- if (!scsi_block_when_processing_errors(scsi_tapes[dev].device)) {
+ if (!scsi_block_when_processing_errors(STp->device)) {
return -ENXIO;
}
- STp = &(scsi_tapes[dev]);
if (STp->in_use) {
DEB( printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); )
return (-EBUSY);
}
STp->in_use = 1;
- STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
+ STp->rew_at_close = STp->autorew_dev = (MINOR(inode->i_rdev) & 0x80) == 0;
- if (scsi_tapes[dev].device->host->hostt->module)
- __MOD_INC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+ if (STp->device->host->hostt->module)
+ __MOD_INC_USE_COUNT(STp->device->host->hostt->module);
if (st_template.module)
__MOD_INC_USE_COUNT(st_template.module);
@@ -626,10 +633,14 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
/* Allocate a buffer for this user */
need_dma_buffer = STp->restr_dma;
+ read_lock(&st_dev_arr_lock);
for (i = 0; i < st_nbr_buffers; i++)
if (!st_buffers[i]->in_use &&
- (!need_dma_buffer || st_buffers[i]->dma))
+ (!need_dma_buffer || st_buffers[i]->dma)) {
+ STp->buffer = st_buffers[i];
break;
+ }
+ read_unlock(&st_dev_arr_lock);
if (i >= st_nbr_buffers) {
STp->buffer = new_tape_buffer(FALSE, need_dma_buffer);
if (STp->buffer == NULL) {
@@ -637,8 +648,8 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
retval = (-EBUSY);
goto err_out;
}
- } else
- STp->buffer = st_buffers[i];
+ }
+
(STp->buffer)->in_use = 1;
(STp->buffer)->writing = 0;
(STp->buffer)->syscall_result = 0;
@@ -824,7 +835,7 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
partition support has been enabled. */
DEBC(printk(ST_DEB_MSG
"st%d: Updating partition number in status.\n", dev));
- if ((STp->partition = find_partition(inode)) < 0) {
+ if ((STp->partition = find_partition(STp)) < 0) {
retval = STp->partition;
goto err_out;
}
@@ -836,11 +847,11 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
STp->density_changed = STp->blksize_changed = FALSE;
STp->compression_changed = FALSE;
if (!(STm->defaults_for_writes) &&
- (retval = set_mode_densblk(inode, STp, STm)) < 0)
+ (retval = set_mode_densblk(STp, STm)) < 0)
goto err_out;
if (STp->default_drvbuffer != 0xff) {
- if (st_int_ioctl(inode, MTSETDRVBUFFER, STp->default_drvbuffer))
+ if (st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer))
printk(KERN_WARNING
"st%d: Can't set default drive buffering to %d.\n",
dev, STp->default_drvbuffer);
@@ -855,8 +866,8 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
STp->buffer = NULL;
}
STp->in_use = 0;
- if (scsi_tapes[dev].device->host->hostt->module)
- __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+ if (STp->device->host->hostt->module)
+ __MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
if (st_template.module)
__MOD_DEC_USE_COUNT(st_template.module);
return retval;
@@ -882,7 +893,9 @@ static int scsi_tape_flush(struct file *filp)
return 0;
dev = TAPE_NR(devt);
- STp = &(scsi_tapes[dev]);
+ read_lock(&st_dev_arr_lock);
+ STp = scsi_tapes[dev];
+ read_unlock(&st_dev_arr_lock);
STm = &(STp->modes[STp->current_mode]);
STps = &(STp->ps[STp->partition]);
@@ -893,7 +906,7 @@ static int scsi_tape_flush(struct file *filp)
}
if (STp->can_partitions &&
- (result2 = update_partition(inode)) < 0) {
+ (result2 = update_partition(STp)) < 0) {
DEBC(printk(ST_DEB_MSG
"st%d: update_partition at close failed.\n", dev));
if (result == 0)
@@ -950,7 +963,7 @@ static int scsi_tape_flush(struct file *filp)
STps = &(STp->ps[STp->partition]);
if (!STm->sysv || STps->rw != ST_READING) {
if (STp->can_bsr)
- result = flush_buffer(inode, filp, 0);
+ result = flush_buffer(STp, 0);
else if (STps->eof == ST_FM_HIT) {
result = cross_eof(STp, FALSE);
if (result) {
@@ -973,7 +986,7 @@ static int scsi_tape_flush(struct file *filp)
out:
if (STp->rew_at_close) {
- result2 = st_int_ioctl(inode, MTREW, 1);
+ result2 = st_int_ioctl(STp, MTREW, 1);
if (result == 0)
result = result2;
}
@@ -991,10 +1004,12 @@ static int scsi_tape_close(struct inode *inode, struct file *filp)
int dev;
dev = TAPE_NR(devt);
- STp = &(scsi_tapes[dev]);
+ read_lock(&st_dev_arr_lock);
+ STp = scsi_tapes[dev];
+ read_unlock(&st_dev_arr_lock);
if (STp->door_locked == ST_LOCKED_AUTO)
- st_int_ioctl(inode, MTUNLOCK, 0);
+ st_int_ioctl(STp, MTUNLOCK, 0);
if (STp->buffer != NULL) {
normalize_buffer(STp->buffer);
@@ -1002,8 +1017,8 @@ static int scsi_tape_close(struct inode *inode, struct file *filp)
}
STp->in_use = 0;
- if (scsi_tapes[dev].device->host->hostt->module)
- __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+ if (STp->device->host->hostt->module)
+ __MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
if (st_template.module)
__MOD_DEC_USE_COUNT(st_template.module);
@@ -1028,7 +1043,9 @@ static ssize_t
ST_partstat *STps;
int dev = TAPE_NR(inode->i_rdev);
- STp = &(scsi_tapes[dev]);
+ read_lock(&st_dev_arr_lock);
+ STp = scsi_tapes[dev];
+ read_unlock(&st_dev_arr_lock);
/*
* If we are in the middle of error recovery, don't let anyone
@@ -1079,7 +1096,7 @@ static ssize_t
}
if (STp->can_partitions &&
- (retval = update_partition(inode)) < 0)
+ (retval = update_partition(STp)) < 0)
return retval;
STps = &(STp->ps[STp->partition]);
@@ -1092,17 +1109,17 @@ static ssize_t
return (-EOVERFLOW);
if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
- !st_int_ioctl(inode, MTLOCK, 0))
+ !st_int_ioctl(STp, MTLOCK, 0))
STp->door_locked = ST_LOCKED_AUTO;
if (STps->rw == ST_READING) {
- retval = flush_buffer(inode, filp, 0);
+ retval = flush_buffer(STp, 0);
if (retval)
return retval;
STps->rw = ST_WRITING;
} else if (STps->rw != ST_WRITING &&
STps->drv_file == 0 && STps->drv_block == 0) {
- if ((retval = set_mode_densblk(inode, STp, STm)) < 0)
+ if ((retval = set_mode_densblk(STp, STm)) < 0)
return retval;
if (STm->default_compression != ST_DONT_TOUCH &&
!(STp->compression_changed)) {
@@ -1328,21 +1345,19 @@ static ssize_t
/* Read data from the tape. Returns zero in the normal case, one if the
eof status has changed, and the negative error code in case of a
fatal error. Otherwise updates the buffer and the eof state. */
-static long read_tape(struct inode *inode, long count, Scsi_Request ** aSRpnt)
+static long read_tape(Scsi_Tape *STp, long count, Scsi_Request ** aSRpnt)
{
int transfer, blks, bytes;
static unsigned char cmd[MAX_COMMAND_SIZE];
Scsi_Request *SRpnt;
- Scsi_Tape *STp;
ST_mode *STm;
ST_partstat *STps;
- int dev = TAPE_NR(inode->i_rdev);
+ int dev = TAPE_NR(STp->devt);
int retval = 0;
if (count == 0)
return 0;
- STp = &(scsi_tapes[dev]);
STm = &(STp->modes[STp->current_mode]);
STps = &(STp->ps[STp->partition]);
if (STps->eof == ST_FM_HIT)
@@ -1418,7 +1433,7 @@ static long read_tape(struct inode *inode, long count, Scsi_Request ** aSRpnt)
printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev);
if (STps->drv_block >= 0)
STps->drv_block += blks - transfer + 1;
- st_int_ioctl(inode, MTBSR, 1);
+ st_int_ioctl(STp, MTBSR, 1);
return (-EIO);
}
/* We have some data, deliver it */
@@ -1429,7 +1444,7 @@ static long read_tape(struct inode *inode, long count, Scsi_Request ** aSRpnt)
dev, count, (STp->buffer)->buffer_bytes));
if (STps->drv_block >= 0)
STps->drv_block += 1;
- if (st_int_ioctl(inode, MTBSR, 1))
+ if (st_int_ioctl(STp, MTBSR, 1))
return (-EIO);
}
} else if (SRpnt->sr_sense_buffer[2] & 0x80) { /* FM overrides EOM */
@@ -1509,7 +1524,9 @@ static ssize_t
ST_partstat *STps;
int dev = TAPE_NR(inode->i_rdev);
- STp = &(scsi_tapes[dev]);
+ read_lock(&st_dev_arr_lock);
+ STp = scsi_tapes[dev];
+ read_unlock(&st_dev_arr_lock);
/*
* If we are in the middle of error recovery, don't let anyone
@@ -1542,7 +1559,7 @@ static ssize_t
} ) /* end DEB */
if (STp->can_partitions &&
- (total = update_partition(inode)) < 0)
+ (total = update_partition(STp)) < 0)
return total;
if (STp->block_size == 0 &&
@@ -1555,12 +1572,12 @@ static ssize_t
return (-EIO); /* Read must be integral number of blocks */
if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
- !st_int_ioctl(inode, MTLOCK, 0))
+ !st_int_ioctl(STp, MTLOCK, 0))
STp->door_locked = ST_LOCKED_AUTO;
STps = &(STp->ps[STp->partition]);
if (STps->rw == ST_WRITING) {
- transfer = flush_buffer(inode, filp, 0);
+ transfer = flush_buffer(STp, 0);
if (transfer)
return transfer;
STps->rw = ST_READING;
@@ -1596,7 +1613,7 @@ static ssize_t
/* Get new data if the buffer is empty */
if ((STp->buffer)->buffer_bytes == 0) {
- special = read_tape(inode, count - total, &SRpnt);
+ special = read_tape(STp, count - total, &SRpnt);
if (special < 0) { /* No need to continue read */
if (SRpnt != NULL) {
scsi_release_request(SRpnt);
@@ -1684,15 +1701,13 @@ static void st_log_options(Scsi_Tape * STp, ST_mode * STm, int dev)
}
-static int st_set_options(struct inode *inode, long options)
+static int st_set_options(Scsi_Tape *STp, long options)
{
int value;
long code;
- Scsi_Tape *STp;
ST_mode *STm;
- int dev = TAPE_NR(inode->i_rdev);
+ int dev = TAPE_NR(STp->devt);
- STp = &(scsi_tapes[dev]);
STm = &(STp->modes[STp->current_mode]);
if (!STm->defined) {
memcpy(STm, &(STp->modes[0]), sizeof(ST_mode));
@@ -1823,95 +1838,146 @@ static int st_set_options(struct inode *inode, long options)
return 0;
}
+#define MODE_HEADER_LENGTH 4
-#define COMPRESSION_PAGE 0x0f
-#define COMPRESSION_PAGE_LENGTH 16
+/* Mode header and page byte offsets */
+#define MH_OFF_DATA_LENGTH 0
+#define MH_OFF_MEDIUM_TYPE 1
+#define MH_OFF_DEV_SPECIFIC 2
+#define MH_OFF_BDESCS_LENGTH 3
+#define MP_OFF_PAGE_NBR 0
+#define MP_OFF_PAGE_LENGTH 1
-#define MODE_HEADER_LENGTH 4
+/* Mode header and page bit masks */
+#define MH_BIT_WP 0x80
+#define MP_MSK_PAGE_NBR 0x3f
-#define DCE_MASK 0x80
-#define DCC_MASK 0x40
-#define RED_MASK 0x60
+/* Don't return block descriptors */
+#define MODE_SENSE_OMIT_BDESCS 0x08
+#define MODE_SELECT_PAGE_FORMAT 0x10
-/* Control the compression with mode page 15. Algorithm not changed if zero. */
-static int st_compression(Scsi_Tape * STp, int state)
+/* Read a mode page into the tape buffer. The block descriptors are included
+ if incl_block_descs is true. */
+static int read_mode_page(Scsi_Tape *STp, int page, int omit_block_descs)
{
- int dev;
unsigned char cmd[MAX_COMMAND_SIZE];
Scsi_Request *SRpnt = NULL;
- if (STp->ready != ST_READY)
- return (-EIO);
-
- /* Read the current page contents */
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = MODE_SENSE;
- cmd[1] = 8;
- cmd[2] = COMPRESSION_PAGE;
- cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH;
+ if (omit_block_descs)
+ cmd[1] = MODE_SENSE_OMIT_BDESCS;
+ cmd[2] = page;
+ cmd[4] = 255;
SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ,
STp->timeout, 0, TRUE);
if (SRpnt == NULL)
return (STp->buffer)->syscall_result;
- dev = TAPE_NR(SRpnt->sr_request.rq_dev);
+ scsi_release_request(SRpnt);
- if ((STp->buffer)->syscall_result != 0) {
+ return (STp->buffer)->syscall_result;
+}
+
+
+/* Send the mode page in the tape buffer to the drive. Assumes that the mode data
+ in the buffer is correctly formatted. */
+static int write_mode_page(Scsi_Tape *STp, int page)
+{
+ int pgo;
+ unsigned char cmd[MAX_COMMAND_SIZE];
+ Scsi_Request *SRpnt = NULL;
+
+ memset(cmd, 0, MAX_COMMAND_SIZE);
+ cmd[0] = MODE_SELECT;
+ cmd[1] = MODE_SELECT_PAGE_FORMAT;
+ pgo = MODE_HEADER_LENGTH + (STp->buffer)->b_data[MH_OFF_BDESCS_LENGTH];
+ cmd[4] = pgo + (STp->buffer)->b_data[pgo + MP_OFF_PAGE_LENGTH] + 2;
+
+ /* Clear reserved fields */
+ (STp->buffer)->b_data[MH_OFF_DATA_LENGTH] = 0;
+ (STp->buffer)->b_data[MH_OFF_MEDIUM_TYPE] = 0;
+ (STp->buffer)->b_data[MH_OFF_DEV_SPECIFIC] &= ~MH_BIT_WP;
+ (STp->buffer)->b_data[pgo + MP_OFF_PAGE_NBR] &= MP_MSK_PAGE_NBR;
+
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE,
+ STp->timeout, 0, TRUE);
+ if (SRpnt == NULL)
+ return (STp->buffer)->syscall_result;
+
+ scsi_release_request(SRpnt);
+
+ return (STp->buffer)->syscall_result;
+}
+
+
+#define COMPRESSION_PAGE 0x0f
+#define COMPRESSION_PAGE_LENGTH 16
+
+#define CP_OFF_DCE_DCC 2
+
+#define DCE_MASK 0x80
+#define DCC_MASK 0x40
+#define RED_MASK 0x60
+
+
+/* Control the compression with mode page 15. Algorithm not changed if zero.
+
+ The block descriptors are read and written because Sony SDT-7000 does not
+ work without this (suggestion from Michael Schaefer <Michael.Schaefer@dlr.de>).
+ Including block descriptors should not cause any harm to other drives. */
+
+static int st_compression(Scsi_Tape * STp, int state)
+{
+ int retval;
+ int mpoffs; /* Offset to mode page start */
+ unsigned char *b_data = (STp->buffer)->b_data;
+ DEB( int dev = TAPE_NR(STp->devt); )
+
+ if (STp->ready != ST_READY)
+ return (-EIO);
+
+ /* Read the current page contents */
+ retval = read_mode_page(STp, COMPRESSION_PAGE, FALSE);
+ if (retval) {
DEBC(printk(ST_DEB_MSG "st%d: Compression mode page not supported.\n",
dev));
- scsi_release_request(SRpnt);
- SRpnt = NULL;
return (-EIO);
}
+
+ mpoffs = MODE_HEADER_LENGTH + b_data[MH_OFF_BDESCS_LENGTH];
DEBC(printk(ST_DEB_MSG "st%d: Compression state is %d.\n", dev,
- ((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCE_MASK ? 1 : 0)));
+ (b_data[mpoffs + CP_OFF_DCE_DCC] & DCE_MASK ? 1 : 0)));
/* Check if compression can be changed */
- if (((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCC_MASK) == 0) {
+ if ((b_data[mpoffs + 2] & DCC_MASK) == 0) {
DEBC(printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev));
- scsi_release_request(SRpnt);
- SRpnt = NULL;
return (-EIO);
}
/* Do the change */
if (state)
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] |= DCE_MASK;
+ b_data[mpoffs + CP_OFF_DCE_DCC] |= DCE_MASK;
else
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] &= ~DCE_MASK;
+ b_data[mpoffs + CP_OFF_DCE_DCC] &= ~DCE_MASK;
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SELECT;
- cmd[1] = 0x10;
- cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
- (STp->buffer)->b_data[0] = 0; /* Reserved data length */
- (STp->buffer)->b_data[1] = 0; /* Reserved media type byte */
- (STp->buffer)->b_data[MODE_HEADER_LENGTH] &= 0x3f;
- SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE,
- STp->timeout, 0, TRUE);
-
- if ((STp->buffer)->syscall_result != 0) {
+ retval = write_mode_page(STp, COMPRESSION_PAGE);
+ if (retval) {
DEBC(printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev));
- scsi_release_request(SRpnt);
- SRpnt = NULL;
return (-EIO);
}
DEBC(printk(ST_DEB_MSG "st%d: Compression state changed to %d.\n",
dev, state));
- scsi_release_request(SRpnt);
- SRpnt = NULL;
STp->compression_changed = TRUE;
return 0;
}
/* Internal ioctl function */
-static int st_int_ioctl(struct inode *inode,
- unsigned int cmd_in, unsigned long arg)
+static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
{
int timeout;
long ltmp;
@@ -1919,13 +1985,11 @@ static int st_int_ioctl(struct inode *inode,
int chg_eof = TRUE;
unsigned char cmd[MAX_COMMAND_SIZE];
Scsi_Request *SRpnt;
- Scsi_Tape *STp;
ST_partstat *STps;
int fileno, blkno, at_sm, undone;
int datalen = 0, direction = SCSI_DATA_NONE;
- int dev = TAPE_NR(inode->i_rdev);
+ int dev = TAPE_NR(STp->devt);
- STp = &(scsi_tapes[dev]);
if (STp->ready != ST_READY && cmd_in != MTLOAD) {
if (STp->ready == ST_NO_TAPE)
return (-ENOMEDIUM);
@@ -2120,7 +2184,7 @@ static int st_int_ioctl(struct inode *inode,
case MTEOM:
if (!STp->fast_mteom) {
/* space to the end of tape */
- ioctl_result = st_int_ioctl(inode, MTFSF, 0x3fff);
+ ioctl_result = st_int_ioctl(STp, MTFSF, 0x3fff);
fileno = STps->drv_file;
if (STps->eof >= ST_EOD_1)
return 0;
@@ -2247,9 +2311,9 @@ static int st_int_ioctl(struct inode *inode,
STp->door_locked = ST_UNLOCKED;
if (cmd_in == MTBSFM)
- ioctl_result = st_int_ioctl(inode, MTFSF, 1);
+ ioctl_result = st_int_ioctl(STp, MTFSF, 1);
else if (cmd_in == MTFSFM)
- ioctl_result = st_int_ioctl(inode, MTBSF, 1);
+ ioctl_result = st_int_ioctl(STp, MTBSF, 1);
if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
STp->block_size = arg & MT_ST_BLKSIZE_MASK;
@@ -2275,7 +2339,7 @@ static int st_int_ioctl(struct inode *inode,
if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
STp->rew_at_close = 0;
else if (cmd_in == MTLOAD) {
- STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
+ STp->rew_at_close = STp->autorew_dev;
for (i = 0; i < ST_NBR_PARTITIONS; i++) {
STp->ps[i].rw = ST_IDLE;
STp->ps[i].last_block_valid = FALSE;
@@ -2368,16 +2432,14 @@ static int st_int_ioctl(struct inode *inode,
/* Get the tape position. If bt == 2, arg points into a kernel space mt_loc
structure. */
-static int get_location(struct inode *inode, unsigned int *block, int *partition,
+static int get_location(Scsi_Tape *STp, unsigned int *block, int *partition,
int logical)
{
- Scsi_Tape *STp;
- int dev = TAPE_NR(inode->i_rdev);
int result;
unsigned char scmd[MAX_COMMAND_SIZE];
Scsi_Request *SRpnt;
+ DEB( int dev = TAPE_NR(STp->devt); )
- STp = &(scsi_tapes[dev]);
if (STp->ready != ST_READY)
return (-EIO);
@@ -2430,19 +2492,17 @@ static int get_location(struct inode *inode, unsigned int *block, int *partition
/* Set the tape block and partition. Negative partition means that only the
block should be set in vendor specific way. */
-static int set_location(struct inode *inode, unsigned int block, int partition,
+static int set_location(Scsi_Tape *STp, unsigned int block, int partition,
int logical)
{
- Scsi_Tape *STp;
ST_partstat *STps;
- int dev = TAPE_NR(inode->i_rdev);
int result, p;
unsigned int blk;
int timeout;
unsigned char scmd[MAX_COMMAND_SIZE];
Scsi_Request *SRpnt;
+ DEB( int dev = TAPE_NR(STp->devt); )
- STp = &(scsi_tapes[dev]);
if (STp->ready != ST_READY)
return (-EIO);
timeout = STp->long_timeout;
@@ -2458,7 +2518,7 @@ static int set_location(struct inode *inode, unsigned int block, int partition,
partition >= ST_NBR_PARTITIONS)
return (-EINVAL);
if (partition != STp->partition) {
- if (get_location(inode, &blk, &p, 1))
+ if (get_location(STp, &blk, &p, 1))
STps->last_block_valid = FALSE;
else {
STps->last_block_valid = TRUE;
@@ -2508,7 +2568,7 @@ static int set_location(struct inode *inode, unsigned int block, int partition,
result = (-EIO);
if (STp->can_partitions &&
(STp->device)->scsi_level >= SCSI_2 &&
- (p = find_partition(inode)) >= 0)
+ (p = find_partition(STp)) >= 0)
STp->partition = p;
} else {
if (STp->can_partitions) {
@@ -2535,12 +2595,12 @@ static int set_location(struct inode *inode, unsigned int block, int partition,
/* Find the current partition number for the drive status. Called from open and
returns either partition number of negative error code. */
-static int find_partition(struct inode *inode)
+static int find_partition(Scsi_Tape *STp)
{
int i, partition;
unsigned int block;
- if ((i = get_location(inode, &block, &partition, 1)) < 0)
+ if ((i = get_location(STp, &block, &partition, 1)) < 0)
return i;
if (partition >= ST_NBR_PARTITIONS)
return (-EIO);
@@ -2549,60 +2609,52 @@ static int find_partition(struct inode *inode)
/* Change the partition if necessary */
-static int update_partition(struct inode *inode)
+static int update_partition(Scsi_Tape *STp)
{
- int dev = TAPE_NR(inode->i_rdev);
- Scsi_Tape *STp;
ST_partstat *STps;
- STp = &(scsi_tapes[dev]);
if (STp->partition == STp->new_partition)
return 0;
STps = &(STp->ps[STp->new_partition]);
if (!STps->last_block_valid)
STps->last_block_visited = 0;
- return set_location(inode, STps->last_block_visited, STp->new_partition, 1);
+ return set_location(STp, STps->last_block_visited, STp->new_partition, 1);
}
/* Functions for reading and writing the medium partition mode page. These
seem to work with Wangtek 6200HS and HP C1533A. */
#define PART_PAGE 0x11
-#define PART_PAGE_LENGTH 10
+#define PART_PAGE_FIXED_LENGTH 8
+
+#define PP_OFF_MAX_ADD_PARTS 2
+#define PP_OFF_NBR_ADD_PARTS 3
+#define PP_OFF_FLAGS 4
+#define PP_OFF_PART_UNITS 6
+#define PP_OFF_RESERVED 7
+
+#define PP_BIT_IDP 0x20
+#define PP_MSK_PSUM_MB 0x10
/* Get the number of partitions on the tape. As a side effect reads the
mode page into the tape buffer. */
-static int nbr_partitions(struct inode *inode)
+static int nbr_partitions(Scsi_Tape *STp)
{
- int dev = TAPE_NR(inode->i_rdev), result;
- Scsi_Tape *STp;
- Scsi_Request *SRpnt = NULL;
- unsigned char cmd[MAX_COMMAND_SIZE];
+ int result;
+ DEB( int dev = TAPE_NR(STp->devt) );
- STp = &(scsi_tapes[dev]);
if (STp->ready != ST_READY)
return (-EIO);
- memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SENSE;
- cmd[1] = 8; /* Page format */
- cmd[2] = PART_PAGE;
- cmd[4] = 200;
-
- SRpnt = st_do_scsi(SRpnt, STp, cmd, 200, SCSI_DATA_READ, STp->timeout,
- MAX_READY_RETRIES, TRUE);
- if (SRpnt == NULL)
- return (STp->buffer)->syscall_result;
+ result = read_mode_page(STp, PART_PAGE, TRUE);
- scsi_release_request(SRpnt);
- SRpnt = NULL;
-
- if ((STp->buffer)->syscall_result != 0) {
+ if (result) {
DEBC(printk(ST_DEB_MSG "st%d: Can't read medium partition page.\n",
dev));
result = (-EIO);
} else {
- result = (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] + 1;
+ result = (STp->buffer)->b_data[MODE_HEADER_LENGTH +
+ PP_OFF_NBR_ADD_PARTS] + 1;
DEBC(printk(ST_DEB_MSG "st%d: Number of partitions %d.\n", dev, result));
}
@@ -2611,62 +2663,69 @@ static int nbr_partitions(struct inode *inode)
/* Partition the tape into two partitions if size > 0 or one partition if
- size == 0 */
-static int partition_tape(struct inode *inode, int size)
+ size == 0.
+
+ The block descriptors are read and written because Sony SDT-7000 does not
+ work without this (suggestion from Michael Schaefer <Michael.Schaefer@dlr.de>).
+
+ My HP C1533A drive returns only one partition size field. This is used to
+ set the size of partition 1. There is no size field for the default partition.
+ Michael Schaefer's Sony SDT-7000 returns two descriptors and the second is
+ used to set the size of partition 1 (this is what the SCSI-3 standard specifies).
+ The following algorithm is used to accomodate both drives: if the number of
+ partition size fields is greater than the maximum number of additional partitions
+ in the mode page, the second field is used. Otherwise the first field is used.
+ */
+static int partition_tape(Scsi_Tape *STp, int size)
{
- int dev = TAPE_NR(inode->i_rdev), result;
- int length;
- Scsi_Tape *STp;
- Scsi_Request *SRpnt = NULL;
- unsigned char cmd[MAX_COMMAND_SIZE], *bp;
+ int dev = TAPE_NR(STp->devt), result;
+ int pgo, psd_cnt, psdo;
+ unsigned char *bp;
- if ((result = nbr_partitions(inode)) < 0)
+ result = read_mode_page(STp, PART_PAGE, FALSE);
+ if (result) {
+ DEBC(printk(ST_DEB_MSG "st%d: Can't read partition mode page.\n", dev));
return result;
- STp = &(scsi_tapes[dev]);
-
+ }
/* The mode page is in the buffer. Let's modify it and write it. */
- bp = &((STp->buffer)->b_data[0]);
+ bp = (STp->buffer)->b_data;
+ pgo = MODE_HEADER_LENGTH + bp[MH_OFF_BDESCS_LENGTH];
+ DEBC(printk(ST_DEB_MSG "st%d: Partition page length is %d bytes.\n",
+ dev, bp[pgo + MP_OFF_PAGE_LENGTH] + 2));
+
+ psd_cnt = (bp[pgo + MP_OFF_PAGE_LENGTH] + 2 - PART_PAGE_FIXED_LENGTH) / 2;
+ psdo = pgo + PART_PAGE_FIXED_LENGTH;
+ if (psd_cnt > bp[pgo + PP_OFF_MAX_ADD_PARTS]) {
+ bp[psdo] = bp[psdo + 1] = 0xff; /* Rest of the tape */
+ psdo += 2;
+ }
+ memset(bp + psdo, 0, bp[pgo + PP_OFF_NBR_ADD_PARTS] * 2);
+
+ DEBC(printk("st%d: psd_cnt %d, max.parts %d, nbr_parts %d\n", dev,
+ psd_cnt, bp[pgo + PP_OFF_MAX_ADD_PARTS],
+ bp[pgo + PP_OFF_NBR_ADD_PARTS]));
+
if (size <= 0) {
- length = 8;
- bp[MODE_HEADER_LENGTH + 3] = 0;
+ bp[pgo + PP_OFF_NBR_ADD_PARTS] = 0;
DEBC(printk(ST_DEB_MSG "st%d: Formatting tape with one partition.\n",
dev));
} else {
- length = 10;
- bp[MODE_HEADER_LENGTH + 3] = 1;
- bp[MODE_HEADER_LENGTH + 8] = (size >> 8) & 0xff;
- bp[MODE_HEADER_LENGTH + 9] = size & 0xff;
+ bp[psdo] = (size >> 8) & 0xff;
+ bp[psdo + 1] = size & 0xff;
+ bp[pgo + 3] = 1;
DEBC(printk(ST_DEB_MSG
- "st%d: Formatting tape with two partition (1 = %d MB).\n",
+ "st%d: Formatting tape with two partitions (1 = %d MB).\n",
dev, size));
}
- bp[MODE_HEADER_LENGTH + 6] = 0;
- bp[MODE_HEADER_LENGTH + 7] = 0;
- bp[MODE_HEADER_LENGTH + 4] = 0x30; /* IDP | PSUM = MB */
-
- bp[0] = 0;
- bp[1] = 0;
- bp[MODE_HEADER_LENGTH] &= 0x3f;
- bp[MODE_HEADER_LENGTH + 1] = length - 2;
+ bp[pgo + PP_OFF_PART_UNITS] = 0;
+ bp[pgo + PP_OFF_RESERVED] = 0;
+ bp[pgo + PP_OFF_FLAGS] = PP_BIT_IDP | PP_MSK_PSUM_MB;
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SELECT;
- cmd[1] = 0x10;
- cmd[4] = length + MODE_HEADER_LENGTH;
-
- SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE,
- STp->long_timeout, MAX_READY_RETRIES, TRUE);
- if (SRpnt == NULL)
- return (STp->buffer)->syscall_result;
-
- scsi_release_request(SRpnt);
- SRpnt = NULL;
-
- if ((STp->buffer)->syscall_result != 0) {
+ result = write_mode_page(STp, PART_PAGE);
+ if (result) {
printk(KERN_INFO "st%d: Partitioning of tape failed.\n", dev);
result = (-EIO);
- } else
- result = 0;
+ }
return result;
}
@@ -2679,14 +2738,15 @@ static int st_ioctl(struct inode *inode, struct file *file,
{
int i, cmd_nr, cmd_type, bt;
unsigned int blk;
- struct mtop mtc;
- struct mtpos mt_pos;
Scsi_Tape *STp;
ST_mode *STm;
ST_partstat *STps;
int dev = TAPE_NR(inode->i_rdev);
- STp = &(scsi_tapes[dev]);
+ read_lock(&st_dev_arr_lock);
+ STp = scsi_tapes[dev];
+ read_unlock(&st_dev_arr_lock);
+
DEB(
if (debugging && !STp->in_use) {
printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
@@ -2709,6 +2769,8 @@ static int st_ioctl(struct inode *inode, struct file *file,
cmd_nr = _IOC_NR(cmd_in);
if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
+ struct mtop mtc;
+
if (_IOC_SIZE(cmd_in) != sizeof(mtc))
return (-EINVAL);
@@ -2751,7 +2813,7 @@ static int st_ioctl(struct inode *inode, struct file *file,
mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
mtc.mt_op == MTCOMPRESSION;
}
- i = flush_buffer(inode, file, i);
+ i = flush_buffer(STp, i);
if (i < 0)
return i;
} else {
@@ -2770,7 +2832,7 @@ static int st_ioctl(struct inode *inode, struct file *file,
STp->device->was_reset = 0;
if (STp->door_locked != ST_UNLOCKED &&
STp->door_locked != ST_LOCK_FAILS) {
- if (st_int_ioctl(inode, MTLOCK, 0)) {
+ if (st_int_ioctl(STp, MTLOCK, 0)) {
printk(KERN_NOTICE
"st%d: Could not relock door after bus reset.\n",
dev);
@@ -2785,18 +2847,18 @@ static int st_ioctl(struct inode *inode, struct file *file,
STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */
if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
- st_int_ioctl(inode, MTUNLOCK, 0); /* Ignore result! */
+ st_int_ioctl(STp, MTUNLOCK, 0); /* Ignore result! */
if (mtc.mt_op == MTSETDRVBUFFER &&
(mtc.mt_count & MT_ST_OPTIONS) != 0)
- return st_set_options(inode, mtc.mt_count);
+ return st_set_options(STp, mtc.mt_count);
if (mtc.mt_op == MTSETPART) {
if (!STp->can_partitions ||
mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS)
return (-EINVAL);
if (mtc.mt_count >= STp->nbr_partitions &&
- (STp->nbr_partitions = nbr_partitions(inode)) < 0)
+ (STp->nbr_partitions = nbr_partitions(STp)) < 0)
return (-EIO);
if (mtc.mt_count >= STp->nbr_partitions)
return (-EINVAL);
@@ -2807,8 +2869,8 @@ static int st_ioctl(struct inode *inode, struct file *file,
if (mtc.mt_op == MTMKPART) {
if (!STp->can_partitions)
return (-EINVAL);
- if ((i = st_int_ioctl(inode, MTREW, 0)) < 0 ||
- (i = partition_tape(inode, mtc.mt_count)) < 0)
+ if ((i = st_int_ioctl(STp, MTREW, 0)) < 0 ||
+ (i = partition_tape(STp, mtc.mt_count)) < 0)
return i;
for (i = 0; i < ST_NBR_PARTITIONS; i++) {
STp->ps[i].rw = ST_IDLE;
@@ -2822,93 +2884,97 @@ static int st_ioctl(struct inode *inode, struct file *file,
}
if (mtc.mt_op == MTSEEK) {
- i = set_location(inode, mtc.mt_count, STp->new_partition, 0);
+ i = set_location(STp, mtc.mt_count, STp->new_partition, 0);
if (!STp->can_partitions)
STp->ps[0].rw = ST_IDLE;
return i;
}
if (STp->can_partitions && STp->ready == ST_READY &&
- (i = update_partition(inode)) < 0)
+ (i = update_partition(STp)) < 0)
return i;
if (mtc.mt_op == MTCOMPRESSION)
return st_compression(STp, (mtc.mt_count & 1));
else
- return st_int_ioctl(inode, mtc.mt_op, mtc.mt_count);
+ return st_int_ioctl(STp, mtc.mt_op, mtc.mt_count);
}
if (!STm->defined)
return (-ENXIO);
- if ((i = flush_buffer(inode, file, FALSE)) < 0)
+ if ((i = flush_buffer(STp, FALSE)) < 0)
return i;
if (STp->can_partitions &&
- (i = update_partition(inode)) < 0)
+ (i = update_partition(STp)) < 0)
return i;
if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
+ struct mtget mt_status;
if (_IOC_SIZE(cmd_in) != sizeof(struct mtget))
return (-EINVAL);
- (STp->mt_status)->mt_dsreg =
+ mt_status.mt_type = STp->tape_type;
+ mt_status.mt_dsreg =
((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
- (STp->mt_status)->mt_blkno = STps->drv_block;
- (STp->mt_status)->mt_fileno = STps->drv_file;
+ mt_status.mt_blkno = STps->drv_block;
+ mt_status.mt_fileno = STps->drv_file;
if (STp->block_size != 0) {
if (STps->rw == ST_WRITING)
- (STp->mt_status)->mt_blkno +=
+ mt_status.mt_blkno +=
(STp->buffer)->buffer_bytes / STp->block_size;
else if (STps->rw == ST_READING)
- (STp->mt_status)->mt_blkno -=
+ mt_status.mt_blkno -=
((STp->buffer)->buffer_bytes +
STp->block_size - 1) / STp->block_size;
}
- (STp->mt_status)->mt_gstat = 0;
+ mt_status.mt_gstat = 0;
if (STp->drv_write_prot)
- (STp->mt_status)->mt_gstat |= GMT_WR_PROT(0xffffffff);
- if ((STp->mt_status)->mt_blkno == 0) {
- if ((STp->mt_status)->mt_fileno == 0)
- (STp->mt_status)->mt_gstat |= GMT_BOT(0xffffffff);
+ mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff);
+ if (mt_status.mt_blkno == 0) {
+ if (mt_status.mt_fileno == 0)
+ mt_status.mt_gstat |= GMT_BOT(0xffffffff);
else
- (STp->mt_status)->mt_gstat |= GMT_EOF(0xffffffff);
+ mt_status.mt_gstat |= GMT_EOF(0xffffffff);
}
- (STp->mt_status)->mt_resid = STp->partition;
+ mt_status.mt_erreg = (STp->recover_reg << MT_ST_SOFTERR_SHIFT);
+ mt_status.mt_resid = STp->partition;
if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
- (STp->mt_status)->mt_gstat |= GMT_EOT(0xffffffff);
+ mt_status.mt_gstat |= GMT_EOT(0xffffffff);
else if (STps->eof >= ST_EOM_OK)
- (STp->mt_status)->mt_gstat |= GMT_EOD(0xffffffff);
+ mt_status.mt_gstat |= GMT_EOD(0xffffffff);
if (STp->density == 1)
- (STp->mt_status)->mt_gstat |= GMT_D_800(0xffffffff);
+ mt_status.mt_gstat |= GMT_D_800(0xffffffff);
else if (STp->density == 2)
- (STp->mt_status)->mt_gstat |= GMT_D_1600(0xffffffff);
+ mt_status.mt_gstat |= GMT_D_1600(0xffffffff);
else if (STp->density == 3)
- (STp->mt_status)->mt_gstat |= GMT_D_6250(0xffffffff);
+ mt_status.mt_gstat |= GMT_D_6250(0xffffffff);
if (STp->ready == ST_READY)
- (STp->mt_status)->mt_gstat |= GMT_ONLINE(0xffffffff);
+ mt_status.mt_gstat |= GMT_ONLINE(0xffffffff);
if (STp->ready == ST_NO_TAPE)
- (STp->mt_status)->mt_gstat |= GMT_DR_OPEN(0xffffffff);
+ mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff);
if (STps->at_sm)
- (STp->mt_status)->mt_gstat |= GMT_SM(0xffffffff);
+ mt_status.mt_gstat |= GMT_SM(0xffffffff);
if (STm->do_async_writes ||
(STm->do_buffer_writes && STp->block_size != 0) ||
STp->drv_buffer != 0)
- (STp->mt_status)->mt_gstat |= GMT_IM_REP_EN(0xffffffff);
+ mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
- i = copy_to_user((char *) arg, (char *) (STp->mt_status),
+ i = copy_to_user((char *) arg, (char *) &(mt_status),
sizeof(struct mtget));
if (i)
return (-EFAULT);
- (STp->mt_status)->mt_erreg = 0; /* Clear after read */
+ STp->recover_reg = 0; /* Clear after read */
return 0;
} /* End of MTIOCGET */
if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
+ struct mtpos mt_pos;
if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos))
return (-EINVAL);
- if ((i = get_location(inode, &blk, &bt, 0)) < 0)
+ if ((i = get_location(STp, &blk, &bt, 0)) < 0)
return i;
mt_pos.mt_blkno = blk;
i = copy_to_user((char *) arg, (char *) (&mt_pos), sizeof(struct mtpos));
@@ -2920,15 +2986,21 @@ static int st_ioctl(struct inode *inode, struct file *file,
}
-/* Try to allocate a new tape buffer */
+/* Try to allocate a new tape buffer. Calling function must not hold
+ dev_arr_lock. */
static ST_buffer *
new_tape_buffer(int from_initialization, int need_dma)
{
int i, priority, b_size, order, got = 0, segs = 0;
+ unsigned long flags;
ST_buffer *tb;
- if (st_nbr_buffers >= st_template.dev_max)
+ read_lock(&st_dev_arr_lock);
+ if (st_nbr_buffers >= st_template.dev_max) {
+ read_unlock(&st_dev_arr_lock);
return NULL; /* Should never happen */
+ }
+ read_unlock(&st_dev_arr_lock);
if (from_initialization)
priority = GFP_ATOMIC;
@@ -3014,7 +3086,10 @@ static ST_buffer *
tb->dma = need_dma;
tb->buffer_size = got;
tb->writing = 0;
+
+ write_lock_irqsave(&st_dev_arr_lock, flags);
st_buffers[st_nbr_buffers++] = tb;
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
return tb;
}
@@ -3039,7 +3114,8 @@ static int enlarge_buffer(ST_buffer * STbuffer, int new_size, int need_dma)
priority |= GFP_DMA;
for (b_size = PAGE_SIZE, order=0;
b_size * nbr < new_size - STbuffer->buffer_size;
- order++, b_size *= 2);
+ order++, b_size *= 2)
+ ; /* empty */
for (segs = STbuffer->sg_segs, got = STbuffer->buffer_size;
segs < max_segs && got < new_size;) {
@@ -3080,7 +3156,7 @@ static void normalize_buffer(ST_buffer * STbuffer)
for (i = STbuffer->orig_sg_segs; i < STbuffer->sg_segs; i++) {
for (b_size=PAGE_SIZE, order=0; b_size < STbuffer->sg[i].length;
order++, b_size *= 2)
- ;
+ ; /* empty */
free_pages((unsigned long)(STbuffer->sg[i].address), order);
STbuffer->buffer_size -= STbuffer->sg[i].length;
}
@@ -3239,23 +3315,77 @@ static int st_attach(Scsi_Device * SDp)
Scsi_Tape *tpnt;
ST_mode *STm;
ST_partstat *STps;
- int i, mode;
+ int i, mode, target_nbr;
+ unsigned long flags = 0;
if (SDp->type != TYPE_TAPE)
return 1;
+ write_lock_irqsave(&st_dev_arr_lock, flags);
if (st_template.nr_dev >= st_template.dev_max) {
- SDp->attached--;
- return 1;
+ Scsi_Tape **tmp_da;
+ ST_buffer **tmp_ba;
+ int tmp_dev_max;
+
+ tmp_dev_max = st_template.nr_dev + ST_DEV_ARR_LUMP;
+ if (tmp_dev_max > ST_MAX_TAPES)
+ tmp_dev_max = ST_MAX_TAPES;
+ if (tmp_dev_max <= st_template.nr_dev) {
+ SDp->attached--;
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
+ printk(KERN_ERR "st: Too many tape devices (max. %d).\n",
+ ST_MAX_TAPES);
+ return 1;
+ }
+
+ tmp_da = (Scsi_Tape **) kmalloc(tmp_dev_max * sizeof(Scsi_Tape *),
+ GFP_ATOMIC);
+ tmp_ba = (ST_buffer **) kmalloc(tmp_dev_max * sizeof(ST_buffer *),
+ GFP_ATOMIC);
+ if (tmp_da == NULL || tmp_ba == NULL) {
+ if (tmp_da != NULL)
+ kfree(tmp_da);
+ SDp->attached--;
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
+ printk(KERN_ERR "st: Can't extend device array.\n");
+ return 1;
+ }
+
+ memset(tmp_da, 0, tmp_dev_max * sizeof(Scsi_Tape *));
+ if (scsi_tapes != NULL) {
+ memcpy(tmp_da, scsi_tapes,
+ st_template.dev_max * sizeof(Scsi_Tape *));
+ kfree(scsi_tapes);
+ }
+ scsi_tapes = tmp_da;
+
+ memset(tmp_ba, 0, tmp_dev_max * sizeof(ST_buffer *));
+ if (st_buffers != NULL) {
+ memcpy(tmp_ba, st_buffers,
+ st_template.dev_max * sizeof(ST_buffer *));
+ kfree(st_buffers);
+ }
+ st_buffers = tmp_ba;
+
+ st_template.dev_max = tmp_dev_max;
}
- for (tpnt = scsi_tapes, i = 0; i < st_template.dev_max; i++, tpnt++)
- if (!tpnt->device)
+ for (i = 0; i < st_template.dev_max; i++)
+ if (scsi_tapes[i] == NULL)
break;
-
if (i >= st_template.dev_max)
panic("scsi_devices corrupt (st)");
+ tpnt = (Scsi_Tape *)kmalloc(sizeof(Scsi_Tape), GFP_ATOMIC);
+ if (tpnt == NULL) {
+ SDp->attached--;
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
+ printk(KERN_ERR "st: Can't allocate device descriptor.\n");
+ return 1;
+ }
+ memset(tpnt, 0, sizeof(Scsi_Tape));
+ scsi_tapes[i] = tpnt;
+
for (mode = 0; mode < ST_NBR_MODES; ++mode) {
char name[8];
static char *formats[ST_NBR_MODES] ={"", "l", "m", "a"};
@@ -3276,11 +3406,11 @@ static int st_attach(Scsi_Device * SDp)
0, 0, &st_fops, NULL);
}
devfs_register_tape (tpnt->de_r[0]);
- scsi_tapes[i].device = SDp;
+ tpnt->device = SDp;
if (SDp->scsi_level <= 2)
- scsi_tapes[i].mt_status->mt_type = MT_ISSCSI1;
+ tpnt->tape_type = MT_ISSCSI1;
else
- scsi_tapes[i].mt_status->mt_type = MT_ISSCSI2;
+ tpnt->tape_type = MT_ISSCSI2;
tpnt->inited = 0;
tpnt->devt = MKDEV(SCSI_TAPE_MAJOR, i);
@@ -3333,6 +3463,20 @@ static int st_attach(Scsi_Device * SDp)
tpnt->blksize_changed = FALSE;
st_template.nr_dev++;
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
+
+ /* See if we need to allocate more static buffers */
+ target_nbr = st_template.nr_dev;
+ if (target_nbr > st_max_buffers)
+ target_nbr = st_max_buffers;
+ for (i=st_nbr_buffers; i < target_nbr; i++)
+ if (!new_tape_buffer(TRUE, TRUE)) {
+ printk(KERN_INFO "st: Unable to allocate new static buffer.\n");
+ break;
+ }
+ /* If the previous allocation fails, we will try again when the buffer is
+ really needed. */
+
return 0;
};
@@ -3354,90 +3498,28 @@ static int st_registered = 0;
/* Driver initialization (not __init because may be called later) */
static int st_init()
{
- int i, j;
- Scsi_Tape *STp;
- int target_nbr;
+ unsigned long flags;
- if (st_template.dev_noticed == 0)
+ if (st_template.dev_noticed == 0 || st_registered)
return 0;
printk(KERN_INFO "st: bufsize %d, wrt %d, max init. buffers %d, s/g segs %d.\n",
st_buffer_size, st_write_threshold, st_max_buffers, st_max_sg_segs);
+ write_lock_irqsave(&st_dev_arr_lock, flags);
if (!st_registered) {
if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops)) {
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",
MAJOR_NR);
return 1;
}
st_registered++;
}
- if (scsi_tapes)
- return 0;
- st_template.dev_max = st_template.dev_noticed + ST_EXTRA_DEVS;
- if (st_template.dev_max < ST_MAX_TAPES)
- st_template.dev_max = ST_MAX_TAPES;
- if (st_template.dev_max > 128 / ST_NBR_MODES)
- printk(KERN_INFO "st: Only %d tapes accessible.\n", 128 / ST_NBR_MODES);
- scsi_tapes =
- (Scsi_Tape *) kmalloc(st_template.dev_max * sizeof(Scsi_Tape),
- GFP_ATOMIC);
- if (scsi_tapes == NULL) {
- printk(KERN_ERR "Unable to allocate descriptors for SCSI tapes.\n");
- devfs_unregister_chrdev(SCSI_TAPE_MAJOR, "st");
- return 1;
- }
-
- DEB(printk(ST_DEB_MSG "st: Buffer size %d bytes, write threshold %d bytes.\n",
- st_buffer_size, st_write_threshold));
- memset(scsi_tapes, 0, st_template.dev_max * sizeof(Scsi_Tape));
- for (i = 0; i < st_template.dev_max; ++i) {
- STp = &(scsi_tapes[i]);
- STp->capacity = 0xfffff;
- STp->mt_status = (struct mtget *) kmalloc(sizeof(struct mtget),
- GFP_ATOMIC);
- if (STp->mt_status == NULL) {
- for (j=0; j < i; j++)
- kfree(scsi_tapes[j].mt_status);
- kfree(scsi_tapes);
- devfs_unregister_chrdev(SCSI_TAPE_MAJOR, "st");
- return 1;
- }
- /* Initialize status */
- memset((void *) scsi_tapes[i].mt_status, 0, sizeof(struct mtget));
- }
-
- /* Allocate the buffers */
- st_buffers =
- (ST_buffer **) kmalloc(st_template.dev_max * sizeof(ST_buffer *),
- GFP_ATOMIC);
- if (st_buffers == NULL) {
- printk(KERN_ERR "Unable to allocate tape buffer pointers.\n");
- devfs_unregister_chrdev(SCSI_TAPE_MAJOR, "st");
- for (i=0; i < st_template.dev_max; i++)
- kfree(scsi_tapes[i].mt_status);
- kfree(scsi_tapes);
- unregister_chrdev(SCSI_TAPE_MAJOR, "st");
- return 1;
- }
- target_nbr = st_template.dev_noticed;
- if (target_nbr < ST_EXTRA_DEVS)
- target_nbr = ST_EXTRA_DEVS;
- if (target_nbr > st_max_buffers)
- target_nbr = st_max_buffers;
-
- for (i = st_nbr_buffers = 0; i < target_nbr; i++) {
- if (!new_tape_buffer(TRUE, TRUE)) {
- if (i == 0) {
- printk(KERN_INFO
- "No tape buffers allocated at initialization.\n");
- break;
- }
- printk(KERN_INFO "Number of tape buffers adjusted.\n");
- break;
- }
- }
+ st_template.dev_max = 0;
+ st_nbr_buffers = 0;
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
return 0;
}
@@ -3446,9 +3528,12 @@ static void st_detach(Scsi_Device * SDp)
{
Scsi_Tape *tpnt;
int i, mode;
+ unsigned long flags;
- for (tpnt = scsi_tapes, i = 0; i < st_template.dev_max; i++, tpnt++)
- if (tpnt->device == SDp) {
+ write_lock_irqsave(&st_dev_arr_lock, flags);
+ for (i = 0; i < st_template.dev_max; i++) {
+ tpnt = scsi_tapes[i];
+ if (tpnt != NULL && tpnt->device == SDp) {
tpnt->device = NULL;
for (mode = 0; mode < ST_NBR_MODES; ++mode) {
devfs_unregister (tpnt->de_r[mode]);
@@ -3456,11 +3541,17 @@ static void st_detach(Scsi_Device * SDp)
devfs_unregister (tpnt->de_n[mode]);
tpnt->de_n[mode] = NULL;
}
+ kfree(tpnt);
+ scsi_tapes[i] = 0;
SDp->attached--;
st_template.nr_dev--;
st_template.dev_noticed--;
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
return;
}
+ }
+
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
return;
}
@@ -3484,7 +3575,8 @@ void cleanup_module(void)
st_registered--;
if (scsi_tapes != NULL) {
for (i=0; i < st_template.dev_max; ++i)
- kfree(scsi_tapes[i].mt_status);
+ if (scsi_tapes[i])
+ kfree(scsi_tapes[i]);
kfree(scsi_tapes);
if (st_buffers != NULL) {
for (i = 0; i < st_nbr_buffers; i++) {
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index e751efc28..47b3fbff5 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -47,6 +47,7 @@ typedef struct {
#define ST_NBR_MODES (1 << ST_NBR_MODE_BITS)
#define ST_MODE_SHIFT (7 - ST_NBR_MODE_BITS)
#define ST_MODE_MASK ((ST_NBR_MODES - 1) << ST_MODE_SHIFT)
+#define ST_MAX_TAPES (1 << ST_MODE_SHIFT)
/* The status related to each partition */
typedef struct {
@@ -64,7 +65,6 @@ typedef struct {
/* The tape drive descriptor */
typedef struct {
kdev_t devt;
- unsigned capacity;
Scsi_Device *device;
struct semaphore sem;
ST_buffer *buffer;
@@ -79,6 +79,7 @@ typedef struct {
unsigned char restr_dma;
unsigned char scsi2_logical;
unsigned char default_drvbuffer; /* 0xff = don't touch, value 3 bits */
+ int tape_type;
int write_threshold;
int timeout; /* timeout for normal commands */
int long_timeout; /* timeout for commands known to take long time */
@@ -105,13 +106,14 @@ typedef struct {
unsigned char drv_buffer;
unsigned char density;
unsigned char door_locked;
- unsigned char rew_at_close;
+ unsigned char autorew_dev; /* auto-rewind device */
+ unsigned char rew_at_close; /* rewind necessary at close */
unsigned char inited;
int block_size;
int min_block;
int max_block;
- int recover_count;
- struct mtget *mt_status;
+ int recover_count; /* From tape opening */
+ int recover_reg; /* From last status call */
#if DEBUG
unsigned char write_pending;
@@ -122,7 +124,6 @@ typedef struct {
#endif
} Scsi_Tape;
-extern Scsi_Tape *scsi_tapes;
/* Values of eof */
#define ST_NOEOF 0
diff --git a/drivers/scsi/st_options.h b/drivers/scsi/st_options.h
index 8cbc1c69e..fa3926c5d 100644
--- a/drivers/scsi/st_options.h
+++ b/drivers/scsi/st_options.h
@@ -3,17 +3,12 @@
Copyright 1995-2000 Kai Makisara.
- Last modified: Sat Jan 1 18:34:38 2000 by makisara@kai.makisara.local
+ Last modified: Sat Mar 11 10:32:00 2000 by makisara@kai.makisara.local
*/
#ifndef _ST_OPTIONS_H
#define _ST_OPTIONS_H
-/* The minimum limit for the number of SCSI tape devices is determined by
- ST_MAX_TAPES. If the number of tape devices and the "slack" defined by
- ST_EXTRA_DEVS exceeds ST_MAX_TAPES, the large number is used. */
-#define ST_MAX_TAPES 4
-
/* The driver does not wait for some operations to finish before returning
to the user program if ST_NOWAIT is non-zero. This helps if the SCSI
adapter does not support multiple outstanding commands. However, the user
@@ -47,7 +42,7 @@
driver initialisation. The number is also constrained by the number
of drives detected. If more buffers are needed, they are allocated
at run time and freed after use. */
-#define ST_MAX_BUFFERS (2 + ST_EXTRA_DEVS)
+#define ST_MAX_BUFFERS 4
/* Maximum number of scatter/gather segments */
#define ST_MAX_SG 16
diff --git a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c
index 36eb7b0c1..f9bbce41e 100644
--- a/drivers/scsi/sym53c8xx.c
+++ b/drivers/scsi/sym53c8xx.c
@@ -55,7 +55,7 @@
*/
/*
-** February 20 2000, sym53c8xx 1.5j
+** March 6 2000, sym53c8xx 1.5k
**
** Supported SCSI features:
** Synchronous data transfers
@@ -84,7 +84,7 @@
/*
** Name and version of the driver
*/
-#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.5j"
+#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.5k"
/* #define DEBUG_896R1 */
#define SCSI_NCR_OPTIMIZE_896
@@ -174,6 +174,9 @@ typedef u64 u_int64;
#include "sym53c8xx.h"
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+
/*
** Hmmm... What complex some PCI-HOST bridges actually are,
** despite the fact that the PCI specifications are looking
@@ -1000,8 +1003,9 @@ static m_addr_t ___dma_getp(m_pool_s *mp)
++mp->nump;
return vp;
}
+ else
+ __m_free(&mp0, vbp, sizeof(*vbp), "VTOB");
}
- __m_free(&mp0, vbp, sizeof(*vbp), "VTOB");
return 0;
}
@@ -1253,7 +1257,7 @@ static void ncr_printl_hex(char *label, u_char *p, int n)
#define SCSI_DATA_READ 2
#define SCSI_DATA_NONE 3
-static __inline__ scsi_data_direction(Scsi_Cmnd *cmd)
+static __inline__ int scsi_data_direction(Scsi_Cmnd *cmd)
{
int direction;
@@ -2043,7 +2047,7 @@ struct head {
#define HF_ACT_PM (1u<<2)
#define HF_DP_SAVED (1u<<3)
#define HF_AUTO_SENSE (1u<<4)
-#define HF_DATA_ST (1u<<5)
+#define HF_DATA_IN (1u<<5)
#define HF_PM_TO_C (1u<<6)
#ifdef SCSI_NCR_IARB_SUPPORT
@@ -2051,6 +2055,11 @@ struct head {
#endif
/*
+** This one is stolen from QU_REG.:)
+*/
+#define HF_DATA_ST (1u<<7)
+
+/*
** First four bytes (script)
*/
#define xerr_st header.scr_st[0]
@@ -2568,8 +2577,12 @@ struct script {
ncrcmd data_in2 [ 4];
ncrcmd data_out [MAX_SCATTER * SCR_SG_SIZE];
ncrcmd data_out2 [ 4];
- ncrcmd pm0_data [ 16];
- ncrcmd pm1_data [ 16];
+ ncrcmd pm0_data [ 12];
+ ncrcmd pm0_data_out [ 6];
+ ncrcmd pm0_data_end [ 6];
+ ncrcmd pm1_data [ 12];
+ ncrcmd pm1_data_out [ 6];
+ ncrcmd pm1_data_end [ 6];
};
/*
@@ -2607,7 +2620,7 @@ struct scripth {
ncrcmd sdata_in [ 6];
ncrcmd data_io [ 2];
ncrcmd data_io_com [ 8];
- ncrcmd data_io_out [ 10];
+ ncrcmd data_io_out [ 12];
ncrcmd bad_identify [ 12];
ncrcmd bad_i_t_l [ 4];
ncrcmd bad_i_t_l_q [ 4];
@@ -3146,12 +3159,11 @@ static struct script script0 __initdata = {
}/*-------------------------< DATAPHASE >------------------*/,{
#ifdef SCSI_NCR_PROFILE_SUPPORT
- SCR_REG_REG (HF_REG, SCR_OR, HF_DATA_ST),
+ SCR_REG_REG (QU_REG, SCR_OR, HF_DATA_ST),
0,
#endif
SCR_RETURN,
- 0,
-
+ 0,
}/*-------------------------< MSG_IN >--------------------*/,{
/*
** Get the first byte of the message.
@@ -3390,7 +3402,7 @@ static struct script script0 __initdata = {
*/
SCR_LOAD_REL (scratcha, 4),
offsetof (struct ccb, phys.num_disc),
- SCR_FROM_REG (HF_REG),
+ SCR_FROM_REG (QU_REG),
0,
SCR_JUMPR ^ IFTRUE (MASK (HF_DATA_ST, HF_DATA_ST)),
8,
@@ -3692,26 +3704,57 @@ static struct script script0 __initdata = {
}/*-------------------------< PM0_DATA >--------------------*/,{
/*
- ** Keep track we are executing the PM0 DATA
- ** mini-script.
+ ** Read our host flags to SFBR, so we will be able
+ ** to check against the data direction we expect.
+ */
+ SCR_FROM_REG (HF_REG),
+ 0,
+ /*
+ ** Check against actual DATA PHASE.
+ */
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
+ PADDR (pm0_data_out),
+ /*
+ ** Actual phase is DATA IN.
+ ** Check against expected direction.
+ */
+ SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)),
+ PADDRH (no_data),
+ /*
+ ** Keep track we are moving data from the
+ ** PM0 DATA mini-script.
*/
SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0),
0,
/*
- ** MOVE the data according to the actual
- ** DATA direction.
+ ** Move the data to memory.
*/
- SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
- 16,
SCR_CHMOV_TBL ^ SCR_DATA_IN,
offsetof (struct ccb, phys.pm0.sg),
- SCR_JUMPR,
- 8,
+ SCR_JUMP,
+ PADDR (pm0_data_end),
+}/*-------------------------< PM0_DATA_OUT >----------------*/,{
+ /*
+ ** Actual phase is DATA OUT.
+ ** Check against expected direction.
+ */
+ SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)),
+ PADDRH (no_data),
+ /*
+ ** Keep track we are moving data from the
+ ** PM0 DATA mini-script.
+ */
+ SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0),
+ 0,
+ /*
+ ** Move the data from memory.
+ */
SCR_CHMOV_TBL ^ SCR_DATA_OUT,
offsetof (struct ccb, phys.pm0.sg),
+}/*-------------------------< PM0_DATA_END >----------------*/,{
/*
- ** Clear the flag that told we were in
- ** the PM0 DATA mini-script.
+ ** Clear the flag that told we were moving
+ ** data from the PM0 DATA mini-script.
*/
SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM0)),
0,
@@ -3726,26 +3769,57 @@ static struct script script0 __initdata = {
0,
}/*-------------------------< PM1_DATA >--------------------*/,{
/*
- ** Keep track we are executing the PM1 DATA
- ** mini-script.
+ ** Read our host flags to SFBR, so we will be able
+ ** to check against the data direction we expect.
+ */
+ SCR_FROM_REG (HF_REG),
+ 0,
+ /*
+ ** Check against actual DATA PHASE.
+ */
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
+ PADDR (pm1_data_out),
+ /*
+ ** Actual phase is DATA IN.
+ ** Check against expected direction.
+ */
+ SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)),
+ PADDRH (no_data),
+ /*
+ ** Keep track we are moving data from the
+ ** PM1 DATA mini-script.
*/
SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1),
0,
/*
- ** MOVE the data according to the actual
- ** DATA direction.
+ ** Move the data to memory.
*/
- SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
- 16,
SCR_CHMOV_TBL ^ SCR_DATA_IN,
offsetof (struct ccb, phys.pm1.sg),
- SCR_JUMPR,
- 8,
+ SCR_JUMP,
+ PADDR (pm1_data_end),
+}/*-------------------------< PM1_DATA_OUT >----------------*/,{
+ /*
+ ** Actual phase is DATA OUT.
+ ** Check against expected direction.
+ */
+ SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)),
+ PADDRH (no_data),
+ /*
+ ** Keep track we are moving data from the
+ ** PM1 DATA mini-script.
+ */
+ SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1),
+ 0,
+ /*
+ ** Move the data from memory.
+ */
SCR_CHMOV_TBL ^ SCR_DATA_OUT,
offsetof (struct ccb, phys.pm1.sg),
+}/*-------------------------< PM1_DATA_END >----------------*/,{
/*
- ** Clear the flag that told we were in
- ** the PM1 DATA mini-script.
+ ** Clear the flag that told we were moving
+ ** data from the PM1 DATA mini-script.
*/
SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM1)),
0,
@@ -4193,6 +4267,8 @@ static struct scripth scripth0 __initdata = {
/*
** Direction is DATA OUT.
*/
+ SCR_REG_REG (HF_REG, SCR_AND, (~HF_DATA_IN)),
+ 0,
SCR_LOAD_REL (scratcha, 4),
offsetof (struct ccb, phys.header.wlastp),
SCR_STORE_REL (scratcha, 4),
@@ -5550,7 +5626,7 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
goto attach_error;
NCR_INIT_LOCK_NCB(np);
np->pdev = device->pdev;
- np->p_ncb = __vtobus(device->pdev, np);
+ np->p_ncb = vtobus(np);
host_data->ncb = np;
/*
@@ -6119,18 +6195,18 @@ static void ncr_free_resources(ncb_p np)
*/
static inline void ncr_queue_done_cmd(ncb_p np, Scsi_Cmnd *cmd)
{
+ unmap_scsi_data(np, cmd);
cmd->host_scribble = (char *) np->done_list;
np->done_list = cmd;
}
-static inline void ncr_flush_done_cmds(pcidev_t pdev, Scsi_Cmnd *lcmd)
+static inline void ncr_flush_done_cmds(Scsi_Cmnd *lcmd)
{
Scsi_Cmnd *cmd;
while (lcmd) {
cmd = lcmd;
lcmd = (Scsi_Cmnd *) cmd->host_scribble;
- __unmap_scsi_data(pdev, cmd);
cmd->scsi_done(cmd);
}
}
@@ -6411,6 +6487,7 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
cp->phys.header.wlastp = cpu_to_scr(lastp);
/* fall through */
case SCSI_DATA_READ:
+ cp->host_flags |= HF_DATA_IN;
goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8;
lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
break;
@@ -6488,7 +6565,7 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
/*
** command
*/
- memcpy(cp->cdb_buf, cmd->cmnd, cmd->cmd_len);
+ memcpy(cp->cdb_buf, cmd->cmnd, MIN(cmd->cmd_len, sizeof(cp->cdb_buf)));
cp->phys.cmd.addr = cpu_to_scr(CCB_PHYS (cp, cdb_buf[0]));
cp->phys.cmd.size = cpu_to_scr(cmd->cmd_len);
@@ -9154,7 +9231,7 @@ next:
cp->scsi_status = S_ILLEGAL;
cp->xerr_status = 0;
cp->phys.extra_bytes = 0;
- cp->host_flags &= HF_PM_TO_C;
+ cp->host_flags &= (HF_PM_TO_C|HF_DATA_IN);
break;
@@ -9221,7 +9298,7 @@ next:
*/
cp->sensecmd[0] = 0x03;
cp->sensecmd[1] = cp->lun << 5;
- cp->sensecmd[4] = sizeof(cmd->sense_buffer);
+ cp->sensecmd[4] = sizeof(cp->sense_buf);
/*
** sense data
@@ -9243,7 +9320,7 @@ next:
cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY;
cp->scsi_status = S_ILLEGAL;
- cp->host_flags = HF_AUTO_SENSE;
+ cp->host_flags = (HF_AUTO_SENSE|HF_DATA_IN);
cp->phys.header.go.start =
cpu_to_scr(NCB_SCRIPT_PHYS (np, select));
@@ -12616,8 +12693,10 @@ printk("sym53c8xx : command successfully queued\n");
NCR_UNLOCK_NCB(np, flags);
- if (sts != DID_OK)
+ if (sts != DID_OK) {
+ unmap_scsi_data(np, cmd);
done(cmd);
+ }
return sts;
}
@@ -12635,7 +12714,6 @@ static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
unsigned long flags;
ncb_p np = (ncb_p) dev_id;
Scsi_Cmnd *done_list;
- pcidev_t pdev;
#ifdef DEBUG_SYM53C8XX
printk("sym53c8xx : interrupt received\n");
@@ -12645,7 +12723,6 @@ static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
NCR_LOCK_NCB(np, flags);
ncr_exception(np);
- pdev = np->pdev;
done_list = np->done_list;
np->done_list = 0;
NCR_UNLOCK_NCB(np, flags);
@@ -12654,7 +12731,7 @@ static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
if (done_list) {
NCR_LOCK_SCSI_DONE(np, flags);
- ncr_flush_done_cmds(pdev, done_list);
+ ncr_flush_done_cmds(done_list);
NCR_UNLOCK_SCSI_DONE(np, flags);
}
}
@@ -12667,19 +12744,17 @@ static void sym53c8xx_timeout(unsigned long npref)
{
ncb_p np = (ncb_p) npref;
unsigned long flags;
- pcidev_t pdev;
Scsi_Cmnd *done_list;
NCR_LOCK_NCB(np, flags);
ncr_timeout((ncb_p) np);
- pdev = np->pdev;
done_list = np->done_list;
np->done_list = 0;
NCR_UNLOCK_NCB(np, flags);
if (done_list) {
NCR_LOCK_SCSI_DONE(np, flags);
- ncr_flush_done_cmds(pdev, done_list);
+ ncr_flush_done_cmds(done_list);
NCR_UNLOCK_SCSI_DONE(np, flags);
}
}
@@ -12697,7 +12772,6 @@ int sym53c8xx_reset(Scsi_Cmnd *cmd)
ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb;
int sts;
unsigned long flags;
- pcidev_t pdev;
Scsi_Cmnd *done_list;
#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
@@ -12742,12 +12816,11 @@ int sym53c8xx_reset(Scsi_Cmnd *cmd)
#endif
out:
- pdev = np->pdev;
done_list = np->done_list;
np->done_list = 0;
NCR_UNLOCK_NCB(np, flags);
- ncr_flush_done_cmds(pdev, done_list);
+ ncr_flush_done_cmds(done_list);
return sts;
}
@@ -12761,7 +12834,6 @@ int sym53c8xx_abort(Scsi_Cmnd *cmd)
ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb;
int sts;
unsigned long flags;
- pcidev_t pdev;
Scsi_Cmnd *done_list;
#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
@@ -12785,12 +12857,11 @@ int sym53c8xx_abort(Scsi_Cmnd *cmd)
sts = ncr_abort_command(np, cmd);
out:
- pdev = np->pdev;
done_list = np->done_list;
np->done_list = 0;
NCR_UNLOCK_NCB(np, flags);
- ncr_flush_done_cmds(pdev, done_list);
+ ncr_flush_done_cmds(done_list);
return sts;
}
diff --git a/drivers/scsi/sym53c8xx_comm.h b/drivers/scsi/sym53c8xx_comm.h
new file mode 100644
index 000000000..fa02ff585
--- /dev/null
+++ b/drivers/scsi/sym53c8xx_comm.h
@@ -0,0 +1,2863 @@
+/******************************************************************************
+** High Performance device driver for the Symbios 53C896 controller.
+**
+** Copyright (C) 1998-2000 Gerard Roudier <groudier@club-internet.fr>
+**
+** This driver also supports all the Symbios 53C8XX controller family,
+** except 53C810 revisions < 16, 53C825 revisions < 16 and all
+** revisions of 53C815 controllers.
+**
+** This driver is based on the Linux port of the FreeBSD ncr driver.
+**
+** Copyright (C) 1994 Wolfgang Stanglmeier
+**
+**-----------------------------------------------------------------------------
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**-----------------------------------------------------------------------------
+**
+** The Linux port of the FreeBSD ncr driver has been achieved in
+** november 1995 by:
+**
+** Gerard Roudier <groudier@club-internet.fr>
+**
+** Being given that this driver originates from the FreeBSD version, and
+** in order to keep synergy on both, any suggested enhancements and corrections
+** received on Linux are automatically a potential candidate for the FreeBSD
+** version.
+**
+** The original driver has been written for 386bsd and FreeBSD by
+** Wolfgang Stanglmeier <wolf@cologne.de>
+** Stefan Esser <se@mi.Uni-Koeln.de>
+**
+**-----------------------------------------------------------------------------
+**
+** Major contributions:
+** --------------------
+**
+** NVRAM detection and reading.
+** Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+**
+*******************************************************************************
+*/
+
+/*
+** This file contains definitions and code that the
+** sym53c8xx and ncr53c8xx drivers should share.
+** The sharing will be achieved in a further version
+** of the driver bundle. For now, only the ncr53c8xx
+** driver includes this file.
+*/
+
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+
+/*==========================================================
+**
+** Hmmm... What complex some PCI-HOST bridges actually
+** are, despite the fact that the PCI specifications
+** are looking so smart and simple! ;-)
+**
+**==========================================================
+*/
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,47)
+#define SCSI_NCR_DYNAMIC_DMA_MAPPING
+#endif
+
+/*==========================================================
+**
+** Io mapped versus memory mapped.
+**
+**==========================================================
+*/
+
+#if defined(SCSI_NCR_IOMAPPED) || defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED)
+#define NCR_IOMAPPED
+#endif
+
+/*==========================================================
+**
+** Miscallaneous defines.
+**
+**==========================================================
+*/
+
+#define u_char unsigned char
+#define u_short unsigned short
+#define u_int unsigned int
+#define u_long unsigned long
+
+#ifndef bcopy
+#define bcopy(s, d, n) memcpy((d), (s), (n))
+#endif
+
+#ifndef bcmp
+#define bcmp(s, d, n) memcmp((d), (s), (n))
+#endif
+
+#ifndef bzero
+#define bzero(d, n) memset((d), 0, (n))
+#endif
+
+#ifndef offsetof
+#define offsetof(t, m) ((size_t) (&((t *)0)->m))
+#endif
+
+/*==========================================================
+**
+** assert ()
+**
+**==========================================================
+**
+** modified copy from 386bsd:/usr/include/sys/assert.h
+**
+**----------------------------------------------------------
+*/
+
+#define assert(expression) { \
+ if (!(expression)) { \
+ (void)panic( \
+ "assertion \"%s\" failed: file \"%s\", line %d\n", \
+ #expression, \
+ __FILE__, __LINE__); \
+ } \
+}
+
+/*==========================================================
+**
+** Debugging tags
+**
+**==========================================================
+*/
+
+#define DEBUG_ALLOC (0x0001)
+#define DEBUG_PHASE (0x0002)
+#define DEBUG_QUEUE (0x0008)
+#define DEBUG_RESULT (0x0010)
+#define DEBUG_POINTER (0x0020)
+#define DEBUG_SCRIPT (0x0040)
+#define DEBUG_TINY (0x0080)
+#define DEBUG_TIMING (0x0100)
+#define DEBUG_NEGO (0x0200)
+#define DEBUG_TAGS (0x0400)
+#define DEBUG_SCATTER (0x0800)
+
+/*
+** Enable/Disable debug messages.
+** Can be changed at runtime too.
+*/
+
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
+static int ncr_debug = SCSI_NCR_DEBUG_FLAGS;
+ #define DEBUG_FLAGS ncr_debug
+#else
+ #define DEBUG_FLAGS SCSI_NCR_DEBUG_FLAGS
+#endif
+
+/*==========================================================
+**
+** A la VMS/CAM-3 queue management.
+** Implemented from linux list management.
+**
+**==========================================================
+*/
+
+typedef struct xpt_quehead {
+ struct xpt_quehead *flink; /* Forward pointer */
+ struct xpt_quehead *blink; /* Backward pointer */
+} XPT_QUEHEAD;
+
+#define xpt_que_init(ptr) do { \
+ (ptr)->flink = (ptr); (ptr)->blink = (ptr); \
+} while (0)
+
+static inline void __xpt_que_add(struct xpt_quehead * new,
+ struct xpt_quehead * blink,
+ struct xpt_quehead * flink)
+{
+ flink->blink = new;
+ new->flink = flink;
+ new->blink = blink;
+ blink->flink = new;
+}
+
+static inline void __xpt_que_del(struct xpt_quehead * blink,
+ struct xpt_quehead * flink)
+{
+ flink->blink = blink;
+ blink->flink = flink;
+}
+
+static inline int xpt_que_empty(struct xpt_quehead *head)
+{
+ return head->flink == head;
+}
+
+static inline void xpt_que_splice(struct xpt_quehead *list,
+ struct xpt_quehead *head)
+{
+ struct xpt_quehead *first = list->flink;
+
+ if (first != list) {
+ struct xpt_quehead *last = list->blink;
+ struct xpt_quehead *at = head->flink;
+
+ first->blink = head;
+ head->flink = first;
+
+ last->flink = at;
+ at->blink = last;
+ }
+}
+
+#define xpt_que_entry(ptr, type, member) \
+ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+
+#define xpt_insque(new, pos) __xpt_que_add(new, pos, (pos)->flink)
+
+#define xpt_remque(el) __xpt_que_del((el)->blink, (el)->flink)
+
+#define xpt_insque_head(new, head) __xpt_que_add(new, head, (head)->flink)
+
+static inline struct xpt_quehead *xpt_remque_head(struct xpt_quehead *head)
+{
+ struct xpt_quehead *elem = head->flink;
+
+ if (elem != head)
+ __xpt_que_del(head, elem->flink);
+ else
+ elem = 0;
+ return elem;
+}
+
+#define xpt_insque_tail(new, head) __xpt_que_add(new, (head)->blink, head)
+
+static inline struct xpt_quehead *xpt_remque_tail(struct xpt_quehead *head)
+{
+ struct xpt_quehead *elem = head->blink;
+
+ if (elem != head)
+ __xpt_que_del(elem->blink, head);
+ else
+ elem = 0;
+ return elem;
+}
+
+/*==========================================================
+**
+** On x86 architecture, write buffers management does
+** not reorder writes to memory. So, using compiler
+** optimization barriers is enough to guarantee some
+** ordering when the CPU is writing data accessed by
+** the NCR.
+** On Alpha architecture, explicit memory barriers have
+** to be used.
+** Other architectures are defaulted to mb() macro if
+** defined, otherwise use compiler barrier.
+**
+**==========================================================
+*/
+
+#if defined(__i386__)
+#define MEMORY_BARRIER() barrier()
+#elif defined(__alpha__)
+#define MEMORY_BARRIER() mb()
+#else
+# ifdef mb
+# define MEMORY_BARRIER() mb()
+# else
+# define MEMORY_BARRIER() barrier()
+# endif
+#endif
+
+/*==========================================================
+**
+** Simple Wrapper to kernel PCI bus interface.
+**
+** This wrapper allows to get rid of old kernel PCI
+** interface and still allows to preserve linux-2.0
+** compatibilty. In fact, it is mostly an incomplete
+** emulation of the new PCI code for pre-2.2 kernels.
+** When kernel-2.0 support will be dropped, we will
+** just have to remove most of this code.
+**
+**==========================================================
+*/
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,2,0)
+
+typedef struct pci_dev *pcidev_t;
+#define PCIDEV_NULL (0)
+#define PciBusNumber(d) (d)->bus->number
+#define PciDeviceFn(d) (d)->devfn
+#define PciVendorId(d) (d)->vendor
+#define PciDeviceId(d) (d)->device
+#define PciIrqLine(d) (d)->irq
+
+#if LINUX_VERSION_CODE > LinuxVersionCode(2,3,12)
+
+static int __init
+pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
+{
+ *base = pdev->resource[index].start;
+ if ((pdev->resource[index].flags & 0x7) == 0x4)
+ ++index;
+ return ++index;
+}
+#else
+static int __init
+pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
+{
+ *base = pdev->base_address[index++];
+ if ((*base & 0x7) == 0x4) {
+#if BITS_PER_LONG > 32
+ *base |= (((u_long)pdev->base_address[index]) << 32);
+#endif
+ ++index;
+ }
+ return index;
+}
+#endif
+
+#else /* Incomplete emulation of current PCI code for pre-2.2 kernels */
+
+typedef unsigned int pcidev_t;
+#define PCIDEV_NULL (~0u)
+#define PciBusNumber(d) ((d)>>8)
+#define PciDeviceFn(d) ((d)&0xff)
+#define __PciDev(busn, devfn) (((busn)<<8)+(devfn))
+
+#define pci_present pcibios_present
+
+#define pci_read_config_byte(d, w, v) \
+ pcibios_read_config_byte(PciBusNumber(d), PciDeviceFn(d), w, v)
+#define pci_read_config_word(d, w, v) \
+ pcibios_read_config_word(PciBusNumber(d), PciDeviceFn(d), w, v)
+#define pci_read_config_dword(d, w, v) \
+ pcibios_read_config_dword(PciBusNumber(d), PciDeviceFn(d), w, v)
+
+#define pci_write_config_byte(d, w, v) \
+ pcibios_write_config_byte(PciBusNumber(d), PciDeviceFn(d), w, v)
+#define pci_write_config_word(d, w, v) \
+ pcibios_write_config_word(PciBusNumber(d), PciDeviceFn(d), w, v)
+#define pci_write_config_dword(d, w, v) \
+ pcibios_write_config_dword(PciBusNumber(d), PciDeviceFn(d), w, v)
+
+static pcidev_t __init
+pci_find_device(unsigned int vendor, unsigned int device, pcidev_t prev)
+{
+ static unsigned short pci_index;
+ int retv;
+ unsigned char bus_number, device_fn;
+
+ if (prev == PCIDEV_NULL)
+ pci_index = 0;
+ else
+ ++pci_index;
+ retv = pcibios_find_device (vendor, device, pci_index,
+ &bus_number, &device_fn);
+ return retv ? PCIDEV_NULL : __PciDev(bus_number, device_fn);
+}
+
+static u_short __init PciVendorId(pcidev_t dev)
+{
+ u_short vendor_id;
+ pci_read_config_word(dev, PCI_VENDOR_ID, &vendor_id);
+ return vendor_id;
+}
+
+static u_short __init PciDeviceId(pcidev_t dev)
+{
+ u_short device_id;
+ pci_read_config_word(dev, PCI_DEVICE_ID, &device_id);
+ return device_id;
+}
+
+static u_int __init PciIrqLine(pcidev_t dev)
+{
+ u_char irq;
+ pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+ return irq;
+}
+
+static int __init
+pci_get_base_address(pcidev_t dev, int offset, u_long *base)
+{
+ u_int32 tmp;
+
+ pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + offset, &tmp);
+ *base = tmp;
+ offset += sizeof(u_int32);
+ if ((tmp & 0x7) == 0x4) {
+#if BITS_PER_LONG > 32
+ pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + offset, &tmp);
+ *base |= (((u_long)tmp) << 32);
+#endif
+ offset += sizeof(u_int32);
+ }
+ return offset;
+}
+
+#endif /* LINUX_VERSION_CODE >= LinuxVersionCode(2,2,0) */
+
+/*==========================================================
+**
+** SMP threading.
+**
+** Assuming that SMP systems are generally high end
+** systems and may use several SCSI adapters, we are
+** using one lock per controller instead of some global
+** one. For the moment (linux-2.1.95), driver's entry
+** points are called with the 'io_request_lock' lock
+** held, so:
+** - We are uselessly loosing a couple of micro-seconds
+** to lock the controller data structure.
+** - But the driver is not broken by design for SMP and
+** so can be more resistant to bugs or bad changes in
+** the IO sub-system code.
+** - A small advantage could be that the interrupt code
+** is grained as wished (e.g.: by controller).
+**
+**==========================================================
+*/
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+spinlock_t DRIVER_SMP_LOCK = SPIN_LOCK_UNLOCKED;
+#define NCR_LOCK_DRIVER(flags) spin_lock_irqsave(&DRIVER_SMP_LOCK, flags)
+#define NCR_UNLOCK_DRIVER(flags) \
+ spin_unlock_irqrestore(&DRIVER_SMP_LOCK, flags)
+
+#define NCR_INIT_LOCK_NCB(np) spin_lock_init(&np->smp_lock)
+#define NCR_LOCK_NCB(np, flags) spin_lock_irqsave(&np->smp_lock, flags)
+#define NCR_UNLOCK_NCB(np, flags) spin_unlock_irqrestore(&np->smp_lock, flags)
+
+#define NCR_LOCK_SCSI_DONE(np, flags) \
+ spin_lock_irqsave(&io_request_lock, flags)
+#define NCR_UNLOCK_SCSI_DONE(np, flags) \
+ spin_unlock_irqrestore(&io_request_lock, flags)
+
+#else
+
+#define NCR_LOCK_DRIVER(flags) do { save_flags(flags); cli(); } while (0)
+#define NCR_UNLOCK_DRIVER(flags) do { restore_flags(flags); } while (0)
+
+#define NCR_INIT_LOCK_NCB(np) do { } while (0)
+#define NCR_LOCK_NCB(np, flags) do { save_flags(flags); cli(); } while (0)
+#define NCR_UNLOCK_NCB(np, flags) do { restore_flags(flags); } while (0)
+
+#define NCR_LOCK_SCSI_DONE(np, flags) do {;} while (0)
+#define NCR_UNLOCK_SCSI_DONE(np, flags) do {;} while (0)
+
+#endif
+
+/*==========================================================
+**
+** Memory mapped IO
+**
+** Since linux-2.1, we must use ioremap() to map the io
+** memory space and iounmap() to unmap it. This allows
+** portability. Linux 1.3.X and 2.0.X allow to remap
+** physical pages addresses greater than the highest
+** physical memory address to kernel virtual pages with
+** vremap() / vfree(). That was not portable but worked
+** with i386 architecture.
+**
+**==========================================================
+*/
+
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,0)
+#define ioremap vremap
+#define iounmap vfree
+#endif
+
+#ifdef __sparc__
+# include <asm/irq.h>
+# define pcivtobus(p) bus_dvma_to_mem(p)
+# define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c))
+#elif defined(__alpha__)
+# define pcivtobus(p) ((p) & 0xfffffffful)
+# define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c))
+#else /* others */
+# define pcivtobus(p) (p)
+# define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c))
+#endif
+
+#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
+static u_long __init remap_pci_mem(u_long base, u_long size)
+{
+ u_long page_base = ((u_long) base) & PAGE_MASK;
+ u_long page_offs = ((u_long) base) - page_base;
+ u_long page_remapped = (u_long) ioremap(page_base, page_offs+size);
+
+ return page_remapped? (page_remapped + page_offs) : 0UL;
+}
+
+static void __init unmap_pci_mem(u_long vaddr, u_long size)
+{
+ if (vaddr)
+ iounmap((void *) (vaddr & PAGE_MASK));
+}
+
+#endif /* not def SCSI_NCR_PCI_MEM_NOT_SUPPORTED */
+
+/*==========================================================
+**
+** Insert a delay in micro-seconds and milli-seconds.
+**
+** Under Linux, udelay() is restricted to delay <
+** 1 milli-second. In fact, it generally works for up
+** to 1 second delay. Since 2.1.105, the mdelay() function
+** is provided for delays in milli-seconds.
+** Under 2.0 kernels, udelay() is an inline function
+** that is very inaccurate on Pentium processors.
+**
+**==========================================================
+*/
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,105)
+#define UDELAY udelay
+#define MDELAY mdelay
+#else
+static void UDELAY(long us) { udelay(us); }
+static void MDELAY(long ms) { while (ms--) UDELAY(1000); }
+#endif
+
+/*==========================================================
+**
+** Simple power of two buddy-like allocator.
+**
+** This simple code is not intended to be fast, but to
+** provide power of 2 aligned memory allocations.
+** Since the SCRIPTS processor only supplies 8 bit
+** arithmetic, this allocator allows simple and fast
+** address calculations from the SCRIPTS code.
+** In addition, cache line alignment is guaranteed for
+** power of 2 cache line size.
+** Enhanced in linux-2.3.44 to provide a memory pool
+** per pcidev to support dynamic dma mapping. (I would
+** have preferred a real bus astraction, btw).
+**
+**==========================================================
+*/
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)
+#define __GetFreePages(flags, order) __get_free_pages(flags, order)
+#else
+#define __GetFreePages(flags, order) __get_free_pages(flags, order, 0)
+#endif
+
+#define MEMO_SHIFT 4 /* 16 bytes minimum memory chunk */
+#if PAGE_SIZE >= 8192
+#define MEMO_PAGE_ORDER 0 /* 1 PAGE maximum */
+#else
+#define MEMO_PAGE_ORDER 1 /* 2 PAGES maximum */
+#endif
+#define MEMO_FREE_UNUSED /* Free unused pages immediately */
+#define MEMO_WARN 1
+#define MEMO_GFP_FLAGS GFP_ATOMIC
+#define MEMO_CLUSTER_SHIFT (PAGE_SHIFT+MEMO_PAGE_ORDER)
+#define MEMO_CLUSTER_SIZE (1UL << MEMO_CLUSTER_SHIFT)
+#define MEMO_CLUSTER_MASK (MEMO_CLUSTER_SIZE-1)
+
+typedef u_long m_addr_t; /* Enough bits to bit-hack addresses */
+typedef pcidev_t m_bush_t; /* Something that addresses DMAable */
+
+typedef struct m_link { /* Link between free memory chunks */
+ struct m_link *next;
+} m_link_s;
+
+#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING
+typedef struct m_vtob { /* Virtual to Bus address translation */
+ struct m_vtob *next;
+ m_addr_t vaddr;
+ m_addr_t baddr;
+} m_vtob_s;
+#define VTOB_HASH_SHIFT 5
+#define VTOB_HASH_SIZE (1UL << VTOB_HASH_SHIFT)
+#define VTOB_HASH_MASK (VTOB_HASH_SIZE-1)
+#define VTOB_HASH_CODE(m) \
+ ((((m_addr_t) (m)) >> MEMO_CLUSTER_SHIFT) & VTOB_HASH_MASK)
+#endif
+
+typedef struct m_pool { /* Memory pool of a given kind */
+#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING
+ m_bush_t bush;
+ m_addr_t (*getp)(struct m_pool *);
+ void (*freep)(struct m_pool *, m_addr_t);
+#define M_GETP() mp->getp(mp)
+#define M_FREEP(p) mp->freep(mp, p)
+#define GetPages() __GetFreePages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER)
+#define FreePages(p) free_pages(p, MEMO_PAGE_ORDER)
+ int nump;
+ m_vtob_s *(vtob[VTOB_HASH_SIZE]);
+ struct m_pool *next;
+#else
+#define M_GETP() __GetFreePages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER)
+#define M_FREEP(p) free_pages(p, MEMO_PAGE_ORDER)
+#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */
+ struct m_link h[PAGE_SHIFT-MEMO_SHIFT+MEMO_PAGE_ORDER+1];
+} m_pool_s;
+
+static void *___m_alloc(m_pool_s *mp, int size)
+{
+ int i = 0;
+ int s = (1 << MEMO_SHIFT);
+ int j;
+ m_addr_t a;
+ m_link_s *h = mp->h;
+
+ if (size > (PAGE_SIZE << MEMO_PAGE_ORDER))
+ return 0;
+
+ while (size > s) {
+ s <<= 1;
+ ++i;
+ }
+
+ j = i;
+ while (!h[j].next) {
+ if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) {
+ h[j].next = (m_link_s *) M_GETP();
+ if (h[j].next)
+ h[j].next->next = 0;
+ break;
+ }
+ ++j;
+ s <<= 1;
+ }
+ a = (m_addr_t) h[j].next;
+ if (a) {
+ h[j].next = h[j].next->next;
+ while (j > i) {
+ j -= 1;
+ s >>= 1;
+ h[j].next = (m_link_s *) (a+s);
+ h[j].next->next = 0;
+ }
+ }
+#ifdef DEBUG
+ printk("___m_alloc(%d) = %p\n", size, (void *) a);
+#endif
+ return (void *) a;
+}
+
+static void ___m_free(m_pool_s *mp, void *ptr, int size)
+{
+ int i = 0;
+ int s = (1 << MEMO_SHIFT);
+ m_link_s *q;
+ m_addr_t a, b;
+ m_link_s *h = mp->h;
+
+#ifdef DEBUG
+ printk("___m_free(%p, %d)\n", ptr, size);
+#endif
+
+ if (size > (PAGE_SIZE << MEMO_PAGE_ORDER))
+ return;
+
+ while (size > s) {
+ s <<= 1;
+ ++i;
+ }
+
+ a = (m_addr_t) ptr;
+
+ while (1) {
+#ifdef MEMO_FREE_UNUSED
+ if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) {
+ M_FREEP(a);
+ break;
+ }
+#endif
+ b = a ^ s;
+ q = &h[i];
+ while (q->next && q->next != (m_link_s *) b) {
+ q = q->next;
+ }
+ if (!q->next) {
+ ((m_link_s *) a)->next = h[i].next;
+ h[i].next = (m_link_s *) a;
+ break;
+ }
+ q->next = q->next->next;
+ a = a & b;
+ s <<= 1;
+ ++i;
+ }
+}
+
+static void *__m_calloc2(m_pool_s *mp, int size, char *name, int uflags)
+{
+ void *p;
+
+ p = ___m_alloc(mp, size);
+
+ if (DEBUG_FLAGS & DEBUG_ALLOC)
+ printk ("new %-10s[%4d] @%p.\n", name, size, p);
+
+ if (p)
+ bzero(p, size);
+ else if (uflags & MEMO_WARN)
+ printk (NAME53C8XX ": failed to allocate %s[%d]\n", name, size);
+
+ return p;
+}
+
+#define __m_calloc(mp, s, n) __m_calloc2(mp, s, n, MEMO_WARN)
+
+static void __m_free(m_pool_s *mp, void *ptr, int size, char *name)
+{
+ if (DEBUG_FLAGS & DEBUG_ALLOC)
+ printk ("freeing %-10s[%4d] @%p.\n", name, size, ptr);
+
+ ___m_free(mp, ptr, size);
+
+}
+
+/*
+ * With pci bus iommu support, we use a default pool of unmapped memory
+ * for memory we donnot need to DMA from/to and one pool per pcidev for
+ * memory accessed by the PCI chip. `mp0' is the default not DMAable pool.
+ */
+
+#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING
+
+static m_pool_s mp0;
+
+#else
+
+static m_addr_t ___mp0_getp(m_pool_s *mp)
+{
+ m_addr_t m = GetPages();
+ if (m)
+ ++mp->nump;
+ return m;
+}
+
+static void ___mp0_freep(m_pool_s *mp, m_addr_t m)
+{
+ FreePages(m);
+ --mp->nump;
+}
+
+static m_pool_s mp0 = {0, ___mp0_getp, ___mp0_freep};
+
+#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */
+
+static void *m_calloc(int size, char *name)
+{
+ u_long flags;
+ void *m;
+ NCR_LOCK_DRIVER(flags);
+ m = __m_calloc(&mp0, size, name);
+ NCR_UNLOCK_DRIVER(flags);
+ return m;
+}
+
+static void m_free(void *ptr, int size, char *name)
+{
+ u_long flags;
+ NCR_LOCK_DRIVER(flags);
+ __m_free(&mp0, ptr, size, name);
+ NCR_UNLOCK_DRIVER(flags);
+}
+
+/*
+ * DMAable pools.
+ */
+
+#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING
+
+/* Without pci bus iommu support, all the memory is assumed DMAable */
+
+#define __m_calloc_dma(b, s, n) m_calloc(s, n)
+#define __m_free_dma(b, p, s, n) m_free(p, s, n)
+#define __vtobus(b, p) virt_to_bus(p)
+
+#else
+
+/*
+ * With pci bus iommu support, we maintain one pool per pcidev and a
+ * hashed reverse table for virtual to bus physical address translations.
+ */
+static m_addr_t ___dma_getp(m_pool_s *mp)
+{
+ m_addr_t vp;
+ m_vtob_s *vbp;
+
+ vbp = __m_calloc(&mp0, sizeof(*vbp), "VTOB");
+ if (vbp) {
+ dma_addr_t daddr;
+ vp = (m_addr_t) pci_alloc_consistent(mp->bush,
+ PAGE_SIZE<<MEMO_PAGE_ORDER,
+ &daddr);
+ if (vp) {
+ int hc = VTOB_HASH_CODE(vp);
+ vbp->vaddr = vp;
+ vbp->baddr = daddr;
+ vbp->next = mp->vtob[hc];
+ mp->vtob[hc] = vbp;
+ ++mp->nump;
+ return vp;
+ }
+ }
+ if (vbp)
+ __m_free(&mp0, vbp, sizeof(*vbp), "VTOB");
+ return 0;
+}
+
+static void ___dma_freep(m_pool_s *mp, m_addr_t m)
+{
+ m_vtob_s **vbpp, *vbp;
+ int hc = VTOB_HASH_CODE(m);
+
+ vbpp = &mp->vtob[hc];
+ while (*vbpp && (*vbpp)->vaddr != m)
+ vbpp = &(*vbpp)->next;
+ if (*vbpp) {
+ vbp = *vbpp;
+ *vbpp = (*vbpp)->next;
+ pci_free_consistent(mp->bush, PAGE_SIZE<<MEMO_PAGE_ORDER,
+ (void *)vbp->vaddr, (dma_addr_t)vbp->baddr);
+ __m_free(&mp0, vbp, sizeof(*vbp), "VTOB");
+ --mp->nump;
+ }
+}
+
+static inline m_pool_s *___get_dma_pool(m_bush_t bush)
+{
+ m_pool_s *mp;
+ for (mp = mp0.next; mp && mp->bush != bush; mp = mp->next);
+ return mp;
+}
+
+static m_pool_s *___cre_dma_pool(m_bush_t bush)
+{
+ m_pool_s *mp;
+ mp = __m_calloc(&mp0, sizeof(*mp), "MPOOL");
+ if (mp) {
+ bzero(mp, sizeof(*mp));
+ mp->bush = bush;
+ mp->getp = ___dma_getp;
+ mp->freep = ___dma_freep;
+ mp->next = mp0.next;
+ mp0.next = mp;
+ }
+ return mp;
+}
+
+static void ___del_dma_pool(m_pool_s *p)
+{
+ struct m_pool **pp = &mp0.next;
+
+ while (*pp && *pp != p)
+ pp = &(*pp)->next;
+ if (*pp) {
+ *pp = (*pp)->next;
+ __m_free(&mp0, p, sizeof(*p), "MPOOL");
+ }
+}
+
+static void *__m_calloc_dma(m_bush_t bush, int size, char *name)
+{
+ u_long flags;
+ struct m_pool *mp;
+ void *m = 0;
+
+ NCR_LOCK_DRIVER(flags);
+ mp = ___get_dma_pool(bush);
+ if (!mp)
+ mp = ___cre_dma_pool(bush);
+ if (mp)
+ m = __m_calloc(mp, size, name);
+ if (mp && !mp->nump)
+ ___del_dma_pool(mp);
+ NCR_UNLOCK_DRIVER(flags);
+
+ return m;
+}
+
+static void __m_free_dma(m_bush_t bush, void *m, int size, char *name)
+{
+ u_long flags;
+ struct m_pool *mp;
+
+ NCR_LOCK_DRIVER(flags);
+ mp = ___get_dma_pool(bush);
+ if (mp)
+ __m_free(mp, m, size, name);
+ if (mp && !mp->nump)
+ ___del_dma_pool(mp);
+ NCR_UNLOCK_DRIVER(flags);
+}
+
+static m_addr_t __vtobus(m_bush_t bush, void *m)
+{
+ u_long flags;
+ m_pool_s *mp;
+ int hc = VTOB_HASH_CODE(m);
+ m_vtob_s *vp = 0;
+ m_addr_t a = ((m_addr_t) m) & ~MEMO_CLUSTER_MASK;
+
+ NCR_LOCK_DRIVER(flags);
+ mp = ___get_dma_pool(bush);
+ if (mp) {
+ vp = mp->vtob[hc];
+ while (vp && (m_addr_t) vp->vaddr != a)
+ vp = vp->next;
+ }
+ NCR_UNLOCK_DRIVER(flags);
+ return vp ? vp->baddr + (((m_addr_t) m) - a) : 0;
+}
+
+#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */
+
+#define _m_calloc_dma(np, s, n) __m_calloc_dma(np->pdev, s, n)
+#define _m_free_dma(np, p, s, n) __m_free_dma(np->pdev, p, s, n)
+#define m_calloc_dma(s, n) _m_calloc_dma(np, s, n)
+#define m_free_dma(p, s, n) _m_free_dma(np, p, s, n)
+#define _vtobus(np, p) __vtobus(np->pdev, p)
+#define vtobus(p) _vtobus(np, p)
+
+/*
+ * Deal with DMA mapping/unmapping.
+ */
+
+#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING
+
+/* Linux versions prior to pci bus iommu kernel interface */
+
+#define __unmap_scsi_data(pdev, cmd) do {; } while (0)
+#define __map_scsi_single_data(pdev, cmd) (__vtobus(pdev,(cmd)->request_buffer))
+#define __map_scsi_sg_data(pdev, cmd) ((cmd)->use_sg)
+#define __sync_scsi_data(pdev, cmd) do {; } while (0)
+
+#define scsi_sg_dma_address(sc) vtobus((sc)->address)
+#define scsi_sg_dma_len(sc) ((sc)->length)
+
+#else
+
+/* Linux version with pci bus iommu kernel interface */
+
+/* To keep track of the dma mapping (sg/single) that has been set */
+#define __data_mapped SCp.phase
+#define __data_mapping SCp.have_data_in
+
+static void __unmap_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd)
+{
+ int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+ switch(cmd->__data_mapped) {
+ case 2:
+ pci_unmap_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+ break;
+ case 1:
+ pci_unmap_single(pdev, cmd->__data_mapping,
+ cmd->request_bufflen, dma_dir);
+ break;
+ }
+ cmd->__data_mapped = 0;
+}
+
+static u_long __map_scsi_single_data(pcidev_t pdev, Scsi_Cmnd *cmd)
+{
+ dma_addr_t mapping;
+ int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+ if (cmd->request_bufflen == 0)
+ return 0;
+
+ mapping = pci_map_single(pdev, cmd->request_buffer,
+ cmd->request_bufflen, dma_dir);
+ cmd->__data_mapped = 1;
+ cmd->__data_mapping = mapping;
+
+ return mapping;
+}
+
+static int __map_scsi_sg_data(pcidev_t pdev, Scsi_Cmnd *cmd)
+{
+ int use_sg;
+ int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+ if (cmd->use_sg == 0)
+ return 0;
+
+ use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+ cmd->__data_mapped = 2;
+ cmd->__data_mapping = use_sg;
+
+ return use_sg;
+}
+
+static void __sync_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd)
+{
+ int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+ switch(cmd->__data_mapped) {
+ case 2:
+ pci_dma_sync_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+ break;
+ case 1:
+ pci_dma_sync_single(pdev, cmd->__data_mapping,
+ cmd->request_bufflen, dma_dir);
+ break;
+ }
+}
+
+#define scsi_sg_dma_address(sc) sg_dma_address(sc)
+#define scsi_sg_dma_len(sc) sg_dma_len(sc)
+
+#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */
+
+#define unmap_scsi_data(np, cmd) __unmap_scsi_data(np->pdev, cmd)
+#define map_scsi_single_data(np, cmd) __map_scsi_single_data(np->pdev, cmd)
+#define map_scsi_sg_data(np, cmd) __map_scsi_sg_data(np->pdev, cmd)
+#define sync_scsi_data(np, cmd) __sync_scsi_data(np->pdev, cmd)
+
+/*==========================================================
+**
+** SCSI data transfer direction
+**
+** Until some linux kernel version near 2.3.40,
+** low-level scsi drivers were not told about data
+** transfer direction. We check the existence of this
+** feature that has been expected for a _long_ time by
+** all SCSI driver developers by just testing against
+** the definition of SCSI_DATA_UNKNOWN. Indeed this is
+** a hack, but testing against a kernel version would
+** have been a shame. ;-)
+**
+**==========================================================
+*/
+#ifdef SCSI_DATA_UNKNOWN
+
+#define scsi_data_direction(cmd) (cmd->sc_data_direction)
+
+#else
+
+#define SCSI_DATA_UNKNOWN 0
+#define SCSI_DATA_WRITE 1
+#define SCSI_DATA_READ 2
+#define SCSI_DATA_NONE 3
+
+static __inline__ int scsi_data_direction(Scsi_Cmnd *cmd)
+{
+ int direction;
+
+ switch((int) cmd->cmnd[0]) {
+ case 0x08: /* READ(6) 08 */
+ case 0x28: /* READ(10) 28 */
+ case 0xA8: /* READ(12) A8 */
+ direction = SCSI_DATA_READ;
+ break;
+ case 0x0A: /* WRITE(6) 0A */
+ case 0x2A: /* WRITE(10) 2A */
+ case 0xAA: /* WRITE(12) AA */
+ direction = SCSI_DATA_WRITE;
+ break;
+ default:
+ direction = SCSI_DATA_UNKNOWN;
+ break;
+ }
+
+ return direction;
+}
+
+#endif /* SCSI_DATA_UNKNOWN */
+
+/*==========================================================
+**
+** Driver setup.
+**
+** This structure is initialized from linux config
+** options. It can be overridden at boot-up by the boot
+** command line.
+**
+**==========================================================
+*/
+static struct ncr_driver_setup
+ driver_setup = SCSI_NCR_DRIVER_SETUP;
+
+#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
+static struct ncr_driver_setup
+ driver_safe_setup __initdata = SCSI_NCR_DRIVER_SAFE_SETUP;
+#endif
+
+#define initverbose (driver_setup.verbose)
+#define bootverbose (np->verbose)
+
+/*==========================================================
+**
+** Big/Little endian support.
+**
+** If the NCR uses big endian addressing mode over the
+** PCI, actual io register addresses for byte and word
+** accesses must be changed according to lane routing.
+** Btw, ncr_offb() and ncr_offw() macros only apply to
+** constants and so donnot generate bloated code.
+**
+** If the CPU and the NCR use same endian-ness adressing,
+** no byte reordering is needed for script patching.
+** Macro cpu_to_scr() is to be used for script patching.
+** Macro scr_to_cpu() is to be used for getting a DWORD
+** from the script.
+**
+**==========================================================
+*/
+
+#if defined(SCSI_NCR_BIG_ENDIAN)
+
+#define ncr_offb(o) (((o)&~3)+((~((o)&3))&3))
+#define ncr_offw(o) (((o)&~3)+((~((o)&3))&2))
+
+#else
+
+#define ncr_offb(o) (o)
+#define ncr_offw(o) (o)
+
+#endif
+
+#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
+
+#define cpu_to_scr(dw) cpu_to_le32(dw)
+#define scr_to_cpu(dw) le32_to_cpu(dw)
+
+#elif defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
+
+#define cpu_to_scr(dw) cpu_to_be32(dw)
+#define scr_to_cpu(dw) be32_to_cpu(dw)
+
+#else
+
+#define cpu_to_scr(dw) (dw)
+#define scr_to_cpu(dw) (dw)
+
+#endif
+
+/*==========================================================
+**
+** Access to the controller chip.
+**
+** If NCR_IOMAPPED is defined, the driver will use
+** normal IOs instead of the MEMORY MAPPED IO method
+** recommended by PCI specifications.
+** If all PCI bridges, host brigdes and architectures
+** would have been correctly designed for PCI, this
+** option would be useless.
+**
+** If the CPU and the NCR use same endian-ness adressing,
+** no byte reordering is needed for accessing chip io
+** registers. Functions suffixed by '_raw' are assumed
+** to access the chip over the PCI without doing byte
+** reordering. Functions suffixed by '_l2b' are
+** assumed to perform little-endian to big-endian byte
+** reordering, those suffixed by '_b2l' blah, blah,
+** blah, ...
+**
+**==========================================================
+*/
+
+#if defined(NCR_IOMAPPED)
+
+/*
+** IO mapped only input / ouput
+*/
+
+#define INB_OFF(o) inb (np->base_io + ncr_offb(o))
+#define OUTB_OFF(o, val) outb ((val), np->base_io + ncr_offb(o))
+
+#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
+
+#define INW_OFF(o) inw_l2b (np->base_io + ncr_offw(o))
+#define INL_OFF(o) inl_l2b (np->base_io + (o))
+
+#define OUTW_OFF(o, val) outw_b2l ((val), np->base_io + ncr_offw(o))
+#define OUTL_OFF(o, val) outl_b2l ((val), np->base_io + (o))
+
+#elif defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
+
+#define INW_OFF(o) inw_b2l (np->base_io + ncr_offw(o))
+#define INL_OFF(o) inl_b2l (np->base_io + (o))
+
+#define OUTW_OFF(o, val) outw_l2b ((val), np->base_io + ncr_offw(o))
+#define OUTL_OFF(o, val) outl_l2b ((val), np->base_io + (o))
+
+#else
+
+#define INW_OFF(o) inw_raw (np->base_io + ncr_offw(o))
+#define INL_OFF(o) inl_raw (np->base_io + (o))
+
+#define OUTW_OFF(o, val) outw_raw ((val), np->base_io + ncr_offw(o))
+#define OUTL_OFF(o, val) outl_raw ((val), np->base_io + (o))
+
+#endif /* ENDIANs */
+
+#else /* defined NCR_IOMAPPED */
+
+/*
+** MEMORY mapped IO input / output
+*/
+
+#define INB_OFF(o) readb((char *)np->reg + ncr_offb(o))
+#define OUTB_OFF(o, val) writeb((val), (char *)np->reg + ncr_offb(o))
+
+#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
+
+#define INW_OFF(o) readw_l2b((char *)np->reg + ncr_offw(o))
+#define INL_OFF(o) readl_l2b((char *)np->reg + (o))
+
+#define OUTW_OFF(o, val) writew_b2l((val), (char *)np->reg + ncr_offw(o))
+#define OUTL_OFF(o, val) writel_b2l((val), (char *)np->reg + (o))
+
+#elif defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
+
+#define INW_OFF(o) readw_b2l((char *)np->reg + ncr_offw(o))
+#define INL_OFF(o) readl_b2l((char *)np->reg + (o))
+
+#define OUTW_OFF(o, val) writew_l2b((val), (char *)np->reg + ncr_offw(o))
+#define OUTL_OFF(o, val) writel_l2b((val), (char *)np->reg + (o))
+
+#else
+
+#define INW_OFF(o) readw_raw((char *)np->reg + ncr_offw(o))
+#define INL_OFF(o) readl_raw((char *)np->reg + (o))
+
+#define OUTW_OFF(o, val) writew_raw((val), (char *)np->reg + ncr_offw(o))
+#define OUTL_OFF(o, val) writel_raw((val), (char *)np->reg + (o))
+
+#endif
+
+#endif /* defined NCR_IOMAPPED */
+
+#define INB(r) INB_OFF (offsetof(struct ncr_reg,r))
+#define INW(r) INW_OFF (offsetof(struct ncr_reg,r))
+#define INL(r) INL_OFF (offsetof(struct ncr_reg,r))
+
+#define OUTB(r, val) OUTB_OFF (offsetof(struct ncr_reg,r), (val))
+#define OUTW(r, val) OUTW_OFF (offsetof(struct ncr_reg,r), (val))
+#define OUTL(r, val) OUTL_OFF (offsetof(struct ncr_reg,r), (val))
+
+/*
+** Set bit field ON, OFF
+*/
+
+#define OUTONB(r, m) OUTB(r, INB(r) | (m))
+#define OUTOFFB(r, m) OUTB(r, INB(r) & ~(m))
+#define OUTONW(r, m) OUTW(r, INW(r) | (m))
+#define OUTOFFW(r, m) OUTW(r, INW(r) & ~(m))
+#define OUTONL(r, m) OUTL(r, INL(r) | (m))
+#define OUTOFFL(r, m) OUTL(r, INL(r) & ~(m))
+
+
+/*==========================================================
+**
+** Structures used by the detection routine to transmit
+** device configuration to the attach function.
+**
+**==========================================================
+*/
+typedef struct {
+ int bus;
+ u_char device_fn;
+ u_long base;
+ u_long base_2;
+ u_long io_port;
+ int irq;
+/* port and reg fields to use INB, OUTB macros */
+ u_long base_io;
+ volatile struct ncr_reg *reg;
+} ncr_slot;
+
+/*==========================================================
+**
+** Structure used to store the NVRAM content.
+**
+**==========================================================
+*/
+typedef struct {
+ int type;
+#define SCSI_NCR_SYMBIOS_NVRAM (1)
+#define SCSI_NCR_TEKRAM_NVRAM (2)
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+ union {
+ Symbios_nvram Symbios;
+ Tekram_nvram Tekram;
+ } data;
+#endif
+} ncr_nvram;
+
+/*==========================================================
+**
+** Structure used by detection routine to save data on
+** each detected board for attach.
+**
+**==========================================================
+*/
+typedef struct {
+ pcidev_t pdev;
+ ncr_slot slot;
+ ncr_chip chip;
+ ncr_nvram *nvram;
+ u_char host_id;
+#ifdef SCSI_NCR_PQS_PDS_SUPPORT
+ u_char pqs_pds;
+#endif
+ int attach_done;
+} ncr_device;
+
+static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device);
+
+/*==========================================================
+**
+** NVRAM detection and reading.
+**
+** Currently supported:
+** - 24C16 EEPROM with both Symbios and Tekram layout.
+** - 93C46 EEPROM with Tekram layout.
+**
+**==========================================================
+*/
+
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+/*
+ * 24C16 EEPROM reading.
+ *
+ * GPOI0 - data in/data out
+ * GPIO1 - clock
+ * Symbios NVRAM wiring now also used by Tekram.
+ */
+
+#define SET_BIT 0
+#define CLR_BIT 1
+#define SET_CLK 2
+#define CLR_CLK 3
+
+/*
+ * Set/clear data/clock bit in GPIO0
+ */
+static void __init
+S24C16_set_bit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode)
+{
+ UDELAY (5);
+ switch (bit_mode){
+ case SET_BIT:
+ *gpreg |= write_bit;
+ break;
+ case CLR_BIT:
+ *gpreg &= 0xfe;
+ break;
+ case SET_CLK:
+ *gpreg |= 0x02;
+ break;
+ case CLR_CLK:
+ *gpreg &= 0xfd;
+ break;
+
+ }
+ OUTB (nc_gpreg, *gpreg);
+ UDELAY (5);
+}
+
+/*
+ * Send START condition to NVRAM to wake it up.
+ */
+static void __init S24C16_start(ncr_slot *np, u_char *gpreg)
+{
+ S24C16_set_bit(np, 1, gpreg, SET_BIT);
+ S24C16_set_bit(np, 0, gpreg, SET_CLK);
+ S24C16_set_bit(np, 0, gpreg, CLR_BIT);
+ S24C16_set_bit(np, 0, gpreg, CLR_CLK);
+}
+
+/*
+ * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!!
+ */
+static void __init S24C16_stop(ncr_slot *np, u_char *gpreg)
+{
+ S24C16_set_bit(np, 0, gpreg, SET_CLK);
+ S24C16_set_bit(np, 1, gpreg, SET_BIT);
+}
+
+/*
+ * Read or write a bit to the NVRAM,
+ * read if GPIO0 input else write if GPIO0 output
+ */
+static void __init
+S24C16_do_bit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg)
+{
+ S24C16_set_bit(np, write_bit, gpreg, SET_BIT);
+ S24C16_set_bit(np, 0, gpreg, SET_CLK);
+ if (read_bit)
+ *read_bit = INB (nc_gpreg);
+ S24C16_set_bit(np, 0, gpreg, CLR_CLK);
+ S24C16_set_bit(np, 0, gpreg, CLR_BIT);
+}
+
+/*
+ * Output an ACK to the NVRAM after reading,
+ * change GPIO0 to output and when done back to an input
+ */
+static void __init
+S24C16_write_ack(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl)
+{
+ OUTB (nc_gpcntl, *gpcntl & 0xfe);
+ S24C16_do_bit(np, 0, write_bit, gpreg);
+ OUTB (nc_gpcntl, *gpcntl);
+}
+
+/*
+ * Input an ACK from NVRAM after writing,
+ * change GPIO0 to input and when done back to an output
+ */
+static void __init
+S24C16_read_ack(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl)
+{
+ OUTB (nc_gpcntl, *gpcntl | 0x01);
+ S24C16_do_bit(np, read_bit, 1, gpreg);
+ OUTB (nc_gpcntl, *gpcntl);
+}
+
+/*
+ * WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK,
+ * GPIO0 must already be set as an output
+ */
+static void __init
+S24C16_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data,
+ u_char *gpreg, u_char *gpcntl)
+{
+ int x;
+
+ for (x = 0; x < 8; x++)
+ S24C16_do_bit(np, 0, (write_data >> (7 - x)) & 0x01, gpreg);
+
+ S24C16_read_ack(np, ack_data, gpreg, gpcntl);
+}
+
+/*
+ * READ a byte from the NVRAM and then send an ACK to say we have got it,
+ * GPIO0 must already be set as an input
+ */
+static void __init
+S24C16_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data,
+ u_char *gpreg, u_char *gpcntl)
+{
+ int x;
+ u_char read_bit;
+
+ *read_data = 0;
+ for (x = 0; x < 8; x++) {
+ S24C16_do_bit(np, &read_bit, 1, gpreg);
+ *read_data |= ((read_bit & 0x01) << (7 - x));
+ }
+
+ S24C16_write_ack(np, ack_data, gpreg, gpcntl);
+}
+
+/*
+ * Read 'len' bytes starting at 'offset'.
+ */
+static int __init
+sym_read_S24C16_nvram (ncr_slot *np, int offset, u_char *data, int len)
+{
+ u_char gpcntl, gpreg;
+ u_char old_gpcntl, old_gpreg;
+ u_char ack_data;
+ int retv = 1;
+ int x;
+
+ /* save current state of GPCNTL and GPREG */
+ old_gpreg = INB (nc_gpreg);
+ old_gpcntl = INB (nc_gpcntl);
+ gpcntl = old_gpcntl & 0xfc;
+
+ /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
+ OUTB (nc_gpreg, old_gpreg);
+ OUTB (nc_gpcntl, gpcntl);
+
+ /* this is to set NVRAM into a known state with GPIO0/1 both low */
+ gpreg = old_gpreg;
+ S24C16_set_bit(np, 0, &gpreg, CLR_CLK);
+ S24C16_set_bit(np, 0, &gpreg, CLR_BIT);
+
+ /* now set NVRAM inactive with GPIO0/1 both high */
+ S24C16_stop(np, &gpreg);
+
+ /* activate NVRAM */
+ S24C16_start(np, &gpreg);
+
+ /* write device code and random address MSB */
+ S24C16_write_byte(np, &ack_data,
+ 0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
+ if (ack_data & 0x01)
+ goto out;
+
+ /* write random address LSB */
+ S24C16_write_byte(np, &ack_data,
+ offset & 0xff, &gpreg, &gpcntl);
+ if (ack_data & 0x01)
+ goto out;
+
+ /* regenerate START state to set up for reading */
+ S24C16_start(np, &gpreg);
+
+ /* rewrite device code and address MSB with read bit set (lsb = 0x01) */
+ S24C16_write_byte(np, &ack_data,
+ 0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
+ if (ack_data & 0x01)
+ goto out;
+
+ /* now set up GPIO0 for inputting data */
+ gpcntl |= 0x01;
+ OUTB (nc_gpcntl, gpcntl);
+
+ /* input all requested data - only part of total NVRAM */
+ for (x = 0; x < len; x++)
+ S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl);
+
+ /* finally put NVRAM back in inactive mode */
+ gpcntl &= 0xfe;
+ OUTB (nc_gpcntl, gpcntl);
+ S24C16_stop(np, &gpreg);
+ retv = 0;
+out:
+ /* return GPIO0/1 to original states after having accessed NVRAM */
+ OUTB (nc_gpcntl, old_gpcntl);
+ OUTB (nc_gpreg, old_gpreg);
+
+ return retv;
+}
+
+#undef SET_BIT 0
+#undef CLR_BIT 1
+#undef SET_CLK 2
+#undef CLR_CLK 3
+
+/*
+ * Try reading Symbios NVRAM.
+ * Return 0 if OK.
+ */
+static int __init sym_read_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram)
+{
+ static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0};
+ u_char *data = (u_char *) nvram;
+ int len = sizeof(*nvram);
+ u_short csum;
+ int x;
+
+ /* probe the 24c16 and read the SYMBIOS 24c16 area */
+ if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len))
+ return 1;
+
+ /* check valid NVRAM signature, verify byte count and checksum */
+ if (nvram->type != 0 ||
+ memcmp(nvram->trailer, Symbios_trailer, 6) ||
+ nvram->byte_count != len - 12)
+ return 1;
+
+ /* verify checksum */
+ for (x = 6, csum = 0; x < len - 6; x++)
+ csum += data[x];
+ if (csum != nvram->checksum)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * 93C46 EEPROM reading.
+ *
+ * GPOI0 - data in
+ * GPIO1 - data out
+ * GPIO2 - clock
+ * GPIO4 - chip select
+ *
+ * Used by Tekram.
+ */
+
+/*
+ * Pulse clock bit in GPIO0
+ */
+static void __init T93C46_Clk(ncr_slot *np, u_char *gpreg)
+{
+ OUTB (nc_gpreg, *gpreg | 0x04);
+ UDELAY (2);
+ OUTB (nc_gpreg, *gpreg);
+}
+
+/*
+ * Read bit from NVRAM
+ */
+static void __init T93C46_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
+{
+ UDELAY (2);
+ T93C46_Clk(np, gpreg);
+ *read_bit = INB (nc_gpreg);
+}
+
+/*
+ * Write bit to GPIO0
+ */
+static void __init T93C46_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg)
+{
+ if (write_bit & 0x01)
+ *gpreg |= 0x02;
+ else
+ *gpreg &= 0xfd;
+
+ *gpreg |= 0x10;
+
+ OUTB (nc_gpreg, *gpreg);
+ UDELAY (2);
+
+ T93C46_Clk(np, gpreg);
+}
+
+/*
+ * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!!
+ */
+static void __init T93C46_Stop(ncr_slot *np, u_char *gpreg)
+{
+ *gpreg &= 0xef;
+ OUTB (nc_gpreg, *gpreg);
+ UDELAY (2);
+
+ T93C46_Clk(np, gpreg);
+}
+
+/*
+ * Send read command and address to NVRAM
+ */
+static void __init
+T93C46_Send_Command(ncr_slot *np, u_short write_data,
+ u_char *read_bit, u_char *gpreg)
+{
+ int x;
+
+ /* send 9 bits, start bit (1), command (2), address (6) */
+ for (x = 0; x < 9; x++)
+ T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg);
+
+ *read_bit = INB (nc_gpreg);
+}
+
+/*
+ * READ 2 bytes from the NVRAM
+ */
+static void __init
+T93C46_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg)
+{
+ int x;
+ u_char read_bit;
+
+ *nvram_data = 0;
+ for (x = 0; x < 16; x++) {
+ T93C46_Read_Bit(np, &read_bit, gpreg);
+
+ if (read_bit & 0x01)
+ *nvram_data |= (0x01 << (15 - x));
+ else
+ *nvram_data &= ~(0x01 << (15 - x));
+ }
+}
+
+/*
+ * Read Tekram NvRAM data.
+ */
+static int __init
+T93C46_Read_Data(ncr_slot *np, u_short *data,int len,u_char *gpreg)
+{
+ u_char read_bit;
+ int x;
+
+ for (x = 0; x < len; x++) {
+
+ /* output read command and address */
+ T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg);
+ if (read_bit & 0x01)
+ return 1; /* Bad */
+ T93C46_Read_Word(np, &data[x], gpreg);
+ T93C46_Stop(np, gpreg);
+ }
+
+ return 0;
+}
+
+/*
+ * Try reading 93C46 Tekram NVRAM.
+ */
+static int __init
+sym_read_T93C46_nvram (ncr_slot *np, Tekram_nvram *nvram)
+{
+ u_char gpcntl, gpreg;
+ u_char old_gpcntl, old_gpreg;
+ int retv = 1;
+
+ /* save current state of GPCNTL and GPREG */
+ old_gpreg = INB (nc_gpreg);
+ old_gpcntl = INB (nc_gpcntl);
+
+ /* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in,
+ 1/2/4 out */
+ gpreg = old_gpreg & 0xe9;
+ OUTB (nc_gpreg, gpreg);
+ gpcntl = (old_gpcntl & 0xe9) | 0x09;
+ OUTB (nc_gpcntl, gpcntl);
+
+ /* input all of NVRAM, 64 words */
+ retv = T93C46_Read_Data(np, (u_short *) nvram,
+ sizeof(*nvram) / sizeof(short), &gpreg);
+
+ /* return GPIO0/1/2/4 to original states after having accessed NVRAM */
+ OUTB (nc_gpcntl, old_gpcntl);
+ OUTB (nc_gpreg, old_gpreg);
+
+ return retv;
+}
+
+/*
+ * Try reading Tekram NVRAM.
+ * Return 0 if OK.
+ */
+static int __init
+sym_read_Tekram_nvram (ncr_slot *np, u_short device_id, Tekram_nvram *nvram)
+{
+ u_char *data = (u_char *) nvram;
+ int len = sizeof(*nvram);
+ u_short csum;
+ int x;
+
+ switch (device_id) {
+ case PCI_DEVICE_ID_NCR_53C885:
+ case PCI_DEVICE_ID_NCR_53C895:
+ case PCI_DEVICE_ID_NCR_53C896:
+ x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
+ data, len);
+ break;
+ case PCI_DEVICE_ID_NCR_53C875:
+ x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
+ data, len);
+ if (!x)
+ break;
+ default:
+ x = sym_read_T93C46_nvram(np, nvram);
+ break;
+ }
+ if (x)
+ return 1;
+
+ /* verify checksum */
+ for (x = 0, csum = 0; x < len - 1; x += 2)
+ csum += data[x] + (data[x+1] << 8);
+ if (csum != 0x1234)
+ return 1;
+
+ return 0;
+}
+
+#endif /* SCSI_NCR_NVRAM_SUPPORT */
+
+/*===================================================================
+**
+** Detect and try to read SYMBIOS and TEKRAM NVRAM.
+**
+** Data can be used to order booting of boards.
+**
+** Data is saved in ncr_device structure if NVRAM found. This
+** is then used to find drive boot order for ncr_attach().
+**
+** NVRAM data is passed to Scsi_Host_Template later during
+** ncr_attach() for any device set up.
+**
+**===================================================================
+*/
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+static void __init ncr_get_nvram(ncr_device *devp, ncr_nvram *nvp)
+{
+ devp->nvram = nvp;
+ if (!nvp)
+ return;
+ /*
+ ** Get access to chip IO registers
+ */
+#ifdef NCR_IOMAPPED
+ request_region(devp->slot.io_port, 128, NAME53C8XX);
+ devp->slot.base_io = devp->slot.io_port;
+#else
+ devp->slot.reg = (struct ncr_reg *) remap_pci_mem(devp->slot.base, 128);
+ if (!devp->slot.reg)
+ return;
+#endif
+
+ /*
+ ** Try to read SYMBIOS nvram.
+ ** Try to read TEKRAM nvram if Symbios nvram not found.
+ */
+ if (!sym_read_Symbios_nvram(&devp->slot, &nvp->data.Symbios))
+ nvp->type = SCSI_NCR_SYMBIOS_NVRAM;
+ else if (!sym_read_Tekram_nvram(&devp->slot, devp->chip.device_id,
+ &nvp->data.Tekram))
+ nvp->type = SCSI_NCR_TEKRAM_NVRAM;
+ else {
+ nvp->type = 0;
+ devp->nvram = 0;
+ }
+
+ /*
+ ** Release access to chip IO registers
+ */
+#ifdef NCR_IOMAPPED
+ release_region(devp->slot.base_io, 128);
+#else
+ unmap_pci_mem((u_long) devp->slot.reg, 128ul);
+#endif
+
+}
+
+/*===================================================================
+**
+** Display the content of NVRAM for debugging purpose.
+**
+**===================================================================
+*/
+#ifdef SCSI_NCR_DEBUG_NVRAM
+static void __init ncr_display_Symbios_nvram(Symbios_nvram *nvram)
+{
+ int i;
+
+ /* display Symbios nvram host data */
+ printk(KERN_DEBUG NAME53C8XX ": HOST ID=%d%s%s%s%s%s\n",
+ nvram->host_id & 0x0f,
+ (nvram->flags & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"",
+ (nvram->flags & SYMBIOS_PARITY_ENABLE) ? " PARITY" :"",
+ (nvram->flags & SYMBIOS_VERBOSE_MSGS) ? " VERBOSE" :"",
+ (nvram->flags & SYMBIOS_CHS_MAPPING) ? " CHS_ALT" :"",
+ (nvram->flags1 & SYMBIOS_SCAN_HI_LO) ? " HI_LO" :"");
+
+ /* display Symbios nvram drive data */
+ for (i = 0 ; i < 15 ; i++) {
+ struct Symbios_target *tn = &nvram->target[i];
+ printk(KERN_DEBUG NAME53C8XX
+ "-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n",
+ i,
+ (tn->flags & SYMBIOS_DISCONNECT_ENABLE) ? " DISC" : "",
+ (tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME) ? " SCAN_BOOT" : "",
+ (tn->flags & SYMBIOS_SCAN_LUNS) ? " SCAN_LUNS" : "",
+ (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ" : "",
+ tn->bus_width,
+ tn->sync_period / 4,
+ tn->timeout);
+ }
+}
+
+static u_char Tekram_boot_delay[7] __initdata = {3, 5, 10, 20, 30, 60, 120};
+
+static void __init ncr_display_Tekram_nvram(Tekram_nvram *nvram)
+{
+ int i, tags, boot_delay;
+ char *rem;
+
+ /* display Tekram nvram host data */
+ tags = 2 << nvram->max_tags_index;
+ boot_delay = 0;
+ if (nvram->boot_delay_index < 6)
+ boot_delay = Tekram_boot_delay[nvram->boot_delay_index];
+ switch((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) {
+ default:
+ case 0: rem = ""; break;
+ case 1: rem = " REMOVABLE=boot device"; break;
+ case 2: rem = " REMOVABLE=all"; break;
+ }
+
+ printk(KERN_DEBUG NAME53C8XX
+ ": HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n",
+ nvram->host_id & 0x0f,
+ (nvram->flags1 & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"",
+ (nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES":"",
+ (nvram->flags & TEKRAM_DRIVES_SUP_1GB) ? " >1GB" :"",
+ (nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET" :"",
+ (nvram->flags & TEKRAM_ACTIVE_NEGATION) ? " ACT_NEG" :"",
+ (nvram->flags & TEKRAM_IMMEDIATE_SEEK) ? " IMM_SEEK" :"",
+ (nvram->flags & TEKRAM_SCAN_LUNS) ? " SCAN_LUNS" :"",
+ (nvram->flags1 & TEKRAM_F2_F6_ENABLED) ? " F2_F6" :"",
+ rem, boot_delay, tags);
+
+ /* display Tekram nvram drive data */
+ for (i = 0; i <= 15; i++) {
+ int sync, j;
+ struct Tekram_target *tn = &nvram->target[i];
+ j = tn->sync_index & 0xf;
+ sync = Tekram_sync[j];
+ printk(KERN_DEBUG NAME53C8XX "-%d:%s%s%s%s%s%s PERIOD=%d\n",
+ i,
+ (tn->flags & TEKRAM_PARITY_CHECK) ? " PARITY" : "",
+ (tn->flags & TEKRAM_SYNC_NEGO) ? " SYNC" : "",
+ (tn->flags & TEKRAM_DISCONNECT_ENABLE) ? " DISC" : "",
+ (tn->flags & TEKRAM_START_CMD) ? " START" : "",
+ (tn->flags & TEKRAM_TAGGED_COMMANDS) ? " TCQ" : "",
+ (tn->flags & TEKRAM_WIDE_NEGO) ? " WIDE" : "",
+ sync);
+ }
+}
+#endif /* SCSI_NCR_DEBUG_NVRAM */
+#endif /* SCSI_NCR_NVRAM_SUPPORT */
+
+
+/*===================================================================
+**
+** Utility routines that protperly return data through /proc FS.
+**
+**===================================================================
+*/
+#ifdef SCSI_NCR_USER_INFO_SUPPORT
+
+struct info_str
+{
+ char *buffer;
+ int length;
+ int offset;
+ int pos;
+};
+
+static void copy_mem_info(struct info_str *info, char *data, int len)
+{
+ if (info->pos + len > info->length)
+ len = info->length - info->pos;
+
+ if (info->pos + len < info->offset) {
+ info->pos += len;
+ return;
+ }
+ if (info->pos < info->offset) {
+ data += (info->offset - info->pos);
+ len -= (info->offset - info->pos);
+ }
+
+ if (len > 0) {
+ memcpy(info->buffer + info->pos, data, len);
+ info->pos += len;
+ }
+}
+
+static int copy_info(struct info_str *info, char *fmt, ...)
+{
+ va_list args;
+ char buf[81];
+ int len;
+
+ va_start(args, fmt);
+ len = vsprintf(buf, fmt, args);
+ va_end(args);
+
+ copy_mem_info(info, buf, len);
+ return len;
+}
+
+#endif
+
+/*===================================================================
+**
+** Driver setup from the boot command line
+**
+**===================================================================
+*/
+
+#ifdef MODULE
+#define ARG_SEP ' '
+#else
+#define ARG_SEP ','
+#endif
+
+#define OPT_TAGS 1
+#define OPT_MASTER_PARITY 2
+#define OPT_SCSI_PARITY 3
+#define OPT_DISCONNECTION 4
+#define OPT_SPECIAL_FEATURES 5
+#define OPT_ULTRA_SCSI 6
+#define OPT_FORCE_SYNC_NEGO 7
+#define OPT_REVERSE_PROBE 8
+#define OPT_DEFAULT_SYNC 9
+#define OPT_VERBOSE 10
+#define OPT_DEBUG 11
+#define OPT_BURST_MAX 12
+#define OPT_LED_PIN 13
+#define OPT_MAX_WIDE 14
+#define OPT_SETTLE_DELAY 15
+#define OPT_DIFF_SUPPORT 16
+#define OPT_IRQM 17
+#define OPT_PCI_FIX_UP 18
+#define OPT_BUS_CHECK 19
+#define OPT_OPTIMIZE 20
+#define OPT_RECOVERY 21
+#define OPT_SAFE_SETUP 22
+#define OPT_USE_NVRAM 23
+#define OPT_EXCLUDE 24
+#define OPT_HOST_ID 25
+
+#ifdef SCSI_NCR_IARB_SUPPORT
+#define OPT_IARB 26
+#endif
+
+static char setup_token[] __initdata =
+ "tags:" "mpar:"
+ "spar:" "disc:"
+ "specf:" "ultra:"
+ "fsn:" "revprob:"
+ "sync:" "verb:"
+ "debug:" "burst:"
+ "led:" "wide:"
+ "settle:" "diff:"
+ "irqm:" "pcifix:"
+ "buschk:" "optim:"
+ "recovery:"
+ "safe:" "nvram:"
+ "excl:" "hostid:"
+#ifdef SCSI_NCR_IARB_SUPPORT
+ "iarb:"
+#endif
+ ; /* DONNOT REMOVE THIS ';' */
+
+#ifdef MODULE
+#define ARG_SEP ' '
+#else
+#define ARG_SEP ','
+#endif
+
+static int __init get_setup_token(char *p)
+{
+ char *cur = setup_token;
+ char *pc;
+ int i = 0;
+
+ while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+ ++pc;
+ ++i;
+ if (!strncmp(p, cur, pc - cur))
+ return i;
+ cur = pc;
+ }
+ return 0;
+}
+
+
+static int __init sym53c8xx__setup(char *str)
+{
+#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
+ char *cur = str;
+ char *pc, *pv;
+ int i, val, c;
+ int xi = 0;
+
+ while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+ char *pe;
+
+ val = 0;
+ pv = pc;
+ c = *++pv;
+
+ if (c == 'n')
+ val = 0;
+ else if (c == 'y')
+ val = 1;
+ else
+ val = (int) simple_strtoul(pv, &pe, 0);
+
+ switch (get_setup_token(cur)) {
+ case OPT_TAGS:
+ driver_setup.default_tags = val;
+ if (pe && *pe == '/') {
+ i = 0;
+ while (*pe && *pe != ARG_SEP &&
+ i < sizeof(driver_setup.tag_ctrl)-1) {
+ driver_setup.tag_ctrl[i++] = *pe++;
+ }
+ driver_setup.tag_ctrl[i] = '\0';
+ }
+ break;
+ case OPT_MASTER_PARITY:
+ driver_setup.master_parity = val;
+ break;
+ case OPT_SCSI_PARITY:
+ driver_setup.scsi_parity = val;
+ break;
+ case OPT_DISCONNECTION:
+ driver_setup.disconnection = val;
+ break;
+ case OPT_SPECIAL_FEATURES:
+ driver_setup.special_features = val;
+ break;
+ case OPT_ULTRA_SCSI:
+ driver_setup.ultra_scsi = val;
+ break;
+ case OPT_FORCE_SYNC_NEGO:
+ driver_setup.force_sync_nego = val;
+ break;
+ case OPT_REVERSE_PROBE:
+ driver_setup.reverse_probe = val;
+ break;
+ case OPT_DEFAULT_SYNC:
+ driver_setup.default_sync = val;
+ break;
+ case OPT_VERBOSE:
+ driver_setup.verbose = val;
+ break;
+ case OPT_DEBUG:
+ driver_setup.debug = val;
+ break;
+ case OPT_BURST_MAX:
+ driver_setup.burst_max = val;
+ break;
+ case OPT_LED_PIN:
+ driver_setup.led_pin = val;
+ break;
+ case OPT_MAX_WIDE:
+ driver_setup.max_wide = val? 1:0;
+ break;
+ case OPT_SETTLE_DELAY:
+ driver_setup.settle_delay = val;
+ break;
+ case OPT_DIFF_SUPPORT:
+ driver_setup.diff_support = val;
+ break;
+ case OPT_IRQM:
+ driver_setup.irqm = val;
+ break;
+ case OPT_PCI_FIX_UP:
+ driver_setup.pci_fix_up = val;
+ break;
+ case OPT_BUS_CHECK:
+ driver_setup.bus_check = val;
+ break;
+ case OPT_OPTIMIZE:
+ driver_setup.optimize = val;
+ break;
+ case OPT_RECOVERY:
+ driver_setup.recovery = val;
+ break;
+ case OPT_USE_NVRAM:
+ driver_setup.use_nvram = val;
+ break;
+ case OPT_SAFE_SETUP:
+ memcpy(&driver_setup, &driver_safe_setup,
+ sizeof(driver_setup));
+ break;
+ case OPT_EXCLUDE:
+ if (xi < SCSI_NCR_MAX_EXCLUDES)
+ driver_setup.excludes[xi++] = val;
+ break;
+ case OPT_HOST_ID:
+ driver_setup.host_id = val;
+ break;
+#ifdef SCSI_NCR_IARB_SUPPORT
+ case OPT_IARB:
+ driver_setup.iarb = val;
+ break;
+#endif
+ default:
+ printk("sym53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
+ break;
+ }
+
+ if ((cur = strchr(cur, ARG_SEP)) != NULL)
+ ++cur;
+ }
+#endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
+ return 0;
+}
+
+/*===================================================================
+**
+** Get device queue depth from boot command line.
+**
+**===================================================================
+*/
+#define DEF_DEPTH (driver_setup.default_tags)
+#define ALL_TARGETS -2
+#define NO_TARGET -1
+#define ALL_LUNS -2
+#define NO_LUN -1
+
+static int device_queue_depth(int unit, int target, int lun)
+{
+ int c, h, t, u, v;
+ char *p = driver_setup.tag_ctrl;
+ char *ep;
+
+ h = -1;
+ t = NO_TARGET;
+ u = NO_LUN;
+ while ((c = *p++) != 0) {
+ v = simple_strtoul(p, &ep, 0);
+ switch(c) {
+ case '/':
+ ++h;
+ t = ALL_TARGETS;
+ u = ALL_LUNS;
+ break;
+ case 't':
+ if (t != target)
+ t = (target == v) ? v : NO_TARGET;
+ u = ALL_LUNS;
+ break;
+ case 'u':
+ if (u != lun)
+ u = (lun == v) ? v : NO_LUN;
+ break;
+ case 'q':
+ if (h == unit &&
+ (t == ALL_TARGETS || t == target) &&
+ (u == ALL_LUNS || u == lun))
+ return v;
+ break;
+ case '-':
+ t = ALL_TARGETS;
+ u = ALL_LUNS;
+ break;
+ default:
+ break;
+ }
+ p = ep;
+ }
+ return DEF_DEPTH;
+}
+
+/*===================================================================
+**
+** Print out information about driver configuration.
+**
+**===================================================================
+*/
+static void __init ncr_print_driver_setup(void)
+{
+#define YesNo(y) y ? 'y' : 'n'
+ printk (NAME53C8XX ": setup=disc:%c,specf:%d,ultra:%d,tags:%d,sync:%d,"
+ "burst:%d,wide:%c,diff:%d,revprob:%c,buschk:0x%x\n",
+ YesNo(driver_setup.disconnection),
+ driver_setup.special_features,
+ driver_setup.ultra_scsi,
+ driver_setup.default_tags,
+ driver_setup.default_sync,
+ driver_setup.burst_max,
+ YesNo(driver_setup.max_wide),
+ driver_setup.diff_support,
+ YesNo(driver_setup.reverse_probe),
+ driver_setup.bus_check);
+
+ printk (NAME53C8XX ": setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,"
+ "led:%c,settle:%d,irqm:0x%x,nvram:0x%x,pcifix:0x%x\n",
+ YesNo(driver_setup.master_parity),
+ YesNo(driver_setup.scsi_parity),
+ YesNo(driver_setup.force_sync_nego),
+ driver_setup.verbose,
+ driver_setup.debug,
+ YesNo(driver_setup.led_pin),
+ driver_setup.settle_delay,
+ driver_setup.irqm,
+ driver_setup.use_nvram,
+ driver_setup.pci_fix_up);
+#undef YesNo
+}
+
+/*===================================================================
+**
+** SYM53C8XX devices description table.
+**
+**===================================================================
+*/
+
+static ncr_chip ncr_chip_table[] __initdata = SCSI_NCR_CHIP_TABLE;
+
+#ifdef SCSI_NCR_PQS_PDS_SUPPORT
+/*===================================================================
+**
+** Detect all NCR PQS/PDS boards and keep track of their bus nr.
+**
+** The NCR PQS or PDS card is constructed as a DEC bridge
+** behind which sit a proprietary NCR memory controller and
+** four or two 53c875s as separate devices. In its usual mode
+** of operation, the 875s are slaved to the memory controller
+** for all transfers. We can tell if an 875 is part of a
+** PQS/PDS or not since if it is, it will be on the same bus
+** as the memory controller. To operate with the Linux
+** driver, the memory controller is disabled and the 875s
+** freed to function independently. The only wrinkle is that
+** the preset SCSI ID (which may be zero) must be read in from
+** a special configuration space register of the 875.
+**
+**===================================================================
+*/
+#define SCSI_NCR_MAX_PQS_BUS 16
+static int pqs_bus[SCSI_NCR_MAX_PQS_BUS] __initdata = { 0 };
+
+static void __init ncr_detect_pqs_pds(void)
+{
+ short index;
+ pcidev_t dev = PCIDEV_NULL;
+
+ for(index=0; index < SCSI_NCR_MAX_PQS_BUS; index++) {
+ u_char tmp;
+
+ dev = pci_find_device(0x101a, 0x0009, dev);
+ if (dev == PCIDEV_NULL) {
+ pqs_bus[index] = -1;
+ break;
+ }
+ printk(KERN_INFO NAME53C8XX ": NCR PQS/PDS memory controller detected on bus %d\n", PciBusNumber(dev));
+ pci_read_config_byte(dev, 0x44, &tmp);
+ /* bit 1: allow individual 875 configuration */
+ tmp |= 0x2;
+ pci_write_config_byte(dev, 0x44, tmp);
+ pci_read_config_byte(dev, 0x45, &tmp);
+ /* bit 2: drive individual 875 interrupts to the bus */
+ tmp |= 0x4;
+ pci_write_config_byte(dev, 0x45, tmp);
+
+ pqs_bus[index] = PciBusNumber(dev);
+ }
+}
+#endif /* SCSI_NCR_PQS_PDS_SUPPORT */
+
+/*===================================================================
+**
+** Read and check the PCI configuration for any detected NCR
+** boards and save data for attaching after all boards have
+** been detected.
+**
+**===================================================================
+*/
+static int __init
+sym53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, ncr_device *device)
+{
+ u_short vendor_id, device_id, command;
+ u_char cache_line_size, latency_timer;
+ u_char suggested_cache_line_size = 0;
+ u_char pci_fix_up = driver_setup.pci_fix_up;
+ u_char revision;
+ u_int irq;
+ u_long base, base_2, io_port;
+ int i;
+ ncr_chip *chip;
+
+ printk(KERN_INFO NAME53C8XX ": at PCI bus %d, device %d, function %d\n",
+ PciBusNumber(pdev),
+ (int) (PciDeviceFn(pdev) & 0xf8) >> 3,
+ (int) (PciDeviceFn(pdev) & 7));
+
+#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING
+ if (!pci_dma_supported(pdev, (dma_addr_t) (0xffffffffUL))) {
+ printk(KERN_WARNING NAME53C8XX
+ "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
+ return -1;
+ }
+#endif
+
+ /*
+ ** Read info from the PCI config space.
+ ** pci_read_config_xxx() functions are assumed to be used for
+ ** successfully detected PCI devices.
+ */
+ vendor_id = PciVendorId(pdev);
+ device_id = PciDeviceId(pdev);
+ irq = PciIrqLine(pdev);
+ i = 0;
+ i = pci_get_base_address(pdev, i, &io_port);
+ i = pci_get_base_address(pdev, i, &base);
+ (void) pci_get_base_address(pdev, i, &base_2);
+
+ pci_read_config_word(pdev, PCI_COMMAND, &command);
+ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line_size);
+ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_timer);
+
+#ifdef SCSI_NCR_PQS_PDS_SUPPORT
+ /*
+ ** Match the BUS number for PQS/PDS devices.
+ ** Read the SCSI ID from a special register mapped
+ ** into the configuration space of the individual
+ ** 875s. This register is set up by the PQS bios
+ */
+ for(i = 0; i < SCSI_NCR_MAX_PQS_BUS && pqs_bus[i] != -1; i++) {
+ u_char tmp;
+ if (pqs_bus[i] == PciBusNumber(pdev)) {
+ pci_read_config_byte(pdev, 0x84, &tmp);
+ device->pqs_pds = 1;
+ device->host_id = tmp;
+ break;
+ }
+ }
+#endif /* SCSI_NCR_PQS_PDS_SUPPORT */
+
+ /*
+ ** If user excludes this chip, donnot initialize it.
+ */
+ for (i = 0 ; i < SCSI_NCR_MAX_EXCLUDES ; i++) {
+ if (driver_setup.excludes[i] ==
+ (io_port & PCI_BASE_ADDRESS_IO_MASK))
+ return -1;
+ }
+ /*
+ ** Check if the chip is supported
+ */
+ chip = 0;
+ for (i = 0; i < sizeof(ncr_chip_table)/sizeof(ncr_chip_table[0]); i++) {
+ if (device_id != ncr_chip_table[i].device_id)
+ continue;
+ if (revision > ncr_chip_table[i].revision_id)
+ continue;
+ chip = &device->chip;
+ memcpy(chip, &ncr_chip_table[i], sizeof(*chip));
+ chip->revision_id = revision;
+ break;
+ }
+
+ /*
+ ** Ignore Symbios chips controlled by SISL RAID controller.
+ ** This controller sets value 0x52414944 at RAM end - 16.
+ */
+#if defined(__i386__) && !defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED)
+ if (chip && (base_2 & PCI_BASE_ADDRESS_MEM_MASK)) {
+ unsigned int ram_size, ram_val;
+ u_long ram_ptr;
+
+ if (chip->features & FE_RAM8K)
+ ram_size = 8192;
+ else
+ ram_size = 4096;
+
+ ram_ptr = remap_pci_mem(base_2 & PCI_BASE_ADDRESS_MEM_MASK,
+ ram_size);
+ if (ram_ptr) {
+ ram_val = readl_raw(ram_ptr + ram_size - 16);
+ unmap_pci_mem(ram_ptr, ram_size);
+ if (ram_val == 0x52414944) {
+ printk(NAME53C8XX": not initializing, "
+ "driven by SISL RAID controller.\n");
+ return -1;
+ }
+ }
+ }
+#endif /* i386 and PCI MEMORY accessible */
+
+ if (!chip) {
+ printk(NAME53C8XX ": not initializing, device not supported\n");
+ return -1;
+ }
+
+#ifdef __powerpc__
+ /*
+ ** Fix-up for power/pc.
+ ** Should not be performed by the driver.
+ */
+ if ((command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY))
+ != (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
+ printk(NAME53C8XX ": setting%s%s...\n",
+ (command & PCI_COMMAND_IO) ? "" : " PCI_COMMAND_IO",
+ (command & PCI_COMMAND_MEMORY) ? "" : " PCI_COMMAND_MEMORY");
+ command |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+ pci_write_config_word(pdev, PCI_COMMAND, command);
+ }
+
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,2,0)
+ if ( is_prep ) {
+ if (io_port >= 0x10000000) {
+ printk(NAME53C8XX ": reallocating io_port (Wacky IBM)");
+ io_port = (io_port & 0x00FFFFFF) | 0x01000000;
+ pci_write_config_dword(pdev,
+ PCI_BASE_ADDRESS_0, io_port);
+ }
+ if (base >= 0x10000000) {
+ printk(NAME53C8XX ": reallocating base (Wacky IBM)");
+ base = (base & 0x00FFFFFF) | 0x01000000;
+ pci_write_config_dword(pdev,
+ PCI_BASE_ADDRESS_1, base);
+ }
+ if (base_2 >= 0x10000000) {
+ printk(NAME53C8XX ": reallocating base2 (Wacky IBM)");
+ base_2 = (base_2 & 0x00FFFFFF) | 0x01000000;
+ pci_write_config_dword(pdev,
+ PCI_BASE_ADDRESS_2, base_2);
+ }
+ }
+#endif
+#endif /* __powerpc__ */
+
+#ifdef __sparc__
+ /*
+ ** Fix-ups for sparc.
+ */
+ if (!cache_line_size)
+ suggested_cache_line_size = 16;
+
+ driver_setup.pci_fix_up |= 0x7;
+#endif /* __sparc__ */
+
+#if defined(__i386__) && !defined(MODULE)
+ if (!cache_line_size) {
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,75)
+ extern char x86;
+ switch(x86) {
+#else
+ switch(boot_cpu_data.x86) {
+#endif
+ case 4: suggested_cache_line_size = 4; break;
+ case 6:
+ case 5: suggested_cache_line_size = 8; break;
+ }
+ }
+#endif /* __i386__ */
+
+ /*
+ ** Check availability of IO space, memory space.
+ ** Enable master capability if not yet.
+ **
+ ** We shouldn't have to care about the IO region when
+ ** we are using MMIO. But calling check_region() from
+ ** both the ncr53c8xx and the sym53c8xx drivers prevents
+ ** from attaching devices from the both drivers.
+ ** If you have a better idea, let me know.
+ */
+/* #ifdef NCR_IOMAPPED */
+#if 1
+ if (!(command & PCI_COMMAND_IO)) {
+ printk(NAME53C8XX ": I/O base address (0x%lx) disabled.\n",
+ (long) io_port);
+ io_port = 0;
+ }
+#endif
+ if (!(command & PCI_COMMAND_MEMORY)) {
+ printk(NAME53C8XX ": PCI_COMMAND_MEMORY not set.\n");
+ base = 0;
+ base_2 = 0;
+ }
+ io_port &= PCI_BASE_ADDRESS_IO_MASK;
+ base &= PCI_BASE_ADDRESS_MEM_MASK;
+ base_2 &= PCI_BASE_ADDRESS_MEM_MASK;
+
+/* #ifdef NCR_IOMAPPED */
+#if 1
+ if (io_port && check_region (io_port, 128)) {
+ printk(NAME53C8XX ": IO region 0x%lx[0..127] is in use\n",
+ (long) io_port);
+ io_port = 0;
+ }
+ if (!io_port)
+ return -1;
+#endif
+#ifndef NCR_IOMAPPED
+ if (!base) {
+ printk(NAME53C8XX ": MMIO base address disabled.\n");
+ return -1;
+ }
+#endif
+
+/* The ncr53c8xx driver never did set the PCI parity bit. */
+/* Since setting this bit is known to trigger spurious MDPE */
+/* errors on some 895 controllers when noise on power lines is */
+/* too high, I donnot want to change previous ncr53c8xx driver */
+/* behaviour on that point (the sym53c8xx driver set this bit). */
+#if 0
+ /*
+ ** Set MASTER capable and PARITY bit, if not yet.
+ */
+ if ((command & (PCI_COMMAND_MASTER | PCI_COMMAND_PARITY))
+ != (PCI_COMMAND_MASTER | PCI_COMMAND_PARITY)) {
+ printk(NAME53C8XX ": setting%s%s...(fix-up)\n",
+ (command & PCI_COMMAND_MASTER) ? "" : " PCI_COMMAND_MASTER",
+ (command & PCI_COMMAND_PARITY) ? "" : " PCI_COMMAND_PARITY");
+ command |= (PCI_COMMAND_MASTER | PCI_COMMAND_PARITY);
+ pci_write_config_word(pdev, PCI_COMMAND, command);
+ }
+#else
+ /*
+ ** Set MASTER capable if not yet.
+ */
+ if ((command & PCI_COMMAND_MASTER) != PCI_COMMAND_MASTER) {
+ printk(NAME53C8XX ": setting PCI_COMMAND_MASTER...(fix-up)\n");
+ command |= PCI_COMMAND_MASTER;
+ pci_write_config_word(pdev, PCI_COMMAND, command);
+ }
+#endif
+
+ /*
+ ** Fix some features according to driver setup.
+ */
+ if (!(driver_setup.special_features & 1))
+ chip->features &= ~FE_SPECIAL_SET;
+ else {
+ if (driver_setup.special_features & 2)
+ chip->features &= ~FE_WRIE;
+ if (driver_setup.special_features & 4)
+ chip->features &= ~FE_NOPM;
+ }
+ if (driver_setup.ultra_scsi < 2 && (chip->features & FE_ULTRA2)) {
+ chip->features |= FE_ULTRA;
+ chip->features &= ~FE_ULTRA2;
+ }
+ if (driver_setup.ultra_scsi < 1)
+ chip->features &= ~FE_ULTRA;
+ if (!driver_setup.max_wide)
+ chip->features &= ~FE_WIDE;
+
+ /*
+ ** Some features are required to be enabled in order to
+ ** work around some chip problems. :) ;)
+ ** (ITEM 12 of a DEL about the 896 I haven't yet).
+ ** We must ensure the chip will use WRITE AND INVALIDATE.
+ ** The revision number limit is for now arbitrary.
+ */
+ if (device_id == PCI_DEVICE_ID_NCR_53C896 && revision <= 0x10) {
+ chip->features |= (FE_WRIE | FE_CLSE);
+ pci_fix_up |= 3; /* Force appropriate PCI fix-up */
+ }
+
+#ifdef SCSI_NCR_PCI_FIX_UP_SUPPORT
+ /*
+ ** Try to fix up PCI config according to wished features.
+ */
+ if ((pci_fix_up & 1) && (chip->features & FE_CLSE) &&
+ !cache_line_size && suggested_cache_line_size) {
+ cache_line_size = suggested_cache_line_size;
+ pci_write_config_byte(pdev,
+ PCI_CACHE_LINE_SIZE, cache_line_size);
+ printk(NAME53C8XX ": PCI_CACHE_LINE_SIZE set to %d (fix-up).\n",
+ cache_line_size);
+ }
+
+ if ((pci_fix_up & 2) && cache_line_size &&
+ (chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
+ printk(NAME53C8XX": setting PCI_COMMAND_INVALIDATE (fix-up)\n");
+ command |= PCI_COMMAND_INVALIDATE;
+ pci_write_config_word(pdev, PCI_COMMAND, command);
+ }
+
+ /*
+ ** Tune PCI LATENCY TIMER according to burst max length transfer.
+ ** (latency timer >= burst length + 6, we add 10 to be quite sure)
+ */
+
+ if (chip->burst_max && (latency_timer == 0 || (pci_fix_up & 4))) {
+ u_char lt = (1 << chip->burst_max) + 6 + 10;
+ if (latency_timer < lt) {
+ printk(NAME53C8XX
+ ": changing PCI_LATENCY_TIMER from %d to %d.\n",
+ (int) latency_timer, (int) lt);
+ latency_timer = lt;
+ pci_write_config_byte(pdev,
+ PCI_LATENCY_TIMER, latency_timer);
+ }
+ }
+
+#endif /* SCSI_NCR_PCI_FIX_UP_SUPPORT */
+
+ /*
+ ** Initialise ncr_device structure with items required by ncr_attach.
+ */
+ device->pdev = pdev;
+ device->slot.bus = PciBusNumber(pdev);
+ device->slot.device_fn = PciDeviceFn(pdev);
+ device->slot.base = base;
+ device->slot.base_2 = base_2;
+ device->slot.io_port = io_port;
+ device->slot.irq = irq;
+ device->attach_done = 0;
+
+ return 0;
+}
+
+/*===================================================================
+**
+** Detect all 53c8xx hosts and then attach them.
+**
+** If we are using NVRAM, once all hosts are detected, we need to
+** check any NVRAM for boot order in case detect and boot order
+** differ and attach them using the order in the NVRAM.
+**
+** If no NVRAM is found or data appears invalid attach boards in
+** the the order they are detected.
+**
+**===================================================================
+*/
+static int __init
+sym53c8xx__detect(Scsi_Host_Template *tpnt, u_short ncr_chip_ids[], int chips)
+{
+ pcidev_t pcidev;
+ int i, j, hosts, count;
+ int attach_count = 0;
+ ncr_device *devtbl, *devp;
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+ ncr_nvram nvram0, nvram, *nvp;
+#endif
+
+ /*
+ ** PCI is required.
+ */
+ if (!pci_present())
+ return 0;
+
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
+ ncr_debug = driver_setup.debug;
+#endif
+ if (initverbose >= 2)
+ ncr_print_driver_setup();
+
+ /*
+ ** Allocate the device table since we donnot want to
+ ** overflow the kernel stack.
+ ** 1 x 4K PAGE is enough for more than 40 devices for i386.
+ */
+ devtbl = m_calloc(PAGE_SIZE, "devtbl");
+ if (!devtbl)
+ return 0;
+
+ /*
+ ** Detect all NCR PQS/PDS memory controllers.
+ */
+#ifdef SCSI_NCR_PQS_PDS_SUPPORT
+ ncr_detect_pqs_pds();
+#endif
+
+ /*
+ ** Detect all 53c8xx hosts.
+ ** Save the first Symbios NVRAM content if any
+ ** for the boot order.
+ */
+ hosts = PAGE_SIZE / sizeof(*devtbl);
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+ nvp = (driver_setup.use_nvram & 0x1) ? &nvram0 : 0;
+#endif
+ j = 0;
+ count = 0;
+ pcidev = PCIDEV_NULL;
+ while (1) {
+ char *msg = "";
+ if (count >= hosts)
+ break;
+ if (j >= chips)
+ break;
+ i = driver_setup.reverse_probe ? chips - 1 - j : j;
+ pcidev = pci_find_device(PCI_VENDOR_ID_NCR, ncr_chip_ids[i],
+ pcidev);
+ if (pcidev == PCIDEV_NULL) {
+ ++j;
+ continue;
+ }
+ /* Some HW as the HP LH4 may report twice PCI devices */
+ for (i = 0; i < count ; i++) {
+ if (devtbl[i].slot.bus == PciBusNumber(pcidev) &&
+ devtbl[i].slot.device_fn == PciDeviceFn(pcidev))
+ break;
+ }
+ if (i != count) /* Ignore this device if we already have it */
+ continue;
+ devp = &devtbl[count];
+ devp->host_id = driver_setup.host_id;
+ devp->attach_done = 0;
+ if (sym53c8xx_pci_init(tpnt, pcidev, devp)) {
+ continue;
+ }
+ ++count;
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+ if (nvp) {
+ ncr_get_nvram(devp, nvp);
+ switch(nvp->type) {
+ case SCSI_NCR_SYMBIOS_NVRAM:
+ /*
+ * Switch to the other nvram buffer, so that
+ * nvram0 will contain the first Symbios
+ * format NVRAM content with boot order.
+ */
+ nvp = &nvram;
+ msg = "with Symbios NVRAM";
+ break;
+ case SCSI_NCR_TEKRAM_NVRAM:
+ msg = "with Tekram NVRAM";
+ break;
+ }
+ }
+#endif
+#ifdef SCSI_NCR_PQS_PDS_SUPPORT
+ if (devp->pqs_pds)
+ msg = "(NCR PQS/PDS)";
+#endif
+ printk(KERN_INFO NAME53C8XX ": 53c%s detected %s\n",
+ devp->chip.name, msg);
+ }
+
+ /*
+ ** If we have found a SYMBIOS NVRAM, use first the NVRAM boot
+ ** sequence as device boot order.
+ ** check devices in the boot record against devices detected.
+ ** attach devices if we find a match. boot table records that
+ ** do not match any detected devices will be ignored.
+ ** devices that do not match any boot table will not be attached
+ ** here but will attempt to be attached during the device table
+ ** rescan.
+ */
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+ if (!nvp || nvram0.type != SCSI_NCR_SYMBIOS_NVRAM)
+ goto next;
+ for (i = 0; i < 4; i++) {
+ Symbios_host *h = &nvram0.data.Symbios.host[i];
+ for (j = 0 ; j < count ; j++) {
+ devp = &devtbl[j];
+ if (h->device_fn != devp->slot.device_fn ||
+ h->bus_nr != devp->slot.bus ||
+ h->device_id != devp->chip.device_id)
+ continue;
+ if (devp->attach_done)
+ continue;
+ if (h->flags & SYMBIOS_INIT_SCAN_AT_BOOT) {
+ ncr_get_nvram(devp, nvp);
+ if (!ncr_attach (tpnt, attach_count, devp))
+ attach_count++;
+ }
+ else if (!(driver_setup.use_nvram & 0x80))
+ printk(KERN_INFO NAME53C8XX
+ ": 53c%s state OFF thus not attached\n",
+ devp->chip.name);
+ else
+ continue;
+
+ devp->attach_done = 1;
+ break;
+ }
+ }
+next:
+#endif
+
+ /*
+ ** Rescan device list to make sure all boards attached.
+ ** Devices without boot records will not be attached yet
+ ** so try to attach them here.
+ */
+ for (i= 0; i < count; i++) {
+ devp = &devtbl[i];
+ if (!devp->attach_done) {
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+ ncr_get_nvram(devp, nvp);
+#endif
+ if (!ncr_attach (tpnt, attach_count, devp))
+ attach_count++;
+ }
+ }
+
+ m_free(devtbl, PAGE_SIZE, "devtbl");
+
+ return attach_count;
+}