From 379a6be1eedb84ae0d476afbc4b4070383681178 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:41:13 -0500 Subject: [PATCH] Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some last-minute stuff that needed fixing (ie the dirty page lists etc), and the best I can do is make a prerelease. There's a 2.4.0-prerelease out there, and this is basically it. I want people to test it for a while, and I want to give other architectures the chance to catch up with some of the changes, but read my lips: no more recounts. There is no "prerelease1", to become "prerelease2" and so on. One thing other architectures will want to catch up with is the changes to handle 2GHz+ machines, which due to overflow issues caused "loops_per_sec" to become "loops_per_jiffy". And some architectures have not had much chance to synchronize with me due to other fires to put out. Give it your worst. After you recover from being hung-over, of course. --- CREDITS | 6 + Documentation/Configure.help | 26 +- Documentation/DocBook/Makefile | 1 + Documentation/DocBook/kernel-api.tmpl | 4 + Documentation/sound/Soundblaster | 3 + MAINTAINERS | 9 +- Makefile | 2 +- arch/i386/defconfig | 5 +- arch/i386/kernel/cpuid.c | 1 + arch/i386/kernel/msr.c | 1 + arch/i386/kernel/setup.c | 10 +- arch/i386/kernel/smpboot.c | 6 +- arch/i386/lib/delay.c | 7 +- drivers/block/acsi.c | 6 +- drivers/block/ll_rw_blk.c | 17 +- drivers/cdrom/cdrom.c | 4 +- drivers/char/dtlk.c | 22 +- drivers/char/epca.c | 11 +- drivers/char/tty_io.c | 12 +- drivers/ide/ide-floppy.c | 2 +- drivers/ide/ide-tape.c | 4 +- drivers/mtd/cfi_probe.c | 4 +- drivers/net/8139too.c | 25 +- drivers/net/appletalk/ltpc.c | 5 +- drivers/net/gmac.c | 29 +- drivers/net/mac89x0.c | 31 +- drivers/net/ncr885e.c | 66 +- drivers/net/ncr885e.h | 2 +- drivers/net/pcmcia/ray_cs.h | 4 +- drivers/net/rcpci45.c | 160 +- drivers/net/wan/cosa.c | 4 +- drivers/scsi/Config.in | 2 + drivers/scsi/README.ibmmca | 91 +- drivers/scsi/README.tmscsim | 201 +- drivers/scsi/dc390.h | 56 +- drivers/scsi/eata_dma.c | 3 +- drivers/scsi/ibmmca.c | 5873 +++++++++++++++------------------ drivers/scsi/ibmmca.h | 65 +- drivers/scsi/osst.c | 103 +- drivers/scsi/scsiiom.c | 3398 ++++++++++--------- drivers/scsi/tmscsim.c | 1360 +++++--- drivers/scsi/tmscsim.h | 210 +- drivers/sound/sb_card.c | 33 +- drivers/sound/wavfront.c | 8 +- drivers/sound/ymf_sb.c | 11 +- drivers/usb/usb.c | 125 +- fs/exec.c | 94 +- fs/fat/inode.c | 6 + fs/partitions/check.c | 6 +- fs/vfat/namei.c | 7 +- include/asm-i386/delay.h | 4 +- include/asm-i386/processor.h | 2 +- include/linux/delay.h | 4 +- include/linux/dtlk.h | 2 +- include/linux/telephony.h | 4 +- include/linux/tty.h | 1 + include/linux/watchdog.h | 11 +- include/linux/wireless.h | 55 +- init/main.c | 46 +- kernel/kmod.c | 34 +- kernel/ksyms.c | 6 +- kernel/printk.c | 4 +- net/x25/af_x25.c | 10 +- scripts/Configure | 13 +- 64 files changed, 6231 insertions(+), 6106 deletions(-) rewrite drivers/scsi/ibmmca.c (65%) rewrite drivers/scsi/scsiiom.c (94%) diff --git a/CREDITS b/CREDITS index 580bc44ba..e9ffeef8c 100644 --- a/CREDITS +++ b/CREDITS @@ -502,6 +502,12 @@ S: Las Cuevas 2385 - Bo Guemes S: Las Heras, Mendoza CP 5539 S: Argentina +N: Steven P. Cole +E: scole@lanl.gov +E: elenstev@mesatop.com +D: Various build fixes and kernel documentation. +S: Los Alamos, New Mexico + N: Hamish Coleman E: hamish@zot.apana.org.au D: SEEQ8005 network driver diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 078b30045..60a6fbef5 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -971,7 +971,7 @@ CONFIG_BLK_DEV_TRM290 VIA82CXXX chipset support CONFIG_BLK_DEV_VIA82CXXX - This allows you to to configure your chipset for a better use while + This allows you to configure your chipset for a better use while running (U)DMA: it will allow you to enable efficiently the second channel dma usage, as it may not be set by BIOS. It allows you to pass a kernel command line at boot time in order to set fifo @@ -5248,6 +5248,30 @@ CONFIG_CHR_DEV_ST module, say M here and read Documentation/modules.txt and Documentation/scsi.txt . +OnStream SC-x0 SCSI tape support +CONFIG_CHR_DEV_OSST + The OnStream SC-x0 SCSI tape drives can not be driven by the + standard st driver, but instead need this special osst driver and + use the /dev/osstX char device nodes (major 206). + Via usb-storage and ide-scsi, you may be able to drive the USB-x0 + and DI-x0 drives as well. Note that there is also a second generation + of OnStream tape drives (ADR-x0) that supports the standard SCSI-2 + commands for tapes (QIC-157) and can be driven by the standard + driver st. + For more information, you may have a look at the SCSI-HOWTO + ftp://metalab.unc.edu/pub/Linux/docs/HOWTO and + drivers/scsi/README.osst in the kernel source. + More info on the OnStream driver may be found on + http://linux1.onstream.nl/test/ + Please also have a look at the standard st docu, as most of it + applies to osst as well. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called osst.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt and + Documentation/scsi.txt . + SCSI CDROM support CONFIG_BLK_DEV_SR If you want to use a SCSI CDROM under Linux, say Y and read the diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 81e9a401a..aebb0303a 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -76,6 +76,7 @@ APISOURCES := $(TOPDIR)/drivers/media/video/videodev.c \ $(TOPDIR)/drivers/sound/sound_firmware.c \ $(TOPDIR)/drivers/net/wan/syncppp.c \ $(TOPDIR)/drivers/net/wan/z85230.c \ + $(TOPDIR)/drivers/usb/usb.c \ $(TOPDIR)/fs/locks.c \ $(TOPDIR)/fs/devfs/base.c \ $(TOPDIR)/kernel/pm.c \ diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index 0c445af2f..a593487ef 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -150,6 +150,10 @@ !Idrivers/sound/sound_firmware.c + + USB Devices +!Edrivers/usb/usb.c + 16x50 UART Driver diff --git a/Documentation/sound/Soundblaster b/Documentation/sound/Soundblaster index 3276245ad..b288d464b 100644 --- a/Documentation/sound/Soundblaster +++ b/Documentation/sound/Soundblaster @@ -24,6 +24,9 @@ isapnp=0 Set this to disable ISAPnP detection (use io=0xXXX etc. above) multiple=0 Set to disable detection of multiple Soundblaster cards. Consider it a bug if this option is needed, and send in a report. +pnplegacy=1 Set this to be able to use a PnP card(s) along with a single + non-PnP (legacy) card. Above options for io, irq, etc. are + needed, and will apply only to the legacy card. reverse=1 Reverses the order of the search in the PnP table. uart401=1 Set to enable detection of mpu devices on some clones. isapnpjump=n Jumps to slot n in the driver's PnP table. Use the source, diff --git a/MAINTAINERS b/MAINTAINERS index 8425f6d46..492d15a40 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -316,7 +316,7 @@ S: Maintained DC390/AM53C974 SCSI driver P: Kurt Garloff -M: kurt@garloff.de +M: garloff@suse.de W: http://www.garloff.de/kurt/linux/dc390/ S: Maintained @@ -909,6 +909,13 @@ L: linux-tr@emissary.aus-etc.com W: http://www.linuxtr.net S: Maintained +ONSTREAM SCSI TAPE DRIVER +P: Willem Riede +M: osst@riede.org +L: osst@linux1.onstream.nl +L: linux-scsi@vger.rutgers.edu +S: Maintained + OPL3-SA2, SA3, and SAx DRIVER P: Scott Murray M: scott@spiteful.org diff --git a/Makefile b/Makefile index 5a67ef713..718448428 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 0 -EXTRAVERSION = -test13-pre7 +EXTRAVERSION = -prerelease KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff --git a/arch/i386/defconfig b/arch/i386/defconfig index bdcf8cf6b..de38a46ef 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -92,7 +92,6 @@ CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=y CONFIG_PM=y -CONFIG_ACPI=y # CONFIG_APM is not set # @@ -256,6 +255,7 @@ CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 # CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set # CONFIG_BLK_DEV_SR is not set # CONFIG_CHR_DEV_SG is not set @@ -592,8 +592,6 @@ CONFIG_LOCKD=y # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -602,6 +600,7 @@ CONFIG_LOCKD=y # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # diff --git a/arch/i386/kernel/cpuid.c b/arch/i386/kernel/cpuid.c index 73b41b215..fe6528460 100644 --- a/arch/i386/kernel/cpuid.c +++ b/arch/i386/kernel/cpuid.c @@ -153,6 +153,7 @@ int __init cpuid_init(void) void __exit cpuid_exit(void) { + unregister_chrdev(CPUID_MAJOR, "cpu/cpuid"); } module_init(cpuid_init); diff --git a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c index badb6ed15..fd8cf7088 100644 --- a/arch/i386/kernel/msr.c +++ b/arch/i386/kernel/msr.c @@ -261,6 +261,7 @@ int __init msr_init(void) void __exit msr_exit(void) { + unregister_chrdev(MSR_MAJOR, "cpu/msr"); } module_init(msr_init); diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 74af012b4..09aa4a08c 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -1149,7 +1149,7 @@ static void __init check_cx686_slop(struct cpuinfo_x86 *c) if (ccr5 & 2) { /* possible wrong calibration done */ printk(KERN_INFO "Recalibrating delay loop with SLOP bit reset\n"); calibrate_delay(); - c->loops_per_sec = loops_per_sec; + c->loops_per_jiffy = loops_per_jiffy; } } } @@ -1553,7 +1553,7 @@ static void __init init_intel(struct cpuinfo_x86 *c) /* L1 D cache */ l1d += 16; break; - default: + default:; /* TLB, or unknown */ } break; @@ -1884,7 +1884,7 @@ void __init identify_cpu(struct cpuinfo_x86 *c) int junk, i; u32 xlvl, tfms; - c->loops_per_sec = loops_per_sec; + c->loops_per_jiffy = loops_per_jiffy; c->x86_cache_size = -1; c->x86_vendor = X86_VENDOR_UNKNOWN; c->cpuid_level = -1; /* CPUID not detected */ @@ -2188,8 +2188,8 @@ int get_cpuinfo(char * buffer) p += sprintf(p, " %s", x86_cap_flags[i]); p += sprintf(p, "\nbogomips\t: %lu.%02lu\n\n", - (c->loops_per_sec+2500)/500000, - ((c->loops_per_sec+2500)/5000) % 100); + c->loops_per_jiffy/(500000/HZ), + (c->loops_per_jiffy/(5000/HZ)) % 100); } return p - buffer; } diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 540ef9a98..aab31e839 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -984,11 +984,11 @@ void __init smp_boot_cpus(void) unsigned long bogosum = 0; for (cpu = 0; cpu < NR_CPUS; cpu++) if (cpu_online_map & (1<= 0 ) if (!(mfp.par_dt_reg & 0x20)) return( 1 ); } @@ -439,7 +439,7 @@ int acsi_wait_for_noIRQ( unsigned timeout ) if (mfp.par_dt_reg & 0x20) return( 1 ); } else { - long tries = loops_per_sec * timeout / HZ / 8; + long tries = loops_per_jiffy * timeout / 8; while( tries-- >= 0 ) if (mfp.par_dt_reg & 0x20) return( 1 ); } diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 520751f2d..ef71dddc7 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -964,6 +964,15 @@ void submit_bh(int rw, struct buffer_head * bh) bh->b_rsector = bh->b_blocknr * (bh->b_size>>9); generic_make_request(rw, bh); + + switch (rw) { + case WRITE: + kstat.pgpgout++; + break; + default: + kstat.pgpgin++; + break; + } } /* @@ -1008,7 +1017,6 @@ static void end_buffer_io_sync(struct buffer_head *bh, int uptodate) void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]) { - struct buffer_head *bh; unsigned int major; int correct_size; int i; @@ -1025,6 +1033,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]) /* Verify requested block sizes. */ for (i = 0; i < nr; i++) { + struct buffer_head *bh; bh = bhs[i]; if (bh->b_size != correct_size) { printk(KERN_NOTICE "ll_rw_block: device %s: " @@ -1042,6 +1051,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]) } for (i = 0; i < nr; i++) { + struct buffer_head *bh; bh = bhs[i]; /* Only one thread can actually submit the I/O. */ @@ -1057,7 +1067,6 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]) /* Hmmph! Nothing to write */ goto end_io; __mark_buffer_clean(bh); - kstat.pgpgout++; break; case READA: @@ -1065,7 +1074,6 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]) if (buffer_uptodate(bh)) /* Hmmph! Already have it */ goto end_io; - kstat.pgpgin++; break; default: BUG(); @@ -1079,8 +1087,9 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]) return; sorry: + /* Make sure we don't get infinite dirty retries.. */ for (i = 0; i < nr; i++) - buffer_IO_error(bhs[i]); + mark_buffer_clean(bhs[i]); } #ifdef CONFIG_STRAM_SWAP diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 7cbdf2291..1e555da55 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2571,13 +2571,13 @@ ctl_table cdrom_cdrom_table[] = { {0} }; -#ifdef CONFIG_PROC_FS /* Make sure that /proc/sys/dev is there */ ctl_table cdrom_root_table[] = { +#ifdef CONFIG_PROC_FS {CTL_DEV, "dev", NULL, 0, 0555, cdrom_cdrom_table}, +#endif /* CONFIG_PROC_FS */ {0} }; -#endif /* CONFIG_PROC_FS */ static struct ctl_table_header *cdrom_sysctl_header; static void cdrom_sysctl_register(void) diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c index 943ceb7eb..76c2ab201 100644 --- a/drivers/char/dtlk.c +++ b/drivers/char/dtlk.c @@ -60,7 +60,7 @@ #include /* for verify_area */ #include /* for -EBUSY */ #include /* for check_region, request_region */ -#include /* for loops_per_sec */ +#include /* for loops_per_jiffy */ #include /* for put_user_byte */ #include /* for inb_p, outb_p, inb, outb, etc. */ #include /* for get_user, etc. */ @@ -144,7 +144,7 @@ static ssize_t dtlk_read(struct file *file, char *buf, if (minor != DTLK_MINOR || !dtlk_has_indexing) return -EINVAL; - for (retries = 0; retries < loops_per_sec / 10; retries++) { + for (retries = 0; retries < loops_per_jiffy; retries++) { while (i < count && dtlk_readable()) { ch = dtlk_read_lpc(); /* printk("dtlk_read() reads 0x%02x\n", ch); */ @@ -156,9 +156,9 @@ static ssize_t dtlk_read(struct file *file, char *buf, return i; if (file->f_flags & O_NONBLOCK) break; - dtlk_delay(10); + dtlk_delay(100); } - if (retries == loops_per_sec) + if (retries == loops_per_jiffy) printk(KERN_ERR "dtlk_read times out\n"); TRACE_RET; return -EAGAIN; @@ -212,7 +212,7 @@ static ssize_t dtlk_write(struct file *file, const char *buf, up to 250 usec for the RDY bit to go nonzero. */ for (retries = 0; - retries < loops_per_sec / 4000; + retries < loops_per_jiffy / (4000/HZ); retries++) if (inb_p(dtlk_port_tts) & TTS_WRITABLE) @@ -463,7 +463,7 @@ static int __init dtlk_dev_probe(void) for (i = 0; i < 10; i++) \ { \ buffer[b++] = inb_p(dtlk_port_lpc); \ - __delay(loops_per_sec/1000000); \ + __delay(loops_per_jiffy/(1000000/HZ)); \ } char buffer[1000]; int b = 0, i, j; @@ -474,7 +474,7 @@ for (i = 0; i < 10; i++) \ LOOK dtlk_write_bytes("\0012I\r", 4); buffer[b++] = 0; - __delay(50 * loops_per_sec / 1000); + __delay(50 * loops_per_jiffy / (1000/HZ)); outb_p(0xff, dtlk_port_lpc); buffer[b++] = 0; LOOK @@ -493,12 +493,12 @@ for (i = 0; i < 10; i++) \ for (i = 0; i < 10; i++) \ { \ buffer[b++] = inb_p(dtlk_port_tts); \ - __delay(loops_per_sec/1000000); /* 1 us */ \ + __delay(loops_per_jiffy/(1000000/HZ)); /* 1 us */ \ } char buffer[1000]; int b = 0, i, j; - __delay(loops_per_sec / 100); /* 10 ms */ + mdelay(10); /* 10 ms */ LOOK outb_p(0x03, dtlk_port_tts); buffer[b++] = 0; @@ -632,7 +632,7 @@ static char dtlk_read_lpc(void) /* acknowledging a read takes 3-4 usec. Here, we wait up to 20 usec for the acknowledgement */ - retries = (loops_per_sec * 20) / 1000000; + retries = (loops_per_jiffy * 20) / (1000000/HZ); while (inb_p(dtlk_port_lpc) != 0x7f && --retries > 0); if (retries == 0) printk(KERN_ERR "dtlk_read_lpc() timeout\n"); @@ -674,7 +674,7 @@ static char dtlk_write_tts(char ch) /* the RDY bit goes zero 2-3 usec after writing, and goes 1 again 180-190 usec later. Here, we wait up to 10 usec for the RDY bit to go zero. */ - for (retries = 0; retries < loops_per_sec / 100000; retries++) + for (retries = 0; retries < loops_per_jiffy / (100000/HZ); retries++) if ((inb_p(dtlk_port_tts) & TTS_WRITABLE) == 0) break; diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 7a1d5471d..d6dbd82a5 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -1636,7 +1636,7 @@ int __init pc_init(void) memory. ------------------------------------------------------------------*/ - ulong flags, save_loops_per_sec; + ulong flags; int crd; struct board_info *bd; unsigned char board_id = 0; @@ -1777,13 +1777,6 @@ int __init pc_init(void) pc_info.subtype = SERIAL_TYPE_INFO; - /* --------------------------------------------------------------------- - loops_per_sec hasn't been set at this point :-(, so fake it out... - I set it, so that I can use the __delay() function. - ------------------------------------------------------------------------ */ - save_loops_per_sec = loops_per_sec; - loops_per_sec = 13L * 500000L; - save_flags(flags); cli(); @@ -1915,8 +1908,6 @@ int __init pc_init(void) if (tty_register_driver(&pc_info)) panic("Couldn't register Digi PC/ info "); - loops_per_sec = save_loops_per_sec; /* reset it to what it should be */ - /* ------------------------------------------------------------------- Start up the poller to check for events on all enabled boards ---------------------------------------------------------------------- */ diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 92569a777..dff7458ae 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -699,9 +699,8 @@ static inline ssize_t do_tty_write( size_t count) { ssize_t ret = 0, written = 0; - struct inode *inode = file->f_dentry->d_inode; - if (down_interruptible(&inode->i_sem)) { + if (down_interruptible(&tty->atomic_write)) { return -ERESTARTSYS; } if ( test_bit(TTY_NO_WRITE_SPLIT, &tty->flags) ) { @@ -734,7 +733,7 @@ static inline ssize_t do_tty_write( file->f_dentry->d_inode->i_mtime = CURRENT_TIME; ret = written; } - up(&inode->i_sem); + up(&tty->atomic_write); return ret; } @@ -1972,6 +1971,7 @@ static void initialize_tty_struct(struct tty_struct *tty) tty->tq_hangup.routine = do_tty_hangup; tty->tq_hangup.data = tty; sema_init(&tty->atomic_read, 1); + sema_init(&tty->atomic_write, 1); spin_lock_init(&tty->read_lock); INIT_LIST_HEAD(&tty->tty_files); } @@ -2319,15 +2319,9 @@ void __init tty_init(void) #ifdef CONFIG_DIGIEPCA pc_init(); #endif -#ifdef CONFIG_RISCOM8 - riscom8_init(); -#endif #ifdef CONFIG_SPECIALIX specialix_init(); #endif -#ifdef CONFIG_SX - sx_init(); -#endif #ifdef CONFIG_RIO rio_init(); #endif diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 1130bd3d5..b6258aad8 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -104,7 +104,7 @@ typedef struct idefloppy_packet_command_s { byte *current_position; /* Pointer into the above buffer */ void (*callback) (ide_drive_t *); /* Called when this packet command is completed */ byte pc_buffer[IDEFLOPPY_PC_BUFFER_SIZE]; /* Temporary buffer */ - unsigned int flags; /* Status/Action bit flags */ + unsigned long flags; /* Status/Action bit flags: long for set_bit */ } idefloppy_pc_t; /* diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 079353425..0e7a23994 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -686,7 +686,7 @@ typedef struct idetape_packet_command_s { byte *current_position; /* Pointer into the above buffer */ ide_startstop_t (*callback) (ide_drive_t *); /* Called when this packet command is completed */ byte pc_buffer[IDETAPE_PC_BUFFER_SIZE]; /* Temporary buffer */ - unsigned int flags; /* Status/Action bit flags */ + unsigned long flags; /* Status/Action bit flags: long for set_bit */ } idetape_pc_t; /* @@ -908,7 +908,7 @@ typedef struct { int pages_per_stage; int excess_bh_size; /* Wasted space in each stage */ - unsigned int flags; /* Status/Action flags */ + unsigned long flags; /* Status/Action flags: long for set_bit */ spinlock_t spinlock; /* protects the ide-tape queue */ /* diff --git a/drivers/mtd/cfi_probe.c b/drivers/mtd/cfi_probe.c index 392f7aa57..e46d26f56 100644 --- a/drivers/mtd/cfi_probe.c +++ b/drivers/mtd/cfi_probe.c @@ -17,7 +17,7 @@ #include -static struct mtd_info *cfi_probe(struct map_info *); +struct mtd_info *cfi_probe(struct map_info *); static void print_cfi_ident(struct cfi_ident *); static void check_cmd_set(struct map_info *, int, unsigned long); @@ -32,7 +32,7 @@ static const char im_name[] = "cfi_probe"; * this module is non-zero, i.e. between inter_module_get and * inter_module_put. Keith Owens 29 Oct 2000. */ -static struct mtd_info *cfi_probe(struct map_info *map) +struct mtd_info *cfi_probe(struct map_info *map) { struct mtd_info *mtd = NULL; struct cfi_private *cfi; diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index b356808c1..6051b34c6 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -74,6 +74,9 @@ Tobias Ringström - Rx interrupt status checking suggestion + Andrew Morton - (v0.9.13): clear blocked signals, avoid + buffer overrun setting current->comm. + Submitting bug reports: "rtl8139-diag -mmmaaavvveefN" output @@ -147,7 +150,7 @@ an MMIO register read. #include -#define RTL8139_VERSION "0.9.12" +#define RTL8139_VERSION "0.9.13" #define MODNAME "8139too" #define RTL8139_DRIVER_NAME MODNAME " Fast Ethernet driver " RTL8139_VERSION #define PFX MODNAME ": " @@ -747,14 +750,6 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev, RTL_W8 (Config1, 0); } -#ifndef USE_IO_OPS - /* sanity checks -- ensure PIO and MMIO registers agree */ - assert (inb (pio_start+Config0) == readb (ioaddr+Config0)); - assert (inb (pio_start+Config1) == readb (ioaddr+Config1)); - assert (inb (pio_start+TxConfig) == readb (ioaddr+TxConfig)); - assert (inb (pio_start+RxConfig) == readb (ioaddr+RxConfig)); -#endif /* !USE_IO_OPS */ - /* make sure chip thinks PIO and MMIO are enabled */ tmp8 = RTL_R8 (Config1); if ((tmp8 & Cfg1_PIO) == 0) { @@ -1460,7 +1455,7 @@ static inline void rtl8139_thread_iter (struct net_device *dev, DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n", dev->name, RTL_R16 (NWayLPAR)); DPRINTK ("%s: Other registers are IntMask %4.4x IntStatus %4.4x" - " RxStatus %4.4x.\n", dev->name, + " RxStatus %4.4lx.\n", dev->name, RTL_R16 (IntrMask), RTL_R16 (IntrStatus), RTL_R32 (RxEarlyStatus)); @@ -1477,7 +1472,13 @@ static int rtl8139_thread (void *data) unsigned long timeout; daemonize (); - sprintf (current->comm, "k8139d-%s", dev->name); + spin_lock_irq(¤t->sigmask_lock); + sigemptyset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + strncpy (current->comm, dev->name, sizeof(current->comm) - 1); + current->comm[sizeof(current->comm) - 1] = '\0'; while (1) { timeout = next_tick; @@ -2135,7 +2136,7 @@ static void rtl8139_set_rx_mode (struct net_device *dev) DPRINTK ("ENTER\n"); - DPRINTK ("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8x.\n", + DPRINTK ("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n", dev->name, dev->flags, RTL_R32 (RxConfig)); /* Note: do not reorder, GCC is clever about common statements. */ diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index b55a37f28..c9cab7ded 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -339,13 +339,12 @@ static int wait_timeout(struct net_device *dev, int c) /* returns true if it stayed c */ /* this uses base+6, but it's ok */ int i; - int timeout; /* twenty second or so total */ - for(i=0;i<20000;i++) { + for(i=0;i<200000;i++) { if ( c != inb_p(dev->base_addr+6) ) return 0; - for(timeout=loops_per_sec/1000; timeout > 0; timeout--) ; + udelay(100); } return 1; /* timed out */ } diff --git a/drivers/net/gmac.c b/drivers/net/gmac.c index f4c526044..78fa8fc12 100644 --- a/drivers/net/gmac.c +++ b/drivers/net/gmac.c @@ -35,6 +35,7 @@ #include #include #include +#include #ifdef CONFIG_PMAC_PBOOK #include #include @@ -45,8 +46,8 @@ #define DEBUG_PHY -/* Driver version 1.2, kernel 2.4.x */ -#define GMAC_VERSION "v1.2k4" +/* Driver version 1.3, kernel 2.4.x */ +#define GMAC_VERSION "v1.3k4" static unsigned char dummy_buf[RX_BUF_ALLOC_SIZE + RX_OFFSET + GMAC_BUFFER_ALIGN]; static struct net_device *gmacs = NULL; @@ -82,9 +83,6 @@ static struct net_device_stats *gmac_stats(struct net_device *dev); static int gmac_probe(void); static void gmac_probe1(struct device_node *gmac); -extern int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr, - unsigned char *devfn_ptr); - #ifdef CONFIG_PMAC_PBOOK int gmac_sleep_notify(struct pmu_sleep_notifier *self, int when); static struct pmu_sleep_notifier gmac_sleep_notifier = { @@ -813,21 +811,18 @@ gmac_set_multicast(struct net_device *dev) static int gmac_open(struct net_device *dev) { + int ret; struct gmac *gm = (struct gmac *) dev->priv; - MOD_INC_USE_COUNT; - /* Power up and reset chip */ - if (gmac_powerup_and_reset(dev)) { - MOD_DEC_USE_COUNT; + if (gmac_powerup_and_reset(dev)) return -EIO; - } /* Get our interrupt */ - if (request_irq(dev->irq, gmac_interrupt, 0, dev->name, dev)) { + ret = request_irq(dev->irq, gmac_interrupt, 0, dev->name, dev); + if (ret) { printk(KERN_ERR "%s can't get irq %d\n", dev->name, dev->irq); - MOD_DEC_USE_COUNT; - return -EAGAIN; + return ret; } gm->full_duplex = 0; @@ -901,7 +896,6 @@ gmac_close(struct net_device *dev) } } - MOD_DEC_USE_COUNT; return 0; } @@ -1360,7 +1354,7 @@ gmac_probe1(struct device_node *gmac) return; } - dev = init_etherdev(0, sizeof(struct gmac)); + dev = init_etherdev(NULL, sizeof(struct gmac)); if (!dev) { printk(KERN_ERR "GMAC: init_etherdev failed, out of memory\n"); @@ -1368,8 +1362,9 @@ gmac_probe1(struct device_node *gmac) free_page(rx_descpage); return; } + SET_MODULE_OWNER(dev); - gm = (struct gmac *) dev->priv; + gm = dev->priv; dev->base_addr = gmac->addrs[0].address; gm->regs = (volatile unsigned int *) ioremap(gmac->addrs[0].address, 0x10000); @@ -1379,7 +1374,7 @@ gmac_probe1(struct device_node *gmac) spin_lock_init(&gm->lock); - if (pci_device_loc(gmac, &gm->pci_bus, &gm->pci_devfn)) { + if (pci_device_from_OF_node(gmac, &gm->pci_bus, &gm->pci_devfn)) { gm->pci_bus = gm->pci_devfn = 0xff; printk(KERN_ERR "Can't locate GMAC PCI entry\n"); } diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index cf1666b1b..f2298caac 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -65,13 +65,7 @@ static char *version = /* Always include 'config.h' first in case the user wants to turn on or override something. */ -#ifdef MODULE #include -#include -#else -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT -#endif #define PRINTK(x) printk x @@ -125,7 +119,9 @@ struct net_local { /* Index to functions, as function prototypes. */ extern int mac89x0_probe(struct net_device *dev); +#if 0 extern void reset_chip(struct net_device *dev); +#endif static int net_open(struct net_device *dev); static int net_send_packet(struct sk_buff *skb, struct net_device *dev); static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -179,6 +175,8 @@ int __init mac89x0_probe(struct net_device *dev) unsigned long ioaddr; unsigned short sig; + SET_MODULE_OWNER(dev); + if (once_is_enough) return -ENODEV; once_is_enough = 1; @@ -286,6 +284,7 @@ int __init mac89x0_probe(struct net_device *dev) return 0; } +#if 0 /* This is useful for something, but I don't know what yet. */ void __init reset_chip(struct net_device *dev) { @@ -302,6 +301,7 @@ void __init reset_chip(struct net_device *dev) while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2) ; } +#endif /* Open/initialize the board. This is called (in the current kernel) sometime after booting when the 'ifconfig' program is run. @@ -352,10 +352,7 @@ net_open(struct net_device *dev) /* now that we've got our act together, enable everything */ writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ); - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - MOD_INC_USE_COUNT; + netif_start_queue(dev); return 0; } @@ -545,13 +542,12 @@ net_close(struct net_device *dev) writereg(dev, PP_BufCFG, 0); writereg(dev, PP_BusCTL, 0); - dev->start = 0; + netif_stop_queue(dev); free_irq(dev->irq, dev); /* Update the statistics here. */ - MOD_DEC_USE_COUNT; return 0; } @@ -615,14 +611,8 @@ static int set_mac_address(struct net_device *dev, void *addr) #ifdef MODULE -static char namespace[16] = ""; -static struct net_device dev_cs89x0 = { - NULL, - 0, 0, 0, 0, - 0, 0, - 0, 0, 0, NULL, NULL }; - -static int debug=0; +static struct net_device dev_cs89x0; +static int debug; MODULE_PARM(debug, "i"); @@ -634,7 +624,6 @@ init_module(void) struct net_local *lp; net_debug = debug; - dev_cs89x0.name = namespace; dev_cs89x0.init = mac89x0_probe; dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); memset(dev_cs89x0.priv, 0, sizeof(struct net_local)); diff --git a/drivers/net/ncr885e.c b/drivers/net/ncr885e.c index e9f724288..78152f427 100644 --- a/drivers/net/ncr885e.c +++ b/drivers/net/ncr885e.c @@ -13,8 +13,6 @@ static const char *version = "ncr885e.c:v1.0 02/10/00 dan@synergymicro.com, cort@fsmlabs.com\n"; -#include - #include #include #include @@ -40,26 +38,7 @@ static const char *version = static const char *chipname = "ncr885e"; -/* debugging flags */ -#if 0 -#define DEBUG_FUNC 0x0001 -#define DEBUG_PACKET 0x0002 -#define DEBUG_CMD 0x0004 -#define DEBUG_CHANNEL 0x0008 -#define DEBUG_INT 0x0010 -#define DEBUG_RX 0x0020 -#define DEBUG_TX 0x0040 -#define DEBUG_DMA 0x0080 -#define DEBUG_MAC 0x0100 -#define DEBUG_DRIVER 0x0200 -#define DEBUG_ALL 0x1fff -#endif - -#ifdef DEBUG_NCR885E #define NCR885E_DEBUG 0 -#else -#define NCR885E_DEBUG 0 -#endif /* The 885's Ethernet PCI device id. */ #ifndef PCI_DEVICE_ID_NCR_53C885_ETHERNET @@ -143,6 +122,12 @@ static void write_mii( unsigned long ioaddr, int reg, int data ); #define RX_RESET_FLAGS (RX_CHANNEL_RUN|RX_CHANNEL_PAUSE|RX_CHANNEL_WAKE) +static struct pci_device_id ncr885e_pci_tbl[] __initdata = { + { PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C885_ETHERNET, PCI_ANY_ID, PCI_ANY_ID, }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, ncr885e_pci_tbl); + #if 0 static int debug_ioctl( struct net_device *dev, struct ifreq *req, int cmd ) @@ -950,8 +935,6 @@ ncr885e_open( struct net_device *dev ) netif_start_queue(dev); - MOD_INC_USE_COUNT; - return 0; } @@ -976,9 +959,10 @@ ncr885e_xmit_start( struct sk_buff *skb, struct net_device *dev ) if ( next >= NR_TX_RING ) next = 0; - +#if 0 /* mark ourselves as busy, even if we have too many packets waiting */ netif_stop_queue(dev); +#endif /* see if it's necessary to defer this packet */ if ( sp->tx_active >= MAX_TX_ACTIVE ) { @@ -1082,8 +1066,6 @@ ncr885e_close(struct net_device *dev) kfree( np->head ); - MOD_DEC_USE_COUNT; - return 0; } @@ -1147,6 +1129,7 @@ static int __init ncr885e_probe1(unsigned long ioaddr, unsigned char irq ) dev = init_etherdev( NULL, sizeof( struct ncr885e_private ) ); if (!dev) return -ENOMEM; + SET_MODULE_OWNER(dev); sp = dev->priv; @@ -1199,9 +1182,8 @@ static int __init ncr885e_probe1(unsigned long ioaddr, unsigned char irq ) static int __init ncr885e_probe(void) { struct pci_dev *pdev = NULL; - unsigned int ioaddr, chips = 0; - unsigned short cmd; - unsigned char irq, latency; + unsigned int ioaddr, ret; + unsigned char irq; /* use 'if' not 'while' where because driver only supports one device */ if (( pdev = pci_find_device( PCI_VENDOR_ID_NCR, @@ -1214,32 +1196,24 @@ static int __init ncr885e_probe(void) } if (pci_enable_device(pdev)) - continue; + return -ENODEV; /* Use I/O space */ ioaddr = pci_resource_start (pdev, 0); irq = pdev->irq; - /* Adjust around the Grackle... */ -#ifdef CONFIG_GEMINI - ioaddr |= 0xfe000000; -#endif - if ( !request_region( ioaddr, NCR885E_TOTAL_SIZE, "ncr885e" )) - continue; + return -ENOMEM; /* finish off the probe */ - if ( !(ncr885e_probe1(ioaddr, irq ))) { - chips++; - pci_set_master (pdev); - } else - release_region( ioaddr, NCR885E_TOTAL_SIZE ); + ret = ncr885e_probe1(ioaddr, irq); + if (ret) + release_region(ioaddr, NCR885E_TOTAL_SIZE); + else + pci_set_master(pdev); } - if ( !chips ) - return -ENODEV; - else - return 0; + return ret; } /* debugging to peek at dma descriptors */ @@ -1382,6 +1356,6 @@ module_exit(ncr885e_cleanup); /* * Local variables: - * compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O6 -c symba.c" + * c-basic-offset: 8 * End: */ diff --git a/drivers/net/ncr885e.h b/drivers/net/ncr885e.h index bbcc82e11..b0e1a05d7 100644 --- a/drivers/net/ncr885e.h +++ b/drivers/net/ncr885e.h @@ -177,7 +177,7 @@ /* bits for the above three interrupt registers */ #define INTERRUPT_INTE 1<<15 /* interrupt enable */ #define INTERRUPT_WI 1<<9 /* wakeup interrupt */ -#define INTERRUPT_ERI 1<<8 /* early recieve interrupt */ +#define INTERRUPT_ERI 1<<8 /* early receive interrupt */ #define INTERRUPT_PPET 1<<7 /* PCI Tx parity error */ #define INTERRUPT_PBFT 1<<6 /* PCI Tx bus fault */ #define INTERRUPT_IIDT 1<<5 /* illegal instruction Tx */ diff --git a/drivers/net/pcmcia/ray_cs.h b/drivers/net/pcmcia/ray_cs.h index 830dd2268..6d4985061 100644 --- a/drivers/net/pcmcia/ray_cs.h +++ b/drivers/net/pcmcia/ray_cs.h @@ -33,8 +33,8 @@ typedef struct ray_dev_t { UCHAR *rmem; /* pointer to receive buffer window */ dev_link_t *finder; /* pointer back to dev_link_t for card */ struct timer_list timer; - int tx_ccs_lock; - int ccs_lock; + long tx_ccs_lock; + long ccs_lock; int dl_param_ccs; union { struct b4_startup_params b4; diff --git a/drivers/net/rcpci45.c b/drivers/net/rcpci45.c index 666078eec..20eeedfb2 100644 --- a/drivers/net/rcpci45.c +++ b/drivers/net/rcpci45.c @@ -36,6 +36,8 @@ ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ** +** Rasmus Andersen, December 2000: Converted to new PCI API. +** ** Pete Popov, January 11,99: Fixed a couple of 2.1.x problems ** (virt_to_bus() not called), tested it under 2.2pre5 (as a module), and ** added a #define(s) to enable the use of the same file for both, the 2.0.x @@ -47,10 +49,6 @@ ** ***************************************************************************/ -static char *version = -"RedCreek Communications PCI linux driver version 2.02\n"; - - #include #include #include @@ -75,6 +73,9 @@ static char *version = #include +static char version[] __initdata = +"RedCreek Communications PCI linux driver version 2.03\n"; + #define RC_LINUX_MODULE #include "rclanmtl.h" #include "rcif.h" @@ -123,7 +124,6 @@ typedef struct U32 function; struct timer_list timer; /* timer */ struct net_device_stats stats; /* the statistics structure */ - struct net_device *next; /* points to the next RC adapter */ unsigned long numOutRcvBuffers;/* number of outstanding receive buffers*/ unsigned char shutdown; unsigned char reboot; @@ -138,8 +138,6 @@ DPA, *PDPA; static PDPA PCIAdapters[MAX_ADAPTERS]; static int RCinit(struct net_device *dev); -static int RCscan(void); -static int RCfound_device(int, int, int, int, int, int); static int RCopen(struct net_device *); static int RC_xmit_packet(struct sk_buff *, struct net_device *); @@ -155,71 +153,29 @@ static void RCreboot_callback(U32, U32, U32, U16); static int RC_allocate_and_post_buffers(struct net_device *, int); -/* A list of all installed RC devices, for removing the driver module. */ -static struct net_device *root_RCdev; +static struct pci_device_id rcpci45_pci_table[] __devinitdata = { + { RC_PCI45_VENDOR_ID, RC_PCI45_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0, } +}; +MODULE_DEVICE_TABLE(pci, rcpci_pci_table); -static int __init rcpci_init_module (void) +static void rcpci45_remove_one(struct pci_dev *pdev) { - int cards_found; - - cards_found = RCscan(); - if (cards_found) - printk(version); - return cards_found ? 0 : -ENODEV; -} + struct net_device *dev = pdev->driver_data; + PDPA pDpa = dev->priv; -static int RCscan(void) -{ - int cards_found = 0; - static int pci_index; - - if (!pcibios_present()) - return cards_found; - - for (;pci_index < 0x8; pci_index++) - { - unsigned char pci_bus, pci_device_fn; - int scan_status; - int board_index = 0; - unsigned char pci_irq_line; - unsigned int pci_ioaddr; - struct pci_dev *pdev; - - scan_status = - (pcibios_find_device (RC_PCI45_VENDOR_ID, - RC_PCI45_DEVICE_ID, - pci_index, - &pci_bus, - &pci_device_fn)); -#ifdef RCDEBUG - printk("rc scan_status = 0x%X\n", scan_status); -#endif - if (scan_status != PCIBIOS_SUCCESSFUL || - !((pdev = pci_find_slot(pci_bus, pci_device_fn)))) - break; - pci_irq_line = pdev->irq; - pci_ioaddr = pci_resource_start (pdev, 0); + if (!dev) { + printk (KERN_ERR "remove non-existent device\n"); + return; + } -#ifdef RCDEBUG - printk("rc: Found RedCreek PCI adapter\n"); - printk("rc: pci_bus = %d, pci_device_fn = %d\n", pci_bus, pci_device_fn); - printk("rc: pci_irq_line = 0x%x \n", pci_irq_line); - printk("rc: pci_ioaddr = 0x%x\n", pci_ioaddr); -#endif + printk("IOP reset: 0x%x\n", RCResetIOP(pDpa->id)); - if (pci_enable_device(pdev)) - break; - pci_set_master(pdev); + unregister_netdev(dev); + iounmap((void *)dev->base_addr); + free_irq(dev->irq, dev); - if (!RCfound_device(pci_ioaddr, pci_irq_line, - pci_bus, pci_device_fn, - board_index++, cards_found)) - cards_found++; - } -#ifdef RCDEBUG - printk("rc: found %d cards \n", cards_found); -#endif - return cards_found; + kfree(dev); } static int RCinit(struct net_device *dev) @@ -233,17 +189,22 @@ static int RCinit(struct net_device *dev) return 0; } -static int -RCfound_device(int memaddr, int irq, - int bus, int function, int product_index, int card_idx) +static int rcpci45_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) { int dev_size = 32768; unsigned long *vaddr=0; PDPA pDpa; int init_status; + long memaddr = pci_resource_start(pdev, 0); + int card_idx; struct net_device *dev; - + + static int card_counter = 0; + + card_idx = card_counter++; /* Yeah, icky hack. */ + /* * Allocate and fill new device structure. * We need enough for struct net_device plus DPA plus the LAN API private @@ -256,10 +217,13 @@ RCfound_device(int memaddr, int irq, dev = (struct net_device *) kmalloc(dev_size, GFP_DMA | GFP_KERNEL |GFP_ATOMIC); if (!dev) { - printk("rc: unable to kmalloc dev\n"); + printk("rcpci45 driver: unable to kmalloc dev struct\n"); return 1; } memset(dev, 0, dev_size); + + pdev->driver_data = dev; + /* * dev->priv will point to the start of DPA. */ @@ -268,15 +232,16 @@ RCfound_device(int memaddr, int irq, #ifdef RCDEBUG printk("rc: dev = 0x%x, dev->priv = 0x%x\n", (uint)dev, (uint)dev->priv); #endif - + pDpa = dev->priv; pDpa->dev = dev; /* this is just for easy reference */ - pDpa->function = function; - pDpa->bus = bus; + pDpa->function = pdev->devfn; + pDpa->bus = (unsigned char)pdev->bus->number; pDpa->id = card_idx; /* the device number */ pDpa->pci_addr = memaddr; PCIAdapters[card_idx] = pDpa; + #ifdef RCDEBUG printk("rc: pDpa = 0x%x, id = %d \n", (uint)pDpa, (uint)pDpa->id); #endif @@ -300,7 +265,7 @@ RCfound_device(int memaddr, int irq, (uint)dev, (uint)dev->priv, (uint)vaddr); #endif dev->base_addr = (unsigned long)vaddr; - dev->irq = irq; + dev->irq = pdev->irq; /* * Request a shared interrupt line. @@ -342,9 +307,6 @@ RCfound_device(int memaddr, int irq, dev->init = &RCinit; ether_setup(dev); /* linux kernel interface */ - pDpa->next = root_RCdev; - root_RCdev = dev; - if (register_netdev(dev) != 0) /* linux kernel interface */ { printk("rc: unable to register device \n"); @@ -359,6 +321,22 @@ RCfound_device(int memaddr, int irq, return 0; /* success */ } +static struct pci_driver rcpci45_driver = { + name: "rcpci45", + id_table: rcpci45_pci_table, + probe: rcpci45_init_one, + remove: rcpci45_remove_one, +}; + +static int __init rcpci_init_module (void) +{ + int rc = pci_module_init(&rcpci45_driver); + + if (!rc) + printk(version); + return rc; +} + static int RCopen(struct net_device *dev) { @@ -1185,31 +1163,7 @@ static int RCconfig(struct net_device *dev, struct ifmap *map) static void __exit rcpci_cleanup_module (void) { - PDPA pDpa; - struct net_device *next; - - -#ifdef RCDEBUG - printk("rc: RC cleanup_module\n"); - printk("rc: root_RCdev = 0x%x\n", (uint)root_RCdev); -#endif - - - while (root_RCdev) - { - pDpa = (PDPA) root_RCdev->priv; -#ifdef RCDEBUG - printk("rc: cleanup 0x%08X\n", (uint)root_RCdev); -#endif - printk("IOP reset: 0x%x\n", RCResetIOP(pDpa->id)); - unregister_netdev(root_RCdev); - next = pDpa->next; - - iounmap((unsigned long *)root_RCdev->base_addr); - free_irq( root_RCdev->irq, root_RCdev ); - kfree(root_RCdev); - root_RCdev = next; - } + pci_unregister_driver(&rcpci45_driver); } module_init(rcpci_init_module); diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index e4fa70c31..9e73fc270 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -165,8 +165,8 @@ struct cosa_data { int nchannels; /* # of channels on this card */ int driver_status; /* For communicating with firware */ int firmware_status; /* Downloaded, reseted, etc. */ - int rxbitmap, txbitmap; /* Bitmap of channels who are willing to send/receive data */ - int rxtx; /* RX or TX in progress? */ + long int rxbitmap, txbitmap; /* Bitmap of channels who are willing to send/receive data */ + long int rxtx; /* RX or TX in progress? */ int enabled; int usage; /* usage count */ int txchan, txsize, rxsize; diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in index 4feaecace..634a5a8e6 100644 --- a/drivers/scsi/Config.in +++ b/drivers/scsi/Config.in @@ -8,6 +8,8 @@ fi dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI +dep_tristate ' SCSI OnStream SC-x0 tape support' CONFIG_CHR_DEV_OSST $CONFIG_SCSI + 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.ibmmca b/drivers/scsi/README.ibmmca index 313690c26..effb3773a 100644 --- a/drivers/scsi/README.ibmmca +++ b/drivers/scsi/README.ibmmca @@ -10,10 +10,10 @@ General Public License. Originally written by Martin Kolinek, December 1995. Officially maintained by Michael Lang since January 1999. - Version 3.2 + Version 4.0 - Last update: 29 July 2000 + Last update: 28 December 2000 Authors of this Driver @@ -196,7 +196,7 @@ ldn=15 is reserved for the subsystem itself. Wide adapters may have to check up to 15 * 8 = 120 pun/lun combinations. - 2.3 SCSI-Device Recognition and dynamical ldn Assignment + 2.3 SCSI-Device Recognition and Dynamical ldn Assignment -------------------------------------------------------- One consequence of information hiding is that the real (pun,lun) numbers are also hidden. The two possibilities to get around this problem @@ -882,15 +882,39 @@ 1) Submission of this driver for kernel 2.4test-XX and 2.2.17. - Michael Lang + December 28, 2000 (v3.2d / v4.0) + 1) The interrupt handler had some wrong statement to wait for. This + was done due to experimental reasons during 3.2 development but it + has shown that this is not stable enough. Going back to wait for the + adapter to be not busy is best. + 2) Inquiry requests can be shorter than 255 bytes of return buffer. Due + to a bug in the ibmmca_queuecommand routine, this buffer was forced + to 255 at minimum. If the memory address, this return buffer is pointing + does not offer more space, invalid memory accesses destabilized the + kernel. + 3) version 4.0 is only valid for kernel 2.4.0 or later. This is necessary + to remove old kernel version dependant waste from the driver. 3.2d is + only distributed with older kernels but keeps compatibility with older + kernel versions. + 4) The commandline argument 'bypass' and all its functionality got removed + in version 4.0. This was never really necessary and is kept in 3.2X for + debugging reasons. + 5) Dynamical reassignment of ldns was again verified and should work now. + 6) All commands that get sent to the SCSI adapter were verified and + completed in such a way, that they are now completely conform to the + demands in the technical description of IBM. Main candidates were the + DEVICE_INQUIRY, REQUEST_SENSE and DEVICE_CAPACITY commands. They must + be tranferred by bypassing the internal command buffer of the adapter + or else the response is a random result. + 7) v3.2d is still hold back for some days for testing, while 4.0 is + released. + - Michael Lang + 4 To do ------- - IBM SCSI-2 F/W external SCSI bus support in seperate mode. - It seems that the handling of bad disks is really bad - non-existent, in fact. - - More testing of the full driver-controlled dynamical ldn - (re)mapping for up to 56 SCSI-devices. I guess, it won't work - at the moment, but nobody ever really tried it. - - Abort and Reset functions still slightly buggy. 5 Users' Manual --------------- @@ -925,7 +949,7 @@ 6543210A where the numbers 0 to 6 light up at the shown position, - when the SCSI-device is accessed. A shows again the SCSI + when the SCSI-device is accessed. 'A' shows again the SCSI hostindex. If display nor adisplay is set, the internal PS/2 harddisk LED is used for media-activities. So, if you really do not have a system with a LED-display, you @@ -945,7 +969,12 @@ activity indicator, which means, that you must use the alphanumeric LED display if you want to monitor SCSI- activity. - bypass This commandline parameter forces the driver never to use + bypass This is obsolete from driver version 4.0, as the adapters + got that far understood, that the selection between + integrated and bypassed commands should now work completely + correct! For historical reasons, the old description is + kept here: + This commandline parameter forces the driver never to use SCSI-subsystems' integrated SCSI-command set. Except of the immediate assign, which is of vital importance for every IBM SCSI-subsystem to set its ldns right. Instead, @@ -997,15 +1026,19 @@ commandN+1 = adapter PUN e.g. ibmmcascsi=0x3540,7 will force the driver to detect a SCSI-subsystem - at I/O-address 0x3540 with adapter PUN 7. + at I/O-address 0x3540 with adapter PUN 7. Please only use this method, if + the driver does really not recognize your SCSI-adapter! With driver version + 3.2, this recognition of various adapters was hugely improved and you + should try first to remove your commandline arguments of such type with a + newer driver. I bet, it will be recognized correctly. Even multiple and + different types of IBM SCSI-adapters should be recognized correctly, too. Examples: - ibmmcascsi=adisplay,bypass + ibmmcascsi=adisplay - This will use the advanced display mode for the model 95 LED display and - every SCSI-command passed to an attached device will get bypassed in order - not to use any of the subsystem built-in commands. + This will use the advanced display mode for the model 95 LED alphanumeric + display. ibmmcascsi=display,0x3558,7 @@ -1127,7 +1160,21 @@ everything should be fine. This is necessary even if one assumes, that some 80486 system should be downward compatible to 80386 software. - + Q: Some commands hang and interrupts block the machine. After some + timeout, the syslog reports that it tries to call abort, but the + machine is frozen. + A: This can be a busy wait bug in the interrupt handler of driver + version 3.2. You should at least upgrade to 3.2c if you use + kernel < 2.4.0 and driver version 4.0 if you use kernel 2.4.0 or + later (including all test releases). + Q: I have a PS/2 model 80 and more than 16 MBytes of RAM. The driver + completely refuses to work, reports NMIs, COMMAND ERRORs or other + ambiguous stuff. When reducing the RAM size down below 16 MB, + everything is running smoothly. + A: No real answer, yet. In any case, one should force the kernel to + present SCBs only below the 16 MBytes barrier. Maybe this solves the + problem. Not yet tried, but guessing that it could work. + 5.3 Bugreports -------------- If you really find bugs in the sourcecode or the driver will successfully @@ -1167,7 +1214,8 @@ Here you can find info about the background of this driver, patches, troubleshooting support, news and a bugreport form. Please check that - WWW-page regularly for latest hints. + WWW-page regularly for latest hints. If ever this URL changes, please + refer to the MAINTAINERS File in order to get the latest address. For the bugreport, please fill out the formular on the corresponding WWW-page. Read the dedicated instructions and write as much as you @@ -1262,7 +1310,9 @@ Erik Weber for the great deal we made about a model 9595 and the nice surrounding equipment and the cool trip to Mannheim - second-hand computer market. + second-hand computer market. In addition, I would like to + to thank him for his exhaustive SCSI-driver testing on his + 95er PS/2 park. Anthony Hogbin for his direct shipment of a SCSI F/W adapter, which allowed me immediately on the first stage to try it on model 8557 @@ -1277,7 +1327,7 @@ and his cool remark about how you make an ordinary diskette drive working and how to connect it to an IBM-diskette port. Johannes Gutenberg-University, Mainz & - Institut fuer Kernphysik, MAMI + Institut fuer Kernphysik, Mainz Microtron (MAMI) for the offered space, the link, placed on the central homepage and the space to store and offer the driver and related material and the free working times, which allow @@ -1301,7 +1351,10 @@ that dataloss or severe damage of hardware is possible while using this part of software on some arbitrary computer hardware or in combination with other software packages. It is highly recommended to make backup - copies of your data before using this software. + copies of your data before using this software. Furthermore, personal + injuries by hardware defects, that could be caused by this SCSI-driver are + not excluded and it is highly recommended to handle this driver with a + maximum of carefulness. This driver supports hardware, produced by International Business Machines Corporation (IBM). diff --git a/drivers/scsi/README.tmscsim b/drivers/scsi/README.tmscsim index 207420eb3..e165229ad 100644 --- a/drivers/scsi/README.tmscsim +++ b/drivers/scsi/README.tmscsim @@ -9,6 +9,7 @@ The tmscsim driver 6. Potential improvements 7. Bug reports, debugging and updates 8. Acknowledgements +9. Copyright 1. Purpose and history @@ -25,7 +26,7 @@ It has originally written by C.L. Huang from the Tekram corp. to support the Tekram DC390(T) adapter. This is where the name comes from: tm = Tekram scsi = SCSI driver, m = AMD (?) as opposed to w for the DC390W/U/F (NCR53c8X5, X=2/7) driver. Yes, there was also a driver for the latter, -tmscsimw, which supported DC390W/U/F adapters. It's not maintained any more, +tmscsiw, which supported DC390W/U/F adapters. It's not maintained any more, as the ncr53c8xx is perfectly supporting these adpaters since some time. The driver first appeared in April 1996, exclusively supported the DC390 @@ -56,10 +57,13 @@ linux/drivers/scsi, you basically have to do nothing special to use this driver. Of course you have to choose to compile SCSI support and DC390(T) support into your kernel or as module when configuring your kernel for compiling. +NEW: You may as well compile this module outside your kernel, using the +supplied Makefile. If you got an old kernel (pre 2.1.127, pre 2.0.37p1) with an old version of this driver: Get dc390-21125-20b.diff.gz or dc390-2036p21-20b1.diff.gz from - my website and apply the patch. + my web page and apply the patch. Apply further patches to upgrade to the + latest version of the driver. If you want to do it manually, you should copy the files (dc390.h, tmscsim.h, tmscsim.c, scsiiom.c and README.tmscsim) from this directory to @@ -91,6 +95,8 @@ So take at least the following measures: tune2fs -e remount-ro /dev/sd?? * have copies of your SCSI disk's partition tables on some safe location: dd if=/dev/sda of=/mnt/floppy/sda bs=512 count=1 + or just print it with: + fdisk -l | lpr * make sure you are able to boot Linux (e.g. from floppy disk using InitRD) if your SCSI disk gets corrupted. You can use ftp://student.physik.uni-dortmund.de/pub/linux/kernel/bootdisk.gz @@ -102,7 +108,7 @@ MHz PCI bus works for me, though, but I don't recommend using higher clocks than the 33.33 MHz being in the PCI spec. If you want to share the IRQ with another device and the driver refuses to -do, you might succeed with changing the DC390_IRQ type in tmscsim.c to +do so, you might succeed with changing the DC390_IRQ type in tmscsim.c to SA_SHIRQ | SA_INTERRUPT. @@ -121,11 +127,12 @@ SA_SHIRQ | SA_INTERRUPT. * Dynamically configurable by writing to /proc/scsi/tmscsim/? * Dynamic allocation of resources * SMP support: Locking on io_request lock (Linux 2.1/2.2) or adapter - specific locks (Linux 2.3) + specific locks (Linux 2.5?) * Uniform source code for Linux-2.x.y * Support for dyn. addition/removal of devices via add/remove-single-device - (Try: echo "scsi add-single-device H C I L" >/proc/scsi/scsi - H = Host, C = Channel, I = SCSI ID, L = SCSI LUN.) Use with care! + (Try: echo "scsi add-single-device C B T U" >/proc/scsi/scsi + C = Controller, B = Bus, T = Target SCSI ID, U = Unit SCSI LUN.) + Use with care! * Try to use the partition table for the determination of the mapping @@ -139,20 +146,21 @@ You will see some info regarding the adapter and, at the end, a listing of the attached devices and their settings. Here's an example: -garloff@kg1:/home/garloff > cat /proc/scsi/tmscsim/0 -Tekram DC390/AM53C974 PCI SCSI Host Adapter, Driver Version 1.20s, 1998/08/20 -SCSI Host Nr 0, AM53C974 Adapter Nr 0 -IOPortBase 0x6200, IRQLevel 0x09 -MaxID 7, MaxLUN 8, AdapterID 7, SelTimeout 250 ms -TagMaxNum 16, Status 0, ACBFlag 0, GlitchEater 24 ns -Statistics: Nr of Cmnds 39563, Cmnds not sent directly 0, Out of SRB conds 0 - Nr of lost arbitrations 17 +garloff@kurt:/home/garloff > cat /proc/scsi/tmscsim/0 +Tekram DC390/AM53C974 PCI SCSI Host Adapter, Driver Version 2.0e7 2000-11-28 +SCSI Host Nr 1, AM53C974 Adapter Nr 0 +IOPortBase 0xb000, IRQ 10 +MaxID 8, MaxLUN 8, AdapterID 6, SelTimeout 250 ms, DelayReset 1 s +TagMaxNum 16, Status 0x00, ACBFlag 0x00, GlitchEater 24 ns +Statistics: Cmnds 1470165, Cmnds not sent directly 0, Out of SRB conds 0 + Lost arbitrations 587, Sel. connected 0, Connected: No Nr of attached devices: 4, Nr of DCBs: 4 -Idx ID LUN Prty Sync DsCn SndS TagQ STOP NegoPeriod SyncSpeed SyncOffs -00 00 00 Yes Yes Yes Yes Yes No 100 ns 10.0 M 15 -01 01 00 Yes Yes Yes Yes Yes No 100 ns 10.0 M 15 -02 03 00 Yes Yes Yes Yes No No 100 ns 10.0 M 15 -03 05 00 Yes No Yes Yes No No (200 ns) +Map of attached LUNs: 01 00 00 03 01 00 00 00 +Idx ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs MaxCmd +00 00 00 Yes Yes Yes Yes Yes 100 ns 10.0 M 15 16 +01 03 00 Yes Yes Yes Yes No 100 ns 10.0 M 15 01 +02 03 01 Yes Yes Yes Yes No 100 ns 10.0 M 15 01 +03 04 00 Yes Yes Yes Yes No 100 ns 10.0 M 15 01 Note that the settings MaxID and MaxLUN are not zero- but one-based, which means that a setting MaxLUN=4, will result in the support of LUNs 0..3. This @@ -178,9 +186,8 @@ SyncOffs is the offset used for synchronous negotiations; max. is 15. The last values are only shown, if Sync is enabled. (NegoPeriod is still displayed in brackets to show the values which will be used after enabling Sync.) -The STOP parameter is for testing/debugging purposes only and should bet set -to No. Please don't fiddle with it, unless you want to get rid of the -contents of your disk. +MaxCmd ist the number of commands (=tags) which can be processed at the same +time by the device. If you want to change a setting, you can do that by writing to /proc/scsi/tmscsim/?. Basically you have to imitate the output of driver. @@ -196,8 +203,8 @@ There are three kinds of changes: echo "MaxLUN=8 seltimeout 200" >/proc/scsi/tmscsim/0 Note that you can only change MaxID, MaxLUN, AdapterID, SelTimeOut, - TagMaxNum, ACBFlag and GlitchEater. Don't change ACBFlag unless you - want to see what happens, if the driver hangs. + TagMaxNum, ACBFlag, GlitchEater and DelayReset. Don't change ACBFlag + unless you want to see what happens, if the driver hangs. (2) Change device settings: You write a config line to the driver. The Nr must match the ID and LUN given. If you give "-" as parameter, it is @@ -207,8 +214,8 @@ There are three kinds of changes: an INQUIRY on the device if necessary to check if it is capable to operate with the given settings (Sync, TagQ). Examples: - echo "0 0 0 y y y - y - 10" >/proc/scsi/tmscsim/0 - echo "3 5 0 y n y" >/proc/scsi/tmscsim/0 + echo "0 0 0 y y y - y - 10 " >/proc/scsi/tmscsim/0 + echo "3 5 0 y n y " >/proc/scsi/tmscsim/0 To give a short explanation of the first example: The first three numbers, "0 0 0" (Device index 0, SCSI ID 0, SCSI LUN 0), @@ -223,22 +230,26 @@ There are three kinds of changes: discussed above. The values used in this example will result in maximum performance. -(3) Special commands: You can force a SCSI bus reset, an INQUIRY command and - the removal of a device's DCB. +(3) Special commands: You can force a SCSI bus reset, an INQUIRY command, the + removal or the addition of a device's DCB and a SCSI register dump. This is only used for debugging when you meet problems. The parameter of - the INQUIRY and remove command is the device index as shown by the + the INQUIRY and REMOVE commands is the device index as shown by the output of /proc/scsi/tmscsim/? in the device listing in the first column - (Idx). + (Idx). ADD takes the SCSI ID and LUN. Examples: echo "reset" >/proc/scsi/tmscsim/0 echo "inquiry 1" >/proc/scsi/tmscsim/0 echo "remove 2" >/proc/scsi/tmscsim/1 + echo "add 2 3" >/proc/scsi/tmscsim/? + echo "dump" >/proc/scsi/tmscsim/0 - Note that you will meet problems when you remove a device's DCB with the + Note that you will meet problems when you REMOVE a device's DCB with the remove command if it contains partitions which are mounted. Only use it after unmounting its partitions, telling the SCSI mid-level code to remove it (scsi remove-single-device) and you really need a few bytes of memory. + The ADD command allows you to configure a device before you tell the + mid-level code to try detection. I'd suggest reviewing the output of /proc/scsi/tmscsim/? after changing @@ -247,18 +258,20 @@ settings to see if everything changed as requested. 5. Configuration via boot/module parameters ------------------------------------------- -With the DC390, the driver reads its EEPROM settings and IGNORES boot / -module parameters. If you want to override the EEPROM settings of a DC390, -you have to use the /proc/scsi/tmscsim/? interface described in the above -chapter. - -However, if you do have another AM53C974 based adapter you might want to -adjust some settings before you are able to write to the /proc/scsi/tmscsim/? -pseudo-file, e.g. if you want to use another adapter ID than 7. (Note that -the log message "DC390: No EEPROM found!" is normal without a DC390.) +With the DC390, the driver reads its EEPROM settings and tries to use them. +But you may want to override the settings prior to being able to change the +driver configuration via /proc/scsi/tmscsim/?. +If you do have another AM53C974 based adapter, that's even the only +possibility to adjust settings before you are able to write to the +/proc/scsi/tmscsim/? pseudo-file, e.g. if you want to use another +adapter ID than 7. +(BTW, the log message "DC390: No EEPROM found!" is normal without a DC390.) For this purpose, you can pass options to the driver before it is initialised by using kernel or module parameters. See lilo(8) or modprobe(1) manual pages on how to pass params to the kernel or a module. +[NOTE: Formerly, it was not possible to override the EEPROM supplied + settings of the DC390 with cmd line parameters. This has changed since + 2.0e7] The syntax of the params is much shorter than the syntax of the /proc/... interface. This makes it a little bit more difficult to use. However, long @@ -269,7 +282,7 @@ As the support for non-DC390 adapters works by simulating the values of the DC390 EEPROM, the settings are given in a DC390 BIOS' way. Here's the syntax: -tmscsim=AdaptID,SpdIdx,DevMode,AdaptMode,TaggedCmnds +tmscsim=AdaptID,SpdIdx,DevMode,AdaptMode,TaggedCmnds,DelayReset Each of the parameters is a number, containing the described information: @@ -278,7 +291,7 @@ Each of the parameters is a number, containing the described information: * SpdIdx: The index of the maximum speed as in the DC390 BIOS. The values 0..7 mean 10, 8.0, 6.7, 5.7, 5.0, 4.0, 3.1 and 2 MHz resp. Default is - 1 (8.0 MHz). + 0 (10.0 MHz). * DevMode is a bit mapped value describing the per-device features. It applies to all devices. (Sync, Disc and TagQ will only apply, if the @@ -289,7 +302,7 @@ Each of the parameters is a number, containing the described information: *1 0x02 2 Synchronous Negotiation *2 0x04 4 Disconnection *3 0x08 8 Send Start command on startup. (Not used) - *4 0x10 16 Tagged Queueing + *4 0x10 16 Tagged Command Queueing As usual, the desired value is obtained by adding the wanted values. If you want to enable all values, e.g., you would use 31(0x1f). Default is 31. @@ -315,18 +328,23 @@ Each of the parameters is a number, containing the described information: *3 16 4 32 +* DelayReset is the time in seconds (minus 0.5s), the adapter waits, after a + bus reset. Default is 1 (corresp. to 1.5s). + Example: modprobe tmscsim tmscsim=6,2,31 would set the adapter ID to 6, max. speed to 6.7 MHz, enable all device -features and leave the adapter features and the number of Tagged Commands -to the defaults. +features and leave the adapter features, the number of Tagged Commands +and the Delay after a reset to the defaults. -As you can see, you don't need to specify all of the five params. +As you can see, you don't need to specify all of the six params. +If you want values to be ignored (i.e. the EEprom settings or the defaults +will be used), you may pass -2 (not 0!) at the corresponding position. -The defaults (7,1,31,15,3) are aggressive to allow good performance. You can -use tmscsim=7,0,31,63,4 for maximum performance, if your SCSI chain is -perfect. If you meet problems, you can use tmscsim=-1 which is a shortcut -for tmscsim=7,4,9,15,2. +The defaults (7,0,31,15,3,1) are aggressive to allow good performance. You +can use tmscsim=7,0,31,63,4,0 for maximum performance, if your SCSI chain +allows it. If you meet problems, you can use tmscsim=-1 which is a shortcut +for tmscsim=7,4,9,15,2,10. 6. Potential improvements @@ -334,42 +352,47 @@ for tmscsim=7,4,9,15,2. Most of the intended work on the driver has been done. Here are a few ideas to further improve its usability: +* Cleanly separate per-Target and per-LUN properties (DCB) * More intelligent abort() routine -* Implement new_eh code (Linux-2.1+) -* Have the mid-level code (and not the driver) handle more of the various - conditions. -* Rework command queueing in the driver +* Use new_eh code (Linux-2.1+) +* Have the mid-level (ML) code (and not the driver) handle more of the + various conditions. +* Command queueing in the driver: Eliminate Query list and use ML instead. * More user friendly boot/module param syntax Further investigation on these problems: * Driver hangs with sync readcdda (xcdroast) (most probably VIA PCI error) -Known problems: - -* There was a report that with a certain Scanner, the last SCSI command - won't be finished correctly. This might be a command queueing bug or a bug - in SCSI implementation of the scanner. Issueing another command to the - scanner seems to help. (Try echo "INQUIRY x" >/proc/scsi/tmscsim/?, where - x is the index (not the SCSI ID!) of the scanner. See 4.(3).) +Known problems: +Please see http://www.garloff.de/kurt/linux/dc390/problems.html + +* Changing the parameters of multi-lun by the tmscsim/? interface will + cause problems, cause these settings are mostly per Target and not per LUN + and should be updated accordingly. To be fixed for 2.0d24. +* CDRs (eg Yam CRW4416) not recognized, because some buggy devices don't + recover from a SCSI reset in time. Use a higher delay or don't issue + a SCSI bus reset on driver initialization. See problems page. + For the CRW4416S, this seems to be solved with firmware 1.0g (reported by + Jean-Yves Barbier). +* TEAC CD-532S not being recognized. (Works with 1.11). +* Scanners (eg. Astra UMAX 1220S) don't work: Disable Sync Negotiation. + If this does not help, try echo "INQUIRY t" >/proc/scsi/tmscsim/? (t + replaced by the dev index of your scanner). You may try to reset your SCSI + bus afterwards (echo "RESET" >/proc/scsi/tmscsim/?). + The problem seems to be solved as of 2.0d18, thanks to Andreas Rick. * If there is a valid partition table, the driver will use it for determing - the mapping. Other operating systems may not like this mapping, though + the mapping. If there's none, a reasonable mapping (Symbios-like) will be + assumed. Other operating systems may not like this mapping, though it's consistent with the BIOS' behaviour. Old DC390 drivers ignored the partition table and used a H/S = 64/32 or 255/63 translation. So if you want to be compatible to those, use this old mapping when creating - partition tables. -* In some situations, the driver will get stuck in an abort loop. Please - disable DsCn, if you meet this problem. Please contact me for further - debugging. -* 2.1.115+: Linux misses locks in sr_ioctl.c and scsi_ioctl.c - There used to be a patch included here, which partially solved the - problem. I suggest you contact Chiaki Ishikawa , - Richard Waltham or Doug Ledford - , if you want to help further debugging it. -* 2.0.35: CD changers (e.g. NAKAMICHI MBR-7.{0,2}) have problems because - the mid-level code doesn't handle BLIST_SINGLELUN correctly. There used - to be a patch included here to fix this, but I was told that it is fixed - in 2.0.36. + partition tables. Even worse, on bootup the DC390 might complain if other + mappings are found, so auto rebooting may fail. +* In some situations, the driver will get stuck in an abort loop. This is a + bad interaction between the Mid-Layer of Linux' SCSI code and the driver. + Try to disable DsCn, if you meet this problem. Please contact me for + further debugging. 7. Bug reports, debugging and updates @@ -394,25 +417,33 @@ having your box spending most of its time doing the logging. The latest version of the driver can be found at: http://www.garloff.de/kurt/linux/dc390/ -and - ftp://student.physik.uni-dortmund.de/pub/linux/kernel/dc390/ -(The latter might shut down some day.) + ftp://ftp.suse.com/pub/people/garloff/linux/dc390/ 8. Acknowledgements ------------------- -Thanks to Linus Torvalds, Alan Cox, David Miller, Rik v. Riel, the FSF -people, the XFree86 team and all the others for the wonderful OS and -software. +Thanks to Linus Torvalds, Alan Cox, the FSF people, the XFree86 team and +all the others for the wonderful OS and software. Thanks to C.L. Huang and Philip Giang (Tekram) for the initial driver release and support. -Thanks to Doug Ledford, Gerard Roudier for support with SCSI coding. +Thanks to Doug Ledford, Gérard Roudier for support with SCSI coding. Thanks to a lot of people (espec. Chiaki Ishikawa, Andreas Haumer, Hubert Tonneau) for intensively testing the driver (and even risking data loss -doing this during early revisions). +doing this during early revisions). +Recently, SuSE GmbH, Nuernberg, FRG, has been paying me for the driver +development and maintenance. Special thanks! + +9. Copyright +------------ + This driver 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; version 2 of the License. + If you want to use any later version of the GNU GPL, you will probably + be allowed to, but you have to ask me and Tekram + before. ------------------------------------------------------------------------- Written by Kurt Garloff 1998/06/11 -Last updated 1998/12/25, driver revision 2.0d -$Id: README.tmscsim,v 2.9 1998/12/25 18:04:20 garloff Exp $ +Last updated 2000/11/28, driver revision 2.0e7 +$Id: README.tmscsim,v 2.25.2.7 2000/12/20 01:07:12 garloff Exp $ diff --git a/drivers/scsi/dc390.h b/drivers/scsi/dc390.h index 96b4b929d..8e3a5c836 100644 --- a/drivers/scsi/dc390.h +++ b/drivers/scsi/dc390.h @@ -4,9 +4,7 @@ * Description: Device Driver for Tekram DC-390(T) PCI SCSI * * Bus Master Host Adapter * ***********************************************************************/ -/* $Id: dc390.h,v 2.12 1998/12/25 17:33:27 garloff Exp $ */ - -#include +/* $Id: dc390.h,v 2.43.2.22 2000/12/20 00:39:36 garloff Exp $ */ /* * DC390/AMD 53C974 driver, header file @@ -15,10 +13,27 @@ #ifndef DC390_H #define DC390_H +#include +#ifndef KERNEL_VERSION +# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#endif + #define DC390_BANNER "Tekram DC390/AM53C974" -#define DC390_VERSION "2.0d 1998/12/25" +#define DC390_VERSION "2.0f 2000-12-20" + +/* We don't have eh_abort_handler, eh_device_reset_handler, + * eh_bus_reset_handler, eh_host_reset_handler yet! + * So long: Use old exception handling :-( */ +#define OLD_EH -#include +#if LINUX_VERSION_CODE < KERNEL_VERSION (2,1,70) || defined (OLD_EH) +# define NEW_EH +#else +# define NEW_EH use_new_eh_code: 1, +# define USE_NEW_EH +#endif + +#if defined(HOSTS_C) || defined(MODULE) || LINUX_VERSION_CODE > KERNEL_VERSION(2,3,99) extern int DC390_detect(Scsi_Host_Template *psht); extern int DC390_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)); @@ -34,8 +49,29 @@ static int DC390_release(struct Scsi_Host *); extern int DC390_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30) +#define DC390_T { \ + proc_name: "tmscsim", \ + proc_info: DC390_proc_info, \ + name: DC390_BANNER " V" DC390_VERSION, \ + detect: DC390_detect, \ + release: DC390_release, \ + queuecommand: DC390_queue_command, \ + abort: DC390_abort, \ + reset: DC390_reset, \ + bios_param: DC390_bios_param, \ + can_queue: 42, \ + this_id: 7, \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: 16, \ + NEW_EH \ + unchecked_isa_dma: 0, \ + use_clustering: DISABLE_CLUSTERING \ + } +#else +extern struct proc_dir_entry DC390_proc_scsi_tmscsim; #define DC390_T { \ - proc_name: "tmscsim", \ + proc_dir: &DC390_proc_scsi_tmscsim, \ proc_info: DC390_proc_info, \ name: DC390_BANNER " V" DC390_VERSION, \ detect: DC390_detect, \ @@ -44,11 +80,15 @@ extern int DC390_proc_info(char *buffer, char **start, off_t offset, int length, abort: DC390_abort, \ reset: DC390_reset, \ bios_param: DC390_bios_param, \ - can_queue: 17, \ + can_queue: 42, \ this_id: 7, \ sg_tablesize: SG_ALL, \ - cmd_per_lun: 8, \ + cmd_per_lun: 16, \ + NEW_EH \ + unchecked_isa_dma: 0, \ use_clustering: DISABLE_CLUSTERING \ } +#endif +#endif /* defined(HOSTS_C) || defined(MODULE) */ #endif /* DC390_H */ diff --git a/drivers/scsi/eata_dma.c b/drivers/scsi/eata_dma.c index 9559c716c..3431655d2 100644 --- a/drivers/scsi/eata_dma.c +++ b/drivers/scsi/eata_dma.c @@ -676,7 +676,8 @@ int eata_abort(Scsi_Cmnd * cmd) int eata_reset(Scsi_Cmnd * cmd, unsigned int resetflags) { uint x; - ulong loop = loops_per_sec / 3; + /* 10 million PCI reads take at least one third of a second */ + ulong loop = 10 * 1000 * 1000; ulong flags; unchar success = FALSE; Scsi_Cmnd *sp; diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c dissimilarity index 65% index 46591840e..b97b90554 100644 --- a/drivers/scsi/ibmmca.c +++ b/drivers/scsi/ibmmca.c @@ -1,3299 +1,2574 @@ -/* - * Low Level Driver for the IBM Microchannel SCSI Subsystem - * - * Copyright (c) 1995 Strom Systems, Inc. under the terms of the GNU - * General Public License. Written by Martin Kolinek, December 1995. - * Further development by: Chris Beauregard, Klaus Kudielka, Michael Lang - * See the file README.ibmmca for a detailed description of this driver, - * the commandline arguments and the history of its development. - * See the WWW-page: http://www.uni-mainz.de/~langm000/linux.html for latest - * updates, info and ADF-files for adapters supported by this driver. - */ - -/******************* HEADER FILE INCLUDES ************************************/ -#ifndef LINUX_VERSION_CODE -#include -#endif - -/* choose adaption for Kernellevel */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,65) -#define OLDKERN -#else -#undef OLDKERN -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,17) -#include -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) -#include -#endif -#include -#include -#include "sd.h" -#include "scsi.h" -#include "hosts.h" -#include "ibmmca.h" - -#include /* for CONFIG_SCSI_IBMMCA etc. */ - -/******************* LOCAL DEFINES *******************************************/ - -/* milliseconds of delay for timing out reset. */ -#ifndef mdelay -#define mdelay(a) udelay((a) * 1000) -#endif - -/*--------------------------------------------------------------------*/ - -/* current version of this driver-source: */ -#define IBMMCA_SCSI_DRIVER_VERSION "3.2" - -/*--------------------------------------------------------------------*/ - -/* driver configuration */ -#define IM_MAX_HOSTS 8 /* maximum number of host adapters */ -#define IM_RESET_DELAY 60 /* seconds allowed for a reset */ - -/* driver debugging - #undef all for normal operation */ - -/* if defined: count interrupts and ignore this special one: */ -#undef IM_DEBUG_TIMEOUT 50 -#define TIMEOUT_PUN 0 -#define TIMEOUT_LUN 0 -/* verbose interrupt: */ -#undef IM_DEBUG_INT -/* verbose queuecommand: */ -#undef IM_DEBUG_CMD -/* verbose queucommand for specific SCSI-device type: */ -#undef IM_DEBUG_CMD_SPEC_DEV -/* verbose device probing */ -#define IM_DEBUG_PROBE - -/* device type that shall be displayed on syslog (only during debugging): */ -#define IM_DEBUG_CMD_DEVICE TYPE_TAPE - -/* relative addresses of hardware registers on a subsystem */ -#define IM_CMD_REG(hi) (hosts[(hi)]->io_port) /*Command Interface, (4 bytes long) */ -#define IM_ATTN_REG(hi) (hosts[(hi)]->io_port+4) /*Attention (1 byte) */ -#define IM_CTR_REG(hi) (hosts[(hi)]->io_port+5) /*Basic Control (1 byte) */ -#define IM_INTR_REG(hi) (hosts[(hi)]->io_port+6) /*Interrupt Status (1 byte, r/o) */ -#define IM_STAT_REG(hi) (hosts[(hi)]->io_port+7) /*Basic Status (1 byte, read only) */ - -/* basic I/O-port of first adapter */ -#define IM_IO_PORT 0x3540 -/* maximum number of hosts that can be found */ -#define IM_N_IO_PORT 8 - -/*requests going into the upper nibble of the Attention register */ -/*note: the lower nibble specifies the device(0-14), or subsystem(15) */ -#define IM_IMM_CMD 0x10 /*immediate command */ -#define IM_SCB 0x30 /*Subsystem Control Block command */ -#define IM_LONG_SCB 0x40 /*long Subsystem Control Block command */ -#define IM_EOI 0xe0 /*end-of-interrupt request */ - -/*values for bits 7,1,0 of Basic Control reg. (bits 6-2 reserved) */ -#define IM_HW_RESET 0x80 /*hardware reset */ -#define IM_ENABLE_DMA 0x02 /*enable subsystem's busmaster DMA */ -#define IM_ENABLE_INTR 0x01 /*enable interrupts to the system */ - -/*to interpret the upper nibble of Interrupt Status register */ -/*note: the lower nibble specifies the device(0-14), or subsystem(15) */ -#define IM_SCB_CMD_COMPLETED 0x10 -#define IM_SCB_CMD_COMPLETED_WITH_RETRIES 0x50 -#define IM_LOOP_SCATTER_BUFFER_FULL 0x60 -#define IM_ADAPTER_HW_FAILURE 0x70 -#define IM_IMMEDIATE_CMD_COMPLETED 0xa0 -#define IM_CMD_COMPLETED_WITH_FAILURE 0xc0 -#define IM_CMD_ERROR 0xe0 -#define IM_SOFTWARE_SEQUENCING_ERROR 0xf0 - -/*to interpret bits 3-0 of Basic Status register (bits 7-4 reserved) */ -#define IM_CMD_REG_FULL 0x08 -#define IM_CMD_REG_EMPTY 0x04 -#define IM_INTR_REQUEST 0x02 -#define IM_BUSY 0x01 - -/*immediate commands (word written into low 2 bytes of command reg) */ -#define IM_RESET_IMM_CMD 0x0400 -#define IM_FEATURE_CTR_IMM_CMD 0x040c -#define IM_DMA_PACING_IMM_CMD 0x040d -#define IM_ASSIGN_IMM_CMD 0x040e -#define IM_ABORT_IMM_CMD 0x040f -#define IM_FORMAT_PREP_IMM_CMD 0x0417 - -/*SCB (Subsystem Control Block) structure */ -struct im_scb - { - unsigned short command; /*command word (read, etc.) */ - unsigned short enable; /*enable word, modifies cmd */ - union - { - unsigned long log_blk_adr; /*block address on SCSI device */ - unsigned char scsi_cmd_length; /*6,10,12, for other scsi cmd */ - } - u1; - unsigned long sys_buf_adr; /*physical system memory adr */ - unsigned long sys_buf_length; /*size of sys mem buffer */ - unsigned long tsb_adr; /*Termination Status Block adr */ - unsigned long scb_chain_adr; /*optional SCB chain address */ - union - { - struct - { - unsigned short count; /*block count, on SCSI device */ - unsigned short length; /*block length, on SCSI device */ - } - blk; - unsigned char scsi_command[12]; /*other scsi command */ - } - u2; - }; - -/*structure scatter-gather element (for list of system memory areas) */ -struct im_sge - { - void *address; - unsigned long byte_length; - }; - -/*structure returned by a get_pos_info command: */ -struct im_pos_info - { - unsigned short pos_id; /* adapter id */ - unsigned char pos_3a; /* pos 3 (if pos 6 = 0) */ - unsigned char pos_2; /* pos 2 */ - unsigned char int_level; /* interrupt level IRQ 11 or 14 */ - unsigned char pos_4a; /* pos 4 (if pos 6 = 0) */ - unsigned short connector_size; /* MCA connector size: 16 or 32 Bit */ - unsigned char num_luns; /* number of supported luns per device */ - unsigned char num_puns; /* number of supported puns */ - unsigned char pacing_factor; /* pacing factor */ - unsigned char num_ldns; /* number of ldns available */ - unsigned char eoi_off; /* time EOI and interrupt inactive */ - unsigned char max_busy; /* time between reset and busy on */ - unsigned short cache_stat; /* ldn cachestat. Bit=1 = not cached */ - unsigned short retry_stat; /* retry status of ldns. Bit=1=disabled */ - unsigned char pos_4b; /* pos 4 (if pos 6 = 1) */ - unsigned char pos_3b; /* pos 3 (if pos 6 = 1) */ - unsigned char pos_6; /* pos 6 */ - unsigned char pos_5; /* pos 5 */ - unsigned short max_overlap; /* maximum overlapping requests */ - unsigned short num_bus; /* number of SCSI-busses */ - }; - -/*values for SCB command word */ -#define IM_NO_SYNCHRONOUS 0x0040 /*flag for any command */ -#define IM_NO_DISCONNECT 0x0080 /*flag for any command */ -#define IM_READ_DATA_CMD 0x1c01 -#define IM_WRITE_DATA_CMD 0x1c02 -#define IM_READ_VERIFY_CMD 0x1c03 -#define IM_WRITE_VERIFY_CMD 0x1c04 -#define IM_REQUEST_SENSE_CMD 0x1c08 -#define IM_READ_CAPACITY_CMD 0x1c09 -#define IM_DEVICE_INQUIRY_CMD 0x1c0b -#define IM_READ_LOGICAL_CMD 0x1c2a -#define IM_OTHER_SCSI_CMD_CMD 0x241f - -/* unused, but supported, SCB commands */ -#define IM_GET_COMMAND_COMPLETE_STATUS_CMD 0x1c07 /* command status */ -#define IM_GET_POS_INFO_CMD 0x1c0a /* returns neat stuff */ -#define IM_READ_PREFETCH_CMD 0x1c31 /* caching controller only */ -#define IM_FOMAT_UNIT_CMD 0x1c16 /* format unit */ -#define IM_REASSIGN_BLOCK_CMD 0x1c18 /* in case of error */ - -/*values to set bits in the enable word of SCB */ -#define IM_READ_CONTROL 0x8000 -#define IM_REPORT_TSB_ONLY_ON_ERROR 0x4000 -#define IM_RETRY_ENABLE 0x2000 -#define IM_POINTER_TO_LIST 0x1000 -#define IM_SUPRESS_EXCEPTION_SHORT 0x0400 -#define IM_BYPASS_BUFFER 0x0200 -#define IM_CHAIN_ON_NO_ERROR 0x0001 - -/*TSB (Termination Status Block) structure */ -struct im_tsb - { - unsigned short end_status; - unsigned short reserved1; - unsigned long residual_byte_count; - unsigned long sg_list_element_adr; - unsigned short status_length; - unsigned char dev_status; - unsigned char cmd_status; - unsigned char dev_error; - unsigned char cmd_error; - unsigned short reserved2; - unsigned short reserved3; - unsigned short low_of_last_scb_adr; - unsigned short high_of_last_scb_adr; - }; - -/*subsystem uses interrupt request level 14 */ -#define IM_IRQ 14 -/*SCSI-2 F/W may evade to interrupt 11 */ -#define IM_IRQ_FW 11 - -/*--------------------------------------------------------------------*/ -/* - The model 95 doesn't have a standard activity light. Instead it - has a row of alphanumerial LEDs on the front. We use the last one - as the activity indicator if we think we're on a model 95. I suspect - the model id check will be either too narrow or too general, and some - machines won't have an activity indicator. Oh well... - - The regular PS/2 disk led is turned on/off by bits 6,7 of system - control port. -*/ - -/* LED display-port (actually, last LED on display) */ -#define MOD95_LED_PORT 0x108 -/* system-control-register of PS/2s with diskindicator */ -#define PS2_SYS_CTR 0x92 -/* activity displaying methods */ -#define LED_DISP 1 -#define LED_ADISP 2 -#define LED_ACTIVITY 4 - -#define CMD_FAIL 255 - -/* The SCSI-ID(!) of the accessed SCSI-device is shown on PS/2-95 machines' LED - displays. ldn is no longer displayed here, because the ldn mapping is now - done dynamically and the ldn <-> pun,lun maps can be looked-up at boottime - or during uptime in /proc/scsi/ibmmca/ in case of trouble, - interest, debugging or just for having fun. The left number gives the - host-adapter number and the right shows the accessed SCSI-ID. */ - -/* display_mode is set by the ibmmcascsi= command line arg */ -static int display_mode = 0; -/* set default adapter timeout */ -static unsigned int adapter_timeout = 45; -/* for probing on feature-command: */ -static unsigned int global_command_error_excuse = 0; -/* global setting by command line for adapter_speed */ -static int global_adapter_speed = 0; /* full speed by default */ - -/* Panel / LED on, do it right for F/W addressin, too. adisplay will - * just ignore ids>7, as the panel has only 7 digits available */ -#define PS2_DISK_LED_ON(ad,id) {\ - if (display_mode & LED_DISP) { \ - if (id>9) \ - outw((ad+48)|((id+55)<<8), MOD95_LED_PORT ); \ - else \ - outw((ad+48)|((id+48)<<8), MOD95_LED_PORT ); } \ - else if (display_mode & LED_ADISP) { \ - if (id<7) outb((char)(id+48),MOD95_LED_PORT+1+id); \ - outb((char)(ad+48), MOD95_LED_PORT); } \ - if ((display_mode & LED_ACTIVITY)||(!display_mode)) \ - outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR); \ -} -/* Panel / LED off */ -/* bug fixed, Dec 15, 1997, where | was replaced by & here */ -#define PS2_DISK_LED_OFF() {\ - if (display_mode & LED_DISP) \ - outw(0x2020, MOD95_LED_PORT ); \ - else if (display_mode & LED_ADISP) { \ - outl(0x20202020,MOD95_LED_PORT); \ - outl(0x20202020,MOD95_LED_PORT+4); } \ - if ((display_mode & LED_ACTIVITY)||(!display_mode)) \ - outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); \ -} - -/*--------------------------------------------------------------------*/ - -/*list of supported subsystems */ -struct subsys_list_struct - { - unsigned short mca_id; - char *description; - }; - -/* types of different supported hardware that goes to hostdata special */ -#define IBM_SCSI2_FW 0 -#define IBM_7568_WCACHE 1 -#define IBM_EXP_UNIT 2 -#define IBM_SCSI_WCACHE 3 -#define IBM_SCSI 4 - -/* other special flags for hostdata structure */ -#define FORCED_DETECTION 100 -#define INTEGRATED_SCSI 101 - -/* List of possible IBM-SCSI-adapters */ -struct subsys_list_struct subsys_list[] = -{ - {0x8efc, "IBM SCSI-2 F/W Adapter"}, /* special = 0 */ - {0x8efd, "IBM 7568 Industrial Computer SCSI Adapter w/Cache"}, /* special = 1 */ - {0x8ef8, "IBM Expansion Unit SCSI Controller"},/* special = 2 */ - {0x8eff, "IBM SCSI Adapter w/Cache"}, /* special = 3 */ - {0x8efe, "IBM SCSI Adapter"}, /* special = 4 */ -}; - -/*for /proc filesystem, only valid in older kernel releases */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,27) -struct proc_dir_entry proc_scsi_ibmmca = -{ - PROC_SCSI_IBMMCA, 6, "ibmmca", - S_IFDIR | S_IRUGO | S_IXUGO, 2, - 0, 0, 0, NULL, NULL, NULL, NULL, - NULL, NULL, NULL -}; -#endif - -/* Max number of logical devices (can be up from 0 to 14). 15 is the address -of the adapter itself. */ -#define MAX_LOG_DEV 15 - -/*local data for a logical device */ -struct logical_device - { - struct im_scb scb; /* SCSI-subsystem-control-block structure */ - struct im_tsb tsb; /* SCSI command complete status block structure */ - struct im_sge sge[16]; /* scatter gather list structure */ - unsigned char buf[256]; /* SCSI command return data buffer */ - Scsi_Cmnd *cmd; /* SCSI-command that is currently in progress */ - int device_type; /* type of the SCSI-device. See include/scsi/scsi.h - for interpretation of the possible values */ - int block_length;/* blocksize of a particular logical SCSI-device */ - int cache_flag; /* 1 if this is uncached, 0 if cache is present for ldn */ - int retry_flag; /* 1 if adapter retry is disabled, 0 if enabled */ - }; - -/* statistics of the driver during operations (for proc_info) */ -struct Driver_Statistics - { - /* SCSI statistics on the adapter */ - int ldn_access[MAX_LOG_DEV+1]; /* total accesses on a ldn */ - int ldn_read_access[MAX_LOG_DEV+1]; /* total read-access on a ldn */ - int ldn_write_access[MAX_LOG_DEV+1]; /* total write-access on a ldn */ - int ldn_inquiry_access[MAX_LOG_DEV+1]; /* total inquiries on a ldn */ - int ldn_modeselect_access[MAX_LOG_DEV+1]; /* total mode selects on ldn */ - int scbs; /* short SCBs queued */ - int long_scbs; /* long SCBs queued */ - int total_accesses; /* total accesses on all ldns */ - int total_interrupts; /* total interrupts (should be - same as total_accesses) */ - int total_errors; /* command completed with error */ - /* dynamical assignment statistics */ - int total_scsi_devices; /* number of physical pun,lun */ - int dyn_flag; /* flag showing dynamical mode */ - int dynamical_assignments; /* number of remappings of ldns */ - int ldn_assignments[MAX_LOG_DEV+1]; /* number of remappings of each - ldn */ - }; - -/* data structure for each host adapter */ -struct ibmmca_hostdata -{ - /* array of logical devices: */ - struct logical_device _ld[MAX_LOG_DEV+1]; - /* array to convert (pun, lun) into logical device number: */ - unsigned char _get_ldn[16][8]; - /*array that contains the information about the physical SCSI-devices - attached to this host adapter: */ - unsigned char _get_scsi[16][8]; - /* used only when checking logical devices: */ - int _local_checking_phase_flag; - /* report received interrupt: */ - int _got_interrupt; - /* report termination-status of SCSI-command: */ - int _stat_result; - /* reset status (used only when doing reset): */ - int _reset_status; - /* code of the last SCSI command (needed for panic info): */ - int _last_scsi_command[MAX_LOG_DEV+1]; - /* identifier of the last SCSI-command type */ - int _last_scsi_type[MAX_LOG_DEV+1]; - /* last blockcount */ - int _last_scsi_blockcount[MAX_LOG_DEV+1]; - /* last locgical block address */ - unsigned long _last_scsi_logical_block[MAX_LOG_DEV+1]; - /* Counter that points on the next reassignable ldn for dynamical - remapping. The default value is 7, that is the first reassignable - number in the list at boottime: */ - int _next_ldn; - /* Statistics-structure for this IBM-SCSI-host: */ - struct Driver_Statistics _IBM_DS; - /* This hostadapters pos-registers pos2 until pos6 */ - unsigned _pos2, _pos3, _pos4, _pos5, _pos6; - /* assign a special variable, that contains dedicated info about the - adaptertype */ - int _special; - /* connector size on the MCA bus */ - int _connector_size; - /* synchronous SCSI transfer rate bitpattern */ - int _adapter_speed; -}; - -/* macros to access host data structure */ -#define subsystem_pun(hi) (hosts[(hi)]->this_id) -#define subsystem_maxid(hi) (hosts[(hi)]->max_id) -#define ld(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_ld) -#define get_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_ldn) -#define get_scsi(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_scsi) -#define local_checking_phase_flag(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_local_checking_phase_flag) -#define got_interrupt(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_got_interrupt) -#define stat_result(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_stat_result) -#define reset_status(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_reset_status) -#define last_scsi_command(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_command) -#define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type) -#define last_scsi_blockcount(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_blockcount) -#define last_scsi_logical_block(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_logical_block) -#define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type) -#define next_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_next_ldn) -#define IBM_DS(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_IBM_DS) -#define special(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_special) -#define subsystem_connector_size(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_connector_size) -#define adapter_speed(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_adapter_speed) -#define pos2(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos2) -#define pos3(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos3) -#define pos4(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos4) -#define pos5(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos5) -#define pos6(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos6) - -/* Define a arbitrary number as subsystem-marker-type. This number is, as - described in the ANSI-SCSI-standard, not occupied by other device-types. */ -#define TYPE_IBM_SCSI_ADAPTER 0x2F - -/* Define 0xFF for no device type, because this type is not defined within - the ANSI-SCSI-standard, therefore, it can be used and should not cause any - harm. */ -#define TYPE_NO_DEVICE 0xFF - -/* define medium-changer. If this is not defined previously, e.g. Linux - 2.0.x, define this type here. */ -#ifndef TYPE_MEDIUM_CHANGER -#define TYPE_MEDIUM_CHANGER 0x08 -#endif - -/* define possible operations for the immediate_assign command */ -#define SET_LDN 0 -#define REMOVE_LDN 1 - -/* ldn which is used to probe the SCSI devices */ -#define PROBE_LDN 0 - -/* reset status flag contents */ -#define IM_RESET_NOT_IN_PROGRESS 0 -#define IM_RESET_IN_PROGRESS 1 -#define IM_RESET_FINISHED_OK 2 -#define IM_RESET_FINISHED_FAIL 3 -#define IM_RESET_NOT_IN_PROGRESS_NO_INT 4 -#define IM_RESET_FINISHED_OK_NO_INT 5 - -/* define undefined SCSI-command */ -#define NO_SCSI 0xffff - -/*-----------------------------------------------------------------------*/ - -/* if this is nonzero, ibmmcascsi option has been passed to the kernel */ -static int io_port[IM_MAX_HOSTS] = { 0, 0, 0, 0, 0, 0, 0, 0 }; -static int scsi_id[IM_MAX_HOSTS] = { 7, 7, 7, 7, 7, 7, 7, 7 }; - -/* fill module-parameters only, when this define is present. - (that is kernel version 2.1.x) */ -#if defined(MODULE) -static char *boot_options = NULL; -#include -MODULE_PARM(boot_options, "s"); -MODULE_PARM(io_port, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i"); -MODULE_PARM(scsi_id, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i"); -MODULE_PARM(display, "1i"); -MODULE_PARM(adisplay, "1i"); -MODULE_PARM(bypass, "1i"); -MODULE_PARM(normal, "1i"); -MODULE_PARM(ansi, "1i"); -#endif - -/*counter of concurrent disk read/writes, to turn on/off disk led */ -static int disk_rw_in_progress = 0; - -/* spinlock handling to avoid command clash while in operation */ -#ifndef OLDKERN -spinlock_t info_lock = SPIN_LOCK_UNLOCKED; -spinlock_t proc_lock = SPIN_LOCK_UNLOCKED; -spinlock_t abort_lock = SPIN_LOCK_UNLOCKED; -spinlock_t reset_lock = SPIN_LOCK_UNLOCKED; -spinlock_t issue_lock = SPIN_LOCK_UNLOCKED; -spinlock_t intr_lock = SPIN_LOCK_UNLOCKED; -#endif - -/* host information */ -static int found = 0; -static struct Scsi_Host *hosts[IM_MAX_HOSTS+1] = { NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL }; -static unsigned int pos[8]; /* whole pos register-line for diagnosis */ -/* Taking into account the additions, made by ZP Gu. - * This selects now the preset value from the configfile and - * offers the 'normal' commandline option to be accepted */ -#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD -static char ibm_ansi_order = 1; -#else -static char ibm_ansi_order = 0; -#endif - -/*-----------------------------------------------------------------------*/ - -/******************* FUNCTIONS IN FORWARD DECLARATION ************************/ - -static void interrupt_handler (int, void *, struct pt_regs *); -#ifndef OLDKERN -static void do_interrupt_handler (int, void *, struct pt_regs *); -#endif -static void issue_cmd (int, unsigned long, unsigned char); -static void internal_done (Scsi_Cmnd * cmd); -static void check_devices (int, int); -static int immediate_assign(int, unsigned int, unsigned int, unsigned int, - unsigned int); -static int immediate_feature(int, unsigned int, unsigned int); -#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET -static int immediate_reset(int, unsigned int); -#endif -static int device_inquiry(int, int); -static int read_capacity(int, int); -static int get_pos_info(int); -static char *ti_p(int); -static char *ti_l(int); -static char *ibmrate(unsigned int, int); -static int probe_display(int); -static int probe_bus_mode(int); -static int device_exists (int, int, int *, int *); -static struct Scsi_Host *ibmmca_register(Scsi_Host_Template *, - int, int, int, char *); -/* local functions needed for proc_info */ -static int ldn_access_load(int, int); -static int ldn_access_total_read_write(int); - -static int bypass_controller = 0; /* bypass integrated SCSI-cmd set flag */ - -/*--------------------------------------------------------------------*/ - -/******************* LOCAL FUNCTIONS IMPLEMENTATION *************************/ - -#ifndef OLDKERN -/* newer Kernels need the spinlock interrupt handler */ -static void do_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned long flags; - - spin_lock_irqsave(&io_request_lock, flags); - interrupt_handler(irq, dev_id, regs); - spin_unlock_irqrestore(&io_request_lock, flags); - return; -} -#endif - -static void interrupt_handler (int irq, void *dev_id, struct pt_regs *regs) -{ - int host_index; - unsigned int intr_reg; - unsigned int cmd_result; - unsigned int ldn; - unsigned long flags; - Scsi_Cmnd *cmd; - int lastSCSI; - - host_index = 0; /* make sure, host_index is 0 */ - - /* search for one adapter-response on shared interrupt */ - while (hosts[host_index] - && !(inb(IM_STAT_REG(host_index)) & IM_INTR_REQUEST)) - host_index++; - - /* return if some other device on this IRQ caused the interrupt */ - if (!hosts[host_index]) return; - - /* the reset-function already did all the job, even ints got - renabled on the subsystem, so just return */ - if ((reset_status(host_index) == IM_RESET_NOT_IN_PROGRESS_NO_INT)|| - (reset_status(host_index) == IM_RESET_FINISHED_OK_NO_INT)) - { - reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS; - return; - } - - /*must wait for attention reg not busy, then send EOI to subsystem */ - while (1) - { -#ifdef OLDKERN - save_flags(flags); - cli(); -#else - spin_lock_irqsave(&intr_lock, flags); -#endif - /* if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY)) */ - if ((inb(IM_STAT_REG(host_index)) & 0xf) == (IM_CMD_REG_EMPTY | IM_INTR_REQUEST)) - break; -#ifdef OLDKERN - restore_flags(flags); -#else - spin_unlock_irqrestore(&intr_lock, flags); -#endif - } - /*get command result and logical device */ - intr_reg = (unsigned char)(inb (IM_INTR_REG(host_index))); - cmd_result = intr_reg & 0xf0; - ldn = intr_reg & 0x0f; - - /* get the last_scsi_command here */ - lastSCSI = last_scsi_command(host_index)[ldn]; - - /*these should never happen (hw fails, or a local programming bug) */ - if (!global_command_error_excuse) - { - switch (cmd_result) - { /* Prevent from Ooopsing on error to show the real reason */ - case IM_ADAPTER_HW_FAILURE: - case IM_SOFTWARE_SEQUENCING_ERROR: - case IM_CMD_ERROR: - printk("\nIBM MCA SCSI: Fatal Subsystem ERROR!\n"); - printk(" Last cmd=0x%x, ena=%x, len=",lastSCSI, - ld(host_index)[ldn].scb.enable); - if (ld(host_index)[ldn].cmd) - printk("%ld/%ld",(long)(ld(host_index)[ldn].cmd->request_bufflen), - (long)(ld(host_index)[ldn].scb.sys_buf_length)); - else - printk("none"); - printk(", "); - if (ld(host_index)[ldn].cmd) - printk("Blocksize=%d",ld(host_index)[ldn].scb.u2.blk.length); - else - printk("Blocksize=none"); - printk(", host=0x%x, ldn=0x%x\n",host_index, ldn); - if (ld(host_index)[ldn].cmd) - { - printk("Blockcount=%d/%d\n",last_scsi_blockcount(host_index)[ldn], - ld(host_index)[ldn].scb.u2.blk.count); - printk("Logical block=%lx/%lx\n",last_scsi_logical_block(host_index)[ldn], - ld(host_index)[ldn].scb.u1.log_blk_adr); - } - printk("Reason given: %s\n", - (cmd_result==IM_ADAPTER_HW_FAILURE) ? "HARDWARE FAILURE" : - (cmd_result==IM_SOFTWARE_SEQUENCING_ERROR) ? "SOFTWARE SEQUENCING ERROR" : - (cmd_result==IM_CMD_ERROR) ? "COMMAND ERROR" : "UNKNOWN"); - /* if errors appear, enter this section to give detailed info */ - printk("IBM MCA SCSI: Subsystem Error-Status follows:\n"); - printk(" Command Type................: %x\n", - last_scsi_type(host_index)[ldn]); - printk(" Attention Register..........: %x\n", - inb (IM_ATTN_REG(host_index))); - printk(" Basic Control Register......: %x\n", - inb (IM_CTR_REG(host_index))); - printk(" Interrupt Status Register...: %x\n", - intr_reg); - printk(" Basic Status Register.......: %x\n", - inb (IM_STAT_REG(host_index))); - if ((last_scsi_type(host_index)[ldn]==IM_SCB)|| - (last_scsi_type(host_index)[ldn]==IM_LONG_SCB)) - { - printk(" SCB-Command.................: %x\n", - ld(host_index)[ldn].scb.command); - printk(" SCB-Enable..................: %x\n", - ld(host_index)[ldn].scb.enable); - printk(" SCB-logical block address...: %lx\n", - ld(host_index)[ldn].scb.u1.log_blk_adr); - printk(" SCB-system buffer address...: %lx\n", - ld(host_index)[ldn].scb.sys_buf_adr); - printk(" SCB-system buffer length....: %lx\n", - ld(host_index)[ldn].scb.sys_buf_length); - printk(" SCB-tsb address.............: %lx\n", - ld(host_index)[ldn].scb.tsb_adr); - printk(" SCB-Chain address...........: %lx\n", - ld(host_index)[ldn].scb.scb_chain_adr); - printk(" SCB-block count.............: %x\n", - ld(host_index)[ldn].scb.u2.blk.count); - printk(" SCB-block length............: %x\n", - ld(host_index)[ldn].scb.u2.blk.length); - } - printk(" Send this report to the maintainer.\n"); - panic("IBM MCA SCSI: Fatal errormessage from the subsystem (0x%X,0x%X)!\n", - lastSCSI,cmd_result); - break; - } - } - else - { /* The command error handling is made silent, but we tell the - * calling function, that there is a reported error from the - * adapter. */ - switch (cmd_result) - { - case IM_ADAPTER_HW_FAILURE: - case IM_SOFTWARE_SEQUENCING_ERROR: - case IM_CMD_ERROR: - global_command_error_excuse = CMD_FAIL; - break; - default: - global_command_error_excuse = 0; - break; - } - } - - /* if no panic appeared, increase the interrupt-counter */ - IBM_DS(host_index).total_interrupts++; - - /*only for local checking phase */ - if (local_checking_phase_flag(host_index)) - { - stat_result(host_index) = cmd_result; - got_interrupt(host_index) = 1; - reset_status(host_index) = IM_RESET_FINISHED_OK; - last_scsi_command(host_index)[ldn] = NO_SCSI; - - outb (IM_EOI | ldn, IM_ATTN_REG(host_index)); -#ifdef OLDKERN - restore_flags(flags); -#else - spin_unlock_irqrestore(&intr_lock, flags); -#endif - return; - } - /*handling of commands coming from upper level of scsi driver */ - else - { - if (last_scsi_type(host_index)[ldn] == IM_IMM_CMD) - { - /*verify ldn, and may handle rare reset immediate command */ - if ((reset_status(host_index) == IM_RESET_IN_PROGRESS)&& - (last_scsi_command(host_index)[ldn] == IM_RESET_IMM_CMD)) - { - if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) - { - disk_rw_in_progress = 0; - PS2_DISK_LED_OFF (); - reset_status(host_index) = IM_RESET_FINISHED_FAIL; - } - else - { - /*reset disk led counter, turn off disk led */ - disk_rw_in_progress = 0; - PS2_DISK_LED_OFF (); - reset_status(host_index) = IM_RESET_FINISHED_OK; - } - stat_result(host_index) = cmd_result; - last_scsi_command(host_index)[ldn] = NO_SCSI; - last_scsi_type(host_index)[ldn] = 0; - outb (IM_EOI | ldn, IM_ATTN_REG(host_index)); -#ifdef OLDKERN - restore_flags(flags); -#else - spin_unlock_irqrestore(&intr_lock, flags); -#endif - return; - } - else if (last_scsi_command(host_index)[ldn] == IM_ABORT_IMM_CMD) - { /* react on SCSI abort command */ -#ifdef IM_DEBUG_PROBE - printk("IBM MCA SCSI: Interrupt from SCSI-abort.\n"); -#endif - disk_rw_in_progress = 0; - PS2_DISK_LED_OFF(); - cmd = ld(host_index)[ldn].cmd; - ld(host_index)[ldn].cmd = NULL; - if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) - cmd->result = DID_NO_CONNECT << 16; - else - cmd->result = DID_ABORT << 16; - stat_result(host_index) = cmd_result; - last_scsi_command(host_index)[ldn] = NO_SCSI; - last_scsi_type(host_index)[ldn] = 0; - outb (IM_EOI | ldn, IM_ATTN_REG(host_index)); -#ifdef OLDKERN - restore_flags(flags); -#else - spin_unlock_irqrestore(&intr_lock, flags); -#endif - if (cmd->scsi_done) - (cmd->scsi_done)(cmd); /* should be the internal_done */ - return; - } - else - { - disk_rw_in_progress = 0; - PS2_DISK_LED_OFF (); - reset_status(host_index) = IM_RESET_FINISHED_OK; - stat_result(host_index) = cmd_result; - last_scsi_command(host_index)[ldn] = NO_SCSI; - - outb (IM_EOI | ldn, IM_ATTN_REG(host_index)); -#ifdef OLDKERN - restore_flags(flags); -#else - spin_unlock_irqrestore(&intr_lock, flags); -#endif - return; - } - } - last_scsi_command(host_index)[ldn] = NO_SCSI; - last_scsi_type(host_index)[ldn] = 0; - cmd = ld(host_index)[ldn].cmd; - ld(host_index)[ldn].cmd = NULL; -#ifdef IM_DEBUG_TIMEOUT - if (cmd) - { - if ((cmd->target == TIMEOUT_PUN)&& - (cmd->lun == TIMEOUT_LUN)) - { - printk("IBM MCA SCSI: Ignoring interrupt from pun=%x, lun=%x.\n", - cmd->target, cmd->lun); - outb (IM_EOI | ldn, IM_ATTN_REG(host_index)); -#ifdef OLDKERN - restore_flags(flags); -#else - spin_unlock_irqrestore(&intr_lock, flags); -#endif - return; - } - } -#endif - /*if no command structure, just return, else clear cmd */ - if (!cmd) - { - outb (IM_EOI | ldn, IM_ATTN_REG(host_index)); -#ifdef OLDKERN - restore_flags(flags); -#else - spin_unlock_irqrestore(&intr_lock, flags); -#endif - return; - } - -#ifdef IM_DEBUG_INT - printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n", - cmd->cmnd[0], intr_reg, - ld(host_index)[ldn].tsb.dev_status, - ld(host_index)[ldn].tsb.cmd_status, - ld(host_index)[ldn].tsb.dev_error, - ld(host_index)[ldn].tsb.cmd_error); -#endif - - /*if this is end of media read/write, may turn off PS/2 disk led */ - if ((ld(host_index)[ldn].device_type!=TYPE_NO_LUN)&& - (ld(host_index)[ldn].device_type!=TYPE_NO_DEVICE)) - { /* only access this, if there was a valid device addressed */ - switch (cmd->cmnd[0]) - { - case READ_6: - case WRITE_6: - case READ_10: - case WRITE_10: - case READ_12: - case WRITE_12: - if (--disk_rw_in_progress == 0) - PS2_DISK_LED_OFF (); - } - } - - /* IBM describes the status-mask to be 0x1e, but this is not conform - * with SCSI-defintion, I suppose, the reason for it is that IBM - * adapters do not support CMD_TERMINATED, TASK_SET_FULL and - * ACA_ACTIVE as returning statusbyte information. (ML) */ - if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) - { - cmd->result = (unsigned char)(ld(host_index)[ldn].tsb.dev_status & 0x1e); - IBM_DS(host_index).total_errors++; - } - else - cmd->result = 0; - /* write device status into cmd->result, and call done function */ - if (lastSCSI == NO_SCSI) /* unexpected interrupt :-( */ - cmd->result |= DID_BAD_INTR << 16; - else /* things went right :-) */ - cmd->result |= DID_OK << 16; - outb (IM_EOI | ldn, IM_ATTN_REG(host_index)); -#ifdef OLDKERN - restore_flags(flags); -#else - spin_unlock_irqrestore(&intr_lock, flags); -#endif - /* This is for Kernel 2.2.x. Something weired happens here. - * Between the command got queued and the interrupt is released, - * the flags sometimes contain different values, which must - * be a strange thing. E.g. it appears when cold-booting with a - * tape drive at id0. */ - cmd->flags &= 0x3f; - if (cmd->scsi_done) - (cmd->scsi_done)(cmd); - } - if (lastSCSI == NO_SCSI) - printk("IBM MCA SCSI: WARNING - Interrupt from non-pending SCSI-command!\n"); - return; -} - -/*--------------------------------------------------------------------*/ - -static void issue_cmd (int host_index, unsigned long cmd_reg, - unsigned char attn_reg) -{ - static unsigned long flags; - /* must wait for attention reg not busy */ - while (1) - { -#ifdef OLDKERN - save_flags(flags); - cli(); -#else - spin_lock_irqsave(&issue_lock, flags); -#endif - if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY)) - break; -#ifdef OLDKERN - restore_flags(flags); -#else - spin_unlock_irqrestore(&issue_lock, flags); -#endif - } - /*write registers and enable system interrupts */ - outl (cmd_reg, IM_CMD_REG(host_index)); - outb (attn_reg, IM_ATTN_REG(host_index)); -#ifdef OLDKERN - restore_flags(flags); -#else - spin_unlock_irqrestore(&issue_lock, flags); -#endif - return; -} - -/*--------------------------------------------------------------------*/ - -static void internal_done (Scsi_Cmnd * cmd) -{ - cmd->SCp.Status++; - return; -} - -/*--------------------------------------------------------------------*/ - -/* SCSI-SCB-command for device_inquiry */ -static int device_inquiry(int host_index, int ldn) -{ - int retries; - Scsi_Cmnd cmd; - struct im_scb *scb; - struct im_tsb *tsb; - unsigned char *buf; - - scb = &(ld(host_index)[ldn].scb); - tsb = &(ld(host_index)[ldn].tsb); - buf = (unsigned char *)(&(ld(host_index)[ldn].buf)); - ld(host_index)[ldn].tsb.dev_status = 0; /* prepare stusblock */ - - if (bypass_controller) - { /* fill the commonly known field for device-inquiry SCSI cmnd */ - cmd.cmd_len = 6; - memset (&(cmd.cmnd), 0x0, sizeof(char) * cmd.cmd_len); - cmd.cmnd[0] = INQUIRY; /* device inquiry */ - cmd.cmnd[4] = 0xff; /* return buffer size = 255 */ - } - for (retries = 0; retries < 3; retries++) - { - if (bypass_controller) - { /* bypass the hardware integrated command set */ - scb->command = IM_OTHER_SCSI_CMD_CMD | IM_NO_DISCONNECT; - scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; - scb->u1.scsi_cmd_length = cmd.cmd_len; - memcpy (scb->u2.scsi_command, &(cmd.cmnd), cmd.cmd_len); - last_scsi_command(host_index)[ldn] = INQUIRY; - last_scsi_type(host_index)[ldn] = IM_LONG_SCB; - } - else - { - /*fill scb with inquiry command */ - scb->command = IM_DEVICE_INQUIRY_CMD | IM_NO_DISCONNECT; - scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT; - last_scsi_command(host_index)[ldn] = IM_DEVICE_INQUIRY_CMD; - last_scsi_type(host_index)[ldn] = IM_SCB; - } - scb->sys_buf_adr = virt_to_bus(buf); - scb->sys_buf_length = 0xff; /* maximum bufferlength gives max info */ - scb->tsb_adr = virt_to_bus(tsb); - - /*issue scb to passed ldn, and busy wait for interrupt */ - got_interrupt(host_index) = 0; - if ((scb->command & IM_OTHER_SCSI_CMD_CMD) == IM_OTHER_SCSI_CMD_CMD) - issue_cmd (host_index, virt_to_bus(scb), IM_LONG_SCB | ldn); - else - issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn); - while (!got_interrupt(host_index)) - barrier (); - - /*if command succesful, break */ - if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)|| - (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES)) - return 1; - } - - /*if all three retries failed, return "no device at this ldn" */ - if (retries >= 3) - return 0; - else - return 1; -} - -static int read_capacity(int host_index, int ldn) -{ - int retries; - Scsi_Cmnd cmd; - struct im_scb *scb; - struct im_tsb *tsb; - unsigned char *buf; - - scb = &(ld(host_index)[ldn].scb); - tsb = &(ld(host_index)[ldn].tsb); - buf = (unsigned char *)(&(ld(host_index)[ldn].buf)); - ld(host_index)[ldn].tsb.dev_status = 0; - - if (bypass_controller) - { /* read capacity in commonly known default SCSI-format */ - cmd.cmd_len = 10; - memset (&(cmd.cmnd), 0x0, sizeof(char) * cmd.cmd_len); - cmd.cmnd[0] = READ_CAPACITY; /* read capacity */ - } - for (retries = 0; retries < 3; retries++) - { - /*fill scb with read capacity command */ - if (bypass_controller) - { /* bypass the SCSI-command */ - scb->command = IM_OTHER_SCSI_CMD_CMD; - scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; - scb->u1.scsi_cmd_length = cmd.cmd_len; - memcpy (scb->u2.scsi_command, &(cmd.cmnd), cmd.cmd_len); - last_scsi_command(host_index)[ldn] = READ_CAPACITY; - last_scsi_type(host_index)[ldn] = IM_SCB; - } - else - { - scb->command = IM_READ_CAPACITY_CMD; - scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT; - last_scsi_command(host_index)[ldn] = IM_READ_CAPACITY_CMD; - last_scsi_type(host_index)[ldn] = IM_SCB; - } - scb->sys_buf_adr = virt_to_bus(buf); - scb->sys_buf_length = 8; - scb->tsb_adr = virt_to_bus(tsb); - - /*issue scb to passed ldn, and busy wait for interrupt */ - got_interrupt(host_index) = 0; - if ((scb->command & IM_OTHER_SCSI_CMD_CMD) == IM_OTHER_SCSI_CMD_CMD) - issue_cmd (host_index, virt_to_bus(scb), IM_LONG_SCB | ldn); - else - issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn); - while (!got_interrupt(host_index)) - barrier (); - - /*if got capacity, get block length and return one device found */ - if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)|| - (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES)) - return 1; - } - /*if all three retries failed, return "no device at this ldn" */ - if (retries >= 3) - return 0; - else - return 1; -} - -static int get_pos_info(int host_index) -{ - int retries; - struct im_scb *scb; - struct im_tsb *tsb; - unsigned char *buf; - - scb = &(ld(host_index)[MAX_LOG_DEV].scb); - tsb = &(ld(host_index)[MAX_LOG_DEV].tsb); - buf = (unsigned char *)(&(ld(host_index)[MAX_LOG_DEV].buf)); - ld(host_index)[MAX_LOG_DEV].tsb.dev_status = 0; - - for (retries = 0; retries < 3; retries++) - { - /*fill scb with get_pos_info command */ - scb->command = IM_GET_POS_INFO_CMD; - scb->enable = IM_READ_CONTROL | IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE | IM_BYPASS_BUFFER | IM_SUPRESS_EXCEPTION_SHORT; - last_scsi_command(host_index)[MAX_LOG_DEV] = IM_GET_POS_INFO_CMD; - last_scsi_type(host_index)[MAX_LOG_DEV] = IM_SCB; - - scb->sys_buf_adr = virt_to_bus(buf); - if (special(host_index)==IBM_SCSI2_FW) - scb->sys_buf_length = 256; /* get all info from F/W adapter */ - else - scb->sys_buf_length = 18; /* get exactly 18 bytes for other SCSI */ - - scb->tsb_adr = virt_to_bus(tsb); - - /*issue scb to ldn=15, and busy wait for interrupt */ - got_interrupt(host_index) = 0; - issue_cmd (host_index, virt_to_bus(scb), IM_SCB | MAX_LOG_DEV); - while (!got_interrupt(host_index)) - barrier (); - - /*if got POS-stuff, get block length and return one device found */ - if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)|| - (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES)) - return 1; - } - /* if all three retries failed, return "no device at this ldn" */ - if (retries >= 3) - return 0; - else - return 1; -} - -/* SCSI-immediate-command for assign. This functions maps/unmaps specific - ldn-numbers on SCSI (PUN,LUN). It is needed for presetting of the - subsystem and for dynamical remapping od ldns. */ -static int immediate_assign(int host_index, unsigned int pun, - unsigned int lun, unsigned int ldn, - unsigned int operation) -{ - int retries; - unsigned long imm_command; - - for (retries=0; retries<3; retries ++) - { - /* select mutation level of the SCSI-adapter */ - switch (special(host_index)) - { - case IBM_SCSI2_FW: - imm_command = (unsigned long)(IM_ASSIGN_IMM_CMD); - imm_command |= (unsigned long)((lun & 7) << 24); - imm_command |= (unsigned long)((operation & 1) << 23); - imm_command |= (unsigned long)((pun & 7)<< 20)|((pun & 8)<< 24); - imm_command |= (unsigned long)((ldn & 15) << 16); - break; - default: - imm_command = inl(IM_CMD_REG(host_index)); - imm_command &= (unsigned long)(0xF8000000); /* keep reserved bits */ - imm_command |= (unsigned long)(IM_ASSIGN_IMM_CMD); - imm_command |= (unsigned long)((lun & 7) << 24); - imm_command |= (unsigned long)((operation & 1) << 23); - imm_command |= (unsigned long)((pun & 7) << 20); - imm_command |= (unsigned long)((ldn & 15) << 16); - break; - } - last_scsi_command(host_index)[MAX_LOG_DEV] = IM_ASSIGN_IMM_CMD; - last_scsi_type(host_index)[MAX_LOG_DEV] = IM_IMM_CMD; - got_interrupt(host_index) = 0; - issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | MAX_LOG_DEV); - while (!got_interrupt(host_index)) - barrier (); - - /*if command succesful, break */ - if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED) - return 1; - } - if (retries >= 3) - return 0; - else - return 1; -} - -static int immediate_feature(int host_index, unsigned int speed, - unsigned int timeout) -{ - int retries; - unsigned long imm_command; - - for (retries=0; retries<3; retries ++) - { - /* select mutation level of the SCSI-adapter */ - switch (special(host_index)) - { - default: - imm_command = IM_FEATURE_CTR_IMM_CMD; - imm_command |= (unsigned long)((speed & 0x7) << 29); - imm_command |= (unsigned long)((timeout & 0x1fff) << 16); - break; - } - last_scsi_command(host_index)[MAX_LOG_DEV] = IM_FEATURE_CTR_IMM_CMD; - last_scsi_type(host_index)[MAX_LOG_DEV] = IM_IMM_CMD; - got_interrupt(host_index) = 0; - /* we need to run into command errors in order to probe for the - * right speed! */ - global_command_error_excuse = 1; - issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | MAX_LOG_DEV); - while (!got_interrupt(host_index)) - barrier (); - if (global_command_error_excuse == CMD_FAIL) - { - global_command_error_excuse = 0; - return 2; - } - else - global_command_error_excuse = 0; - - /*if command succesful, break */ - if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED) - return 1; - } - - if (retries >= 3) - return 0; - else - return 1; -} - -#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET -static int immediate_reset(int host_index, unsigned int ldn) -{ - int retries; - int ticks; - unsigned long imm_command; - - for (retries=0; retries<3; retries ++) - { - imm_command = inl(IM_CMD_REG(host_index)); - imm_command &= (unsigned long)(0xFFFF0000); /* keep reserved bits */ - imm_command |= (unsigned long)(IM_RESET_IMM_CMD); - last_scsi_command(host_index)[ldn] = IM_RESET_IMM_CMD; - last_scsi_type(host_index)[ldn] = IM_IMM_CMD; - - got_interrupt(host_index) = 0; - reset_status(host_index) = IM_RESET_IN_PROGRESS; - issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | ldn); - ticks = IM_RESET_DELAY*HZ; - while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks) - { - mdelay(1+999/HZ); - barrier(); - } - /* if reset did not complete, just claim */ - if (!ticks) - { - printk("IBM MCA SCSI: reset did not complete within %d seconds.\n", - IM_RESET_DELAY); - reset_status(host_index) = IM_RESET_FINISHED_OK; - /* did not work, finish */ - return 1; - } - /*if command succesful, break */ - if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED) - return 1; - } - - if (retries >= 3) - return 0; - else - return 1; -} -#endif - -/* type-interpreter for physical device numbers */ -static char *ti_p(int value) -{ - switch (value) - { - case TYPE_IBM_SCSI_ADAPTER: return("A"); break; - case TYPE_DISK: return("D"); break; - case TYPE_TAPE: return("T"); break; - case TYPE_PROCESSOR: return("P"); break; - case TYPE_WORM: return("W"); break; - case TYPE_ROM: return("R"); break; - case TYPE_SCANNER: return("S"); break; - case TYPE_MOD: return("M"); break; - case TYPE_MEDIUM_CHANGER: return("C"); break; - case TYPE_NO_LUN: return("+"); break; /* show NO_LUN */ - case TYPE_NO_DEVICE: - default: return("-"); break; - } - return("-"); -} - -/* interpreter for logical device numbers (ldn) */ -static char *ti_l(int value) -{ - const char hex[16] = "0123456789abcdef"; - static char answer[2]; - - answer[1] = (char)(0x0); - if (value<=MAX_LOG_DEV) - answer[0] = hex[value]; - else - answer[0] = '-'; - - return (char *)&answer; -} - -/* transfers bitpattern of the feature command to values in MHz */ -static char *ibmrate(unsigned int speed, int adaptertype) -{ - int i; - i=adaptertype; - switch (speed) - { - case 0: if (i) return "5.00"; else return "10.00"; break; - case 1: if (i) return "4.00"; else return "8.00"; break; - case 2: if (i) return "3.33"; else return "6.66"; break; - case 3: if (i) return "2.86"; else return "5.00"; break; - case 4: if (i) return "2.50"; else return "4.00"; break; - case 5: if (i) return "2.22"; else return "3.10"; break; - case 6: if (i) return "2.00"; else return "2.50"; break; - case 7: if (i) return "1.82"; else return "2.00"; break; - } - return "---"; -} - -static int probe_display(int what) -{ - static int rotator = 0; - const char rotor[] = "|/-\\"; - - if (!(display_mode & LED_DISP)) - return 0; - if (!what) - { - outl(0x20202020,MOD95_LED_PORT); - outl(0x20202020,MOD95_LED_PORT+4); - } - else - { - outb('S',MOD95_LED_PORT+7); - outb('C',MOD95_LED_PORT+6); - outb('S',MOD95_LED_PORT+5); - outb('I',MOD95_LED_PORT+4); - outb('i',MOD95_LED_PORT+3); - outb('n',MOD95_LED_PORT+2); - outb('i',MOD95_LED_PORT+1); - outb((char)(rotor[rotator]),MOD95_LED_PORT); - rotator++; - if (rotator>3) - rotator=0; - } - return 0; -} - -static int probe_bus_mode(int host_index) -{ - struct im_pos_info *info; - int num_bus = 0; - int ldn; - - info = (struct im_pos_info *)(&(ld(host_index)[MAX_LOG_DEV].buf)); - - if (get_pos_info(host_index)) - { - if (info->connector_size & 0xf000) - subsystem_connector_size(host_index)=16; - else - subsystem_connector_size(host_index)=32; - num_bus |= (info->pos_4b & 8) >> 3; - for (ldn=0; ldn<=MAX_LOG_DEV; ldn++) - { - if ((special(host_index)==IBM_SCSI_WCACHE)|| - (special(host_index)==IBM_7568_WCACHE)) - { - if (!((info->cache_stat >> ldn) & 1)) - ld(host_index)[ldn].cache_flag = 0; - } - if (!((info->retry_stat >> ldn) & 1)) - ld(host_index)[ldn].retry_flag = 0; - } -#ifdef IM_DEBUG_PROBE - printk("IBM MCA SCSI: SCSI-Cache bits: "); - for (ldn=0; ldn<=MAX_LOG_DEV; ldn++) - { - printk("%d",ld(host_index)[ldn].cache_flag); - } - printk("\nIBM MCA SCSI: SCSI-Retry bits: "); - for (ldn=0; ldn<=MAX_LOG_DEV; ldn++) - { - printk("%d",ld(host_index)[ldn].retry_flag); - } - printk("\n"); -#endif - } - return num_bus; -} - -/* - The following routine probes the SCSI-devices in four steps: - 1. The current ldn -> pun,lun mapping is removed on the SCSI-adapter. - 2. ldn 0 is used to go through all possible combinations of pun,lun and - a device_inquiry is done to fiddle out whether there is a device - responding or not. This physical map is stored in get_scsi[][]. - 3. The 15 available ldns (0-14) are mapped to existing pun,lun. - If there are more devices than ldns, it stops at 14 for the boot - time. Dynamical remapping will be done in ibmmca_queuecommand. - 4. If there are less than 15 valid pun,lun, the remaining ldns are - mapped to NON-existing pun,lun to satisfy the adapter. Information - about pun,lun -> ldn is stored as before in get_ldn[][]. - This method leads to the result, that the SCSI-pun,lun shown to Linux - mid-level- and higher-level-drivers is exactly corresponding to the - physical reality on the SCSI-bus. Therefore, it is possible that users - of older releases of this driver have to rewrite their fstab-file, because - the /dev/sdXXX could have changed due to the right pun,lun report, now. - The assignment of ALL ldns avoids dynamical remapping by the adapter - itself. - */ -static void check_devices (int host_index, int adaptertype) -{ - int id, lun, ldn, ticks; - int count_devices; /* local counter for connected device */ - int max_pun; - int num_bus; - int speedrun; /* local adapter_speed check variable */ - - /* assign default values to certain variables */ - ticks = 0; - count_devices = 0; - IBM_DS(host_index).dyn_flag = 0; /* normally no need for dynamical ldn management */ - IBM_DS(host_index).total_errors = 0; /* set errorcounter to 0 */ - next_ldn(host_index) = 7; /* next ldn to be assigned is 7, because 0-6 is 'hardwired'*/ - - /* initialize the very important driver-informational arrays/structs */ - memset (ld(host_index), 0, - sizeof(ld(host_index))); - for (ldn=0; ldn<=MAX_LOG_DEV; ldn++) - { - last_scsi_command(host_index)[ldn] = NO_SCSI; /* emptify last SCSI-command storage */ - last_scsi_type(host_index)[ldn] = 0; - ld(host_index)[ldn].cache_flag = 1; - ld(host_index)[ldn].retry_flag = 1; - } - memset (get_ldn(host_index), TYPE_NO_DEVICE, - sizeof(get_ldn(host_index))); /* this is essential ! */ - memset (get_scsi(host_index), TYPE_NO_DEVICE, - sizeof(get_scsi(host_index))); /* this is essential ! */ - - for (lun=0; lun<8; lun++) /* mark the adapter at its pun on all luns*/ - { - get_scsi(host_index)[subsystem_pun(host_index)][lun] = TYPE_IBM_SCSI_ADAPTER; - get_ldn(host_index)[subsystem_pun(host_index)][lun] = MAX_LOG_DEV; /* make sure, the subsystem - ldn is active for all - luns. */ - } - - probe_display(0); /* Supercool display usage during SCSI-probing. */ - /* This makes sense, when booting without any */ - /* monitor connected on model XX95. */ - - /* STEP 1: */ - adapter_speed(host_index) = global_adapter_speed; - speedrun = adapter_speed(host_index); - while (immediate_feature(host_index,speedrun,adapter_timeout)==2) - { - probe_display(1); - if (speedrun==7) - panic("IBM MCA SCSI: Cannot set Synchronous-Transfer-Rate!\n"); - speedrun++; - if (speedrun>7) - speedrun=7; - } - adapter_speed(host_index) = speedrun; - /* Get detailed information about the current adapter, necessary for - * device operations: */ - num_bus=probe_bus_mode(host_index); - - /* num_bus contains only valid data for the F/W adapter! */ - if (adaptertype==IBM_SCSI2_FW) /* F/W SCSI adapter: */ - { - /* F/W adapter PUN-space extension evaluation: */ - if (num_bus) - { - printk("IBM MCA SCSI: Seperate bus mode (wide-addressing enabled)\n"); - subsystem_maxid(host_index) = 16; - } - else - { - printk("IBM MCA SCSI: Combined bus mode (wide-addressing disabled)\n"); - subsystem_maxid(host_index) = 8; - } - printk("IBM MCA SCSI: Sync.-Rate (F/W: 20, Int.: 10, Ext.: %s) MBytes/s\n", - ibmrate(speedrun,adaptertype)); - } - else /* all other IBM SCSI adapters: */ - printk("IBM MCA SCSI: Synchronous-SCSI-Transfer-Rate: %s MBytes/s\n", - ibmrate(speedrun,adaptertype)); - - /* assign correct PUN device space */ - max_pun = subsystem_maxid(host_index); - -#ifdef IM_DEBUG_PROBE - printk("IBM MCA SCSI: Current SCSI-host index: %d\n",host_index); -#endif - printk("IBM MCA SCSI: Removing default logical SCSI-device mapping."); - for (ldn=0; ldn 0) - { - /* remove mapping */ - get_ldn(host_index)[id][lun]=TYPE_NO_DEVICE; - immediate_assign(host_index,0,0,ldn,REMOVE_LDN); - } - else ldn++; - } - } - else if (lun == 0) - { - /* map lun == 0, even if no device exists */ - immediate_assign(host_index,id,lun,ldn,SET_LDN); - get_ldn(host_index)[id][lun]=ldn; /* map ldn */ - ldn++; - } - } - } - - /* STEP 4: */ - - /* map remaining ldns to non-existing devices */ - for (lun=1; lun<8 && ldn=MAX_LOG_DEV) - IBM_DS(host_index).dyn_flag = 1; /* dynamical assignment is necessary */ - else - IBM_DS(host_index).dyn_flag = 0; /* dynamical assignment is not necessary */ - - /* If no SCSI-devices are assigned, return 1 in order to cause message. */ - if (ldn == 0) - printk("IBM MCA SCSI: Warning: No SCSI-devices found/assigned!\n"); - - /* reset the counters for statistics on the current adapter */ - IBM_DS(host_index).scbs = 0; - IBM_DS(host_index).long_scbs = 0; - IBM_DS(host_index).total_accesses = 0; - IBM_DS(host_index).total_interrupts = 0; - IBM_DS(host_index).dynamical_assignments = 0; - memset (IBM_DS(host_index).ldn_access, 0x0, - sizeof (IBM_DS(host_index).ldn_access)); - memset (IBM_DS(host_index).ldn_read_access, 0x0, - sizeof (IBM_DS(host_index).ldn_read_access)); - memset (IBM_DS(host_index).ldn_write_access, 0x0, - sizeof (IBM_DS(host_index).ldn_write_access)); - memset (IBM_DS(host_index).ldn_inquiry_access, 0x0, - sizeof (IBM_DS(host_index).ldn_inquiry_access)); - memset (IBM_DS(host_index).ldn_modeselect_access, 0x0, - sizeof (IBM_DS(host_index).ldn_modeselect_access)); - memset (IBM_DS(host_index).ldn_assignments, 0x0, - sizeof (IBM_DS(host_index).ldn_assignments)); - probe_display(0); - return; -} - -/*--------------------------------------------------------------------*/ - -static int device_exists (int host_index, int ldn, int *block_length, - int *device_type) -{ - unsigned char *buf; - - /* if no valid device found, return immediately with 0 */ - if (!(device_inquiry(host_index, ldn))) - return 0; - - buf = (unsigned char *)(&(ld(host_index)[ldn].buf)); - - /*if device is CD_ROM, assume block size 2048 and return */ - if (*buf == TYPE_ROM) - { - *device_type = TYPE_ROM; - *block_length = 2048; /* (standard blocksize for yellow-/red-book) */ - return 1; - } - - if (*buf == TYPE_WORM) /* CD-burner, WORM, Linux handles this as CD-ROM - therefore, the block_length is also 2048. */ - { - *device_type = TYPE_WORM; - *block_length = 2048; - return 1; - } - - /* if device is disk, use "read capacity" to find its block size */ - if (*buf == TYPE_DISK) - { - *device_type = TYPE_DISK; - if (read_capacity( host_index, ldn)) - { - *block_length = *(buf+7) + (*(buf+6) << 8) + - (*(buf+5) << 16) + (*(buf+4) << 24); - return 1; - } - else - return 0; - } - - /* if this is a magneto-optical drive, treat it like a harddisk */ - if (*buf == TYPE_MOD) - { - *device_type = TYPE_MOD; - if (read_capacity( host_index, ldn)) - { - *block_length = *(buf+7) + (*(buf+6) << 8) + - (*(buf+5) << 16) + (*(buf+4) << 24); - return 1; - } - else - return 0; - } - - if (*buf == TYPE_TAPE) /* TAPE-device found */ - { - *device_type = TYPE_TAPE; - *block_length = 0; /* not in use (setting by mt and mtst in op.) */ - return 1; - } - - if (*buf == TYPE_PROCESSOR) /* HP-Scanners, diverse SCSI-processing units*/ - { - *device_type = TYPE_PROCESSOR; - *block_length = 0; /* they set their stuff on drivers */ - return 1; - } - - if (*buf == TYPE_SCANNER) /* other SCSI-scanners */ - { - *device_type = TYPE_SCANNER; - *block_length = 0; /* they set their stuff on drivers */ - return 1; - } - - if (*buf == TYPE_MEDIUM_CHANGER) /* Medium-Changer */ - { - *device_type = TYPE_MEDIUM_CHANGER; - *block_length = 0; /* One never knows, what to expect on a medium - changer device. */ - return 1; - } - - /* Up to now, no SCSI-devices that are known up to kernel 2.1.31 are - ignored! MO-drives are now supported and treated as harddisk. */ - return 0; -} - -/*--------------------------------------------------------------------*/ - -void internal_ibmmca_scsi_setup (char *str, int *ints) -{ - int i, j, io_base, id_base; - char *token; - - io_base = 0; - id_base = 0; - - if (str) - { - token = strtok(str,","); - j = 0; - while (token) - { - if (!strcmp(token,"activity")) - display_mode |= LED_ACTIVITY; - if (!strcmp(token,"display")) - display_mode |= LED_DISP; - if (!strcmp(token,"adisplay")) - display_mode |= LED_ADISP; - if (!strcmp(token,"bypass")) - bypass_controller = 1; - if (!strcmp(token,"normal")) - ibm_ansi_order = 0; - if (!strcmp(token,"ansi")) - ibm_ansi_order = 1; - if (!strcmp(token,"fast")) - global_adapter_speed = 0; - if (!strcmp(token,"medium")) - global_adapter_speed = 4; - if (!strcmp(token,"slow")) - global_adapter_speed = 7; - if ( (*token == '-') || (isdigit(*token)) ) - { - if (!(j%2) && (io_base < IM_MAX_HOSTS)) - io_port[io_base++] = simple_strtoul(token,NULL,0); - if ((j%2) && (id_base < IM_MAX_HOSTS)) - scsi_id[id_base++] = simple_strtoul(token,NULL,0); - j++; - } - token = strtok(NULL,","); - } - } - else if (ints) - { - for (i = 0; i < IM_MAX_HOSTS && 2*i+2 < ints[0]; i++) - { - io_port[i] = ints[2*i+2]; - scsi_id[i] = ints[2*i+2]; - } - } - return; -} - -/*--------------------------------------------------------------------*/ - -static int ibmmca_getinfo (char *buf, int slot, void *dev) -{ - struct Scsi_Host *shpnt; - int len, speciale,connectore; - unsigned int pos2, pos3; - static unsigned long flags; - -#ifdef OLDKERN - save_flags(flags); - cli(); -#else - spin_lock_irqsave(&info_lock, flags); -#endif - - shpnt = dev; /* assign host-structure to local pointer */ - len = 0; /* set filled text-buffer index to 0 */ - /* get the _special contents of the hostdata structure */ - speciale = ((struct ibmmca_hostdata *)shpnt->hostdata)->_special; - connectore = ((struct ibmmca_hostdata *)shpnt->hostdata)->_connector_size; - pos2 = ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2; - pos3 = ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3; - - if (speciale == FORCED_DETECTION) /* forced detection */ - { - len += sprintf (buf + len, "Adapter category: forced detected\n"); - len += sprintf(buf + len, "***************************************\n"); - len += sprintf(buf + len, "*** Forced detected SCSI Adapter ***\n"); - len += sprintf(buf + len, "*** No chip-information available ***\n"); - len += sprintf(buf + len, "***************************************\n"); - } - else if (speciale == INTEGRATED_SCSI) - { /* if the integrated subsystem has been found automatically: */ - len += sprintf (buf + len, "Adapter category: integrated\n"); - len += sprintf (buf + len, "Chip revision level: %d\n", - ((pos2 & 0xf0) >> 4)); - len += sprintf (buf + len, "Chip status: %s\n", - (pos2 & 1) ? "enabled" : "disabled"); - len += sprintf (buf + len, "8 kByte NVRAM status: %s\n", - (pos2 & 2) ? "locked" : "accessible"); - } - else if ((speciale>=0)&& - (speciale<(sizeof(subsys_list)/sizeof(struct subsys_list_struct)))) - { /* if the subsystem is a slot adapter */ - len += sprintf (buf + len, "Adapter category: slot-card\n"); - len += sprintf (buf + len, "ROM Segment Address: "); - if ((pos2 & 0xf0) == 0xf0) - len += sprintf (buf + len, "off\n"); - else - len += sprintf (buf + len, "0x%x\n", - ((pos2 & 0xf0) << 13) + 0xc0000); - len += sprintf (buf + len, "Chip status: %s\n", - (pos2 & 1) ? "enabled" : "disabled"); - len += sprintf (buf + len, "Adapter I/O Offset: 0x%x\n", - ((pos2 & 0x0e) << 2)); - } - else - { - len += sprintf (buf + len, "Adapter category: unknown\n"); - } - /* common subsystem information to write to the slotn file */ - len += sprintf (buf + len, "Subsystem PUN: %d\n", shpnt->this_id); - len += sprintf (buf + len, "I/O base address range: 0x%x-0x%x\n", - (unsigned int)(shpnt->io_port), - (unsigned int)(shpnt->io_port+7)); - len += sprintf (buf + len, "MCA-slot size: %d bits",connectore); - /* Now make sure, the bufferlength is devidable by 4 to avoid - * paging problems of the buffer. */ - while ( len % sizeof( int ) != ( sizeof ( int ) - 1 ) ) - { - len += sprintf (buf + len, " "); - } - len += sprintf (buf + len, "\n"); - -#ifdef OLDKERN - restore_flags(flags); -#else - spin_unlock_irqrestore(&info_lock, flags); -#endif - return len; -} - -int ibmmca_detect (Scsi_Host_Template * scsi_template) -{ - struct Scsi_Host *shpnt; - int port, id, i, j, list_size, slot; - int devices_on_irq_11 = 0; - int devices_on_irq_14 = 0; - int IRQ14_registered = 0; - int IRQ11_registered = 0; - - found = 0; /* make absolutely sure, that found is set to 0 */ - - /* First of all, print the version number of the driver. This is - * important to allow better user bugreports in case of already - * having problems with the MCA_bus probing. */ - printk("IBM MCA SCSI: Version %s\n",IBMMCA_SCSI_DRIVER_VERSION); - /* if this is not MCA machine, return "nothing found" */ - if (!MCA_bus) - { - printk("IBM MCA SCSI: No Microchannel-bus present --> Aborting.\n"); - printk(" This machine does not have any IBM MCA-bus\n"); - printk(" or the MCA-Kernel-support is not enabled!\n"); - return 0; - } - -#ifdef MODULE - /* If the driver is run as module, read from conf.modules or cmd-line */ - if (boot_options) - option_setup(boot_options); -#endif - - /* get interrupt request level */ -#ifdef OLDKERN - if (request_irq (IM_IRQ, interrupt_handler, SA_SHIRQ, "ibmmcascsi", - hosts)) -#else - if (request_irq (IM_IRQ, do_interrupt_handler, SA_SHIRQ, "ibmmcascsi", - hosts)) -#endif - { - printk("IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ); - return 0; - } - else - IRQ14_registered++; - - /* if ibmmcascsi setup option was passed to kernel, return "found" */ - for (i = 0; i < IM_MAX_HOSTS; i++) - if (io_port[i] > 0 && scsi_id[i] >= 0 && scsi_id[i] < 8) - { - printk("IBM MCA SCSI: forced detected SCSI Adapter, io=0x%x, scsi id=%d.\n", - io_port[i], scsi_id[i]); - if ((shpnt = ibmmca_register(scsi_template, io_port[i], scsi_id[i], - FORCED_DETECTION, - "forced detected SCSI Adapter"))) - { - ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = 0; - ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = 0; - ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos4 = 0; - ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos5 = 0; - ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos6 = 0; - ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = - FORCED_DETECTION; - mca_set_adapter_name(MCA_INTEGSCSI, "forced detected SCSI Adapter"); - mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo, - shpnt); - mca_mark_as_used(MCA_INTEGSCSI); - devices_on_irq_14++; - } - } - if (found) return found; - - /* The POS2-register of all PS/2 model SCSI-subsystems has the following - * interpretation of bits: - * Bit 7 - 4 : Chip Revision ID (Release) - * Bit 3 - 2 : Reserved - * Bit 1 : 8k NVRAM Disabled - * Bit 0 : Chip Enable (EN-Signal) - * The POS3-register is interpreted as follows: - * Bit 7 - 5 : SCSI ID - * Bit 4 : Reserved = 0 - * Bit 3 - 0 : Reserved = 0 - * (taken from "IBM, PS/2 Hardware Interface Technical Reference, Common - * Interfaces (1991)"). - * In short words, this means, that IBM PS/2 machines only support - * 1 single subsystem by default. The slot-adapters must have another - * configuration on pos2. Here, one has to assume the following - * things for POS2-register: - * Bit 7 - 4 : Chip Revision ID (Release) - * Bit 3 - 1 : port offset factor - * Bit 0 : Chip Enable (EN-Signal) - * As I found a patch here, setting the IO-registers to 0x3540 forced, - * as there was a 0x05 in POS2 on a model 56, I assume, that the - * port 0x3540 must be fix for integrated SCSI-controllers. - * Ok, this discovery leads to the following implementation: (M.Lang) */ - - /* first look for the IBM SCSI integrated subsystem on the motherboard */ - for (j=0;j<8;j++) /* read the pos-information */ - pos[j] = mca_read_stored_pos(MCA_INTEGSCSI,j); - /* pos2 = pos3 = 0xff if there is no integrated SCSI-subsystem present */ - /* if (( pos[2] != 0xff) || (pos[3] != 0xff )) */ - /* Previous if-arguments do fail! Therefore, we use now the following to - * make sure, we see a real integrated onboard SCSI-interface: */ - if ((!pos[0] && !pos[1] && pos[2]>0 && pos[3]>0 && !pos[4] && !pos[5] && !pos[6] && !pos[7]) || - (pos[0]==0xff && pos[1]==0xff && pos[2]<0xff && pos[3]<0xff && pos[4]==0xff && pos[5]==0xff && pos[6]==0xff && pos[7]==0xff)) - { - if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */ - port = IM_IO_PORT; - else - { /* if disabled, no IRQs will be generated, as the chip won't - * listen to the incomming commands and will do really nothing, - * except for listening to the pos-register settings. If this - * happens, I need to hugely think about it, as one has to - * write something to the MCA-Bus pos register in order to - * enable the chip. Normally, IBM-SCSI won't pass the POST, - * when the chip is disabled (see IBM tech. ref.). */ - port = IM_IO_PORT; /* anyway, set the portnumber and warn */ - printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n"); - printk(" SCSI-operations may not work.\n"); - } - id = (pos[3] & 0xe0) >> 5; /* this is correct and represents the PUN */ - - /* give detailed information on the subsystem. This helps me - * additionally during debugging and analyzing bug-reports. */ - printk("IBM MCA SCSI: IBM Integrated SCSI Controller found, io=0x%x, scsi id=%d,\n", - port, id); - printk(" chip rev.=%d, 8K NVRAM=%s, subsystem=%s\n", - ((pos[2] & 0xf0) >> 4), (pos[2] & 2) ? "locked" : "accessible", - (pos[2] & 1) ? "enabled." : "disabled."); - - /* register the found integrated SCSI-subsystem */ - if ((shpnt = ibmmca_register(scsi_template, port, id, - INTEGRATED_SCSI, - "IBM Integrated SCSI Controller"))) - { - ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = pos[2]; - ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = pos[3]; - ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos4 = pos[4]; - ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos5 = pos[5]; - ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos6 = pos[6]; - ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = - INTEGRATED_SCSI; - mca_set_adapter_name(MCA_INTEGSCSI, "IBM Integrated SCSI Controller"); - mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo, - shpnt); - mca_mark_as_used(MCA_INTEGSCSI); - devices_on_irq_14++; - } - } - - /* now look for other adapters in MCA slots, */ - /* determine the number of known IBM-SCSI-subsystem types */ - /* see the pos[2] dependence to get the adapter port-offset. */ - list_size = sizeof(subsys_list) / sizeof(struct subsys_list_struct); - for (i = 0; i < list_size; i++) - { /* scan each slot for a fitting adapter id */ - slot = 0; /* start at slot 0 */ - while ((slot = mca_find_adapter(subsys_list[i].mca_id, slot)) - != MCA_NOTFOUND) - { /* scan through all slots */ - for (j=0;j<8;j++) /* read the pos-information */ - pos[j] = mca_read_stored_pos(slot, j); - if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */ - { /* (explanations see above) */ - port = IM_IO_PORT + ((pos[2] & 0x0e) << 2); - } - else - { /* anyway, set the portnumber and warn */ - port = IM_IO_PORT + ((pos[2] & 0x0e) << 2); - printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n"); - printk(" SCSI-operations may not work.\n"); - } - if ((i==IBM_SCSI2_FW)&&(pos[6]!=0)) - { - printk("IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n"); - printk(" Impossible to determine adapter PUN!\n"); - printk(" Guessing adapter PUN = 7.\n"); - id = 7; - } - else - { - id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */ - if (i==IBM_SCSI2_FW) - { - id |= (pos[3] & 0x10) >> 1; /* get subsystem PUN high-bit - * for F/W adapters */ - } - } - if ((i==IBM_SCSI2_FW)&&(pos[4] & 0x01)&&(pos[6]==0)) - { /* IRQ11 is used by SCSI-2 F/W Adapter/A */ - printk("IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n"); - /* get interrupt request level */ -#ifdef OLDKERN - if (request_irq (IM_IRQ_FW, interrupt_handler, SA_SHIRQ, - "ibmmcascsi", hosts)) -#else - if (request_irq (IM_IRQ_FW, do_interrupt_handler, SA_SHIRQ, - "ibmmcascsi", hosts)) -#endif - { - printk("IBM MCA SCSI: Unable to get shared IRQ %d.\n", - IM_IRQ_FW); - } - else - IRQ11_registered++; - } - printk("IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n", - subsys_list[i].description, slot + 1, port, id); - if ((pos[2] & 0xf0) == 0xf0) - printk(" ROM Addr.=off,"); - else - printk(" ROM Addr.=0x%x,", - ((pos[2] & 0xf0) << 13) + 0xc0000); - printk(" port-offset=0x%x, subsystem=%s\n", - ((pos[2] & 0x0e) << 2), - (pos[2] & 1) ? "enabled." : "disabled."); - - /* register the hostadapter */ - if ((shpnt = ibmmca_register(scsi_template, port, id, i, - subsys_list[i].description))) - { - ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = pos[2]; - ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = pos[3]; - ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos4 = pos[4]; - ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos5 = pos[5]; - ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos6 = pos[6]; - ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = i; - - mca_set_adapter_name (slot, subsys_list[i].description); - mca_set_adapter_procfn (slot, (MCA_ProcFn) ibmmca_getinfo, - shpnt); - mca_mark_as_used(slot); - if ((i==IBM_SCSI2_FW)&&(pos[4] & 0x01)&&(pos[6]==0)) - devices_on_irq_11++; - else - devices_on_irq_14++; - } - slot++; /* advance to next slot */ - } /* advance to next adapter id in the list of IBM-SCSI-subsystems*/ - } - - - /* now look for SCSI-adapters, by bugs mapped to the integrated SCSI - * area. E.g. a W/Cache in MCA-slot 9 ???? Arrrrgh!! */ - list_size = sizeof(subsys_list) / sizeof(struct subsys_list_struct); - for (i = 0; i < list_size; i++) - { /* scan each slot for a fitting adapter id */ - slot = mca_find_adapter(subsys_list[i].mca_id, MCA_INTEGSCSI); - if (slot != MCA_NOTFOUND) - { /* scan through all slots */ - for (j=0;j<8;j++) /* read the pos-information */ - pos[j] = mca_read_stored_pos(slot, j); - if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */ - { /* (explanations see above) */ - port = IM_IO_PORT + ((pos[2] & 0x0e) << 2); - } - else - { /* anyway, set the portnumber and warn */ - port = IM_IO_PORT + ((pos[2] & 0x0e) << 2); - printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n"); - printk(" SCSI-operations may not work.\n"); - } - if ((i==IBM_SCSI2_FW)&&(pos[6]!=0)) - { - printk("IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n"); - printk(" Impossible to determine adapter PUN!\n"); - printk(" Guessing adapter PUN = 7.\n"); - id = 7; - } - else - { - id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */ - if (i==IBM_SCSI2_FW) - { - id |= (pos[3] & 0x10) >> 1; /* get subsystem PUN high-bit - * for F/W adapters */ - } - } - if ((i==IBM_SCSI2_FW)&&(pos[4] & 0x01)&&(pos[6]==0)) - { /* IRQ11 is used by SCSI-2 F/W Adapter/A */ - printk("IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n"); - /* get interrupt request level */ -#ifdef OLDKERN - if (request_irq (IM_IRQ_FW, interrupt_handler, SA_SHIRQ, - "ibmmcascsi", hosts)) -#else - if (request_irq (IM_IRQ_FW, do_interrupt_handler, SA_SHIRQ, - "ibmmcascsi", hosts)) -#endif - { - printk("IBM MCA SCSI: Unable to get shared IRQ %d.\n", - IM_IRQ_FW); - } - else - IRQ11_registered++; - } - printk("IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n", - subsys_list[i].description, slot + 1, port, id); - if ((pos[2] & 0xf0) == 0xf0) - printk(" ROM Addr.=off,"); - else - printk(" ROM Addr.=0x%x,", - ((pos[2] & 0xf0) << 13) + 0xc0000); - printk(" port-offset=0x%x, subsystem=%s\n", - ((pos[2] & 0x0e) << 2), - (pos[2] & 1) ? "enabled." : "disabled."); - - /* register the hostadapter */ - if ((shpnt = ibmmca_register(scsi_template, port, id, i, - subsys_list[i].description))) - { - ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = pos[2]; - ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = pos[3]; - ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos4 = pos[4]; - ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos5 = pos[5]; - ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos6 = pos[6]; - ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = i; - - mca_set_adapter_name (slot, subsys_list[i].description); - mca_set_adapter_procfn (slot, (MCA_ProcFn) ibmmca_getinfo, - shpnt); - mca_mark_as_used(slot); - if ((i==IBM_SCSI2_FW)&&(pos[4] & 0x01)&&(pos[6]==0)) - devices_on_irq_11++; - else - devices_on_irq_14++; - } - slot++; /* advance to next slot */ - } /* advance to next adapter id in the list of IBM-SCSI-subsystems*/ - } - - if ( IRQ11_registered && !devices_on_irq_11 ) - free_irq(IM_IRQ_FW, hosts); /* no devices on IRQ 11 */ - if ( IRQ14_registered && !devices_on_irq_14 ) - free_irq(IM_IRQ, hosts); /* no devices on IRQ 14 */ - if ( !devices_on_irq_11 && !devices_on_irq_14 ) - printk("IBM MCA SCSI: No IBM SCSI-subsystem adapter attached.\n"); - return found; /* return the number of found SCSI hosts. Should be 1 or 0. */ -} - -static struct Scsi_Host * -ibmmca_register(Scsi_Host_Template * scsi_template, int port, int id, - int adaptertype, char *hostname) -{ - struct Scsi_Host *shpnt; - int i, j; - unsigned int ctrl; - - /* check I/O region */ - if (check_region(port, IM_N_IO_PORT)) - { - printk("IBM MCA SCSI: Unable to get I/O region 0x%x-0x%x (%d ports).\n", - port, port + IM_N_IO_PORT - 1, IM_N_IO_PORT); - return NULL; - } - - /* register host */ - shpnt = scsi_register(scsi_template, sizeof(struct ibmmca_hostdata)); - if (!shpnt) - { - printk("IBM MCA SCSI: Unable to register host.\n"); - return NULL; - } - - /* request I/O region */ - request_region(port, IM_N_IO_PORT, hostname); - - hosts[found] = shpnt; /* add new found hostadapter to the list */ - special(found) = adaptertype; /* important assignment or else crash! */ - subsystem_connector_size(found) = 0; /* preset slot-size */ - shpnt->irq = IM_IRQ; /* assign necessary stuff for the adapter */ - shpnt->io_port = port; - shpnt->n_io_port = IM_N_IO_PORT; - shpnt->this_id = id; - shpnt->max_id = 8; /* 8 PUNs are default */ - /* now, the SCSI-subsystem is connected to Linux */ - - ctrl = (unsigned int)(inb(IM_CTR_REG(found))); /* get control-register status */ -#ifdef IM_DEBUG_PROBE - printk("IBM MCA SCSI: Control Register contents: %x, status: %x\n", - ctrl,inb(IM_STAT_REG(found))); - printk("IBM MCA SCSI: This adapters' POS-registers: "); - for (i=0;i<8;i++) - printk("%x ",pos[i]); - printk("\n"); - if (bypass_controller) - printk("IBM MCA SCSI: Subsystem SCSI-commands get bypassed.\n"); -#endif - - reset_status(found) = IM_RESET_NOT_IN_PROGRESS; - - for (i = 0; i < 16; i++) /* reset the tables */ - for (j = 0; j < 8; j++) - get_ldn(found)[i][j] = MAX_LOG_DEV; - - /* check which logical devices exist */ - /* after this line, local interrupting is possible: */ - local_checking_phase_flag(found) = 1; - check_devices(found,adaptertype); /* call by value, using the global variable hosts*/ - local_checking_phase_flag(found) = 0; - - found++; /* now increase index to be prepared for next found subsystem */ - /* an ibm mca subsystem has been detected */ - return shpnt; -} - -/*--------------------------------------------------------------------*/ - -int ibmmca_command (Scsi_Cmnd * cmd) -{ - ibmmca_queuecommand (cmd, internal_done); - cmd->SCp.Status = 0; - while (!cmd->SCp.Status) - barrier (); - return cmd->result; -} - -/*--------------------------------------------------------------------*/ - -int ibmmca_release(struct Scsi_Host *shpnt) -{ - release_region(shpnt->io_port, shpnt->n_io_port); - if (!(--found)) - free_irq(shpnt->irq, hosts); - return 0; -} - -/*--------------------------------------------------------------------*/ - -/* The following routine is the SCSI command queue. The old edition is - now improved by dynamical reassignment of ldn numbers that are - currently not assigned. The mechanism works in a way, that first - the physical structure is checked. If at a certain pun,lun a device - should be present, the routine proceeds to the ldn check from - get_ldn. An answer of 0xff would show-up, that the aimed device is - currently not assigned any ldn. At this point, the dynamical - remapping algorithm is called. It works in a way, that it goes in - cyclic order through the ldns from 7 to 14. If a ldn is assigned, - it takes 8 dynamical reassignment calls, until a device looses its - ldn again. With this method it is assured, that while doing - intense I/O between up to eight devices, no dynamical remapping is - done there. ldns 0 through 6(!) are left untouched, which means, that - puns 0 through 7(!) on lun=0 are always accessible without remapping. - These ldns are statically assigned by this driver. The subsystem always - occupies at least one pun, therefore 7 ldns (at lun=0) for other devices - are sufficient. (The adapter uses always ldn=15, at whatever pun it is.) */ -int ibmmca_queuecommand (Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) -{ - unsigned int ldn; - unsigned int scsi_cmd; - struct im_scb *scb; - struct Scsi_Host *shpnt; - int current_ldn; - int id,lun; - int target; - int host_index; - int max_pun; - int i; - struct scatterlist *sl; - - shpnt = cmd->host; - - /* search for the right hostadapter */ - for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++); - - if (!hosts[host_index]) - { /* invalid hostadapter descriptor address */ - cmd->result = DID_NO_CONNECT << 16; - if (done) - done (cmd); - return 0; - } - - max_pun = subsystem_maxid(host_index); - - if (ibm_ansi_order) - { - target = max_pun - 1 - cmd->target; - if ((target <= subsystem_pun(host_index))&&(cmd->target <= subsystem_pun(host_index))) - target--; - else if ((target >= subsystem_pun(host_index))&&(cmd->target >= subsystem_pun(host_index))) - target++; - } - else - target = cmd->target; - - /*if (target,lun) is NO LUN or not existing at all, return error */ - if ((get_scsi(host_index)[target][cmd->lun] == TYPE_NO_LUN)|| - (get_scsi(host_index)[target][cmd->lun] == TYPE_NO_DEVICE)) - { - cmd->result = DID_NO_CONNECT << 16; - if (done) - done (cmd); - return 0; - } - - /*if (target,lun) unassigned, do further checks... */ - ldn = get_ldn(host_index)[target][cmd->lun]; - if (ldn >= MAX_LOG_DEV) /* on invalid ldn do special stuff */ - { - if (ldn > MAX_LOG_DEV) /* dynamical remapping if ldn unassigned */ - { - current_ldn = next_ldn(host_index); /* stop-value for one circle */ - while (ld(host_index)[next_ldn(host_index)].cmd) /* search for a occupied, but not in */ - { /* command-processing ldn. */ - next_ldn(host_index)++; - if (next_ldn(host_index)>=MAX_LOG_DEV) - next_ldn(host_index) = 7; - if (current_ldn == next_ldn(host_index)) /* One circle done ? */ - { /* no non-processing ldn found */ - printk("IBM MCA SCSI: Cannot assign SCSI-device dynamically!\n"); - printk(" On ldn 7-14 SCSI-commands everywhere in progress.\n"); - printk(" Reporting DID_NO_CONNECT for device (%d,%d).\n", - target, cmd->lun); - cmd->result = DID_NO_CONNECT << 16;/* return no connect*/ - if (done) - done (cmd); - return 0; - } - } - - /* unmap non-processing ldn */ - for (id=0; idlun,next_ldn(host_index),SET_LDN); - /* map found ldn to pun,lun */ - get_ldn(host_index)[target][cmd->lun] = next_ldn(host_index); - /* change ldn to the right value, that is now next_ldn */ - ldn = next_ldn(host_index); - /* get device information for ld[ldn] */ - if (device_exists (host_index, ldn, - &ld(host_index)[ldn].block_length, - &ld(host_index)[ldn].device_type)) - { - ld(host_index)[ldn].cmd = 0; /* To prevent panic set 0, because - devices that were not assigned, - should have nothing in progress. */ - - /* increase assignment counters for statistics in /proc */ - IBM_DS(host_index).dynamical_assignments++; - IBM_DS(host_index).ldn_assignments[ldn]++; - } - else - /* panic here, because a device, found at boottime has - vanished */ - panic("IBM MCA SCSI: ldn=0x%x, SCSI-device on (%d,%d) vanished!\n", - ldn, target, cmd->lun); - - /* set back to normal interrupt_handling */ - local_checking_phase_flag(host_index) = 0; - - /* Information on syslog terminal */ - printk("IBM MCA SCSI: ldn=0x%x dynamically reassigned to (%d,%d).\n", - ldn, target, cmd->lun); - - /* increase next_ldn for next dynamical assignment */ - next_ldn(host_index)++; - if (next_ldn(host_index)>=MAX_LOG_DEV) - next_ldn(host_index) = 7; - } - else - { /* wall against Linux accesses to the subsystem adapter */ - cmd->result = DID_BAD_TARGET << 16; - if (done) - done (cmd); - return 0; - } - } - - /*verify there is no command already in progress for this log dev */ - if (ld(host_index)[ldn].cmd) - panic ("IBM MCA SCSI: cmd already in progress for this ldn.\n"); - - /*save done in cmd, and save cmd for the interrupt handler */ - cmd->scsi_done = done; - ld(host_index)[ldn].cmd = cmd; - - /*fill scb information independent of the scsi command */ - scb = &(ld(host_index)[ldn].scb); - ld(host_index)[ldn].tsb.dev_status = 0; - scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE; - scb->tsb_adr = virt_to_bus(&(ld(host_index)[ldn].tsb)); - scsi_cmd = cmd->cmnd[0]; - - if (cmd->use_sg) - { - i = cmd->use_sg; - sl = (struct scatterlist *)(cmd->request_buffer); - if (i > 16) - panic ("IBM MCA SCSI: scatter-gather list too long.\n"); - while (--i >= 0) - { - ld(host_index)[ldn].sge[i].address = (void *)(virt_to_bus(sl[i].address)); - ld(host_index)[ldn].sge[i].byte_length = sl[i].length; - } - scb->enable |= IM_POINTER_TO_LIST; - scb->sys_buf_adr = virt_to_bus(&(ld(host_index)[ldn].sge[0])); - scb->sys_buf_length = cmd->use_sg * sizeof (struct im_sge); - } - else - { - scb->sys_buf_adr = virt_to_bus(cmd->request_buffer); - /* recent Linux midlevel SCSI places 1024 byte for inquiry - * command. Far too much for old PS/2 hardware. */ - switch (scsi_cmd) - { /* avoid command errors by setting bufferlengths to - * ANSI-standard. */ - case INQUIRY: - case REQUEST_SENSE: - case MODE_SENSE: - case MODE_SELECT: - scb->sys_buf_length = 255; - break; - case TEST_UNIT_READY: - scb->sys_buf_length = 0; - break; - default: - scb->sys_buf_length = cmd->request_bufflen; - break; - } - } - /*fill scb information dependent on scsi command */ - -#ifdef IM_DEBUG_CMD - printk("issue scsi cmd=%02x to ldn=%d\n", scsi_cmd, ldn); -#endif - - /* for specific device-type debugging: */ -#ifdef IM_DEBUG_CMD_SPEC_DEV - if (ld(host_index)[ldn].device_type==IM_DEBUG_CMD_DEVICE) - printk("(SCSI-device-type=0x%x) issue scsi cmd=%02x to ldn=%d\n", - ld(host_index)[ldn].device_type, scsi_cmd, ldn); -#endif - - /* for possible panics store current command */ - last_scsi_command(host_index)[ldn] = scsi_cmd; - last_scsi_type(host_index)[ldn] = IM_SCB; - /* update statistical info */ - IBM_DS(host_index).total_accesses++; - IBM_DS(host_index).ldn_access[ldn]++; - - switch (scsi_cmd) - { - case READ_6: - case WRITE_6: - case READ_10: - case WRITE_10: - case READ_12: - case WRITE_12: - /* Distinguish between disk and other devices. Only disks (that are the - most frequently accessed devices) should be supported by the - IBM-SCSI-Subsystem commands. */ - switch (ld(host_index)[ldn].device_type) - { - case TYPE_DISK: /* for harddisks enter here ... */ - case TYPE_MOD: /* ... try it also for MO-drives (send flames as */ - /* you like, if this won't work.) */ - if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || - scsi_cmd == READ_12) - { /* read command preparations */ - scb->enable |= IM_READ_CONTROL; - IBM_DS(host_index).ldn_read_access[ldn]++; /* increase READ-access on ldn stat. */ - if (bypass_controller) - { - scb->command = IM_OTHER_SCSI_CMD_CMD; - scb->enable |= IM_BYPASS_BUFFER; - scb->u1.scsi_cmd_length = cmd->cmd_len; - memcpy(scb->u2.scsi_command,cmd->cmnd,cmd->cmd_len); - last_scsi_type(host_index)[ldn] = IM_LONG_SCB; - } - else - scb->command = IM_READ_DATA_CMD | IM_NO_DISCONNECT; - } - else - { /* write command preparations */ - IBM_DS(host_index).ldn_write_access[ldn]++; /* increase write-count on ldn stat.*/ - if (bypass_controller) - { - scb->command = IM_OTHER_SCSI_CMD_CMD; - scb->enable |= IM_BYPASS_BUFFER; - scb->u1.scsi_cmd_length = cmd->cmd_len; - memcpy(scb->u2.scsi_command,cmd->cmnd,cmd->cmd_len); - last_scsi_type(host_index)[ldn] = IM_LONG_SCB; - } - else - scb->command = IM_WRITE_DATA_CMD | IM_NO_DISCONNECT; - } - - if (!bypass_controller) - { - if (scsi_cmd == READ_6 || scsi_cmd == WRITE_6) - { - scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[3]) << 0) | - (((unsigned) cmd->cmnd[2]) << 8) | - ((((unsigned) cmd->cmnd[1]) & 0x1f) << 16); - scb->u2.blk.count = (unsigned) cmd->cmnd[4]; - } - else - { - scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[5]) << 0) | - (((unsigned) cmd->cmnd[4]) << 8) | - (((unsigned) cmd->cmnd[3]) << 16) | - (((unsigned) cmd->cmnd[2]) << 24); - scb->u2.blk.count = (((unsigned) cmd->cmnd[8]) << 0) | - (((unsigned) cmd->cmnd[7]) << 8); - } - last_scsi_logical_block(host_index)[ldn] = scb->u1.log_blk_adr; - last_scsi_blockcount(host_index)[ldn] = scb->u2.blk.count; - scb->u2.blk.length = ld(host_index)[ldn].block_length; - } - if (++disk_rw_in_progress == 1) - PS2_DISK_LED_ON (shpnt->host_no, target); - break; - - /* for other devices, enter here. Other types are not known by - Linux! TYPE_NO_LUN is forbidden as valid device. */ - case TYPE_ROM: - case TYPE_TAPE: - case TYPE_PROCESSOR: - case TYPE_WORM: - case TYPE_SCANNER: - case TYPE_MEDIUM_CHANGER: - /* If there is a sequential-device, IBM recommends to use - IM_OTHER_SCSI_CMD_CMD instead of subsystem READ/WRITE. - Good/modern CD-ROM-drives are capable of - reading sequential AND random-access. This leads to the problem, - that random-accesses are covered by the subsystem, but - sequentials are not, as like for tape-drives. Therefore, it is - the easiest way to use IM_OTHER_SCSI_CMD_CMD for all read-ops - on CD-ROM-drives in order not to run into timing problems and - to have a stable state. In addition, data-access on CD-ROMs - works faster like that. Strange, but obvious. */ - - scb->command = IM_OTHER_SCSI_CMD_CMD; - if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || - scsi_cmd == READ_12) /* enable READ */ - scb->enable |= IM_READ_CONTROL; - scb->enable |= IM_BYPASS_BUFFER; - scb->u1.scsi_cmd_length = cmd->cmd_len; - memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); - last_scsi_type(host_index)[ldn] = IM_LONG_SCB; - - /* Read/write on this non-disk devices is also displayworthy, - so flash-up the LED/display. */ - if (++disk_rw_in_progress == 1) - PS2_DISK_LED_ON (shpnt->host_no, target); - break; - } - break; - case INQUIRY: - IBM_DS(host_index).ldn_inquiry_access[ldn]++; - if (bypass_controller) - { - scb->command = IM_OTHER_SCSI_CMD_CMD; - scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; - scb->u1.log_blk_adr = 0; - scb->u1.scsi_cmd_length = cmd->cmd_len; - memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); - last_scsi_type(host_index)[ldn] = IM_LONG_SCB; - } - else - { - scb->command = IM_DEVICE_INQUIRY_CMD; - scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT; - scb->u1.log_blk_adr = 0; - } - break; - case TEST_UNIT_READY: - scb->command = IM_OTHER_SCSI_CMD_CMD; - scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; - scb->u1.log_blk_adr = 0; - scb->u1.scsi_cmd_length = 6; - memcpy (scb->u2.scsi_command, cmd->cmnd, 6); - last_scsi_type(host_index)[ldn] = IM_LONG_SCB; - break; - case READ_CAPACITY: - /* the length of system memory buffer must be exactly 8 bytes */ - if (scb->sys_buf_length > 8) - scb->sys_buf_length = 8; - if (bypass_controller) - { - scb->command = IM_OTHER_SCSI_CMD_CMD; - scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; - scb->u1.scsi_cmd_length = cmd->cmd_len; - memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); - last_scsi_type(host_index)[ldn] = IM_LONG_SCB; - } - else - { - scb->command = IM_READ_CAPACITY_CMD; - scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT; - } - break; - - /* Commands that need read-only-mode (system <- device): */ - case REQUEST_SENSE: - if (bypass_controller) - { - scb->command = IM_OTHER_SCSI_CMD_CMD; - scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; - scb->u1.scsi_cmd_length = cmd->cmd_len; - memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); - last_scsi_type(host_index)[ldn] = IM_LONG_SCB; - } - else - { - scb->command = IM_REQUEST_SENSE_CMD; - scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT; - } - break; - - /* Commands that need write-only-mode (system -> device): */ - case MODE_SELECT: - case MODE_SELECT_10: - IBM_DS(host_index).ldn_modeselect_access[ldn]++; - scb->command = IM_OTHER_SCSI_CMD_CMD; - scb->enable |= IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; /*Select needs WRITE-enabled*/ - scb->u1.scsi_cmd_length = cmd->cmd_len; - memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); - last_scsi_type(host_index)[ldn] = IM_LONG_SCB; - break; - - /* For other commands, read-only is useful. Most other commands are - running without an input-data-block. */ - default: - scb->command = IM_OTHER_SCSI_CMD_CMD; - scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; - scb->u1.scsi_cmd_length = cmd->cmd_len; - memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); - last_scsi_type(host_index)[ldn] = IM_LONG_SCB; - break; - } - /*issue scb command, and return */ - if (last_scsi_type(host_index)[ldn] == IM_LONG_SCB) - { - issue_cmd (host_index, virt_to_bus(scb), IM_LONG_SCB | ldn); - IBM_DS(host_index).long_scbs++; - } - else - { - issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn); - IBM_DS(host_index).scbs++; - } - return 0; -} - -/*--------------------------------------------------------------------*/ - -int ibmmca_abort (Scsi_Cmnd * cmd) -{ - /* Abort does not work, as the adapter never generates an interrupt on - * whatever situation is simulated, even when really pending commands - * are running on the adapters' hardware ! */ - - struct Scsi_Host *shpnt; - unsigned int ldn; - void (*saved_done) (Scsi_Cmnd *); - int target; - int host_index; - int max_pun; - static unsigned long flags; - unsigned long imm_command; - - /* return SCSI_ABORT_SNOOZE ; */ - -#ifdef OLDKERN - save_flags(flags); - cli(); -#else - spin_lock_irqsave(&abort_lock, flags); -#endif - shpnt = cmd->host; - - /* search for the right hostadapter */ - for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++); - - if (!hosts[host_index]) - { /* invalid hostadapter descriptor address */ - cmd->result = DID_NO_CONNECT << 16; - if (cmd->scsi_done) - (cmd->scsi_done) (cmd); - return SCSI_ABORT_SNOOZE; - } - - max_pun = subsystem_maxid(host_index); - - if (ibm_ansi_order) - { - target = max_pun - 1 - cmd->target; - if ((target <= subsystem_pun(host_index))&&(cmd->target <= subsystem_pun(host_index))) - target--; - else if ((target >= subsystem_pun(host_index))&&(cmd->target >= subsystem_pun(host_index))) - target++; - } - else - target = cmd->target; - - /*get logical device number, and disable system interrupts */ - printk ("IBM MCA SCSI: Sending abort to device pun=%d, lun=%d.\n", - target, cmd->lun); - ldn = get_ldn(host_index)[target][cmd->lun]; - - /*if cmd for this ldn has already finished, no need to abort */ - if (!ld(host_index)[ldn].cmd) - { -#ifdef OLDKERN - restore_flags(flags); -#else - spin_unlock_irqrestore(&abort_lock, flags); -#endif - return SCSI_ABORT_NOT_RUNNING; - } - - /* Clear ld.cmd, save done function, install internal done, - * send abort immediate command (this enables sys. interrupts), - * and wait until the interrupt arrives. - */ - saved_done = cmd->scsi_done; - cmd->scsi_done = internal_done; - cmd->SCp.Status = 0; - last_scsi_command(host_index)[ldn] = IM_ABORT_IMM_CMD; - last_scsi_type(host_index)[ldn] = IM_IMM_CMD; - imm_command = inl(IM_CMD_REG(host_index)); - imm_command &= (unsigned long)(0xffff0000); /* mask reserved stuff */ - imm_command |= (unsigned long)(IM_ABORT_IMM_CMD); - /* must wait for attention reg not busy */ - while (1) - { - if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY)) - break; -#ifdef OLDKERN - restore_flags (flags); -#else - spin_unlock_irqrestore(&abort_lock, flags); -#endif -#ifdef OLDKERN - save_flags(flags); - cli(); -#else - spin_lock_irqsave(&abort_lock, flags); -#endif - } - /*write registers and enable system interrupts */ - outl (imm_command, IM_CMD_REG(host_index)); - outb (IM_IMM_CMD | ldn, IM_ATTN_REG(host_index)); -#ifdef OLDKERN - restore_flags (flags); -#else - spin_unlock_irqrestore(&abort_lock, flags); -#endif - -#ifdef IM_DEBUG_PROBE - printk("IBM MCA SCSI: Abort submitted, waiting for adapter response...\n"); -#endif - while (!cmd->SCp.Status) - barrier (); - cmd->scsi_done = saved_done; - /*if abort went well, call saved done, then return success or error */ - if (cmd->result == (DID_ABORT << 16)) - { - cmd->result |= DID_ABORT << 16; - if (cmd->scsi_done) - (cmd->scsi_done) (cmd); - ld(host_index)[ldn].cmd = NULL; -#ifdef IM_DEBUG_PROBE - printk("IBM MCA SCSI: Abort finished with success.\n"); -#endif - return SCSI_ABORT_SUCCESS; - } - else - { - cmd->result |= DID_NO_CONNECT << 16; - if (cmd->scsi_done) - (cmd->scsi_done) (cmd); - ld(host_index)[ldn].cmd = NULL; -#ifdef IM_DEBUG_PROBE - printk("IBM MCA SCSI: Abort failed.\n"); -#endif - return SCSI_ABORT_ERROR; - } -} - -/*--------------------------------------------------------------------*/ - -int ibmmca_reset (Scsi_Cmnd * cmd, unsigned int reset_flags) -{ - struct Scsi_Host *shpnt; - Scsi_Cmnd *cmd_aid; - int ticks,i; - int host_index; - static unsigned long flags; - unsigned long imm_command; - - if (cmd == NULL) - { - printk("IBM MCA SCSI: Reset called with NULL-command!\n"); - return(SCSI_RESET_SNOOZE); - } -#ifdef OLDKERN - save_flags(flags); - cli(); -#else - spin_lock_irqsave(&reset_lock, flags); -#endif - ticks = IM_RESET_DELAY*HZ; - shpnt = cmd->host; - /* search for the right hostadapter */ - for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++); - - if (!hosts[host_index]) - { /* invalid hostadapter descriptor address */ - if (!local_checking_phase_flag(host_index)) - { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132) - if (flags & SCSI_RESET_SYNCHRONOUS) - { -#ifdef OLDKERN - restore_flags(flags); -#else - spin_unlock_irqrestore(&reset_lock, flags); -#endif - cmd->result = DID_NO_CONNECT << 16; - if (cmd->scsi_done) - (cmd->scsi_done) (cmd); - } -#endif - } - return SCSI_ABORT_SNOOZE; - } - - if (local_checking_phase_flag(host_index)) - { - printk("IBM MCA SCSI: unable to reset while checking devices.\n"); -#ifdef OLDKERN - restore_flags(flags); -#else - spin_unlock_irqrestore(&reset_lock, flags); -#endif - return SCSI_RESET_SNOOZE; - } - - /* issue reset immediate command to subsystem, and wait for interrupt */ - printk("IBM MCA SCSI: resetting all devices.\n"); - reset_status(host_index) = IM_RESET_IN_PROGRESS; - last_scsi_command(host_index)[0xf] = IM_RESET_IMM_CMD; - last_scsi_type(host_index)[0xf] = IM_IMM_CMD; - imm_command = inl(IM_CMD_REG(host_index)); - imm_command &= (unsigned long)(0xffff0000); /* mask reserved stuff */ - imm_command |= (unsigned long)(IM_RESET_IMM_CMD); - /* must wait for attention reg not busy */ - while (1) - { - if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY)) - break; -#ifdef OLDKERN - restore_flags(flags); -#else - spin_unlock_irqrestore(&reset_lock, flags); -#endif -#ifdef OLDKERN - save_flags(flags); - cli(); -#else - spin_lock_irqsave(&reset_lock, flags); -#endif - } - /*write registers and enable system interrupts */ - outl (imm_command, IM_CMD_REG(host_index)); - outb (IM_IMM_CMD | 0xf, IM_ATTN_REG(host_index)); - /* wait for interrupt finished or intr_stat register to be set, as the - * interrupt will not be executed, while we are in here! */ - while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks - && ((inb(IM_INTR_REG(host_index)) & 0x8f)!=0x8f)) { - mdelay(1+999/HZ); - barrier(); - } - /* if reset did not complete, just return an error*/ - if (!ticks) { - printk("IBM MCA SCSI: reset did not complete within %d seconds.\n", - IM_RESET_DELAY); - reset_status(host_index) = IM_RESET_FINISHED_FAIL; -#ifdef OLDKERN - restore_flags(flags); -#else - spin_unlock_irqrestore(&reset_lock, flags); -#endif - return SCSI_RESET_ERROR; - } - - if ((inb(IM_INTR_REG(host_index)) & 0x8f)==0x8f) - { /* analysis done by this routine and not by the intr-routine */ - if (inb(IM_INTR_REG(host_index))==0xaf) - reset_status(host_index) = IM_RESET_FINISHED_OK_NO_INT; - else if (inb(IM_INTR_REG(host_index))==0xcf) - reset_status(host_index) = IM_RESET_FINISHED_FAIL; - else /* failed, 4get it */ - reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS_NO_INT; - outb (IM_EOI | 0xf, IM_ATTN_REG(host_index)); - } - - /* if reset failed, just return an error */ - if (reset_status(host_index) == IM_RESET_FINISHED_FAIL) { - printk("IBM MCA SCSI: reset failed.\n"); -#ifdef OLDKERN - restore_flags(flags); -#else - spin_unlock_irqrestore(&reset_lock, flags); -#endif - return SCSI_RESET_ERROR; - } - - /* so reset finished ok - call outstanding done's, and return success */ - printk ("IBM MCA SCSI: Reset successfully completed.\n"); -#ifdef OLDKERN - restore_flags(flags); -#else - spin_unlock_irqrestore(&reset_lock, flags); -#endif - for (i = 0; i < MAX_LOG_DEV; i++) - { - cmd_aid = ld(host_index)[i].cmd; - if (cmd_aid && cmd_aid->scsi_done) - { - ld(host_index)[i].cmd = NULL; - cmd_aid->result = DID_RESET << 16; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132) - if (flags & SCSI_RESET_SYNCHRONOUS) - { - cmd_aid->result = DID_BUS_BUSY << 16; - if (cmd_aid->scsi_done) - (cmd_aid->scsi_done) (cmd_aid); - } -#endif - } - } - if (flags & SCSI_RESET_SUGGEST_HOST_RESET) - return (SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET); - else if (flags & SCSI_RESET_SUGGEST_BUS_RESET) - return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET); - else - return SCSI_RESET_SUCCESS; -} - -/*--------------------------------------------------------------------*/ - -int ibmmca_biosparam (Disk * disk, kdev_t dev, int *info) -{ - info[0] = 64; - info[1] = 32; - info[2] = disk->capacity / (info[0] * info[1]); - if (info[2] >= 1024) - { - info[0] = 128; - info[1] = 63; - info[2] = disk->capacity / (info[0] * info[1]); - if (info[2] >= 1024) - { - info[0] = 255; - info[1] = 63; - info[2] = disk->capacity / (info[0] * info[1]); - if (info[2] >= 1024) - info[2] = 1023; - } - } - return 0; -} - -/* calculate percentage of total accesses on a ldn */ -static int ldn_access_load(int host_index, int ldn) -{ - if (IBM_DS(host_index).total_accesses == 0) return (0); - if (IBM_DS(host_index).ldn_access[ldn] == 0) return (0); - return (IBM_DS(host_index).ldn_access[ldn] * 100) / IBM_DS(host_index).total_accesses; -} - -/* calculate total amount of r/w-accesses */ -static int ldn_access_total_read_write(int host_index) -{ - int a; - int i; - - a = 0; - for (i=0; i<=MAX_LOG_DEV; i++) - a+=IBM_DS(host_index).ldn_read_access[i]+IBM_DS(host_index).ldn_write_access[i]; - return(a); -} - -static int ldn_access_total_inquiry(int host_index) -{ - int a; - int i; - - a = 0; - for (i=0; i<=MAX_LOG_DEV; i++) - a+=IBM_DS(host_index).ldn_inquiry_access[i]; - return(a); -} - -static int ldn_access_total_modeselect(int host_index) -{ - int a; - int i; - - a = 0; - for (i=0; i<=MAX_LOG_DEV; i++) - a+=IBM_DS(host_index).ldn_modeselect_access[i]; - return(a); -} - -/* routine to display info in the proc-fs-structure (a deluxe feature) */ -int ibmmca_proc_info (char *buffer, char **start, off_t offset, int length, - int hostno, int inout) -{ - int len=0; - int i,id,lun,host_index; - struct Scsi_Host *shpnt; - unsigned long flags; - int max_pun; - -#ifdef OLDKERN - save_flags(flags); - cli(); -#else - spin_lock_irqsave(&proc_lock, flags); -#endif - - for (i = 0; hosts[i] && hosts[i]->host_no != hostno; i++); - shpnt = hosts[i]; - host_index = i; - if (!shpnt) { - len += sprintf(buffer+len, "\nIBM MCA SCSI: Can't find adapter for host number %d\n", hostno); - return len; - } - max_pun = subsystem_maxid(host_index); - - len += sprintf(buffer+len, "\n IBM-SCSI-Subsystem-Linux-Driver, Version %s\n\n\n", - IBMMCA_SCSI_DRIVER_VERSION); - len += sprintf(buffer+len, " SCSI Access-Statistics:\n"); - len += sprintf(buffer+len, " Device Scanning Order....: %s\n", - (ibm_ansi_order) ? "IBM/ANSI" : "New Industry Standard"); -#ifdef CONFIG_SCSI_MULTI_LUN - len += sprintf(buffer+len, " Multiple LUN probing.....: Yes\n"); -#else - len += sprintf(buffer+len, " Multiple LUN probing.....: No\n"); -#endif - len += sprintf(buffer+len, " This Hostnumber..........: %d\n", - hostno); - len += sprintf(buffer+len, " Base I/O-Port............: 0x%x\n", - (unsigned int)(IM_CMD_REG(host_index))); - len += sprintf(buffer+len, " (Shared) IRQ.............: %d\n", - IM_IRQ); - len += sprintf(buffer+len, " SCSI-command set used....: %s\n", - (bypass_controller) ? "software" : "hardware integrated"); - len += sprintf(buffer+len, " Total Interrupts.........: %d\n", - IBM_DS(host_index).total_interrupts); - len += sprintf(buffer+len, " Total SCSI Accesses......: %d\n", - IBM_DS(host_index).total_accesses); - len += sprintf(buffer+len, " Total short SCBs.........: %d\n", - IBM_DS(host_index).scbs); - len += sprintf(buffer+len, " Total long SCBs..........: %d\n", - IBM_DS(host_index).long_scbs); - len += sprintf(buffer+len, " Total SCSI READ/WRITE..: %d\n", - ldn_access_total_read_write(host_index)); - len += sprintf(buffer+len, " Total SCSI Inquiries...: %d\n", - ldn_access_total_inquiry(host_index)); - len += sprintf(buffer+len, " Total SCSI Modeselects.: %d\n", - ldn_access_total_modeselect(host_index)); - len += sprintf(buffer+len, " Total SCSI other cmds..: %d\n", - IBM_DS(host_index).total_accesses - ldn_access_total_read_write(host_index) - - ldn_access_total_modeselect(host_index) - - ldn_access_total_inquiry(host_index)); - len += sprintf(buffer+len, " Total SCSI command fails.: %d\n\n", - IBM_DS(host_index).total_errors); - len += sprintf(buffer+len, " Logical-Device-Number (LDN) Access-Statistics:\n"); - len += sprintf(buffer+len, " LDN | Accesses [%%] | READ | WRITE | ASSIGNMENTS\n"); - len += sprintf(buffer+len, " -----|--------------|-----------|-----------|--------------\n"); - for (i=0; i<=MAX_LOG_DEV; i++) - len += sprintf(buffer+len, " %2X | %3d | %8d | %8d | %8d\n", - i, ldn_access_load(host_index, i), IBM_DS(host_index).ldn_read_access[i], - IBM_DS(host_index).ldn_write_access[i], IBM_DS(host_index).ldn_assignments[i]); - len += sprintf(buffer+len, " -----------------------------------------------------------\n\n"); - - len += sprintf(buffer+len, " Dynamical-LDN-Assignment-Statistics:\n"); - len += sprintf(buffer+len, " Number of physical SCSI-devices..: %d (+ Adapter)\n", - IBM_DS(host_index).total_scsi_devices); - len += sprintf(buffer+len, " Dynamical Assignment necessary...: %s\n", - IBM_DS(host_index).dyn_flag ? "Yes" : "No "); - len += sprintf(buffer+len, " Next LDN to be assigned..........: 0x%x\n", - next_ldn(host_index)); - len += sprintf(buffer+len, " Dynamical assignments done yet...: %d\n", - IBM_DS(host_index).dynamical_assignments); - - len += sprintf(buffer+len, "\n Current SCSI-Device-Mapping:\n"); - len += sprintf(buffer+len, " Physical SCSI-Device Map Logical SCSI-Device Map\n"); - len += sprintf(buffer+len, " ID\\LUN 0 1 2 3 4 5 6 7 ID\\LUN 0 1 2 3 4 5 6 7\n"); - for (id=0; id length) - len = length; -#ifdef OLDKERN - restore_flags(flags); -#else - spin_unlock_irqrestore(&proc_lock, flags); -#endif - return len; -} - -void ibmmca_scsi_setup (char *str, int *ints) -{ - internal_ibmmca_scsi_setup (str, ints); -} - -static int option_setup(char *str) -{ - int ints[IM_MAX_HOSTS]; - char *cur = str; - int i = 1; - - while (cur && isdigit(*cur) && i <= IM_MAX_HOSTS) { - ints[i++] = simple_strtoul(cur, NULL, 0); - if ((cur = strchr(cur,',')) != NULL) cur++; - } - ints[0] = i - 1; - internal_ibmmca_scsi_setup(cur, ints); - return 0; -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) -__setup("ibmmcascsi=", option_setup); -#endif - -/* Eventually this will go into an include file, but this will be later */ -static Scsi_Host_Template driver_template = IBMMCA; - -#include "scsi_module.c" - -/*--------------------------------------------------------------------*/ - +/* + Low Level Linux Driver for the IBM Microchannel SCSI Subsystem for + Linux Kernel >= 2.4.0. + Copyright (c) 1995 Strom Systems, Inc. under the terms of the GNU + General Public License. Written by Martin Kolinek, December 1995. + Further development by: Chris Beauregard, Klaus Kudielka, Michael Lang + See the file README.ibmmca for a detailed description of this driver, + the commandline arguments and the history of its development. + See the WWW-page: http://www.uni-mainz.de/~langm000/linux.html for latest + updates, info and ADF-files for adapters supported by this driver. +*/ + +#ifndef LINUX_VERSION_CODE +#include +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) +#error "This driver works only with kernel 2.4.0 or higher!" +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sd.h" +#include "scsi.h" +#include "hosts.h" +#include "ibmmca.h" +#include + +/* current version of this driver-source: */ +#define IBMMCA_SCSI_DRIVER_VERSION "4.0" + +#define IBMLOCK spin_lock_irqsave(&io_request_lock, flags); +#define IBMUNLOCK spin_unlock_irqrestore(&io_request_lock, flags); + +/* driver configuration */ +#define IM_MAX_HOSTS 8 /* maximum number of host adapters */ +#define IM_RESET_DELAY 60 /* seconds allowed for a reset */ + +/* driver debugging - #undef all for normal operation */ +/* if defined: count interrupts and ignore this special one: */ +#undef IM_DEBUG_TIMEOUT 50 +#define TIMEOUT_PUN 0 +#define TIMEOUT_LUN 0 +/* verbose interrupt: */ +#undef IM_DEBUG_INT +/* verbose queuecommand: */ +#undef IM_DEBUG_CMD +/* verbose queucommand for specific SCSI-device type: */ +#undef IM_DEBUG_CMD_SPEC_DEV +/* verbose device probing */ +#undef IM_DEBUG_PROBE + +/* device type that shall be displayed on syslog (only during debugging): */ +#define IM_DEBUG_CMD_DEVICE TYPE_TAPE + +/* relative addresses of hardware registers on a subsystem */ +#define IM_CMD_REG(hi) (hosts[(hi)]->io_port) /*Command Interface, (4 bytes long) */ +#define IM_ATTN_REG(hi) (hosts[(hi)]->io_port+4) /*Attention (1 byte) */ +#define IM_CTR_REG(hi) (hosts[(hi)]->io_port+5) /*Basic Control (1 byte) */ +#define IM_INTR_REG(hi) (hosts[(hi)]->io_port+6) /*Interrupt Status (1 byte, r/o) */ +#define IM_STAT_REG(hi) (hosts[(hi)]->io_port+7) /*Basic Status (1 byte, read only) */ + +/* basic I/O-port of first adapter */ +#define IM_IO_PORT 0x3540 +/* maximum number of hosts that can be found */ +#define IM_N_IO_PORT 8 + +/*requests going into the upper nibble of the Attention register */ +/*note: the lower nibble specifies the device(0-14), or subsystem(15) */ +#define IM_IMM_CMD 0x10 /*immediate command */ +#define IM_SCB 0x30 /*Subsystem Control Block command */ +#define IM_LONG_SCB 0x40 /*long Subsystem Control Block command */ +#define IM_EOI 0xe0 /*end-of-interrupt request */ + +/*values for bits 7,1,0 of Basic Control reg. (bits 6-2 reserved) */ +#define IM_HW_RESET 0x80 /*hardware reset */ +#define IM_ENABLE_DMA 0x02 /*enable subsystem's busmaster DMA */ +#define IM_ENABLE_INTR 0x01 /*enable interrupts to the system */ + +/*to interpret the upper nibble of Interrupt Status register */ +/*note: the lower nibble specifies the device(0-14), or subsystem(15) */ +#define IM_SCB_CMD_COMPLETED 0x10 +#define IM_SCB_CMD_COMPLETED_WITH_RETRIES 0x50 +#define IM_LOOP_SCATTER_BUFFER_FULL 0x60 +#define IM_ADAPTER_HW_FAILURE 0x70 +#define IM_IMMEDIATE_CMD_COMPLETED 0xa0 +#define IM_CMD_COMPLETED_WITH_FAILURE 0xc0 +#define IM_CMD_ERROR 0xe0 +#define IM_SOFTWARE_SEQUENCING_ERROR 0xf0 + +/*to interpret bits 3-0 of Basic Status register (bits 7-4 reserved) */ +#define IM_CMD_REG_FULL 0x08 +#define IM_CMD_REG_EMPTY 0x04 +#define IM_INTR_REQUEST 0x02 +#define IM_BUSY 0x01 + +/*immediate commands (word written into low 2 bytes of command reg) */ +#define IM_RESET_IMM_CMD 0x0400 +#define IM_FEATURE_CTR_IMM_CMD 0x040c +#define IM_DMA_PACING_IMM_CMD 0x040d +#define IM_ASSIGN_IMM_CMD 0x040e +#define IM_ABORT_IMM_CMD 0x040f +#define IM_FORMAT_PREP_IMM_CMD 0x0417 + +/*SCB (Subsystem Control Block) structure */ +struct im_scb { + unsigned short command; /*command word (read, etc.) */ + unsigned short enable; /*enable word, modifies cmd */ + union { + unsigned long log_blk_adr; /*block address on SCSI device */ + unsigned char scsi_cmd_length; /*6,10,12, for other scsi cmd */ + } u1; + unsigned long sys_buf_adr; /*physical system memory adr */ + unsigned long sys_buf_length; /*size of sys mem buffer */ + unsigned long tsb_adr; /*Termination Status Block adr */ + unsigned long scb_chain_adr; /*optional SCB chain address */ + union { + struct { + unsigned short count; /*block count, on SCSI device */ + unsigned short length; /*block length, on SCSI device */ + } blk; + unsigned char scsi_command[12]; /*other scsi command */ + } u2; +}; + +/*structure scatter-gather element (for list of system memory areas) */ +struct im_sge { + void *address; + unsigned long byte_length; +}; + +/*structure returned by a get_pos_info command: */ +struct im_pos_info { + unsigned short pos_id; /* adapter id */ + unsigned char pos_3a; /* pos 3 (if pos 6 = 0) */ + unsigned char pos_2; /* pos 2 */ + unsigned char int_level; /* interrupt level IRQ 11 or 14 */ + unsigned char pos_4a; /* pos 4 (if pos 6 = 0) */ + unsigned short connector_size; /* MCA connector size: 16 or 32 Bit */ + unsigned char num_luns; /* number of supported luns per device */ + unsigned char num_puns; /* number of supported puns */ + unsigned char pacing_factor; /* pacing factor */ + unsigned char num_ldns; /* number of ldns available */ + unsigned char eoi_off; /* time EOI and interrupt inactive */ + unsigned char max_busy; /* time between reset and busy on */ + unsigned short cache_stat; /* ldn cachestat. Bit=1 = not cached */ + unsigned short retry_stat; /* retry status of ldns. Bit=1=disabled */ + unsigned char pos_4b; /* pos 4 (if pos 6 = 1) */ + unsigned char pos_3b; /* pos 3 (if pos 6 = 1) */ + unsigned char pos_6; /* pos 6 */ + unsigned char pos_5; /* pos 5 */ + unsigned short max_overlap; /* maximum overlapping requests */ + unsigned short num_bus; /* number of SCSI-busses */ +}; + +/*values for SCB command word */ +#define IM_NO_SYNCHRONOUS 0x0040 /*flag for any command */ +#define IM_NO_DISCONNECT 0x0080 /*flag for any command */ +#define IM_READ_DATA_CMD 0x1c01 +#define IM_WRITE_DATA_CMD 0x1c02 +#define IM_READ_VERIFY_CMD 0x1c03 +#define IM_WRITE_VERIFY_CMD 0x1c04 +#define IM_REQUEST_SENSE_CMD 0x1c08 +#define IM_READ_CAPACITY_CMD 0x1c09 +#define IM_DEVICE_INQUIRY_CMD 0x1c0b +#define IM_READ_LOGICAL_CMD 0x1c2a +#define IM_OTHER_SCSI_CMD_CMD 0x241f + +/* unused, but supported, SCB commands */ +#define IM_GET_COMMAND_COMPLETE_STATUS_CMD 0x1c07 /* command status */ +#define IM_GET_POS_INFO_CMD 0x1c0a /* returns neat stuff */ +#define IM_READ_PREFETCH_CMD 0x1c31 /* caching controller only */ +#define IM_FOMAT_UNIT_CMD 0x1c16 /* format unit */ +#define IM_REASSIGN_BLOCK_CMD 0x1c18 /* in case of error */ + +/*values to set bits in the enable word of SCB */ +#define IM_READ_CONTROL 0x8000 +#define IM_REPORT_TSB_ONLY_ON_ERROR 0x4000 +#define IM_RETRY_ENABLE 0x2000 +#define IM_POINTER_TO_LIST 0x1000 +#define IM_SUPRESS_EXCEPTION_SHORT 0x0400 +#define IM_BYPASS_BUFFER 0x0200 +#define IM_CHAIN_ON_NO_ERROR 0x0001 + +/*TSB (Termination Status Block) structure */ +struct im_tsb { + unsigned short end_status; + unsigned short reserved1; + unsigned long residual_byte_count; + unsigned long sg_list_element_adr; + unsigned short status_length; + unsigned char dev_status; + unsigned char cmd_status; + unsigned char dev_error; + unsigned char cmd_error; + unsigned short reserved2; + unsigned short reserved3; + unsigned short low_of_last_scb_adr; + unsigned short high_of_last_scb_adr; +}; + +/*subsystem uses interrupt request level 14 */ +#define IM_IRQ 14 +/*SCSI-2 F/W may evade to interrupt 11 */ +#define IM_IRQ_FW 11 + +/* Model 95 has an additional alphanumeric display, which can be used + to display SCSI-activities. 8595 models do not have any disk led, which + makes this feature quite useful. + The regular PS/2 disk led is turned on/off by bits 6,7 of system + control port. */ + +/* LED display-port (actually, last LED on display) */ +#define MOD95_LED_PORT 0x108 +/* system-control-register of PS/2s with diskindicator */ +#define PS2_SYS_CTR 0x92 +/* activity displaying methods */ +#define LED_DISP 1 +#define LED_ADISP 2 +#define LED_ACTIVITY 4 +/* failed intr */ +#define CMD_FAIL 255 + +/* The SCSI-ID(!) of the accessed SCSI-device is shown on PS/2-95 machines' LED + displays. ldn is no longer displayed here, because the ldn mapping is now + done dynamically and the ldn <-> pun,lun maps can be looked-up at boottime + or during uptime in /proc/scsi/ibmmca/ in case of trouble, + interest, debugging or just for having fun. The left number gives the + host-adapter number and the right shows the accessed SCSI-ID. */ + +/* display_mode is set by the ibmmcascsi= command line arg */ +static int display_mode = 0; +/* set default adapter timeout */ +static unsigned int adapter_timeout = 45; +/* for probing on feature-command: */ +static unsigned int global_command_error_excuse = 0; +/* global setting by command line for adapter_speed */ +static int global_adapter_speed = 0; /* full speed by default */ + +/* Panel / LED on, do it right for F/W addressin, too. adisplay will + * just ignore ids>7, as the panel has only 7 digits available */ +#define PS2_DISK_LED_ON(ad,id) { if (display_mode & LED_DISP) { if (id>9) \ + outw((ad+48)|((id+55)<<8), MOD95_LED_PORT ); else \ + outw((ad+48)|((id+48)<<8), MOD95_LED_PORT ); } else \ + if (display_mode & LED_ADISP) { if (id<7) outb((char)(id+48),MOD95_LED_PORT+1+id); \ + outb((char)(ad+48), MOD95_LED_PORT); } \ + if ((display_mode & LED_ACTIVITY)||(!display_mode)) \ + outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR); } + +/* Panel / LED off */ +/* bug fixed, Dec 15, 1997, where | was replaced by & here */ +#define PS2_DISK_LED_OFF() { if (display_mode & LED_DISP) \ + outw(0x2020, MOD95_LED_PORT ); else if (display_mode & LED_ADISP) { \ + outl(0x20202020,MOD95_LED_PORT); outl(0x20202020,MOD95_LED_PORT+4); } \ + if ((display_mode & LED_ACTIVITY)||(!display_mode)) \ + outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); } + +/*list of supported subsystems */ +struct subsys_list_struct { + unsigned short mca_id; + char *description; +}; + +/* types of different supported hardware that goes to hostdata special */ +#define IBM_SCSI2_FW 0 +#define IBM_7568_WCACHE 1 +#define IBM_EXP_UNIT 2 +#define IBM_SCSI_WCACHE 3 +#define IBM_SCSI 4 + +/* other special flags for hostdata structure */ +#define FORCED_DETECTION 100 +#define INTEGRATED_SCSI 101 + +/* List of possible IBM-SCSI-adapters */ +struct subsys_list_struct subsys_list[] = { + {0x8efc,"IBM SCSI-2 F/W Adapter"}, /* special = 0 */ + {0x8efd,"IBM 7568 Industrial Computer SCSI Adapter w/Cache"}, /* special = 1 */ + {0x8ef8,"IBM Expansion Unit SCSI Controller"},/* special = 2 */ + {0x8eff,"IBM SCSI Adapter w/Cache"}, /* special = 3 */ + {0x8efe,"IBM SCSI Adapter"}, /* special = 4 */ +}; + +/* Max number of logical devices (can be up from 0 to 14). 15 is the address +of the adapter itself. */ +#define MAX_LOG_DEV 15 + +/*local data for a logical device */ +struct logical_device { + struct im_scb scb; /* SCSI-subsystem-control-block structure */ + struct im_tsb tsb; /* SCSI command complete status block structure */ + struct im_sge sge[16]; /* scatter gather list structure */ + unsigned char buf[256]; /* SCSI command return data buffer */ + Scsi_Cmnd *cmd; /* SCSI-command that is currently in progress */ + int device_type; /* type of the SCSI-device. See include/scsi/scsi.h + for interpretation of the possible values */ + int block_length; /* blocksize of a particular logical SCSI-device */ + int cache_flag; /* 1 if this is uncached, 0 if cache is present for ldn */ + int retry_flag; /* 1 if adapter retry is disabled, 0 if enabled */ +}; + +/* statistics of the driver during operations (for proc_info) */ +struct Driver_Statistics { + /* SCSI statistics on the adapter */ + int ldn_access[MAX_LOG_DEV+1]; /* total accesses on a ldn */ + int ldn_read_access[MAX_LOG_DEV+1]; /* total read-access on a ldn */ + int ldn_write_access[MAX_LOG_DEV+1]; /* total write-access on a ldn */ + int ldn_inquiry_access[MAX_LOG_DEV+1]; /* total inquiries on a ldn */ + int ldn_modeselect_access[MAX_LOG_DEV+1]; /* total mode selects on ldn */ + int scbs; /* short SCBs queued */ + int long_scbs; /* long SCBs queued */ + int total_accesses; /* total accesses on all ldns */ + int total_interrupts; /* total interrupts (should be + same as total_accesses) */ + int total_errors; /* command completed with error */ + /* dynamical assignment statistics */ + int total_scsi_devices; /* number of physical pun,lun */ + int dyn_flag; /* flag showing dynamical mode */ + int dynamical_assignments; /* number of remappings of ldns */ + int ldn_assignments[MAX_LOG_DEV+1]; /* number of remappings of each + ldn */ +}; + +/* data structure for each host adapter */ +struct ibmmca_hostdata { + /* array of logical devices: */ + struct logical_device _ld[MAX_LOG_DEV+1]; + /* array to convert (pun, lun) into logical device number: */ + unsigned char _get_ldn[16][8]; + /*array that contains the information about the physical SCSI-devices + attached to this host adapter: */ + unsigned char _get_scsi[16][8]; + /* used only when checking logical devices: */ + int _local_checking_phase_flag; + /* report received interrupt: */ + int _got_interrupt; + /* report termination-status of SCSI-command: */ + int _stat_result; + /* reset status (used only when doing reset): */ + int _reset_status; + /* code of the last SCSI command (needed for panic info): */ + int _last_scsi_command[MAX_LOG_DEV+1]; + /* identifier of the last SCSI-command type */ + int _last_scsi_type[MAX_LOG_DEV+1]; + /* last blockcount */ + int _last_scsi_blockcount[MAX_LOG_DEV+1]; + /* last locgical block address */ + unsigned long _last_scsi_logical_block[MAX_LOG_DEV+1]; + /* Counter that points on the next reassignable ldn for dynamical + remapping. The default value is 7, that is the first reassignable + number in the list at boottime: */ + int _next_ldn; + /* Statistics-structure for this IBM-SCSI-host: */ + struct Driver_Statistics _IBM_DS; + /* This hostadapters pos-registers pos2 until pos6 */ + unsigned int _pos[8]; + /* assign a special variable, that contains dedicated info about the + adaptertype */ + int _special; + /* connector size on the MCA bus */ + int _connector_size; + /* synchronous SCSI transfer rate bitpattern */ + int _adapter_speed; +}; + +/* macros to access host data structure */ +#define subsystem_pun(hi) (hosts[(hi)]->this_id) +#define subsystem_maxid(hi) (hosts[(hi)]->max_id) +#define ld(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_ld) +#define get_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_ldn) +#define get_scsi(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_scsi) +#define local_checking_phase_flag(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_local_checking_phase_flag) +#define got_interrupt(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_got_interrupt) +#define stat_result(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_stat_result) +#define reset_status(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_reset_status) +#define last_scsi_command(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_command) +#define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type) +#define last_scsi_blockcount(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_blockcount) +#define last_scsi_logical_block(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_logical_block) +#define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type) +#define next_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_next_ldn) +#define IBM_DS(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_IBM_DS) +#define special(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_special) +#define subsystem_connector_size(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_connector_size) +#define adapter_speed(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_adapter_speed) +#define pos2(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[2]) +#define pos3(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[3]) +#define pos4(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[4]) +#define pos5(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[5]) +#define pos6(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[6]) + +/* Define a arbitrary number as subsystem-marker-type. This number is, as + described in the ANSI-SCSI-standard, not occupied by other device-types. */ +#define TYPE_IBM_SCSI_ADAPTER 0x2F + +/* Define 0xFF for no device type, because this type is not defined within + the ANSI-SCSI-standard, therefore, it can be used and should not cause any + harm. */ +#define TYPE_NO_DEVICE 0xFF + +/* define medium-changer. If this is not defined previously, e.g. Linux + 2.0.x, define this type here. */ +#ifndef TYPE_MEDIUM_CHANGER +#define TYPE_MEDIUM_CHANGER 0x08 +#endif + +/* define possible operations for the immediate_assign command */ +#define SET_LDN 0 +#define REMOVE_LDN 1 + +/* ldn which is used to probe the SCSI devices */ +#define PROBE_LDN 0 + +/* reset status flag contents */ +#define IM_RESET_NOT_IN_PROGRESS 0 +#define IM_RESET_IN_PROGRESS 1 +#define IM_RESET_FINISHED_OK 2 +#define IM_RESET_FINISHED_FAIL 3 +#define IM_RESET_NOT_IN_PROGRESS_NO_INT 4 +#define IM_RESET_FINISHED_OK_NO_INT 5 + +/* define undefined SCSI-command */ +#define NO_SCSI 0xffff + +/*-----------------------------------------------------------------------*/ + +/* if this is nonzero, ibmmcascsi option has been passed to the kernel */ +static int io_port[IM_MAX_HOSTS] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +static int scsi_id[IM_MAX_HOSTS] = { 7, 7, 7, 7, 7, 7, 7, 7 }; + +/* fill module-parameters only, when this define is present. + (that is kernel version 2.1.x) */ +#if defined(MODULE) +static char *boot_options = NULL; +#include +MODULE_PARM(boot_options, "s"); +MODULE_PARM(io_port, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i"); +MODULE_PARM(scsi_id, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i"); +MODULE_PARM(display, "1i"); +MODULE_PARM(adisplay, "1i"); +MODULE_PARM(normal, "1i"); +MODULE_PARM(ansi, "1i"); +#endif +/*counter of concurrent disk read/writes, to turn on/off disk led */ +static int disk_rw_in_progress = 0; + +/* host information */ +static int found = 0; +static struct Scsi_Host *hosts[IM_MAX_HOSTS+1] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; +static unsigned int pos[8]; /* whole pos register-line for diagnosis */ +/* Taking into account the additions, made by ZP Gu. + * This selects now the preset value from the configfile and + * offers the 'normal' commandline option to be accepted */ +#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD +static char ibm_ansi_order = 1; +#else +static char ibm_ansi_order = 0; +#endif + +static void interrupt_handler (int, void *, struct pt_regs *); +static void issue_cmd (int, unsigned long, unsigned char); +static void internal_done (Scsi_Cmnd * cmd); +static void check_devices (int, int); +static int immediate_assign(int, unsigned int, unsigned int, unsigned int, + unsigned int); +static int immediate_feature(int, unsigned int, unsigned int); +#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET +static int immediate_reset(int, unsigned int); +#endif +static int device_inquiry(int, int); +static int read_capacity(int, int); +static int get_pos_info(int); +static char *ti_p(int); +static char *ti_l(int); +static char *ibmrate(unsigned int, int); +static int probe_display(int); +static int probe_bus_mode(int); +static int device_exists (int, int, int *, int *); +static struct Scsi_Host *ibmmca_register(Scsi_Host_Template *, + int, int, int, char *); +/* local functions needed for proc_info */ +static int ldn_access_load(int, int); +static int ldn_access_total_read_write(int); + +static void interrupt_handler (int irq, void *dev_id, struct pt_regs *regs) +{ + int host_index, ihost_index; + unsigned int intr_reg; + unsigned int cmd_result; + unsigned int ldn; + unsigned long flags; + Scsi_Cmnd *cmd; + int lastSCSI; + + IBMLOCK + /* search for one adapter-response on shared interrupt */ + for (host_index=0; + hosts[host_index] && !(inb(IM_STAT_REG(host_index)) & IM_INTR_REQUEST); + host_index++); + /* return if some other device on this IRQ caused the interrupt */ + if (!hosts[host_index]) { + IBMUNLOCK + return; + } + + /* the reset-function already did all the job, even ints got + renabled on the subsystem, so just return */ + if ((reset_status(host_index) == IM_RESET_NOT_IN_PROGRESS_NO_INT)|| + (reset_status(host_index) == IM_RESET_FINISHED_OK_NO_INT)) { + reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS; + IBMUNLOCK + return; + } + + /*must wait for attention reg not busy, then send EOI to subsystem */ + while (1) { + if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY)) break; + IBMUNLOCK /* cycle interrupt */ + IBMLOCK + } + ihost_index=host_index; + /*get command result and logical device */ + intr_reg = (unsigned char)(inb (IM_INTR_REG(ihost_index))); + cmd_result = intr_reg & 0xf0; + ldn = intr_reg & 0x0f; + /* get the last_scsi_command here */ + lastSCSI = last_scsi_command(ihost_index)[ldn]; + outb (IM_EOI | ldn, IM_ATTN_REG(ihost_index)); + IBMUNLOCK + /*these should never happen (hw fails, or a local programming bug) */ + if (!global_command_error_excuse) { + switch (cmd_result) { + /* Prevent from Ooopsing on error to show the real reason */ + case IM_ADAPTER_HW_FAILURE: + case IM_SOFTWARE_SEQUENCING_ERROR: + case IM_CMD_ERROR: + printk("\nIBM MCA SCSI: Fatal Subsystem ERROR!\n"); + printk(" Last cmd=0x%x, ena=%x, len=",lastSCSI, + ld(ihost_index)[ldn].scb.enable); + if (ld(ihost_index)[ldn].cmd) + printk("%ld/%ld,",(long)(ld(ihost_index)[ldn].cmd->request_bufflen), + (long)(ld(ihost_index)[ldn].scb.sys_buf_length)); + else + printk("none,"); + if (ld(ihost_index)[ldn].cmd) + printk("Blocksize=%d",ld(ihost_index)[ldn].scb.u2.blk.length); + else + printk("Blocksize=none"); + printk(", host=0x%x, ldn=0x%x\n",ihost_index, ldn); + if (ld(ihost_index)[ldn].cmd) { + printk("Blockcount=%d/%d\n",last_scsi_blockcount(ihost_index)[ldn], + ld(ihost_index)[ldn].scb.u2.blk.count); + printk("Logical block=%lx/%lx\n",last_scsi_logical_block(ihost_index)[ldn], + ld(ihost_index)[ldn].scb.u1.log_blk_adr); + } + printk("Reason given: %s\n", + (cmd_result==IM_ADAPTER_HW_FAILURE) ? "HARDWARE FAILURE" : + (cmd_result==IM_SOFTWARE_SEQUENCING_ERROR) ? "SOFTWARE SEQUENCING ERROR" : + (cmd_result==IM_CMD_ERROR) ? "COMMAND ERROR" : "UNKNOWN"); + /* if errors appear, enter this section to give detailed info */ + printk("IBM MCA SCSI: Subsystem Error-Status follows:\n"); + printk(" Command Type................: %x\n", + last_scsi_type(ihost_index)[ldn]); + printk(" Attention Register..........: %x\n", + inb (IM_ATTN_REG(ihost_index))); + printk(" Basic Control Register......: %x\n", + inb (IM_CTR_REG(ihost_index))); + printk(" Interrupt Status Register...: %x\n", + intr_reg); + printk(" Basic Status Register.......: %x\n", + inb (IM_STAT_REG(ihost_index))); + if ((last_scsi_type(ihost_index)[ldn]==IM_SCB)|| + (last_scsi_type(ihost_index)[ldn]==IM_LONG_SCB)) { + printk(" SCB-Command.................: %x\n", + ld(ihost_index)[ldn].scb.command); + printk(" SCB-Enable..................: %x\n", + ld(ihost_index)[ldn].scb.enable); + printk(" SCB-logical block address...: %lx\n", + ld(ihost_index)[ldn].scb.u1.log_blk_adr); + printk(" SCB-system buffer address...: %lx\n", + ld(ihost_index)[ldn].scb.sys_buf_adr); + printk(" SCB-system buffer length....: %lx\n", + ld(ihost_index)[ldn].scb.sys_buf_length); + printk(" SCB-tsb address.............: %lx\n", + ld(ihost_index)[ldn].scb.tsb_adr); + printk(" SCB-Chain address...........: %lx\n", + ld(ihost_index)[ldn].scb.scb_chain_adr); + printk(" SCB-block count.............: %x\n", + ld(ihost_index)[ldn].scb.u2.blk.count); + printk(" SCB-block length............: %x\n", + ld(ihost_index)[ldn].scb.u2.blk.length); + } + printk(" Send this report to the maintainer.\n"); + panic("IBM MCA SCSI: Fatal errormessage from the subsystem (0x%X,0x%X)!\n", + lastSCSI,cmd_result); + break; + } + } else { + /* The command error handling is made silent, but we tell the + * calling function, that there is a reported error from the + * adapter. */ + switch (cmd_result) { + case IM_ADAPTER_HW_FAILURE: case IM_SOFTWARE_SEQUENCING_ERROR: + case IM_CMD_ERROR: global_command_error_excuse = CMD_FAIL; break; + default: global_command_error_excuse = 0; break; + } + } + /* if no panic appeared, increase the interrupt-counter */ + IBM_DS(ihost_index).total_interrupts++; + /*only for local checking phase */ + if (local_checking_phase_flag(ihost_index)) { + stat_result(ihost_index) = cmd_result; + got_interrupt(ihost_index) = 1; + reset_status(ihost_index) = IM_RESET_FINISHED_OK; + last_scsi_command(ihost_index)[ldn] = NO_SCSI; + return; + } + /* handling of commands coming from upper level of scsi driver */ + if (last_scsi_type(ihost_index)[ldn] == IM_IMM_CMD) { + /* verify ldn, and may handle rare reset immediate command */ + if ((reset_status(ihost_index) == IM_RESET_IN_PROGRESS)&& + (last_scsi_command(ihost_index)[ldn] == IM_RESET_IMM_CMD)) { + if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) { + disk_rw_in_progress = 0; + PS2_DISK_LED_OFF (); + reset_status(ihost_index) = IM_RESET_FINISHED_FAIL; + } else { + /*reset disk led counter, turn off disk led */ + disk_rw_in_progress = 0; + PS2_DISK_LED_OFF (); + reset_status(ihost_index) = IM_RESET_FINISHED_OK; + } + stat_result(ihost_index) = cmd_result; + last_scsi_command(ihost_index)[ldn] = NO_SCSI; + last_scsi_type(ihost_index)[ldn] = 0; + return; + } else if (last_scsi_command(ihost_index)[ldn] == IM_ABORT_IMM_CMD) { + /* react on SCSI abort command */ +#ifdef IM_DEBUG_PROBE + printk("IBM MCA SCSI: Interrupt from SCSI-abort.\n"); +#endif + disk_rw_in_progress = 0; + PS2_DISK_LED_OFF(); + cmd = ld(ihost_index)[ldn].cmd; + ld(ihost_index)[ldn].cmd = NULL; + if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) + cmd->result = DID_NO_CONNECT << 16; + else + cmd->result = DID_ABORT << 16; + stat_result(ihost_index) = cmd_result; + last_scsi_command(ihost_index)[ldn] = NO_SCSI; + last_scsi_type(ihost_index)[ldn] = 0; + if (cmd->scsi_done) + (cmd->scsi_done)(cmd); /* should be the internal_done */ + return; + } else { + disk_rw_in_progress = 0; + PS2_DISK_LED_OFF (); + reset_status(ihost_index) = IM_RESET_FINISHED_OK; + stat_result(ihost_index) = cmd_result; + last_scsi_command(ihost_index)[ldn] = NO_SCSI; + return; + } + } + last_scsi_command(ihost_index)[ldn] = NO_SCSI; + last_scsi_type(ihost_index)[ldn] = 0; + cmd = ld(ihost_index)[ldn].cmd; + ld(ihost_index)[ldn].cmd = NULL; +#ifdef IM_DEBUG_TIMEOUT + if (cmd) { + if ((cmd->target == TIMEOUT_PUN)&&(cmd->lun == TIMEOUT_LUN)) { + printk("IBM MCA SCSI: Ignoring interrupt from pun=%x, lun=%x.\n", + cmd->target, cmd->lun); + return; + } + } +#endif + /*if no command structure, just return, else clear cmd */ + if (!cmd) return; + +#ifdef IM_DEBUG_INT + printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n", + cmd->cmnd[0], intr_reg, + ld(ihost_index)[ldn].tsb.dev_status, + ld(ihost_index)[ldn].tsb.cmd_status, + ld(ihost_index)[ldn].tsb.dev_error, + ld(ihost_index)[ldn].tsb.cmd_error); +#endif + /*if this is end of media read/write, may turn off PS/2 disk led */ + if ((ld(ihost_index)[ldn].device_type!=TYPE_NO_LUN)&& + (ld(ihost_index)[ldn].device_type!=TYPE_NO_DEVICE)) { + /* only access this, if there was a valid device addressed */ + if (--disk_rw_in_progress == 0) PS2_DISK_LED_OFF (); + } + + /* IBM describes the status-mask to be 0x1e, but this is not conform + * with SCSI-definition, I suppose, the reason for it is that IBM + * adapters do not support CMD_TERMINATED, TASK_SET_FULL and + * ACA_ACTIVE as returning statusbyte information. (ML) */ + if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) { + cmd->result = (unsigned char)(ld(ihost_index)[ldn].tsb.dev_status & 0x1e); + IBM_DS(ihost_index).total_errors++; + } else + cmd->result = 0; + /* write device status into cmd->result, and call done function */ + if (lastSCSI == NO_SCSI) { /* unexpected interrupt :-( */ + cmd->result |= DID_BAD_INTR << 16; + printk("IBM MCA SCSI: WARNING - Interrupt from non-pending SCSI-command!\n"); + } else /* things went right :-) */ + cmd->result |= DID_OK << 16; + if (cmd->scsi_done) (cmd->scsi_done)(cmd); + return; +} + +static void issue_cmd (int host_index, unsigned long cmd_reg, + unsigned char attn_reg) +{ + unsigned long flags; + /* must wait for attention reg not busy */ + while (1) { + IBMLOCK + if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY)) break; + IBMUNLOCK + } + /* write registers and enable system interrupts */ + outl (cmd_reg, IM_CMD_REG(host_index)); + outb (attn_reg, IM_ATTN_REG(host_index)); + IBMUNLOCK + return; +} + +static void internal_done (Scsi_Cmnd * cmd) +{ + cmd->SCp.Status++; + return; +} + +/* SCSI-SCB-command for device_inquiry */ +static int device_inquiry(int host_index, int ldn) +{ + int retries; + struct im_scb *scb; + struct im_tsb *tsb; + unsigned char *buf; + + scb = &(ld(host_index)[ldn].scb); + tsb = &(ld(host_index)[ldn].tsb); + buf = (unsigned char *)(&(ld(host_index)[ldn].buf)); + ld(host_index)[ldn].tsb.dev_status = 0; /* prepare statusblock */ + for (retries = 0; retries < 3; retries++) { + /* fill scb with inquiry command */ + scb->command = IM_DEVICE_INQUIRY_CMD | IM_NO_DISCONNECT; + scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_RETRY_ENABLE | IM_BYPASS_BUFFER; + last_scsi_command(host_index)[ldn] = IM_DEVICE_INQUIRY_CMD; + last_scsi_type(host_index)[ldn] = IM_SCB; + scb->sys_buf_adr = virt_to_bus(buf); + scb->sys_buf_length = 0xff; /* maximum bufferlength gives max info */ + scb->tsb_adr = virt_to_bus(tsb); + /* issue scb to passed ldn, and busy wait for interrupt */ + got_interrupt(host_index) = 0; + issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn); + while (!got_interrupt(host_index)) + barrier (); + + /*if command succesful, break */ + if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)|| + (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES)) + return 1; + } + /*if all three retries failed, return "no device at this ldn" */ + if (retries >= 3) + return 0; + else + return 1; +} + +static int read_capacity(int host_index, int ldn) +{ + int retries; + struct im_scb *scb; + struct im_tsb *tsb; + unsigned char *buf; + + scb = &(ld(host_index)[ldn].scb); + tsb = &(ld(host_index)[ldn].tsb); + buf = (unsigned char *)(&(ld(host_index)[ldn].buf)); + ld(host_index)[ldn].tsb.dev_status = 0; + for (retries = 0; retries < 3; retries++) { + /*fill scb with read capacity command */ + scb->command = IM_READ_CAPACITY_CMD; + scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_RETRY_ENABLE | IM_BYPASS_BUFFER; + last_scsi_command(host_index)[ldn] = IM_READ_CAPACITY_CMD; + last_scsi_type(host_index)[ldn] = IM_SCB; + scb->sys_buf_adr = virt_to_bus(buf); + scb->sys_buf_length = 8; + scb->tsb_adr = virt_to_bus(tsb); + /*issue scb to passed ldn, and busy wait for interrupt */ + got_interrupt(host_index) = 0; + issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn); + while (!got_interrupt(host_index)) + barrier (); + + /*if got capacity, get block length and return one device found */ + if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)|| + (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES)) + return 1; + } + /*if all three retries failed, return "no device at this ldn" */ + if (retries >= 3) + return 0; + else + return 1; +} + +static int get_pos_info(int host_index) +{ + int retries; + struct im_scb *scb; + struct im_tsb *tsb; + unsigned char *buf; + + scb = &(ld(host_index)[MAX_LOG_DEV].scb); + tsb = &(ld(host_index)[MAX_LOG_DEV].tsb); + buf = (unsigned char *)(&(ld(host_index)[MAX_LOG_DEV].buf)); + ld(host_index)[MAX_LOG_DEV].tsb.dev_status = 0; + for (retries = 0; retries < 3; retries++) { + /*fill scb with get_pos_info command */ + scb->command = IM_GET_POS_INFO_CMD; + scb->enable = IM_READ_CONTROL | IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE | IM_BYPASS_BUFFER; + last_scsi_command(host_index)[MAX_LOG_DEV] = IM_GET_POS_INFO_CMD; + last_scsi_type(host_index)[MAX_LOG_DEV] = IM_SCB; + scb->sys_buf_adr = virt_to_bus(buf); + if (special(host_index)==IBM_SCSI2_FW) + scb->sys_buf_length = 256; /* get all info from F/W adapter */ + else + scb->sys_buf_length = 18; /* get exactly 18 bytes for other SCSI */ + scb->tsb_adr = virt_to_bus(tsb); + /*issue scb to ldn=15, and busy wait for interrupt */ + got_interrupt(host_index) = 0; + issue_cmd (host_index, virt_to_bus(scb), IM_SCB | MAX_LOG_DEV); + while (!got_interrupt(host_index)) + barrier (); + + /*if got POS-stuff, get block length and return one device found */ + if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)|| + (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES)) + return 1; + } + /* if all three retries failed, return "no device at this ldn" */ + if (retries >= 3) + return 0; + else + return 1; +} + +/* SCSI-immediate-command for assign. This functions maps/unmaps specific + ldn-numbers on SCSI (PUN,LUN). It is needed for presetting of the + subsystem and for dynamical remapping od ldns. */ +static int immediate_assign(int host_index, unsigned int pun, + unsigned int lun, unsigned int ldn, + unsigned int operation) +{ + int retries; + unsigned long imm_command; + + for (retries=0; retries<3; retries ++) { + /* select mutation level of the SCSI-adapter */ + switch (special(host_index)) { + case IBM_SCSI2_FW: + imm_command = (unsigned long)(IM_ASSIGN_IMM_CMD); + imm_command |= (unsigned long)((lun & 7) << 24); + imm_command |= (unsigned long)((operation & 1) << 23); + imm_command |= (unsigned long)((pun & 7)<< 20)|((pun & 8)<< 24); + imm_command |= (unsigned long)((ldn & 15) << 16); + break; + default: + imm_command = inl(IM_CMD_REG(host_index)); + imm_command &= (unsigned long)(0xF8000000); /* keep reserved bits */ + imm_command |= (unsigned long)(IM_ASSIGN_IMM_CMD); + imm_command |= (unsigned long)((lun & 7) << 24); + imm_command |= (unsigned long)((operation & 1) << 23); + imm_command |= (unsigned long)((pun & 7) << 20); + imm_command |= (unsigned long)((ldn & 15) << 16); + break; + } + last_scsi_command(host_index)[MAX_LOG_DEV] = IM_ASSIGN_IMM_CMD; + last_scsi_type(host_index)[MAX_LOG_DEV] = IM_IMM_CMD; + got_interrupt(host_index) = 0; + issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | MAX_LOG_DEV); + while (!got_interrupt(host_index)) + barrier (); + + /*if command succesful, break */ + if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED) + return 1; + } + if (retries >= 3) + return 0; + else + return 1; +} + +static int immediate_feature(int host_index, unsigned int speed, + unsigned int timeout) +{ + int retries; + unsigned long imm_command; + + for (retries=0; retries<3; retries ++) { + /* select mutation level of the SCSI-adapter */ + imm_command = IM_FEATURE_CTR_IMM_CMD; + imm_command |= (unsigned long)((speed & 0x7) << 29); + imm_command |= (unsigned long)((timeout & 0x1fff) << 16); + last_scsi_command(host_index)[MAX_LOG_DEV] = IM_FEATURE_CTR_IMM_CMD; + last_scsi_type(host_index)[MAX_LOG_DEV] = IM_IMM_CMD; + got_interrupt(host_index) = 0; + /* we need to run into command errors in order to probe for the + * right speed! */ + global_command_error_excuse = 1; + issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | MAX_LOG_DEV); + while (!got_interrupt(host_index)) + barrier (); + if (global_command_error_excuse == CMD_FAIL) { + global_command_error_excuse = 0; + return 2; + } else + global_command_error_excuse = 0; + /*if command succesful, break */ + if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED) + return 1; + } + if (retries >= 3) + return 0; + else + return 1; +} + +#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET +static int immediate_reset(int host_index, unsigned int ldn) +{ + int retries; + int ticks; + unsigned long imm_command; + + for (retries=0; retries<3; retries ++) { + imm_command = inl(IM_CMD_REG(host_index)); + imm_command &= (unsigned long)(0xFFFF0000); /* keep reserved bits */ + imm_command |= (unsigned long)(IM_RESET_IMM_CMD); + last_scsi_command(host_index)[ldn] = IM_RESET_IMM_CMD; + last_scsi_type(host_index)[ldn] = IM_IMM_CMD; + got_interrupt(host_index) = 0; + reset_status(host_index) = IM_RESET_IN_PROGRESS; + issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | ldn); + ticks = IM_RESET_DELAY*HZ; + while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks) { + udelay((1+999/HZ)*1000); + barrier(); + } + /* if reset did not complete, just complain */ + if (!ticks) { + printk("IBM MCA SCSI: reset did not complete within %d seconds.\n", + IM_RESET_DELAY); + reset_status(host_index) = IM_RESET_FINISHED_OK; + /* did not work, finish */ + return 1; + } + /*if command succesful, break */ + if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED) + return 1; + } + if (retries >= 3) + return 0; + else + return 1; +} +#endif + +/* type-interpreter for physical device numbers */ +static char *ti_p(int value) +{ + switch (value) { + case TYPE_IBM_SCSI_ADAPTER: return("A"); break; + case TYPE_DISK: return("D"); break; + case TYPE_TAPE: return("T"); break; + case TYPE_PROCESSOR: return("P"); break; + case TYPE_WORM: return("W"); break; + case TYPE_ROM: return("R"); break; + case TYPE_SCANNER: return("S"); break; + case TYPE_MOD: return("M"); break; + case TYPE_MEDIUM_CHANGER: return("C"); break; + case TYPE_NO_LUN: return("+"); break; /* show NO_LUN */ + case TYPE_NO_DEVICE: + default: return("-"); break; + } + return("-"); +} + +/* interpreter for logical device numbers (ldn) */ +static char *ti_l(int value) +{ + const char hex[16] = "0123456789abcdef"; + static char answer[2]; + + answer[1] = (char)(0x0); + if (value<=MAX_LOG_DEV) answer[0] = hex[value]; else answer[0] = '-'; + return (char *)&answer; +} + +/* transfers bitpattern of the feature command to values in MHz */ +static char *ibmrate(unsigned int speed, int i) +{ + switch (speed) { + case 0: if (i) return "5.00"; else return "10.00"; break; + case 1: if (i) return "4.00"; else return "8.00"; break; + case 2: if (i) return "3.33"; else return "6.66"; break; + case 3: if (i) return "2.86"; else return "5.00"; break; + case 4: if (i) return "2.50"; else return "4.00"; break; + case 5: if (i) return "2.22"; else return "3.10"; break; + case 6: if (i) return "2.00"; else return "2.50"; break; + case 7: if (i) return "1.82"; else return "2.00"; break; + } + return "---"; +} + +static int probe_display(int what) +{ + static int rotator = 0; + const char rotor[] = "|/-\\"; + + if (!(display_mode & LED_DISP)) + return 0; + if (!what) { + outl(0x20202020,MOD95_LED_PORT); + outl(0x20202020,MOD95_LED_PORT+4); + } else { + outb('S',MOD95_LED_PORT+7); outb('C',MOD95_LED_PORT+6); + outb('S',MOD95_LED_PORT+5); outb('I',MOD95_LED_PORT+4); + outb('i',MOD95_LED_PORT+3); outb('n',MOD95_LED_PORT+2); + outb('i',MOD95_LED_PORT+1); outb((char)(rotor[rotator]),MOD95_LED_PORT); + rotator++; + if (rotator>3) rotator=0; + } + return 0; +} + +static int probe_bus_mode(int host_index) +{ + struct im_pos_info *info; + int num_bus = 0; + int ldn; + + info = (struct im_pos_info *)(&(ld(host_index)[MAX_LOG_DEV].buf)); + if (get_pos_info(host_index)) { + if (info->connector_size & 0xf000) + subsystem_connector_size(host_index)=16; + else + subsystem_connector_size(host_index)=32; + num_bus |= (info->pos_4b & 8) >> 3; + for (ldn=0; ldn<=MAX_LOG_DEV; ldn++) { + if ((special(host_index)==IBM_SCSI_WCACHE)|| + (special(host_index)==IBM_7568_WCACHE)) { + if (!((info->cache_stat >> ldn) & 1)) + ld(host_index)[ldn].cache_flag = 0; + } + if (!((info->retry_stat >> ldn) & 1)) + ld(host_index)[ldn].retry_flag = 0; + } +#ifdef IM_DEBUG_PROBE + printk("IBM MCA SCSI: SCSI-Cache bits: "); + for (ldn=0; ldn<=MAX_LOG_DEV; ldn++) { + printk("%d",ld(host_index)[ldn].cache_flag); + } + printk("\nIBM MCA SCSI: SCSI-Retry bits: "); + for (ldn=0; ldn<=MAX_LOG_DEV; ldn++) { + printk("%d",ld(host_index)[ldn].retry_flag); + } + printk("\n"); +#endif + } + return num_bus; +} + +/* probing scsi devices */ +static void check_devices (int host_index, int adaptertype) +{ + int id, lun, ldn, ticks; + int count_devices; /* local counter for connected device */ + int max_pun; + int num_bus; + int speedrun; /* local adapter_speed check variable */ + + /* assign default values to certain variables */ + ticks = 0; + count_devices = 0; + IBM_DS(host_index).dyn_flag = 0; /* normally no need for dynamical ldn management */ + IBM_DS(host_index).total_errors = 0; /* set errorcounter to 0 */ + next_ldn(host_index) = 7; /* next ldn to be assigned is 7, because 0-6 is 'hardwired'*/ + + /* initialize the very important driver-informational arrays/structs */ + memset (ld(host_index), 0, sizeof(ld(host_index))); + for (ldn=0; ldn<=MAX_LOG_DEV; ldn++) { + last_scsi_command(host_index)[ldn] = NO_SCSI; /* emptify last SCSI-command storage */ + last_scsi_type(host_index)[ldn] = 0; + ld(host_index)[ldn].cache_flag = 1; + ld(host_index)[ldn].retry_flag = 1; + } + memset (get_ldn(host_index), TYPE_NO_DEVICE, sizeof(get_ldn(host_index))); /* this is essential ! */ + memset (get_scsi(host_index), TYPE_NO_DEVICE, sizeof(get_scsi(host_index))); /* this is essential ! */ + for (lun=0; lun<8; lun++) { + /* mark the adapter at its pun on all luns*/ + get_scsi(host_index)[subsystem_pun(host_index)][lun] = TYPE_IBM_SCSI_ADAPTER; + get_ldn(host_index)[subsystem_pun(host_index)][lun] = MAX_LOG_DEV; /* make sure, the subsystem + ldn is active for all + luns. */ + } + probe_display(0); /* Supercool display usage during SCSI-probing. */ + /* This makes sense, when booting without any */ + /* monitor connected on model XX95. */ + + /* STEP 1: */ + adapter_speed(host_index) = global_adapter_speed; + speedrun = adapter_speed(host_index); + while (immediate_feature(host_index,speedrun,adapter_timeout)==2) { + probe_display(1); + if (speedrun==7) + panic("IBM MCA SCSI: Cannot set Synchronous-Transfer-Rate!\n"); + speedrun++; + if (speedrun>7) + speedrun=7; + } + adapter_speed(host_index) = speedrun; + /* Get detailed information about the current adapter, necessary for + * device operations: */ + num_bus=probe_bus_mode(host_index); + + /* num_bus contains only valid data for the F/W adapter! */ + if (adaptertype==IBM_SCSI2_FW) { /* F/W SCSI adapter: */ + /* F/W adapter PUN-space extension evaluation: */ + if (num_bus) { + printk("IBM MCA SCSI: Seperate bus mode (wide-addressing enabled)\n"); + subsystem_maxid(host_index) = 16; + } else { + printk("IBM MCA SCSI: Combined bus mode (wide-addressing disabled)\n"); + subsystem_maxid(host_index) = 8; + } + printk("IBM MCA SCSI: Sync.-Rate (F/W: 20, Int.: 10, Ext.: %s) MBytes/s\n", + ibmrate(speedrun,adaptertype)); + } else /* all other IBM SCSI adapters: */ + printk("IBM MCA SCSI: Synchronous-SCSI-Transfer-Rate: %s MBytes/s\n", + ibmrate(speedrun,adaptertype)); + + /* assign correct PUN device space */ + max_pun = subsystem_maxid(host_index); + +#ifdef IM_DEBUG_PROBE + printk("IBM MCA SCSI: Current SCSI-host index: %d\n",host_index); + printk("IBM MCA SCSI: Removing default logical SCSI-device mapping."); +#else + printk("IBM MCA SCSI: Dev. Order: %s, Mapping (takes <2min): ", + (ibm_ansi_order) ? "ANSI" : "New"); +#endif + for (ldn=0; ldn 0) { + /* remove mapping */ + get_ldn(host_index)[id][lun]=TYPE_NO_DEVICE; + immediate_assign(host_index,0,0,ldn,REMOVE_LDN); + } else ldn++; + } + } else if (lun == 0) { + /* map lun == 0, even if no device exists */ + immediate_assign(host_index,id,lun,ldn,SET_LDN); + get_ldn(host_index)[id][lun]=ldn; /* map ldn */ + ldn++; + } + } + } + /* STEP 4: */ + + /* map remaining ldns to non-existing devices */ + for (lun=1; lun<8 && ldn=MAX_LOG_DEV) + IBM_DS(host_index).dyn_flag = 1; /* dynamical assignment is necessary */ + else + IBM_DS(host_index).dyn_flag = 0; /* dynamical assignment is not necessary */ + + /* If no SCSI-devices are assigned, return 1 in order to cause message. */ + if (ldn == 0) + printk("IBM MCA SCSI: Warning: No SCSI-devices found/assigned!\n"); + + /* reset the counters for statistics on the current adapter */ + IBM_DS(host_index).scbs = 0; + IBM_DS(host_index).long_scbs = 0; + IBM_DS(host_index).total_accesses = 0; + IBM_DS(host_index).total_interrupts = 0; + IBM_DS(host_index).dynamical_assignments = 0; + memset (IBM_DS(host_index).ldn_access, 0x0, + sizeof (IBM_DS(host_index).ldn_access)); + memset (IBM_DS(host_index).ldn_read_access, 0x0, + sizeof (IBM_DS(host_index).ldn_read_access)); + memset (IBM_DS(host_index).ldn_write_access, 0x0, + sizeof (IBM_DS(host_index).ldn_write_access)); + memset (IBM_DS(host_index).ldn_inquiry_access, 0x0, + sizeof (IBM_DS(host_index).ldn_inquiry_access)); + memset (IBM_DS(host_index).ldn_modeselect_access, 0x0, + sizeof (IBM_DS(host_index).ldn_modeselect_access)); + memset (IBM_DS(host_index).ldn_assignments, 0x0, + sizeof (IBM_DS(host_index).ldn_assignments)); + probe_display(0); + return; +} + +static int device_exists (int host_index, int ldn, int *block_length, + int *device_type) +{ + unsigned char *buf; + /* if no valid device found, return immediately with 0 */ + if (!(device_inquiry(host_index, ldn))) + return 0; + buf = (unsigned char *)(&(ld(host_index)[ldn].buf)); + if (*buf == TYPE_ROM) { + *device_type = TYPE_ROM; + *block_length = 2048; /* (standard blocksize for yellow-/red-book) */ + return 1; + } + if (*buf == TYPE_WORM) { + *device_type = TYPE_WORM; + *block_length = 2048; + return 1; + } + if (*buf == TYPE_DISK) { + *device_type = TYPE_DISK; + if (read_capacity( host_index, ldn)) { + *block_length = *(buf+7) + (*(buf+6) << 8) + + (*(buf+5) << 16) + (*(buf+4) << 24); + return 1; + } else + return 0; + } + if (*buf == TYPE_MOD) { + *device_type = TYPE_MOD; + if (read_capacity( host_index, ldn)) { + *block_length = *(buf+7) + (*(buf+6) << 8) + + (*(buf+5) << 16) + (*(buf+4) << 24); + return 1; + } else + return 0; + } + if (*buf == TYPE_TAPE) { + *device_type = TYPE_TAPE; + *block_length = 0; /* not in use (setting by mt and mtst in op.) */ + return 1; + } + if (*buf == TYPE_PROCESSOR) { + *device_type = TYPE_PROCESSOR; + *block_length = 0; /* they set their stuff on drivers */ + return 1; + } + if (*buf == TYPE_SCANNER) { + *device_type = TYPE_SCANNER; + *block_length = 0; /* they set their stuff on drivers */ + return 1; + } + if (*buf == TYPE_MEDIUM_CHANGER) { + *device_type = TYPE_MEDIUM_CHANGER; + *block_length = 0; /* One never knows, what to expect on a medium + changer device. */ + return 1; + } + return 0; +} + +#ifdef CONFIG_SCSI_IBMMCA +void internal_ibmmca_scsi_setup (char *str, int *ints) +{ + int i, j, io_base, id_base; + char *token; + + io_base = 0; + id_base = 0; + if (str) { + token = strtok(str,","); + j = 0; + while (token) { + if (!strcmp(token,"activity")) display_mode |= LED_ACTIVITY; + if (!strcmp(token,"display")) display_mode |= LED_DISP; + if (!strcmp(token,"adisplay")) display_mode |= LED_ADISP; + if (!strcmp(token,"normal")) ibm_ansi_order = 0; + if (!strcmp(token,"ansi")) ibm_ansi_order = 1; + if (!strcmp(token,"fast")) global_adapter_speed = 0; + if (!strcmp(token,"medium")) global_adapter_speed = 4; + if (!strcmp(token,"slow")) global_adapter_speed = 7; + if ((*token == '-') || (isdigit(*token))) { + if (!(j%2) && (io_base < IM_MAX_HOSTS)) + io_port[io_base++] = simple_strtoul(token,NULL,0); + if ((j%2) && (id_base < IM_MAX_HOSTS)) + scsi_id[id_base++] = simple_strtoul(token,NULL,0); + j++; + } + token = strtok(NULL,","); + } + } else if (ints) { + for (i = 0; i < IM_MAX_HOSTS && 2*i+2 < ints[0]; i++) { + io_port[i] = ints[2*i+2]; + scsi_id[i] = ints[2*i+2]; + } + } + return; +} +#endif + +static int ibmmca_getinfo (char *buf, int slot, void *dev) +{ + struct Scsi_Host *shpnt; + int len, speciale, connectore, k; + unsigned int pos[8]; + unsigned long flags; + + IBMLOCK + shpnt = dev; /* assign host-structure to local pointer */ + len = 0; /* set filled text-buffer index to 0 */ + /* get the _special contents of the hostdata structure */ + speciale = ((struct ibmmca_hostdata *)shpnt->hostdata)->_special; + connectore = ((struct ibmmca_hostdata *)shpnt->hostdata)->_connector_size; + for (k=2;k<4;k++) + pos[k] = ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos[k]; + if (speciale == FORCED_DETECTION) { /* forced detection */ + len += sprintf (buf+len, + "Adapter category: forced detected\n" + "***************************************\n" + "*** Forced detected SCSI Adapter ***\n" + "*** No chip-information available ***\n" + "***************************************\n"); + } else if (speciale == INTEGRATED_SCSI) { + /* if the integrated subsystem has been found automatically: */ + len += sprintf (buf+len, + "Adapter category: integrated\n" + "Chip revision level: %d\n" + "Chip status: %s\n" + "8 kByte NVRAM status: %s\n", + ((pos[2] & 0xf0) >> 4), + (pos[2] & 1) ? "enabled" : "disabled", + (pos[2] & 2) ? "locked" : "accessible"); + } else if ((speciale>=0)&& + (speciale<(sizeof(subsys_list)/sizeof(struct subsys_list_struct)))) { + /* if the subsystem is a slot adapter */ + len += sprintf (buf+len, + "Adapter category: slot-card\n" + "ROM Segment Address: "); + if ((pos[2] & 0xf0) == 0xf0) + len += sprintf (buf+len, "off\n"); + else + len += sprintf (buf+len, "0x%x\n", + ((pos[2] & 0xf0) << 13) + 0xc0000); + len += sprintf (buf + len, "Chip status: %s\n", + (pos[2] & 1) ? "enabled" : "disabled"); + len += sprintf (buf + len, "Adapter I/O Offset: 0x%x\n", + ((pos[2] & 0x0e) << 2)); + } else { + len += sprintf (buf + len, "Adapter category: unknown\n"); + } + /* common subsystem information to write to the slotn file */ + len += sprintf (buf + len, "Subsystem PUN: %d\n", shpnt->this_id); + len += sprintf (buf + len, "I/O base address range: 0x%x-0x%x\n", + (unsigned int)(shpnt->io_port), + (unsigned int)(shpnt->io_port+7)); + len += sprintf (buf + len, "MCA-slot size: %d bits",connectore); + /* Now make sure, the bufferlength is devidable by 4 to avoid + * paging problems of the buffer. */ + while ( len % sizeof( int ) != ( sizeof ( int ) - 1 ) ) + len += sprintf (buf+len, " "); + len += sprintf (buf+len, "\n"); + IBMUNLOCK + return len; +} + +int ibmmca_detect (Scsi_Host_Template * scsi_template) +{ + struct Scsi_Host *shpnt; + int port, id, i, j, k, list_size, slot; + int devices_on_irq_11 = 0; + int devices_on_irq_14 = 0; + int IRQ14_registered = 0; + int IRQ11_registered = 0; + + found = 0; /* make absolutely sure, that found is set to 0 */ + + /* First of all, print the version number of the driver. This is + * important to allow better user bugreports in case of already + * having problems with the MCA_bus probing. */ + printk("IBM MCA SCSI: Version %s\n",IBMMCA_SCSI_DRIVER_VERSION); + /* if this is not MCA machine, return "nothing found" */ + if (!MCA_bus) { + printk("IBM MCA SCSI: No Microchannel-bus present --> Aborting.\n" + " This machine does not have any IBM MCA-bus\n" + " or the MCA-Kernel-support is not enabled!\n"); + return 0; + } + +#ifdef MODULE + /* If the driver is run as module, read from conf.modules or cmd-line */ + if (boot_options) option_setup(boot_options); +#endif + + /* get interrupt request level */ + if (request_irq (IM_IRQ, interrupt_handler, SA_SHIRQ, "ibmmcascsi", + hosts)) { + printk("IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ); + return 0; + } else + IRQ14_registered++; + + /* if ibmmcascsi setup option was passed to kernel, return "found" */ + for (i = 0; i < IM_MAX_HOSTS; i++) + if (io_port[i] > 0 && scsi_id[i] >= 0 && scsi_id[i] < 8) { + printk("IBM MCA SCSI: forced detected SCSI Adapter, io=0x%x, scsi id=%d.\n", + io_port[i], scsi_id[i]); + if ((shpnt = ibmmca_register(scsi_template, io_port[i], scsi_id[i], + FORCED_DETECTION, "forced detected SCSI Adapter"))) { + for (k=2;k<7;k++) + ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos[k] = 0; + ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = FORCED_DETECTION; + mca_set_adapter_name(MCA_INTEGSCSI, "forced detected SCSI Adapter"); + mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo, + shpnt); + mca_mark_as_used(MCA_INTEGSCSI); + devices_on_irq_14++; + } + } + if (found) return found; + + /* The POS2-register of all PS/2 model SCSI-subsystems has the following + * interpretation of bits: + * Bit 7 - 4 : Chip Revision ID (Release) + * Bit 3 - 2 : Reserved + * Bit 1 : 8k NVRAM Disabled + * Bit 0 : Chip Enable (EN-Signal) + * The POS3-register is interpreted as follows: + * Bit 7 - 5 : SCSI ID + * Bit 4 : Reserved = 0 + * Bit 3 - 0 : Reserved = 0 + * (taken from "IBM, PS/2 Hardware Interface Technical Reference, Common + * Interfaces (1991)"). + * In short words, this means, that IBM PS/2 machines only support + * 1 single subsystem by default. The slot-adapters must have another + * configuration on pos2. Here, one has to assume the following + * things for POS2-register: + * Bit 7 - 4 : Chip Revision ID (Release) + * Bit 3 - 1 : port offset factor + * Bit 0 : Chip Enable (EN-Signal) + * As I found a patch here, setting the IO-registers to 0x3540 forced, + * as there was a 0x05 in POS2 on a model 56, I assume, that the + * port 0x3540 must be fix for integrated SCSI-controllers. + * Ok, this discovery leads to the following implementation: (M.Lang) */ + + /* first look for the IBM SCSI integrated subsystem on the motherboard */ + for (j=0;j<8;j++) /* read the pos-information */ + pos[j] = mca_read_stored_pos(MCA_INTEGSCSI,j); + /* pos2 = pos3 = 0xff if there is no integrated SCSI-subsystem present, but + * if we ignore the settings of all surrounding pos registers, it is not + * completely sufficient to only check pos2 and pos3. */ + /* Therefore, now the following if statement is used to + * make sure, we see a real integrated onboard SCSI-interface and no + * internal system information, which gets mapped to some pos registers + * on models 95xx. */ + if ((!pos[0] && !pos[1] && pos[2]>0 && pos[3]>0 && !pos[4] && !pos[5] && !pos[6] && !pos[7]) || + (pos[0]==0xff && pos[1]==0xff && pos[2]<0xff && pos[3]<0xff && pos[4]==0xff && pos[5]==0xff && pos[6]==0xff && pos[7]==0xff)) { + if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */ + port = IM_IO_PORT; + else { /* if disabled, no IRQs will be generated, as the chip won't + * listen to the incomming commands and will do really nothing, + * except for listening to the pos-register settings. If this + * happens, I need to hugely think about it, as one has to + * write something to the MCA-Bus pos register in order to + * enable the chip. Normally, IBM-SCSI won't pass the POST, + * when the chip is disabled (see IBM tech. ref.). */ + port = IM_IO_PORT; /* anyway, set the portnumber and warn */ + printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n" + " SCSI-operations may not work.\n"); + } + id = (pos[3] & 0xe0) >> 5; /* this is correct and represents the PUN */ + /* give detailed information on the subsystem. This helps me + * additionally during debugging and analyzing bug-reports. */ + printk("IBM MCA SCSI: IBM Integrated SCSI Controller found, io=0x%x, scsi id=%d,\n" + " chip rev.=%d, 8K NVRAM=%s, subsystem=%s\n", + port, id, + ((pos[2] & 0xf0) >> 4), (pos[2] & 2) ? "locked" : "accessible", + (pos[2] & 1) ? "enabled." : "disabled."); + + /* register the found integrated SCSI-subsystem */ + if ((shpnt = ibmmca_register(scsi_template, port, id, INTEGRATED_SCSI, + "IBM Integrated SCSI Controller"))) { + for (k=2;k<7;k++) + ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos[k] = pos[k]; + ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = INTEGRATED_SCSI; + mca_set_adapter_name(MCA_INTEGSCSI, "IBM Integrated SCSI Controller"); + mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo, + shpnt); + mca_mark_as_used(MCA_INTEGSCSI); + devices_on_irq_14++; + } + } + + /* now look for other adapters in MCA slots, */ + /* determine the number of known IBM-SCSI-subsystem types */ + /* see the pos[2] dependence to get the adapter port-offset. */ + list_size = sizeof(subsys_list) / sizeof(struct subsys_list_struct); + for (i = 0; i < list_size; i++) { + /* scan each slot for a fitting adapter id */ + slot = 0; /* start at slot 0 */ + while ((slot = mca_find_adapter(subsys_list[i].mca_id, slot)) + != MCA_NOTFOUND) { /* scan through all slots */ + for (j=0;j<8;j++) /* read the pos-information */ + pos[j] = mca_read_stored_pos(slot, j); + if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */ + /* (explanations see above) */ + port = IM_IO_PORT + ((pos[2] & 0x0e) << 2); + else { + /* anyway, set the portnumber and warn */ + port = IM_IO_PORT + ((pos[2] & 0x0e) << 2); + printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n" + " SCSI-operations may not work.\n"); + } + if ((i==IBM_SCSI2_FW)&&(pos[6]!=0)) { + printk("IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n" + " Impossible to determine adapter PUN!\n" + " Guessing adapter PUN = 7.\n"); + id = 7; + } else { + id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */ + if (i==IBM_SCSI2_FW) { + id |= (pos[3] & 0x10) >> 1; /* get subsystem PUN high-bit + * for F/W adapters */ + } + } + if ((i==IBM_SCSI2_FW)&&(pos[4] & 0x01)&&(pos[6]==0)) { + /* IRQ11 is used by SCSI-2 F/W Adapter/A */ + printk("IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n"); + /* get interrupt request level */ + if (request_irq (IM_IRQ_FW, interrupt_handler, SA_SHIRQ, + "ibmmcascsi", hosts)) { + printk("IBM MCA SCSI: Unable to get shared IRQ %d.\n", + IM_IRQ_FW); + } else + IRQ11_registered++; + } + printk("IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n", + subsys_list[i].description, slot + 1, port, id); + if ((pos[2] & 0xf0) == 0xf0) + printk(" ROM Addr.=off,"); + else + printk(" ROM Addr.=0x%x,", + ((pos[2] & 0xf0) << 13) + 0xc0000); + printk(" port-offset=0x%x, subsystem=%s\n", + ((pos[2] & 0x0e) << 2), + (pos[2] & 1) ? "enabled." : "disabled."); + + /* register the hostadapter */ + if ((shpnt = ibmmca_register(scsi_template, port, id, i, + subsys_list[i].description))) { + for (k=2;k<8;k++) + ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos[k] = pos[k]; + ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = i; + mca_set_adapter_name (slot, subsys_list[i].description); + mca_set_adapter_procfn (slot, (MCA_ProcFn) ibmmca_getinfo, + shpnt); + mca_mark_as_used(slot); + if ((i==IBM_SCSI2_FW)&&(pos[4] & 0x01)&&(pos[6]==0)) + devices_on_irq_11++; + else + devices_on_irq_14++; + } + slot++; /* advance to next slot */ + } /* advance to next adapter id in the list of IBM-SCSI-subsystems*/ + } + + /* now check for SCSI-adapters, mapped to the integrated SCSI + * area. E.g. a W/Cache in MCA-slot 9(!). Do the check correct here, + * as this is a known effect on some models 95xx. */ + list_size = sizeof(subsys_list) / sizeof(struct subsys_list_struct); + for (i = 0; i < list_size; i++) { + /* scan each slot for a fitting adapter id */ + slot = mca_find_adapter(subsys_list[i].mca_id, MCA_INTEGSCSI); + if (slot != MCA_NOTFOUND) { /* scan through all slots */ + for (j=0;j<8;j++) /* read the pos-information */ + pos[j] = mca_read_stored_pos(slot, j); + if ((pos[2] & 1) == 1) { /* is the subsystem chip enabled ? */ + /* (explanations see above) */ + port = IM_IO_PORT + ((pos[2] & 0x0e) << 2); + } else { /* anyway, set the portnumber and warn */ + port = IM_IO_PORT + ((pos[2] & 0x0e) << 2); + printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n" + " SCSI-operations may not work.\n"); + } + if ((i==IBM_SCSI2_FW)&&(pos[6]!=0)) { + printk("IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n" + " Impossible to determine adapter PUN!\n" + " Guessing adapter PUN = 7.\n"); + id = 7; + } else { + id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */ + if (i==IBM_SCSI2_FW) + id |= (pos[3] & 0x10) >> 1; /* get subsystem PUN high-bit + * for F/W adapters */ + } + if ((i==IBM_SCSI2_FW)&&(pos[4] & 0x01)&&(pos[6]==0)) { + /* IRQ11 is used by SCSI-2 F/W Adapter/A */ + printk("IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n"); + /* get interrupt request level */ + if (request_irq (IM_IRQ_FW, interrupt_handler, SA_SHIRQ, + "ibmmcascsi", hosts)) + printk("IBM MCA SCSI: Unable to get shared IRQ %d.\n", + IM_IRQ_FW); + else + IRQ11_registered++; + } + printk("IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n", + subsys_list[i].description, slot + 1, port, id); + if ((pos[2] & 0xf0) == 0xf0) + printk(" ROM Addr.=off,"); + else + printk(" ROM Addr.=0x%x,", + ((pos[2] & 0xf0) << 13) + 0xc0000); + printk(" port-offset=0x%x, subsystem=%s\n", + ((pos[2] & 0x0e) << 2), + (pos[2] & 1) ? "enabled." : "disabled."); + + /* register the hostadapter */ + if ((shpnt = ibmmca_register(scsi_template, port, id, i, + subsys_list[i].description))) { + for (k=2;k<7;k++) + ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos[k] = pos[k]; + ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = i; + mca_set_adapter_name (slot, subsys_list[i].description); + mca_set_adapter_procfn (slot, (MCA_ProcFn) ibmmca_getinfo, shpnt); + mca_mark_as_used(slot); + if ((i==IBM_SCSI2_FW)&&(pos[4] & 0x01)&&(pos[6]==0)) + devices_on_irq_11++; + else + devices_on_irq_14++; + } + slot++; /* advance to next slot */ + } /* advance to next adapter id in the list of IBM-SCSI-subsystems*/ + } + if ( IRQ11_registered && !devices_on_irq_11 ) + free_irq(IM_IRQ_FW, hosts); /* no devices on IRQ 11 */ + if ( IRQ14_registered && !devices_on_irq_14 ) + free_irq(IM_IRQ, hosts); /* no devices on IRQ 14 */ + if ( !devices_on_irq_11 && !devices_on_irq_14 ) + printk("IBM MCA SCSI: No IBM SCSI-subsystem adapter attached.\n"); + return found; /* return the number of found SCSI hosts. Should be 1 or 0. */ +} + +static struct Scsi_Host * +ibmmca_register(Scsi_Host_Template * scsi_template, int port, int id, + int adaptertype, char *hostname) +{ + struct Scsi_Host *shpnt; + int i, j; + unsigned int ctrl; + + /* check I/O region */ + if (check_region(port, IM_N_IO_PORT)) { + printk("IBM MCA SCSI: Unable to get I/O region 0x%x-0x%x (%d ports).\n", + port, port + IM_N_IO_PORT - 1, IM_N_IO_PORT); + return NULL; + } + + /* register host */ + shpnt = scsi_register(scsi_template, sizeof(struct ibmmca_hostdata)); + if (!shpnt) { + printk("IBM MCA SCSI: Unable to register host.\n"); + return NULL; + } + + /* request I/O region */ + request_region(port, IM_N_IO_PORT, hostname); + hosts[found] = shpnt; /* add new found hostadapter to the list */ + special(found) = adaptertype; /* important assignment or else crash! */ + subsystem_connector_size(found) = 0; /* preset slot-size */ + shpnt->irq = IM_IRQ; /* assign necessary stuff for the adapter */ + shpnt->io_port = port; + shpnt->n_io_port = IM_N_IO_PORT; + shpnt->this_id = id; + shpnt->max_id = 8; /* 8 PUNs are default */ + /* now, the SCSI-subsystem is connected to Linux */ + + ctrl = (unsigned int)(inb(IM_CTR_REG(found))); /* get control-register status */ +#ifdef IM_DEBUG_PROBE + printk("IBM MCA SCSI: Control Register contents: %x, status: %x\n", + ctrl,inb(IM_STAT_REG(found))); + printk("IBM MCA SCSI: This adapters' POS-registers: "); + for (i=0;i<8;i++) + printk("%x ",pos[i]); + printk("\n"); +#endif + reset_status(found) = IM_RESET_NOT_IN_PROGRESS; + + for (i = 0; i < 16; i++) /* reset the tables */ + for (j = 0; j < 8; j++) + get_ldn(found)[i][j] = MAX_LOG_DEV; + + /* check which logical devices exist */ + /* after this line, local interrupting is possible: */ + local_checking_phase_flag(found) = 1; + check_devices(found,adaptertype); /* call by value, using the global variable hosts*/ + local_checking_phase_flag(found) = 0; + found++; /* now increase index to be prepared for next found subsystem */ + /* an ibm mca subsystem has been detected */ + return shpnt; +} + +int ibmmca_command (Scsi_Cmnd * cmd) +{ + ibmmca_queuecommand (cmd, internal_done); + cmd->SCp.Status = 0; + while (!cmd->SCp.Status) barrier (); + return cmd->result; +} + +int ibmmca_release(struct Scsi_Host *shpnt) +{ + release_region(shpnt->io_port, shpnt->n_io_port); + if (!(--found)) free_irq(shpnt->irq, hosts); + return 0; +} + +/* The following routine is the SCSI command queue for the midlevel driver */ +int ibmmca_queuecommand (Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) +{ + unsigned int ldn; + unsigned int scsi_cmd; + struct im_scb *scb; + struct Scsi_Host *shpnt; + int current_ldn; + int id,lun; + int target; + int host_index; + int max_pun; + int i; + struct scatterlist *sl; + + shpnt = cmd->host; + /* search for the right hostadapter */ + for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++); + + if (!hosts[host_index]) { /* invalid hostadapter descriptor address */ + cmd->result = DID_NO_CONNECT << 16; + if (done) done (cmd); + return 0; + } + max_pun = subsystem_maxid(host_index); + if (ibm_ansi_order) { + target = max_pun - 1 - cmd->target; + if ((target <= subsystem_pun(host_index))&&(cmd->target <= subsystem_pun(host_index))) + target--; + else if ((target >= subsystem_pun(host_index))&&(cmd->target >= subsystem_pun(host_index))) + target++; + } else + target = cmd->target; + + /* if (target,lun) is NO LUN or not existing at all, return error */ + if ((get_scsi(host_index)[target][cmd->lun] == TYPE_NO_LUN)|| + (get_scsi(host_index)[target][cmd->lun] == TYPE_NO_DEVICE)) { + cmd->result = DID_NO_CONNECT << 16; + if (done) done (cmd); + return 0; + } + + /*if (target,lun) unassigned, do further checks... */ + ldn = get_ldn(host_index)[target][cmd->lun]; + if (ldn >= MAX_LOG_DEV) { /* on invalid ldn do special stuff */ + if (ldn > MAX_LOG_DEV) { /* dynamical remapping if ldn unassigned */ + current_ldn = next_ldn(host_index); /* stop-value for one circle */ + while (ld(host_index)[next_ldn(host_index)].cmd) { /* search for a occupied, but not in */ + /* command-processing ldn. */ + next_ldn(host_index)++; + if (next_ldn(host_index)>=MAX_LOG_DEV) + next_ldn(host_index) = 7; + if (current_ldn == next_ldn(host_index)) { /* One circle done ? */ + /* no non-processing ldn found */ + printk("IBM MCA SCSI: Cannot assign SCSI-device dynamically!\n" \ + " On ldn 7-14 SCSI-commands everywhere in progress.\n" \ + " Reporting DID_NO_CONNECT for device (%d,%d).\n", + target, cmd->lun); + cmd->result = DID_NO_CONNECT << 16;/* return no connect*/ + if (done) done (cmd); + return 0; + } + } + + /* unmap non-processing ldn */ + for (id=0; idlun] = next_ldn(host_index); + /* change ldn to the right value, that is now next_ldn */ + ldn = next_ldn(host_index); + /* unassign all ldns (pun,lun,ldn does not matter for remove) */ + immediate_assign(host_index,0,0,0,REMOVE_LDN); + /* set only LDN for remapped device */ + immediate_assign(host_index,target,cmd->lun,ldn,SET_LDN); + /* get device information for ld[ldn] */ + if (device_exists (host_index, ldn, + &ld(host_index)[ldn].block_length, + &ld(host_index)[ldn].device_type)) { + ld(host_index)[ldn].cmd = NULL; /* To prevent panic set 0, because + devices that were not assigned, + should have nothing in progress. */ + get_scsi(host_index)[target][cmd->lun] = ld(host_index)[ldn].device_type; + /* increase assignment counters for statistics in /proc */ + IBM_DS(host_index).dynamical_assignments++; + IBM_DS(host_index).ldn_assignments[ldn]++; + } else + /* panic here, because a device, found at boottime has + vanished */ + panic("IBM MCA SCSI: ldn=0x%x, SCSI-device on (%d,%d) vanished!\n", + ldn, target, cmd->lun); + /* unassign again all ldns (pun,lun,ldn does not matter for remove) */ + immediate_assign(host_index,0,0,0,REMOVE_LDN); + /* remap all ldns, as written in the pun/lun table */ + lun=0; +#ifdef CONFIG_SCSI_MULTI_LUN + for (lun=0; lun<8; lun++) +#endif + for (id=0; idlun); +#endif + /* increase next_ldn for next dynamical assignment */ + next_ldn(host_index)++; + if (next_ldn(host_index)>=MAX_LOG_DEV) + next_ldn(host_index) = 7; + } else { /* wall against Linux accesses to the subsystem adapter */ + cmd->result = DID_BAD_TARGET << 16; + if (done) done (cmd); + return 0; + } + } + + /*verify there is no command already in progress for this log dev */ + if (ld(host_index)[ldn].cmd) + panic ("IBM MCA SCSI: cmd already in progress for this ldn.\n"); + + /*save done in cmd, and save cmd for the interrupt handler */ + cmd->scsi_done = done; + ld(host_index)[ldn].cmd = cmd; + + /*fill scb information independent of the scsi command */ + scb = &(ld(host_index)[ldn].scb); + ld(host_index)[ldn].tsb.dev_status = 0; + scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE; + scb->tsb_adr = virt_to_bus(&(ld(host_index)[ldn].tsb)); + scsi_cmd = cmd->cmnd[0]; + + if (cmd->use_sg) { + i = cmd->use_sg; + sl = (struct scatterlist *)(cmd->request_buffer); + if (i > 16) + panic ("IBM MCA SCSI: scatter-gather list too long.\n"); + while (--i >= 0) { + ld(host_index)[ldn].sge[i].address = (void *)(virt_to_bus(sl[i].address)); + ld(host_index)[ldn].sge[i].byte_length = sl[i].length; + } + scb->enable |= IM_POINTER_TO_LIST; + scb->sys_buf_adr = virt_to_bus(&(ld(host_index)[ldn].sge[0])); + scb->sys_buf_length = cmd->use_sg * sizeof (struct im_sge); + } else { + scb->sys_buf_adr = virt_to_bus(cmd->request_buffer); + /* recent Linux midlevel SCSI places 1024 byte for inquiry + * command. Far too much for old PS/2 hardware. */ + switch (scsi_cmd) { + /* avoid command errors by setting bufferlengths to + * ANSI-standard. Beware of forcing it to 255, + * this could SEGV the kernel!!! */ + case INQUIRY: + case REQUEST_SENSE: + case MODE_SENSE: + case MODE_SELECT: + if (cmd->request_bufflen > 255) scb->sys_buf_length = 255; + else scb->sys_buf_length = cmd->request_bufflen; + break; + case TEST_UNIT_READY: + scb->sys_buf_length = 0; + break; + default: + scb->sys_buf_length = cmd->request_bufflen; + break; + } + } + /*fill scb information dependent on scsi command */ + +#ifdef IM_DEBUG_CMD + printk("issue scsi cmd=%02x to ldn=%d\n", scsi_cmd, ldn); +#endif + + /* for specific device-type debugging: */ +#ifdef IM_DEBUG_CMD_SPEC_DEV + if (ld(host_index)[ldn].device_type==IM_DEBUG_CMD_DEVICE) + printk("(SCSI-device-type=0x%x) issue scsi cmd=%02x to ldn=%d\n", + ld(host_index)[ldn].device_type, scsi_cmd, ldn); +#endif + + /* for possible panics store current command */ + last_scsi_command(host_index)[ldn] = scsi_cmd; + last_scsi_type(host_index)[ldn] = IM_SCB; + /* update statistical info */ + IBM_DS(host_index).total_accesses++; + IBM_DS(host_index).ldn_access[ldn]++; + + switch (scsi_cmd) { + case READ_6: + case WRITE_6: + case READ_10: + case WRITE_10: + case READ_12: + case WRITE_12: + /* Distinguish between disk and other devices. Only disks (that are the + most frequently accessed devices) should be supported by the + IBM-SCSI-Subsystem commands. */ + switch (ld(host_index)[ldn].device_type) { + case TYPE_DISK: /* for harddisks enter here ... */ + case TYPE_MOD: /* ... try it also for MO-drives (send flames as */ + /* you like, if this won't work.) */ + if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || scsi_cmd == READ_12) { + /* read command preparations */ + scb->enable |= IM_READ_CONTROL; + IBM_DS(host_index).ldn_read_access[ldn]++; /* increase READ-access on ldn stat. */ + scb->command = IM_READ_DATA_CMD | IM_NO_DISCONNECT; + } else { /* write command preparations */ + IBM_DS(host_index).ldn_write_access[ldn]++; /* increase write-count on ldn stat.*/ + scb->command = IM_WRITE_DATA_CMD | IM_NO_DISCONNECT; + } + if (scsi_cmd == READ_6 || scsi_cmd == WRITE_6) { + scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[3]) << 0) | + (((unsigned) cmd->cmnd[2]) << 8) | + ((((unsigned) cmd->cmnd[1]) & 0x1f) << 16); + scb->u2.blk.count = (unsigned) cmd->cmnd[4]; + } else { + scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[5]) << 0) | + (((unsigned) cmd->cmnd[4]) << 8) | + (((unsigned) cmd->cmnd[3]) << 16) | + (((unsigned) cmd->cmnd[2]) << 24); + scb->u2.blk.count = (((unsigned) cmd->cmnd[8]) << 0) | + (((unsigned) cmd->cmnd[7]) << 8); + } + last_scsi_logical_block(host_index)[ldn] = scb->u1.log_blk_adr; + last_scsi_blockcount(host_index)[ldn] = scb->u2.blk.count; + scb->u2.blk.length = ld(host_index)[ldn].block_length; + break; + /* for other devices, enter here. Other types are not known by + Linux! TYPE_NO_LUN is forbidden as valid device. */ + case TYPE_ROM: + case TYPE_TAPE: + case TYPE_PROCESSOR: + case TYPE_WORM: + case TYPE_SCANNER: + case TYPE_MEDIUM_CHANGER: + /* If there is a sequential-device, IBM recommends to use + IM_OTHER_SCSI_CMD_CMD instead of subsystem READ/WRITE. + This includes CD-ROM devices, too, due to the partial sequential + read capabilities. */ + scb->command = IM_OTHER_SCSI_CMD_CMD; + if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || scsi_cmd == READ_12) + /* enable READ */ + scb->enable |= IM_READ_CONTROL; + scb->enable |= IM_BYPASS_BUFFER; + scb->u1.scsi_cmd_length = cmd->cmd_len; + memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); + last_scsi_type(host_index)[ldn] = IM_LONG_SCB; + /* Read/write on this non-disk devices is also displayworthy, + so flash-up the LED/display. */ + break; + } + break; + case INQUIRY: + IBM_DS(host_index).ldn_inquiry_access[ldn]++; + scb->command = IM_DEVICE_INQUIRY_CMD; + scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; + scb->u1.log_blk_adr = 0; + break; + case TEST_UNIT_READY: + scb->command = IM_OTHER_SCSI_CMD_CMD; + scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; + scb->u1.log_blk_adr = 0; + scb->u1.scsi_cmd_length = 6; + memcpy (scb->u2.scsi_command, cmd->cmnd, 6); + last_scsi_type(host_index)[ldn] = IM_LONG_SCB; + break; + case READ_CAPACITY: + /* the length of system memory buffer must be exactly 8 bytes */ + scb->command = IM_READ_CAPACITY_CMD; + scb->enable |= IM_READ_CONTROL | IM_BYPASS_BUFFER; + if (scb->sys_buf_length > 8) scb->sys_buf_length = 8; + break; + /* Commands that need read-only-mode (system <- device): */ + case REQUEST_SENSE: + scb->command = IM_REQUEST_SENSE_CMD; + scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; + break; + /* Commands that need write-only-mode (system -> device): */ + case MODE_SELECT: + case MODE_SELECT_10: + IBM_DS(host_index).ldn_modeselect_access[ldn]++; + scb->command = IM_OTHER_SCSI_CMD_CMD; + scb->enable |= IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; /*Select needs WRITE-enabled*/ + scb->u1.scsi_cmd_length = cmd->cmd_len; + memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); + last_scsi_type(host_index)[ldn] = IM_LONG_SCB; + break; + /* For other commands, read-only is useful. Most other commands are + running without an input-data-block. */ + default: + scb->command = IM_OTHER_SCSI_CMD_CMD; + scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; + scb->u1.scsi_cmd_length = cmd->cmd_len; + memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); + last_scsi_type(host_index)[ldn] = IM_LONG_SCB; + break; + } + /*issue scb command, and return */ + if (++disk_rw_in_progress == 1) + PS2_DISK_LED_ON (shpnt->host_no, target); + + if (last_scsi_type(host_index)[ldn] == IM_LONG_SCB) { + issue_cmd (host_index, virt_to_bus(scb), IM_LONG_SCB | ldn); + IBM_DS(host_index).long_scbs++; + } else { + issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn); + IBM_DS(host_index).scbs++; + } + return 0; +} + +int ibmmca_abort (Scsi_Cmnd * cmd) +{ + /* Abort does not work, as the adapter never generates an interrupt on + * whatever situation is simulated, even when really pending commands + * are running on the adapters' hardware ! */ + + struct Scsi_Host *shpnt; + unsigned int ldn; + void (*saved_done) (Scsi_Cmnd *); + int target; + int host_index; + int max_pun; + static unsigned long flags; + unsigned long imm_command; + +#ifdef IM_DEBUG_PROBE + printk("IBM MCA SCSI: Abort subroutine called...\n"); +#endif + IBMLOCK + shpnt = cmd->host; + /* search for the right hostadapter */ + for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++); + + if (!hosts[host_index]) { /* invalid hostadapter descriptor address */ + cmd->result = DID_NO_CONNECT << 16; + if (cmd->scsi_done) (cmd->scsi_done) (cmd); + shpnt = cmd->host; + IBMUNLOCK +#ifdef IM_DEBUG_PROBE + printk("IBM MCA SCSI: Abort adapter selection failed!\n"); +#endif + return SCSI_ABORT_SNOOZE; + } + max_pun = subsystem_maxid(host_index); + if (ibm_ansi_order) { + target = max_pun - 1 - cmd->target; + if ((target <= subsystem_pun(host_index))&&(cmd->target <= subsystem_pun(host_index))) + target--; + else if ((target >= subsystem_pun(host_index))&&(cmd->target >= subsystem_pun(host_index))) + target++; + } else + target = cmd->target; + + /* get logical device number, and disable system interrupts */ + printk ("IBM MCA SCSI: Sending abort to device pun=%d, lun=%d.\n", + target, cmd->lun); + ldn = get_ldn(host_index)[target][cmd->lun]; + + /*if cmd for this ldn has already finished, no need to abort */ + if (!ld(host_index)[ldn].cmd) { + IBMUNLOCK + return SCSI_ABORT_NOT_RUNNING; + } + + /* Clear ld.cmd, save done function, install internal done, + * send abort immediate command (this enables sys. interrupts), + * and wait until the interrupt arrives. + */ + saved_done = cmd->scsi_done; + cmd->scsi_done = internal_done; + cmd->SCp.Status = 0; + last_scsi_command(host_index)[ldn] = IM_ABORT_IMM_CMD; + last_scsi_type(host_index)[ldn] = IM_IMM_CMD; + imm_command = inl(IM_CMD_REG(host_index)); + imm_command &= (unsigned long)(0xffff0000); /* mask reserved stuff */ + imm_command |= (unsigned long)(IM_ABORT_IMM_CMD); + /* must wait for attention reg not busy */ + while (1) { + if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY)) + break; + IBMUNLOCK + IBMLOCK + } + /* write registers and enable system interrupts */ + outl (imm_command, IM_CMD_REG(host_index)); + outb (IM_IMM_CMD | ldn, IM_ATTN_REG(host_index)); + IBMUNLOCK +#ifdef IM_DEBUG_PROBE + printk("IBM MCA SCSI: Abort queued to adapter...\n"); +#endif + while (!cmd->SCp.Status) barrier (); + cmd->scsi_done = saved_done; +#ifdef IM_DEBUG_PROBE + printk("IBM MCA SCSI: Abort returned with adapter response...\n"); +#endif + + /*if abort went well, call saved done, then return success or error */ + if (cmd->result == (DID_ABORT << 16)) { + IBMLOCK + cmd->result |= DID_ABORT << 16; + if (cmd->scsi_done) (cmd->scsi_done) (cmd); + ld(host_index)[ldn].cmd = NULL; + IBMUNLOCK +#ifdef IM_DEBUG_PROBE + printk("IBM MCA SCSI: Abort finished with success.\n"); +#endif + return SCSI_ABORT_SUCCESS; + } else { + IBMLOCK + cmd->result |= DID_NO_CONNECT << 16; + if (cmd->scsi_done) (cmd->scsi_done) (cmd); + ld(host_index)[ldn].cmd = NULL; + IBMUNLOCK +#ifdef IM_DEBUG_PROBE + printk("IBM MCA SCSI: Abort failed.\n"); +#endif + return SCSI_ABORT_ERROR; + } +} + +int ibmmca_reset (Scsi_Cmnd * cmd, unsigned int reset_flags) +{ + struct Scsi_Host *shpnt; + Scsi_Cmnd *cmd_aid; + int ticks,i; + int host_index; + static unsigned long flags; + unsigned long imm_command; + + if (cmd == NULL) { + printk("IBM MCA SCSI: Reset called with NULL-command!\n"); + return(SCSI_RESET_SNOOZE); + } + IBMLOCK + ticks = IM_RESET_DELAY*HZ; + shpnt = cmd->host; + /* search for the right hostadapter */ + for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++); + + if (!hosts[host_index]) /* invalid hostadapter descriptor address */ + return SCSI_ABORT_SNOOZE; + + if (local_checking_phase_flag(host_index)) { + printk("IBM MCA SCSI: unable to reset while checking devices.\n"); + IBMUNLOCK + return SCSI_RESET_SNOOZE; + } + + /* issue reset immediate command to subsystem, and wait for interrupt */ + printk("IBM MCA SCSI: resetting all devices.\n"); + reset_status(host_index) = IM_RESET_IN_PROGRESS; + last_scsi_command(host_index)[0xf] = IM_RESET_IMM_CMD; + last_scsi_type(host_index)[0xf] = IM_IMM_CMD; + imm_command = inl(IM_CMD_REG(host_index)); + imm_command &= (unsigned long)(0xffff0000); /* mask reserved stuff */ + imm_command |= (unsigned long)(IM_RESET_IMM_CMD); + /* must wait for attention reg not busy */ + while (1) { + if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY)) + break; + IBMUNLOCK + IBMLOCK + } + /*write registers and enable system interrupts */ + outl (imm_command, IM_CMD_REG(host_index)); + outb (IM_IMM_CMD | 0xf, IM_ATTN_REG(host_index)); + /* wait for interrupt finished or intr_stat register to be set, as the + * interrupt will not be executed, while we are in here! */ + while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks + && ((inb(IM_INTR_REG(host_index)) & 0x8f)!=0x8f)) { + udelay((1+999/HZ)*1000); + barrier(); + } + /* if reset did not complete, just return an error*/ + if (!ticks) { + printk("IBM MCA SCSI: reset did not complete within %d seconds.\n", + IM_RESET_DELAY); + reset_status(host_index) = IM_RESET_FINISHED_FAIL; + IBMUNLOCK + return SCSI_RESET_ERROR; + } + + if ((inb(IM_INTR_REG(host_index)) & 0x8f)==0x8f) { + /* analysis done by this routine and not by the intr-routine */ + if (inb(IM_INTR_REG(host_index))==0xaf) + reset_status(host_index) = IM_RESET_FINISHED_OK_NO_INT; + else if (inb(IM_INTR_REG(host_index))==0xcf) + reset_status(host_index) = IM_RESET_FINISHED_FAIL; + else /* failed, 4get it */ + reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS_NO_INT; + outb (IM_EOI | 0xf, IM_ATTN_REG(host_index)); + } + + /* if reset failed, just return an error */ + if (reset_status(host_index) == IM_RESET_FINISHED_FAIL) { + printk("IBM MCA SCSI: reset failed.\n"); + IBMUNLOCK + return SCSI_RESET_ERROR; + } + + /* so reset finished ok - call outstanding done's, and return success */ + printk ("IBM MCA SCSI: Reset successfully completed.\n"); + IBMUNLOCK + for (i = 0; i < MAX_LOG_DEV; i++) { + cmd_aid = ld(host_index)[i].cmd; + if (cmd_aid && cmd_aid->scsi_done) { + ld(host_index)[i].cmd = NULL; + cmd_aid->result = DID_RESET << 16; + } + } + if (reset_flags & SCSI_RESET_SUGGEST_HOST_RESET) + return (SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET); + else if (reset_flags & SCSI_RESET_SUGGEST_BUS_RESET) + return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET); + else + return SCSI_RESET_SUCCESS; +} + +int ibmmca_biosparam (Disk * disk, kdev_t dev, int *info) +{ + info[0] = 64; + info[1] = 32; + info[2] = disk->capacity / (info[0] * info[1]); + if (info[2] >= 1024) { + info[0] = 128; + info[1] = 63; + info[2] = disk->capacity / (info[0] * info[1]); + if (info[2] >= 1024) { + info[0] = 255; + info[1] = 63; + info[2] = disk->capacity / (info[0] * info[1]); + if (info[2] >= 1024) + info[2] = 1023; + } + } + return 0; +} + +/* calculate percentage of total accesses on a ldn */ +static int ldn_access_load(int host_index, int ldn) +{ + if (IBM_DS(host_index).total_accesses == 0) return (0); + if (IBM_DS(host_index).ldn_access[ldn] == 0) return (0); + return (IBM_DS(host_index).ldn_access[ldn] * 100) / IBM_DS(host_index).total_accesses; +} + +/* calculate total amount of r/w-accesses */ +static int ldn_access_total_read_write(int host_index) +{ + int a; + int i; + + a = 0; + for (i=0; i<=MAX_LOG_DEV; i++) + a+=IBM_DS(host_index).ldn_read_access[i]+IBM_DS(host_index).ldn_write_access[i]; + return(a); +} + +static int ldn_access_total_inquiry(int host_index) +{ + int a; + int i; + + a = 0; + for (i=0; i<=MAX_LOG_DEV; i++) + a+=IBM_DS(host_index).ldn_inquiry_access[i]; + return(a); +} + +static int ldn_access_total_modeselect(int host_index) +{ + int a; + int i; + + a = 0; + for (i=0; i<=MAX_LOG_DEV; i++) + a+=IBM_DS(host_index).ldn_modeselect_access[i]; + return(a); +} + +/* routine to display info in the proc-fs-structure (a deluxe feature) */ +int ibmmca_proc_info (char *buffer, char **start, off_t offset, int length, + int hostno, int inout) +{ + int len=0; + int i,id,lun,host_index; + struct Scsi_Host *shpnt; + unsigned long flags; + int max_pun; + + IBMLOCK + for (i = 0; hosts[i] && hosts[i]->host_no != hostno; i++); + shpnt = hosts[i]; + host_index = i; + if (!shpnt) { + len += sprintf(buffer+len, "\nIBM MCA SCSI: Can't find adapter for host number %d\n", hostno); + return len; + } + max_pun = subsystem_maxid(host_index); + + len += sprintf(buffer+len, "\n IBM-SCSI-Subsystem-Linux-Driver, Version %s\n\n\n", + IBMMCA_SCSI_DRIVER_VERSION); + len += sprintf(buffer+len, " SCSI Access-Statistics:\n"); + len += sprintf(buffer+len, " Device Scanning Order....: %s\n", + (ibm_ansi_order) ? "IBM/ANSI" : "New Industry Standard"); +#ifdef CONFIG_SCSI_MULTI_LUN + len += sprintf(buffer+len, " Multiple LUN probing.....: Yes\n"); +#else + len += sprintf(buffer+len, " Multiple LUN probing.....: No\n"); +#endif + len += sprintf(buffer+len, " This Hostnumber..........: %d\n", + hostno); + len += sprintf(buffer+len, " Base I/O-Port............: 0x%x\n", + (unsigned int)(IM_CMD_REG(host_index))); + len += sprintf(buffer+len, " (Shared) IRQ.............: %d\n", + IM_IRQ); + len += sprintf(buffer+len, " Total Interrupts.........: %d\n", + IBM_DS(host_index).total_interrupts); + len += sprintf(buffer+len, " Total SCSI Accesses......: %d\n", + IBM_DS(host_index).total_accesses); + len += sprintf(buffer+len, " Total short SCBs.........: %d\n", + IBM_DS(host_index).scbs); + len += sprintf(buffer+len, " Total long SCBs..........: %d\n", + IBM_DS(host_index).long_scbs); + len += sprintf(buffer+len, " Total SCSI READ/WRITE..: %d\n", + ldn_access_total_read_write(host_index)); + len += sprintf(buffer+len, " Total SCSI Inquiries...: %d\n", + ldn_access_total_inquiry(host_index)); + len += sprintf(buffer+len, " Total SCSI Modeselects.: %d\n", + ldn_access_total_modeselect(host_index)); + len += sprintf(buffer+len, " Total SCSI other cmds..: %d\n", + IBM_DS(host_index).total_accesses - ldn_access_total_read_write(host_index) + - ldn_access_total_modeselect(host_index) + - ldn_access_total_inquiry(host_index)); + len += sprintf(buffer+len, " Total SCSI command fails.: %d\n\n", + IBM_DS(host_index).total_errors); + len += sprintf(buffer+len, " Logical-Device-Number (LDN) Access-Statistics:\n"); + len += sprintf(buffer+len, " LDN | Accesses [%%] | READ | WRITE | ASSIGNMENTS\n"); + len += sprintf(buffer+len, " -----|--------------|-----------|-----------|--------------\n"); + for (i=0; i<=MAX_LOG_DEV; i++) + len += sprintf(buffer+len, " %2X | %3d | %8d | %8d | %8d\n", + i, ldn_access_load(host_index, i), IBM_DS(host_index).ldn_read_access[i], + IBM_DS(host_index).ldn_write_access[i], IBM_DS(host_index).ldn_assignments[i]); + len += sprintf(buffer+len, " -----------------------------------------------------------\n\n"); + len += sprintf(buffer+len, " Dynamical-LDN-Assignment-Statistics:\n"); + len += sprintf(buffer+len, " Number of physical SCSI-devices..: %d (+ Adapter)\n", + IBM_DS(host_index).total_scsi_devices); + len += sprintf(buffer+len, " Dynamical Assignment necessary...: %s\n", + IBM_DS(host_index).dyn_flag ? "Yes" : "No "); + len += sprintf(buffer+len, " Next LDN to be assigned..........: 0x%x\n", + next_ldn(host_index)); + len += sprintf(buffer+len, " Dynamical assignments done yet...: %d\n", + IBM_DS(host_index).dynamical_assignments); + len += sprintf(buffer+len, "\n Current SCSI-Device-Mapping:\n"); + len += sprintf(buffer+len, " Physical SCSI-Device Map Logical SCSI-Device Map\n"); + len += sprintf(buffer+len, " ID\\LUN 0 1 2 3 4 5 6 7 ID\\LUN 0 1 2 3 4 5 6 7\n"); + for (id=0; id length) len = length; + IBMUNLOCK + return len; +} + +void ibmmca_scsi_setup (char *str, int *ints) +{ + internal_ibmmca_scsi_setup (str, ints); +} + +static int option_setup(char *str) +{ + int ints[IM_MAX_HOSTS]; + char *cur = str; + int i = 1; + + while (cur && isdigit(*cur) && i <= IM_MAX_HOSTS) { + ints[i++] = simple_strtoul(cur, NULL, 0); + if ((cur = strchr(cur,',')) != NULL) cur++; + } + ints[0] = i - 1; + internal_ibmmca_scsi_setup(cur, ints); + return 0; +} + +__setup("ibmmcascsi=", option_setup); + +#ifdef MODULE +/* Eventually this will go into an include file, but this will be later */ +Scsi_Host_Template driver_template = IBMMCA; + +#include "scsi_module.c" +#endif diff --git a/drivers/scsi/ibmmca.h b/drivers/scsi/ibmmca.h index 52cd7386b..d584cb160 100644 --- a/drivers/scsi/ibmmca.h +++ b/drivers/scsi/ibmmca.h @@ -2,21 +2,11 @@ * Low Level Driver for the IBM Microchannel SCSI Subsystem * (Headerfile, see README.ibmmca for description of the IBM MCA SCSI-driver * For use under the GNU public license within the Linux-kernel project. - */ + * This include file works only correctly with kernel 2.4.0 or higher!!! */ #ifndef _IBMMCA_H #define _IBMMCA_H -#ifndef LINUX_VERSION_CODE -#include -#endif - -/* Note to the Linux-toplevel-maintainers: - * This file contains the unified header for all available Linux-distributions. - * For reasons of maintenance, it is recommended to keep this unmodified to - * be downward compatible until I no longer get any requests from people - * using older kernel releases on their PS/2 machines. (23 Apr 2000, M.Lang) */ - /* Common forward declarations for all Linux-versions: */ /* Interfaces to the midlevel Linux SCSI driver */ @@ -32,36 +22,12 @@ extern int ibmmca_biosparam (Disk *, kdev_t, int *); /*structure for /proc filesystem */ extern struct proc_dir_entry proc_scsi_ibmmca; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,75) -/* Stuff for Linux >= 2.1.75: */ /* * 2/8/98 * Note to maintainer of IBMMCA. Do not change this initializer back to * the old format. Please ask eric@andante.jic.com if you have any questions * about this, but it will break things in the future. */ -/*initialization for Scsi_host_template type (Linux >= 2.1.75 && < 2.3.27) */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,27) -#define IBMMCA { \ - proc_dir: &proc_scsi_ibmmca, /*proc_dir*/ \ - proc_info: ibmmca_proc_info, /*proc info fn*/ \ - name: "IBM SCSI-Subsystem", /*name*/ \ - detect: ibmmca_detect, /*detect fn*/ \ - release: ibmmca_release, /*release fn*/ \ - command: ibmmca_command, /*command fn*/ \ - queuecommand: ibmmca_queuecommand, /*queuecommand fn*/ \ - abort: ibmmca_abort, /*abort fn*/ \ - reset: ibmmca_reset, /*reset fn*/ \ - bios_param: ibmmca_biosparam, /*bios fn*/ \ - can_queue: 16, /*can_queue*/ \ - this_id: 7, /*set by detect*/ \ - sg_tablesize: 16, /*sg_tablesize*/ \ - cmd_per_lun: 1, /*cmd_per_lun*/ \ - unchecked_isa_dma: 0, /*32-Bit Busmaster */ \ - use_clustering: ENABLE_CLUSTERING /*use_clustering*/ \ - } -#else #define IBMMCA { \ proc_name: "ibmmca", /*proc_name*/ \ proc_info: ibmmca_proc_info, /*proc info fn*/ \ @@ -80,34 +46,5 @@ extern struct proc_dir_entry proc_scsi_ibmmca; unchecked_isa_dma: 0, /*32-Bit Busmaster */ \ use_clustering: ENABLE_CLUSTERING /*use_clustering*/ \ } -#endif -#else -/* Stuff for Linux < 2.1.75: */ - -/*initialization for Scsi_host_template type (Linux < 2.1.75) */ -#define IBMMCA { \ - NULL, /*next*/ \ - NULL, /*usage_count*/ \ - &proc_scsi_ibmmca, /*proc_dir*/ \ - ibmmca_proc_info, /*proc info fn*/ \ - "IBM SCSI-Subsystem", /*name*/ \ - ibmmca_detect, /*detect fn*/ \ - ibmmca_release, /*release fn*/ \ - NULL, /*info fn*/ \ - ibmmca_command, /*command fn*/ \ - ibmmca_queuecommand, /*queuecommand fn*/ \ - ibmmca_abort, /*abort fn*/ \ - ibmmca_reset, /*reset fn*/ \ - NULL, /*slave_attach fn*/ \ - ibmmca_biosparam, /*bios fn*/ \ - 16, /*can_queue*/ \ - 7, /*set by detect*/ \ - 16, /*sg_tablesize*/ \ - 1, /*cmd_per_lun*/ \ - 0, /*present*/ \ - 0, /*unchecked_isa_dma*/ \ - ENABLE_CLUSTERING /*use_clustering*/ \ - } -#endif /* kernelversion selection */ #endif /* _IBMMCA_H */ diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 2eca1b673..07eb52008 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -16,14 +16,15 @@ Copyright 1992 - 2000 Kai Makisara email Kai.Makisara@metla.fi - $Header: /home/cvsroot/Driver/osst.c,v 1.49 2000/12/20 02:56:01 garloff Exp $ + $Header: /home/cvsroot/Driver/osst.c,v 1.51 2000/12/22 20:48:27 garloff Exp $ + Microscopic alterations - Rik Ling, 2000/12/21 Last modified: Wed Feb 2 22:04:05 2000 by makisara@kai.makisara.local Some small formal changes - aeb, 950809 */ -static const char * cvsid = "$Id: osst.c,v 1.49 2000/12/20 02:56:01 garloff Exp $"; -const char * osst_version = "0.9.4.2"; +static const char * cvsid = "$Id: osst.c,v 1.51 2000/12/22 20:48:27 garloff Exp $"; +const char * osst_version = "0.9.4.3"; /* The "failure to reconnect" firmware bug */ #define OSST_FW_NEED_POLL_MIN 10602 /*(107A)*/ @@ -44,6 +45,7 @@ const char * osst_version = "0.9.4.2"; #include #include #include +#include #include #include #include @@ -73,6 +75,11 @@ const char * osst_version = "0.9.4.2"; #include "constants.h" +static int buffer_kbs = 0; +static int write_threshold_kbs = 0; +static int max_buffers = 0; +static int max_sg_segs = 0; + #ifdef MODULE MODULE_AUTHOR("Willem Riede"); MODULE_DESCRIPTION("OnStream SCSI Tape Driver"); @@ -80,10 +87,6 @@ MODULE_PARM(buffer_kbs, "i"); MODULE_PARM(write_threshold_kbs, "i"); MODULE_PARM(max_buffers, "i"); MODULE_PARM(max_sg_segs, "i"); -static int buffer_kbs = 0; -static int write_threshold_kbs = 0; -static int max_buffers = 0; -static int max_sg_segs = 0; #else static struct osst_dev_parm { char *name; @@ -92,7 +95,8 @@ static struct osst_dev_parm { { "buffer_kbs", &buffer_kbs }, { "write_threshold_kbs", &write_threshold_kbs }, { "max_buffers", &max_buffers }, - { "max_sg_segs", &max_sg_segs }; + { "max_sg_segs", &max_sg_segs } + }; #endif /* Some default definitions have been moved to osst_options.h */ @@ -4932,22 +4936,62 @@ static int osst_copy_from_buffer(OSST_buffer *st_bp, unsigned char *ptr) /* Module housekeeping */ +static void validate_options (void) +{ + if (buffer_kbs > 0) + osst_buffer_size = buffer_kbs * ST_KILOBYTE; + if (write_threshold_kbs > 0) + osst_write_threshold = write_threshold_kbs * ST_KILOBYTE; + if (osst_write_threshold > osst_buffer_size) + osst_write_threshold = osst_buffer_size; + if (max_buffers > 0) + osst_max_buffers = max_buffers; + if (max_sg_segs >= OSST_FIRST_SG) + osst_max_sg_segs = max_sg_segs; + printk(KERN_INFO "osst: bufsize %d, wrt %d, max buffers %d, s/g segs %d.\n", + osst_buffer_size, osst_write_threshold, osst_max_buffers, osst_max_sg_segs); +//printk(OSST_DEB_MSG "osst: sizeof(header) = %d (%s)\n",sizeof(os_header_t),sizeof(os_header_t)==OS_DATA_SIZE?"ok":"error"); +} + #ifndef MODULE -/* Set the boot options. Syntax: st=xxx,yyy +/* Set the boot options. Syntax: osst=xxx,yyy,... where xxx is buffer size in 1024 byte blocks and yyy is write threshold in 1024 byte blocks. */ -__initfunc( void osst_setup(char *str, int *ints)) +static int __init osst_setup (char *str) { - if (ints[0] > 0 && ints[1] > 0) - osst_buffer_size = ints[1] * ST_KILOBYTE; - if (ints[0] > 1 && ints[2] > 0) { - osst_write_threshold = ints[2] * ST_KILOBYTE; - if (osst_write_threshold > osst_buffer_size) - osst_write_threshold = osst_buffer_size; + int i, ints[5]; + char *stp; + + stp = get_options(str, ARRAY_SIZE(ints), ints); + + if (ints[0] > 0) { + for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++) + *parms[i].val = ints[i + 1]; + } else { + while (stp != NULL) { + for (i = 0; i < ARRAY_SIZE(parms); i++) { + int len = strlen(parms[i].name); + if (!strncmp(stp, parms[i].name, len) && + (*(stp + len) == ':' || *(stp + len) == '=')) { + *parms[i].val = + simple_strtoul(stp + len + 1, NULL, 0); + break; + } + } + if (i >= sizeof(parms) / sizeof(struct osst_dev_parm)) + printk(KERN_WARNING "osst: illegal parameter in '%s'\n", + stp); + stp = strchr(stp, ','); + if (stp) + stp++; + } } - if (ints[0] > 2 && ints[3] > 0) - osst_max_buffers = ints[3]; + + return 1; } + +__setup("osst=", osst_setup); + #endif @@ -5240,30 +5284,11 @@ static void osst_detach(Scsi_Device * SDp) return; } - static int __init init_osst(void) { - int result; - - if (buffer_kbs > 0) - osst_buffer_size = buffer_kbs * ST_KILOBYTE; - if (write_threshold_kbs > 0) - osst_write_threshold = write_threshold_kbs * ST_KILOBYTE; - if (osst_write_threshold > osst_buffer_size) - osst_write_threshold = osst_buffer_size; - if (max_buffers > 0) - osst_max_buffers = max_buffers; - if (max_sg_segs >= OSST_FIRST_SG) - osst_max_sg_segs = max_sg_segs; - printk(KERN_INFO "osst: bufsize %d, wrt %d, max buffers %d, s/g segs %d.\n", - osst_buffer_size, osst_write_threshold, osst_max_buffers, osst_max_sg_segs); -//printk(OSST_DEB_MSG "osst: sizeof(header) = %d (%s)\n",sizeof(os_header_t),sizeof(os_header_t)==OS_DATA_SIZE?"ok":"error"); + validate_options(); osst_template.module = THIS_MODULE; - result = scsi_register_module(MODULE_SCSI_DEV, &osst_template); - if (result) - return result; - - return 0; + return scsi_register_module(MODULE_SCSI_DEV, &osst_template); } static void __exit exit_osst (void) diff --git a/drivers/scsi/scsiiom.c b/drivers/scsi/scsiiom.c dissimilarity index 94% index 3923cb8e4..5d0520234 100644 --- a/drivers/scsi/scsiiom.c +++ b/drivers/scsi/scsiiom.c @@ -1,1608 +1,1790 @@ -/*********************************************************************** - * FILE NAME : SCSIIOM.C * - * BY : C.L. Huang, ching@tekram.com.tw * - * Description: Device Driver for Tekram DC-390 (T) PCI SCSI * - * Bus Master Host Adapter * - ***********************************************************************/ -/* $Id: scsiiom.c,v 2.15 1998/12/25 17:33:27 garloff Exp $ */ - -UCHAR -dc390_StartSCSI(PACB pACB, PDCB pDCB, PSRB pSRB) -{ - USHORT wlval; - UCHAR bval, bval1; - - pSRB->TagNumber = 31; - DC390_write8(Scsi_Dest_ID, pDCB->UnitSCSIID); - DC390_write8(Sync_Period, pDCB->SyncPeriod); - DC390_write8(Sync_Offset, pDCB->SyncOffset); - DC390_write8(CtrlReg1, pDCB->CtrlR1); - DC390_write8(CtrlReg3, pDCB->CtrlR3); - DC390_write8(CtrlReg4, pDCB->CtrlR4); - DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); /* Flush FIFO */ - DEBUG1(printk(KERN_INFO "DC390: Start SCSI command: %02x (Sync:%02x)\n", \ - pSRB->CmdBlock[0], pDCB->SyncMode); - ) - pSRB->ScsiPhase = SCSI_NOP0; - //pSRB->MsgOutBuf[0] = MSG_NOP; - //pSRB->MsgCnt = 0; - bval = pDCB->IdentifyMsg; - if (!(pDCB->SyncMode & EN_ATN_STOP)) { /* Don't always try send Extended messages on arbitration */ - if ((pSRB->CmdBlock[0] == INQUIRY) || - (pSRB->CmdBlock[0] == REQUEST_SENSE) || - (pSRB->SRBFlag & AUTO_REQSENSE)) { - bval &= 0xBF; /* No DisConn */ - DC390_write8(ScsiFifo, bval); - bval1 = SEL_W_ATN; - pSRB->SRBState = SRB_START_; - DEBUG1(printk(KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1); - ) - if (pDCB->SyncMode & SYNC_ENABLE) { - if (!(pDCB->IdentifyMsg & 7) || /* LUN == 0 || Cmd != INQUIRY */ - (pSRB->CmdBlock[0] != INQUIRY)) { - bval1 = SEL_W_ATN_STOP; /* Try to establish SYNC nego */ - pSRB->SRBState = SRB_MSGOUT; - } - } - } else { /* TagQ ? */ - DC390_write8(ScsiFifo, bval); - if (pDCB->SyncMode & EN_TAG_QUEUEING) { - DC390_write8(ScsiFifo, MSG_SIMPLE_QTAG); - DEBUG1(printk(KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval & 0x40 ? "" : "No "), bval, SEL_W_ATN3, pDCB->TagMask); - ) - bval = 0; - wlval = 1; - while (wlval & pDCB->TagMask) { - bval++; - wlval <<= 1; - }; - pDCB->TagMask |= wlval; - DC390_write8(ScsiFifo, bval); - pSRB->TagNumber = bval; - DEBUG1(printk(KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval); - ) - bval1 = SEL_W_ATN3; - pSRB->SRBState = SRB_START_; - } else { /* No TagQ */ - bval1 = SEL_W_ATN; - DEBUG1(printk(KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval & 0x40 ? "" : "No "), bval, bval1, pDCB->TagMask); - ) - pSRB->SRBState = SRB_START_; - } - } - - } else { /* ATN_STOP: Always try to establish Sync nego */ - if ((pSRB->CmdBlock[0] == INQUIRY) || - (pSRB->CmdBlock[0] == REQUEST_SENSE) || - (pSRB->SRBFlag & AUTO_REQSENSE)) { - bval &= 0xBF; /* No DisConn */ - DC390_write8(ScsiFifo, bval); - bval1 = SEL_W_ATN; - DEBUG1(printk(KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1); - ) - pSRB->SRBState = SRB_START_; - /* ??? */ - if (pDCB->SyncMode & SYNC_ENABLE) { - if (!(pDCB->IdentifyMsg & 7) || /* LUN == 0 || Cmd != INQUIRY */ - (pSRB->CmdBlock[0] != INQUIRY)) { - bval1 = SEL_W_ATN_STOP; /* Try to establish Sync nego */ - pSRB->SRBState = SRB_MSGOUT; - } - } - } else { /* TagQ ? */ - DC390_write8(ScsiFifo, bval); - if (pDCB->SyncMode & EN_TAG_QUEUEING) { - pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG; - DEBUG1(printk(KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval & 0x40 ? "" : "No "), bval, SEL_W_ATN_STOP, pDCB->TagMask); - ) - bval = 0; - wlval = 1; - while (wlval & pDCB->TagMask) { - bval++; - wlval <<= 1; - }; - pDCB->TagMask |= wlval; - pSRB->TagNumber = bval; - DEBUG1(printk(KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval); - ) - pSRB->MsgOutBuf[1] = bval; - pSRB->MsgCnt = 2; - bval1 = SEL_W_ATN_STOP; - pSRB->SRBState = SRB_START_; /* ?? */ - } else { /* No TagQ */ - pSRB->MsgOutBuf[0] = MSG_NOP; - pSRB->MsgCnt = 1; - pSRB->SRBState = SRB_START_; - bval1 = SEL_W_ATN_STOP; - DEBUG1(printk(KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval & 0x40 ? "" : "No "), bval, bval1, pDCB->TagMask); - ) - }; - } - } - if (bval1 != SEL_W_ATN_STOP) { /* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */ - if (pSRB->SRBFlag & AUTO_REQSENSE) { - bval = 0; - DC390_write8(ScsiFifo, REQUEST_SENSE); - DC390_write8(ScsiFifo, pDCB->IdentifyMsg << 5); - DC390_write8(ScsiFifo, bval); - DC390_write8(ScsiFifo, bval); - DC390_write8(ScsiFifo, sizeof(pSRB->pcmd->sense_buffer)); - DC390_write8(ScsiFifo, bval); - DEBUG1(printk(KERN_DEBUG "DC390: AutoReqSense !\n"); - ) - } else { /* write cmnd to bus */ - PUCHAR ptr; - UCHAR i; - ptr = (PUCHAR) pSRB->CmdBlock; - for (i = 0; i < pSRB->ScsiCmdLen; i++) - DC390_write8(ScsiFifo, *(ptr++)); - }; - } - /* Check if we can't win arbitration */ - if (DC390_read8(Scsi_Status) & INTERRUPT) { - pSRB->SRBState = SRB_READY; - pDCB->TagMask &= ~(1 << pSRB->TagNumber); - DEBUG0(printk(KERN_WARNING "DC390: Interrupt during StartSCSI!\n"); - ) - return 1; - } else { - pSRB->ScsiPhase = SCSI_NOP1; - DEBUG0(if (pACB->pActiveDCB) \ - printk(KERN_WARNING "DC390: ActiveDCB != 0\n");) - DEBUG0(if (pDCB->pActiveSRB) \ - printk(KERN_WARNING "DC390: ActiveSRB != 0\n");) - pACB->pActiveDCB = pDCB; - pDCB->pActiveSRB = pSRB; - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); - DC390_write8(ScsiCmd, bval1); - return 0; - } -} - -//#define DMA_INT EN_DMA_INT /*| EN_PAGE_INT*/ -#define DMA_INT 0 - -#if DMA_INT -/* This is similar to AM53C974.c ... */ -static UCHAR - dc390_dma_intr(PACB pACB) -{ - PSRB pSRB; - UCHAR dstate; - DEBUG0(USHORT pstate; - PDEVDECL1; - ) - DEBUG0(PDEVSET1; - ) - DEBUG0(PCI_READ_CONFIG_WORD(PDEV, PCI_STATUS, &pstate); - ) - DEBUG0(if (pstate & (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY)) \ - { - printk(KERN_WARNING "DC390: PCI state = %04x!\n", pstate); \ - PCI_WRITE_CONFIG_WORD(PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY)); - }; - ) - dstate = DC390_read8(DMA_Status); - - if (!pACB->pActiveDCB || !pACB->pActiveDCB->pActiveSRB) - return dstate; - else - pSRB = pACB->pActiveDCB->pActiveSRB; - - if (dstate & (DMA_XFER_ABORT | DMA_XFER_ERROR | POWER_DOWN | PCI_MS_ABORT)) { - printk(KERN_ERR "DC390: DMA error (%02x)!\n", dstate); - return dstate; - }; - if (dstate & DMA_XFER_DONE) { - ULONG residual, xferCnt; - int ctr = 5000000; - if (!(DC390_read8(DMA_Cmd) & READ_DIRECTION)) { - do { - DEBUG1(printk(KERN_DEBUG "DC390: read residual bytes ... \n"); - ) - dstate = DC390_read8(DMA_Status); - residual = DC390_read8(CtcReg_Low) | DC390_read8(CtcReg_Mid) << 8 | - DC390_read8(CtcReg_High) << 16; - residual += DC390_read8(Current_Fifo) & 0x1f; - } while (residual && !(dstate & SCSI_INTERRUPT) && --ctr); - if (!ctr) - printk(KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32(DMA_Wk_ByteCntr)); - /* residual = ... */ - } else - residual = 0; - - /* ??? */ - - xferCnt = pSRB->SGToBeXferLen - residual; - pSRB->SGBusAddr += xferCnt; - pSRB->TotalXferredLen += xferCnt; - pSRB->SGToBeXferLen = residual; -#ifdef DC390_DEBUG0 - printk(KERN_INFO "DC390: DMA: residual = %i, xfer = %i\n", - (unsigned int) residual, (unsigned int) xferCnt); -#endif - - DC390_write8(DMA_Cmd, DMA_IDLE_CMD); - } - dc390_laststatus &= ~0xff000000; - dc390_laststatus |= dstate << 24; - return dstate; -}; -#endif - -void __inline__ - DC390_Interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - PACB pACB; - PDCB pDCB; - PSRB pSRB; - UCHAR sstatus = 0; - UCHAR phase, i; - void (*stateV) (PACB, PSRB, PUCHAR); - UCHAR istate, istatus; -#if DMA_INT - UCHAR dstatus; -#endif - DC390_AFLAGS DC390_IFLAGS DC390_DFLAGS - - pACB = dc390_pACB_start; - - if (pACB == 0) { - printk(KERN_WARNING "DC390: Interrupt on uninitialized adapter!\n"); - return; - } - DC390_LOCK_DRV; - - for (i = 0; i < dc390_adapterCnt; i++) { - if (pACB->IRQLevel == (UCHAR) irq) { - sstatus = DC390_read8(Scsi_Status); - if (sstatus & INTERRUPT) - break; - else - pACB = pACB->pNextACB; - } else { - pACB = pACB->pNextACB; - } - } - - DEBUG1(printk(KERN_DEBUG "sstatus=%02x,", sstatus); - ) - if (!pACB) { - DC390_UNLOCK_DRV; - return; - }; - -#if DMA_INT - DC390_LOCK_IO; - DC390_LOCK_ACB; - dstatus = dc390_dma_intr(pACB); - DC390_UNLOCK_ACB; - DC390_UNLOCK_IO; - - DEBUG1(printk(KERN_DEBUG "dstatus=%02x,", dstatus); - ) - if (!(dstatus & SCSI_INTERRUPT)) { - DEBUG0(printk(KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n"); - ) - DC390_UNLOCK_DRV; - return; - }; -#else - //DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT); - //dstatus = DC390_read8 (DMA_Status); - //DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT); -#endif - - DC390_LOCK_IO; - DC390_LOCK_ACB; - DC390_UNLOCK_DRV_NI; /* Allow _other_ CPUs to process IRQ (useful for shared IRQs) */ - - istate = DC390_read8(Intern_State); - istatus = DC390_read8(INT_Status); /* This clears Scsi_Status, Intern_State and INT_Status ! */ - - DEBUG1(printk(KERN_INFO "Istatus(Res,Inv,Dis,Serv,Succ,ReS,SelA,Sel)=%02x,", istatus); - ) - dc390_laststatus &= ~0x00ffffff; - dc390_laststatus |= /* dstatus<<24 | */ sstatus << 16 | istate << 8 | istatus; - - if (sstatus & ILLEGAL_OP_ERR) { - printk("DC390: Illegal Operation detected (%08lx)!\n", dc390_laststatus); - dc390_dumpinfo(pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB); - }; - - if (istatus & DISCONNECTED) { - dc390_Disconnect(pACB); - goto unlock; - } - if (istatus & RESELECTED) { - dc390_Reselect(pACB); - goto unlock; - } - if (istatus & (SUCCESSFUL_OP | SERVICE_REQUEST)) { - pDCB = pACB->pActiveDCB; - if (!pDCB) { - printk(KERN_ERR "DC390: Suc. op/ Serv. req: pActiveDCB = 0!\n"); - goto unlock; - }; - pSRB = pDCB->pActiveSRB; - if (pDCB->DCBFlag & ABORT_DEV_) - dc390_EnableMsgOut_Abort(pACB, pSRB); - - phase = pSRB->ScsiPhase; - DEBUG1(printk(KERN_INFO "DC390: [%i]%s(0) (%02x)\n", phase, dc390_p0_str[phase], sstatus); - ) - stateV = (void *) dc390_phase0[phase]; - (*stateV) (pACB, pSRB, &sstatus); - - pSRB->ScsiPhase = sstatus & 7; - phase = (UCHAR) sstatus & 7; - DEBUG1(printk(KERN_INFO "DC390: [%i]%s(1) (%02x)\n", phase, dc390_p1_str[phase], sstatus); - ) - stateV = (void *) dc390_phase1[phase]; - (*stateV) (pACB, pSRB, &sstatus); - goto unlock; - } - if (istatus & INVALID_CMD) { - dc390_InvalidCmd(pACB); - goto unlock; - } - if (istatus & SCSI_RESET) { - dc390_ScsiRstDetect(pACB); - goto unlock; - } - unlock: - DC390_LOCK_DRV_NI; - DC390_UNLOCK_ACB; - DC390_UNLOCK_IO; - DC390_UNLOCK_DRV; /* Restore initial flags */ -} - -void do_DC390_Interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - DEBUG1(printk(KERN_INFO "DC390: Irq (%i) caught: ", irq); - ) - /* Locking is done in DC390_Interrupt */ - DC390_Interrupt(irq, dev_id, regs); - DEBUG1(printk(".. IRQ returned\n"); - ) -} - -void dc390_DataOut_0(PACB pACB, PSRB pSRB, PUCHAR psstatus) -{ - UCHAR sstatus; - PSGL psgl; - ULONG ResidCnt, xferCnt; - UCHAR dstate = 0; - - sstatus = *psstatus; - - if (!(pSRB->SRBState & SRB_XFERPAD)) { - if (sstatus & (PARITY_ERR | ILLEGAL_OP_ERR)) - pSRB->SRBStatus |= PARITY_ERROR; - - if (sstatus & COUNT_2_ZERO) { - int ctr = 5000000; /* only try for about a tenth of a second */ - while (--ctr && !((dstate = DC390_read8(DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen); - if (!ctr) - printk(KERN_CRIT "DC390: Deadlock in DataOut_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32(DMA_Wk_ByteCntr)); - dc390_laststatus &= ~0xff000000; - dc390_laststatus |= dstate << 24; - pSRB->TotalXferredLen += pSRB->SGToBeXferLen; - pSRB->SGIndex++; - if (pSRB->SGIndex < pSRB->SGcount) { - pSRB->pSegmentList++; - psgl = pSRB->pSegmentList; - - pSRB->SGBusAddr = virt_to_bus(psgl->address); - pSRB->SGToBeXferLen = (ULONG) psgl->length; - } else - pSRB->SGToBeXferLen = 0; - } else { - ResidCnt = (ULONG) DC390_read8(Current_Fifo) & 0x1f; - ResidCnt |= (ULONG) DC390_read8(CtcReg_High) << 16; - ResidCnt |= (ULONG) DC390_read8(CtcReg_Mid) << 8; - ResidCnt += (ULONG) DC390_read8(CtcReg_Low); - - xferCnt = pSRB->SGToBeXferLen - ResidCnt; - pSRB->SGBusAddr += xferCnt; - pSRB->TotalXferredLen += xferCnt; - pSRB->SGToBeXferLen = ResidCnt; - } - } - DC390_write8(DMA_Cmd, WRITE_DIRECTION + DMA_IDLE_CMD); /* | DMA_INT */ -} - -void dc390_DataIn_0(PACB pACB, PSRB pSRB, PUCHAR psstatus) -{ - UCHAR sstatus, residual, bval; - PSGL psgl; - ULONG ResidCnt, xferCnt, i; - PUCHAR ptr; - - sstatus = *psstatus; - - if (!(pSRB->SRBState & SRB_XFERPAD)) { - if (sstatus & (PARITY_ERR | ILLEGAL_OP_ERR)) - pSRB->SRBStatus |= PARITY_ERROR; - - if (sstatus & COUNT_2_ZERO) { - int ctr = 5000000; /* only try for about a tenth of a second */ - int dstate = 0; - while (--ctr && !((dstate = DC390_read8(DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen); - if (!ctr) - printk(KERN_CRIT "DC390: Deadlock in DataIn_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32(DMA_Wk_ByteCntr)); - if (!ctr) - printk(KERN_CRIT "DC390: DataIn_0: DMA State: %i\n", dstate); - dc390_laststatus &= ~0xff000000; - dc390_laststatus |= dstate << 24; - DEBUG1(ResidCnt = ((ULONG) DC390_read8(CtcReg_High) << 16) \ - +((ULONG) DC390_read8(CtcReg_Mid) << 8) \ - +((ULONG) DC390_read8(CtcReg_Low)); - ) - DEBUG1(printk(KERN_DEBUG "Count_2_Zero (ResidCnt=%li,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen); - ) - DC390_write8(DMA_Cmd, READ_DIRECTION + DMA_IDLE_CMD); /* | DMA_INT */ - - pSRB->TotalXferredLen += pSRB->SGToBeXferLen; - pSRB->SGIndex++; - if (pSRB->SGIndex < pSRB->SGcount) { - pSRB->pSegmentList++; - psgl = pSRB->pSegmentList; - - pSRB->SGBusAddr = virt_to_bus(psgl->address); - pSRB->SGToBeXferLen = (ULONG) psgl->length; - } else - pSRB->SGToBeXferLen = 0; - } else { /* phase changed */ - residual = 0; - bval = DC390_read8(Current_Fifo); - while (bval & 0x1f) { - DEBUG1(printk(KERN_DEBUG "Check for residuals,"); - ) - if ((bval & 0x1f) == 1) { - for (i = 0; i < 0x100; i++) { - bval = DC390_read8(Current_Fifo); - if (!(bval & 0x1f)) - goto din_1; - else if (i == 0x0ff) { - residual = 1; /* ;1 residual byte */ - goto din_1; - } - } - } else - bval = DC390_read8(Current_Fifo); - } - din_1: - DC390_write8(DMA_Cmd, READ_DIRECTION + DMA_BLAST_CMD); - for (i = 0xa000; i; i--) { - bval = DC390_read8(DMA_Status); - if (bval & BLAST_COMPLETE) - break; - } - /* It seems a DMA Blast abort isn't that bad ... */ - if (!i) - printk(KERN_ERR "DC390: DMA Blast aborted unfinished!\n"); - //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ - dc390_laststatus &= ~0xff000000; - dc390_laststatus |= bval << 24; - - DEBUG1(printk(KERN_DEBUG "Blast: Read %li times DMA_Status %02x", 0xa000 - i, bval); - ) - ResidCnt = (ULONG) DC390_read8(CtcReg_High); - ResidCnt <<= 8; - ResidCnt |= (ULONG) DC390_read8(CtcReg_Mid); - ResidCnt <<= 8; - ResidCnt |= (ULONG) DC390_read8(CtcReg_Low); - - xferCnt = pSRB->SGToBeXferLen - ResidCnt; - pSRB->SGBusAddr += xferCnt; - pSRB->TotalXferredLen += xferCnt; - pSRB->SGToBeXferLen = ResidCnt; - - if (residual) { - bval = DC390_read8(ScsiFifo); /* get one residual byte */ - ptr = (PUCHAR) bus_to_virt(pSRB->SGBusAddr); - *ptr = bval; - pSRB->SGBusAddr++; - xferCnt++; - pSRB->TotalXferredLen++; - pSRB->SGToBeXferLen--; - } - DEBUG1(printk(KERN_DEBUG "Xfered: %li, Total: %li, Remaining: %li\n", xferCnt, \ - pSRB->TotalXferredLen, pSRB->SGToBeXferLen); - ) - } - } -} - -static void dc390_Command_0(PACB pACB, PSRB pSRB, PUCHAR psstatus) -{ -} - -static void dc390_Status_0(PACB pACB, PSRB pSRB, PUCHAR psstatus) -{ - - pSRB->TargetStatus = DC390_read8(ScsiFifo); - //udelay (1); - pSRB->EndMessage = DC390_read8(ScsiFifo); /* get message */ - - *psstatus = SCSI_NOP0; - pSRB->SRBState = SRB_COMPLETED; - DC390_write8(ScsiCmd, MSG_ACCEPTED_CMD); -} - -static void dc390_MsgOut_0(PACB pACB, PSRB pSRB, PUCHAR psstatus) -{ - if (pSRB->SRBState & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT)) - *psstatus = SCSI_NOP0; - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); -} - - -static void __inline__ - dc390_reprog(PACB pACB, PDCB pDCB) -{ - DC390_write8(Sync_Period, pDCB->SyncPeriod); - DC390_write8(Sync_Offset, pDCB->SyncOffset); - DC390_write8(CtrlReg3, pDCB->CtrlR3); - DC390_write8(CtrlReg4, pDCB->CtrlR4); - dc390_SetXferRate(pACB, pDCB); -}; - - -#ifdef DC390_DEBUG0 -static void dc390_printMsg(UCHAR * MsgBuf, UCHAR len) -{ - int i; - printk(" %02x", MsgBuf[0]); - for (i = 1; i < len; i++) - printk(" %02x", MsgBuf[i]); - printk("\n"); -}; -#endif - -#define DC390_ENABLE_MSGOUT DC390_write8 (ScsiCmd, SET_ATN_CMD) - -/* reject_msg */ -static void __inline__ - dc390_MsgIn_reject(PACB pACB, PSRB pSRB) -{ - pSRB->MsgOutBuf[0] = MSG_REJECT_; - pSRB->MsgCnt = 1; - DC390_ENABLE_MSGOUT; - DEBUG0(printk(KERN_INFO "DC390: Reject message\n"); - ) -} - -/* abort command */ -static void __inline__ - dc390_EnableMsgOut_Abort(PACB pACB, PSRB pSRB) -{ - pSRB->MsgOutBuf[0] = MSG_ABORT; - pSRB->MsgCnt = 1; - DC390_ENABLE_MSGOUT; - pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_; -} - -static PSRB - dc390_MsgIn_QTag(PACB pACB, PDCB pDCB, UCHAR tag) -{ - PSRB lastSRB = pDCB->pGoingLast; - PSRB pSRB = pDCB->pGoingSRB; - - if (pSRB) { - for (; pSRB;) { - if (pSRB->TagNumber == tag) - break; - if (pSRB == lastSRB) - goto mingx0; - pSRB = pSRB->pNextSRB; - } - - if (pDCB->DCBFlag & ABORT_DEV_) { - pSRB->SRBState = SRB_ABORT_SENT; - dc390_EnableMsgOut_Abort(pACB, pSRB); - } - if (!(pSRB->SRBState & SRB_DISCONNECT)) - goto mingx0; - - pDCB->pActiveSRB = pSRB; - pSRB->SRBState = SRB_DATA_XFER; - } else { - mingx0: - pSRB = pACB->pTmpSRB; - pSRB->SRBState = SRB_UNEXPECT_RESEL; - pDCB->pActiveSRB = pSRB; - pSRB->MsgOutBuf[0] = MSG_ABORT_TAG; - pSRB->MsgCnt = 1; - DC390_ENABLE_MSGOUT; - } - return pSRB; -} - - -/* set async transfer mode */ -static void dc390_MsgIn_set_async(PACB pACB, PSRB pSRB) -{ - PDCB pDCB = pSRB->pSRBDCB; - if (!(pSRB->SRBState & DO_SYNC_NEGO)) - printk("DC390: Target %i initiates Non-Sync?\n", pDCB->UnitSCSIID); - pSRB->SRBState &= ~DO_SYNC_NEGO; - pDCB->SyncMode &= ~(SYNC_ENABLE + SYNC_NEGO_DONE); - pDCB->SyncPeriod = 0; - pDCB->SyncOffset = 0; - //pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */ - pDCB->CtrlR3 = FAST_CLK; /* fast clock / normal scsi */ - pDCB->CtrlR4 &= 0x3f; - pDCB->CtrlR4 |= pACB->glitch_cfg; /* glitch eater */ - dc390_reprog(pACB, pDCB); -} - -/* set sync transfer mode */ -static void dc390_MsgIn_set_sync(PACB pACB, PSRB pSRB) -{ - UCHAR bval; - USHORT wval, wval1; - PDCB pDCB = pSRB->pSRBDCB; - UCHAR oldsyncperiod = pDCB->SyncPeriod; - UCHAR oldsyncoffset = pDCB->SyncOffset; - - if (!(pSRB->SRBState & DO_SYNC_NEGO)) { - printk("DC390: Target %i initiates Sync: %ins %i ... answer ...\n", - pDCB->UnitSCSIID, pSRB->MsgInBuf[3] << 2, pSRB->MsgInBuf[4]); - - /* reject */ - //dc390_MsgIn_reject (pACB, pSRB); - //return dc390_MsgIn_set_async (pACB, pSRB); - - /* Reply with corrected SDTR Message */ - if (pSRB->MsgInBuf[4] > 15) { - printk("DC390: Lower Sync Offset to 15\n"); - pSRB->MsgInBuf[4] = 15; - } - if (pSRB->MsgInBuf[3] < pDCB->NegoPeriod) { - printk("DC390: Set sync nego period to %ins\n", pDCB->NegoPeriod << 2); - pSRB->MsgInBuf[3] = pDCB->NegoPeriod; - }; - memcpy(pSRB->MsgOutBuf, pSRB->MsgInBuf, 5); - pSRB->MsgCnt = 5; - DC390_ENABLE_MSGOUT; - }; - - pSRB->SRBState &= ~DO_SYNC_NEGO; - pDCB->SyncMode |= SYNC_ENABLE + SYNC_NEGO_DONE; - pDCB->SyncOffset &= 0x0f0; - pDCB->SyncOffset |= pSRB->MsgInBuf[4]; - pDCB->NegoPeriod = pSRB->MsgInBuf[3]; - - wval = (USHORT) pSRB->MsgInBuf[3]; - wval = wval << 2; - wval -= 3; - wval1 = wval / 25; /* compute speed */ - if ((wval1 * 25) != wval) - wval1++; - bval = FAST_CLK + FAST_SCSI; /* fast clock / fast scsi */ - - pDCB->CtrlR4 &= 0x3f; /* Glitch eater: 12ns less than normal */ - if (pACB->glitch_cfg != NS_TO_GLITCH(0)) - pDCB->CtrlR4 |= NS_TO_GLITCH(((GLITCH_TO_NS(pACB->glitch_cfg)) - 1)); - else - pDCB->CtrlR4 |= NS_TO_GLITCH(0); - if (wval1 < 4) - pDCB->CtrlR4 |= NS_TO_GLITCH(0); /* Ultra */ - - if (wval1 >= 8) { - wval1--; /* Timing computation differs by 1 from FAST_SCSI */ - bval = FAST_CLK; /* fast clock / normal scsi */ - pDCB->CtrlR4 |= pACB->glitch_cfg; /* glitch eater */ - } - pDCB->CtrlR3 = bval; - pDCB->SyncPeriod = (UCHAR) wval1; - - if ((oldsyncperiod != wval1 || oldsyncoffset != pDCB->SyncOffset) && pDCB->UnitSCSILUN == 0) { - if (!(bval & FAST_SCSI)) - wval1++; - printk("DC390: Target %i: Sync transfer %i.%1i MHz, Offset %i\n", pDCB->UnitSCSIID, - 40 / wval1, ((40 % wval1) * 10 + wval1 / 2) / wval1, pDCB->SyncOffset & 0x0f); - } - dc390_reprog(pACB, pDCB); -}; - - -/* According to the docs, the AM53C974 reads the message and - * generates a Succesful Operation IRQ before asserting ACK for - * the last byte (how does it know whether it's the last ?) */ -/* The old code handled it in another way, indicating, that on - * every message byte an IRQ is generated and every byte has to - * be manually ACKed. Hmmm ? (KG, 98/11/28) */ -/* The old implementation was correct. Sigh! */ - -/* Check if the message is complete */ -static UCHAR __inline__ - dc390_MsgIn_complete(UCHAR * msgbuf, ULONG len) -{ - if (*msgbuf == MSG_EXTENDED) { - if (len < 2) - return 0; - if (len < msgbuf[1] + 2) - return 0; - } else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f) // two byte messages - - if (len < 2) - return 0; - return 1; -} - - - -/* read and eval received messages */ -void dc390_MsgIn_0(PACB pACB, PSRB pSRB, PUCHAR psstatus) -{ - PDCB pDCB = pACB->pActiveDCB; - - /* Read the msg */ - - pSRB->MsgInBuf[pACB->MsgLen++] = DC390_read8(ScsiFifo); - //pSRB->SRBState = 0; - - /* Msg complete ? */ - if (dc390_MsgIn_complete(pSRB->MsgInBuf, pACB->MsgLen)) { - DEBUG0(printk(KERN_INFO "DC390: MsgIn:"); - dc390_printMsg(pSRB->MsgInBuf, pACB->MsgLen); - ) - /* Now eval the msg */ - switch (pSRB->MsgInBuf[0]) { - case MSG_DISCONNECT: - pSRB->SRBState = SRB_DISCONNECT; - break; - - case MSG_SIMPLE_QTAG: - case MSG_HEAD_QTAG: - case MSG_ORDER_QTAG: - pSRB = dc390_MsgIn_QTag(pACB, pDCB, pSRB->MsgInBuf[1]); - break; - - case MSG_REJECT_: - DC390_write8(ScsiCmd, RESET_ATN_CMD); - pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */ - if (pSRB->SRBState & DO_SYNC_NEGO) - dc390_MsgIn_set_async(pACB, pSRB); - break; - - case MSG_EXTENDED: - /* reject every extended msg but SDTR */ - if (pSRB->MsgInBuf[1] != 3 || pSRB->MsgInBuf[2] != EXTENDED_SDTR) - dc390_MsgIn_reject(pACB, pSRB); - else { - if (pSRB->MsgInBuf[3] == 0 || pSRB->MsgInBuf[4] == 0) - dc390_MsgIn_set_async(pACB, pSRB); - else - dc390_MsgIn_set_sync(pACB, pSRB); - }; - - // nothing has to be done - case MSG_COMPLETE: - break; - - // SAVE POINTER my be ignored as we have the PSRB associated with the - // scsi command. Thanks, Gerard, for pointing it out. - case MSG_SAVE_PTR: - break; - // The device might want to restart transfer with a RESTORE - case MSG_RESTORE_PTR: - printk("DC390: RESTORE POINTER message received ... reject\n"); - // fall through - - // reject unknown messages - default: - dc390_MsgIn_reject(pACB, pSRB); - } - - /* Clear counter and MsgIn state */ - pSRB->SRBState &= ~SRB_MSGIN; - pACB->MsgLen = 0; - }; - - *psstatus = SCSI_NOP0; - DC390_write8(ScsiCmd, MSG_ACCEPTED_CMD); - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); -} - - -void dc390_DataIO_Comm(PACB pACB, PSRB pSRB, UCHAR ioDir) -{ - PSGL psgl; - ULONG lval; - - if (pSRB->SGIndex < pSRB->SGcount) { - DC390_write8(DMA_Cmd, DMA_IDLE_CMD | ioDir /* | DMA_INT */ ); - if (!pSRB->SGToBeXferLen) { - psgl = pSRB->pSegmentList; - pSRB->SGBusAddr = virt_to_bus(psgl->address); - pSRB->SGToBeXferLen = (ULONG) psgl->length; - DEBUG1(printk(KERN_DEBUG " DC390: Next SG segment."); - ) - } - lval = pSRB->SGToBeXferLen; - DEBUG1(printk(KERN_DEBUG " DC390: Transfer %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr); - ) - DC390_write8(CtcReg_Low, (UCHAR) lval); - lval >>= 8; - DC390_write8(CtcReg_Mid, (UCHAR) lval); - lval >>= 8; - DC390_write8(CtcReg_High, (UCHAR) lval); - - DC390_write32(DMA_XferCnt, pSRB->SGToBeXferLen); - DC390_write32(DMA_XferAddr, pSRB->SGBusAddr); - - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); /* | DMA_INT; */ - pSRB->SRBState = SRB_DATA_XFER; - - DC390_write8(ScsiCmd, DMA_COMMAND + INFO_XFER_CMD); - - DC390_write8(DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT); - //DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);) - //DEBUG1(printk (KERN_DEBUG "DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status));) - //DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);) - } else { /* xfer pad */ - if (pSRB->SGcount) { - pSRB->AdaptStatus = H_OVER_UNDER_RUN; - pSRB->SRBStatus |= OVER_RUN; - DEBUG0(printk(KERN_WARNING " DC390: Overrun -"); - ) - } - DEBUG0(printk(KERN_WARNING " Clear transfer pad \n"); - ) - DC390_write8(CtcReg_Low, 0); - DC390_write8(CtcReg_Mid, 0); - DC390_write8(CtcReg_High, 0); - - pSRB->SRBState |= SRB_XFERPAD; - DC390_write8(ScsiCmd, DMA_COMMAND + XFER_PAD_BYTE); -/* - DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); // | DMA_INT; - DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT); - */ - } -} - - -static void dc390_DataOutPhase(PACB pACB, PSRB pSRB, PUCHAR psstatus) -{ - dc390_DataIO_Comm(pACB, pSRB, WRITE_DIRECTION); -} - -static void dc390_DataInPhase(PACB pACB, PSRB pSRB, PUCHAR psstatus) -{ - dc390_DataIO_Comm(pACB, pSRB, READ_DIRECTION); -} - -void dc390_CommandPhase(PACB pACB, PSRB pSRB, PUCHAR psstatus) -{ - PDCB pDCB; - UCHAR i, cnt; - PUCHAR ptr; - - DC390_write8(ScsiCmd, RESET_ATN_CMD); - DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); - if (!(pSRB->SRBFlag & AUTO_REQSENSE)) { - cnt = (UCHAR) pSRB->ScsiCmdLen; - ptr = (PUCHAR) pSRB->CmdBlock; - for (i = 0; i < cnt; i++) - DC390_write8(ScsiFifo, *(ptr++)); - } else { - UCHAR bval = 0; - DC390_write8(ScsiFifo, REQUEST_SENSE); - pDCB = pACB->pActiveDCB; - DC390_write8(ScsiFifo, pDCB->IdentifyMsg << 5); - DC390_write8(ScsiFifo, bval); - DC390_write8(ScsiFifo, bval); - DC390_write8(ScsiFifo, sizeof(pSRB->pcmd->sense_buffer)); - DC390_write8(ScsiFifo, bval); - } - pSRB->SRBState = SRB_COMMAND; - DC390_write8(ScsiCmd, INFO_XFER_CMD); -} - -static void dc390_StatusPhase(PACB pACB, PSRB pSRB, PUCHAR psstatus) -{ - DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); - pSRB->SRBState = SRB_STATUS; - DC390_write8(ScsiCmd, INITIATOR_CMD_CMPLTE); - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); -} - -void dc390_MsgOutPhase(PACB pACB, PSRB pSRB, PUCHAR psstatus) -{ - UCHAR bval, i, cnt; - PUCHAR ptr; - PDCB pDCB; - - DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); - pDCB = pACB->pActiveDCB; - if (!(pSRB->SRBState & SRB_MSGOUT)) { - cnt = pSRB->MsgCnt; - if (cnt) { - ptr = (PUCHAR) pSRB->MsgOutBuf; - for (i = 0; i < cnt; i++) - DC390_write8(ScsiFifo, *(ptr++)); - pSRB->MsgCnt = 0; - if ((pDCB->DCBFlag & ABORT_DEV_) && - (pSRB->MsgOutBuf[0] == MSG_ABORT)) - pSRB->SRBState = SRB_ABORT_SENT; - } else { - bval = MSG_ABORT; /* ??? MSG_NOP */ - if ((pSRB->CmdBlock[0] == INQUIRY) || - (pSRB->CmdBlock[0] == REQUEST_SENSE) || - (pSRB->SRBFlag & AUTO_REQSENSE)) { - if (pDCB->SyncMode & SYNC_ENABLE) - goto mop1; - } - DC390_write8(ScsiFifo, bval); - } - DC390_write8(ScsiCmd, INFO_XFER_CMD); - } else { - mop1: - //printk ("DC390: Send SDTR message to %i %i ... \n", pDCB->UnitSCSIID, pDCB->UnitSCSILUN); - DC390_write8(ScsiFifo, MSG_EXTENDED); - DC390_write8(ScsiFifo, 3); /* ;length of extended msg */ - DC390_write8(ScsiFifo, EXTENDED_SDTR); /* ; sync nego */ - DC390_write8(ScsiFifo, pDCB->NegoPeriod); - if (pDCB->SyncOffset & 0x0f) - DC390_write8(ScsiFifo, pDCB->SyncOffset); - else - DC390_write8(ScsiFifo, SYNC_NEGO_OFFSET); - pSRB->SRBState |= DO_SYNC_NEGO; - DC390_write8(ScsiCmd, INFO_XFER_CMD); - } -} - -static void dc390_MsgInPhase(PACB pACB, PSRB pSRB, PUCHAR psstatus) -{ - DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); - if (!(pSRB->SRBState & SRB_MSGIN)) { - pSRB->SRBState &= ~SRB_DISCONNECT; - pSRB->SRBState |= SRB_MSGIN; - } - DC390_write8(ScsiCmd, INFO_XFER_CMD); - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); -} - -static void dc390_Nop_0(PACB pACB, PSRB pSRB, PUCHAR psstatus) -{ -} - -static void dc390_Nop_1(PACB pACB, PSRB pSRB, PUCHAR psstatus) -{ -} - - -static void dc390_SetXferRate(PACB pACB, PDCB pDCB) -{ - UCHAR bval, i, cnt; - PDCB ptr; - - if (!(pDCB->IdentifyMsg & 0x07)) { - if (pACB->scan_devices) { - dc390_CurrSyncOffset = pDCB->SyncOffset; - } else { - ptr = pACB->pLinkDCB; - cnt = pACB->DCBCnt; - bval = pDCB->UnitSCSIID; - for (i = 0; i < cnt; i++) { - if (ptr->UnitSCSIID == bval) { - ptr->SyncPeriod = pDCB->SyncPeriod; - ptr->SyncOffset = pDCB->SyncOffset; - ptr->CtrlR3 = pDCB->CtrlR3; - ptr->CtrlR4 = pDCB->CtrlR4; - ptr->SyncMode = pDCB->SyncMode; - } - ptr = ptr->pNextDCB; - } - } - } - return; -} - - -void dc390_Disconnect(PACB pACB) -{ - PDCB pDCB; - PSRB pSRB, psrb; - UCHAR i, cnt; - - DEBUG0(printk(KERN_INFO "DISC,"); - ) - pDCB = pACB->pActiveDCB; - if (!pDCB) { - int j = 400; - DEBUG0(printk(KERN_WARNING "ACB:%08lx->ActiveDCB:%08lx IOPort:%04x IRQ:%02x !\n", \ - (ULONG) pACB, (ULONG) pDCB, pACB->IOPortBase, pACB->IRQLevel); - ) - while (--j) - udelay(1000); - DC390_read8(INT_Status); /* Reset Pending INT */ - DC390_write8(ScsiCmd, EN_SEL_RESEL); - return; - } - pSRB = pDCB->pActiveSRB; - pACB->pActiveDCB = 0; - pSRB->ScsiPhase = SCSI_NOP0; - DC390_write8(ScsiCmd, EN_SEL_RESEL); - if (pSRB->SRBState & SRB_UNEXPECT_RESEL) { - pSRB->SRBState = 0; - dc390_DoWaitingSRB(pACB); - } else if (pSRB->SRBState & SRB_ABORT_SENT) { - pDCB->TagMask = 0; - pDCB->DCBFlag = 0; - cnt = pDCB->GoingSRBCnt; - pDCB->GoingSRBCnt = 0; - pSRB = pDCB->pGoingSRB; - for (i = 0; i < cnt; i++) { - psrb = pSRB->pNextSRB; - pSRB->pNextSRB = pACB->pFreeSRB; - pACB->pFreeSRB = pSRB; - pSRB = psrb; - } - pDCB->pGoingSRB = 0; - dc390_DoWaitingSRB(pACB); - } else { - if ((pSRB->SRBState & (SRB_START_ + SRB_MSGOUT)) || - !(pSRB->SRBState & (SRB_DISCONNECT + SRB_COMPLETED))) { /* Selection time out */ - if (!(pACB->scan_devices)) { - pSRB->SRBState = SRB_READY; - dc390_RewaitSRB(pDCB, pSRB); - } else { - pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT; - goto disc1; - } - } else if (pSRB->SRBState & SRB_DISCONNECT) { - dc390_DoWaitingSRB(pACB); - } else if (pSRB->SRBState & SRB_COMPLETED) { - disc1: - if (pDCB->MaxCommand > 1) { - pDCB->TagMask &= (~(1 << pSRB->TagNumber)); /* free tag mask */ - } - pDCB->pActiveSRB = 0; - pSRB->SRBState = SRB_FREE; - dc390_SRBdone(pACB, pDCB, pSRB); - } - } - pACB->MsgLen = 0; -} - - -void dc390_Reselect(PACB pACB) -{ - PDCB pDCB; - PSRB pSRB; - USHORT wval; - UCHAR bval; - - DEBUG0(printk(KERN_INFO "RSEL,"); - ) - pDCB = pACB->pActiveDCB; - if (pDCB) { /* Arbitration lost but Reselection won */ - DEBUG0(printk("(ActiveDCB != 0)"); - ) - pSRB = pDCB->pActiveSRB; - if (!(pACB->scan_devices)) { - pSRB->SRBState = SRB_READY; - dc390_RewaitSRB(pDCB, pSRB); - } - } - bval = DC390_read8(ScsiFifo); /* get ID */ - DEBUG0(printk("Dev %02x,", bval); - ) - bval ^= 1 << pACB->pScsiHost->this_id; /* Mask AdapterID */ - wval = 0; - while (bval >>= 1) - wval++; - wval |= ((USHORT) DC390_read8(ScsiFifo) & 7) << 8; /* get LUN */ - DEBUG0(printk("(ID %02x, LUN %02x),", wval & 0xff, (wval & 0xff00) >> 8); - ) - pDCB = pACB->pLinkDCB; - while (wval != *((PUSHORT) & pDCB->UnitSCSIID)) { - pDCB = pDCB->pNextDCB; - if (pDCB == pACB->pLinkDCB) { - printk(KERN_ERR "DC390: Reselect from non existing device (ID %02x, LUN %02x)\n", - wval & 0xff, (wval & 0xff00) >> 8); - return; - } - } - pACB->pActiveDCB = pDCB; - if (pDCB->SyncMode & EN_TAG_QUEUEING) { - pSRB = pACB->pTmpSRB; /* ?? */ - pDCB->pActiveSRB = pSRB; - } else { - pSRB = pDCB->pActiveSRB; - if (!pSRB || !(pSRB->SRBState & SRB_DISCONNECT)) { - pSRB = pACB->pTmpSRB; - pSRB->SRBState = SRB_UNEXPECT_RESEL; - printk(KERN_ERR "DC390: Reselect without outstanding cmnd (ID %02x, LUN %02x)\n", - wval & 0xff, (wval & 0xff00) >> 8); - pDCB->pActiveSRB = pSRB; - dc390_EnableMsgOut_Abort(pACB, pSRB); - } else { - if (pDCB->DCBFlag & ABORT_DEV_) { - pSRB->SRBState = SRB_ABORT_SENT; - printk(KERN_INFO "DC390: Reselect: Abort (ID %02x, LUN %02x)\n", - wval & 0xff, (wval & 0xff00) >> 8); - dc390_EnableMsgOut_Abort(pACB, pSRB); - } else - pSRB->SRBState = SRB_DATA_XFER; - } - } - - DEBUG1(printk(KERN_DEBUG "Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber); - ) - pSRB->ScsiPhase = SCSI_NOP0; - DC390_write8(Scsi_Dest_ID, pDCB->UnitSCSIID); - DC390_write8(Sync_Period, pDCB->SyncPeriod); - DC390_write8(Sync_Offset, pDCB->SyncOffset); - DC390_write8(CtrlReg1, pDCB->CtrlR1); - DC390_write8(CtrlReg3, pDCB->CtrlR3); - DC390_write8(CtrlReg4, pDCB->CtrlR4); /* ; Glitch eater */ - DC390_write8(ScsiCmd, MSG_ACCEPTED_CMD); /* ;to release the /ACK signal */ -} - - -static void dc390_remove_dev(PACB pACB, PDCB pDCB) -{ - PDCB pPrevDCB = pACB->pLinkDCB; - - pACB->DCBmap[pDCB->UnitSCSIID] &= ~(1 << pDCB->UnitSCSILUN); - if (pDCB->GoingSRBCnt > 1) { - DCBDEBUG(printk(KERN_INFO "DC390: Driver won't free DCB (ID %i, LUN %i): 0x%08x because of SRBCnt %i\n", \ - pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int) pDCB, pDCB->GoingSRBCnt); - ) - return; - }; - - if (pDCB == pACB->pLinkDCB) { - if (pDCB->pNextDCB == pDCB) - pDCB->pNextDCB = 0; - pACB->pLinkDCB = pDCB->pNextDCB; - pACB->pLastDCB->pNextDCB = pDCB->pNextDCB; - } else { - while (pPrevDCB->pNextDCB != pDCB) - pPrevDCB = pPrevDCB->pNextDCB; - pPrevDCB->pNextDCB = pDCB->pNextDCB; - if (pDCB == pACB->pLastDCB) - pACB->pLastDCB = pPrevDCB; - } - - DCBDEBUG(printk(KERN_INFO "DC390: Driver about to free DCB (ID %i, LUN %i): 0x%08x\n", \ - pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int) pDCB); - ) - kfree(pDCB); - if (pDCB == pACB->pActiveDCB) - pACB->pActiveDCB = 0; - pACB->DCBCnt--; - /* pACB->DeviceCnt--; */ -}; - - -static UCHAR __inline__ - dc390_tagq_blacklist(char *name) -{ - UCHAR i; - for (i = 0; i < BADDEVCNT; i++) - if (memcmp(name, dc390_baddevname1[i], 28) == 0) - return 1; - return 0; -}; - - -static void dc390_disc_tagq_set(PDCB pDCB, PSCSI_INQDATA ptr) -{ - /* Check for SCSI format (ANSI and Response data format) */ - if ((ptr->Vers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2) { - if ((ptr->Flags & SCSI_INQ_CMDQUEUE) && - (pDCB->DevMode & TAG_QUEUEING_) && - /* ((pDCB->DevType == TYPE_DISK) - || (pDCB->DevType == TYPE_MOD)) && */ - !dc390_tagq_blacklist(((char *) ptr) + 8)) { - pDCB->MaxCommand = pDCB->pDCBACB->TagMaxNum; - pDCB->SyncMode |= EN_TAG_QUEUEING /* | EN_ATN_STOP */ ; - pDCB->TagMask = 0; - } else { - /* Do we really need to check for DevType here ? */ - if (0 /*(pDCB->DevMode & EN_DISCONNECT_) */ - /* && ((pDCB->DevType == TYPE_DISK) - || (pDCB->DevType == TYPE_MOD)) */ ) - pDCB->SyncMode |= EN_ATN_STOP; - else - //pDCB->SyncMode &= ~EN_ATN_STOP; - pDCB->SyncMode &= ~0; - } - } -}; - - -static void dc390_add_dev(PACB pACB, PDCB pDCB, PSCSI_INQDATA ptr) -{ - UCHAR bval1 = ptr->DevType & SCSI_DEVTYPE; - pDCB->DevType = bval1; - /* if (bval1 == TYPE_DISK || bval1 == TYPE_MOD) */ - dc390_disc_tagq_set(pDCB, ptr); -}; - - -void dc390_SRBdone(PACB pACB, PDCB pDCB, PSRB pSRB) -{ - PSRB psrb; - UCHAR bval, status, i; - PSCSICMD pcmd; - PSCSI_INQDATA ptr; - PSGL ptr2; - ULONG swlval; - - pcmd = pSRB->pcmd; - status = pSRB->TargetStatus; - DEBUG0(printk(" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result, \ - pSRB, pcmd->pid); - ) - if (pSRB->SRBFlag & AUTO_REQSENSE) { /* Last command was a Request Sense */ - pSRB->SRBFlag &= ~AUTO_REQSENSE; - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = SCSI_STAT_CHECKCOND; -#ifdef DC390_REMOVABLEDEBUG - switch (pcmd->sense_buffer[2] & 0x0f) { - case NOT_READY: - printk(KERN_INFO "DC390: ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, - status, pACB->scan_devices); - break; - case UNIT_ATTENTION: - printk(KERN_INFO "DC390: ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, - status, pACB->scan_devices); - break; - case ILLEGAL_REQUEST: - printk(KERN_INFO "DC390: ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, - status, pACB->scan_devices); - break; - case MEDIUM_ERROR: - printk(KERN_INFO "DC390: ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, - status, pACB->scan_devices); - break; - case HARDWARE_ERROR: - printk(KERN_INFO "DC390: ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, - status, pACB->scan_devices); - break; - } -#endif - //pcmd->result = DRIVER_SENSE << 24 | DID_OK << 16 | status; - if (status == SCSI_STAT_CHECKCOND) { - pcmd->result = DID_BAD_TARGET << 16; - goto ckc_e; - } - if (pSRB->RetryCnt == 0) { - (ULONG) (pSRB->CmdBlock[0]) = pSRB->Segment0[0]; - pSRB->TotalXferredLen = pSRB->Segment1[1]; - if ((pSRB->TotalXferredLen) && - (pSRB->TotalXferredLen >= pcmd->underflow)) - pcmd->result |= (DID_OK << 16); - else - pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) | - SCSI_STAT_CHECKCOND; - REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x,Result=%08x,XferL=%08x\n", pSRB->CmdBlock[0], \ - (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen); - ) - goto ckc_e; - } else { /* Retry */ - pSRB->RetryCnt--; - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = 0; - *((PULONG) & (pSRB->CmdBlock[0])) = pSRB->Segment0[0]; - *((PULONG) & (pSRB->CmdBlock[4])) = pSRB->Segment0[1]; - /* Don't retry on TEST_UNIT_READY */ - if (pSRB->CmdBlock[0] == TEST_UNIT_READY /* || pSRB->CmdBlock[0] == START_STOP */ ) { - pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) - | SCSI_STAT_CHECKCOND; - REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x, Result=%08x, XferL=%08x\n", pSRB->CmdBlock[0], \ - (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen); - ) - goto ckc_e; - } - pcmd->result |= (DRIVER_SENSE << 24); - pSRB->SGcount = (UCHAR) pSRB->Segment1[0]; - pSRB->ScsiCmdLen = (UCHAR) (pSRB->Segment1[0] >> 8); - pSRB->SGIndex = 0; - pSRB->TotalXferredLen = 0; - pSRB->SGToBeXferLen = 0; - if (pcmd->use_sg) - pSRB->pSegmentList = (PSGL) pcmd->request_buffer; - else if (pcmd->request_buffer) { - pSRB->pSegmentList = (PSGL) & pSRB->Segmentx; - pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; - pSRB->Segmentx.length = pcmd->request_bufflen; - } - if (dc390_StartSCSI(pACB, pDCB, pSRB)) - dc390_RewaitSRB(pDCB, pSRB); - return; - } - } - if (status) { - if (status == SCSI_STAT_CHECKCOND) { - REMOVABLEDEBUG(printk(KERN_INFO "DC390: Scsi_Stat_CheckCond (Cmd %02x, Id %02x, LUN %02x)\n", \ - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN); - ) - if ((pSRB->SGIndex < pSRB->SGcount) && (pSRB->SGcount) && (pSRB->SGToBeXferLen)) { - bval = pSRB->SGcount; - swlval = 0; - ptr2 = pSRB->pSegmentList; - for (i = pSRB->SGIndex; i < bval; i++) { - swlval += ptr2->length; - ptr2++; - } - REMOVABLEDEBUG(printk(KERN_INFO "XferredLen=%08x,NotXferLen=%08x\n", \ - (UINT) pSRB->TotalXferredLen, (UINT) swlval); - ) - } - dc390_RequestSense(pACB, pDCB, pSRB); - return; - } else if (status == SCSI_STAT_QUEUEFULL) { - bval = (UCHAR) pDCB->GoingSRBCnt; - bval--; - pDCB->MaxCommand = bval; - dc390_RewaitSRB(pDCB, pSRB); - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = 0; - return; - } else if (status == SCSI_STAT_SEL_TIMEOUT) { - pSRB->AdaptStatus = H_SEL_TIMEOUT; - pSRB->TargetStatus = 0; - pcmd->result = DID_BAD_TARGET << 16; - /* Devices are removed below ... */ - } else if (status == SCSI_STAT_BUSY && - (pSRB->CmdBlock[0] == TEST_UNIT_READY || pSRB->CmdBlock[0] == INQUIRY) && - pACB->scan_devices) { - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = status; - pcmd->result = (ULONG) (pSRB->EndMessage << 8) - /* | (ULONG) status */ ; - } else { /* Another error */ - pSRB->AdaptStatus = 0; - if (pSRB->RetryCnt) { /* Retry */ - pSRB->RetryCnt--; - pSRB->TargetStatus = 0; - pSRB->SGIndex = 0; - pSRB->TotalXferredLen = 0; - pSRB->SGToBeXferLen = 0; - if (pcmd->use_sg) - pSRB->pSegmentList = (PSGL) pcmd->request_buffer; - else if (pcmd->request_buffer) { - pSRB->pSegmentList = (PSGL) & pSRB->Segmentx; - pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; - pSRB->Segmentx.length = pcmd->request_bufflen; - } - if (dc390_StartSCSI(pACB, pDCB, pSRB)) - dc390_RewaitSRB(pDCB, pSRB); - return; - } else { /* Report error */ - pcmd->result |= (DID_ERROR << 16) | (ULONG) (pSRB->EndMessage << 8) | - (ULONG) status; - } - } - } else { /* Target status == 0 */ - status = pSRB->AdaptStatus; - if (status & H_OVER_UNDER_RUN) { - pSRB->TargetStatus = 0; - pcmd->result |= (DID_OK << 16) | (pSRB->EndMessage << 8); - } else if (pSRB->SRBStatus & PARITY_ERROR) { - pcmd->result |= (DID_PARITY << 16) | (pSRB->EndMessage << 8); - } else { /* No error */ - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = 0; - pcmd->result |= (DID_OK << 16); - } - } - - ckc_e: - if (pACB->scan_devices) { - if (pSRB->CmdBlock[0] == TEST_UNIT_READY) { -#ifdef DC390_DEBUG0 - printk(KERN_INFO "DC390: Test_Unit_Ready: result: %08x", pcmd->result); - if (pcmd->result & DRIVER_SENSE << 24) - printk(" (sense: %02x %02x %02x %02x)\n", - pcmd->sense_buffer[0], pcmd->sense_buffer[1], - pcmd->sense_buffer[2], pcmd->sense_buffer[3]); - else - printk("\n"); -#endif - if ((pcmd->result != (DID_OK << 16) && !(pcmd->result & SCSI_STAT_CHECKCOND) && !(pcmd->result & SCSI_STAT_BUSY)) || - ((pcmd->result & DRIVER_SENSE << 24) && (pcmd->sense_buffer[0] & 0x70) == 0x70 && - (pcmd->sense_buffer[2] & 0xf) == ILLEGAL_REQUEST) || pcmd->result & DID_ERROR << 16) { - /* device not present: remove */ - dc390_remove_dev(pACB, pDCB); - - if ((pcmd->target == pACB->pScsiHost->max_id - 1) && - ((pcmd->lun == 0) || (pcmd->lun == pACB->pScsiHost->max_lun - 1))) - pACB->scan_devices = 0; - } else { - /* device present: add */ - if ((pcmd->target == pACB->pScsiHost->max_id - 1) && - (pcmd->lun == pACB->pScsiHost->max_lun - 1)) - pACB->scan_devices = END_SCAN; - /* pACB->DeviceCnt++; *//* Dev is added on INQUIRY */ - } - } - } - if (pSRB->CmdBlock[0] == INQUIRY && - (pcmd->result == DID_OK << 16 || pcmd->result & SCSI_STAT_CHECKCOND)) { - ptr = (PSCSI_INQDATA) (pcmd->request_buffer); - if (pcmd->use_sg) - ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address); - if ((ptr->DevType & SCSI_DEVTYPE) == TYPE_NODEV) { - /* device not present: remove */ - dc390_remove_dev(pACB, pDCB); - } else { - /* device found: add */ - dc390_add_dev(pACB, pDCB, ptr); - if (pACB->scan_devices) - pACB->DeviceCnt++; - } - if ((pcmd->target == pACB->pScsiHost->max_id - 1) && - (pcmd->lun == pACB->pScsiHost->max_lun - 1)) - pACB->scan_devices = 0; - }; -/* dc390_ReleaseSRB( pDCB, pSRB ); */ - - if (pSRB == pDCB->pGoingSRB) { - pDCB->pGoingSRB = pSRB->pNextSRB; - } else { - psrb = pDCB->pGoingSRB; - while (psrb->pNextSRB != pSRB) - psrb = psrb->pNextSRB; - psrb->pNextSRB = pSRB->pNextSRB; - if (pSRB == pDCB->pGoingLast) - pDCB->pGoingLast = psrb; - } - pSRB->pNextSRB = pACB->pFreeSRB; - pACB->pFreeSRB = pSRB; - pDCB->GoingSRBCnt--; - - dc390_DoWaitingSRB(pACB); - - DC390_UNLOCK_ACB_NI; - pcmd->scsi_done(pcmd); - DC390_LOCK_ACB_NI; - - if (pDCB->QIORBCnt) - dc390_DoNextCmd(pACB, pDCB); - return; -} - - -/* Remove all SRBs and tell midlevel code DID_RESET */ -void dc390_DoingSRB_Done(PACB pACB) -{ - PDCB pDCB, pdcb; - PSRB psrb, psrb2; - UCHAR i; - PSCSICMD pcmd; - - pDCB = pACB->pLinkDCB; - pdcb = pDCB; - if (!pdcb) - return; - do { - psrb = pdcb->pGoingSRB; - for (i = 0; i < pdcb->GoingSRBCnt; i++) { - psrb2 = psrb->pNextSRB; - pcmd = psrb->pcmd; - pcmd->result = DID_RESET << 16; - -/* ReleaseSRB( pDCB, pSRB ); */ - - psrb->pNextSRB = pACB->pFreeSRB; - pACB->pFreeSRB = psrb; - - DC390_UNLOCK_ACB_NI; - pcmd->scsi_done(pcmd); - DC390_LOCK_ACB_NI; - psrb = psrb2; - } - pdcb->GoingSRBCnt = 0;; - pdcb->pGoingSRB = NULL; - pdcb->TagMask = 0; - pdcb = pdcb->pNextDCB; - } while (pdcb != pDCB); -} - - -static void dc390_ResetSCSIBus(PACB pACB) -{ - pACB->ACBFlag |= RESET_DEV; - - DC390_write8(ScsiCmd, RST_DEVICE_CMD); - udelay(250); - DC390_write8(ScsiCmd, NOP_CMD); - - DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); - DC390_write8(DMA_Cmd, DMA_IDLE_CMD); - DC390_write8(ScsiCmd, RST_SCSI_BUS_CMD); - - return; -} - -static void dc390_ScsiRstDetect(PACB pACB) -{ - printk("DC390: Rst_Detect: laststat = %08lx\n", dc390_laststatus); - //DEBUG0(printk(KERN_INFO "RST_DETECT,");) - - DC390_write8(DMA_Cmd, DMA_IDLE_CMD); - /* Unlock before ? */ - /* delay a second */ - { - unsigned int msec = 1 * 1000; - while (--msec) - udelay(1000); - } - DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); - - if (pACB->ACBFlag & RESET_DEV) - pACB->ACBFlag |= RESET_DONE; - else { - pACB->ACBFlag |= RESET_DETECT; - - dc390_ResetDevParam(pACB); -/* dc390_DoingSRB_Done( pACB ); ???? */ - dc390_RecoverSRB(pACB); - pACB->pActiveDCB = NULL; - pACB->ACBFlag = 0; - dc390_DoWaitingSRB(pACB); - } - return; -} - - -static void __inline__ - dc390_RequestSense(PACB pACB, PDCB pDCB, PSRB pSRB) -{ - PSCSICMD pcmd; - - REMOVABLEDEBUG(printk(KERN_INFO "DC390: RequestSense (Cmd %02x, Id %02x, LUN %02x)\n", \ - pSRB->CmdBlock[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN); - ) - pSRB->SRBFlag |= AUTO_REQSENSE; - pSRB->Segment0[0] = (ULONG) pSRB->CmdBlock[0]; - pSRB->Segment0[1] = (ULONG) pSRB->CmdBlock[4]; - pSRB->Segment1[0] = (ULONG) ((pSRB->ScsiCmdLen << 8) + pSRB->SGcount); - pSRB->Segment1[1] = pSRB->TotalXferredLen; - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = 0; /* SCSI_STAT_CHECKCOND; */ - - pcmd = pSRB->pcmd; - - pSRB->Segmentx.address = (PUCHAR) & (pcmd->sense_buffer); - pSRB->Segmentx.length = sizeof(pcmd->sense_buffer); - pSRB->pSegmentList = &pSRB->Segmentx; - pSRB->SGcount = 1; - pSRB->SGIndex = 0; - - pSRB->CmdBlock[0] = REQUEST_SENSE; - pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5; - (USHORT) pSRB->CmdBlock[2] = 0; - (USHORT) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer); - pSRB->ScsiCmdLen = 6; - - pSRB->TotalXferredLen = 0; - pSRB->SGToBeXferLen = 0; - if (dc390_StartSCSI(pACB, pDCB, pSRB)) - dc390_RewaitSRB(pDCB, pSRB); -} - - - -static void __inline__ - dc390_InvalidCmd(PACB pACB) -{ - if (pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_ + SRB_MSGOUT)) - DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); -} +/*********************************************************************** + * FILE NAME : SCSIIOM.C * + * BY : C.L. Huang, ching@tekram.com.tw * + * Description: Device Driver for Tekram DC-390 (T) PCI SCSI * + * Bus Master Host Adapter * + ***********************************************************************/ +/* $Id: scsiiom.c,v 2.55.2.17 2000/12/20 00:39:37 garloff Exp $ */ + +static void __inline__ +dc390_freetag (PDCB pDCB, PSRB pSRB) +{ + if (pSRB->TagNumber < 255) { + pDCB->TagMask &= ~(1 << pSRB->TagNumber); /* free tag mask */ + pSRB->TagNumber = 255; + } +}; + + +UCHAR +dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ) +{ + UCHAR cmd; UCHAR disc_allowed, try_sync_nego; + + pSRB->ScsiPhase = SCSI_NOP0; + + if (pACB->Connected) + { + // Should not happen normally + printk (KERN_WARNING "DC390: Can't select when connected! (%08x,%02x)\n", + pSRB->SRBState, pSRB->SRBFlag); + pSRB->SRBState = SRB_READY; + pACB->SelConn++; + return 1; + } + if (time_before (jiffies, pACB->pScsiHost->last_reset)) + { + DEBUG0(printk ("DC390: We were just reset and don't accept commands yet!\n");) + return 1; + } + DC390_write8 (Scsi_Dest_ID, pDCB->TargetID); + DC390_write8 (Sync_Period, pDCB->SyncPeriod); + DC390_write8 (Sync_Offset, pDCB->SyncOffset); + DC390_write8 (CtrlReg1, pDCB->CtrlR1); + DC390_write8 (CtrlReg3, pDCB->CtrlR3); + DC390_write8 (CtrlReg4, pDCB->CtrlR4); + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); /* Flush FIFO */ + DEBUG1(printk (KERN_INFO "DC390: Start SCSI command: %02x (Sync:%02x)\n",\ + pSRB->pcmd->cmnd[0], pDCB->SyncMode);) + disc_allowed = pDCB->DevMode & EN_DISCONNECT_; try_sync_nego = 0; + /* Don't disconnect on AUTO_REQSENSE, cause it might be an + * Contingent Allegiance Condition (6.6), where no tags should be used. + * All other have to be allowed to disconnect to prevent Incorrect + * Initiator Connection (6.8.2/6.5.2) */ + /* Changed KG, 99/06/06 */ + if( /*(((pSRB->pcmd->cmnd[0] == INQUIRY) || (pSRB->pcmd->cmnd[0] == REQUEST_SENSE) || + * (pSRB->pcmd->cmnd[0] == TEST_UNIT_READY)) && pACB->scan_devices) + ||*/ (pSRB->SRBFlag & AUTO_REQSENSE) ) + disc_allowed = 0; + if ( (pDCB->SyncMode & SYNC_ENABLE) && (pDCB->TargetLUN == 0) && (pDCB->Inquiry7 & 0x10) && + ( ( ( (pSRB->pcmd->cmnd[0] == REQUEST_SENSE) || (pSRB->SRBFlag & AUTO_REQSENSE) ) + && !(pDCB->SyncMode & SYNC_NEGO_DONE) ) || (pSRB->pcmd->cmnd[0] == INQUIRY) ) ) + try_sync_nego = 1; + + pSRB->MsgCnt = 0; cmd = SEL_W_ATN; + DC390_write8 (ScsiFifo, IDENTIFY(disc_allowed, pDCB->TargetLUN)); + /* Change 99/05/31: Don't use tags when not disconnecting (BUSY) */ + if ((pDCB->SyncMode & EN_TAG_QUEUEING) && disc_allowed) + { + UCHAR tag_no = 0; + while ((1 << tag_no) & pDCB->TagMask) tag_no++; + if (tag_no >= sizeof (pDCB->TagMask)*8 || tag_no >= pDCB->MaxCommand) { + printk (KERN_WARNING "DC390: Out of tags for Dev. %02x %02x\n", pDCB->TargetID, pDCB->TargetLUN); + return 1; + //goto no_tag; + }; + DC390_write8 (ScsiFifo, SIMPLE_QUEUE_TAG); + pDCB->TagMask |= (1 << tag_no); pSRB->TagNumber = tag_no; + DC390_write8 (ScsiFifo, tag_no); + DEBUG1(printk (KERN_DEBUG "DC390: Select w/DisCn for Cmd %li (SRB %p), Using Tag %02x\n", pSRB->pcmd->pid, pSRB, tag_no);) + cmd = SEL_W_ATN3; + } + else /* No TagQ */ + { +// no_tag: + DEBUG1(printk (KERN_DEBUG "DC390: Select w%s/DisCn for Cmd %li (SRB %p), No TagQ\n", (disc_allowed?"":"o"), pSRB->pcmd->pid, pSRB);) + }; + + pSRB->SRBState = SRB_START_; + + if (try_sync_nego) + { + UCHAR Sync_Off = pDCB->SyncOffset; + DEBUG0(printk (KERN_INFO "DC390: NEW Sync Nego code triggered (%i %i)\n", pDCB->TargetID, pDCB->TargetLUN);) + pSRB->MsgOutBuf[0] = EXTENDED_MESSAGE; + pSRB->MsgOutBuf[1] = 3; + pSRB->MsgOutBuf[2] = EXTENDED_SDTR; + pSRB->MsgOutBuf[3] = pDCB->NegoPeriod; + if (!(Sync_Off & 0x0f)) Sync_Off = SYNC_NEGO_OFFSET; + pSRB->MsgOutBuf[4] = Sync_Off; + pSRB->MsgCnt = 5; + //pSRB->SRBState = SRB_MSGOUT_; + pSRB->SRBState |= DO_SYNC_NEGO; + cmd = SEL_W_ATN_STOP; + }; + + /* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */ + if (cmd != SEL_W_ATN_STOP) + { + if( pSRB->SRBFlag & AUTO_REQSENSE ) + { + DC390_write8 (ScsiFifo, REQUEST_SENSE); + DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5); + DC390_write8 (ScsiFifo, 0); + DC390_write8 (ScsiFifo, 0); + DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer)); + DC390_write8 (ScsiFifo, 0); + DEBUG1(printk (KERN_DEBUG "DC390: AutoReqSense !\n");) + } + else /* write cmnd to bus */ + { + PUCHAR ptr; UCHAR i; + ptr = (PUCHAR) pSRB->pcmd->cmnd; + for (i=0; ipcmd->cmd_len; i++) + DC390_write8 (ScsiFifo, *(ptr++)); + }; + } + DEBUG0(if (pACB->pActiveDCB) \ + printk (KERN_WARNING "DC390: ActiveDCB != 0\n");) + DEBUG0(if (pDCB->pActiveSRB) \ + printk (KERN_WARNING "DC390: ActiveSRB != 0\n");) + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); + if (DC390_read8 (Scsi_Status) & INTERRUPT) + { + dc390_freetag (pDCB, pSRB); + DEBUG0(printk ("DC390: Interrupt during Start SCSI (pid %li, target %02i-%02i)\n", + pSRB->pcmd->pid, pSRB->pcmd->target, pSRB->pcmd->lun);) + pSRB->SRBState = SRB_READY; + //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + pACB->SelLost++; + return 1; + }; + DC390_write8 (ScsiCmd, cmd); + pACB->pActiveDCB = pDCB; pDCB->pActiveSRB = pSRB; + pACB->Connected = 1; + pSRB->ScsiPhase = SCSI_NOP1; + return 0; +} + +//#define DMA_INT EN_DMA_INT /*| EN_PAGE_INT*/ +#define DMA_INT 0 + +#if DMA_INT +/* This is similar to AM53C974.c ... */ +static UCHAR +dc390_dma_intr (PACB pACB) +{ + PSRB pSRB; + UCHAR dstate; + DEBUG0(USHORT pstate;PDEVDECL1;) + + DEBUG0(PDEVSET1;) + DEBUG0(PCI_READ_CONFIG_WORD (PDEV, PCI_STATUS, &pstate);) + DEBUG0(if (pstate & (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY))\ + { printk(KERN_WARNING "DC390: PCI state = %04x!\n", pstate); \ + PCI_WRITE_CONFIG_WORD (PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));};) + + dstate = DC390_read8 (DMA_Status); + + if (! pACB->pActiveDCB || ! pACB->pActiveDCB->pActiveSRB) return dstate; + else pSRB = pACB->pActiveDCB->pActiveSRB; + + if (dstate & (DMA_XFER_ABORT | DMA_XFER_ERROR | POWER_DOWN | PCI_MS_ABORT)) + { + printk (KERN_ERR "DC390: DMA error (%02x)!\n", dstate); + return dstate; + }; + if (dstate & DMA_XFER_DONE) + { + UINT residual, xferCnt; int ctr = 6000000; + if (! (DC390_read8 (DMA_Cmd) & READ_DIRECTION)) + { + do + { + DEBUG1(printk (KERN_DEBUG "DC390: read residual bytes ... \n");) + dstate = DC390_read8 (DMA_Status); + residual = DC390_read8 (CtcReg_Low) | DC390_read8 (CtcReg_Mid) << 8 | + DC390_read8 (CtcReg_High) << 16; + residual += DC390_read8 (Current_Fifo) & 0x1f; + } while (residual && ! (dstate & SCSI_INTERRUPT) && --ctr); + if (!ctr) printk (KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr)); + /* residual = ... */ + } + else + residual = 0; + + /* ??? */ + + xferCnt = pSRB->SGToBeXferLen - residual; + pSRB->SGBusAddr += xferCnt; + pSRB->TotalXferredLen += xferCnt; + pSRB->SGToBeXferLen = residual; +# ifdef DC390_DEBUG0 + printk (KERN_INFO "DC390: DMA: residual = %i, xfer = %i\n", + (unsigned int)residual, (unsigned int)xferCnt); +# endif + + DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); + } + dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24; + return dstate; +}; +#endif + +void __inline__ +DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs) +{ + PACB pACB, pACB2; + PDCB pDCB; + PSRB pSRB; + UCHAR sstatus=0; + UCHAR phase; + void (*stateV)( PACB, PSRB, PUCHAR ); + UCHAR istate, istatus; +#if DMA_INT + UCHAR dstatus; +#endif + DC390_AFLAGS DC390_IFLAGS //DC390_DFLAGS + + pACB = (PACB)dev_id; + for (pACB2 = dc390_pACB_start; (pACB2 && pACB2 != pACB); pACB2 = pACB2->pNextACB); + if (!pACB2) + { + printk ("DC390: IRQ called with foreign dev_id %p!\n", pACB); + return; + } + + //DC390_LOCK_DRV; + + sstatus = DC390_read8 (Scsi_Status); + if( !(sstatus & INTERRUPT) ) + { /*DC390_UNLOCK_DRV;*/ return; }; + + DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus);) + +#if DMA_INT + DC390_LOCK_IO; + DC390_LOCK_ACB; + dstatus = dc390_dma_intr (pACB); + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; + + DEBUG1(printk (KERN_DEBUG "dstatus=%02x,", dstatus);) + if (! (dstatus & SCSI_INTERRUPT)) + { + DEBUG0(printk (KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n");) + //DC390_UNLOCK_DRV; + return; + }; +#else + //DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT); + //dstatus = DC390_read8 (DMA_Status); + //DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT); +#endif + + DC390_LOCK_IO; + DC390_LOCK_ACB; + //DC390_UNLOCK_DRV_NI; /* Allow _other_ CPUs to process IRQ (useful for shared IRQs) */ + + istate = DC390_read8 (Intern_State); + istatus = DC390_read8 (INT_Status); /* This clears Scsi_Status, Intern_State and INT_Status ! */ + + DEBUG1(printk (KERN_INFO "Istatus(Res,Inv,Dis,Serv,Succ,ReS,SelA,Sel)=%02x,",istatus);) + dc390_laststatus &= ~0x00ffffff; + dc390_laststatus |= /* dstatus<<24 | */ sstatus<<16 | istate<<8 | istatus; + + if (sstatus & ILLEGAL_OP_ERR) + { + printk ("DC390: Illegal Operation detected (%08x)!\n", dc390_laststatus); + dc390_dumpinfo (pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB); + } + + else if (istatus & INVALID_CMD) + { + printk ("DC390: Invalid Command detected (%08x)!\n", dc390_laststatus); + dc390_InvalidCmd( pACB ); + goto unlock; + } + + if (istatus & SCSI_RESET) + { + dc390_ScsiRstDetect( pACB ); + goto unlock; + } + + if (istatus & DISCONNECTED) + { + dc390_Disconnect( pACB ); + goto unlock; + } + + if (istatus & RESELECTED) + { + dc390_Reselect( pACB ); + goto unlock; + } + + else if (istatus & (SELECTED | SEL_ATTENTION)) + { + printk (KERN_ERR "DC390: Target mode not supported!\n"); + goto unlock; + } + + if (istatus & (SUCCESSFUL_OP|SERVICE_REQUEST) ) + { + pDCB = pACB->pActiveDCB; + if (!pDCB) + { + printk (KERN_ERR "DC390: Suc. op/ Serv. req: pActiveDCB = 0!\n"); + goto unlock; + }; + pSRB = pDCB->pActiveSRB; + if( pDCB->DCBFlag & ABORT_DEV_ ) + dc390_EnableMsgOut_Abort (pACB, pSRB); + + phase = pSRB->ScsiPhase; + DEBUG1(printk (KERN_INFO "DC390: [%i]%s(0) (%02x)\n", phase, dc390_p0_str[phase], sstatus);) + stateV = (void *) dc390_phase0[phase]; + ( *stateV )( pACB, pSRB, &sstatus ); + + pSRB->ScsiPhase = sstatus & 7; + phase = (UCHAR) sstatus & 7; + DEBUG1(printk (KERN_INFO "DC390: [%i]%s(1) (%02x)\n", phase, dc390_p1_str[phase], sstatus);) + stateV = (void *) dc390_phase1[phase]; + ( *stateV )( pACB, pSRB, &sstatus ); + goto unlock; + } + + unlock: + //DC390_LOCK_DRV_NI; + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; + //DC390_UNLOCK_DRV; /* Restore initial flags */ +} + +void +do_DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs) +{ + DEBUG1(printk (KERN_INFO "DC390: Irq (%i) caught: ", irq);) + /* Locking is done in DC390_Interrupt */ + DC390_Interrupt(irq, dev_id, regs); + DEBUG1(printk (".. IRQ returned\n");) +} + +void +dc390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + UCHAR sstatus; + PSGL psgl; + UINT ResidCnt, xferCnt; + UCHAR dstate = 0; + + sstatus = *psstatus; + + if( !(pSRB->SRBState & SRB_XFERPAD) ) + { + if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR) ) + pSRB->SRBStatus |= PARITY_ERROR; + + if( sstatus & COUNT_2_ZERO ) + { + int ctr = 6000000; /* only try for about a second */ + while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen ); + if (!ctr) printk (KERN_CRIT "DC390: Deadlock in DataOut_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr)); + dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24; + pSRB->TotalXferredLen += pSRB->SGToBeXferLen; + pSRB->SGIndex++; + if( pSRB->SGIndex < pSRB->SGcount ) + { + pSRB->pSegmentList++; + psgl = pSRB->pSegmentList; + + pSRB->SGBusAddr = virt_to_bus( psgl->address ); + pSRB->SGToBeXferLen = (ULONG) psgl->length; + } + else + pSRB->SGToBeXferLen = 0; + } + else + { + ResidCnt = (UINT) DC390_read8 (Current_Fifo) & 0x1f; + ResidCnt |= (UINT) DC390_read8 (CtcReg_High) << 16; + ResidCnt |= (UINT) DC390_read8 (CtcReg_Mid) << 8; + ResidCnt += (UINT) DC390_read8 (CtcReg_Low); + + xferCnt = pSRB->SGToBeXferLen - ResidCnt; + pSRB->SGBusAddr += xferCnt; + pSRB->TotalXferredLen += xferCnt; + pSRB->SGToBeXferLen = ResidCnt; + } + } + if ((*psstatus & 7) != SCSI_DATA_OUT) + { + DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + } +} + +void +dc390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + UCHAR sstatus, residual, bval; + PSGL psgl; + UINT ResidCnt, i; + ULONG xferCnt; + PUCHAR ptr; + + sstatus = *psstatus; + + if( !(pSRB->SRBState & SRB_XFERPAD) ) + { + if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR)) + pSRB->SRBStatus |= PARITY_ERROR; + + if( sstatus & COUNT_2_ZERO ) + { + int ctr = 6000000; /* only try for about a second */ + int dstate = 0; + while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen ); + if (!ctr) printk (KERN_CRIT "DC390: Deadlock in DataIn_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr)); + if (!ctr) printk (KERN_CRIT "DC390: DataIn_0: DMA State: %i\n", dstate); + dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24; + DEBUG1(ResidCnt = ((ULONG) DC390_read8 (CtcReg_High) << 16) \ + + ((ULONG) DC390_read8 (CtcReg_Mid) << 8) \ + + ((ULONG) DC390_read8 (CtcReg_Low));) + DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%i,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen);) + + DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ + + pSRB->TotalXferredLen += pSRB->SGToBeXferLen; + pSRB->SGIndex++; + if( pSRB->SGIndex < pSRB->SGcount ) + { + pSRB->pSegmentList++; + psgl = pSRB->pSegmentList; + + pSRB->SGBusAddr = virt_to_bus( psgl->address ); + pSRB->SGToBeXferLen = (ULONG) psgl->length; + } + else + pSRB->SGToBeXferLen = 0; + } + else /* phase changed */ + { + residual = 0; + bval = DC390_read8 (Current_Fifo); + while( bval & 0x1f ) + { + DEBUG1(printk (KERN_DEBUG "Check for residuals,");) + if( (bval & 0x1f) == 1 ) + { + for(i=0; i < 0x100; i++) + { + bval = DC390_read8 (Current_Fifo); + if( !(bval & 0x1f) ) + goto din_1; + else if( i == 0x0ff ) + { + residual = 1; /* ;1 residual byte */ + goto din_1; + } + } + } + else + bval = DC390_read8 (Current_Fifo); + } +din_1: + DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_BLAST_CMD); + for (i = 0xa000; i; i--) + { + bval = DC390_read8 (DMA_Status); + if (bval & BLAST_COMPLETE) + break; + } + /* It seems a DMA Blast abort isn't that bad ... */ + if (!i) printk (KERN_ERR "DC390: DMA Blast aborted unfinished!\n"); + //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ + dc390_laststatus &= ~0xff000000; dc390_laststatus |= bval << 24; + + DEBUG1(printk (KERN_DEBUG "Blast: Read %i times DMA_Status %02x", 0xa000-i, bval);) + ResidCnt = (UINT) DC390_read8 (CtcReg_High); + ResidCnt <<= 8; + ResidCnt |= (UINT) DC390_read8 (CtcReg_Mid); + ResidCnt <<= 8; + ResidCnt |= (UINT) DC390_read8 (CtcReg_Low); + + xferCnt = pSRB->SGToBeXferLen - ResidCnt; + pSRB->SGBusAddr += xferCnt; + pSRB->TotalXferredLen += xferCnt; + pSRB->SGToBeXferLen = ResidCnt; + + if( residual ) + { + bval = DC390_read8 (ScsiFifo); /* get one residual byte */ + ptr = (PUCHAR) bus_to_virt( pSRB->SGBusAddr ); + *ptr = bval; + pSRB->SGBusAddr++; xferCnt++; + pSRB->TotalXferredLen++; + pSRB->SGToBeXferLen--; + } + DEBUG1(printk (KERN_DEBUG "Xfered: %li, Total: %li, Remaining: %li\n", xferCnt,\ + pSRB->TotalXferredLen, pSRB->SGToBeXferLen);) + + } + } + if ((*psstatus & 7) != SCSI_DATA_IN) + { + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ + } +} + +static void +dc390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ +} + +static void +dc390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + + pSRB->TargetStatus = DC390_read8 (ScsiFifo); + //udelay (1); + pSRB->EndMessage = DC390_read8 (ScsiFifo); /* get message */ + + *psstatus = SCSI_NOP0; + pSRB->SRBState = SRB_COMPLETED; + DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD); +} + +static void +dc390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) ) + *psstatus = SCSI_NOP0; + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); +} + + +static void __inline__ +dc390_reprog (PACB pACB, PDCB pDCB) +{ + DC390_write8 (Sync_Period, pDCB->SyncPeriod); + DC390_write8 (Sync_Offset, pDCB->SyncOffset); + DC390_write8 (CtrlReg3, pDCB->CtrlR3); + DC390_write8 (CtrlReg4, pDCB->CtrlR4); + dc390_SetXferRate (pACB, pDCB); +}; + + +#ifdef DC390_DEBUG0 +static void +dc390_printMsg (UCHAR *MsgBuf, UCHAR len) +{ + int i; + printk (" %02x", MsgBuf[0]); + for (i = 1; i < len; i++) + printk (" %02x", MsgBuf[i]); + printk ("\n"); +}; +#endif + +#define DC390_ENABLE_MSGOUT DC390_write8 (ScsiCmd, SET_ATN_CMD) + +/* reject_msg */ +static void __inline__ +dc390_MsgIn_reject (PACB pACB, PSRB pSRB) +{ + pSRB->MsgOutBuf[0] = MESSAGE_REJECT; + pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT; + DEBUG0 (printk (KERN_INFO "DC390: Reject message\n");) +} + +/* abort command */ +static void __inline__ +dc390_EnableMsgOut_Abort ( PACB pACB, PSRB pSRB ) +{ + pSRB->MsgOutBuf[0] = ABORT; + pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT; + pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_; +} + +static PSRB +dc390_MsgIn_QTag (PACB pACB, PDCB pDCB, UCHAR tag) +{ + PSRB lastSRB = pDCB->pGoingLast; + PSRB pSRB = pDCB->pGoingSRB; + + if (pSRB) + { + for( ;pSRB ; ) + { + if (pSRB->TagNumber == tag) break; + if (pSRB == lastSRB) goto mingx0; + pSRB = pSRB->pNextSRB; + } + + if( pDCB->DCBFlag & ABORT_DEV_ ) + { + pSRB->SRBState = SRB_ABORT_SENT; + dc390_EnableMsgOut_Abort( pACB, pSRB ); + } + + if( !(pSRB->SRBState & SRB_DISCONNECT) ) + goto mingx0; + + pDCB->pActiveSRB = pSRB; + pSRB->SRBState = SRB_DATA_XFER; + } + else + { + mingx0: + pSRB = pACB->pTmpSRB; + pSRB->SRBState = SRB_UNEXPECT_RESEL; + pDCB->pActiveSRB = pSRB; + pSRB->MsgOutBuf[0] = ABORT_TAG; + pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT; + } + return pSRB; +} + + +/* set async transfer mode */ +static void +dc390_MsgIn_set_async (PACB pACB, PSRB pSRB) +{ + PDCB pDCB = pSRB->pSRBDCB; + if (!(pSRB->SRBState & DO_SYNC_NEGO)) + printk (KERN_INFO "DC390: Target %i initiates Non-Sync?\n", pDCB->TargetID); + pSRB->SRBState &= ~DO_SYNC_NEGO; + pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE); + pDCB->SyncPeriod = 0; + pDCB->SyncOffset = 0; + //pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */ + pDCB->CtrlR3 = FAST_CLK; /* fast clock / normal scsi */ + pDCB->CtrlR4 &= 0x3f; + pDCB->CtrlR4 |= pACB->glitch_cfg; /* glitch eater */ + dc390_reprog (pACB, pDCB); +} + +/* set sync transfer mode */ +static void +dc390_MsgIn_set_sync (PACB pACB, PSRB pSRB) +{ + UCHAR bval; + USHORT wval, wval1; + PDCB pDCB = pSRB->pSRBDCB; + UCHAR oldsyncperiod = pDCB->SyncPeriod; + UCHAR oldsyncoffset = pDCB->SyncOffset; + + if (!(pSRB->SRBState & DO_SYNC_NEGO)) + { + printk (KERN_INFO "DC390: Target %i initiates Sync: %ins %i ... answer ...\n", + pDCB->TargetID, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]); + + /* reject */ + //dc390_MsgIn_reject (pACB, pSRB); + //return dc390_MsgIn_set_async (pACB, pSRB); + + /* Reply with corrected SDTR Message */ + if (pSRB->MsgInBuf[4] > 15) + { + printk (KERN_INFO "DC390: Lower Sync Offset to 15\n"); + pSRB->MsgInBuf[4] = 15; + } + if (pSRB->MsgInBuf[3] < pDCB->NegoPeriod) + { + printk (KERN_INFO "DC390: Set sync nego period to %ins\n", pDCB->NegoPeriod << 2); + pSRB->MsgInBuf[3] = pDCB->NegoPeriod; + }; + memcpy (pSRB->MsgOutBuf, pSRB->MsgInBuf, 5); + pSRB->MsgCnt = 5; + DC390_ENABLE_MSGOUT; + }; + + pSRB->SRBState &= ~DO_SYNC_NEGO; + pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE; + pDCB->SyncOffset &= 0x0f0; + pDCB->SyncOffset |= pSRB->MsgInBuf[4]; + pDCB->NegoPeriod = pSRB->MsgInBuf[3]; + + wval = (USHORT) pSRB->MsgInBuf[3]; + wval = wval << 2; wval -= 3; wval1 = wval / 25; /* compute speed */ + if( (wval1 * 25) != wval) wval1++; + bval = FAST_CLK+FAST_SCSI; /* fast clock / fast scsi */ + + pDCB->CtrlR4 &= 0x3f; /* Glitch eater: 12ns less than normal */ + if (pACB->glitch_cfg != NS_TO_GLITCH(0)) + pDCB->CtrlR4 |= NS_TO_GLITCH(((GLITCH_TO_NS(pACB->glitch_cfg)) - 1)); + else + pDCB->CtrlR4 |= NS_TO_GLITCH(0); + if (wval1 < 4) pDCB->CtrlR4 |= NS_TO_GLITCH(0); /* Ultra */ + + if (wval1 >= 8) + { + wval1--; /* Timing computation differs by 1 from FAST_SCSI */ + bval = FAST_CLK; /* fast clock / normal scsi */ + pDCB->CtrlR4 |= pACB->glitch_cfg; /* glitch eater */ + } + + pDCB->CtrlR3 = bval; + pDCB->SyncPeriod = (UCHAR)wval1; + + if ((oldsyncperiod != wval1 || oldsyncoffset != pDCB->SyncOffset) && pDCB->TargetLUN == 0) + { + if (! (bval & FAST_SCSI)) wval1++; + printk (KERN_INFO "DC390: Target %i: Sync transfer %i.%1i MHz, Offset %i\n", pDCB->TargetID, + 40/wval1, ((40%wval1)*10+wval1/2)/wval1, pDCB->SyncOffset & 0x0f); + } + + dc390_reprog (pACB, pDCB); +}; + + +/* handle RESTORE_PTR */ +static void +dc390_restore_ptr (PACB pACB, PSRB pSRB) +{ + PSGL psgl; + pSRB->TotalXferredLen = 0; + pSRB->SGIndex = 0; + if( pSRB->pcmd->use_sg ) + { + pSRB->SGcount = (UCHAR) pSRB->pcmd->use_sg; + pSRB->pSegmentList = (PSGL) pSRB->pcmd->request_buffer; + psgl = pSRB->pSegmentList; + while (pSRB->TotalXferredLen + (ULONG) psgl->length < pSRB->Saved_Ptr) + { + pSRB->TotalXferredLen += (ULONG) psgl->length; + pSRB->SGIndex++; + if( pSRB->SGIndex < pSRB->SGcount ) + { + pSRB->pSegmentList++; + psgl = pSRB->pSegmentList; + + pSRB->SGBusAddr = virt_to_bus( psgl->address ); + pSRB->SGToBeXferLen = (ULONG) psgl->length; + } + else + pSRB->SGToBeXferLen = 0; + } + pSRB->SGToBeXferLen -= (pSRB->Saved_Ptr - pSRB->TotalXferredLen); + pSRB->SGBusAddr += (pSRB->Saved_Ptr - pSRB->TotalXferredLen); + printk (KERN_INFO "DC390: Pointer restored. Segment %i, Total %li, Bus %08lx\n", pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr); + } + else if( pSRB->pcmd->request_buffer ) + { + pSRB->SGcount = 1; + pSRB->pSegmentList = (PSGL) &pSRB->Segmentx; + pSRB->Segmentx.address = (PUCHAR) pSRB->pcmd->request_buffer + pSRB->Saved_Ptr; + pSRB->Segmentx.length = pSRB->pcmd->request_bufflen - pSRB->Saved_Ptr; + printk (KERN_INFO "DC390: Pointer restored. Total %li, Bus %p\n", + pSRB->Saved_Ptr, pSRB->Segmentx.address); + } + else + { + pSRB->SGcount = 0; + printk (KERN_INFO "DC390: RESTORE_PTR message for Transfer without Scatter-Gather ??\n"); + }; + + pSRB->TotalXferredLen = pSRB->Saved_Ptr; +}; + + +/* According to the docs, the AM53C974 reads the message and + * generates a Succesful Operation IRQ before asserting ACK for + * the last byte (how does it know whether it's the last ?) */ +/* The old code handled it in another way, indicating, that on + * every message byte an IRQ is generated and every byte has to + * be manually ACKed. Hmmm ? (KG, 98/11/28) */ +/* The old implementation was correct. Sigh! */ + +/* Check if the message is complete */ +static UCHAR __inline__ +dc390_MsgIn_complete (UCHAR *msgbuf, UINT len) +{ + if (*msgbuf == EXTENDED_MESSAGE) + { + if (len < 2) return 0; + if (len < msgbuf[1] + 2) return 0; + } + else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f) // two byte messages + if (len < 2) return 0; + return 1; +} + + + +/* read and eval received messages */ +void +dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + PDCB pDCB = pACB->pActiveDCB; + + /* Read the msg */ + + pSRB->MsgInBuf[pACB->MsgLen++] = DC390_read8 (ScsiFifo); + //pSRB->SRBState = 0; + + /* Msg complete ? */ + if (dc390_MsgIn_complete (pSRB->MsgInBuf, pACB->MsgLen)) + { + DEBUG0 (printk (KERN_INFO "DC390: MsgIn:"); dc390_printMsg (pSRB->MsgInBuf, pACB->MsgLen);) + /* Now eval the msg */ + switch (pSRB->MsgInBuf[0]) + { + case DISCONNECT: + pSRB->SRBState = SRB_DISCONNECT; break; + + case SIMPLE_QUEUE_TAG: + case HEAD_OF_QUEUE_TAG: + case ORDERED_QUEUE_TAG: + pSRB = dc390_MsgIn_QTag (pACB, pDCB, pSRB->MsgInBuf[1]); + break; + + case MESSAGE_REJECT: + DC390_write8 (ScsiCmd, RESET_ATN_CMD); + pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */ + if( pSRB->SRBState & DO_SYNC_NEGO) + dc390_MsgIn_set_async (pACB, pSRB); + break; + + case EXTENDED_MESSAGE: + /* reject every extended msg but SDTR */ + if (pSRB->MsgInBuf[1] != 3 || pSRB->MsgInBuf[2] != EXTENDED_SDTR) + dc390_MsgIn_reject (pACB, pSRB); + else + { + if (pSRB->MsgInBuf[3] == 0 || pSRB->MsgInBuf[4] == 0) + dc390_MsgIn_set_async (pACB, pSRB); + else + dc390_MsgIn_set_sync (pACB, pSRB); + }; + + // nothing has to be done + case COMMAND_COMPLETE: break; + + // SAVE POINTER may be ignored as we have the PSRB associated with the + // scsi command. Thanks, Gerard, for pointing it out. + case SAVE_POINTERS: + pSRB->Saved_Ptr = pSRB->TotalXferredLen; + break; + // The device might want to restart transfer with a RESTORE + case RESTORE_POINTERS: + DEBUG0(printk ("DC390: RESTORE POINTER message received ... try to handle\n");) + dc390_restore_ptr (pACB, pSRB); + break; + + // reject unknown messages + default: dc390_MsgIn_reject (pACB, pSRB); + } + + /* Clear counter and MsgIn state */ + pSRB->SRBState &= ~SRB_MSGIN; + pACB->MsgLen = 0; + }; + + *psstatus = SCSI_NOP0; + DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD); + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); +} + + +void +dc390_DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir) +{ + PSGL psgl; + ULONG lval; + PDCB pDCB = pACB->pActiveDCB; + + if (pSRB == pACB->pTmpSRB) + { + if (pDCB) printk (KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (%02i-%i)\n", + pDCB->TargetID, pDCB->TargetLUN); + else printk (KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (DCB 0!)\n"); + dc390_EnableMsgOut_Abort (pACB, pSRB); + if (pDCB) pDCB->DCBFlag |= ABORT_DEV; + return; + } + + if( pSRB->SGIndex < pSRB->SGcount ) + { + DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir /* | DMA_INT */); + if( !pSRB->SGToBeXferLen ) + { + psgl = pSRB->pSegmentList; + pSRB->SGBusAddr = virt_to_bus( psgl->address ); + pSRB->SGToBeXferLen = (ULONG) psgl->length; + DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment.");) + } + lval = pSRB->SGToBeXferLen; + DEBUG1(printk (KERN_DEBUG " DC390: Start transfer: %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr);) + DC390_write8 (CtcReg_Low, (UCHAR) lval); + lval >>= 8; + DC390_write8 (CtcReg_Mid, (UCHAR) lval); + lval >>= 8; + DC390_write8 (CtcReg_High, (UCHAR) lval); + + DC390_write32 (DMA_XferCnt, pSRB->SGToBeXferLen); + DC390_write32 (DMA_XferAddr, pSRB->SGBusAddr); + + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); /* | DMA_INT; */ + pSRB->SRBState = SRB_DATA_XFER; + + DC390_write8 (ScsiCmd, DMA_COMMAND+INFO_XFER_CMD); + + DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT); + //DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);) + //DEBUG1(printk (KERN_DEBUG "DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status));) + //DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);) + } + else /* xfer pad */ + { + if( pSRB->SGcount ) + { + pSRB->AdaptStatus = H_OVER_UNDER_RUN; + pSRB->SRBStatus |= OVER_RUN; + DEBUG0(printk (KERN_WARNING " DC390: Overrun -");) + } + DEBUG0(printk (KERN_WARNING " Clear transfer pad \n");) + DC390_write8 (CtcReg_Low, 0); + DC390_write8 (CtcReg_Mid, 0); + DC390_write8 (CtcReg_High, 0); + + pSRB->SRBState |= SRB_XFERPAD; + DC390_write8 (ScsiCmd, DMA_COMMAND+XFER_PAD_BYTE); +/* + DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); // | DMA_INT; + DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT); +*/ + } +} + + +static void +dc390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + dc390_DataIO_Comm (pACB, pSRB, WRITE_DIRECTION); +} + +static void +dc390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + dc390_DataIO_Comm (pACB, pSRB, READ_DIRECTION); +} + +void +dc390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + PDCB pDCB; + UCHAR i, cnt; + PUCHAR ptr; + + DC390_write8 (ScsiCmd, RESET_ATN_CMD); + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + if( !(pSRB->SRBFlag & AUTO_REQSENSE) ) + { + cnt = (UCHAR) pSRB->pcmd->cmd_len; + ptr = (PUCHAR) pSRB->pcmd->cmnd; + for(i=0; i < cnt; i++) + DC390_write8 (ScsiFifo, *(ptr++)); + } + else + { + UCHAR bval = 0; + DC390_write8 (ScsiFifo, REQUEST_SENSE); + pDCB = pACB->pActiveDCB; + DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5); + DC390_write8 (ScsiFifo, bval); + DC390_write8 (ScsiFifo, bval); + DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer)); + DC390_write8 (ScsiFifo, bval); + DEBUG0(printk(KERN_DEBUG "DC390: AutoReqSense (CmndPhase)!\n");) + } + pSRB->SRBState = SRB_COMMAND; + DC390_write8 (ScsiCmd, INFO_XFER_CMD); +} + +static void +dc390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + pSRB->SRBState = SRB_STATUS; + DC390_write8 (ScsiCmd, INITIATOR_CMD_CMPLTE); + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); +} + +void +dc390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + UCHAR bval, i, cnt; + PUCHAR ptr; + PDCB pDCB; + + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + pDCB = pACB->pActiveDCB; + if( !(pSRB->SRBState & SRB_MSGOUT) ) + { + cnt = pSRB->MsgCnt; + if( cnt ) + { + ptr = (PUCHAR) pSRB->MsgOutBuf; + for(i=0; i < cnt; i++) + DC390_write8 (ScsiFifo, *(ptr++)); + pSRB->MsgCnt = 0; + if( (pDCB->DCBFlag & ABORT_DEV_) && + (pSRB->MsgOutBuf[0] == ABORT) ) + pSRB->SRBState = SRB_ABORT_SENT; + } + else + { + bval = ABORT; /* ??? MSG_NOP */ + if( (pSRB->pcmd->cmnd[0] == INQUIRY ) || + (pSRB->pcmd->cmnd[0] == REQUEST_SENSE) || + (pSRB->SRBFlag & AUTO_REQSENSE) ) + { + if( pDCB->SyncMode & SYNC_ENABLE ) + goto mop1; + } + DC390_write8 (ScsiFifo, bval); + } + DC390_write8 (ScsiCmd, INFO_XFER_CMD); + } + else + { +mop1: + printk (KERN_ERR "DC390: OLD Sync Nego code triggered! (%i %i)\n", pDCB->TargetID, pDCB->TargetLUN); + DC390_write8 (ScsiFifo, EXTENDED_MESSAGE); + DC390_write8 (ScsiFifo, 3); /* ;length of extended msg */ + DC390_write8 (ScsiFifo, EXTENDED_SDTR); /* ; sync nego */ + DC390_write8 (ScsiFifo, pDCB->NegoPeriod); + if (pDCB->SyncOffset & 0x0f) + DC390_write8 (ScsiFifo, pDCB->SyncOffset); + else + DC390_write8 (ScsiFifo, SYNC_NEGO_OFFSET); + pSRB->SRBState |= DO_SYNC_NEGO; + DC390_write8 (ScsiCmd, INFO_XFER_CMD); + } +} + +static void +dc390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + if( !(pSRB->SRBState & SRB_MSGIN) ) + { + pSRB->SRBState &= ~SRB_DISCONNECT; + pSRB->SRBState |= SRB_MSGIN; + } + DC390_write8 (ScsiCmd, INFO_XFER_CMD); + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); +} + +static void +dc390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ +} + +static void +dc390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus) +{ +} + + +static void +dc390_SetXferRate( PACB pACB, PDCB pDCB ) +{ + UCHAR bval, i, cnt; + PDCB ptr; + + if( !(pDCB->TargetLUN) ) + { + if( !pACB->scan_devices ) + { + ptr = pACB->pLinkDCB; + cnt = pACB->DCBCnt; + bval = pDCB->TargetID; + for(i=0; iTargetID == bval ) + { + ptr->SyncPeriod = pDCB->SyncPeriod; + ptr->SyncOffset = pDCB->SyncOffset; + ptr->CtrlR3 = pDCB->CtrlR3; + ptr->CtrlR4 = pDCB->CtrlR4; + ptr->SyncMode = pDCB->SyncMode; + } + ptr = ptr->pNextDCB; + } + } + } + return; +} + + +void +dc390_Disconnect( PACB pACB ) +{ + PDCB pDCB; + PSRB pSRB, psrb; + UCHAR i, cnt; + + DEBUG0(printk(KERN_INFO "DISC,");) + + if (!pACB->Connected) printk(KERN_ERR "DC390: Disconnect not-connected bus?\n"); + pACB->Connected = 0; + pDCB = pACB->pActiveDCB; + if (!pDCB) + { + int j = 400; + DEBUG0(printk(KERN_ERR "ACB:%p->ActiveDCB:%p IOPort:%04x IRQ:%02x !\n",\ + pACB, pDCB, pACB->IOPortBase, pACB->IRQLevel);) + while (--j) udelay (1000); + DC390_read8 (INT_Status); /* Reset Pending INT */ + DC390_write8 (ScsiCmd, EN_SEL_RESEL); + return; + } + DC390_write8 (ScsiCmd, EN_SEL_RESEL); + pSRB = pDCB->pActiveSRB; + pACB->pActiveDCB = 0; + pSRB->ScsiPhase = SCSI_NOP0; + if( pSRB->SRBState & SRB_UNEXPECT_RESEL ) + { + pSRB->SRBState = 0; + dc390_Waiting_process ( pACB ); + } + else if( pSRB->SRBState & SRB_ABORT_SENT ) + { + pDCB->TagMask = 0; + pDCB->DCBFlag = 0; + cnt = pDCB->GoingSRBCnt; + pDCB->GoingSRBCnt = 0; + pSRB = pDCB->pGoingSRB; + for( i=0; i < cnt; i++) + { + psrb = pSRB->pNextSRB; + dc390_Free_insert (pACB, pSRB); + pSRB = psrb; + } + pDCB->pGoingSRB = 0; + dc390_Query_to_Waiting (pACB); + dc390_Waiting_process (pACB); + } + else + { + if( (pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) || + !(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED)) ) + { /* Selection time out */ + if( !(1/*pACB->scan_devices*/) ) + { + pSRB->SRBState = SRB_READY; + dc390_freetag (pDCB, pSRB); + dc390_Going_to_Waiting (pDCB, pSRB); + dc390_waiting_timer (pACB, HZ/5); + } + else + { + pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT; + goto disc1; + } + } + else if( pSRB->SRBState & SRB_DISCONNECT ) + { + dc390_Waiting_process ( pACB ); + } + else if( pSRB->SRBState & SRB_COMPLETED ) + { +disc1: + dc390_freetag (pDCB, pSRB); + pDCB->pActiveSRB = 0; + pSRB->SRBState = SRB_FREE; + dc390_SRBdone( pACB, pDCB, pSRB); + } + } + pACB->MsgLen = 0; +} + + +void +dc390_Reselect( PACB pACB ) +{ + PDCB pDCB; + PSRB pSRB; + UCHAR id, lun; + + DEBUG0(printk(KERN_INFO "RSEL,");) + pACB->Connected = 1; + pDCB = pACB->pActiveDCB; + if( pDCB ) + { /* Arbitration lost but Reselection won */ + DEBUG0(printk ("DC390: (ActiveDCB != 0: Arb. lost but resel. won)!\n");) + pSRB = pDCB->pActiveSRB; + if( !( pACB->scan_devices ) ) + { + pSRB->SRBState = SRB_READY; + dc390_freetag (pDCB, pSRB); + dc390_Going_to_Waiting ( pDCB, pSRB); + dc390_waiting_timer (pACB, HZ/5); + } + } + /* Get ID */ + lun = DC390_read8 (ScsiFifo); + DEBUG0(printk ("Dev %02x,", lun);) + if (!(lun & (1 << pACB->pScsiHost->this_id))) + printk (KERN_ERR "DC390: Reselection must select host adapter: %02x!\n", lun); + else + lun ^= 1 << pACB->pScsiHost->this_id; /* Mask AdapterID */ + id = 0; while (lun >>= 1) id++; + /* Get LUN */ + lun = DC390_read8 (ScsiFifo); + if (!(lun & IDENTIFY_BASE)) printk (KERN_ERR "DC390: Resel: Expect identify message!\n"); + lun &= 7; + DEBUG0(printk ("(%02i-%i),", id, lun);) + pDCB = dc390_findDCB (pACB, id, lun); + if (!pDCB) + { + printk (KERN_ERR "DC390: Reselect from non existing device (%02i-%i)\n", + id, lun); + return; + } + pACB->pActiveDCB = pDCB; + /* TagQ: We expect a message soon, so never mind the exact SRB */ + if( pDCB->SyncMode & EN_TAG_QUEUEING ) + { + pSRB = pACB->pTmpSRB; + pDCB->pActiveSRB = pSRB; + } + else + { + pSRB = pDCB->pActiveSRB; + if( !pSRB || !(pSRB->SRBState & SRB_DISCONNECT) ) + { + pSRB= pACB->pTmpSRB; + pSRB->SRBState = SRB_UNEXPECT_RESEL; + printk (KERN_ERR "DC390: Reselect without outstanding cmnd (%02i-%i)\n", + id, lun); + pDCB->pActiveSRB = pSRB; + dc390_EnableMsgOut_Abort ( pACB, pSRB ); + } + else + { + if( pDCB->DCBFlag & ABORT_DEV_ ) + { + pSRB->SRBState = SRB_ABORT_SENT; + printk (KERN_INFO "DC390: Reselect: Abort (%02i-%i)\n", + id, lun); + dc390_EnableMsgOut_Abort( pACB, pSRB ); + } + else + pSRB->SRBState = SRB_DATA_XFER; + } + } + + DEBUG1(printk (KERN_DEBUG "Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber);) + pSRB->ScsiPhase = SCSI_NOP0; + DC390_write8 (Scsi_Dest_ID, pDCB->TargetID); + DC390_write8 (Sync_Period, pDCB->SyncPeriod); + DC390_write8 (Sync_Offset, pDCB->SyncOffset); + DC390_write8 (CtrlReg1, pDCB->CtrlR1); + DC390_write8 (CtrlReg3, pDCB->CtrlR3); + DC390_write8 (CtrlReg4, pDCB->CtrlR4); /* ; Glitch eater */ + DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD); /* ;to release the /ACK signal */ +} + + +static void +dc390_remove_dev (PACB pACB, PDCB pDCB) +{ + PDCB pPrevDCB = pACB->pLinkDCB; + + if (pDCB->GoingSRBCnt > 1) + { + DCBDEBUG(printk (KERN_INFO "DC390: Driver won't free DCB (ID %i, LUN %i): 0x%08x because of SRBCnt %i\n",\ + pDCB->TargetID, pDCB->TargetLUN, (int)pDCB, pDCB->GoingSRBCnt);) + return; + }; + pACB->DCBmap[pDCB->TargetID] &= ~(1 << pDCB->TargetLUN); + + // The first one + if (pDCB == pACB->pLinkDCB) + { + // The last one + if (pACB->pLastDCB == pDCB) { + pDCB->pNextDCB = 0; pACB->pLastDCB = 0; + } + pACB->pLinkDCB = pDCB->pNextDCB; + } + else + { + while (pPrevDCB->pNextDCB != pDCB) pPrevDCB = pPrevDCB->pNextDCB; + pPrevDCB->pNextDCB = pDCB->pNextDCB; + if (pDCB == pACB->pLastDCB) pACB->pLastDCB = pPrevDCB; + } + + DCBDEBUG(printk (KERN_INFO "DC390: Driver about to free DCB (ID %i, LUN %i): %p\n",\ + pDCB->TargetID, pDCB->TargetLUN, pDCB);) + if (pDCB == pACB->pActiveDCB) pACB->pActiveDCB = 0; + if (pDCB == pACB->pLinkDCB) pACB->pLinkDCB = pDCB->pNextDCB; + if (pDCB == pACB->pDCBRunRobin) pACB->pDCBRunRobin = pDCB->pNextDCB; + kfree (pDCB); + pACB->DCBCnt--; + /* pACB->DeviceCnt--; */ +}; + + +static UCHAR __inline__ +dc390_tagq_blacklist (char* name) +{ + UCHAR i; + for(i=0; iVers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2 ) + { + if ( (ptr->Flags & SCSI_INQ_CMDQUEUE) && + (pDCB->DevMode & TAG_QUEUEING_) && + /* ((pDCB->DevType == TYPE_DISK) + || (pDCB->DevType == TYPE_MOD)) &&*/ + !dc390_tagq_blacklist (((char*)ptr)+8) ) + { + if (pDCB->MaxCommand ==1) pDCB->MaxCommand = pDCB->pDCBACB->TagMaxNum; + pDCB->SyncMode |= EN_TAG_QUEUEING /* | EN_ATN_STOP */; + //pDCB->TagMask = 0; + } + else + pDCB->MaxCommand = 1; + } +}; + + +static void +dc390_add_dev (PACB pACB, PDCB pDCB, PSCSI_INQDATA ptr) +{ + UCHAR bval1 = ptr->DevType & SCSI_DEVTYPE; + pDCB->DevType = bval1; + /* if (bval1 == TYPE_DISK || bval1 == TYPE_MOD) */ + dc390_disc_tagq_set (pDCB, ptr); +}; + + +void +dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) +{ + UCHAR bval, status, i, DCB_removed; + PSCSICMD pcmd; + PSCSI_INQDATA ptr; + PSGL ptr2; + ULONG swlval; + + pcmd = pSRB->pcmd; DCB_removed = 0; + status = pSRB->TargetStatus; + ptr = (PSCSI_INQDATA) (pcmd->request_buffer); + if( pcmd->use_sg ) + ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address); + + DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result,\ + pSRB, pcmd->pid);) + if(pSRB->SRBFlag & AUTO_REQSENSE) + { /* Last command was a Request Sense */ + pSRB->SRBFlag &= ~AUTO_REQSENSE; + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = CHECK_CONDITION << 1; +#ifdef DC390_REMOVABLEDEBUG + switch (pcmd->sense_buffer[2] & 0x0f) + { + case NOT_READY: printk (KERN_INFO "DC390: ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, + status, pACB->scan_devices); break; + case UNIT_ATTENTION: printk (KERN_INFO "DC390: ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, + status, pACB->scan_devices); break; + case ILLEGAL_REQUEST: printk (KERN_INFO "DC390: ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, + status, pACB->scan_devices); break; + case MEDIUM_ERROR: printk (KERN_INFO "DC390: ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, + status, pACB->scan_devices); break; + case HARDWARE_ERROR: printk (KERN_INFO "DC390: ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, + status, pACB->scan_devices); break; + } +#endif + //pcmd->result = MK_RES(DRIVER_SENSE,DID_OK,0,status); + if (status == (CHECK_CONDITION << 1)) + { + pcmd->result = MK_RES_LNX(0,DID_BAD_TARGET,0,/*CHECK_CONDITION*/0); + goto ckc_e; + } + if(pSRB->RetryCnt == 0) + { + //(UINT)(pSRB->pcmd->cmnd[0]) = pSRB->Segment0[0]; + pSRB->TotalXferredLen = pSRB->SavedTotXLen; + if( (pSRB->TotalXferredLen) && + (pSRB->TotalXferredLen >= pcmd->underflow) ) + SET_RES_DID(pcmd->result,DID_OK) + else + pcmd->result = MK_RES_LNX(DRIVER_SENSE,DID_OK,0,CHECK_CONDITION); + REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x,Result=%08x,XferL=%08x\n",pSRB->pcmd->cmnd[0],\ + (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);) + goto ckc_e; + } + else /* Retry */ + { + pSRB->RetryCnt--; + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + //*((PUINT) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0]; + //*((PUINT) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1]; + /* Don't retry on TEST_UNIT_READY */ + if( pSRB->pcmd->cmnd[0] == TEST_UNIT_READY /* || pSRB->pcmd->cmnd[0] == START_STOP */) + { + pcmd->result = MK_RES_LNX(DRIVER_SENSE,DID_OK,0,CHECK_CONDITION); + REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->pcmd->cmnd[0],\ + (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);) + goto ckc_e; + } + SET_RES_DRV(pcmd->result,DRIVER_SENSE); + pSRB->SGcount = (UCHAR) pSRB->SavedSGCount; + //pSRB->ScsiCmdLen = (UCHAR) (pSRB->Segment1[0] >> 8); + DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->pid, pcmd->cmnd[0], pcmd->target, pcmd->lun);) + pSRB->SGIndex = 0; + pSRB->TotalXferredLen = 0; + pSRB->SGToBeXferLen = 0; + if( pcmd->use_sg ) + pSRB->pSegmentList = (PSGL) pcmd->request_buffer; + else if( pcmd->request_buffer ) + { + pSRB->pSegmentList = (PSGL) &pSRB->Segmentx; + pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; + pSRB->Segmentx.length = pcmd->request_bufflen; + } + if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) { + dc390_Going_to_Waiting ( pDCB, pSRB ); + dc390_waiting_timer (pACB, HZ/5); + } + return; + } + } + if( status ) + { + if( status_byte(status) == CHECK_CONDITION ) + { + REMOVABLEDEBUG(printk (KERN_INFO "DC390: Check_Condition (Cmd %02x, Id %02x, LUN %02x)\n",\ + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN);) + if( (pSRB->SGIndex < pSRB->SGcount) && (pSRB->SGcount) && (pSRB->SGToBeXferLen) ) + { + bval = pSRB->SGcount; + swlval = 0; + ptr2 = pSRB->pSegmentList; + for( i=pSRB->SGIndex; i < bval; i++) + { + swlval += ptr2->length; + ptr2++; + } + REMOVABLEDEBUG(printk(KERN_INFO "XferredLen=%08x,NotXferLen=%08x\n",\ + (UINT) pSRB->TotalXferredLen, (UINT) swlval);) + } + dc390_RequestSense( pACB, pDCB, pSRB ); + return; + } + else if( status_byte(status) == QUEUE_FULL ) + { + bval = (UCHAR) pDCB->GoingSRBCnt; + bval--; + pDCB->MaxCommand = bval; + dc390_freetag (pDCB, pSRB); + dc390_Going_to_Waiting ( pDCB, pSRB ); + dc390_waiting_timer (pACB, HZ/5); + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + return; + } + else if(status == SCSI_STAT_SEL_TIMEOUT) + { + pSRB->AdaptStatus = H_SEL_TIMEOUT; + pSRB->TargetStatus = 0; + pcmd->result = MK_RES(0,DID_NO_CONNECT,0,0); + /* Devices are removed below ... */ + } + else if (status_byte(status) == BUSY && + (pcmd->cmnd[0] == TEST_UNIT_READY || pcmd->cmnd[0] == INQUIRY) && + pACB->scan_devices) + { + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = status; + pcmd->result = MK_RES(0,0,pSRB->EndMessage,/*status*/0); + } + else + { /* Another error */ + pSRB->AdaptStatus = 0; + if( pSRB->RetryCnt ) + { /* Retry */ + //printk ("DC390: retry\n"); + pSRB->RetryCnt--; + pSRB->TargetStatus = 0; + pSRB->SGIndex = 0; + pSRB->TotalXferredLen = 0; + pSRB->SGToBeXferLen = 0; + if( pcmd->use_sg ) + pSRB->pSegmentList = (PSGL) pcmd->request_buffer; + else if( pcmd->request_buffer ) + { + pSRB->pSegmentList = (PSGL) &pSRB->Segmentx; + pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; + pSRB->Segmentx.length = pcmd->request_bufflen; + } + if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) { + dc390_Going_to_Waiting ( pDCB, pSRB ); + dc390_waiting_timer (pACB, HZ/5); + } + return; + } + else + { /* Report error */ + //pcmd->result = MK_RES(0, DID_ERROR, pSRB->EndMessage, status); + SET_RES_DID(pcmd->result,DID_ERROR); + SET_RES_MSG(pcmd->result,pSRB->EndMessage); + SET_RES_TARGET(pcmd->result,status); + } + } + } + else + { /* Target status == 0 */ + status = pSRB->AdaptStatus; + if(status & H_OVER_UNDER_RUN) + { + pSRB->TargetStatus = 0; + SET_RES_DID(pcmd->result,DID_OK); + SET_RES_MSG(pcmd->result,pSRB->EndMessage); + } + else if( pSRB->SRBStatus & PARITY_ERROR) + { + //pcmd->result = MK_RES(0,DID_PARITY,pSRB->EndMessage,0); + SET_RES_DID(pcmd->result,DID_PARITY); + SET_RES_MSG(pcmd->result,pSRB->EndMessage); + } + else /* No error */ + { + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + SET_RES_DID(pcmd->result,DID_OK); + } + } + if ((pcmd->result & RES_DID) == 0 && + pcmd->cmnd[0] == INQUIRY && + pcmd->cmnd[2] == 0 && + pcmd->request_bufflen >= 8 && + ptr && + (ptr->Vers & 0x07) >= 2) + pDCB->Inquiry7 = ptr->Flags; + +ckc_e: + if( pACB->scan_devices ) + { + if( pcmd->cmnd[0] == TEST_UNIT_READY || + pcmd->cmnd[0] == INQUIRY) + { +#ifdef DC390_DEBUG0 + printk (KERN_INFO "DC390: %s: result: %08x", + (pcmd->cmnd[0] == INQUIRY? "INQUIRY": "TEST_UNIT_READY"), + pcmd->result); + if (pcmd->result & (DRIVER_SENSE << 24)) printk (" (sense: %02x %02x %02x %02x)\n", + pcmd->sense_buffer[0], pcmd->sense_buffer[1], + pcmd->sense_buffer[2], pcmd->sense_buffer[3]); + else printk ("\n"); +#endif + if( (host_byte(pcmd->result) != DID_OK && !(status_byte(pcmd->result) & CHECK_CONDITION) && !(status_byte(pcmd->result) & BUSY)) || + ((driver_byte(pcmd->result) & DRIVER_SENSE) && (pcmd->sense_buffer[0] & 0x70) == 0x70 && + (pcmd->sense_buffer[2] & 0xf) == ILLEGAL_REQUEST) || host_byte(pcmd->result) & DID_ERROR ) + { + /* device not present: remove */ + //dc390_Going_remove (pDCB, pSRB); + dc390_remove_dev (pACB, pDCB); DCB_removed = 1; + + if( (pcmd->target == pACB->pScsiHost->max_id - 1) && + ((pcmd->lun == 0) || (pcmd->lun == pACB->pScsiHost->max_lun - 1)) ) + pACB->scan_devices = 0; + } + else + { + /* device present: add */ + if( (pcmd->target == pACB->pScsiHost->max_id - 1) && + (pcmd->lun == pACB->pScsiHost->max_lun - 1) ) + pACB->scan_devices = END_SCAN ; + /* pACB->DeviceCnt++; */ /* Dev is added on INQUIRY */ + } + } + } + + //if( pSRB->pcmd->cmnd[0] == INQUIRY && + // (host_byte(pcmd->result) == DID_OK || status_byte(pcmd->result) & CHECK_CONDITION) ) + if( pcmd->cmnd[0] == INQUIRY && + (pcmd->result == (DID_OK << 16) || status_byte(pcmd->result) & CHECK_CONDITION) ) + { + if ((ptr->DevType & SCSI_DEVTYPE) == TYPE_NODEV && !DCB_removed) + { + //printk ("DC390: Type = nodev! (%02i-%i)\n", pcmd->target, pcmd->lun); + /* device not present: remove */ + //dc390_Going_remove (pDCB, pSRB); + dc390_remove_dev (pACB, pDCB); DCB_removed = 1; + } + else + { + /* device found: add */ + dc390_add_dev (pACB, pDCB, ptr); + if (pACB->scan_devices) pACB->DeviceCnt++; + } + if( (pcmd->target == pACB->pScsiHost->max_id - 1) && + (pcmd->lun == pACB->pScsiHost->max_lun - 1) ) + pACB->scan_devices = 0; + }; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,30) + pcmd->resid = pcmd->request_bufflen - pSRB->TotalXferredLen; +#endif + + if (!DCB_removed) dc390_Going_remove (pDCB, pSRB); + /* Add to free list */ + dc390_Free_insert (pACB, pSRB); + + DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done pid %li\n", pcmd->pid);) + DC390_UNLOCK_ACB_NI; + pcmd->scsi_done (pcmd); + DC390_LOCK_ACB_NI; + + dc390_Query_to_Waiting (pACB); + dc390_Waiting_process (pACB); + return; +} + + +/* Remove all SRBs from Going list and inform midlevel */ +void +dc390_DoingSRB_Done( PACB pACB, PSCSICMD cmd ) +{ + PDCB pDCB, pdcb; + PSRB psrb, psrb2; + UCHAR i; + PSCSICMD pcmd; + + pDCB = pACB->pLinkDCB; + pdcb = pDCB; + if (! pdcb) return; + do + { + psrb = pdcb->pGoingSRB; + for( i=0; iGoingSRBCnt; i++) + { + psrb2 = psrb->pNextSRB; + pcmd = psrb->pcmd; + dc390_Free_insert (pACB, psrb); +#ifndef USE_NEW_EH + /* New EH will crash on being given timed out cmnds */ + if (pcmd == cmd) + pcmd->result = MK_RES(0,DID_ABORT,0,0); + else + pcmd->result = MK_RES(0,DID_RESET,0,0); + +/* ReleaseSRB( pDCB, pSRB ); */ + + DEBUG0(printk (KERN_DEBUG "DC390: DoingSRB_Done: done pid %li\n", pcmd->pid);) + DC390_UNLOCK_ACB_NI; + pcmd->scsi_done( pcmd ); + DC390_LOCK_ACB_NI; +#endif + psrb = psrb2; + } + pdcb->GoingSRBCnt = 0;; + pdcb->pGoingSRB = NULL; + pdcb->TagMask = 0; + pdcb = pdcb->pNextDCB; + } while( pdcb != pDCB ); + dc390_Query_to_Waiting (pACB); +} + + +static void +dc390_ResetSCSIBus( PACB pACB ) +{ + //DC390_write8 (ScsiCmd, RST_DEVICE_CMD); + //udelay (250); + //DC390_write8 (ScsiCmd, NOP_CMD); + + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); + DC390_write8 (ScsiCmd, RST_SCSI_BUS_CMD); + pACB->Connected = 0; + + return; +} + +static void +dc390_ScsiRstDetect( PACB pACB ) +{ + printk ("DC390: Rst_Detect: laststat = %08x\n", dc390_laststatus); + //DEBUG0(printk(KERN_INFO "RST_DETECT,");) + + if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer); + DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); + /* Unlock before ? */ + /* delay half a second */ + udelay (1000); + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + pACB->pScsiHost->last_reset = jiffies + 5*HZ/2 + + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]; + pACB->Connected = 0; + + if( pACB->ACBFlag & RESET_DEV ) + pACB->ACBFlag |= RESET_DONE; + else + { /* Reset was issued by sb else */ + pACB->ACBFlag |= RESET_DETECT; + + dc390_ResetDevParam( pACB ); + dc390_DoingSRB_Done( pACB, 0 ); + //dc390_RecoverSRB( pACB ); + pACB->pActiveDCB = NULL; + pACB->ACBFlag = 0; + dc390_Waiting_process( pACB ); + } + return; +} + + +static void __inline__ +dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ) +{ + PSCSICMD pcmd; + + REMOVABLEDEBUG(printk (KERN_INFO "DC390: RequestSense (Cmd %02x, Id %02x, LUN %02x)\n",\ + pSRB->pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN);) + + pSRB->SRBFlag |= AUTO_REQSENSE; + //pSRB->Segment0[0] = (UINT) pSRB->CmdBlock[0]; + //pSRB->Segment0[1] = (UINT) pSRB->CmdBlock[4]; + //pSRB->Segment1[0] = ((UINT)(pSRB->pcmd->cmd_len) << 8) + pSRB->SGcount; + //pSRB->Segment1[1] = pSRB->TotalXferredLen; + pSRB->SavedSGCount = pSRB->SGcount; + pSRB->SavedTotXLen = pSRB->TotalXferredLen; + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; /* CHECK_CONDITION<<1; */ + + pcmd = pSRB->pcmd; + + pSRB->Segmentx.address = (PUCHAR) &(pcmd->sense_buffer); + pSRB->Segmentx.length = sizeof(pcmd->sense_buffer); + pSRB->pSegmentList = &pSRB->Segmentx; + pSRB->SGcount = 1; + pSRB->SGIndex = 0; + + //pSRB->CmdBlock[0] = REQUEST_SENSE; + //pSRB->CmdBlock[1] = pDCB->TargetLUN << 5; + //(USHORT) pSRB->CmdBlock[2] = 0; + //(USHORT) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer); + //pSRB->ScsiCmdLen = 6; + + pSRB->TotalXferredLen = 0; + pSRB->SGToBeXferLen = 0; + if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) { + dc390_Going_to_Waiting ( pDCB, pSRB ); + dc390_waiting_timer (pACB, HZ/5); + } +} + + + +static void __inline__ +dc390_InvalidCmd( PACB pACB ) +{ + if( pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_+SRB_MSGOUT) ) + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); +} + diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index 56a2cacfc..5d2c5c467 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -5,11 +5,11 @@ * Bus Master Host Adapter * * (C)Copyright 1995-1996 Tekram Technology Co., Ltd. * ***********************************************************************/ -/* (C) Copyright: put under GNU GPL in 10/96 * +/* (C) Copyright: put under GNU GPL in 10/96 (see README.tmscsim) * *************************************************************************/ -/* $Id: tmscsim.c,v 2.16 1998/12/25 17:54:44 garloff Exp $ */ +/* $Id: tmscsim.c,v 2.60.2.30 2000/12/20 01:07:12 garloff Exp $ */ /* Enhancements and bugfixes by * - * Kurt Garloff * + * Kurt Garloff * ***********************************************************************/ /* HISTORY: * * * @@ -95,8 +95,75 @@ * 2.0c 98/11/19 KG Cleaned up detect/init for SMP boxes, * * Write Erase DMA (1.20t) caused problems * * 2.0d 98/12/25 KG Christmas release ;-) Message handling * - * competely reworked. Handle target ini- * + * completely reworked. Handle target ini- * * tiated SDTR correctly. * + * 2.0d1 99/01/25 KG Try to handle RESTORE_PTR * + * 2.0d2 99/02/08 KG Check for failure of kmalloc, correct * + * inclusion of scsicam.h, DelayReset * + * 2.0d3 99/05/31 KG DRIVER_OK -> DID_OK, DID_NO_CONNECT, * + * detect Target mode and warn. * + * pcmd->result handling cleaned up. * + * 2.0d4 99/06/01 KG Cleaned selection process. Found bug * + * which prevented more than 16 tags. Now: * + * 24. SDTR cleanup. Cleaner multi-LUN * + * handling. Don't modify ControlRegs/FIFO * + * when connected. * + * 2.0d5 99/06/01 KG Clear DevID, Fix INQUIRY after cfg chg. * + * 2.0d6 99/06/02 KG Added ADD special command to allow cfg. * + * before detection. Reset SYNC_NEGO_DONE * + * after a bus reset. * + * 2.0d7 99/06/03 KG Fixed bugs wrt add,remove commands * + * 2.0d8 99/06/04 KG Removed copying of cmnd into CmdBlock. * + * Fixed Oops in _release(). * + * 2.0d9 99/06/06 KG Also tag queue INQUIRY, T_U_R, ... * + * Allow arb. no. of Tagged Cmnds. Max 32 * + * 2.0d1099/06/20 KG TagMaxNo changes now honoured! Queueing * + * clearified (renamed ..) TagMask handling* + * cleaned. * + * 2.0d1199/06/28 KG cmd->result now identical to 2.0d2 * + * 2.0d1299/07/04 KG Changed order of processing in IRQ * + * 2.0d1399/07/05 KG Don't update DCB fields if removed * + * 2.0d1499/07/05 KG remove_dev: Move kfree() to the end * + * 2.0d1599/07/12 KG use_new_eh_code: 0, ULONG -> UINT where * + * appropriate * + * 2.0d1699/07/13 KG Reenable StartSCSI interrupt, Retry msg * + * 2.0d1799/07/15 KG Remove debug msg. Disable recfg. when * + * there are queued cmnds * + * 2.0d1899/07/18 KG Selection timeout: Don't requeue * + * 2.0d1999/07/18 KG Abort: Only call scsi_done if dequeued * + * 2.0d2099/07/19 KG Rst_Detect: DoingSRB_Done * + * 2.0d2199/08/15 KG dev_id for request/free_irq, cmnd[0] for* + * RETRY, SRBdone does DID_ABORT for the * + * cmd passed by DC390_reset() * + * 2.0d2299/08/25 KG dev_id fixed. can_queue: 42 * + * 2.0d2399/08/25 KG Removed some debugging code. dev_id * + * now is set to pACB. Use u8,u16,u32. * + * 2.0d2499/11/14 KG Unreg. I/O if failed IRQ alloc. Call * + * done () w/ DID_BAD_TARGET in case of * + * missing DCB. We are old EH!! * + * 2.0d2500/01/15 KG 2.3.3x compat from Andreas Schultz * + * set unique_id. Disable RETRY message. * + * 2.0d2600/01/29 KG Go to new EH. * + * 2.0d2700/01/31 KG ... but maintain 2.0 compat. * + * and fix DCB freeing * + * 2.0d2800/02/14 KG Queue statistics fixed, dump special cmd* + * Waiting_Timer for failed StartSCSI * + * New EH: Don't return cmnds to ML on RST * + * Use old EH (don't have new EH fns yet) * + * Reset: Unlock, but refuse to queue * + * 2.3 __setup function * + * 2.0e 00/05/22 KG Return residual for 2.3 * + * 2.0e1 00/05/25 KG Compile fixes for 2.3.99 * + * 2.0e2 00/05/27 KG Jeff Garzik's pci_enable_device() * + * 2.0e3 00/09/29 KG Some 2.4 changes. Don't try Sync Nego * + * before INQUIRY has reported ability. * + * Recognise INQUIRY as scanning command. * + * 2.0e4 00/10/13 KG Allow compilation into 2.4 kernel * + * 2.0e5 00/11/17 KG Store Inq.flags in DCB * + * 2.0e6 00/11/22 KG 2.4 init function (Thx to O.Schumann) * + * 2.4 PCI device table (Thx to A.Richter) * + * 2.0e7 00/11/28 KG Allow overriding of BIOS settings * + * 2.0f 00/12/20 KG Handle failed INQUIRYs during scan * ***********************************************************************/ /* Uncomment SA_INTERRUPT, if the driver refuses to share its IRQ with other devices */ @@ -108,6 +175,7 @@ //#define DC390_DCBDEBUG //#define DC390_PARSEDEBUG //#define DC390_REMOVABLEDEBUG +//#define DC390_LOCKDEBUG /* Debug definitions */ #ifdef DC390_DEBUG0 @@ -159,6 +227,7 @@ #include #include #include +#include #include "scsi.h" #include "hosts.h" @@ -175,8 +244,7 @@ /* Note: Starting from 2.1.9x, the mid-level scsi code issues a * spinlock_irqsave (&io_request_lock) before calling the driver's - * routines, so we don't need to lock. - * TODO: Verify, if we are locked in every case! + * routines, so we don't need to lock, except in the IRQ handler. * The policy 3, let the midlevel scsi code do the io_request_locks * and us locking on a driver specific lock, shouldn't hurt anybody; it * just causes a minor performance degradation for setting the locks. @@ -191,24 +259,39 @@ //#define DEBUG_SPINLOCKS 2 /* Set to 0, 1 or 2 in include/linux/spinlock.h */ -#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) - -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30) # include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30) # include +#else +# include +#endif #endif -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93) # define USE_SPINLOCKS 1 # define NEW_PCI 1 #else # undef NEW_PCI -# if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30) # define USE_SPINLOCKS 2 # endif #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,99) +static struct pci_device_id tmscsim_pci_tbl[] __initdata = { + { + vendor: PCI_VENDOR_ID_AMD, + device: PCI_DEVICE_ID_AMD53C974, + subvendor: PCI_ANY_ID, + subdevice: PCI_ANY_ID, + }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, tmscsim_pci_tbl); +#endif + #ifdef USE_SPINLOCKS # if USE_SPINLOCKS == 3 /* both */ @@ -242,7 +325,7 @@ # if USE_SPINLOCKS == 2 /* adapter specific locks */ -# if defined (CONFIG_SMP) || DEBUG_SPINLOCKS > 0 +# if defined (__SMP__) || DEBUG_SPINLOCKS > 0 # define DC390_LOCKA_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; }; # else # define DC390_LOCKA_INIT @@ -320,7 +403,11 @@ # define PCI_PRESENT pci_present () # define PCI_SET_MASTER pci_set_master (pdev) # define PCI_FIND_DEVICE(vend, id) (pdev = pci_find_device (vend, id, pdev)) -# define PCI_GET_IO_AND_IRQ io_port = pci_resource_start(pdev, 0); irq = pdev->irq; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,10) +# define PCI_GET_IO_AND_IRQ io_port = pci_resource_start (pdev, 0); irq = pdev->irq +#else +# define PCI_GET_IO_AND_IRQ io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; irq = pdev->irq +#endif #else # include # define PDEV pbus, pdevfn @@ -369,7 +456,7 @@ static void dc390_SetXferRate( PACB pACB, PDCB pDCB ); void dc390_Disconnect( PACB pACB ); void dc390_Reselect( PACB pACB ); void dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ); -void dc390_DoingSRB_Done( PACB pACB ); +void dc390_DoingSRB_Done( PACB pACB, PSCSICMD cmd ); static void dc390_ScsiRstDetect( PACB pACB ); static void dc390_ResetSCSIBus( PACB pACB ); static void __inline__ dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ); @@ -379,7 +466,7 @@ static void dc390_remove_dev (PACB pACB, PDCB pDCB); void do_DC390_Interrupt( int, void *, struct pt_regs *); int dc390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, UCHAR index ); -void dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd ); +void dc390_initDCB( PACB pACB, PDCB *ppDCB, UCHAR id, UCHAR lun); void dc390_updateDCB (PACB pACB, PDCB pDCB); #ifdef MODULE @@ -393,31 +480,19 @@ void dc390_updateDCB (PACB pACB, PDCB pDCB); //static PSH dc390_pSH_current = NULL; static PACB dc390_pACB_start= NULL; static PACB dc390_pACB_current = NULL; -static UCHAR dc390_adapterCnt = 0; -static UCHAR dc390_CurrSyncOffset = 0; static ULONG dc390_lastabortedpid = 0; -static ULONG dc390_laststatus = 0; +static UINT dc390_laststatus = 0; +static UCHAR dc390_adapterCnt = 0; -#ifndef CONFIG_SCSI_DC390T_NOGENSUPP /* Startup values, to be overriden on the commandline */ -int tmscsim[] = {7, 1 /* 8MHz */, - PARITY_CHK_ | SEND_START_ | EN_DISCONNECT_ - | SYNC_NEGO_ | TAG_QUEUEING_, - MORE2_DRV | GREATER_1G | RST_SCSI_BUS | ACTIVE_NEGATION - /* | NO_SEEK */ -# ifdef CONFIG_SCSI_MULTI_LUN - | LUN_CHECK -# endif - , 3 /* 16 Tags per LUN */}; +int tmscsim[] = {-2, -2, -2, -2, -2, -2}; -# if defined(MODULE) && LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) -MODULE_PARM(tmscsim, "1-5i"); -MODULE_PARM_DESC(tmscsim, "Host SCSI ID, Speed (0=10MHz), Device Flags, Adapter Flags, Max Tags (log2(tags)-1)"); +# if defined(MODULE) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30) +MODULE_PARM(tmscsim, "1-6i"); +MODULE_PARM_DESC(tmscsim, "Host SCSI ID, Speed (0=10MHz), Device Flags, Adapter Flags, Max Tags (log2(tags)-1), DelayReset (s)"); # endif -#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */ - -#if defined(MODULE) && LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) +#if defined(MODULE) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30) MODULE_AUTHOR("C.L. Huang / Kurt Garloff"); MODULE_DESCRIPTION("SCSI host adapter driver for Tekram DC390 and other AMD53C974A based PCI SCSI adapters"); MODULE_SUPPORTED_DEVICE("sd,sr,sg,st"); @@ -482,6 +557,14 @@ UCHAR dc390_baddevname1[2][28] ={ static char* dc390_adapname = "DC390"; UCHAR dc390_eepromBuf[MAX_ADAPTER_NUM][EE_LEN]; UCHAR dc390_clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20}; +UCHAR dc390_clock_speed[] = {100,80,67,57,50, 40, 31, 20}; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,30) +struct proc_dir_entry DC390_proc_scsi_tmscsim ={ + PROC_SCSI_DC390T, 7 ,"tmscsim", + S_IFDIR | S_IRUGO | S_IXUGO, 2 + }; +#endif /*********************************************************************** * Functions for access to DC390 EEPROM @@ -505,59 +588,107 @@ static void __init dc390_EnDisableCE( UCHAR mode, PDEVDECL, PUCHAR regval ) udelay(160); } -#ifndef CONFIG_SCSI_DC390T_NOGENSUPP -static void __init dc390_EEpromDefaults (UCHAR index) + +/* Override EEprom values with explicitly set values */ +static void __init dc390_EEprom_Override (UCHAR index) { PUCHAR ptr; UCHAR id; ptr = (PUCHAR) dc390_eepromBuf[index]; /* Adapter Settings */ - ptr[EE_ADAPT_SCSI_ID] = (UCHAR)tmscsim[0]; /* Adapter ID */ - ptr[EE_MODE2] = (UCHAR)tmscsim[3]; - ptr[EE_DELAY] = 0; /* ?? */ - ptr[EE_TAG_CMD_NUM] = (UCHAR)tmscsim[4]; /* Tagged Comds */ + if (tmscsim[0] != -2) + ptr[EE_ADAPT_SCSI_ID] = (UCHAR)tmscsim[0]; /* Adapter ID */ + if (tmscsim[3] != -2) + ptr[EE_MODE2] = (UCHAR)tmscsim[3]; + if (tmscsim[5] != -2) + ptr[EE_DELAY] = tmscsim[5]; /* Reset delay */ + if (tmscsim[4] != -2) + ptr[EE_TAG_CMD_NUM] = (UCHAR)tmscsim[4]; /* Tagged Cmds */ /* Device Settings */ for (id = 0; id < MAX_SCSI_ID; id++) { - ptr[id<<2] = (UCHAR)tmscsim[2]; /* EE_MODE1 */ - ptr[(id<<2) + 1] = (UCHAR)tmscsim[1]; /* EE_Speed */ + if (tmscsim[2] != -2) + ptr[id<<2] = (UCHAR)tmscsim[2]; /* EE_MODE1 */ + if (tmscsim[1] != -2) + ptr[(id<<2) + 1] = (UCHAR)tmscsim[1]; /* EE_Speed */ }; - dc390_adapname = "AM53C974"; } -static void __init dc390_checkparams (void) +/* Handle "-1" case */ +static void __init dc390_check_for_safe_settings (void) { - PARSEDEBUG(printk(KERN_INFO "DC390: setup %08x %08x %08x %08x %08x\n", tmscsim[0],\ - tmscsim[1], tmscsim[2], tmscsim[3], tmscsim[4]);) - if (tmscsim[0] < 0 || tmscsim[0] > 7) /* modules-2.0.0 passes -1 as string */ + if (tmscsim[0] == -1 || tmscsim[0] > 15) /* modules-2.0.0 passes -1 as string */ { - tmscsim[0] = 7; tmscsim[1] = 4; - tmscsim[2] = 9; tmscsim[3] = 15; - tmscsim[4] = 2; + tmscsim[0] = 7; tmscsim[1] = 4; + tmscsim[2] = 0x09; tmscsim[3] = 0x0f; + tmscsim[4] = 2; tmscsim[5] = 10; printk (KERN_INFO "DC390: Using safe settings.\n"); } - else +} + + +#ifndef CONFIG_SCSI_DC390T_NOGENSUPP +int __initdata tmscsim_def[] = {7, 0 /* 10MHz */, + PARITY_CHK_ | SEND_START_ | EN_DISCONNECT_ + | SYNC_NEGO_ | TAG_QUEUEING_, + MORE2_DRV | GREATER_1G | RST_SCSI_BUS | ACTIVE_NEGATION + /* | NO_SEEK */ +# ifdef CONFIG_SCSI_MULTI_LUN + | LUN_CHECK +# endif + , 3 /* 16 Tags per LUN */, 1 /* s delay after Reset */ }; + +/* Copy defaults over set values where missing */ +static void __init dc390_fill_with_defaults (void) +{ + int i; + PARSEDEBUG(printk(KERN_INFO "DC390: setup %08x %08x %08x %08x %08x %08x\n", tmscsim[0],\ + tmscsim[1], tmscsim[2], tmscsim[3], tmscsim[4], tmscsim[5]);) + for (i = 0; i < 6; i++) { - /* if (tmscsim[0] < 0 || tmscsim[0] > 7) tmscsim[0] = 7; */ - if (tmscsim[1] < 0 || tmscsim[1] > 7) tmscsim[1] = 4; - if (tmscsim[4] < 0 || tmscsim[4] > 5) tmscsim[4] = 4; - }; + if (tmscsim[i] < 0 || tmscsim[i] > 255) + tmscsim[i] = tmscsim_def[i]; + } + /* Sanity checks */ + if (tmscsim[0] > 7) tmscsim[0] = 7; + if (tmscsim[1] > 7) tmscsim[1] = 4; + if (tmscsim[4] > 5) tmscsim[4] = 4; + if (tmscsim[5] > 180) tmscsim[5] = 180; }; +#endif + /* Override defaults on cmdline: * tmscsim: AdaptID, MaxSpeed (Index), DevMode (Bitmapped), AdaptMode (Bitmapped) */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13) +void __init dc390_setup (char *str) +{ + int ints[8]; + int i, im; + (void)get_options (str, ARRAY_SIZE(ints), ints); +#else void __init dc390_setup (char *str, int *ints) { - int i; - for (i = 0; i < ints[0]; i++) - tmscsim[i] = ints[i+1]; - if (ints[0] > 5) + int i, im; +#endif + im = ints[0]; + if (im > 6) + { printk (KERN_NOTICE "DC390: ignore extra params!\n"); + im = 6; + }; + for (i = 0; i < im; i++) + tmscsim[i] = ints[i+1]; /* dc390_checkparams (); */ }; -#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13) +#ifndef MODULE +__setup("tmscsim=", dc390_setup); +#endif +#endif static void __init dc390_EEpromOutDI( PDEVDECL, PUCHAR regval, UCHAR Carry ) @@ -646,6 +777,12 @@ static void __init dc390_ReadEEprom( PDEVDECL, PUSHORT ptr) } +static void __init dc390_interpret_delay (UCHAR index) +{ + char interpd [] = {1,3,5,10,16,30,60,120}; + dc390_eepromBuf[index][EE_DELAY] = interpd [dc390_eepromBuf[index][EE_DELAY]]; +}; + static UCHAR __init dc390_CheckEEpromCheckSum( PDEVDECL, UCHAR index ) { UCHAR i; @@ -656,6 +793,8 @@ static UCHAR __init dc390_CheckEEpromCheckSum( PDEVDECL, UCHAR index ) memcpy (dc390_eepromBuf[index], EEbuf, EE_ADAPT_SCSI_ID); memcpy (&dc390_eepromBuf[index][EE_ADAPT_SCSI_ID], &EEbuf[REAL_EE_ADAPT_SCSI_ID], EE_LEN - EE_ADAPT_SCSI_ID); + dc390_interpret_delay (index); + wval = 0; for(i=0; i<0x40; i++, ptr++) wval += *ptr; @@ -668,65 +807,94 @@ static UCHAR __init dc390_CheckEEpromCheckSum( PDEVDECL, UCHAR index ) * (DCBs, SRBs, Queueing) * **********************************************************************/ -static PDCB __inline__ dc390_findDCB ( PACB pACB, Scsi_Cmnd *cmd) +static PDCB __inline__ dc390_findDCB ( PACB pACB, UCHAR id, UCHAR lun) { PDCB pDCB = pACB->pLinkDCB; if (!pDCB) return 0; - while (pDCB->UnitSCSIID != cmd->target || pDCB->UnitSCSILUN != cmd->lun) + while (pDCB->TargetID != id || pDCB->TargetLUN != lun) { pDCB = pDCB->pNextDCB; if (pDCB == pACB->pLinkDCB) { - printk (KERN_WARNING "DC390: DCB not found (DCB=%08x, DCBmap[%2x]=%2x)\n", - (int)pDCB, cmd->target, pACB->DCBmap[cmd->target]); + DCBDEBUG(printk (KERN_WARNING "DC390: DCB not found (DCB=%p, DCBmap[%2x]=%2x)\n", + pDCB, id, pACB->DCBmap[id]);) return 0; } }; - DCBDEBUG1( printk (KERN_DEBUG "DCB %08x (%02x,%02x) found.\n", \ - (int)pDCB, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);) + DCBDEBUG1( printk (KERN_DEBUG "DCB %p (%02x,%02x) found.\n", \ + pDCB, pDCB->TargetID, pDCB->TargetLUN);) return pDCB; }; -static void dc390_QLinkcmd( PSCSICMD cmd, PDCB pDCB ) -{ - PSCSICMD pcmd; +/* Queueing philosphy: + * There are a couple of lists: + * - Query: Contains the Scsi Commands not yet turned into SRBs (per ACB) + * (Note: For new EH, it is unecessary!) + * - Waiting: Contains a list of SRBs not yet sent (per DCB) + * - Free: List of free SRB slots + * + * If there are no waiting commands for the DCB, the new one is sent to the bus + * otherwise the oldest one is taken from the Waiting list and the new one is + * queued to the Waiting List + * + * Lists are managed using two pointers and eventually a counter + */ + - if( !pDCB->QIORBCnt ) +#if 0 +/* Look for a SCSI cmd in a SRB queue */ +static PSRB dc390_find_cmd_in_SRBq (PSCSICMD cmd, PSRB queue) +{ + PSRB q = queue; + while (q) { - pDCB->pQIORBhead = cmd; - pDCB->pQIORBtail = cmd; - pDCB->QIORBCnt++; - cmd->next = NULL; + if (q->pcmd == cmd) return q; + q = q->pNextSRB; + if (q == queue) return 0; } + return q; +}; +#endif + + +/* Append to Query List */ +static void dc390_Query_append( PSCSICMD cmd, PACB pACB ) +{ + DEBUG0(printk ("DC390: Append cmd %li to Query\n", cmd->pid);) + if( !pACB->QueryCnt ) + pACB->pQueryHead = cmd; else - { - pcmd = pDCB->pQIORBtail; - pcmd->next = cmd; - pDCB->pQIORBtail = cmd; - pDCB->QIORBCnt++; - cmd->next = NULL; - } + pACB->pQueryTail->next = cmd; + pACB->pQueryTail = cmd; + pACB->QueryCnt++; + pACB->CmdOutOfSRB++; + cmd->next = NULL; } -static __inline__ PSCSICMD dc390_Getcmd( PDCB pDCB ) +/* Return next cmd from Query list */ +static PSCSICMD dc390_Query_get ( PACB pACB ) { PSCSICMD pcmd; - pcmd = pDCB->pQIORBhead; - pDCB->pQIORBhead = pcmd->next; + pcmd = pACB->pQueryHead; + if (!pcmd) return pcmd; + DEBUG0(printk ("DC390: Get cmd %li from Query\n", pcmd->pid);) + pACB->pQueryHead = pcmd->next; pcmd->next = NULL; - pDCB->QIORBCnt--; - + if (!pACB->pQueryHead) pACB->pQueryTail = NULL; + pACB->QueryCnt--; return( pcmd ); } -static __inline__ PSRB dc390_GetSRB( PACB pACB ) +/* Return next free SRB */ +static __inline__ PSRB dc390_Free_get ( PACB pACB ) { PSRB pSRB; pSRB = pACB->pFreeSRB; + DEBUG0(printk ("DC390: Get Free SRB %p\n", pSRB);) if( pSRB ) { pACB->pFreeSRB = pSRB->pNextSRB; @@ -736,130 +904,174 @@ static __inline__ PSRB dc390_GetSRB( PACB pACB ) return( pSRB ); } - -static __inline__ void dc390_RewaitSRB0( PDCB pDCB, PSRB pSRB ) +/* Insert SRB oin top of free list */ +static __inline__ void dc390_Free_insert (PACB pACB, PSRB pSRB) { - PSRB psrb1; + DEBUG0(printk ("DC390: Free SRB %p\n", pSRB);) + pSRB->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = pSRB; +} - if( (psrb1 = pDCB->pWaitingSRB) ) - { - pSRB->pNextSRB = psrb1; - } - else - { - pSRB->pNextSRB = NULL; + +/* Inserts a SRB to the top of the Waiting list */ +static __inline__ void dc390_Waiting_insert ( PDCB pDCB, PSRB pSRB ) +{ + DEBUG0(printk ("DC390: Insert pSRB %p cmd %li to Waiting\n", pSRB, pSRB->pcmd->pid);) + pSRB->pNextSRB = pDCB->pWaitingSRB; + if (!pDCB->pWaitingSRB) pDCB->pWaitLast = pSRB; - } pDCB->pWaitingSRB = pSRB; + pDCB->WaitSRBCnt++; } -static void dc390_RewaitSRB( PDCB pDCB, PSRB pSRB ) +/* Queue SRB to waiting list */ +static __inline__ void dc390_Waiting_append ( PDCB pDCB, PSRB pSRB) { - PSRB psrb1; - UCHAR bval; - - pDCB->GoingSRBCnt--; pDCB->pDCBACB->SelLost++; - DEBUG0(printk(KERN_INFO "DC390: RewaitSRB (%p, %p) pid = %li\n", pDCB, pSRB, pSRB->pcmd->pid);) - psrb1 = pDCB->pGoingSRB; - if( pSRB == psrb1 ) - { - pDCB->pGoingSRB = psrb1->pNextSRB; - } + DEBUG0(printk ("DC390: Append pSRB %p cmd %li to Waiting\n", pSRB, pSRB->pcmd->pid);) + if( pDCB->pWaitingSRB ) + pDCB->pWaitLast->pNextSRB = pSRB; else - { - while( pSRB != psrb1->pNextSRB ) - psrb1 = psrb1->pNextSRB; - psrb1->pNextSRB = pSRB->pNextSRB; - if( pSRB == pDCB->pGoingLast ) - pDCB->pGoingLast = psrb1; - } - if( (psrb1 = pDCB->pWaitingSRB) ) - { - pSRB->pNextSRB = psrb1; pDCB->pWaitingSRB = pSRB; - } + + pDCB->pWaitLast = pSRB; + pSRB->pNextSRB = NULL; + pDCB->WaitSRBCnt++; + pDCB->pDCBACB->CmdInQ++; +} + +static __inline__ void dc390_Going_append (PDCB pDCB, PSRB pSRB) +{ + pDCB->GoingSRBCnt++; + DEBUG0(printk("DC390: Append SRB %p to Going\n", pSRB);) + /* Append to the list of Going commands */ + if( pDCB->pGoingSRB ) + pDCB->pGoingLast->pNextSRB = pSRB; else - { - pSRB->pNextSRB = NULL; - pDCB->pWaitingSRB = pSRB; - pDCB->pWaitLast = pSRB; - } + pDCB->pGoingSRB = pSRB; + + pDCB->pGoingLast = pSRB; + /* No next one in sent list */ + pSRB->pNextSRB = NULL; +}; + +static __inline__ void dc390_Going_remove (PDCB pDCB, PSRB pSRB) +{ + DEBUG0(printk("DC390: Remove SRB %p from Going\n", pSRB);) + if (pSRB == pDCB->pGoingSRB) + pDCB->pGoingSRB = pSRB->pNextSRB; + else + { + PSRB psrb = pDCB->pGoingSRB; + while (psrb && psrb->pNextSRB != pSRB) + psrb = psrb->pNextSRB; + if (!psrb) + { printk (KERN_ERR "DC390: Remove non-ex. SRB %p from Going!\n", pSRB); return; } + psrb->pNextSRB = pSRB->pNextSRB; + if (pSRB == pDCB->pGoingLast) + pDCB->pGoingLast = psrb; + } + pDCB->GoingSRBCnt--; +}; + +/* Moves SRB from Going list to the top of Waiting list */ +static void dc390_Going_to_Waiting ( PDCB pDCB, PSRB pSRB ) +{ + DEBUG0(printk(KERN_INFO "DC390: Going_to_Waiting (SRB %p) pid = %li\n", pSRB, pSRB->pcmd->pid);) + /* Remove SRB from Going */ + dc390_Going_remove (pDCB, pSRB); + /* Insert on top of Waiting */ + dc390_Waiting_insert (pDCB, pSRB); + /* Tag Mask must be freed elsewhere ! (KG, 99/06/18) */ +} - bval = pSRB->TagNumber; - pDCB->TagMask &= (~(1 << bval)); /* Free TAG number */ +/* Moves first SRB from Waiting list to Going list */ +static __inline__ void dc390_Waiting_to_Going ( PDCB pDCB, PSRB pSRB ) +{ + /* Remove from waiting list */ + DEBUG0(printk("DC390: Remove SRB %p from head of Waiting\n", pSRB);) + pDCB->pWaitingSRB = pSRB->pNextSRB; + if( !pDCB->pWaitingSRB ) pDCB->pWaitLast = NULL; + pDCB->WaitSRBCnt--; + dc390_Going_append (pDCB, pSRB); } +/* 2.0 timer compatibility */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,30) + static inline int timer_pending(struct timer_list * timer) + { + return timer->prev != NULL; + } + #define time_after(a,b) ((long)(b) - (long)(a) < 0) + #define time_before(a,b) time_after(b,a) +#endif -static void dc390_DoWaitingSRB( PACB pACB ) +void DC390_waiting_timed_out (unsigned long ptr); +/* Sets the timer to wake us up */ +static void dc390_waiting_timer (PACB pACB, unsigned long to) +{ + if (timer_pending (&pACB->Waiting_Timer)) return; + init_timer (&pACB->Waiting_Timer); + pACB->Waiting_Timer.function = DC390_waiting_timed_out; + pACB->Waiting_Timer.data = (unsigned long)pACB; + if (time_before (jiffies + to, pACB->pScsiHost->last_reset)) + pACB->Waiting_Timer.expires = pACB->pScsiHost->last_reset + 1; + else + pACB->Waiting_Timer.expires = jiffies + to + 1; + add_timer (&pACB->Waiting_Timer); +} + + +/* Send the next command from the waiting list to the bus */ +static void dc390_Waiting_process ( PACB pACB ) { PDCB ptr, ptr1; PSRB pSRB; - if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) ) - { - ptr = pACB->pDCBRunRobin; - if( !ptr ) - { - ptr = pACB->pLinkDCB; - pACB->pDCBRunRobin = ptr; - } - ptr1 = ptr; - for( ;ptr1; ) - { - pACB->pDCBRunRobin = ptr1->pNextDCB; - if( !( ptr1->MaxCommand > ptr1->GoingSRBCnt ) || - !( pSRB = ptr1->pWaitingSRB ) ) - { - if(pACB->pDCBRunRobin == ptr) - break; - ptr1 = ptr1->pNextDCB; - } + if( (pACB->pActiveDCB) || (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) ) + return; + if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer); + ptr = pACB->pDCBRunRobin; + if( !ptr ) + { + ptr = pACB->pLinkDCB; + pACB->pDCBRunRobin = ptr; + } + ptr1 = ptr; + if (!ptr1) return; + do + { + pACB->pDCBRunRobin = ptr1->pNextDCB; + if( !( pSRB = ptr1->pWaitingSRB ) || + ( ptr1->MaxCommand <= ptr1->GoingSRBCnt )) + ptr1 = ptr1->pNextDCB; + else + { + /* Try to send to the bus */ + if( !dc390_StartSCSI(pACB, ptr1, pSRB) ) + dc390_Waiting_to_Going (ptr1, pSRB); else - { - if( !dc390_StartSCSI(pACB, ptr1, pSRB) ) - { - ptr1->GoingSRBCnt++; - if( ptr1->pWaitLast == pSRB ) - { - ptr1->pWaitingSRB = NULL; - ptr1->pWaitLast = NULL; - } - else - { - ptr1->pWaitingSRB = pSRB->pNextSRB; - } - pSRB->pNextSRB = NULL; - - if( ptr1->pGoingSRB ) - ptr1->pGoingLast->pNextSRB = pSRB; - else - ptr1->pGoingSRB = pSRB; - ptr1->pGoingLast = pSRB; - } - break; - } - } - } + dc390_waiting_timer (pACB, HZ/5); + break; + } + } while (ptr1 != ptr); return; } - -static __inline__ void dc390_SRBwaiting( PDCB pDCB, PSRB pSRB) +/* Wake up waiting queue */ +void DC390_waiting_timed_out (unsigned long ptr) { - if( pDCB->pWaitingSRB ) - { - pDCB->pWaitLast->pNextSRB = pSRB; - pSRB->pNextSRB = NULL; - } - else - { - pDCB->pWaitingSRB = pSRB; - } - pDCB->pWaitLast = pSRB; + PACB pACB = (PACB)ptr; + DC390_IFLAGS + DC390_AFLAGS + DEBUG0(printk ("DC390: Debug: Waiting queue woken up by timer!\n");) + DC390_LOCK_IO; + DC390_LOCK_ACB; + dc390_Waiting_process (pACB); + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; } - /*********************************************************************** * Function: static void dc390_SendSRB (PACB pACB, PSRB pSRB) * @@ -872,41 +1084,33 @@ static void dc390_SendSRB( PACB pACB, PSRB pSRB ) PDCB pDCB; pDCB = pSRB->pSRBDCB; - if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) || + if( (pDCB->MaxCommand <= pDCB->GoingSRBCnt) || (pACB->pActiveDCB) || (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) ) { - dc390_SRBwaiting(pDCB, pSRB); - goto SND_EXIT; + dc390_Waiting_append (pDCB, pSRB); + dc390_Waiting_process (pACB); + return; } +#if 0 if( pDCB->pWaitingSRB ) { - dc390_SRBwaiting(pDCB, pSRB); + dc390_Waiting_append (pDCB, pSRB); /* pSRB = GetWaitingSRB(pDCB); */ /* non-existent */ pSRB = pDCB->pWaitingSRB; + /* Remove from waiting list */ pDCB->pWaitingSRB = pSRB->pNextSRB; pSRB->pNextSRB = NULL; + if (!pDCB->pWaitingSRB) pDCB->pWaitLast = NULL; } - - if( !dc390_StartSCSI(pACB, pDCB, pSRB) ) - { - pDCB->GoingSRBCnt++; - if( pDCB->pGoingSRB ) - { - pDCB->pGoingLast->pNextSRB = pSRB; - pDCB->pGoingLast = pSRB; - } - else - { - pDCB->pGoingSRB = pSRB; - pDCB->pGoingLast = pSRB; - } - } - else - dc390_RewaitSRB0( pDCB, pSRB ); - -SND_EXIT: - return; +#endif + + if (!dc390_StartSCSI(pACB, pDCB, pSRB)) + dc390_Going_append (pDCB, pSRB); + else { + dc390_Waiting_insert (pDCB, pSRB); + dc390_waiting_timer (pACB, HZ/5); + }; } /*********************************************************************** @@ -921,8 +1125,8 @@ static void dc390_BuildSRB (Scsi_Cmnd* pcmd, PDCB pDCB, PSRB pSRB) { pSRB->pSRBDCB = pDCB; pSRB->pcmd = pcmd; - pSRB->ScsiCmdLen = pcmd->cmd_len; - memcpy (pSRB->CmdBlock, pcmd->cmnd, pcmd->cmd_len); + //pSRB->ScsiCmdLen = pcmd->cmd_len; + //memcpy (pSRB->CmdBlock, pcmd->cmnd, pcmd->cmd_len); if( pcmd->use_sg ) { @@ -955,8 +1159,39 @@ static void dc390_BuildSRB (Scsi_Cmnd* pcmd, PDCB pDCB, PSRB pSRB) pSRB->SGToBeXferLen = 0; pSRB->ScsiPhase = 0; pSRB->EndMessage = 0; + pSRB->TagNumber = 255; }; +/* Put cmnd from Query to Waiting list and send next Waiting cmnd */ +static void dc390_Query_to_Waiting (PACB pACB) +{ + Scsi_Cmnd *pcmd; + PSRB pSRB; + PDCB pDCB; + + if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) + return; + + while (pACB->QueryCnt) + { + pSRB = dc390_Free_get ( pACB ); + if (!pSRB) return; + pcmd = dc390_Query_get ( pACB ); + if (!pcmd) { dc390_Free_insert (pACB, pSRB); return; }; /* should not happen */ + pDCB = dc390_findDCB (pACB, pcmd->target, pcmd->lun); + if (!pDCB) + { + dc390_Free_insert (pACB, pSRB); + printk (KERN_ERR "DC390: Command in queue to non-existing device!\n"); + pcmd->result = MK_RES(DRIVER_ERROR,DID_ERROR,0,0); + DC390_UNLOCK_ACB_NI; + pcmd->done (pcmd); + DC390_LOCK_ACB_NI; + }; + dc390_BuildSRB (pcmd, pDCB, pSRB); + dc390_Waiting_append ( pDCB, pSRB ); + } +} /*********************************************************************** * Function : static int DC390_queue_command (Scsi_Cmnd *cmd, @@ -979,7 +1214,6 @@ static void dc390_BuildSRB (Scsi_Cmnd* pcmd, PDCB pDCB, PSRB pSRB) int DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) { - Scsi_Cmnd *pcmd; PDCB pDCB; PSRB pSRB; DC390_AFLAGS @@ -987,7 +1221,7 @@ int DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) DEBUG0(/* if(pACB->scan_devices) */ \ - printk(KERN_INFO "DC390: Queue Cmd=%02x,ID=%d,LUN=%d (pid=%li)\n",\ + printk(KERN_INFO "DC390: Queue Cmd=%02x,Tgt=%d,LUN=%d (pid=%li)\n",\ cmd->cmnd[0],cmd->target,cmd->lun,cmd->pid);) DC390_LOCK_ACB; @@ -1008,25 +1242,32 @@ int DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) if ( ( cmd->target >= pACB->pScsiHost->max_id ) || (cmd->lun >= pACB->pScsiHost->max_lun) ) { -/* printk("DC390: Ignore target %d lun %d\n", +/* printk ("DC390: Ignore target %d lun %d\n", cmd->target, cmd->lun); */ DC390_UNLOCK_ACB; - done(cmd); - return( 0 ); + //return (1); + done (cmd); + return (0); } - if( (pACB->scan_devices || cmd->cmnd[0] == TEST_UNIT_READY) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) ) + if( (pACB->scan_devices || cmd->cmnd[0] == TEST_UNIT_READY || cmd->cmnd[0] == INQUIRY) && + !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) ) { - pACB->DCBmap[cmd->target] |= (1 << cmd->lun); pACB->scan_devices = 1; - dc390_initDCB( pACB, &pDCB, cmd ); + dc390_initDCB( pACB, &pDCB, cmd->target, cmd->lun ); if (!pDCB) { - printk (KERN_ERR "DC390: kmalloc for DCB failed, ID=%2x\n", cmd->target); + printk (KERN_ERR "DC390: kmalloc for DCB failed, target %02x lun %02x\n", + cmd->target, cmd->lun); DC390_UNLOCK_ACB; - done(cmd); - return(0); + printk ("DC390: No DCB in queue_command!\n"); +#ifdef USE_NEW_EH + return (1); +#else + done (cmd); + return (0); +#endif }; } @@ -1035,71 +1276,73 @@ int DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) printk(KERN_INFO "DC390: Ignore target %02x lun %02x\n", cmd->target, cmd->lun); DC390_UNLOCK_ACB; - done(cmd); - return(0); + //return (1); + done (cmd); + return (0); } else { - pDCB = dc390_findDCB (pACB, cmd); + pDCB = dc390_findDCB (pACB, cmd->target, cmd->lun); if (!pDCB) { /* should never happen */ + printk (KERN_ERR "DC390: no DCB failed, target %02x lun %02x\n", + cmd->target, cmd->lun); DC390_UNLOCK_ACB; - done(cmd); - return(0); + printk ("DC390: No DCB in queuecommand (2)!\n"); +#ifdef USE_NEW_EH + return (1); +#else + done (cmd); + return (0); +#endif }; } pACB->Cmds++; cmd->scsi_done = done; cmd->result = 0; + + dc390_Query_to_Waiting (pACB); - if( pDCB->QIORBCnt ) /* Unsent commands ? */ + if( pACB->QueryCnt ) /* Unsent commands ? */ { - dc390_QLinkcmd( cmd, pDCB ); - pcmd = dc390_Getcmd( pDCB ); /* Get first command */ - pACB->CmdInQ++; + DEBUG0(printk ("DC390: QueryCnt != 0\n");) + dc390_Query_append ( cmd, pACB ); + dc390_Waiting_process (pACB); } - else - pcmd = cmd; - - pSRB = dc390_GetSRB( pACB ); - - if( !pSRB ) + else if (pDCB->pWaitingSRB) { - dc390_QLinkcmd( pcmd, pDCB ); /* Queue command at the end */ - pACB->CmdOutOfSRB++; - DC390_UNLOCK_ACB; - return(0); + pSRB = dc390_Free_get ( pACB ); + DEBUG0(if (!pSRB) printk ("DC390: No free SRB but Waiting\n"); else printk ("DC390: Free SRB w/ Waiting\n");) + if (!pSRB) dc390_Query_append (cmd, pACB); + else + { + dc390_BuildSRB (cmd, pDCB, pSRB); + dc390_Waiting_append (pDCB, pSRB); + } + dc390_Waiting_process (pACB); } - - dc390_BuildSRB (pcmd, pDCB, pSRB); - dc390_SendSRB( pACB, pSRB ); + else + { + pSRB = dc390_Free_get ( pACB ); + DEBUG0(if (!pSRB) printk ("DC390: No free SRB w/o Waiting\n"); else printk ("DC390: Free SRB w/o Waiting\n");) + if (!pSRB) + { + dc390_Query_append (cmd, pACB); + dc390_Waiting_process (pACB); + } + else + { + dc390_BuildSRB (cmd, pDCB, pSRB); + dc390_SendSRB (pACB, pSRB); + }; + }; DC390_UNLOCK_ACB; - DEBUG1(printk (KERN_DEBUG " ... command (%02x) queued successfully.\n", pcmd->cmnd[0]);) + DEBUG1(printk (KERN_DEBUG " ... command (pid %li) queued successfully.\n", cmd->pid);) return(0); } - -static void dc390_DoNextCmd( PACB pACB, PDCB pDCB ) -{ - Scsi_Cmnd *pcmd; - PSRB pSRB; - - if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) - return; - - pcmd = dc390_Getcmd( pDCB ); - pSRB = dc390_GetSRB( pACB ); - if( !pSRB ) - dc390_QLinkcmd( pcmd, pDCB ); - else - { - dc390_BuildSRB (pcmd, pDCB, pSRB); - dc390_SendSRB( pACB, pSRB ); - }; -} - /* We ignore mapping problems, as we expect everybody to respect * valid partition tables. Waiting for complaints ;-) */ @@ -1236,15 +1479,17 @@ int DC390_bios_param (Disk *disk, kdev_t devno, int geom[]) void dc390_dumpinfo (PACB pACB, PDCB pDCB, PSRB pSRB) { USHORT pstat; PDEVDECL1; + if (!pDCB) pDCB = pACB->pActiveDCB; + if (!pSRB && pDCB) pSRB = pDCB->pActiveSRB; if (pSRB) { - printk ("DC390: SRB: Xferred %08lx, Remain %08lx, State %08lx, Phase %02x\n", + printk ("DC390: SRB: Xferred %08lx, Remain %08lx, State %08x, Phase %02x\n", pSRB->TotalXferredLen, pSRB->SGToBeXferLen, pSRB->SRBState, pSRB->ScsiPhase); printk ("DC390: AdpaterStatus: %02x, SRB Status %02x\n", pSRB->AdaptStatus, pSRB->SRBStatus); }; - printk ("DC390: Status of last IRQ (DMA/SC/Int/IRQ): %08lx\n", dc390_laststatus); + printk ("DC390: Status of last IRQ (DMA/SC/Int/IRQ): %08x\n", dc390_laststatus); printk ("DC390: Register dump: SCSI block:\n"); printk ("DC390: XferCnt Cmd Stat IntS IRQS FFIS Ctl1 Ctl2 Ctl3 Ctl4\n"); printk ("DC390: %06x %02x %02x %02x", @@ -1254,6 +1499,12 @@ void dc390_dumpinfo (PACB pACB, PDCB pDCB, PSRB pSRB) DC390_read8(INT_Status), DC390_read8(Current_Fifo), DC390_read8(CtrlReg1), DC390_read8(CtrlReg2), DC390_read8(CtrlReg3), DC390_read8(CtrlReg4)); DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT); + if (DC390_read8(Current_Fifo) & 0x1f) + { + printk ("DC390: FIFO:"); + while (DC390_read8(Current_Fifo) & 0x1f) printk (" %02x", DC390_read8(ScsiFifo)); + printk ("\n"); + }; printk ("DC390: Register dump: DMA engine:\n"); printk ("DC390: Cmd STrCnt SBusA WrkBC WrkAC Stat SBusCtrl\n"); printk ("DC390: %02x %08x %08x %08x %08x %02x %08x\n", @@ -1283,44 +1534,40 @@ int DC390_abort (Scsi_Cmnd *cmd) { PDCB pDCB; PSRB pSRB, psrb; - ULONG count, i; - PSCSICMD pcmd, pcmd1; + UINT count, i; + PSCSICMD pcmd; int status; - ULONG sbac; + //ULONG sbac; DC390_AFLAGS PACB pACB = (PACB) cmd->host->hostdata; DC390_LOCK_ACB; - pDCB = dc390_findDCB (pACB, cmd); - /* abort() is too buggy at the moment. If it's called we are in trouble anyway. - * so let's dump some info into the syslog at least. (KG, 98/08/20) */ - if (pDCB) pSRB = pDCB->pActiveSRB; else pSRB = 0; - printk ("DC390: Abort command (pid %li, DCB %p, SRB %p)\n", - cmd->pid, pDCB, pSRB); - dc390_dumpinfo (pACB, pDCB, pSRB); - - if( !pDCB ) goto NOT_RUN; + printk ("DC390: Abort command (pid %li, Device %02i-%02i)\n", + cmd->pid, cmd->target, cmd->lun); - if( pDCB->QIORBCnt ) + /* First scan Query list */ + if( pACB->QueryCnt ) { - pcmd = pDCB->pQIORBhead; + pcmd = pACB->pQueryHead; if( pcmd == cmd ) { - pDCB->pQIORBhead = pcmd->next; + /* Found: Dequeue */ + pACB->pQueryHead = pcmd->next; pcmd->next = NULL; - pDCB->QIORBCnt--; + if (cmd == pACB->pQueryTail) pACB->pQueryTail = NULL; + pACB->QueryCnt--; status = SCSI_ABORT_SUCCESS; goto ABO_X; } - for( count = pDCB->QIORBCnt, i=0; iQueryCnt, i=0; inext == cmd ) { - pcmd1 = pcmd->next; - pcmd->next = pcmd1->next; - pcmd1->next = NULL; - pDCB->QIORBCnt--; + pcmd->next = cmd->next; + cmd->next = NULL; + if (cmd == pACB->pQueryTail) pACB->pQueryTail = NULL; + pACB->QueryCnt--; status = SCSI_ABORT_SUCCESS; goto ABO_X; } @@ -1331,14 +1578,21 @@ int DC390_abort (Scsi_Cmnd *cmd) } } + pDCB = dc390_findDCB (pACB, cmd->target, cmd->lun); + if( !pDCB ) goto NOT_RUN; + /* Added 98/07/02 KG */ + /* pSRB = pDCB->pActiveSRB; if (pSRB && pSRB->pcmd == cmd ) goto ON_GOING; - + */ + pSRB = pDCB->pWaitingSRB; if( !pSRB ) goto ON_GOING; + + /* Now scan Waiting queue */ if( pSRB->pcmd == cmd ) { pDCB->pWaitingSRB = pSRB->pNextSRB; @@ -1358,16 +1612,21 @@ int DC390_abort (Scsi_Cmnd *cmd) pSRB = psrb->pNextSRB; psrb->pNextSRB = pSRB->pNextSRB; if( pSRB == pDCB->pWaitLast ) - pDCB->pWaitLast = psrb; /* No check for psrb == NULL ? */ + pDCB->pWaitLast = psrb; IN_WAIT: - pSRB->pNextSRB = pACB->pFreeSRB; - pACB->pFreeSRB = pSRB; + dc390_Free_insert (pACB, pSRB); + pDCB->WaitSRBCnt--; cmd->next = NULL; status = SCSI_ABORT_SUCCESS; goto ABO_X; } + /* SRB has already been sent ! */ ON_GOING: + /* abort() is too stupid for already sent commands at the moment. + * If it's called we are in trouble anyway, so let's dump some info + * into the syslog at least. (KG, 98/08/20,99/06/20) */ + dc390_dumpinfo (pACB, pDCB, pSRB); pSRB = pDCB->pGoingSRB; pDCB->DCBFlag |= ABORT_DEV_; /* Now for the hard part: The command is currently processed */ @@ -1398,12 +1657,13 @@ NOT_RUN: ABO_X: cmd->result = DID_ABORT << 16; printk(KERN_INFO "DC390: Aborted pid %li with status %i\n", cmd->pid, status); +#if 0 if (cmd->pid == dc390_lastabortedpid) /* repeated failure ? */ { /* Let's do something to help the bus getting clean again */ DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); DC390_write8 (ScsiCmd, DMA_COMMAND); - //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); //DC390_write8 (ScsiCmd, RESET_ATN_CMD); DC390_write8 (ScsiCmd, NOP_CMD); //udelay (10000); @@ -1428,10 +1688,13 @@ ABO_X: sbac = DC390_read32 (DMA_ScsiBusCtrl); printk ("%08lx\n", sbac); }; +#endif dc390_lastabortedpid = cmd->pid; DC390_UNLOCK_ACB; //do_DC390_Interrupt (pACB->IRQLevel, 0, 0); - cmd->scsi_done(cmd); +#ifndef USE_NEW_EH + if (status == SCSI_ABORT_SUCCESS) cmd->scsi_done(cmd); +#endif return( status ); } @@ -1448,20 +1711,24 @@ static void dc390_ResetDevParam( PACB pACB ) pDCB->SyncMode &= ~SYNC_NEGO_DONE; pDCB->SyncPeriod = 0; pDCB->SyncOffset = 0; + pDCB->TagMask = 0; pDCB->CtrlR3 = FAST_CLK; pDCB->CtrlR4 &= NEGATE_REQACKDATA | CTRL4_RESERVED | NEGATE_REQACK; pDCB->CtrlR4 |= pACB->glitch_cfg; pDCB = pDCB->pNextDCB; } while( pdcb != pDCB ); -} + pACB->ACBFlag &= ~(RESET_DEV | RESET_DONE | RESET_DETECT); +} +#if 0 +/* Moves all SRBs from Going to Waiting for all DCBs */ static void dc390_RecoverSRB( PACB pACB ) { PDCB pDCB, pdcb; PSRB psrb, psrb2; - ULONG cnt, i; + UINT cnt, i; pDCB = pACB->pLinkDCB; if( !pDCB ) return; @@ -1493,7 +1760,7 @@ static void dc390_RecoverSRB( PACB pACB ) pdcb = pdcb->pNextDCB; } while( pdcb != pDCB ); } - +#endif /*********************************************************************** * Function : int DC390_reset (Scsi_Cmnd *cmd, ...) @@ -1501,34 +1768,37 @@ static void dc390_RecoverSRB( PACB pACB ) * Purpose : perform a hard reset on the SCSI bus * * Inputs : cmd - command which caused the SCSI RESET + * resetFlags - how hard to try * * Returns : 0 on success. ***********************************************************************/ -int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags) +int DC390_reset (Scsi_Cmnd *cmd, unsigned int resetFlags) { UCHAR bval; - ULONG i; DC390_AFLAGS PACB pACB = (PACB) cmd->host->hostdata; printk(KERN_INFO "DC390: RESET ... "); DC390_LOCK_ACB; + if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer); bval = DC390_read8 (CtrlReg1); bval |= DIS_INT_ON_SCSI_RST; - DC390_write8 (CtrlReg1, bval); /* disable interrupt */ + DC390_write8 (CtrlReg1, bval); /* disable IRQ on bus reset */ + pACB->ACBFlag |= RESET_DEV; dc390_ResetSCSIBus( pACB ); - /* Unlock ? */ - for( i=0; i<600; i++ ) - udelay(1000); + dc390_ResetDevParam( pACB ); + udelay (1000); + pACB->pScsiHost->last_reset = jiffies + 3*HZ/2 + + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]; + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); DC390_read8 (INT_Status); /* Reset Pending INT */ - dc390_ResetDevParam( pACB ); - dc390_DoingSRB_Done( pACB ); + dc390_DoingSRB_Done( pACB, cmd ); /* dc390_RecoverSRB (pACB); */ pACB->pActiveDCB = NULL; @@ -1537,10 +1807,10 @@ int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags) bval &= ~DIS_INT_ON_SCSI_RST; DC390_write8 (CtrlReg1, bval); /* re-enable interrupt */ - dc390_DoWaitingSRB( pACB ); + dc390_Waiting_process( pACB ); - DC390_UNLOCK_ACB; printk("done\n"); + DC390_UNLOCK_ACB; return( SCSI_RESET_SUCCESS ); } @@ -1550,22 +1820,22 @@ int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags) /*********************************************************************** * Function : static void dc390_initDCB() * - * Purpose : initialize the internal structures for a given DCB + * Purpose : initialize the internal structures for a DCB (to be malloced) * - * Inputs : cmd - pointer to this scsi cmd request block structure + * Inputs : SCSI id and lun ***********************************************************************/ -void dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd ) +void dc390_initDCB( PACB pACB, PDCB *ppDCB, UCHAR id, UCHAR lun ) { PEEprom prom; UCHAR index; - PDCB pDCB; + PDCB pDCB, pDCB2; pDCB = kmalloc (sizeof(DC390_DCB), GFP_ATOMIC); - DCBDEBUG(printk (KERN_INFO "DC390: alloc mem for DCB (ID %i, LUN %i): 0x%08x\n", \ - cmd->target, cmd->lun, (int)pDCB);) + DCBDEBUG(printk (KERN_INFO "DC390: alloc mem for DCB (ID %i, LUN %i): %p\n" \ + id, lun, pDCB);) - *ppDCB = pDCB; + *ppDCB = pDCB; pDCB2 = 0; if (!pDCB) return; if( pACB->DCBCnt == 0 ) { @@ -1579,37 +1849,58 @@ void dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd ) pACB->DCBCnt++; - pACB->pLastDCB = pDCB; pDCB->pNextDCB = pACB->pLinkDCB; + pACB->pLastDCB = pDCB; pDCB->pDCBACB = pACB; - pDCB->QIORBCnt = 0; - pDCB->UnitSCSIID = cmd->target; - pDCB->UnitSCSILUN = cmd->lun; + pDCB->TargetID = id; + pDCB->TargetLUN = lun; pDCB->pWaitingSRB = NULL; pDCB->pGoingSRB = NULL; pDCB->GoingSRBCnt = 0; + pDCB->WaitSRBCnt = 0; pDCB->pActiveSRB = NULL; pDCB->TagMask = 0; pDCB->MaxCommand = 1; index = pACB->AdapterIndex; pDCB->DCBFlag = 0; - prom = (PEEprom) &dc390_eepromBuf[index][cmd->target << 2]; - pDCB->DevMode = prom->EE_MODE1; + /* Is there a corresp. LUN==0 device ? */ + if (lun != 0) + pDCB2 = dc390_findDCB (pACB, id, 0); + prom = (PEEprom) &dc390_eepromBuf[index][id << 2]; + /* Some values are for all LUNs: Copy them */ + /* In a clean way: We would have an own structure for a SCSI-ID */ + if (pDCB2) + { + pDCB->DevMode = pDCB2->DevMode; + pDCB->SyncMode = pDCB2->SyncMode; + pDCB->SyncPeriod = pDCB2->SyncPeriod; + pDCB->SyncOffset = pDCB2->SyncOffset; + pDCB->NegoPeriod = pDCB2->NegoPeriod; + + pDCB->CtrlR3 = pDCB2->CtrlR3; + pDCB->CtrlR4 = pDCB2->CtrlR4; + pDCB->Inquiry7 = pDCB2->Inquiry7; + } + else + { + pDCB->DevMode = prom->EE_MODE1; + pDCB->SyncMode = 0; + pDCB->SyncPeriod = 0; + pDCB->SyncOffset = 0; + pDCB->NegoPeriod = (dc390_clock_period1[prom->EE_SPEED] * 25) >> 2; + + pDCB->CtrlR3 = FAST_CLK; + + pDCB->CtrlR4 = pACB->glitch_cfg | CTRL4_RESERVED; + if( dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) + pDCB->CtrlR4 |= NEGATE_REQACKDATA | NEGATE_REQACK; + pDCB->Inquiry7 = 0; + } - pDCB->SyncMode = 0; + pACB->DCBmap[id] |= (1 << lun); dc390_updateDCB(pACB, pDCB); - - pDCB->SyncPeriod = 0; - pDCB->SyncOffset = 0; - pDCB->NegoPeriod = (dc390_clock_period1[prom->EE_SPEED] * 25) >> 2; - - pDCB->CtrlR3 = FAST_CLK; - - pDCB->CtrlR4 = pACB->glitch_cfg | CTRL4_RESERVED; - if( dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) - pDCB->CtrlR4 |= NEGATE_REQACKDATA | NEGATE_REQACK; } /*********************************************************************** @@ -1620,24 +1911,26 @@ void dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd ) void dc390_updateDCB (PACB pACB, PDCB pDCB) { - pDCB->IdentifyMsg = IDENTIFY (pDCB->DevMode & EN_DISCONNECT_, pDCB->UnitSCSILUN); - - if (pDCB->DevMode & TAG_QUEUEING_) pDCB->SyncMode &= EN_TAG_QUEUEING | SYNC_NEGO_DONE | EN_ATN_STOP; - else pDCB->SyncMode &= SYNC_NEGO_DONE | EN_ATN_STOP; - - if( pDCB->DevMode & SYNC_NEGO_ && (!(pDCB->UnitSCSILUN) || dc390_CurrSyncOffset) ) - pDCB->SyncMode |= SYNC_ENABLE; - else - { + pDCB->SyncMode &= EN_TAG_QUEUEING | SYNC_NEGO_DONE /*| EN_ATN_STOP*/; + if (pDCB->DevMode & TAG_QUEUEING_) { + //if (pDCB->SyncMode & EN_TAG_QUEUEING) pDCB->MaxCommand = pACB->TagMaxNum; + } else { + pDCB->SyncMode &= ~EN_TAG_QUEUEING; + pDCB->MaxCommand = 1; + }; + + if( pDCB->DevMode & SYNC_NEGO_ ) + pDCB->SyncMode |= SYNC_ENABLE; + else { pDCB->SyncMode &= ~(SYNC_NEGO_DONE | SYNC_ENABLE); pDCB->SyncOffset &= ~0x0f; - }; - - if (! (pDCB->DevMode & EN_DISCONNECT_)) pDCB->SyncMode &= ~EN_ATN_STOP; - + }; + + //if (! (pDCB->DevMode & EN_DISCONNECT_)) pDCB->SyncMode &= ~EN_ATN_STOP; + pDCB->CtrlR1 = pACB->pScsiHost->this_id; if( pDCB->DevMode & PARITY_CHK_ ) - pDCB->CtrlR1 |= PARITY_ERR_REPO; + pDCB->CtrlR1 |= PARITY_ERR_REPO; }; @@ -1651,7 +1944,7 @@ static void dc390_updateDCBs (PACB pACB) { int i; PDCB pDCB = pACB->pLinkDCB; - for (i = 0; i < pACB->DeviceCnt; i++) + for (i = 0; i < pACB->DCBCnt; i++) { dc390_updateDCB (pACB, pDCB); pDCB = pDCB->pNextDCB; @@ -1675,12 +1968,12 @@ static void __inline__ dc390_initSRB( PSRB psrb ) void dc390_linkSRB( PACB pACB ) { - ULONG count, i; + UINT count, i; count = pACB->SRBCount; - for( i=0; i< count; i++) + for( i=0; iSRB_array[i].pNextSRB = &pACB->SRB_array[i+1]; else pACB->SRB_array[i].pNextSRB = NULL; @@ -1710,7 +2003,15 @@ void __init dc390_initACB (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index) psh->io_port = io_port; psh->n_io_port = 0x80; psh->irq = Irq; - +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,50) + psh->base = io_port; +#else + psh->base = (char*)io_port; +#endif + psh->unique_id = io_port; + psh->dma_channel = -1; + psh->last_reset = jiffies; + pACB = (PACB) psh->hostdata; DC390_LOCKA_INIT; DC390_LOCK_ACB; @@ -1735,6 +2036,8 @@ void __init dc390_initACB (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index) pACB->pActiveDCB = NULL; pACB->pFreeSRB = pACB->SRB_array; pACB->SRBCount = MAX_SRB_CNT; + pACB->QueryCnt = 0; + pACB->pQueryHead = NULL; pACB->AdapterIndex = index; pACB->status = 0; psh->this_id = dc390_eepromBuf[index][EE_ADAPT_SCSI_ID]; @@ -1753,7 +2056,9 @@ void __init dc390_initACB (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index) pACB->DCBmap[i] = 0; pACB->sel_timeout = SEL_TIMEOUT; pACB->glitch_cfg = EATER_25NS; - pACB->Cmds = pACB->CmdInQ = pACB->CmdOutOfSRB = pACB->SelLost = 0; + pACB->Cmds = pACB->CmdInQ = pACB->CmdOutOfSRB = 0; + pACB->SelLost = pACB->SelConn = 0; + init_timer (&pACB->Waiting_Timer); } @@ -1771,22 +2076,11 @@ void __init dc390_initACB (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index) int __init dc390_initAdapter (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index) { PACB pACB, pACB2; - UCHAR used_irq = 0, dstate; + UCHAR dstate; int i; pACB = (PACB) psh->hostdata; - for ( pACB2 = dc390_pACB_start; pACB2 ; ) - { - if( pACB2->IRQLevel == Irq ) - { - used_irq = 1; - break; - } - else - pACB2 = pACB2->pNextACB; - } - if (check_region (io_port, psh->n_io_port)) { printk(KERN_ERR "DC390: register IO ports error!\n"); @@ -1797,14 +2091,12 @@ int __init dc390_initAdapter (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index) DC390_read8_ (INT_Status, io_port); /* Reset Pending INT */ - if( !used_irq ) - { - if( (i = request_irq(Irq, do_DC390_Interrupt, DC390_IRQ, "tmscsim", NULL) )) - { - printk(KERN_ERR "DC390: register IRQ error!\n"); - return( -1 ); - } - } + if( (i = request_irq(Irq, do_DC390_Interrupt, DC390_IRQ, "tmscsim", pACB) )) + { + printk(KERN_ERR "DC390: register IRQ error!\n"); + release_region (io_port, psh->n_io_port); + return( -1 ); + } if( !dc390_pACB_start ) { @@ -1826,9 +2118,13 @@ int __init dc390_initAdapter (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index) if (pACB->Gmode2 & RST_SCSI_BUS) { dc390_ResetSCSIBus( pACB ); - /* Unlock before ? */ - for( i=0; i<600; i++ ) + udelay (1000); + pACB->pScsiHost->last_reset = jiffies + HZ/2 + + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]; + /* + for( i=0; i<(500 + 1000*dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]); i++ ) udelay(1000); + */ }; pACB->ACBFlag = 0; DC390_read8 (INT_Status); /* Reset Pending INT */ @@ -1840,6 +2136,7 @@ int __init dc390_initAdapter (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index) DC390_write8 (CtrlReg3, FAST_CLK); /* fast clock */ DC390_write8 (CtrlReg4, pACB->glitch_cfg | /* glitch eater */ (dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) ? NEGATE_REQACKDATA : 0); /* Negation */ + DC390_write8 (CtcReg_High, 0); /* Clear Transfer Count High: ID */ DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT); @@ -1879,18 +2176,24 @@ static int __init DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, PDEVDECL, UCH printk (KERN_ERR "DC390_init: No EEPROM found!\n"); return( -1 ); #else - int period; - printk (KERN_INFO "DC390_init: No EEPROM found!\n"); - printk (KERN_INFO "DC390_init: Trying default EEPROM settings:\n"); - dc390_checkparams (); - period = dc390_clock_period1[tmscsim[1]]; + int speed; + dc390_adapname = "AM53C974"; + printk (KERN_INFO "DC390_init: No EEPROM found! Trying default settings ...\n"); + dc390_check_for_safe_settings (); + dc390_fill_with_defaults (); + dc390_EEprom_Override (index); + speed = dc390_clock_speed[tmscsim[1]]; printk (KERN_INFO "DC390: Used defaults: AdaptID=%i, SpeedIdx=%i (%i.%i MHz)," - " DevMode=0x%02x, AdaptMode=0x%02x, TaggedCmnds=%i (%i)\n", tmscsim[0], tmscsim[1], - 40 / period, ((40%period)*10 + period/2) / period, - (UCHAR)tmscsim[2], (UCHAR)tmscsim[3], tmscsim[4], 2 << (tmscsim[4])); - dc390_EEpromDefaults (index); + " DevMode=0x%02x, AdaptMode=0x%02x, TaggedCmnds=%i (%i), DelayReset=%is\n", + tmscsim[0], tmscsim[1], speed/10, speed%10, + (UCHAR)tmscsim[2], (UCHAR)tmscsim[3], tmscsim[4], 2 << (tmscsim[4]), tmscsim[5]); #endif - }; + } + else + { + dc390_check_for_safe_settings (); + dc390_EEprom_Override (index); + } psh = scsi_register( psht, sizeof(DC390_ACB) ); if( !psh ) return( -1 ); @@ -1994,7 +2297,8 @@ int __init DC390_detect (Scsi_Host_Template *psht) PDEVDECL0; UCHAR irq; UINT io_port; - DC390_IFLAGS DC390_DFLAGS + //DC390_IFLAGS + DC390_DFLAGS DC390_LOCK_DRV; //dc390_pSHT_start = psht; @@ -2003,9 +2307,11 @@ int __init DC390_detect (Scsi_Host_Template *psht) if ( PCI_PRESENT ) while (PCI_FIND_DEVICE (PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974)) { - if (pci_enable_device(pdev)) - continue; - DC390_LOCK_IO; /* Remove this when going to new eh */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,30) + if (pci_enable_device (pdev)) + continue; +#endif + //DC390_LOCK_IO; /* Remove this when going to new eh */ PCI_GET_IO_AND_IRQ; DEBUG0(printk(KERN_INFO "DC390(%i): IO_PORT=%04x,IRQ=%x\n", dc390_adapterCnt, (UINT) io_port, irq);) @@ -2015,14 +2321,17 @@ int __init DC390_detect (Scsi_Host_Template *psht) dc390_set_pci_cfg (PDEV); dc390_adapterCnt++; }; - DC390_UNLOCK_IO; /* Remove when going to new eh */ + //DC390_UNLOCK_IO; /* Remove when going to new eh */ } else printk (KERN_ERR "DC390: No PCI BIOS found!\n"); if (dc390_adapterCnt) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30) psht->proc_name = "tmscsim"; - +#else + psht->proc_dir = &DC390_proc_scsi_tmscsim; +#endif printk(KERN_INFO "DC390: %i adapters found\n", dc390_adapterCnt); DC390_UNLOCK_DRV; return( dc390_adapterCnt ); @@ -2044,7 +2353,7 @@ static void dc390_inquiry_done (Scsi_Cmnd* cmd) if (cmd->result) { PACB pACB = (PACB)cmd->host->hostdata; - PDCB pDCB = dc390_findDCB (pACB, cmd); + PDCB pDCB = dc390_findDCB (pACB, cmd->target, cmd->lun); printk ("DC390: Unsetting DsCn, Sync and TagQ!\n"); if (pDCB) { @@ -2052,7 +2361,6 @@ static void dc390_inquiry_done (Scsi_Cmnd* cmd) dc390_updateDCB (pACB, pDCB); }; }; - kfree (cmd->buffer); kfree (cmd); }; @@ -2060,20 +2368,21 @@ void dc390_inquiry (PACB pACB, PDCB pDCB) { char* buffer; Scsi_Cmnd* cmd; - buffer = kmalloc (256, GFP_ATOMIC); - cmd = kmalloc (sizeof (Scsi_Cmnd), GFP_ATOMIC); + cmd = kmalloc (sizeof(Scsi_Cmnd) + 256, GFP_ATOMIC); + if (!cmd) { printk ("DC390: kmalloc failed in inquiry!\n"); return; }; + buffer = (char*)cmd + sizeof(Scsi_Cmnd); - memset (buffer, 0, 256); - memset (cmd, 0, sizeof(Scsi_Cmnd)); + memset (cmd, 0, sizeof(Scsi_Cmnd) + 256); cmd->cmnd[0] = INQUIRY; - cmd->cmnd[1] = (pDCB->UnitSCSILUN << 5) & 0xe0; + cmd->cmnd[1] = (pDCB->TargetLUN << 5) & 0xe0; cmd->cmnd[4] = 0xff; cmd->cmd_len = 6; cmd->old_cmd_len = 6; cmd->host = pACB->pScsiHost; - cmd->target = pDCB->UnitSCSIID; - cmd->lun = pDCB->UnitSCSILUN; + cmd->target = pDCB->TargetID; + cmd->lun = pDCB->TargetLUN; cmd->serial_number = 1; + cmd->pid = 390; cmd->bufflen = 128; cmd->buffer = buffer; cmd->request_bufflen = 128; @@ -2084,11 +2393,62 @@ void dc390_inquiry (PACB pACB, PDCB pDCB) cmd->request.rq_status = RQ_SCSI_BUSY; + pDCB->SyncMode &= ~SYNC_NEGO_DONE; printk (KERN_INFO "DC390: Queue INQUIRY command to dev ID %02x LUN %02x\n", - pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + pDCB->TargetID, pDCB->TargetLUN); DC390_queue_command (cmd, dc390_inquiry_done); }; +/*********************************************************************** + * Functions: dc390_sendstart(), dc390_sendstart_done() + * + * Purpose: When changing speed etc., we have to issue an INQUIRY + * command to make sure, we agree upon the nego parameters + * with the device + ***********************************************************************/ + +static void dc390_sendstart_done (Scsi_Cmnd* cmd) +{ + printk (KERN_INFO "DC390: SENDSTART (ID %02x LUN %02x) returned %08x\n", + cmd->target, cmd->lun, cmd->result); + kfree (cmd); +}; + +void dc390_sendstart (PACB pACB, PDCB pDCB) +{ + char* buffer; + Scsi_Cmnd* cmd; + cmd = kmalloc (sizeof(Scsi_Cmnd) + 256, GFP_ATOMIC); + if (!cmd) { printk ("DC390: kmalloc failed in sendstart!\n"); return; }; + buffer = (char*)cmd + sizeof(Scsi_Cmnd); + + memset (cmd, 0, sizeof(Scsi_Cmnd) + 256); + cmd->cmnd[0] = 0x1b; /* START_STOP_UNIT */ + cmd->cmnd[1] = (pDCB->TargetLUN << 5) & 0xe0; + cmd->cmnd[4] = 0x01; /* START */ + + cmd->cmd_len = 6; cmd->old_cmd_len = 6; + cmd->host = pACB->pScsiHost; + cmd->target = pDCB->TargetID; + cmd->lun = pDCB->TargetLUN; + cmd->serial_number = 1; + cmd->pid = 310; + cmd->bufflen = 128; + cmd->buffer = buffer; + cmd->request_bufflen = 128; + cmd->request_buffer = &buffer[128]; + cmd->done = dc390_sendstart_done; + cmd->scsi_done = dc390_sendstart_done; + cmd->timeout_per_command = 5*HZ; + + cmd->request.rq_status = RQ_SCSI_BUSY; + + pDCB->SyncMode &= ~SYNC_NEGO_DONE; + printk (KERN_INFO "DC390: Queue SEND_START command to dev ID %02x LUN %02x\n", + pDCB->TargetID, pDCB->TargetLUN); + DC390_queue_command (cmd, dc390_sendstart_done); +}; + /******************************************************************** * Function: dc390_set_info() * @@ -2206,6 +2566,9 @@ int dc390_set_info (char *buffer, int length, PACB pACB) if (!memcmp (pos, "RESET", 5)) goto reset; else if (!memcmp (pos, "INQUIRY", 7)) goto inquiry; else if (!memcmp (pos, "REMOVE", 6)) goto remove; + else if (!memcmp (pos, "ADD", 3)) goto add; + else if (!memcmp (pos, "START", 5)) goto start; + else if (!memcmp (pos, "DUMP", 4)) goto dump; if (isdigit (*pos)) { @@ -2222,13 +2585,20 @@ int dc390_set_info (char *buffer, int length, PACB pACB) pDCB = pACB->pLinkDCB; for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB; /* Sanity Check */ - if (pDCB->UnitSCSIID != id || pDCB->UnitSCSILUN != lun) + if (pDCB->TargetID != id || pDCB->TargetLUN != lun) { printk (KERN_ERR "DC390: no such device: Idx=%02i ID=%02i LUN=%02i\n", dev, id, lun); goto einv2; }; + if (pDCB->pWaitingSRB || pDCB->pGoingSRB) + { + printk ("DC390: Cannot change dev (%i-%i) cfg: Pending requests\n", + pDCB->TargetID, pDCB->TargetLUN); + goto einv; + }; + olddevmode = pDCB->DevMode; YESNO (pos, pDCB->DevMode, PARITY_CHK_); needs_inquiry++; @@ -2241,8 +2611,7 @@ int dc390_set_info (char *buffer, int length, PACB pACB) needs_inquiry++; YESNO (pos, pDCB->DevMode, TAG_QUEUEING_); if ((olddevmode & TAG_QUEUEING_) == (pDCB->DevMode & TAG_QUEUEING_)) needs_inquiry--; - YESNO (pos, pDCB->SyncMode, EN_ATN_STOP); - + dc390_updateDCB (pACB, pDCB); if (!pos) goto ok; @@ -2262,7 +2631,7 @@ int dc390_set_info (char *buffer, int length, PACB pACB) else pos = strtok (0, " \t\n:=,;."); if (!pos) goto ok; - /* Speed: NegoPeriod */ + /* Sync Speed in MHz */ if (*pos != '-') { SCANF (pos, p0, dum, 1, 13); @@ -2277,11 +2646,11 @@ int dc390_set_info (char *buffer, int length, PACB pACB) for (; p0-pos > 1; p0--) dum /= 10; pDCB->NegoPeriod = (100000/(100*dumold + dum)) >> 2; if (pDCB->NegoPeriod < 19) pDCB->NegoPeriod = 19; - if (pDCB->NegoPeriod != olddevmode) needs_inquiry++; pos = strtok (0, " \t\n:=,;"); if (!pos) goto ok; }; if (*pos == 'M') pos = strtok (0, " \t\n:=,;"); + if (pDCB->NegoPeriod != olddevmode) needs_inquiry++; } else pos = strtok (0, " \t\n:=,;"); /* dc390_updateDCB (pACB, pDCB); */ @@ -2296,28 +2665,49 @@ int dc390_set_info (char *buffer, int length, PACB pACB) if (pDCB->SyncOffset > olddevmode) needs_inquiry++; } else pos = strtok (0, " \t\n:=,;"); + if (!pos) goto ok; dc390_updateDCB (pACB, pDCB); + + //olddevmode = pDCB->MaxCommand; + /* MaxCommand (Tags) */ + if (*pos != '-') + { + SCANF (pos, p0, dum, 1, 32 /*pACB->TagMaxNum*/); + if (pDCB->SyncMode & EN_TAG_QUEUEING) + pDCB->MaxCommand = dum; + else printk (KERN_INFO "DC390: Can't set MaxCmd larger than one without Tag Queueing!\n"); + } + else pos = strtok (0, " \t\n:=,;"); + } else { - char* p1 = pos; UCHAR dum; + char* p1 = pos; UCHAR dum, newadaptid; PARSEDEBUG(printk (KERN_INFO "DC390: chg adapt cfg \"%s\"\n", prstr (pos, &buffer[length]));) dum = GLITCH_TO_NS (pACB->glitch_cfg); /* Adapter setting */ SEARCH (pos, p0, pACB->pScsiHost->max_id, "MAXID", 8); SEARCH (pos, p0, pACB->pScsiHost->max_lun, "MAXLUN", 8); - SEARCH (pos, p0, pACB->pScsiHost->this_id, "ADAPTERID", 7); + SEARCH (pos, p0, newadaptid, "ADAPTERID", 7); SEARCH (pos, p0, pACB->TagMaxNum, "TAGMAXNUM", 32); SEARCH (pos, p0, pACB->ACBFlag, "ACBFLAG", 255); SEARCH3 (pos, p0, dum, "GLITCHEATER", 40, 1000, "NS"); SEARCH3 (pos, p0, pACB->sel_timeout, "SELTIMEOUT", 400, 163, "MS"); + SEARCH3 (pos, p0, dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY], "DELAYRESET", 180, 100, "S"); ok2: pACB->glitch_cfg = NS_TO_GLITCH (dum); if (pACB->sel_timeout < 60) pACB->sel_timeout = 60; - dum = 0; while (1 << dum <= pACB->TagMaxNum) dum ++; - pACB->TagMaxNum &= (1 << --dum); - if (pos == p1) goto einv; + DC390_write8 (Scsi_TimeOut, pACB->sel_timeout); + if (newadaptid != pACB->pScsiHost->this_id) + { + pACB->pScsiHost->this_id = newadaptid; + dc390_ResetDevParam (pACB); + } + //dum = 0; while (1 << dum <= pACB->TagMaxNum) dum ++; + //pACB->TagMaxNum &= (1 << --dum); dc390_updateDCBs (pACB); + // All devs should be INQUIRED now + if (pos == p1) goto einv; } if (pos) goto next; @@ -2347,7 +2737,15 @@ int dc390_set_info (char *buffer, int length, PACB pACB) DC390_UNLOCK_IO; }; return (length); - + + dump: + { + dc390_dumpinfo (pACB, 0, 0); + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; + } + return (length); + inquiry: { pos = strtok (0, " \t\n.:;="); if (!pos) goto einv; @@ -2355,7 +2753,7 @@ int dc390_set_info (char *buffer, int length, PACB pACB) if (dev >= pACB->DCBCnt) goto einv_dev; for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB; printk (KERN_NOTICE " DC390: Issue INQUIRY command to Dev(Idx) %i SCSI ID %i LUN %i\n", - dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + dev, pDCB->TargetID, pDCB->TargetLUN); DC390_UNLOCK_ACB; dc390_inquiry (pACB, pDCB); DC390_UNLOCK_IO; @@ -2369,13 +2767,45 @@ int dc390_set_info (char *buffer, int length, PACB pACB) if (dev >= pACB->DCBCnt) goto einv_dev; for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB; printk (KERN_NOTICE " DC390: Remove DCB for Dev(Idx) %i SCSI ID %i LUN %i\n", - dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + dev, pDCB->TargetID, pDCB->TargetLUN); + /* TO DO: We should make sure no pending commands are left */ dc390_remove_dev (pACB, pDCB); DC390_UNLOCK_ACB; DC390_UNLOCK_IO; }; return (length); + add: + { + int id, lun; + pos = strtok (0, " \t\n.:;="); + if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv; + if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv; + pDCB = dc390_findDCB (pACB, id, lun); + if (pDCB) { printk ("DC390: ADD: Device already existing\n"); goto einv; }; + dc390_initDCB (pACB, &pDCB, id, lun); + DC390_UNLOCK_ACB; + dc390_inquiry (pACB, pDCB); + DC390_UNLOCK_IO; + }; + return (length); + + start: + { + int id, lun; + pos = strtok (0, " \t\n.:;="); + if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv; + if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv; + pDCB = dc390_findDCB (pACB, id, lun); + if (pDCB) printk ("DC390: SendStart: Device already existing ...\n"); + else dc390_initDCB (pACB, &pDCB, id, lun); + DC390_UNLOCK_ACB; + dc390_sendstart (pACB, pDCB); + dc390_inquiry (pACB, pDCB); + DC390_UNLOCK_IO; + }; + return (length); + einv_dev: printk (KERN_WARNING "DC390: Ignore cmnd to illegal Dev(Idx) %i. Valid range: 0 - %i.\n", dev, pACB->DCBCnt - 1); @@ -2425,6 +2855,7 @@ int DC390_proc_info (char *buffer, char **start, PSH shpnt; PACB pACB; PDCB pDCB; + PSCSICMD pcmd; DC390_AFLAGS pACB = dc390_pACB_start; @@ -2450,46 +2881,87 @@ int DC390_proc_info (char *buffer, char **start, SPRINTF("SCSI Host Nr %i, ", shpnt->host_no); SPRINTF("%s Adapter Nr %i\n", dc390_adapname, pACB->AdapterIndex); SPRINTF("IOPortBase 0x%04x, ", pACB->IOPortBase); - SPRINTF("IRQLevel 0x%02x\n", pACB->IRQLevel); + SPRINTF("IRQ %02i\n", pACB->IRQLevel); SPRINTF("MaxID %i, MaxLUN %i, ", shpnt->max_id, shpnt->max_lun); - SPRINTF("AdapterID %i, SelTimeout %i ms\n", - shpnt->this_id, (pACB->sel_timeout*164)/100); + SPRINTF("AdapterID %i, SelTimeout %i ms, DelayReset %i s\n", + shpnt->this_id, (pACB->sel_timeout*164)/100, + dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]); - SPRINTF("TagMaxNum %i, Status %i, ACBFlag %i, GlitchEater %i ns\n", + SPRINTF("TagMaxNum %i, Status 0x%02x, ACBFlag 0x%02x, GlitchEater %i ns\n", pACB->TagMaxNum, pACB->status, pACB->ACBFlag, GLITCH_TO_NS(pACB->glitch_cfg)*12); - SPRINTF("Statistics: Cmnds %li, Cmnds not sent directly %li, Out of SRB conds %li\n", + SPRINTF("Statistics: Cmnds %li, Cmnds not sent directly %i, Out of SRB conds %i\n", pACB->Cmds, pACB->CmdInQ, pACB->CmdOutOfSRB); - SPRINTF(" Lost arbitrations %li\n", pACB->SelLost); + SPRINTF(" Lost arbitrations %i, Sel. connected %i, Connected: %s\n", + pACB->SelLost, pACB->SelConn, pACB->Connected? "Yes": "No"); SPRINTF("Nr of attached devices: %i, Nr of DCBs: %i\n", pACB->DeviceCnt, pACB->DCBCnt); + SPRINTF("Map of attached LUNs: %02x %02x %02x %02x %02x %02x %02x %02x\n", + pACB->DCBmap[0], pACB->DCBmap[1], pACB->DCBmap[2], pACB->DCBmap[3], + pACB->DCBmap[4], pACB->DCBmap[5], pACB->DCBmap[6], pACB->DCBmap[7]); - SPRINTF("Idx ID LUN Prty Sync DsCn SndS TagQ STOP NegoPeriod SyncSpeed SyncOffs\n"); + SPRINTF("Idx ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs MaxCmd\n"); pDCB = pACB->pLinkDCB; for (dev = 0; dev < pACB->DCBCnt; dev++) { - SPRINTF("%02i %02i %02i ", dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + SPRINTF("%02i %02i %02i ", dev, pDCB->TargetID, pDCB->TargetLUN); YESNO(pDCB->DevMode & PARITY_CHK_); YESNO(pDCB->SyncMode & SYNC_NEGO_DONE); YESNO(pDCB->DevMode & EN_DISCONNECT_); - //YESNO(pDCB->SyncMode & EN_ATN_STOP); YESNO(pDCB->DevMode & SEND_START_); YESNO(pDCB->SyncMode & EN_TAG_QUEUEING); - YESNO(pDCB->SyncMode & EN_ATN_STOP); if (pDCB->SyncOffset & 0x0f) { int sp = pDCB->SyncPeriod; if (! (pDCB->CtrlR3 & FAST_SCSI)) sp++; SPRINTF(" %03i ns ", (pDCB->NegoPeriod) << 2); spd = 40/(sp); spd1 = 40%(sp); spd1 = (spd1 * 10 + sp/2) / (sp); - SPRINTF(" %2i.%1i M %02i\n", spd, spd1, (pDCB->SyncOffset & 0x0f)); + SPRINTF(" %2i.%1i M %02i", spd, spd1, (pDCB->SyncOffset & 0x0f)); } - else SPRINTF(" (%03i ns)\n", (pDCB->NegoPeriod) << 2); + else SPRINTF(" (%03i ns) ", (pDCB->NegoPeriod) << 2); /* Add more info ...*/ + SPRINTF (" %02i\n", pDCB->MaxCommand); pDCB = pDCB->pNextDCB; } + SPRINTF ("Commands in Queues: Query: %li:", pACB->QueryCnt); + for (pcmd = pACB->pQueryHead; pcmd; pcmd = pcmd->next) + SPRINTF (" %li", pcmd->pid); + if (timer_pending(&pACB->Waiting_Timer)) SPRINTF ("Waiting queue timer running\n"); + else SPRINTF ("\n"); + pDCB = pACB->pLinkDCB; + + for (dev = 0; dev < pACB->DCBCnt; dev++) + { + PSRB pSRB; + if (pDCB->WaitSRBCnt) + SPRINTF ("DCB (%02i-%i): Waiting: %i:", pDCB->TargetID, pDCB->TargetLUN, + pDCB->WaitSRBCnt); + for (pSRB = pDCB->pWaitingSRB; pSRB; pSRB = pSRB->pNextSRB) + SPRINTF(" %li", pSRB->pcmd->pid); + if (pDCB->GoingSRBCnt) + SPRINTF ("\nDCB (%02i-%i): Going : %i:", pDCB->TargetID, pDCB->TargetLUN, + pDCB->GoingSRBCnt); + for (pSRB = pDCB->pGoingSRB; pSRB; pSRB = pSRB->pNextSRB) +#if 0 //def DC390_DEBUGTRACE + SPRINTF(" %s\n ", pSRB->debugtrace); +#else + SPRINTF(" %li", pSRB->pcmd->pid); +#endif + if (pDCB->WaitSRBCnt || pDCB->GoingSRBCnt) SPRINTF ("\n"); + pDCB = pDCB->pNextDCB; + } + +#ifdef DC390_DEBUGDCB + SPRINTF ("DCB list for ACB %p:\n", pACB); + pDCB = pACB->pLinkDCB; + SPRINTF ("%p", pDCB); + for (dev = 0; dev < pACB->DCBCnt; dev++, pDCB=pDCB->pNextDCB) + SPRINTF ("->%p", pDCB->pNextDCB); + SPRINTF("\n"); +#endif + DC390_UNLOCK_ACB; *start = buffer + offset; @@ -2524,13 +2996,14 @@ static int dc390_shutdown (struct Scsi_Host *host) printk(KERN_INFO "DC390: shutdown\n"); - pACB->ACBFlag = RESET_DONE; + pACB->ACBFlag = RESET_DEV; bval = DC390_read8 (CtrlReg1); bval |= DIS_INT_ON_SCSI_RST; DC390_write8 (CtrlReg1, bval); /* disable interrupt */ if (pACB->Gmode2 & RST_SCSI_BUS) dc390_ResetSCSIBus (pACB); + if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer); return( 0 ); } @@ -2544,41 +3017,30 @@ void dc390_freeDCBs (struct Scsi_Host *host) do { nDCB = pDCB->pNextDCB; - DCBDEBUG(printk (KERN_INFO "DC390: Free DCB (ID %i, LUN %i): 0x%08x\n",\ - pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB);) - kfree (pDCB); + DCBDEBUG(printk (KERN_INFO "DC390: Free DCB (ID %i, LUN %i): %p\n",\ + pDCB->TargetID, pDCB->TargetLUN, pDCB);) + //kfree (pDCB); + dc390_remove_dev (pACB, pDCB); pDCB = nDCB; - } while (pDCB && pDCB != pACB->pLinkDCB); + } while (pDCB && pACB->pLinkDCB); }; -int DC390_release(struct Scsi_Host *host) +int DC390_release (struct Scsi_Host *host) { - int irq_count; - PACB pACB; DC390_AFLAGS DC390_IFLAGS -#if USE_SPINLOCKS > 1 PACB pACB = (PACB)(host->hostdata); -#endif DC390_LOCK_IO; DC390_LOCK_ACB; + /* TO DO: We should check for outstanding commands first. */ dc390_shutdown (host); if (host->irq != IRQ_NONE) { - for (irq_count = 0, pACB = dc390_pACB_start; - pACB; pACB = pACB->pNextACB) - { - if ( pACB->IRQLevel == host->irq ) - ++irq_count; - } - if (irq_count == 1) - { - DEBUG0(printk(KERN_INFO "DC390: Free IRQ %i\n",host->irq);) - free_irq(host->irq,NULL); - } + DEBUG0(printk(KERN_INFO "DC390: Free IRQ %i\n",host->irq);) + free_irq (host->irq, pACB); } release_region(host->io_port,host->n_io_port); @@ -2587,8 +3049,12 @@ int DC390_release(struct Scsi_Host *host) DC390_UNLOCK_IO; return( 1 ); } +#endif /* def MODULE */ -#endif - +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,99) static Scsi_Host_Template driver_template = DC390_T; #include "scsi_module.c" +#elif defined(MODULE) +Scsi_Host_Template driver_template = DC390_T; +#include "scsi_module.c" +#endif diff --git a/drivers/scsi/tmscsim.h b/drivers/scsi/tmscsim.h index c824bf0d0..09a4cd9da 100644 --- a/drivers/scsi/tmscsim.h +++ b/drivers/scsi/tmscsim.h @@ -3,35 +3,47 @@ ;* TEKRAM DC-390(T) PCI SCSI Bus Master Host Adapter * ;* Device Driver * ;***********************************************************************/ -/* $Id: tmscsim.h,v 2.4 1998/12/25 17:33:27 garloff Exp $ */ +/* $Id: tmscsim.h,v 2.15.2.3 2000/11/17 20:52:27 garloff Exp $ */ #ifndef _TMSCSIM_H #define _TMSCSIM_H +#include #include +/* 2.0 compat */ +#if defined(__SMP__) && !defined(CONFIG_SMP) +# if LINUX_VERSION_CODE < KERNEL_VERSION (2,2,0) +# define CONFIG_SMP +# else +# error __SMP__ defined but not CONFIG_SMP +# endif +#endif + #define IRQ_NONE 255 #define MAX_ADAPTER_NUM 4 -#define MAX_SG_LIST_BUF 16 -#define MAX_CMD_PER_LUN 8 -#define MAX_CMD_QUEUE 2*MAX_CMD_PER_LUN+1 +#define MAX_SG_LIST_BUF 16 /* Not used */ +#define MAX_CMD_PER_LUN 32 +#define MAX_CMD_QUEUE MAX_CMD_PER_LUN+MAX_CMD_PER_LUN/2+1 #define MAX_SCSI_ID 8 #define MAX_SRB_CNT MAX_CMD_QUEUE+1 /* Max number of started commands */ -#define END_SCAN 2 #define SEL_TIMEOUT 153 /* 250 ms selection timeout (@ 40 MHz) */ -typedef unsigned char UCHAR; -typedef unsigned short USHORT; -typedef unsigned long ULONG; -typedef unsigned int UINT; +#define END_SCAN 2 + +typedef u8 UCHAR; /* 8 bits */ +typedef u16 USHORT; /* 16 bits */ +typedef u32 UINT; /* 32 bits */ +typedef unsigned long ULONG; /* 32/64 bits */ typedef UCHAR *PUCHAR; typedef USHORT *PUSHORT; +typedef UINT *PUINT; typedef ULONG *PULONG; -typedef Scsi_Host_Template *PSHT; -typedef struct Scsi_Host *PSH; +typedef Scsi_Host_Template *PSHT; +typedef struct Scsi_Host *PSH; typedef Scsi_Device *PSCSIDEV; typedef Scsi_Cmnd *PSCSICMD; typedef void *PVOID; @@ -74,48 +86,49 @@ ULONG SGXPtr; */ struct _SRB { -UCHAR CmdBlock[12]; +//UCHAR CmdBlock[12]; struct _SRB *pNextSRB; struct _DCB *pSRBDCB; PSCSICMD pcmd; PSGL pSegmentList; -ULONG Segment0[2]; -ULONG Segment1[2]; +/* 0x10: */ +SGL Segmentx; /* make a one entry of S/G list table */ -/* 0x2c:*/ -ULONG TotalXferredLen; +/* 0x1c: */ ULONG SGBusAddr; /*;a segment starting address as seen by AM53C974A*/ ULONG SGToBeXferLen; /*; to be xfer length */ -ULONG SRBState; - -/* 0x3c: */ -UCHAR MsgInBuf[6]; -UCHAR MsgOutBuf[6]; - -/* 0x48: */ -SGL Segmentx; /* make a one entry of S/G list table */ - -UCHAR ScsiCmdLen; -UCHAR ScsiPhase; +ULONG TotalXferredLen; +ULONG SavedTotXLen; +UINT SRBState; +/* 0x30: */ +UCHAR SRBStatus; +UCHAR SRBFlag; /*; b0-AutoReqSense,b6-Read,b7-write */ + /*; b4-settimeout,b5-Residual valid */ UCHAR AdaptStatus; UCHAR TargetStatus; -/* 0x58: */ +UCHAR ScsiPhase; +UCHAR TagNumber; +UCHAR SGIndex; +UCHAR SGcount; + +/* 0x38: */ UCHAR MsgCnt; UCHAR EndMessage; UCHAR RetryCnt; -UCHAR SRBFlag; /*; b0-AutoReqSense,b6-Read,b7-write */ - /*; b4-settimeout,b5-Residual valid */ -UCHAR TagNumber; -UCHAR SGcount; -UCHAR SGIndex; -UCHAR SRBStatus; - //UCHAR IORBFlag; /*;81h-Reset, 2-retry */ +UCHAR SavedSGCount; + +ULONG Saved_Ptr; + +/* 0x40: */ +UCHAR MsgInBuf[6]; +UCHAR MsgOutBuf[6]; -/* 0x60: */ +//UCHAR IORBFlag; /*;81h-Reset, 2-retry */ +/* 0x4c: */ }; @@ -131,48 +144,47 @@ struct _DCB struct _DCB *pNextDCB; struct _ACB *pDCBACB; -PSCSICMD pQIORBhead; -PSCSICMD pQIORBtail; -PSCSICMD AboIORBhead; -PSCSICMD AboIORBtail; -ULONG QIORBCnt; -ULONG AboIORBcnt; +/* Aborted Commands */ +//PSCSICMD AboIORBhead; +//PSCSICMD AboIORBtail; +//ULONG AboIORBcnt; -/* 0x20: */ +/* 0x08: */ +/* Queued SRBs */ PSRB pWaitingSRB; PSRB pWaitLast; PSRB pGoingSRB; PSRB pGoingLast; PSRB pActiveSRB; +UCHAR WaitSRBCnt; /* Not used */ UCHAR GoingSRBCnt; -UCHAR WaitSRBCnt; /* ??? */ + UCHAR DevType; UCHAR MaxCommand; -/* 0x38: */ -ULONG TagMask; +/* 0x20: */ +UINT TagMask; -UCHAR UnitSCSIID; /*; SCSI Target ID (SCSI Only) */ -UCHAR UnitSCSILUN; /*; SCSI Log. Unit (SCSI Only) */ +UCHAR TargetID; /*; SCSI Target ID (SCSI Only) */ +UCHAR TargetLUN; /*; SCSI Log. Unit (SCSI Only) */ UCHAR DevMode; -UCHAR IdentifyMsg; +UCHAR DCBFlag; UCHAR CtrlR1; UCHAR CtrlR3; UCHAR CtrlR4; +UCHAR Inquiry7; -UCHAR DCBFlag; - -/* 0x44: */ +/* 0x2c: */ UCHAR SyncMode; /*; 0:async mode */ UCHAR NegoPeriod; /*;for nego. */ UCHAR SyncPeriod; /*;for reg. */ UCHAR SyncOffset; /*;for reg. and nego.(low nibble) */ -/* 0x48:*/ +/* 0x30:*/ //UCHAR InqDataBuf[8]; //UCHAR CapacityBuf[8]; -/* 0x58: */ +///* 0x40: */ }; typedef struct _DCB DC390_DCB, *PDCB; @@ -203,15 +215,23 @@ UCHAR scan_devices; PDCB pLinkDCB; PDCB pLastDCB; PDCB pDCBRunRobin; + PDCB pActiveDCB; PSRB pFreeSRB; PSRB pTmpSRB; /* 0x2c: */ +ULONG QueryCnt; +PSCSICMD pQueryHead; +PSCSICMD pQueryTail; +/* 0x38: */ UCHAR msgin123[4]; UCHAR DCBmap[MAX_SCSI_ID]; +UCHAR Connected; +UCHAR pad; +/* 0x3c: */ #if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(CONFIG_SMP) || DEBUG_SPINLOCKS > 0) spinlock_t lock; #endif @@ -222,18 +242,20 @@ UCHAR MsgLen; UCHAR Ignore_IRQ; /* Not used */ PDEVDECL1; /* Pointer to PCI cfg. space */ -/* 0x40/0x3c: */ +/* 0x4c/0x48: */ ULONG Cmds; -ULONG CmdInQ; -ULONG CmdOutOfSRB; -ULONG SelLost; - +UINT SelLost; +UINT SelConn; +UINT CmdInQ; +UINT CmdOutOfSRB; -/* 0x50/0x4c: */ +/* 0x60/0x5c: */ +struct timer_list Waiting_Timer; +/* 0x74/0x70: */ DC390_SRB TmpSRB; -/* 0xb4/0xb0: */ -DC390_SRB SRB_array[MAX_SRB_CNT]; /* 18 SRBs */ -/* 0x7bc/0x7b8: */ +/* 0xd8/0xd4: */ +DC390_SRB SRB_array[MAX_SRB_CNT]; /* 50 SRBs */ +/* 0xfb0/0xfac: */ }; typedef struct _ACB DC390_ACB, *PACB; @@ -341,21 +363,29 @@ typedef struct _ACB DC390_ACB, *PACB; #define H_BAD_CCB_OR_SG 0x1A #define H_ABORT 0x0FF -/*; SCSI Status byte codes*/ /* Twice the values defined in scsi/scsi.h */ -#define SCSI_STAT_GOOD 0x0 /*; Good status */ -#define SCSI_STAT_CHECKCOND 0x02 /*; SCSI Check Condition */ -#define SCSI_STAT_CONDMET 0x04 /*; Condition Met */ -#define SCSI_STAT_BUSY 0x08 /*; Target busy status */ -#define SCSI_STAT_INTER 0x10 /*; Intermediate status */ -#define SCSI_STAT_INTERCONDMET 0x14 /*; Intermediate condition met */ -#define SCSI_STAT_RESCONFLICT 0x18 /*; Reservation conflict */ -#define SCSI_STAT_CMDTERM 0x22 /*; Command Terminated */ -#define SCSI_STAT_QUEUEFULL 0x28 /*; Queue Full */ +/*; SCSI Status byte codes*/ +/* The values defined in include/scsi/scsi.h, to be shifted << 1 */ #define SCSI_STAT_UNEXP_BUS_F 0xFD /*; Unexpect Bus Free */ #define SCSI_STAT_BUS_RST_DETECT 0xFE /*; Scsi Bus Reset detected */ #define SCSI_STAT_SEL_TIMEOUT 0xFF /*; Selection Time out */ +/* cmd->result */ +#define RES_TARGET 0x000000FF /* Target State */ +#define RES_TARGET_LNX STATUS_MASK /* Only official ... */ +#define RES_ENDMSG 0x0000FF00 /* End Message */ +#define RES_DID 0x00FF0000 /* DID_ codes */ +#define RES_DRV 0xFF000000 /* DRIVER_ codes */ + +#define MK_RES(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt)) +#define MK_RES_LNX(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt)<<1) + +#define SET_RES_TARGET(who,tgt) { who &= ~RES_TARGET; who |= (int)(tgt); } +#define SET_RES_TARGET_LNX(who,tgt) { who &= ~RES_TARGET_LNX; who |= (int)(tgt) << 1; } +#define SET_RES_MSG(who,msg) { who &= ~RES_ENDMSG; who |= (int)(msg) << 8; } +#define SET_RES_DID(who,did) { who &= ~RES_DID; who |= (int)(did) << 16; } +#define SET_RES_DRV(who,drv) { who &= ~RES_DRV; who |= (int)(drv) << 24; } + /*;---Sync_Mode */ #define SYNC_DISABLE 0 #define SYNC_ENABLE BIT0 @@ -377,31 +407,8 @@ typedef struct _ACB DC390_ACB, *PACB; #define SCSI_MSG_OUT 6 #define SCSI_MSG_IN 7 -/*;----SCSI MSG BYTE*/ /* see scsi/scsi.h */ -#define MSG_COMPLETE 0x00 -#define MSG_EXTENDED 0x01 -#define MSG_SAVE_PTR 0x02 -#define MSG_RESTORE_PTR 0x03 -#define MSG_DISCONNECT 0x04 -#define MSG_INITIATOR_ERROR 0x05 -#define MSG_ABORT 0x06 -#define MSG_REJECT_ 0x07 -#define MSG_NOP 0x08 -#define MSG_PARITY_ERROR 0x09 -#define MSG_LINK_CMD_COMPL 0x0A -#define MSG_LINK_CMD_COMPL_FLG 0x0B -#define MSG_BUS_RESET 0x0C -#define MSG_ABORT_TAG 0x0D -#define MSG_SIMPLE_QTAG 0x20 -#define MSG_HEAD_QTAG 0x21 -#define MSG_ORDER_QTAG 0x22 -#define MSG_IDENTIFY 0x80 -#define MSG_HOST_ID 0x0C0 - -/* cmd->result */ -#define STATUS_MASK_ 0xFF -#define MSG_MASK 0xFF00 -#define RETURN_MASK 0xFF0000 +/*;----SCSI MSG BYTE*/ /* see scsi/scsi.h */ /* One is missing ! */ +#define ABORT_TAG 0x0d /* ** Inquiry Data format @@ -441,7 +448,12 @@ typedef struct _SCSIInqData { /* INQUIRY */ /* Peripheral Device Type definitions */ /* see include/scsi/scsi.h for the rest */ -#define TYPE_PRINTER 0x02 /* Printer device */ +#ifndef TYPE_PRINTER +# define TYPE_PRINTER 0x02 /* Printer device */ +#endif +#ifndef TYPE_COMM +# define TYPE_COMM 0x09 /* Communications device */ +#endif /* ** Inquiry flag definitions (Inq data byte 7) diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c index e6846f887..782bb46f1 100644 --- a/drivers/sound/sb_card.c +++ b/drivers/sound/sb_card.c @@ -50,6 +50,9 @@ * * 21-09-2000 Got rid of attach_sbmpu * Arnaldo Carvalho de Melo + * + * 28-10-2000 Added pnplegacy support + * Daniel Church */ #include @@ -64,7 +67,7 @@ #include "sb.h" #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE -#define SB_CARDS_MAX 4 +#define SB_CARDS_MAX 5 #else #define SB_CARDS_MAX 1 #endif @@ -194,6 +197,7 @@ struct pci_dev *sb_dev[SB_CARDS_MAX] = {NULL}, static int isapnp = 1; static int isapnpjump = 0; static int multiple = 1; +static int pnplegacy = 0; static int reverse = 0; static int uart401 = 0; @@ -203,6 +207,7 @@ static int opl_activated[SB_CARDS_MAX] = {0}; #else static int isapnp = 0; static int multiple = 0; +static int pnplegacy = 0; #endif MODULE_DESCRIPTION("Soundblaster driver"); @@ -221,11 +226,13 @@ MODULE_PARM(acer, "i"); MODULE_PARM(isapnp, "i"); MODULE_PARM(isapnpjump, "i"); MODULE_PARM(multiple, "i"); +MODULE_PARM(pnplegacy, "i"); MODULE_PARM(reverse, "i"); MODULE_PARM(uart401, "i"); MODULE_PARM_DESC(isapnp, "When set to 0, Plug & Play support will be disabled"); MODULE_PARM_DESC(isapnpjump, "Jumps to a specific slot in the driver's PnP table. Use the source, Luke."); MODULE_PARM_DESC(multiple, "When set to 0, will not search for multiple cards"); +MODULE_PARM_DESC(pnplegacy, "When set to 1, will search for a legacy SB card along with any PnP cards."); MODULE_PARM_DESC(reverse, "When set to 1, will reverse ISAPnP search order"); MODULE_PARM_DESC(uart401, "When set to 1, will attempt to detect and enable the mpu on some clones"); #endif @@ -659,7 +666,7 @@ static int __init init_sb(void) /* Please remember that even with CONFIG_ISAPNP defined one * should still be able to disable PNP support for this * single driver! */ - if(isapnp && (sb_isapnp_probe(&cfg[card], &cfg_mpu[card], card) < 0) ) { + if((!pnplegacy||card>0) && isapnp && (sb_isapnp_probe(&cfg[card], &cfg_mpu[card], card) < 0) ) { if(!sb_cards_num) { /* Found no ISAPnP cards, so check for a non-pnp * card and set the detection loop for 1 cycle @@ -674,7 +681,7 @@ static int __init init_sb(void) } #endif - if(!isapnp) { + if(!isapnp || (pnplegacy&&card==0)) { cfg[card].io_base = io; cfg[card].irq = irq; cfg[card].dma = dma; @@ -695,15 +702,29 @@ static int __init init_sb(void) card--; sb_cards_num--; continue; + } else if(pnplegacy && isapnp) { + printk(KERN_NOTICE "sb: No legacy SoundBlaster cards " \ + "found. Continuing with PnP detection.\n"); + pnplegacy=0; + card--; + continue; } else return -ENODEV; } attach_sb_card(&cfg[card]); - if(cfg[card].slots[0]==-1) - return -ENODEV; + if(cfg[card].slots[0]==-1) { + if(card==0 && pnplegacy && isapnp) { + printk(KERN_NOTICE "sb: No legacy SoundBlaster cards " \ + "found. Continuing with PnP detection.\n"); + pnplegacy=0; + card--; + continue; + } else + return -ENODEV; + } - if (!isapnp) + if (!isapnp||(pnplegacy&&card==0)) cfg_mpu[card].io_base = mpu_io; if (probe_sbmpu(&cfg_mpu[card], THIS_MODULE)) sbmpu[card] = 1; diff --git a/drivers/sound/wavfront.c b/drivers/sound/wavfront.c index 521f2045a..8e8106917 100644 --- a/drivers/sound/wavfront.c +++ b/drivers/sound/wavfront.c @@ -92,14 +92,14 @@ #if defined(__alpha__) #ifdef CONFIG_SMP -#define LOOPS_PER_SEC cpu_data[smp_processor_id()].loops_per_sec +#define LOOPS_PER_TICK cpu_data[smp_processor_id()].loops_per_jiffy #else -#define LOOPS_PER_SEC loops_per_sec +#define LOOPS_PER_TICK loops_per_sec #endif #endif #if defined(__i386__) -#define LOOPS_PER_SEC current_cpu_data.loops_per_sec +#define LOOPS_PER_TICK current_cpu_data.loops_per_jiffy #endif #define _MIDI_SYNTH_C_ @@ -460,7 +460,7 @@ wavefront_wait (int mask) if (short_loop_cnt == 0) { short_loop_cnt = wait_usecs * - (LOOPS_PER_SEC / 1000000); + (LOOPS_PER_TICK / (1000000 / HZ)); } /* Spin for a short period of time, because >99% of all diff --git a/drivers/sound/ymf_sb.c b/drivers/sound/ymf_sb.c index 26a062a8f..37a5d917a 100644 --- a/drivers/sound/ymf_sb.c +++ b/drivers/sound/ymf_sb.c @@ -43,10 +43,6 @@ Thu Sep 21 05:32:51 BRT 2000 0.0.5 * got rid of attach_uart401 and attach_sbmpu Arnaldo Carvalho de Melo - - Fri Nov 10 21:24:11 CET 2000 0.0.6 - * added some __init and __initdata to entries in 724hwmcode.h - Bartlomiej Zolnierkiewicz */ #include @@ -436,7 +432,7 @@ static int __init setupLegacyIO( struct pci_dev *pcidev ) printk(PFX "set DMA address at 0x%x\n",sb_data[cards].dma); #endif - v = 0x0000 | ((dma<<6)&0x03) | 0x003f; + v = 0x0000 | ((dma & 0x03) << 6) | 0x003f; pci_write_config_word(pcidev, YMFSB_PCIR_LEGCTRL, v); #ifdef YMF_DEBUG printk(PFX "LEGCTRL: 0x%x\n",v); @@ -446,7 +442,9 @@ static int __init setupLegacyIO( struct pci_dev *pcidev ) case PCI_DEVICE_ID_YMF740: case PCI_DEVICE_ID_YMF724F: case PCI_DEVICE_ID_YMF740C: - v = 0x8800 | ((mpuio<<4)&0x03) | ((sbio<<2)&0x03) | (oplio&0x03); + v = 0x8800 | ((mpuio & 0x03) << 4) + | ((sbio & 0x03) << 2) + | (oplio & 0x03); pci_write_config_word(pcidev, YMFSB_PCIR_ELEGCTRL, v); #ifdef YMF_DEBUG printk(PFX "ELEGCTRL: 0x%x\n",v); @@ -843,6 +841,7 @@ static void __exit cleanup_ymf7xxsb_module(void) } free_iomaps(); + pci_unregister_driver(&ymf7xxsb_driver); } diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c index fad7e48f6..1f531fd6b 100644 --- a/drivers/usb/usb.c +++ b/drivers/usb/usb.c @@ -73,6 +73,15 @@ static struct usb_busmap busmap; static struct usb_driver *usb_minors[16]; +/** + * usb_register - register a USB driver + * @new_driver: USB operations for the driver + * + * Registers a USB driver with the USB core. The list of unattached + * interfaces will be rescanned whenever a new driver is added, allowing + * the new driver to attach to any recognized devices. + * Returns a negative error code on failure and 0 on success. + */ int usb_register(struct usb_driver *new_driver) { if (new_driver->fops != NULL) { @@ -95,12 +104,14 @@ int usb_register(struct usb_driver *new_driver) return 0; } -/* - * We go through all existing devices, and see if any of them would - * be acceptable to the new driver.. This is done using a depth-first - * search for devices without a registered driver already, then - * running 'probe' with each of the drivers registered on every one - * of these. +/** + * usb_scan_devices - scans all unclaimed USB interfaces + * + * Goes through all unclaimed USB interfaces, and offers them to all + * registered USB drivers through the 'probe' function. + * This will automatically be called after usb_register is called. + * It is called by some of the USB subsystems after one of their subdrivers + * are registered. */ void usb_scan_devices(void) { @@ -152,8 +163,11 @@ static void usb_drivers_purge(struct usb_driver *driver,struct usb_device *dev) } } -/* - * Unlink a driver from the driver list when it is unloaded +/** + * usb_deregister - unregister a USB driver + * @driver: USB operations of the driver to unregister + * + * Unlinks the specified driver from the internal USB driver list. */ void usb_deregister(struct usb_driver *driver) { @@ -329,8 +343,16 @@ void usb_release_bandwidth(struct usb_device *dev, struct urb *urb, int isoc) urb->bandwidth = 0; } -/* - * New functions for (de)registering a controller +/** + * usb_alloc_bus - creates a new USB host controller structure + * @op: pointer to a struct usb_operations that this bus structure should use + * + * Creates a USB host controller bus structure with the specified + * usb_operations and initializes all the necessary internal objects. + * + * If no memory is available, NULL is returned. + * + * The caller should call usb_free_bus() when it is finished with the structure. */ struct usb_bus *usb_alloc_bus(struct usb_operations *op) { @@ -356,6 +378,11 @@ struct usb_bus *usb_alloc_bus(struct usb_operations *op) return bus; } +/** + * usb_free_bus - frees the memory used by a bus structure + * @bus: pointer to the bus to free + * + */ void usb_free_bus(struct usb_bus *bus) { if (!bus) @@ -364,6 +391,11 @@ void usb_free_bus(struct usb_bus *bus) kfree(bus); } +/** + * usb_register_bus - registers the USB host controller with the usb core + * @bus: pointer to the bus to register + * + */ void usb_register_bus(struct usb_bus *bus) { int busnum; @@ -875,6 +907,18 @@ void usb_inc_dev_use(struct usb_device *dev) * New USB Core Functions * -------------------------------------------------------------------------------------*/ +/** + * usb_alloc_urb - creates a new urb for a USB driver to use + * @iso_packets: number of iso packets for this urb + * + * Creates an urb for the USB driver to use and returns a pointer to it. + * If no memory is available, NULL is returned. + * + * If the driver want to use this urb for interrupt, control, or bulk + * endpoints, pass '0' as the number of iso packets. + * + * The driver should call usb_free_urb() when it is finished with the urb. + */ urb_t *usb_alloc_urb(int iso_packets) { urb_t *urb; @@ -893,7 +937,14 @@ urb_t *usb_alloc_urb(int iso_packets) return urb; } -/*-------------------------------------------------------------------*/ +/** + * usb_free_urb - frees the memory used by a urb + * @urb: pointer to the urb to free + * + * If an urb is created with a call to usb_create_urb() it should be + * cleaned up with a call to usb_free_urb() when the driver is finished + * with it. + */ void usb_free_urb(urb_t* urb) { if (urb) @@ -1010,12 +1061,27 @@ int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, } -/*-------------------------------------------------------------------*/ -/* usb_control_msg() - builds control urb, and waits for completion */ -/* Synchronous behavior - don't use this function from within an */ -/* interrupt context, (like a bottom half handler.) In this case, */ -/* use usb_submit_urb() directly instead. */ - +/** + * usb_control_msg - Builds a control urb, sends it off and waits for completion + * @dev: pointer to the usb device to send the message to + * @pipe: endpoint "pipe" to send the message to + * @request: USB message request value + * @requesttype: USB message request type value + * @value: USB message value + * @index: USB message index value + * @data: pointer to the data to send + * @size: length in bytes of the data to send + * @timeout: time to wait for the message to complete before timing out (if 0 the wait is forever) + * + * This function sends a simple control message to a specified endpoint + * and waits for the message to complete, or timeout. + * + * If successful, it returns 0, othwise a negative error number. + * + * Don't use this function from within an interrupt context, like a + * bottom half handler. If you need a asyncronous message, or need to send + * a message from within interrupt context, use usb_submit_urb() + */ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout) { @@ -1040,12 +1106,27 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u return ret; } -/*-------------------------------------------------------------------*/ -/* usb_bulk_msg() Builds a bulk urb, and waits for completion. */ -/* Synchronous behavior - don't use this function from within an */ -/* interrupt context, (like a bottom half handler.) In this case, */ -/* use usb_submit_urb() directly instead. */ +/** + * usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion + * @usb_dev: pointer to the usb device to send the message to + * @pipe: endpoint "pipe" to send the message to + * @data: pointer to the data to send + * @len: length in bytes of the data to send + * @actual_length: pointer to a location to put the actual length transfered in bytes + * @timeout: time to wait for the message to complete before timing out (if 0 the wait is forever) + * + * This function sends a simple bulk message to a specified endpoint + * and waits for the message to complete, or timeout. + * + * If successful, it returns 0, othwise a negative error number. + * The number of actual bytes transferred will be plaed in the + * actual_timeout paramater. + * + * Don't use this function from within an interrupt context, like a + * bottom half handler. If you need a asyncronous message, or need to + * send a message from within interrupt context, use usb_submit_urb() + */ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout) { diff --git a/fs/exec.c b/fs/exec.c index 757aa1263..36f3a8c6e 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -594,7 +594,6 @@ static inline int must_not_trace_exec(struct task_struct * p) int prepare_binprm(struct linux_binprm *bprm) { int mode; - int id_change,cap_raised; struct inode * inode = bprm->file->f_dentry->d_inode; mode = inode->i_mode; @@ -606,25 +605,20 @@ int prepare_binprm(struct linux_binprm *bprm) bprm->e_uid = current->euid; bprm->e_gid = current->egid; - id_change = cap_raised = 0; - /* Set-uid? */ - if (mode & S_ISUID) { - bprm->e_uid = inode->i_uid; - if (bprm->e_uid != current->euid) - id_change = 1; - } - - /* Set-gid? */ - /* - * If setgid is set but no group execute bit then this - * is a candidate for mandatory locking, not a setgid - * executable. - */ - if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { - bprm->e_gid = inode->i_gid; - if (!in_group_p(bprm->e_gid)) - id_change = 1; + if(!IS_NOSUID(inode)) { + /* Set-uid? */ + if (mode & S_ISUID) + bprm->e_uid = inode->i_uid; + + /* Set-gid? */ + /* + * If setgid is set but no group execute bit then this + * is a candidate for mandatory locking, not a setgid + * executable. + */ + if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) + bprm->e_gid = inode->i_gid; } /* We don't have VFS support for capabilities yet */ @@ -649,39 +643,6 @@ int prepare_binprm(struct linux_binprm *bprm) cap_set_full(bprm->cap_effective); } - /* Only if pP' is _not_ a subset of pP, do we consider there - * has been a capability related "change of capability". In - * such cases, we need to check that the elevation of - * privilege does not go against other system constraints. - * The new Permitted set is defined below -- see (***). */ - { - kernel_cap_t permitted, working; - - permitted = cap_intersect(bprm->cap_permitted, cap_bset); - working = cap_intersect(bprm->cap_inheritable, - current->cap_inheritable); - working = cap_combine(permitted, working); - if (!cap_issubset(working, current->cap_permitted)) { - cap_raised = 1; - } - } - - if (id_change || cap_raised) { - /* We can't suid-execute if we're sharing parts of the executable */ - /* or if we're being traced (or if suid execs are not allowed) */ - /* (current->mm->mm_users > 1 is ok, as we'll get a new mm anyway) */ - if (IS_NOSUID(inode) - || must_not_trace_exec(current) - || (atomic_read(¤t->fs->count) > 1) - || (atomic_read(¤t->sig->count) > 1) - || (atomic_read(¤t->files->count) > 1)) { - if (id_change && !capable(CAP_SETUID)) - return -EPERM; - if (cap_raised && !capable(CAP_SETPCAP)) - return -EPERM; - } - } - memset(bprm->buf,0,BINPRM_BUF_SIZE); return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE); } @@ -698,17 +659,41 @@ int prepare_binprm(struct linux_binprm *bprm) * * I=Inheritable, P=Permitted, E=Effective // p=process, f=file * ' indicates post-exec(), and X is the global 'cap_bset'. + * */ void compute_creds(struct linux_binprm *bprm) { kernel_cap_t new_permitted, working; + int do_unlock = 0; new_permitted = cap_intersect(bprm->cap_permitted, cap_bset); working = cap_intersect(bprm->cap_inheritable, current->cap_inheritable); new_permitted = cap_combine(new_permitted, working); + if (bprm->e_uid != current->uid || bprm->e_gid != current->gid || + !cap_issubset(new_permitted, current->cap_permitted)) { + current->dumpable = 0; + + lock_kernel(); + if (must_not_trace_exec(current) + || atomic_read(¤t->fs->count) > 1 + || atomic_read(¤t->files->count) > 1 + || atomic_read(¤t->sig->count) > 1) { + if(!capable(CAP_SETUID)) { + bprm->e_uid = current->uid; + bprm->e_gid = current->gid; + } + if(!capable(CAP_SETPCAP)) { + new_permitted = cap_intersect(new_permitted, + current->cap_permitted); + } + } + do_unlock = 1; + } + + /* For init, we want to retain the capabilities set * in the init_task struct. Thus we skip the usual * capability rules */ @@ -722,10 +707,9 @@ void compute_creds(struct linux_binprm *bprm) current->suid = current->euid = current->fsuid = bprm->e_uid; current->sgid = current->egid = current->fsgid = bprm->e_gid; - if (current->euid != current->uid || current->egid != current->gid || - !cap_issubset(new_permitted, current->cap_permitted)) - current->dumpable = 0; + if(do_unlock) + unlock_kernel(); current->keep_capabilities = 0; } diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 61ad8c2b2..f13260966 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -904,6 +904,12 @@ int fat_notify_change(struct dentry * dentry, struct iattr * attr) struct inode *inode = dentry->d_inode; int error; + /* FAT cannot truncate to a longer file */ + if (attr->ia_valid & ATTR_SIZE) { + if (attr->ia_size > inode->i_size) + return -EPERM; + } + error = inode_change_ok(inode, attr); if (error) return MSDOS_SB(sb)->options.quiet ? 0 : error; diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 9cee2ab15..0c6f1de62 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -123,8 +123,8 @@ char *disk_name (struct gendisk *hd, int minor, char *buf) maj = "hd"; break; case MD_MAJOR: - unit -= 'a'-'0'; - break; + sprintf(buf, "%s%d", maj, unit - 'a'); + return buf; } if (hd->major >= SCSI_DISK1_MAJOR && hd->major <= SCSI_DISK7_MAJOR) { unit = unit + (hd->major - SCSI_DISK1_MAJOR + 1) * 16; @@ -408,7 +408,7 @@ void register_disk(struct gendisk *gdev, kdev_t dev, unsigned minors, { if (!gdev) return; - grok_partitions(gdev, MINOR(dev)>>gdev->minor_shift, minors, size); + grok_partitions(gdev, MINOR(dev)>>gdev->minor_shift, minors, size); } void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size) diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index 1f4829709..35c6529be 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -442,10 +442,9 @@ static int vfat_valid_shortname(struct nls_table *nls, wchar_t *name, int len) space = 1; /* disallow names starting with a dot */ for (walk = name; len && walk-name < 8;) { len--; - if ( (chl = nls->uni2char(*walk, charbuf, NLS_MAX_CHARSET_SIZE)) < 0) { - walk++; + chl = nls->uni2char(*walk++, charbuf, NLS_MAX_CHARSET_SIZE); + if (chl < 0) return -EINVAL; - } for (chi = 0; chi < chl; chi++) { c = vfat_getupper(nls, charbuf[chi]); @@ -471,7 +470,7 @@ dot:; if (len >= 4) return -EINVAL; while (len > 0) { len--; - chl = vfat_uni2short(nls, *walk++, charbuf, NLS_MAX_CHARSET_SIZE); + chl = nls->uni2char(*walk++, charbuf, NLS_MAX_CHARSET_SIZE); if (chl < 0) return -EINVAL; for (chi = 0; chi < chl; chi++) { diff --git a/include/asm-i386/delay.h b/include/asm-i386/delay.h index 2166c4c6d..c7d218492 100644 --- a/include/asm-i386/delay.h +++ b/include/asm-i386/delay.h @@ -7,12 +7,14 @@ * Delay routines calling functions in arch/i386/lib/delay.c */ +extern void __bad_udelay(void); + extern void __udelay(unsigned long usecs); extern void __const_udelay(unsigned long usecs); extern void __delay(unsigned long loops); #define udelay(n) (__builtin_constant_p(n) ? \ - __const_udelay((n) * 0x10c6ul) : \ + ((n) > 20000 ? __bad_udelay() : __const_udelay((n) * 0x10c6ul)) : \ __udelay(n)) #endif /* defined(_I386_DELAY_H) */ diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index 364bb475f..21296d961 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -47,7 +47,7 @@ struct cpuinfo_x86 { int fdiv_bug; int f00f_bug; int coma_bug; - unsigned long loops_per_sec; + unsigned long loops_per_jiffy; unsigned long *pgd_quick; unsigned long *pmd_quick; unsigned long *pte_quick; diff --git a/include/linux/delay.h b/include/linux/delay.h index e1cf03d69..0454b786d 100644 --- a/include/linux/delay.h +++ b/include/linux/delay.h @@ -4,10 +4,10 @@ /* * Copyright (C) 1993 Linus Torvalds * - * Delay routines, using a pre-computed "loops_per_second" value. + * Delay routines, using a pre-computed "loops_per_jiffy" value. */ -extern unsigned long loops_per_sec; +extern unsigned long loops_per_jiffy; #include diff --git a/include/linux/dtlk.h b/include/linux/dtlk.h index 07a6b82bc..2896d9011 100644 --- a/include/linux/dtlk.h +++ b/include/linux/dtlk.h @@ -27,7 +27,7 @@ #define DTLK_CLEAR 0x18 /* stops speech */ -#define DTLK_MAX_RETRIES (loops_per_sec/10000) +#define DTLK_MAX_RETRIES (loops_per_jiffy/(10000/HZ)) /* TTS Port Status Flags */ #define TTS_READABLE 0x80 /* mask for bit which is nonzero if a diff --git a/include/linux/telephony.h b/include/linux/telephony.h index 3dd5a969a..4e38e8ccb 100644 --- a/include/linux/telephony.h +++ b/include/linux/telephony.h @@ -207,8 +207,8 @@ struct phone_codec_data * indicate the current state of the hookswitch. The pstn_ring bit * indicates that the DAA on a LineJACK card has detected ring voltage on * the PSTN port. The caller_id bit indicates that caller_id data has been -* recieved and is available. The pstn_wink bit indicates that the DAA on -* the LineJACK has recieved a wink from the telco switch. The f0, f1, f2 +* received and is available. The pstn_wink bit indicates that the DAA on +* the LineJACK has received a wink from the telco switch. The f0, f1, f2 * and f3 bits indicate that the filter has been triggered by detecting the * frequency programmed into that filter. * diff --git a/include/linux/tty.h b/include/linux/tty.h index 642c8bd7e..057cb57a6 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -305,6 +305,7 @@ struct tty_struct { unsigned long canon_head; unsigned int canon_column; struct semaphore atomic_read; + struct semaphore atomic_write; spinlock_t read_lock; }; diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h index 3f358258b..8d7a7764d 100644 --- a/include/linux/watchdog.h +++ b/include/linux/watchdog.h @@ -6,14 +6,17 @@ * */ +#ifndef _LINUX_WATCHDOG_H +#define _LINUX_WATCHDOG_H + #include #define WATCHDOG_IOCTL_BASE 'W' struct watchdog_info { - u32 options; /* Options the card/driver supports */ - u32 firmware_version; /* Firmware version of the card */ - u8 identity[32]; /* Identity of the board */ + __u32 options; /* Options the card/driver supports */ + __u32 firmware_version; /* Firmware version of the card */ + __u8 identity[32]; /* Identity of the board */ }; #define WDIOC_GETSUPPORT _IOR(WATCHDOG_IOCTL_BASE, 0, struct watchdog_info) @@ -38,3 +41,5 @@ struct watchdog_info { #define WDIOS_DISABLECARD 0x0001 /* Turn off the watchdog timer */ #define WDIOS_ENABLECARD 0x0002 /* Turn on the watchdog timer */ #define WDIOS_TEMPPANIC 0x0004 /* Kernel panic on temperature trip */ + +#endif /* ifndef _LINUX_WATCHDOG_H */ diff --git a/include/linux/wireless.h b/include/linux/wireless.h index 868f812ac..c552ff21b 100644 --- a/include/linux/wireless.h +++ b/include/linux/wireless.h @@ -63,7 +63,7 @@ * (there is some stuff that will be added in the future...) * I just plan to increment with each new version. */ -#define WIRELESS_EXT 9 +#define WIRELESS_EXT 10 /* * Changes : @@ -104,26 +104,33 @@ * - Change encoding to support larger tokens (>64 bits) * - Updated iw_params (disable, flags) and use it for NWID * - Extracted iw_point from iwreq for clarity + * + * V9 to V10 + * --------- + * - Add PM capability to range structure + * - Add PM modifier : MAX/MIN/RELATIVE + * - Add encoding option : IW_ENCODE_NOKEY + * - Add TxPower ioctls (work like TxRate) */ /* -------------------------- IOCTL LIST -------------------------- */ /* Basic operations */ -#define SIOCSIWNAME 0x8B00 /* Unused ??? */ -#define SIOCGIWNAME 0x8B01 /* get name */ +#define SIOCSIWNAME 0x8B00 /* Unused */ +#define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ #define SIOCSIWNWID 0x8B02 /* set network id (the cell) */ #define SIOCGIWNWID 0x8B03 /* get network id */ -#define SIOCSIWFREQ 0x8B04 /* set channel/frequency */ -#define SIOCGIWFREQ 0x8B05 /* get channel/frequency */ +#define SIOCSIWFREQ 0x8B04 /* set channel/frequency (Hz) */ +#define SIOCGIWFREQ 0x8B05 /* get channel/frequency (Hz) */ #define SIOCSIWMODE 0x8B06 /* set operation mode */ #define SIOCGIWMODE 0x8B07 /* get operation mode */ -#define SIOCSIWSENS 0x8B08 /* set sensitivity */ -#define SIOCGIWSENS 0x8B09 /* get sensitivity */ +#define SIOCSIWSENS 0x8B08 /* set sensitivity (dBm) */ +#define SIOCGIWSENS 0x8B09 /* get sensitivity (dBm) */ /* Informative stuff */ -#define SIOCSIWRANGE 0x8B0A /* Unused ??? */ +#define SIOCSIWRANGE 0x8B0A /* Unused */ #define SIOCGIWRANGE 0x8B0B /* Get range of parameters */ -#define SIOCSIWPRIV 0x8B0C /* Unused ??? */ +#define SIOCSIWPRIV 0x8B0C /* Unused */ #define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */ /* Mobile IP support */ @@ -153,6 +160,8 @@ #define SIOCGIWRTS 0x8B23 /* get RTS/CTS threshold (bytes) */ #define SIOCSIWFRAG 0x8B24 /* set fragmentation thr (bytes) */ #define SIOCGIWFRAG 0x8B25 /* get fragmentation thr (bytes) */ +#define SIOCSIWTXPOW 0x8B26 /* set transmit power (dBm) */ +#define SIOCGIWTXPOW 0x8B27 /* get transmit power (dBm) */ /* Encoding stuff (scrambling, hardware security, WEP...) */ #define SIOCSIWENCODE 0x8B2A /* set encoding token & mode */ @@ -205,6 +214,9 @@ /* Maximum bit rates in the range struct */ #define IW_MAX_BITRATES 8 +/* Maximum tx powers in the range struct */ +#define IW_MAX_TXPOWER 8 + /* Maximum of address that you may set with SPY */ #define IW_MAX_SPY 8 @@ -232,11 +244,13 @@ /* Flags for encoding (along with the token) */ #define IW_ENCODE_INDEX 0x00FF /* Token index (if needed) */ -#define IW_ENCODE_FLAGS 0xF000 /* Flags defined below */ +#define IW_ENCODE_FLAGS 0xFF00 /* Flags defined below */ +#define IW_ENCODE_MODE 0xF000 /* Modes defined below */ #define IW_ENCODE_DISABLED 0x8000 /* Encoding disabled */ #define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */ #define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */ #define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */ +#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ /* Power management flags available (along with the value, if any) */ #define IW_POWER_ON 0x0000 /* No details... */ @@ -249,6 +263,14 @@ #define IW_POWER_ALL_R 0x0300 /* Receive all messages though PM */ #define IW_POWER_FORCE_S 0x0400 /* Force PM procedure for sending unicast */ #define IW_POWER_REPEATER 0x0800 /* Repeat broadcast messages in PM period */ +#define IW_POWER_MODIFIER 0x000F /* Modify a parameter */ +#define IW_POWER_MIN 0x0001 /* Value is a minimum */ +#define IW_POWER_MAX 0x0002 /* Value is a maximum */ +#define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ + +/* Transmit Power flags available */ +#define IW_TXPOW_DBM 0x0000 /* Value is in dBm */ +#define IW_TXPOW_MWATT 0x0001 /* Value is in mW */ /****************************** TYPES ******************************/ @@ -359,6 +381,7 @@ struct iwreq struct iw_param sens; /* signal level threshold */ struct iw_param bitrate; /* default bit rate */ + struct iw_param txpower; /* default transmit power */ struct iw_param rts; /* RTS threshold threshold */ struct iw_param frag; /* Fragmentation threshold */ __u32 mode; /* Operation mode */ @@ -422,15 +445,23 @@ struct iw_range __s32 max_frag; /* Maximal frag threshold */ /* Power Management duration & timeout */ - __s32 min_pmd; /* Minimal PM duration */ - __s32 max_pmd; /* Maximal PM duration */ + __s32 min_pmp; /* Minimal PM period */ + __s32 max_pmp; /* Maximal PM period */ __s32 min_pmt; /* Minimal PM timeout */ __s32 max_pmt; /* Maximal PM timeout */ + __u16 pmp_flags; /* How to decode max/min PM period */ + __u16 pmt_flags; /* How to decode max/min PM timeout */ + __u16 pm_capa; /* What PM options are supported */ /* Encoder stuff */ __u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */ __u8 num_encoding_sizes; /* Number of entry in the list */ __u8 max_encoding_tokens; /* Max number of tokens */ + + /* Transmit power */ + __u16 txpower_capa; /* What options are supported */ + __u8 num_txpower; /* Number of entries in the list */ + __s32 txpower[IW_MAX_TXPOWER]; /* list, in bps */ }; /* diff --git a/init/main.c b/init/main.c index 7e8ac67a6..299adbc01 100644 --- a/init/main.c +++ b/init/main.c @@ -252,6 +252,24 @@ static struct dev_name_struct { { "ida/c0d14p",0x48E0 }, { "ida/c0d15p",0x48F0 }, #endif +#if defined(CONFIG_BLK_CPQ_CISS_DA) || defined(CONFIG_BLK_CPQ_CISS_DA_MODULE) + { "cciss/c0d0p",0x6800 }, + { "cciss/c0d1p",0x6810 }, + { "cciss/c0d2p",0x6820 }, + { "cciss/c0d3p",0x6830 }, + { "cciss/c0d4p",0x6840 }, + { "cciss/c0d5p",0x6850 }, + { "cciss/c0d6p",0x6860 }, + { "cciss/c0d7p",0x6870 }, + { "cciss/c0d8p",0x6880 }, + { "cciss/c0d9p",0x6890 }, + { "cciss/c0d10p",0x68A0 }, + { "cciss/c0d11p",0x68B0 }, + { "cciss/c0d12p",0x68C0 }, + { "cciss/c0d13p",0x68D0 }, + { "cciss/c0d14p",0x68E0 }, + { "cciss/c0d15p",0x68F0 }, +#endif #ifdef CONFIG_NFTL { "nftla", 0x5d00 }, #endif @@ -315,9 +333,9 @@ static int __init checksetup(char *line) /* this should be approx 2 Bo*oMips to start (note initial shift), and will still work even if initially too large, it will just take slightly longer */ -unsigned long loops_per_sec = (1<<12); +unsigned long loops_per_jiffy = (1<<12); -/* This is the number of bits of precision for the loops_per_second. Each +/* This is the number of bits of precision for the loops_per_jiffy. Each bit takes on average 1.5/HZ seconds. This (like the original) is a little better than 1% */ #define LPS_PREC 8 @@ -327,42 +345,40 @@ void __init calibrate_delay(void) unsigned long ticks, loopbit; int lps_precision = LPS_PREC; - loops_per_sec = (1<<12); + loops_per_jiffy = (1<<12); printk("Calibrating delay loop... "); - while (loops_per_sec <<= 1) { + while (loops_per_jiffy <<= 1) { /* wait for "start of" clock tick */ ticks = jiffies; while (ticks == jiffies) /* nothing */; /* Go .. */ ticks = jiffies; - __delay(loops_per_sec); + __delay(loops_per_jiffy); ticks = jiffies - ticks; if (ticks) break; } -/* Do a binary approximation to get loops_per_second set to equal one clock +/* Do a binary approximation to get loops_per_jiffy set to equal one clock (up to lps_precision bits) */ - loops_per_sec >>= 1; - loopbit = loops_per_sec; + loops_per_jiffy >>= 1; + loopbit = loops_per_jiffy; while ( lps_precision-- && (loopbit >>= 1) ) { - loops_per_sec |= loopbit; + loops_per_jiffy |= loopbit; ticks = jiffies; while (ticks == jiffies); ticks = jiffies; - __delay(loops_per_sec); + __delay(loops_per_jiffy); if (jiffies != ticks) /* longer than 1 tick */ - loops_per_sec &= ~loopbit; + loops_per_jiffy &= ~loopbit; } -/* finally, adjust loops per second in terms of seconds instead of clocks */ - loops_per_sec *= HZ; /* Round the value and print it */ printk("%lu.%02lu BogoMIPS\n", - (loops_per_sec+2500)/500000, - ((loops_per_sec+2500)/5000) % 100); + loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ)) % 100); } static int __init readonly(char *str) diff --git a/kernel/kmod.c b/kernel/kmod.c index b68392685..ac840a901 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -11,6 +11,9 @@ Limit the concurrent number of kmod modprobes to catch loops from "modprobe needs a service that is in a module". Keith Owens December 1999 + + Unblock all signals when we exec a usermode process. + Shuu Yamaguchi December 2000 */ #define __KERNEL_SYSCALLS__ @@ -83,9 +86,10 @@ use_init_fs_context(void) int exec_usermodehelper(char *program_path, char *argv[], char *envp[]) { int i; + struct task_struct *curtask = current; - current->session = 1; - current->pgrp = 1; + curtask->session = 1; + curtask->pgrp = 1; use_init_fs_context(); @@ -95,19 +99,21 @@ int exec_usermodehelper(char *program_path, char *argv[], char *envp[]) as the super user right after the execve fails if you time the signal just right. */ - spin_lock_irq(¤t->sigmask_lock); - flush_signals(current); - flush_signal_handlers(current); - spin_unlock_irq(¤t->sigmask_lock); - - for (i = 0; i < current->files->max_fds; i++ ) { - if (current->files->fd[i]) close(i); + spin_lock_irq(&curtask->sigmask_lock); + sigemptyset(&curtask->blocked); + flush_signals(curtask); + flush_signal_handlers(curtask); + recalc_sigpending(curtask); + spin_unlock_irq(&curtask->sigmask_lock); + + for (i = 0; i < curtask->files->max_fds; i++ ) { + if (curtask->files->fd[i]) close(i); } /* Drop the "current user" thing */ { - struct user_struct *user = current->user; - current->user = INIT_USER; + struct user_struct *user = curtask->user; + curtask->user = INIT_USER; atomic_inc(&INIT_USER->__count); atomic_inc(&INIT_USER->processes); atomic_dec(&user->processes); @@ -115,9 +121,9 @@ int exec_usermodehelper(char *program_path, char *argv[], char *envp[]) } /* Give kmod all effective privileges.. */ - current->euid = current->fsuid = 0; - current->egid = current->fsgid = 0; - cap_set_full(current->cap_effective); + curtask->euid = curtask->fsuid = 0; + curtask->egid = curtask->fsgid = 0; + cap_set_full(curtask->cap_effective); /* Allow execve args to be in kernel space. */ set_fs(KERNEL_DS); diff --git a/kernel/ksyms.c b/kernel/ksyms.c index ade551556..8d74cdb91 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -429,9 +429,13 @@ EXPORT_SYMBOL(jiffies); EXPORT_SYMBOL(xtime); EXPORT_SYMBOL(do_gettimeofday); EXPORT_SYMBOL(do_settimeofday); -#ifndef __ia64__ + +#ifdef CONFIG_X86 +EXPORT_SYMBOL(loops_per_jiffy); +#elif !defined(__ia64__) EXPORT_SYMBOL(loops_per_sec); #endif + EXPORT_SYMBOL(kstat); EXPORT_SYMBOL(nr_running); diff --git a/kernel/printk.c b/kernel/printk.c index 7b967e30f..4a459b605 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -113,8 +113,8 @@ __setup("console=", console_setup); * 0 -- Close the log. Currently a NOP. * 1 -- Open the log. Currently a NOP. * 2 -- Read from the log. - * 3 -- Read up to the last 4k of messages in the ring buffer. - * 4 -- Read and clear last 4k of messages in the ring buffer + * 3 -- Read all messages remaining in the ring buffer. + * 4 -- Read and clear all messages remaining in the ring buffer * 5 -- Clear ring buffer. * 6 -- Disable printk's to console * 7 -- Enable printk's to console diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 8d42109d8..c8f8c3e97 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -29,7 +29,6 @@ */ #include -#if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE) #include #include #include @@ -65,7 +64,7 @@ int sysctl_x25_reset_request_timeout = X25_DEFAULT_T22; int sysctl_x25_clear_request_timeout = X25_DEFAULT_T23; int sysctl_x25_ack_holdback_timeout = X25_DEFAULT_T2; -static struct sock *volatile x25_list = NULL; +static struct sock *volatile x25_list /* = NULL initially */; static struct proto_ops x25_proto_ops; @@ -1329,10 +1328,8 @@ static int __init x25_init(void) x25_register_sysctl(); #endif -#ifdef CONFIG_PROC_FS proc_net_create("x25", 0, x25_get_info); proc_net_create("x25_routes", 0, x25_routes_get_info); -#endif #ifdef MODULE /* @@ -1355,7 +1352,6 @@ module_init(x25_init); -#ifdef MODULE EXPORT_NO_SYMBOLS; MODULE_AUTHOR("Jonathan Naylor "); @@ -1364,10 +1360,8 @@ MODULE_DESCRIPTION("The X.25 Packet Layer network layer protocol"); static void __exit x25_exit(void) { -#ifdef CONFIG_PROC_FS proc_net_remove("x25"); proc_net_remove("x25_routes"); -#endif x25_link_free(); x25_route_free(); @@ -1383,6 +1377,4 @@ static void __exit x25_exit(void) sock_unregister(AF_X25); } module_exit(x25_exit); -#endif -#endif diff --git a/scripts/Configure b/scripts/Configure index 16c99f0d4..f931c4cbf 100644 --- a/scripts/Configure +++ b/scripts/Configure @@ -479,11 +479,14 @@ function choice () { while [ -n "$1" ]; do name=$(echo $1 | tr a-z A-Z) case "$name" in - "$ans"* ) - if [ "$name" = "$ans" ]; then - val="$2" - break # stop on exact match - fi + "$ans"* | */"$ans"* ) + case "$name" in + "$ans" | */"$ans"/* | \ + "$ans"/* | */"$ans" ) + val="$2" + break # exact match + ;; + esac if [ -n "$val" ]; then echo;echo \ " Sorry, \"$ans\" is ambiguous; please enter a longer string." -- 2.11.4.GIT