diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-03-19 01:28:40 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-03-19 01:28:40 +0000 |
commit | 8abb719409c9060a7c0676f76e9182c1e0b8ca46 (patch) | |
tree | b88cc5a6cd513a04a512b7e6215c873c90a1c5dd /drivers/scsi | |
parent | f01bd7aeafd95a08aafc9e3636bb26974df69d82 (diff) |
Merge with 2.3.99-pre1.
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/ChangeLog.ncr53c8xx | 17 | ||||
-rw-r--r-- | drivers/scsi/ChangeLog.sym53c8xx | 9 | ||||
-rw-r--r-- | drivers/scsi/Config.in | 4 | ||||
-rw-r--r-- | drivers/scsi/README.st | 8 | ||||
-rw-r--r-- | drivers/scsi/atp870u.c | 5 | ||||
-rw-r--r-- | drivers/scsi/constants.c | 563 | ||||
-rw-r--r-- | drivers/scsi/eata_dma_proc.c | 18 | ||||
-rw-r--r-- | drivers/scsi/hosts.h | 28 | ||||
-rw-r--r-- | drivers/scsi/ncr53c8xx.c | 2600 | ||||
-rw-r--r-- | drivers/scsi/scsi.c | 18 | ||||
-rw-r--r-- | drivers/scsi/scsi.h | 11 | ||||
-rw-r--r-- | drivers/scsi/scsi_debug.c | 12 | ||||
-rw-r--r-- | drivers/scsi/scsi_ioctl.c | 64 | ||||
-rw-r--r-- | drivers/scsi/scsi_lib.c | 9 | ||||
-rw-r--r-- | drivers/scsi/scsi_merge.c | 8 | ||||
-rw-r--r-- | drivers/scsi/scsi_scan.c | 80 | ||||
-rw-r--r-- | drivers/scsi/scsi_syms.c | 1 | ||||
-rw-r--r-- | drivers/scsi/sd.c | 74 | ||||
-rw-r--r-- | drivers/scsi/sr.c | 4 | ||||
-rw-r--r-- | drivers/scsi/st.c | 738 | ||||
-rw-r--r-- | drivers/scsi/st.h | 11 | ||||
-rw-r--r-- | drivers/scsi/st_options.h | 9 | ||||
-rw-r--r-- | drivers/scsi/sym53c8xx.c | 175 | ||||
-rw-r--r-- | drivers/scsi/sym53c8xx_comm.h | 2863 |
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; +} |