## Automatically generated incremental diff ## From: linux-2.4.22-bk29 ## To: linux-2.4.22-bk30 ## Robot: $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $ diff -urN linux-2.4.22-bk29/Documentation/Configure.help linux-2.4.22-bk30/Documentation/Configure.help --- linux-2.4.22-bk29/Documentation/Configure.help 2003-10-07 02:50:26.000000000 -0700 +++ linux-2.4.22-bk30/Documentation/Configure.help 2003-10-07 02:50:33.000000000 -0700 @@ -10881,6 +10881,26 @@ The module will be called dscc4.o. For general information about modules read . +PCISYNC feature +CONFIG_DSCC4_PCISYNC + Due to Etinc's design choice for its PCISYNC cards, some operations + are only allowed on specific ports of the DSCC4. This option is the + only way for the driver to know that it shouldn't return a success + code for these operations. + + Please say Y if your card is an Etinc's PCISYNC. + +Hard reset support +CONFIG_DSCC4_PCI_RST + Various DSCC4 bug forbid any reliable software reset of the asic. + As a replacement, some vendors provide a way to assert the PCI #RST + pin of DSCC4 through the GPIO port of the card. If you choose Y, the + driver will make use of this feature before module removal (i.e. rmmod). + This feature is known to exist on Commtech's cards. + Contact your manufacturer for details. + + Say Y if yout card supports this feature. + LanMedia Corp. serial boards (SSI/V.35, T1/E1, HSSI, T3) CONFIG_LANMEDIA This is a driver for the following Lan Media family of serial diff -urN linux-2.4.22-bk29/Documentation/README.nsp32_cb.eng linux-2.4.22-bk30/Documentation/README.nsp32_cb.eng --- linux-2.4.22-bk29/Documentation/README.nsp32_cb.eng 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.22-bk30/Documentation/README.nsp32_cb.eng 2003-10-07 02:50:33.000000000 -0700 @@ -0,0 +1,57 @@ + <> + + +1. What's this? + + This is Workbit corp.'s(http://www.workbit.co.jp/) NinjaSCSI-32Bi +(http://www.workbit.co.jp/ts/z_njsc32bi.html) PCMCIA card and NinjaSCSI-32UDE +PCI card driver module for Linux. + + + +2. Install + +[1] This driver requires Kernel 2.4.x/2.6.x or later. + And you want to load the module when Ninja card was inserted, you also + install "hotplug" (http://linux-hotplug.sourceforge.net/) utility. + +[2] Insert Ninja card to your PC, and check your card is NinjaSCSI-32Bi/UDE + card. + +# lspci +.... +01:00.0 SCSI storage controller: I-O Data Device, Inc. CBSC-II duo SCSI PCMCIA card (rev 01) + +[3] This driver requires Kernel 2.4/2.6's source code. Please install cernel + source code. + +[4] Please check your kernel have PCI, CardBus, PCMCIA and SCSI support. + If not, rebuild your kernel. And also requires PCMCIA-CS if you use + CardBus card. + +[5] Extract this archive somewhere. + +[6] Edit "Makefile" and type "make" to compile the driver. + +[7] Copy "nsp32.o" to /lib/modules//kernel/driver/scsi/pcmcia/ . + +[8] Type "depmod -ae" to re-made "/lib/modules//modules.pcimap" + +[9] Ok. Now you can use Ninja card in CardBus mode. Check your Ninja card is in + CardBus mode, and insert the card to PC card slot. + + + +3. Caution + If you eject card when doing some operation for your SCSI device or suspend +your computer, you encount some *BAD* error like disk crash. + It works good when I using this driver right way. But I'm not guarantee +your data. Please backup your data when you use this driver. + + +4. Copyright. + + No, no, this is Copyleft software. See GPL. + + +YOKOTA Hiroshi diff -urN linux-2.4.22-bk29/Documentation/README.nsp_cs.eng linux-2.4.22-bk30/Documentation/README.nsp_cs.eng --- linux-2.4.22-bk29/Documentation/README.nsp_cs.eng 2001-10-11 11:17:22.000000000 -0700 +++ linux-2.4.22-bk30/Documentation/README.nsp_cs.eng 2003-10-07 02:50:33.000000000 -0700 @@ -8,8 +8,8 @@ for Linux. 2. My Linux environment -Linux kernel: 2.4.7 / 2.2.19 -pcmcia-cs: 3.1.27 +Linux kernel: 2.4.20 / 2.5.63 +pcmcia-cs: 3.1.33 gcc: gcc-2.95.4 PC card: I-O data PCSC-F (NinjaSCSI-3) I-O data CBSC-II in 16 bit mode (NinjaSCSI-32Bi) @@ -46,22 +46,16 @@ $ make config ... -[3] If you use this driver with Kernel 2.2, Unpack pcmcia-cs in some directory - and make & install. This driver requies pcmcia-cs header file. -$ cd /usr/src -$ tar zxvf cs-pcmcia-cs-3.x.x.tar.gz -... - -[4] Extract this driver's archive somewhere, and edit Makefile, then do make. +[3] Extract this driver's archive somewhere, and edit Makefile, then do make. $ tar -zxvf nsp_cs-x.x.tar.gz $ cd nsp_cs-x.x $ emacs Makefile ... $ make -[5] Copy nsp_cs.o to suitable plase, like /lib/modules//pcmcia/ . +[4] Copy nsp_cs.o to suitable plase, like /lib/modules//pcmcia/ . -[6] Add these lines to /etc/pcmcia/config . +[5] Add these lines to /etc/pcmcia/config . If you yse pcmcia-cs-3.1.8 or later, we can use "nsp_cs.conf" file. So, you don't need to edit file. Just copy to /etc/pcmcia/ . @@ -97,7 +91,7 @@ bind "nsp_cs" ------------------------------------- -[7] Start (or restart) pcmcia-cs. +[6] Start (or restart) pcmcia-cs. # /etc/rc.d/rc.pcmcia start (BSD style) or # /etc/init.d/pcmcia start (SYSV style) @@ -113,8 +107,7 @@ your data. Please backup your data when you use this driver. 6. Known Bugs - In 2.4 kernel, you can't use 640MB Optical disk. This error comes from -high level SCSI driver. + Many bugs in this driver. Be careful! 7. Testing Please send me some reports(bug reports etc..) of this software. @@ -127,4 +120,4 @@ See GPL. -2001/08/08 yokota@netlab.is.tsukuba.ac.jp +2002/01/17 yokota@netlab.is.tsukuba.ac.jp diff -urN linux-2.4.22-bk29/Documentation/ioctl-number.txt linux-2.4.22-bk30/Documentation/ioctl-number.txt --- linux-2.4.22-bk29/Documentation/ioctl-number.txt 2001-07-11 16:35:37.000000000 -0700 +++ linux-2.4.22-bk30/Documentation/ioctl-number.txt 2003-10-07 02:50:33.000000000 -0700 @@ -171,10 +171,6 @@ 0xA0 all linux/sdp/sdp.h Industrial Device Project -0xA2 00-0F DVD decoder driver in development: - -0xA3 00-1F Philips SAA7146 dirver in development: - 0xA3 80-8F Port ACL in development: 0xA3 90-9F linux/dtlk.h diff -urN linux-2.4.22-bk29/Documentation/zorro.txt linux-2.4.22-bk30/Documentation/zorro.txt --- linux-2.4.22-bk29/Documentation/zorro.txt 2000-10-16 12:51:16.000000000 -0700 +++ linux-2.4.22-bk30/Documentation/zorro.txt 2003-10-07 02:50:33.000000000 -0700 @@ -2,7 +2,7 @@ ---------------------------------------- Written by Geert Uytterhoeven -Last revised: February 27, 2000 +Last revised: September 5, 2003 1. Introduction @@ -77,7 +77,7 @@ The treatment of these regions depends on the type of Zorro space: - Zorro II address space is always mapped and does not have to be mapped - explicitly using ioremap(). + explicitly using z_ioremap(). Conversion from bus/physical Zorro II addresses to kernel virtual addresses and vice versa is done using: @@ -85,22 +85,20 @@ virt_addr = ZTWO_VADDR(bus_addr); bus_addr = ZTWO_PADDR(virt_addr); - - Zorro III address space must be mapped explicitly using ioremap() first + - Zorro III address space must be mapped explicitly using z_ioremap() first before it can be accessed: - virt_addr = ioremap(bus_addr, size); + virt_addr = z_ioremap(bus_addr, size); ... - iounmap(virt_addr); + z_iounmap(virt_addr); 5. References ------------- linux/include/linux/zorro.h -linux/include/linux/ioport.h -linux/include/asm-m68k/io.h -linux/include/asm-m68k/amigahw.h -linux/include/asm-ppc/io.h +linux/include/asm-{m68k,ppc}/zorro.h +linux/include/linux/zorro_ids.h linux/drivers/zorro /proc/bus/zorro diff -urN linux-2.4.22-bk29/Makefile linux-2.4.22-bk30/Makefile --- linux-2.4.22-bk29/Makefile 2003-10-07 02:50:26.000000000 -0700 +++ linux-2.4.22-bk30/Makefile 2003-10-07 02:50:33.000000000 -0700 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 22 -EXTRAVERSION = -bk29 +EXTRAVERSION = -bk30 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -urN linux-2.4.22-bk29/arch/m68k/q40/q40ints.c linux-2.4.22-bk30/arch/m68k/q40/q40ints.c --- linux-2.4.22-bk29/arch/m68k/q40/q40ints.c 2003-10-07 02:50:27.000000000 -0700 +++ linux-2.4.22-bk30/arch/m68k/q40/q40ints.c 2003-10-07 02:50:33.000000000 -0700 @@ -124,7 +124,6 @@ case 11: printk("warning IRQ 10 and 11 not distinguishable\n"); irq=10; - default: } if (irqpc, fp->d0, fp->orig_d0, fp->d1, fp->d2); + printk("\tIIRQ_REG = %x, EIRQ_REG = %x\n",master_inb(IIRQ_REG),master_inb(EIRQ_REG)); } /* @@ -313,7 +313,6 @@ unsigned mir, mer; int irq,i; - repeat: mir=master_inb(IIRQ_REG); if (mir&Q40_IRQ_FRAME_MASK) { irq_tab[Q40_IRQ_FRAME].count++; @@ -373,7 +372,6 @@ /*printk("reenabling irq %d\n",irq); */ #endif } -// used to do 'goto repeat;' her, this delayed bh processing too long return; } } @@ -382,6 +380,7 @@ } iirq: mir=master_inb(IIRQ_REG); + /* should test whether keyboard irq is really enabled, doing it in defhand */ if (mir&Q40_IRQ_KEYB_MASK) { irq_tab[Q40_IRQ_KEYBOARD].count++; irq_tab[Q40_IRQ_KEYBOARD].handler(Q40_IRQ_KEYBOARD,irq_tab[Q40_IRQ_KEYBOARD].dev_id,fp); @@ -408,7 +407,9 @@ static void q40_defhand (int irq, void *dev_id, struct pt_regs *fp) { - printk ("Unknown q40 interrupt 0x%02x\n", irq); + if (irq!=Q40_IRQ_KEYBOARD) + printk ("Unknown q40 interrupt %d\n", irq); + else master_outb(-1,KEYBOARD_UNLOCK_REG); } static void sys_default_handler(int lev, void *dev_id, struct pt_regs *regs) { diff -urN linux-2.4.22-bk29/arch/ppc/8xx_io/uart.c linux-2.4.22-bk30/arch/ppc/8xx_io/uart.c --- linux-2.4.22-bk29/arch/ppc/8xx_io/uart.c 2003-10-07 02:50:27.000000000 -0700 +++ linux-2.4.22-bk30/arch/ppc/8xx_io/uart.c 2003-10-07 02:50:33.000000000 -0700 @@ -81,7 +81,11 @@ #define TX_WAKEUP ASYNC_SHARE_IRQ static char *serial_name = "CPM UART driver"; -static char *serial_version = "0.03"; +static char *serial_version = "0.04"; + +/* TX buffer length used by my_console_write. + Assume minumun length until it gets set by this driver */ +static int console_tx_buf_len = 1; static DECLARE_TASK_QUEUE(tq_serial); @@ -196,6 +200,7 @@ /* The number of buffer descriptors and their sizes. */ +#define EARLY_BUF_SIZE 4 #define RX_NUM_FIFO 4 #define RX_BUF_SIZE 32 #define TX_NUM_FIFO 4 @@ -1068,6 +1073,7 @@ ser_info_t *info = (ser_info_t *)tty->driver_data; volatile cbd_t *bdp; unsigned char *cp; + unsigned long flags; if (serial_paranoia_check(info, tty->device, "rs_put_char")) return; @@ -1075,7 +1081,16 @@ if (!tty) return; + local_irq_save(flags); bdp = info->tx_cur; + /* Get next BD. + */ + if (bdp->cbd_sc & BD_SC_WRAP) + info->tx_cur = info->tx_bd_base; + else + info->tx_cur = (cbd_t *)bdp + 1; + local_irq_restore(flags); + while (bdp->cbd_sc & BD_SC_READY); cp = info->tx_va_base + ((bdp - info->tx_bd_base) * TX_BUF_SIZE); @@ -1083,14 +1098,6 @@ bdp->cbd_datlen = 1; bdp->cbd_sc |= BD_SC_READY; - /* Get next BD. - */ - if (bdp->cbd_sc & BD_SC_WRAP) - bdp = info->tx_bd_base; - else - bdp++; - - info->tx_cur = (cbd_t *)bdp; } static int rs_8xx_write(struct tty_struct * tty, int from_user, @@ -1100,6 +1107,7 @@ ser_info_t *info = (ser_info_t *)tty->driver_data; volatile cbd_t *bdp; unsigned char *cp; + unsigned long flags; #ifdef CONFIG_KGDB_CONSOLE /* Try to let stub handle output. Returns true if it did. */ @@ -1113,44 +1121,50 @@ if (!tty) return 0; - bdp = info->tx_cur; - while (1) { c = MIN(count, TX_BUF_SIZE); if (c <= 0) break; + local_irq_save(flags); + bdp = info->tx_cur; if (bdp->cbd_sc & BD_SC_READY) { info->flags |= TX_WAKEUP; + local_irq_restore(flags); break; } + /* Get next BD. + */ + if (bdp->cbd_sc & BD_SC_WRAP) + info->tx_cur = info->tx_bd_base; + else + info->tx_cur = (cbd_t *)bdp + 1; + local_irq_restore(flags); - cp = info->tx_va_base + ((bdp - info->tx_bd_base) * TX_BUF_SIZE); - if (from_user) { - if (copy_from_user((void *)cp, buf, c)) { - if (!ret) - ret = -EFAULT; - break; - } - } else { + cp = info->tx_va_base + ((bdp - info->tx_bd_base) * + TX_BUF_SIZE); + if (from_user) + c -= copy_from_user((void *)cp, buf, c); + else memcpy((void *)cp, buf, c); - } - bdp->cbd_datlen = c; - bdp->cbd_sc |= BD_SC_READY; + if (c) { + bdp->cbd_datlen = c; + bdp->cbd_sc |= BD_SC_READY; + } else { + /* Need to TX at least 1 char to keep CPM sane */ + bdp->cbd_datlen = 1; + *cp = 0; + bdp->cbd_sc |= BD_SC_READY; + if (!ret) + ret = -EFAULT; + break; + } buf += c; count -= c; ret += c; - - /* Get next BD. - */ - if (bdp->cbd_sc & BD_SC_WRAP) - bdp = info->tx_bd_base; - else - bdp++; - info->tx_cur = (cbd_t *)bdp; } return ret; } @@ -1210,28 +1224,28 @@ { volatile cbd_t *bdp; unsigned char *cp; + unsigned long flags; ser_info_t *info = (ser_info_t *)tty->driver_data; if (serial_paranoia_check(info, tty->device, "rs_send_char")) return; + local_irq_save(flags); bdp = info->tx_cur; + /* Get next BD. + */ + if (bdp->cbd_sc & BD_SC_WRAP) + info->tx_cur = info->tx_bd_base; + else + info->tx_cur = (cbd_t *)bdp + 1; + local_irq_restore(flags); while (bdp->cbd_sc & BD_SC_READY); cp = info->tx_va_base + ((bdp - info->tx_bd_base) * TX_BUF_SIZE); *cp = ch; bdp->cbd_datlen = 1; bdp->cbd_sc |= BD_SC_READY; - - /* Get next BD. - */ - if (bdp->cbd_sc & BD_SC_WRAP) - bdp = info->tx_bd_base; - else - bdp++; - - info->tx_cur = (cbd_t *)bdp; } /* @@ -1802,7 +1816,7 @@ static void rs_8xx_wait_until_sent(struct tty_struct *tty, int timeout) { ser_info_t *info = (ser_info_t *)tty->driver_data; - unsigned long orig_jiffies, char_time; + unsigned long orig_jiffies, char_time, tst_res; /*int lsr;*/ volatile cbd_t *bdp; @@ -1837,6 +1851,7 @@ * are empty. */ do { + unsigned long flags; #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("lsr = %d (jiff=%lu)...", lsr, jiffies); #endif @@ -1854,12 +1869,15 @@ * is the buffer is available. There are still characters * in the CPM FIFO. */ + local_irq_save(flags); bdp = info->tx_cur; if (bdp == info->tx_bd_base) bdp += (TX_NUM_FIFO-1); else bdp--; - } while (bdp->cbd_sc & BD_SC_READY); + tst_res = !!(bdp->cbd_sc & BD_SC_READY); + local_irq_restore(flags); + } while (tst_res); current->state = TASK_RUNNING; #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); @@ -2261,10 +2279,11 @@ { struct serial_state *ser; ser_info_t *info; - unsigned i; + unsigned i, c, cr_missing, max_tx_size; volatile cbd_t *bdp, *bdbase; volatile smc_uart_t *up; volatile u_char *cp; + unsigned long flags; ser = rs_table + idx; @@ -2273,40 +2292,39 @@ * we simply use the single buffer allocated. */ if ((info = (ser_info_t *)ser->info) != NULL) { - bdp = info->tx_cur; bdbase = info->tx_bd_base; - } - else { - /* Pointer to UART in parameter ram. - */ + } else { + /* Pointer to UART in parameter ram. */ up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; - /* Get the address of the host memory buffer. - */ - bdp = bdbase = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase]; - + /* Get the address of the host memory buffer.*/ info = &consinfo; + info->tx_bd_base = (cbd_t *)bdbase = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase]; + info->tx_cur = (cbd_t *)bdbase; } + max_tx_size = console_tx_buf_len; + cr_missing = 0; + while (1){ + c = MIN(max_tx_size, count); + if (c <= 0) + break; - /* - * We need to gracefully shut down the transmitter, disable - * interrupts, then send our bytes out. - */ + local_irq_save(flags); + bdp = info->tx_cur; + bdbase = info->tx_bd_base; + if (bdp->cbd_sc & BD_SC_WRAP) + info->tx_cur = (cbd_t *)bdbase; + else + info->tx_cur = (cbd_t *)(bdp+1); + local_irq_restore(flags); - /* - * Now, do each character. This is not as bad as it looks - * since this is a holding FIFO and not a transmitting FIFO. - * We could add the complexity of filling the entire transmit - * buffer, but we would just wait longer between accesses...... - */ - for (i = 0; i < count; i++, s++) { /* Wait for transmitter fifo to empty. * Ready indicates output is ready, and xmt is doing * that, not that it is ready for us to send. */ while (bdp->cbd_sc & BD_SC_READY); - /* Send the character out. + /* Send the characters out. * If the buffer address is in the CPM DPRAM, don't * convert it. */ @@ -2314,54 +2332,32 @@ cp = (u_char *)(bdp->cbd_bufaddr); else cp = info->tx_va_base + ((bdp - info->tx_bd_base) * TX_BUF_SIZE); - *cp = *s; - bdp->cbd_datlen = 1; + i=1; /* Keeps track of consumed TX buffer space */ + if (cr_missing) { + /* Previus loop didn't have room for the CR, insert it first in this */ + *cp++ = '\r'; + i++; + } + cr_missing = 0; + for (; i <= c; i++) { + if ((*cp++ = *s++) != '\n') + continue; /* Copy bytes until a NewLine is found */ + /* NewLine found, see if there is space in the TX buffer to add a CR */ + if (i < max_tx_size) { + *cp++ = '\r'; /* yes, there is space to add a CR */ + i++; + } else + cr_missing = 1; /* No space in the TX buffer, + rember it so it can be inserted in the next loop */ + } + count -= (c-cr_missing); + bdp->cbd_datlen = i-1; bdp->cbd_sc |= BD_SC_READY; - if (bdp->cbd_sc & BD_SC_WRAP) - bdp = bdbase; - else - bdp++; - - /* if a LF, also do CR... */ - if (*s == 10) { - while (bdp->cbd_sc & BD_SC_READY); - /* This 'if' below will never be true, but a few - * people argued with me that it was a "bug by - * inspection" that is was easier to add the code - * than continue the discussion. The only time - * the buffer address is in DPRAM is during early - * use by kgdb/xmon, which format their own packets - * and we never get here. -- Dan - */ - if ((uint)(bdp->cbd_bufaddr) > (uint)IMAP_ADDR) - cp = (u_char *)(bdp->cbd_bufaddr); - else - cp = info->tx_va_base + ((bdp - info->tx_bd_base) * TX_BUF_SIZE); - *cp = 13; - bdp->cbd_datlen = 1; - bdp->cbd_sc |= BD_SC_READY; - - if (bdp->cbd_sc & BD_SC_WRAP) { - bdp = bdbase; - } - else { - bdp++; - } - } } - - /* - * Finally, Wait for transmitter & holding register to empty - * and restore the IER - */ - while (bdp->cbd_sc & BD_SC_READY); - - if (info) - info->tx_cur = (cbd_t *)bdp; + /* while (bdp->cbd_sc & BD_SC_READY); is this really needed? */ } - static void serial_console_write(struct console *c, const char *s, unsigned count) { @@ -3002,7 +2998,7 @@ } } - + console_tx_buf_len = TX_BUF_SIZE; return 0; } @@ -3058,7 +3054,7 @@ * memory yet because vm allocator isn't initialized * during this early console init. */ - dp_addr = m8xx_cpm_dpalloc(8); + dp_addr = m8xx_cpm_dpalloc(2*EARLY_BUF_SIZE); mem_addr = (uint)(&cpmp->cp_dpmem[dp_addr]); /* Allocate space for two buffer descriptors in the DP ram. @@ -3072,10 +3068,10 @@ bdp->cbd_bufaddr = iopa(mem_addr); (bdp+1)->cbd_bufaddr = iopa(mem_addr+4); - consinfo.rx_va_base = mem_addr; - consinfo.rx_bd_base = bdp; - consinfo.tx_va_base = mem_addr + 4; - consinfo.tx_bd_base = bdp+1; + consinfo.rx_va_base = (unsigned char *) mem_addr; + consinfo.rx_bd_base = (cbd_t *) bdp; + consinfo.tx_va_base = (unsigned char *) (mem_addr + EARLY_BUF_SIZE); + consinfo.tx_bd_base = (cbd_t *) (bdp+1); /* For the receive, set empty and wrap. * For transmit, set wrap. @@ -3176,7 +3172,7 @@ /* Set up the baud rate generator. */ m8xx_cpm_setbrg((ser - rs_table), bd->bi_baudrate); - + console_tx_buf_len = EARLY_BUF_SIZE; return 0; } diff -urN linux-2.4.22-bk29/arch/ppc/Makefile linux-2.4.22-bk30/arch/ppc/Makefile --- linux-2.4.22-bk29/arch/ppc/Makefile 2003-10-07 02:50:27.000000000 -0700 +++ linux-2.4.22-bk30/arch/ppc/Makefile 2003-10-07 02:50:33.000000000 -0700 @@ -85,7 +85,7 @@ checks: @$(MAKE) -C arch/$(ARCH)/kernel checks -BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd +BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd uImage # All the instructions talk about "make bzImage". bzImage: zImage diff -urN linux-2.4.22-bk29/arch/ppc/boot/Makefile linux-2.4.22-bk30/arch/ppc/boot/Makefile --- linux-2.4.22-bk29/arch/ppc/boot/Makefile 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.22-bk30/arch/ppc/boot/Makefile 2003-10-07 02:50:33.000000000 -0700 @@ -17,7 +17,7 @@ AFLAGS += -D__BOOTER__ OBJCOPY_ARGS = -O elf32-powerpc -MKIMAGE := ./utils/mkimage.wrapper +MKIMAGE := $(TOPDIR)/scripts/mkuboot.sh lib/zlib.a: lib/zlib.c $(MAKE) -C lib @@ -61,12 +61,14 @@ gzip $(GZIP_FLAGS) images/vmapus endif -# Make an image for PPCBoot -pImage: images/vmlinux.gz - $(MKIMAGE) -A ppc -O linux -T kernel -C gzip -a 00000000 -e 00000000 \ +# Make an image for PPCBoot / U-Boot. +uImage: $(MKIMAGE) images/vmlinux.gz + $(CONFIG_SHELL) $(MKIMAGE) -A ppc -O linux -T kernel \ + -C gzip -a 00000000 -e 00000000 \ -n 'Linux-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)' \ - -d $< images/vmlinux.PPCBoot - ln -sf vmlinux.PPCBoot images/pImage + -d images/vmlinux.gz images/vmlinux.UBoot + ln -sf vmlinux.UBoot images/uImage + rm -f ./mkuboot # These are subdirs with files not normally rm'ed. -- Tom clean: diff -urN linux-2.4.22-bk29/arch/ppc/boot/images/Makefile linux-2.4.22-bk30/arch/ppc/boot/images/Makefile --- linux-2.4.22-bk29/arch/ppc/boot/images/Makefile 2002-08-02 17:39:43.000000000 -0700 +++ linux-2.4.22-bk30/arch/ppc/boot/images/Makefile 2003-10-07 02:50:33.000000000 -0700 @@ -9,4 +9,4 @@ gzip -vf9 vmlinux clean: - rm -f sImage vmapus vmlinux* miboot* zImage* zvmlinux* + rm -f sImage vmapus vmlinux* miboot* zImage* zvmlinux* uImage diff -urN linux-2.4.22-bk29/arch/ppc/boot/utils/mkimage.wrapper linux-2.4.22-bk30/arch/ppc/boot/utils/mkimage.wrapper --- linux-2.4.22-bk29/arch/ppc/boot/utils/mkimage.wrapper 2002-08-02 17:39:43.000000000 -0700 +++ linux-2.4.22-bk30/arch/ppc/boot/utils/mkimage.wrapper 1969-12-31 16:00:00.000000000 -0800 @@ -1,16 +0,0 @@ -#!/bin/bash - -# -# Build PPCBoot image when `mkimage' tool is available. -# - -MKIMAGE=$(type -path mkimage) - -if [ -z "${MKIMAGE}" ]; then - # Doesn't exist - echo '"mkimage" command not found - PPCBoot images will not be built' >&2 - exit 0; -fi - -# Call "mkimage" to create PPCBoot image -${MKIMAGE} "$@" diff -urN linux-2.4.22-bk29/arch/ppc/kernel/setup.c linux-2.4.22-bk30/arch/ppc/kernel/setup.c --- linux-2.4.22-bk29/arch/ppc/kernel/setup.c 2003-10-07 02:50:27.000000000 -0700 +++ linux-2.4.22-bk30/arch/ppc/kernel/setup.c 2003-10-07 02:50:33.000000000 -0700 @@ -152,12 +152,12 @@ return 0; pvr = cpu_data[i].pvr; lpj = cpu_data[i].loops_per_jiffy; - seq_printf(m, "processor\t: %lu\n", i); #else pvr = mfspr(PVR); lpj = loops_per_jiffy; #endif + seq_printf(m, "processor\t: %lu\n", i); seq_printf(m, "cpu\t\t: "); if (cur_cpu_spec[i]->pvr_mask) diff -urN linux-2.4.22-bk29/drivers/acpi/Config.in linux-2.4.22-bk30/drivers/acpi/Config.in --- linux-2.4.22-bk29/drivers/acpi/Config.in 2003-10-07 02:50:28.000000000 -0700 +++ linux-2.4.22-bk30/drivers/acpi/Config.in 2003-10-07 02:50:34.000000000 -0700 @@ -32,7 +32,8 @@ tristate ' Toshiba Laptop Extras' CONFIG_ACPI_TOSHIBA bool ' Debug Statements' CONFIG_ACPI_DEBUG bool ' Relaxed AML Checking' CONFIG_ACPI_RELAXED_AML - else if [ "$CONFIG_SMP" = "y" ]; then + else + if [ "$CONFIG_SMP" = "y" ]; then define_bool CONFIG_ACPI_BOOT y fi fi diff -urN linux-2.4.22-bk29/drivers/acpi/system.c linux-2.4.22-bk30/drivers/acpi/system.c --- linux-2.4.22-bk29/drivers/acpi/system.c 2003-08-25 04:44:41.000000000 -0700 +++ linux-2.4.22-bk30/drivers/acpi/system.c 2003-10-07 02:50:34.000000000 -0700 @@ -1192,11 +1192,21 @@ #if defined(CONFIG_MAGIC_SYSRQ) && defined(CONFIG_PM) +static int po_cb_active; + +static void acpi_po_tramp(void *x) +{ + acpi_power_off(); +} + /* Simple wrapper calling power down function. */ static void acpi_sysrq_power_off(int key, struct pt_regs *pt_regs, struct kbd_struct *kbd, struct tty_struct *tty) -{ - acpi_power_off(); +{ + static struct tq_struct tq = { .routine = acpi_po_tramp }; + if (po_cb_active++) + return; + schedule_task(&tq); } struct sysrq_key_op sysrq_acpi_poweroff_op = { diff -urN linux-2.4.22-bk29/drivers/net/wan/Config.in linux-2.4.22-bk30/drivers/net/wan/Config.in --- linux-2.4.22-bk29/drivers/net/wan/Config.in 2003-10-07 02:50:29.000000000 -0700 +++ linux-2.4.22-bk30/drivers/net/wan/Config.in 2003-10-07 02:50:34.000000000 -0700 @@ -38,12 +38,12 @@ fi dep_tristate ' Support for Frame Relay on MultiGate boards' CONFIG_COMX_PROTO_FR $CONFIG_COMX fi -# -# The Etinc driver has not been tested as non-modular yet. -# - - dep_tristate ' Etinc PCISYNC serial board support (EXPERIMENTAL)' CONFIG_DSCC4 m + dep_tristate ' DSCC4 support' CONFIG_DSCC4 m + if [ "$CONFIG_DSCC4" = "m" ]; then + bool ' Etinc PCISYNC features' CONFIG_DSCC4_PCISYNC + bool ' GPIO and PCI #RST pins wired together' CONFIG_DSCC4_PCI_RST + fi # # Lan Media's board. Currently 1000, 1200, 5200, 5245 diff -urN linux-2.4.22-bk29/drivers/net/wan/dscc4.c linux-2.4.22-bk30/drivers/net/wan/dscc4.c --- linux-2.4.22-bk29/drivers/net/wan/dscc4.c 2003-10-07 02:50:29.000000000 -0700 +++ linux-2.4.22-bk30/drivers/net/wan/dscc4.c 2003-10-07 02:50:34.000000000 -0700 @@ -111,6 +111,11 @@ static int debug; static int quartz; +#ifdef CONFIG_DSCC4_PCI_RST +static DECLARE_MUTEX(dscc4_sem); +static u32 dscc4_pci_config_store[16]; +#endif + #define DRV_NAME "dscc4" #undef DSCC4_POLLING @@ -163,7 +168,14 @@ #define SOURCE_ID(flags) (((flags) >> 28) & 0x03) #define TO_SIZE(state) (((state) >> 16) & 0x1fff) -#define TO_STATE(len) cpu_to_le32(((len) & TxSizeMax) << 16) + +/* + * Given the operating range of Linux HDLC, the 2 defines below could be + * made simpler. However they are a fine reminder for the limitations of + * the driver: it's better to stay < TxSizeMax and < RxSizeMax. + */ +#define TO_STATE_TX(len) cpu_to_le32(((len) & TxSizeMax) << 16) +#define TO_STATE_RX(len) cpu_to_le32((RX_MAX(len) % RxSizeMax) << 16) #define RX_MAX(len) ((((len) >> 5) + 1) << 5) /* Cf RLCR */ #define SCC_REG_START(dpriv) (SCC_START+(dpriv->dev_id)*SCC_OFFSET) @@ -255,6 +267,10 @@ #define IMR 0x54 #define ISR 0x58 +#define GPDIR 0x0400 +#define GPDATA 0x0404 +#define GPIM 0x0408 + /* Bit masks */ #define EncodingMask 0x00700000 #define CrcMask 0x00000003 @@ -271,7 +287,8 @@ #define Idt 0x00080000 #define TxSccRes 0x01000000 #define RxSccRes 0x00010000 -#define TxSizeMax 0x1fff +#define TxSizeMax 0x1fff /* Datasheet DS1 - 11.1.1.1 */ +#define RxSizeMax 0x1ffc /* Datasheet DS1 - 11.1.2.1 */ #define Ccr0ClockMask 0x0000003f #define Ccr1LoopMask 0x00000200 @@ -319,10 +336,13 @@ #define Arf 0x00000002 #define ArAck 0x00000001 -/* Misc */ +/* State flags */ +#define Ready 0x00000000 #define NeedIDR 0x00000001 #define NeedIDT 0x00000002 #define RdoSet 0x00000004 +#define FakeReset 0x00000008 + /* Don't mask RDO. Ever. */ #ifdef DSCC4_POLLING #define EventsMask 0xfffeef7f @@ -572,15 +592,19 @@ return (i >= 0 ) ? i : -EAGAIN; } -/* Requires protection against interrupt */ +#if 0 /* dscc4_{rx/tx}_reset are both unreliable - more tweak needed */ static void dscc4_rx_reset(struct dscc4_dev_priv *dpriv, struct net_device *dev) { + unsigned long flags; + + spin_lock_irqsave(&dpriv->pci_priv->lock, flags); /* Cf errata DS5 p.6 */ writel(0x00000000, dev->base_addr + CH0LRDA + dpriv->dev_id*4); scc_patchl(PowerUp, 0, dpriv, dev, CCR0); readl(dev->base_addr + CH0LRDA + dpriv->dev_id*4); writel(MTFi|Rdr, dev->base_addr + dpriv->dev_id*0x0c + CH0CFG); writel(Action, dev->base_addr + GCMDR); + spin_unlock_irqrestore(&dpriv->pci_priv->lock, flags); } static void dscc4_tx_reset(struct dscc4_dev_priv *dpriv, struct net_device *dev) @@ -602,6 +626,7 @@ if (dscc4_do_action(dev, "Rdt") < 0) printk(KERN_ERR "%s: Tx reset failed\n", dev->name); } +#endif /* TODO: (ab)use this function to refill a completely depleted RX ring. */ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, @@ -822,8 +847,9 @@ * No address recognition/crc-CCITT/cts enabled * Shared flags transmission disabled - cf errata DS5 p.11 * Carrier detect disabled - cf errata p.14 + * FIXME: carrier detection/polarity may be handled more gracefully. */ - scc_writel(0x021c8000, dpriv, dev, CCR1); + scc_writel(0x02408000, dpriv, dev, CCR1); /* crc not forwarded - Cf errata DS5 p.11 */ scc_writel(0x00050008 & ~RxActivate, dpriv, dev, CCR2); @@ -835,7 +861,7 @@ { struct dscc4_pci_priv *ppriv; struct dscc4_dev_priv *root; - int i = 0; + int i, ret = -ENOMEM; root = (struct dscc4_dev_priv *) kmalloc(dev_per_card*sizeof(*root), GFP_KERNEL); @@ -867,6 +893,8 @@ d->tx_timeout = dscc4_tx_timeout; d->watchdog_timeo = TX_TIMEOUT; + SET_MODULE_OWNER(d); + dpriv->dev_id = i; dpriv->pci_priv = ppriv; spin_lock_init(&dpriv->lock); @@ -874,31 +902,40 @@ hdlc->xmit = dscc4_start_xmit; hdlc->attach = dscc4_hdlc_attach; - if (register_hdlc_device(hdlc)) { + ret = register_hdlc_device(hdlc); + if (ret < 0) { printk(KERN_ERR "%s: unable to register\n", DRV_NAME); goto err_unregister; } - hdlc->proto = IF_PROTO_HDLC; - SET_MODULE_OWNER(d); + dscc4_init_registers(dpriv, d); dpriv->parity = PARITY_CRC16_PR0_CCITT; dpriv->encoding = ENCODING_NRZ; + + ret = dscc4_init_ring(d); + if (ret < 0) { + unregister_hdlc_device(hdlc); + goto err_unregister; + } } - if (dscc4_set_quartz(root, quartz) < 0) + ret = dscc4_set_quartz(root, quartz); + if (ret < 0) goto err_unregister; ppriv->root = root; spin_lock_init(&ppriv->lock); pci_set_drvdata(pdev, ppriv); - return 0; + return ret; err_unregister: - while (--i >= 0) + while (--i >= 0) { + dscc4_release_ring(root + i); unregister_hdlc_device(&root[i].hdlc); + } kfree(ppriv); err_free_dev: kfree(root); err_out: - return -1; + return ret; }; /* FIXME: get rid of the unneeded code */ @@ -932,6 +969,46 @@ return 0; } +#ifdef CONFIG_DSCC4_PCI_RST +/* + * Some DSCC4-based cards wires the GPIO port and the PCI #RST pin together + * so as to provide a safe way to reset the asic while not the whole machine + * rebooting. + * + * This code doesn't need to be efficient. Keep It Simple + */ +static void dscc4_pci_reset(struct pci_dev *pdev, u32 ioaddr) +{ + int i; + + down(&dscc4_sem); + for (i = 0; i < 16; i++) + pci_read_config_dword(pdev, i << 2, dscc4_pci_config_store + i); + + /* Maximal LBI clock divider (who cares ?) and whole GPIO range. */ + writel(0x001c0000, ioaddr + GMODE); + /* Configure GPIO port as output */ + writel(0x0000ffff, ioaddr + GPDIR); + /* Disable interruption */ + writel(0x0000ffff, ioaddr + GPIM); + + writel(0x0000ffff, ioaddr + GPDATA); + writel(0x00000000, ioaddr + GPDATA); + + /* Flush posted writes */ + readl(ioaddr + GSTAR); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(10); + + for (i = 0; i < 16; i++) + pci_write_config_dword(pdev, i << 2, dscc4_pci_config_store[i]); + up(&dscc4_sem); +} +#else +#define dscc4_pci_reset(pdev,ioaddr) do {} while (0) +#endif /* CONFIG_DSCC4_PCI_RST */ + static int dscc4_open(struct net_device *dev) { struct dscc4_dev_priv *dpriv = dscc4_priv(dev); @@ -949,8 +1026,23 @@ ppriv = dpriv->pci_priv; - if ((ret = dscc4_init_ring(dev))) - goto err_out; + /* + * Due to various bugs, there is no way to reliably reset a + * specific port (manufacturer's dependant special PCI #RST wiring + * apart: it affects all ports). Thus the device goes in the best + * silent mode possible at dscc4_close() time and simply claims to + * be up if it's opened again. It still isn't possible to change + * the HDLC configuration without rebooting but at least the ports + * can be up/down ifconfig'ed without killing the host. + */ + if (dpriv->flags & FakeReset) { + dpriv->flags &= ~FakeReset; + scc_patchl(0, PowerUp, dpriv, dev, CCR0); + scc_patchl(0, 0x00050000, dpriv, dev, CCR2); + scc_writel(EventsMask, dpriv, dev, IMR); + printk(KERN_INFO "%s: up again.\n", dev->name); + goto done; + } /* IDT+IDR during XPR */ dpriv->flags = NeedIDR | NeedIDT; @@ -967,7 +1059,7 @@ if (scc_readl_star(dpriv, dev) & SccBusy) { printk(KERN_ERR "%s busy. Try later\n", dev->name); ret = -EAGAIN; - goto err_free_ring; + goto err_out; } else printk(KERN_INFO "%s: available. Good\n", dev->name); @@ -994,6 +1086,7 @@ if (debug > 2) dscc4_tx_print(dev, dpriv, "Open"); +done: netif_start_queue(dev); init_timer(&dpriv->timer); @@ -1007,9 +1100,7 @@ err_disable_scc_events: scc_writel(0xffffffff, dpriv, dev, IMR); -err_free_ring: scc_patchl(PowerUp | Vis, 0, dpriv, dev, CCR0); - dscc4_release_ring(dpriv); err_out: hdlc_close(hdlc); MOD_DEC_USE_COUNT; @@ -1034,7 +1125,7 @@ next = dpriv->tx_current%TX_RING_SIZE; dpriv->tx_skbuff[next] = skb; tx_fd = dpriv->tx_fd + next; - tx_fd->state = FrameEnd | TO_STATE(skb->len); + tx_fd->state = FrameEnd | TO_STATE_TX(skb->len); tx_fd->data = pci_map_single(ppriv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); tx_fd->complete = 0x00000000; @@ -1065,36 +1156,27 @@ { struct dscc4_dev_priv *dpriv = dscc4_priv(dev); hdlc_device *hdlc = dev_to_hdlc(dev); - unsigned long flags; del_timer_sync(&dpriv->timer); netif_stop_queue(dev); - spin_lock_irqsave(&dpriv->pci_priv->lock, flags); - dscc4_rx_reset(dpriv, dev); - spin_unlock_irqrestore(&dpriv->pci_priv->lock, flags); - - dscc4_tx_reset(dpriv, dev); - scc_patchl(PowerUp | Vis, 0, dpriv, dev, CCR0); + scc_patchl(0x00050000, 0, dpriv, dev, CCR2); scc_writel(0xffffffff, dpriv, dev, IMR); + dpriv->flags |= FakeReset; + hdlc_close(hdlc); - dscc4_release_ring(dpriv); MOD_DEC_USE_COUNT; return 0; } -/* - * Et*nc's PCISYNC only allows clock generation on first two ports. - * DSCC4 can do more. It depends on the manufacturer of the card. - */ static inline int dscc4_check_clock_ability(int port) { int ret = 0; -#ifdef CONFIG_DSCC4_CLOCK_ON_TWO_PORTS_ONLY +#ifdef CONFIG_DSCC4_PCISYNC if (port >= 2) ret = -1; #endif @@ -1225,6 +1307,11 @@ if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (dpriv->flags & FakeReset) { + printk(KERN_INFO "%s: please reset the device" + " before this command\n", dev->name); + return -EPERM; + } if (copy_from_user(&dpriv->settings, line, size)) return -EFAULT; ret = dscc4_set_iface(dpriv, dev); @@ -1278,9 +1365,9 @@ if (bps) { /* DCE */ printk(KERN_DEBUG "%s: generated RxClk (DCE)\n", dev->name); if (settings->clock_rate != bps) { - settings->clock_rate = bps; printk(KERN_DEBUG "%s: clock adjusted (%08d -> %08d)\n", - dev->name, dpriv->settings.clock_rate, bps); + dev->name, settings->clock_rate, bps); + settings->clock_rate = bps; } } else { /* DTE */ state |= PowerUp | Vis; @@ -1389,6 +1476,8 @@ state = readl(ioaddr + GSTAR); if (!state) goto out; + if (debug > 3) + printk(KERN_DEBUG "%s: GSTAR = 0x%08x\n", DRV_NAME, state); writel(state, ioaddr + GSTAR); if (state & Arf) { @@ -1434,6 +1523,9 @@ cur = dpriv->iqtx_current%IRQ_RING_SIZE; state = dpriv->iqtx[cur]; if (!state) { + if (debug > 4) + printk(KERN_DEBUG "%s: Tx ISR = 0x%08x\n", dev->name, + state); if ((debug > 1) && (loop > 1)) printk(KERN_DEBUG "%s: Tx irq loop=%d\n", dev->name, loop); if (loop && netif_queue_stopped(dev)) @@ -1488,7 +1580,7 @@ * random freeze induced by null sized tx frames. */ tx_fd->data = tx_fd->next; - tx_fd->state = FrameEnd | TO_STATE(2*DUMMY_SKB_SIZE); + tx_fd->state = FrameEnd | TO_STATE_TX(2*DUMMY_SKB_SIZE); tx_fd->complete = 0x00000000; tx_fd->jiffies = 0; @@ -1567,7 +1659,8 @@ goto try; } if (state & Cd) { - printk(KERN_INFO "%s: CD transition\n", dev->name); + if (debug > 0) + printk(KERN_INFO "%s: CD transition\n", dev->name); if (!(state &= ~Cd)) /* DEBUG */ goto try; } @@ -1609,6 +1702,9 @@ if (!(state & SccEvt)){ struct RxFD *rx_fd; + if (debug > 4) + printk(KERN_DEBUG "%s: Rx ISR = 0x%08x\n", dev->name, + state); state &= 0x00ffffff; if (state & Err) { /* Hold or reset */ printk(KERN_DEBUG "%s: Rx ERR\n", dev->name); @@ -1785,7 +1881,7 @@ skb->len = DUMMY_SKB_SIZE; memcpy(skb->data, version, strlen(version)%DUMMY_SKB_SIZE); - tx_fd->state = FrameEnd | TO_STATE(DUMMY_SKB_SIZE); + tx_fd->state = FrameEnd | TO_STATE_TX(DUMMY_SKB_SIZE); tx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data, DUMMY_SKB_SIZE, PCI_DMA_TODEVICE); dpriv->tx_skbuff[last] = skb; @@ -1816,7 +1912,7 @@ dpriv->tx_dirty = 0xffffffff; i = dpriv->tx_current = 0; do { - tx_fd->state = FrameEnd | TO_STATE(2*DUMMY_SKB_SIZE); + tx_fd->state = FrameEnd | TO_STATE_TX(2*DUMMY_SKB_SIZE); tx_fd->complete = 0x00000000; /* FIXME: NULL should be ok - to be tried */ tx_fd->data = dpriv->tx_fd_dma; @@ -1834,7 +1930,7 @@ rx_fd->state1 = HiDesc; rx_fd->state2 = 0x00000000; rx_fd->end = 0xbabeface; - rx_fd->state1 |= TO_STATE(RX_MAX(HDLC_MAX_MRU)); + rx_fd->state1 |= TO_STATE_RX(HDLC_MAX_MRU); // FIXME: return value verifiee mais traitement suspect if (try_get_rx_skb(dpriv, dev) >= 0) dpriv->rx_dirty++; @@ -1863,12 +1959,16 @@ root = ppriv->root; ioaddr = hdlc_to_dev(&root->hdlc)->base_addr; + + dscc4_pci_reset(pdev, ioaddr); + free_irq(pdev->irq, root); pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), ppriv->iqcfg, ppriv->iqcfg_dma); for (i = 0; i < dev_per_card; i++) { struct dscc4_dev_priv *dpriv = root + i; + dscc4_release_ring(dpriv); pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), dpriv->iqrx, dpriv->iqrx_dma); pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), diff -urN linux-2.4.22-bk29/drivers/pcmcia/i82365.c linux-2.4.22-bk30/drivers/pcmcia/i82365.c --- linux-2.4.22-bk29/drivers/pcmcia/i82365.c 2002-11-28 15:53:14.000000000 -0800 +++ linux-2.4.22-bk30/drivers/pcmcia/i82365.c 2003-10-07 02:50:34.000000000 -0700 @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include @@ -89,7 +88,6 @@ /* Parameters that can be set with 'insmod' */ -#ifdef CONFIG_ISA /* Default base address for i82365sl and other ISA chips */ static int i365_base = 0x3e0; /* Should we probe at 0x3e2 for an extra ISA controller? */ @@ -101,7 +99,6 @@ static int irq_list[16] = { -1 }; /* The card status change interrupt -- 0 means autoselect */ static int cs_irq = 0; -#endif /* Probe for safe interrupts? */ static int do_scan = 1; @@ -120,14 +117,11 @@ static int cmd_time = -1; static int recov_time = -1; -#ifdef CONFIG_ISA /* Vadem options */ static int async_clock = -1; static int cable_mode = -1; static int wakeup = 0; -#endif -#ifdef CONFIG_ISA MODULE_PARM(i365_base, "i"); MODULE_PARM(ignore, "i"); MODULE_PARM(extra_sockets, "i"); @@ -137,7 +131,6 @@ MODULE_PARM(async_clock, "i"); MODULE_PARM(cable_mode, "i"); MODULE_PARM(wakeup, "i"); -#endif MODULE_PARM(do_scan, "i"); MODULE_PARM(poll_interval, "i"); @@ -188,45 +181,29 @@ /* Default ISA interrupt mask */ #define I365_MASK 0xdeb8 /* irq 15,14,12,11,10,9,7,5,4,3 */ -#ifdef CONFIG_ISA static int grab_irq; static spinlock_t isa_lock = SPIN_LOCK_UNLOCKED; #define ISA_LOCK(n, f) spin_lock_irqsave(&isa_lock, f) #define ISA_UNLOCK(n, f) spin_unlock_irqrestore(&isa_lock, f) -#else -#define ISA_LOCK(n, f) do { } while (0) -#define ISA_UNLOCK(n, f) do { } while (0) -#endif static struct timer_list poll_timer; /*====================================================================*/ -/* Default settings for PCI command configuration register */ -#define CMD_DFLT (PCI_COMMAND_IO|PCI_COMMAND_MEMORY| \ - PCI_COMMAND_MASTER|PCI_COMMAND_WAIT) - /* These definitions must match the pcic table! */ -#ifdef CONFIG_ISA typedef enum pcic_id { IS_I82365A, IS_I82365B, IS_I82365DF, IS_IBM, IS_RF5Cx96, IS_VLSI, IS_VG468, IS_VG469, IS_PD6710, IS_PD672X, IS_VT83C469, } pcic_id; -#endif /* Flags for classifying groups of controllers */ #define IS_VADEM 0x0001 #define IS_CIRRUS 0x0002 -#define IS_TI 0x0004 -#define IS_O2MICRO 0x0008 #define IS_VIA 0x0010 -#define IS_TOPIC 0x0020 -#define IS_RICOH 0x0040 #define IS_UNKNOWN 0x0400 #define IS_VG_PWR 0x0800 #define IS_DF_PWR 0x1000 -#define IS_PCI 0x2000 #define IS_ALIVE 0x8000 typedef struct pcic_t { @@ -235,7 +212,6 @@ } pcic_t; static pcic_t pcic[] = { -#ifdef CONFIG_ISA { "Intel i82365sl A step", 0 }, { "Intel i82365sl B step", 0 }, { "Intel i82365sl DF", IS_DF_PWR }, @@ -247,7 +223,6 @@ { "Cirrus PD6710", IS_CIRRUS }, { "Cirrus PD672x", IS_CIRRUS }, { "VIA VT83C469", IS_CIRRUS|IS_VIA }, -#endif }; #define PCIC_COUNT (sizeof(pcic)/sizeof(pcic_t)) @@ -369,26 +344,24 @@ if (has_ring == -1) has_ring = 1; flip(p->misc2, PD67_MC2_IRQ15_RI, has_ring); flip(p->misc2, PD67_MC2_DYNAMIC_MODE, dynamic_mode); + flip(p->misc2, PD67_MC2_FREQ_BYPASS, freq_bypass); if (p->misc2 & PD67_MC2_IRQ15_RI) strcat(buf, " [ring]"); if (p->misc2 & PD67_MC2_DYNAMIC_MODE) strcat(buf, " [dyn mode]"); + if (p->misc2 & PD67_MC2_FREQ_BYPASS) + strcat(buf, " [freq bypass]"); if (p->misc1 & PD67_MC1_INPACK_ENA) strcat(buf, " [inpack]"); - if (!(t->flags & IS_PCI)) { - if (p->misc2 & PD67_MC2_IRQ15_RI) - mask &= ~0x8000; - if (has_led > 0) { - strcat(buf, " [led]"); - mask &= ~0x1000; - } - if (has_dma > 0) { - strcat(buf, " [dma]"); - mask &= ~0x0600; - flip(p->misc2, PD67_MC2_FREQ_BYPASS, freq_bypass); - if (p->misc2 & PD67_MC2_FREQ_BYPASS) - strcat(buf, " [freq bypass]"); - } + if (p->misc2 & PD67_MC2_IRQ15_RI) + mask &= ~0x8000; + if (has_led > 0) { + strcat(buf, " [led]"); + mask &= ~0x1000; + } + if (has_dma > 0) { + strcat(buf, " [dma]"); + mask &= ~0x0600; } if (!(t->flags & IS_VIA)) { if (setup_time >= 0) @@ -419,8 +392,6 @@ ======================================================================*/ -#ifdef CONFIG_ISA - static void vg46x_get_state(u_short s) { vg46x_state_t *p = &socket[s].state.vg46x; @@ -462,9 +433,6 @@ return 0xffff; } -#endif - - /*====================================================================== Generic routines to get and set controller options @@ -476,10 +444,8 @@ socket_info_t *t = &socket[s]; if (t->flags & IS_CIRRUS) cirrus_get_state(s); -#ifdef CONFIG_ISA else if (t->flags & IS_VADEM) vg46x_get_state(s); -#endif } static void set_bridge_state(u_short s) @@ -492,10 +458,8 @@ i365_set(s, I365_GENCTL, 0x00); } i365_bflip(s, I365_INTCTL, I365_INTR_ENA, t->intr); -#ifdef CONFIG_ISA if (t->flags & IS_VADEM) vg46x_set_state(s); -#endif } static u_int __init set_bridge_opts(u_short s, u_short ns) @@ -513,10 +477,8 @@ get_bridge_state(i); if (socket[i].flags & IS_CIRRUS) m = cirrus_set_opts(i, buf); -#ifdef CONFIG_ISA else if (socket[i].flags & IS_VADEM) m = vg46x_set_opts(i, buf); -#endif set_bridge_state(i); printk(KERN_INFO " host opts [%d]:%s\n", i, (*buf) ? buf : " none"); @@ -568,8 +530,6 @@ return (irq_hits != 1); } -#ifdef CONFIG_ISA - static u_int __init isa_scan(u_short sock, u_int mask0) { u_int mask1 = 0; @@ -614,8 +574,6 @@ return mask1; } -#endif /* CONFIG_ISA */ - /*====================================================================*/ /* Time conversion functions */ @@ -632,8 +590,6 @@ /*====================================================================*/ -#ifdef CONFIG_ISA - static int __init identify(u_short port, u_short sock) { u_char val; @@ -693,8 +649,6 @@ return type; } /* identify */ -#endif - /*====================================================================== See if a card is present, powered up, in IO mode, and already @@ -738,7 +692,7 @@ static void __init add_pcic(int ns, int type) { u_int mask = 0, i, base; - int use_pci = 0, isa_irq = 0; + int isa_irq = 0; socket_info_t *t = &socket[sockets-ns]; base = sockets-ns; @@ -750,32 +704,25 @@ t->ioaddr, t->psock*0x40); printk(", %d socket%s\n", ns, ((ns > 1) ? "s" : "")); -#ifdef CONFIG_ISA /* Set host options, build basic interrupt mask */ if (irq_list[0] == -1) mask = irq_mask; else for (i = mask = 0; i < 16; i++) mask |= (1< 0; cs_irq--) @@ -788,9 +735,8 @@ printk(" status change on irq %d\n", cs_irq); } } -#endif - if (!use_pci && !isa_irq) { + if (!isa_irq) { if (poll_interval == 0) poll_interval = HZ; printk(" polling interval = %d ms\n", @@ -808,11 +754,8 @@ } /* add_pcic */ - /*====================================================================*/ -#ifdef CONFIG_ISA - #if defined(CONFIG_ISAPNP) || (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE)) #define I82365_ISAPNP #endif @@ -882,7 +825,9 @@ } } } else { - for (i = 0; i < (extra_sockets ? 8 : 4); i += 2) { + for (i = 0; i < 8; i += 2) { + if (sockets && !extra_sockets && (i == 4)) + break; port = i365_base + 2*(i>>2); sock = (i & 3); id = identify(port, sock); @@ -906,8 +851,6 @@ } } -#endif - /*====================================================================*/ static u_int pending_events[8]; @@ -946,17 +889,14 @@ { int i, j, csc; u_int events, active; -#ifdef CONFIG_ISA u_long flags = 0; -#endif DEBUG(4, "i82365: pcic_interrupt(%d)\n", irq); for (j = 0; j < 20; j++) { active = 0; for (i = 0; i < sockets; i++) { - if ((socket[i].cs_irq != irq) && - (socket[i].cap.pci_irq != irq)) + if (socket[i].cs_irq != irq) continue; ISA_LOCK(i, flags); csc = i365_get(i, I365_CSC); @@ -1055,7 +995,6 @@ *value |= (status & I365_CS_READY) ? SS_READY : 0; *value |= (status & I365_CS_POWERON) ? SS_POWERON : 0; -#ifdef CONFIG_ISA if (socket[sock].type == IS_VG469) { status = i365_get(sock, VG469_VSENSE); if (socket[sock].psock & 1) { @@ -1066,7 +1005,6 @@ *value |= (status & VG469_VSENSE_A_VS2) ? 0 : SS_XVCARD; } } -#endif DEBUG(1, "i82365: GetStatus(%d) = %#4.4x\n", sock, *value); return 0; @@ -1160,7 +1098,7 @@ /* IO card, RESET flag, IO interrupt */ reg = t->intr; - if (state->io_irq != t->cap.pci_irq) reg |= state->io_irq; + reg |= state->io_irq; reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET; reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0; i365_set(sock, I365_INTCTL, reg); @@ -1357,8 +1295,7 @@ if ((map > 4) || (mem->card_start > 0x3ffffff) || (mem->sys_start > mem->sys_stop) || (mem->speed > 1000)) return -EINVAL; - if (!(socket[sock].flags & IS_PCI) && - ((mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff))) + if ((mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff)) return -EINVAL; /* Turn off the window before changing anything */ @@ -1417,9 +1354,7 @@ char *p = buf; int i, top; -#ifdef CONFIG_ISA u_long flags = 0; -#endif ISA_LOCK(sock, flags); top = 0x40; for (i = 0; i < top; i += 4) { @@ -1464,15 +1399,8 @@ /*====================================================================*/ -/* - * The locking is rather broken. Why do we only lock for ISA, not for - * all other cases? If there are reasons to lock, we should lock. Not - * this silly conditional. - * - * Plan: make it bug-for-bug compatible with the old stuff, and clean - * it up when the infrastructure is done. - */ -#ifdef CONFIG_ISA +/* this is horribly ugly... proper locking needs to be done here at + * some time... */ #define LOCKED(x) do { \ int retval; \ unsigned long flags; \ @@ -1481,10 +1409,6 @@ spin_unlock_irqrestore(&isa_lock, flags); \ return retval; \ } while (0) -#else -#define LOCKED(x) return x -#endif - static int pcic_get_status(unsigned int sock, u_int *value) { @@ -1595,12 +1519,10 @@ return -1; } DEBUG(0, "%s\n", version); - printk(KERN_INFO "Intel PCIC probe: "); + printk(KERN_INFO "Intel ISA PCIC probe: "); sockets = 0; -#ifdef CONFIG_ISA isa_probe(); -#endif if (sockets == 0) { printk("not found.\n"); @@ -1608,10 +1530,8 @@ } /* Set up interrupt handler(s) */ -#ifdef CONFIG_ISA if (grab_irq != 0) request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt); -#endif if (register_ss_entry(sockets, &pcic_operations) != 0) printk(KERN_NOTICE "i82365: register_ss_entry() failed\n"); @@ -1638,16 +1558,14 @@ unregister_ss_entry(&pcic_operations); if (poll_interval != 0) del_timer(&poll_timer); -#ifdef CONFIG_ISA if (grab_irq != 0) free_irq(cs_irq, pcic_interrupt); -#endif for (i = 0; i < sockets; i++) { /* Turn off all interrupt sources! */ i365_set(i, I365_CSCINT, 0); release_region(socket[i].ioaddr, 2); } -#if defined(CONFIG_ISA) && defined(I82365_ISAPNP) +#if defined(I82365_ISAPNP) if (i82365_pnpdev && i82365_pnpdev->deactivate) i82365_pnpdev->deactivate(i82365_pnpdev); #endif diff -urN linux-2.4.22-bk29/drivers/scsi/nsp32.c linux-2.4.22-bk30/drivers/scsi/nsp32.c --- linux-2.4.22-bk29/drivers/scsi/nsp32.c 2003-06-13 07:51:36.000000000 -0700 +++ linux-2.4.22-bk30/drivers/scsi/nsp32.c 2003-10-07 02:50:34.000000000 -0700 @@ -1,8 +1,8 @@ /* * NinjaSCSI-32Bi Cardbus, NinjaSCSI-32UDE PCI/CardBus SCSI driver - * Copyright (C) 2001, 2002 + * Copyright (C) 2001, 2002, 2003 * YOKOTA Hiroshi - * GOTO Masanori + * GOTO Masanori , * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -13,6 +13,14 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. + * + * + * Revision History: + * 1.0: Initial Release. + * 1.1: Add /proc SDTR status. + * Remove obsolete error handler nsp32_reset. + * Some clean up. + * 1.2: PowerPC (big endian) support. */ #include @@ -25,10 +33,12 @@ #include #include #include -#include +#include +#include #include #include #include +#include #include #include @@ -39,373 +49,327 @@ #include #include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) +# include +#endif + #include "nsp32.h" -static int trans_mode = 0; /* default: BIOS */ -static int auto_param = 0; /* default: ON */ -MODULE_PARM(trans_mode, "i"); -MODULE_PARM(auto_param, "i"); -MODULE_PARM_DESC(trans_mode, "transfer mode (0: BIOS 1: Async 2: Ultra20M"); -MODULE_PARM_DESC(auto_param, "AutoParameter mode (0: ON 1: OFF)"); +/*********************************************************************** + * Module parameters + */ +static int trans_mode = 0; /* default: BIOS */ +MODULE_PARM (trans_mode, "i"); +MODULE_PARM_DESC(trans_mode, "transfer mode (0: BIOS(default) 1: Async 2: Ultra20M"); #define ASYNC_MODE 1 #define ULTRA20M_MODE 2 +static int auto_param = 0; /* default: ON */ +MODULE_PARM (auto_param, "i"); +MODULE_PARM_DESC(auto_param, "AutoParameter mode (0: ON(default) 1: OFF)"); + +static int disc_priv = 1; /* default: OFF */ +MODULE_PARM (disc_priv, "i"); +MODULE_PARM_DESC(disc_priv, "disconnection privilege mode (0: ON 1: OFF(default))"); + MODULE_AUTHOR("YOKOTA Hiroshi , GOTO Masanori "); -MODULE_DESCRIPTION("Workbit NinjaSCSI-32Bi/UDE PCI/CardBus SCSI host bus adapter module"); +MODULE_DESCRIPTION("Workbit NinjaSCSI-32Bi/UDE CardBus/PCI SCSI host bus adapter module"); MODULE_LICENSE("GPL"); -static const char *nsp32_release_version = "1.0"; - - -/* - * structure for DMA/Scatter Gather list - */ -#define AUTOPARAM_SIZE (sizeof(int)*0x15) /* 4x15H = 0x60 */ -#define NSP_SG_SIZE SG_ALL -#define NSP32_SG_END_SGT 0x80000000 /* Last SGT marker */ -#define NSP32_SG_CNT_MASK 0x1FFFF - -struct nsp32_sgtable { - unsigned long addr; /* transfer address */ - unsigned long len; /* transfer length. - Bit (24-32) is for SGT_END */ -}; - -struct nsp32_sglun { - struct nsp32_sgtable sgt[NSP_SG_SIZE+1]; /* SG table */ -}; - - -/* - * host data structure - */ -/* message in/out buffer */ -#define MSGOUTBUF_MAX 13 /* 13 is ok ? */ -#define MSGINBUF_MAX 13 - -/* flag for trans_method */ -#define NSP32_TRANSFER_BUSMASTER BIT(0) -#define NSP32_TRANSFER_MMIO BIT(1) /* Not supported yet */ -#define NSP32_TRANSFER_PIO BIT(2) /* Not supported yet */ - - -/* - * SCSI TARGET/LUN definition - */ -#define NSP32_HOST_SCSIID 7 /* SCSI initiator is everytime defined as 7 */ -#define MAX_TARGET 8 -#define MAX_LUN 8 /* XXX: In SPI3, max number of LUN is 64. */ - +static const char *nsp32_release_version = "1.2"; -/* - * structure for synchronous transfer negotiation data - */ -#define SYNC_NOT_YET 0 -#define SYNC_OK 1 -#define SYNC_NG 2 - -struct nsp32_sync_table { - unsigned char period_num; /* period number */ - unsigned char ackwidth; /* ack width designated by period */ - unsigned char start_period; /* search range - start period */ - unsigned char end_period; /* search range - end period */ -}; - -/* - * structure for target device static data +/**************************************************************************** + * Supported hardware */ -/* flag for nsp32_target.sync_flag */ -#define SDTR_INITIATOR BIT(0) /* sending SDTR from initiator */ -#define SDTR_TARGET BIT(1) /* sending SDTR from target */ -#define SDTR_DONE BIT(2) /* exchanging SDTR has been processed */ - -/* syncronous period value for nsp32_target.config_max */ -#define FAST5M 0x32 -#define FAST10M 0x19 -#define ULTRA20M 0x0c - -/* flag for nsp32_target.{sync_offset}, period */ -#define ASYNC_OFFSET 0 /* asynchronous transfer */ -#define SYNC_OFFSET 0xf /* synchronous transfer max offset */ - -/* syncreg: - 07 06 05 04 03 02 01 00 - ---PERIOD-- ---OFFSET-- */ -#define TO_SYNCREG(period, offset) (period << 4 | offset) - -struct nsp32_target { - unsigned char syncreg; /* value for SYNCREG */ - unsigned char ackwidth; /* value for ACKWIDTH */ - unsigned char offset; /* sync offset (0-15) */ - int sync_flag; /* SDTR_*, 0 */ - int limit_entry; /* max speed limit entry designated - by EEPROM configuration */ +static struct pci_device_id nsp32_pci_table[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_IODATA, + .device = PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = MODEL_IODATA, + }, + { + .vendor = PCI_VENDOR_ID_WORKBIT, + .device = PCI_DEVICE_ID_NINJASCSI_32BI_KME, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = MODEL_KME, + }, + { + .vendor = PCI_VENDOR_ID_WORKBIT, + .device = PCI_DEVICE_ID_NINJASCSI_32BI_WBT, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = MODEL_WORKBIT, + }, + { + .vendor = PCI_VENDOR_ID_WORKBIT, + .device = PCI_DEVICE_ID_WORKBIT_STANDARD, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = MODEL_PCI_WORKBIT, + }, + { + .vendor = PCI_VENDOR_ID_WORKBIT, + .device = PCI_DEVICE_ID_NINJASCSI_32BI_LOGITEC, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = MODEL_LOGITEC, + }, + { + .vendor = PCI_VENDOR_ID_WORKBIT, + .device = PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = MODEL_PCI_LOGITEC, + }, + { + .vendor = PCI_VENDOR_ID_WORKBIT, + .device = PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = MODEL_PCI_MELCO, + }, + { + .vendor = PCI_VENDOR_ID_WORKBIT, + .device = PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO_II, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = MODEL_PCI_MELCO, + }, + {0,0,}, }; +MODULE_DEVICE_TABLE(pci, nsp32_pci_table); -typedef struct _nsp32_hw_data { - int IrqNumber; - int BaseAddress; - int NumAddress; -#define NSP32_MMIO_OFFSET 0x0800 - unsigned long MmioAddress; - unsigned long length; - - Scsi_Cmnd *CurrentSC; - - struct pci_dev *Pci; - const struct pci_device_id *pci_devid; - struct Scsi_Host *Host; - spinlock_t Lock; - - char info_str[100]; - - /* allocated memory region */ - struct nsp32_lunt *lunt_list; /* kmalloc region for lunt */ - struct nsp32_sglun *sg_list; /* sglist virtual address */ - dma_addr_t sgaddr; /* physical address of hw_sg_table */ - unsigned char *autoparam; /* auto parameter transfer region */ - dma_addr_t apaddr; /* physical address of autoparam */ - int cur_entry; /* current sgt entry */ - - /* target/LUN */ - struct nsp32_lunt *curlunt; /* Current connected LUN table */ - struct nsp32_lunt *lunt[MAX_TARGET][MAX_LUN]; /* All LUN table */ - struct nsp32_target *curtarget; /* Current connected SCSI ID */ - struct nsp32_target target[MAX_TARGET]; /* SCSI ID */ - int pid; /* Current connected target ID */ - int plun; /* Current connected target LUN */ - - /* behavior setting parameters */ - int trans_method; /* transfer method flag */ - int resettime; /* Reset time */ - int clock; /* clock dividing flag */ - struct nsp32_sync_table *synct; /* sync_table determined by clock */ - int syncnum; /* the max number of synct element */ - - /* message buffer */ - unsigned char msgoutbuf[MSGOUTBUF_MAX]; /* msgout buffer */ - char msgoutlen; /* msgoutbuf length */ - unsigned char msginbuf[MSGINBUF_MAX]; /* megin buffer */ - char msginlen; /* msginbuf length */ - - -} nsp32_hw_data; static nsp32_hw_data nsp32_data_base; /* probe <-> detect glue */ /* - * TIME definition - */ -#define RESET_HOLD_TIME 10000 /* reset time in us (SCSI-2 says the - minimum is 25us) */ -#define SEL_TIMEOUT_TIME 10000 /* 250ms defined in SCSI specification - (25.6us/1unit) */ -#define ARBIT_TIMEOUT_TIME 100 /* 100us */ -#define REQSACK_TIMEOUT_TIME 10000 /* max wait time for REQ/SACK assertion - or negation, 10000us == 10ms */ - -/* - * structure for connected LUN dynamic data - * - * Note: Currently tagged queuing is disabled, each nsp32_lunt holds - * one SCSI command and one state. - */ -#define DISCPRIV_OK BIT(0) /* DISCPRIV Enable mode */ -#define MSGIN03 BIT(1) /* Auto Msg In 03 Flag */ - -struct nsp32_lunt { - Scsi_Cmnd *SCpnt; /* Current Handling Scsi_Cmnd */ - unsigned long save_datp; /* Save Data Pointer - saved position from initial address */ - int msgin03; /* auto msg in 03 flag */ - unsigned int sg_num; /* Total number of SG entries */ - int cur_entry; /* Current SG entry number */ - struct nsp32_sglun *sglun; /* sg table per lun */ - long sglun_paddr; /* sglun physical address */ -}; - - -/* * Period/AckWidth speed conversion table * * Note: This period/ackwidth speed table must be in descending order. */ -static struct nsp32_sync_table nsp32_sync_table_40M[] = { - /* {PNo, AW, SP, EP} Speed(MB/s) Period AckWidth */ - {0x1, 0, 0x0c, 0x0c}, /* 20.0 : 50ns, 25ns */ - {0x2, 0, 0x0d, 0x18}, /* 13.3 : 75ns, 25ns */ - {0x3, 1, 0x19, 0x19}, /* 10.0 : 100ns, 50ns */ - {0x4, 1, 0x1a, 0x1f}, /* 8.0 : 125ns, 50ns */ - {0x5, 2, 0x20, 0x25}, /* 6.7 : 150ns, 75ns */ - {0x6, 2, 0x26, 0x31}, /* 5.7 : 175ns, 75ns */ - {0x7, 3, 0x32, 0x32}, /* 5.0 : 200ns, 100ns */ - {0x8, 3, 0x33, 0x38}, /* 4.4 : 225ns, 100ns */ - {0x9, 3, 0x39, 0x3e}, /* 4.0 : 250ns, 100ns */ +static nsp32_sync_table nsp32_sync_table_40M[] = { + /* {PNo, AW, SP, EP, SREQ smpl} Speed(MB/s) Period AckWidth */ + {0x1, 0, 0x0c, 0x0c, SMPL_40M}, /* 20.0 : 50ns, 25ns */ + {0x2, 0, 0x0d, 0x18, SMPL_40M}, /* 13.3 : 75ns, 25ns */ + {0x3, 1, 0x19, 0x19, SMPL_40M}, /* 10.0 : 100ns, 50ns */ + {0x4, 1, 0x1a, 0x1f, SMPL_20M}, /* 8.0 : 125ns, 50ns */ + {0x5, 2, 0x20, 0x25, SMPL_20M}, /* 6.7 : 150ns, 75ns */ + {0x6, 2, 0x26, 0x31, SMPL_20M}, /* 5.7 : 175ns, 75ns */ + {0x7, 3, 0x32, 0x32, SMPL_20M}, /* 5.0 : 200ns, 100ns */ + {0x8, 3, 0x33, 0x38, SMPL_10M}, /* 4.4 : 225ns, 100ns */ + {0x9, 3, 0x39, 0x3e, SMPL_10M}, /* 4.0 : 250ns, 100ns */ + {0xa, 3, 0x3f, 0x44, SMPL_10M}, /* 3.64: 275ns, 100ns */ + {0xb, 3, 0x45, 0x4b, SMPL_10M}, /* 3.33: 300ns, 100ns */ + {0xc, 3, 0x4c, 0x53, SMPL_10M}, /* 3.01: 325ns, 100ns */ + {0xd, 3, 0x54, 0x57, SMPL_10M}, /* 2.86: 350ns, 100ns */ + {0xe, 3, 0x58, 0x5d, SMPL_10M}, /* 2.67: 375ns, 100ns */ + {0xf, 3, 0x5e, 0x64, SMPL_10M}, /* 2.5 : 400ns, 100ns */ }; -static const int nsp32_table_40M_num = - sizeof(nsp32_sync_table_40M)/sizeof(struct nsp32_sync_table); -static struct nsp32_sync_table nsp32_sync_table_20M[] = { - {0x1, 0, 0x19, 0x19}, /* 10.0 : 100ns, 50ns */ - {0x2, 0, 0x1a, 0x25}, /* 6.7 : 150ns, 50ns */ - {0x3, 1, 0x26, 0x32}, /* 5.0 : 200ns, 100ns */ - {0x4, 1, 0x33, 0x3e}, /* 4.0 : 250ns, 100ns */ - {0x5, 2, 0x3f, 0x4b}, /* 3.3 : 300ns, 150ns */ - {0x6, 2, 0x4c, 0x57}, /* 2.8 : 350ns, 150ns */ - {0x7, 3, 0x58, 0x64}, /* 2.5 : 400ns, 200ns */ - {0x8, 3, 0x65, 0x70}, /* 2.2 : 450ns, 200ns */ - {0x9, 3, 0x71, 0x7d}, /* 2.0 : 500ns, 200ns */ +static nsp32_sync_table nsp32_sync_table_20M[] = { + {0x1, 0, 0x19, 0x19, SMPL_40M}, /* 10.0 : 100ns, 50ns */ + {0x2, 0, 0x1a, 0x25, SMPL_20M}, /* 6.7 : 150ns, 50ns */ + {0x3, 1, 0x26, 0x32, SMPL_20M}, /* 5.0 : 200ns, 100ns */ + {0x4, 1, 0x33, 0x3e, SMPL_10M}, /* 4.0 : 250ns, 100ns */ + {0x5, 2, 0x3f, 0x4b, SMPL_10M}, /* 3.3 : 300ns, 150ns */ + {0x6, 2, 0x4c, 0x57, SMPL_10M}, /* 2.8 : 350ns, 150ns */ + {0x7, 3, 0x58, 0x64, SMPL_10M}, /* 2.5 : 400ns, 200ns */ + {0x8, 3, 0x65, 0x70, SMPL_10M}, /* 2.2 : 450ns, 200ns */ + {0x9, 3, 0x71, 0x7d, SMPL_10M}, /* 2.0 : 500ns, 200ns */ + {0xa, 3, 0x7e, 0x89, SMPL_10M}, /* 1.82: 550ns, 200ns */ + {0xb, 3, 0x8a, 0x95, SMPL_10M}, /* 1.67: 550ns, 200ns */ + {0xc, 3, 0x96, 0xa2, SMPL_10M}, /* 1.54: 550ns, 200ns */ + {0xd, 3, 0xa3, 0xae, SMPL_10M}, /* 1.43: 550ns, 200ns */ + {0xe, 3, 0xaf, 0xbb, SMPL_10M}, /* 1.33: 550ns, 200ns */ + {0xf, 3, 0xbc, 0xc8, SMPL_10M}, /* 1.25: 550ns, 200ns */ }; -static const int nsp32_table_20M_num = - sizeof(nsp32_sync_table_20M)/sizeof(struct nsp32_sync_table); -static struct nsp32_sync_table nsp32_sync_table_pci[] = { - {0x1, 0, 0x0c, 0x0f}, /* 16.6 : 60ns, 30ns */ - {0x2, 0, 0x10, 0x16}, /* 11.1 : 90ns, 30ns */ - {0x3, 1, 0x17, 0x1e}, /* 8.3 : 120ns, 60ns */ - {0x4, 1, 0x1f, 0x25}, /* 6.7 : 150ns, 60ns */ - {0x5, 2, 0x26, 0x2d}, /* 5.6 : 180ns, 90ns */ - {0x6, 2, 0x2e, 0x34}, /* 4.8 : 210ns, 90ns */ - {0x7, 3, 0x35, 0x3c}, /* 4.2 : 240ns, 120ns */ - {0x8, 3, 0x3d, 0x43}, /* 3.7 : 270ns, 120ns */ - {0x9, 3, 0x44, 0x4b}, /* 3.3 : 300ns, 120ns */ +static nsp32_sync_table nsp32_sync_table_pci[] = { + {0x1, 0, 0x0c, 0x0f, SMPL_40M}, /* 16.6 : 60ns, 30ns */ + {0x2, 0, 0x10, 0x16, SMPL_40M}, /* 11.1 : 90ns, 30ns */ + {0x3, 1, 0x17, 0x1e, SMPL_20M}, /* 8.3 : 120ns, 60ns */ + {0x4, 1, 0x1f, 0x25, SMPL_20M}, /* 6.7 : 150ns, 60ns */ + {0x5, 2, 0x26, 0x2d, SMPL_20M}, /* 5.6 : 180ns, 90ns */ + {0x6, 2, 0x2e, 0x34, SMPL_10M}, /* 4.8 : 210ns, 90ns */ + {0x7, 3, 0x35, 0x3c, SMPL_10M}, /* 4.2 : 240ns, 120ns */ + {0x8, 3, 0x3d, 0x43, SMPL_10M}, /* 3.7 : 270ns, 120ns */ + {0x9, 3, 0x44, 0x4b, SMPL_10M}, /* 3.3 : 300ns, 120ns */ + {0xa, 3, 0x4c, 0x53, SMPL_10M}, /* 3.0 : 330ns, 120ns */ + {0xb, 3, 0x54, 0x59, SMPL_10M}, /* 2.8 : 360ns, 120ns */ + {0xc, 3, 0x5a, 0x60, SMPL_10M}, /* 2.6 : 390ns, 120ns */ + {0xd, 3, 0x61, 0x68, SMPL_10M}, /* 2.4 : 420ns, 120ns */ + {0xe, 3, 0x69, 0x71, SMPL_10M}, /* 2.2 : 450ns, 120ns */ + {0xf, 3, 0x72, 0x77, SMPL_10M}, /* 2.1 : 480ns, 120ns */ }; -static const int nsp32_table_pci_num = - sizeof(nsp32_sync_table_pci)/sizeof(struct nsp32_sync_table); /* * function declaration */ -static int nsp32_detect(Scsi_Host_Template *); -static int nsp32_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -static const char *nsp32_info(struct Scsi_Host *); -static int nsp32_eh_abort(Scsi_Cmnd *); -static int nsp32_eh_bus_reset(Scsi_Cmnd *); -static int nsp32_eh_host_reset(Scsi_Cmnd *); -static int nsp32_reset(Scsi_Cmnd *, unsigned int); -static int nsp32_release(struct Scsi_Host *); -static int nsp32_proc_info(char *, char **, off_t, int, int, int); -static int __devinit nsp32_probe(struct pci_dev *, const struct pci_device_id *); +/* module entry point */ +static int __devinit nsp32_probe (struct pci_dev *, const struct pci_device_id *); static void __devexit nsp32_remove(struct pci_dev *); -static int __init init_nsp32(void); -static void __exit exit_nsp32(void); +static int __init init_nsp32 (void); +static void __exit exit_nsp32 (void); + +/* struct Scsi_Host_Template */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) +static int nsp32_proc_info (struct Scsi_Host *, char *, char **, off_t, int, int); +#else +static int nsp32_proc_info (char *, char **, off_t, int, int, int); +#endif -static void nsp32_message(char *, int, char *, char *, ...); -static void nsp32_dmessage(char *, int, int, char *, ...); -static void nsp32_build_identify(nsp32_hw_data *, Scsi_Cmnd *); -static void nsp32_build_sdtr(nsp32_hw_data *, unsigned char, unsigned char); -static void nsp32_build_nop(nsp32_hw_data *); -static void nsp32_build_reject(nsp32_hw_data *); -static int nsp32hw_start_selection(Scsi_Cmnd *, nsp32_hw_data *); -static int nsp32_selection_autoscsi(Scsi_Cmnd *, nsp32_hw_data *); -static int nsp32_reselection(nsp32_hw_data *, unsigned char); -static int nsp32hw_setup_sg_table(Scsi_Cmnd *, nsp32_hw_data *); -static int nsp32hw_init(struct Scsi_Host *); -static void nsp32_scsi_done(nsp32_hw_data *, Scsi_Cmnd *); -static int nsp32_busfree_occur(nsp32_hw_data *, unsigned short); -static void nsp32_adjust_busfree(nsp32_hw_data *, unsigned int); -static void nsp32_msgout_occur(nsp32_hw_data *); -static void nsp32_restart_autoscsi(nsp32_hw_data *, unsigned short); -static void nsp32_msgin_occur(nsp32_hw_data *, unsigned long, unsigned short); -static void nsp32_analyze_sdtr(nsp32_hw_data *); -static int nsp32_search_period_entry(nsp32_hw_data *,struct nsp32_target *, unsigned char); -static void nsp32_set_async(nsp32_hw_data *, struct nsp32_target *); -static void nsp32_set_max_sync(nsp32_hw_data *, struct nsp32_target *, unsigned char *, unsigned char *); -static void nsp32_set_sync_entry(nsp32_hw_data *, struct nsp32_target *, int, unsigned char); -static void nsp32_wait_req(nsp32_hw_data *, int); -static void nsp32_wait_sack(nsp32_hw_data *, int); -static void nsp32_sack_assert(nsp32_hw_data *); -static void nsp32_sack_negate(nsp32_hw_data *); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) +static int nsp32_detect (struct pci_dev *pdev); +#else +static int nsp32_detect (Scsi_Host_Template *); +#endif +static int nsp32_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +static const char *nsp32_info (struct Scsi_Host *); +static int nsp32_release (struct Scsi_Host *); + +/* SCSI error handler */ +static int nsp32_eh_abort (Scsi_Cmnd *); +static int nsp32_eh_bus_reset (Scsi_Cmnd *); +static int nsp32_eh_host_reset(Scsi_Cmnd *); + +/* generate SCSI message */ +static void nsp32_build_identify(Scsi_Cmnd *); +static void nsp32_build_nop (Scsi_Cmnd *); +static void nsp32_build_reject (Scsi_Cmnd *); +static void nsp32_build_sdtr (Scsi_Cmnd *, unsigned char, unsigned char); + +/* SCSI message handler */ +static int nsp32_busfree_occur(Scsi_Cmnd *, unsigned short); +static void nsp32_msgout_occur (Scsi_Cmnd *); +static void nsp32_msgin_occur (Scsi_Cmnd *, unsigned long, unsigned short); + +static int nsp32_setup_sg_table (Scsi_Cmnd *); +static unsigned long nsp32_msgout_register (Scsi_Cmnd *); +static int nsp32_selection_autopara(Scsi_Cmnd *); +static int nsp32_selection_autoscsi(Scsi_Cmnd *); +static void nsp32_scsi_done (Scsi_Cmnd *); +static int nsp32_arbitration (Scsi_Cmnd *, unsigned int); +static int nsp32_reselection (Scsi_Cmnd *, unsigned char); +static void nsp32_adjust_busfree (Scsi_Cmnd *, unsigned int); +static void nsp32_restart_autoscsi (Scsi_Cmnd *, unsigned short); + +/* SCSI SDTR */ +static void nsp32_analyze_sdtr (Scsi_Cmnd *); +static int nsp32_search_period_entry(nsp32_hw_data *, nsp32_target *, unsigned char); +static void nsp32_set_async (nsp32_hw_data *, nsp32_target *); +static void nsp32_set_max_sync (nsp32_hw_data *, nsp32_target *, unsigned char *, unsigned char *); +static void nsp32_set_sync_entry (nsp32_hw_data *, nsp32_target *, int, unsigned char); + +/* SCSI bus status handler */ +static void nsp32_wait_req (nsp32_hw_data *, int); +static void nsp32_wait_sack (nsp32_hw_data *, int); +static void nsp32_sack_assert (nsp32_hw_data *); +static void nsp32_sack_negate (nsp32_hw_data *); static void nsp32_do_bus_reset(nsp32_hw_data *); -static void do_nsp32_isr(int, void *, struct pt_regs *); -static int nsp32_getprom_param(nsp32_hw_data *); -static int nsp32_getprom_new(nsp32_hw_data *); -static int nsp32_getprom_standard(nsp32_hw_data *); -static int nsp32_prom_read(nsp32_hw_data *, int); -static void nsp32_prom_start(nsp32_hw_data *); -static void nsp32_prom_stop(nsp32_hw_data *); -static void nsp32_prom_write(nsp32_hw_data *, int); -static int nsp32_prom_fetch(nsp32_hw_data *); -static inline void nsp32_prom_set(nsp32_hw_data *, int, int); -static inline int nsp32_prom_get(nsp32_hw_data *, int); +/* hardware interrupt handler */ +static irqreturn_t do_nsp32_isr(int, void *, struct pt_regs *); + +/* initialize hardware */ +static int nsp32hw_init(nsp32_hw_data *); + +/* EEPROM handler */ +static int nsp32_getprom_param (nsp32_hw_data *); +static int nsp32_getprom_at24 (nsp32_hw_data *); +static int nsp32_getprom_c16 (nsp32_hw_data *); +static void nsp32_prom_start (nsp32_hw_data *); +static void nsp32_prom_stop (nsp32_hw_data *); +static int nsp32_prom_read (nsp32_hw_data *, int); +static int nsp32_prom_read_bit (nsp32_hw_data *); +static void nsp32_prom_write_bit(nsp32_hw_data *, int); +static inline void nsp32_prom_set (nsp32_hw_data *, int, int); +static inline int nsp32_prom_get (nsp32_hw_data *, int); +/* debug/warning/info message */ +static void nsp32_message (const char *, int, char *, char *, ...); +#ifdef NSP32_DEBUG +static void nsp32_dmessage(const char *, int, int, char *, ...); +#endif /* * max_sectors is currently limited up to 128. */ -static Scsi_Host_Template driver_template = { - .proc_name = "nsp32", - .name = "Workbit NinjaSCSI-32Bi/UDE", - .proc_info = nsp32_proc_info, - .detect = nsp32_detect, - .info = nsp32_info, - .queuecommand = nsp32_queuecommand, - .can_queue = 1, - .sg_tablesize = NSP_SG_SIZE, - .max_sectors = 128, - .cmd_per_lun = 1, - .this_id = 7, - .use_clustering = DISABLE_CLUSTERING, - .eh_abort_handler = nsp32_eh_abort, - .eh_device_reset_handler = NULL, - .eh_bus_reset_handler = nsp32_eh_bus_reset, - .eh_host_reset_handler = nsp32_eh_host_reset, - .reset = nsp32_reset, - .release = nsp32_release, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2)) - .use_new_eh_code = 1, +static Scsi_Host_Template nsp32_template = { + .proc_name = "nsp32", + .name = "Workbit NinjaSCSI-32Bi/UDE", + .proc_info = nsp32_proc_info, + .info = nsp32_info, + .queuecommand = nsp32_queuecommand, + .can_queue = 1, + .sg_tablesize = NSP32_SG_SIZE, + .max_sectors = 128, + .cmd_per_lun = 1, + .this_id = NSP32_HOST_SCSIID, + .use_clustering = DISABLE_CLUSTERING, + .eh_abort_handler = nsp32_eh_abort, +/* .eh_device_reset_handler = NULL, */ + .eh_bus_reset_handler = nsp32_eh_bus_reset, + .eh_host_reset_handler = nsp32_eh_host_reset, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)) + .detect = nsp32_detect, + .release = nsp32_release, + .use_new_eh_code = 1, #else - /* .highmem_io = 1, */ +/* .highmem_io = 1, */ #endif }; #include "nsp32_io.h" -/* +/*********************************************************************** * debug, error print */ -#define nsp32_msg(type, args...) \ - nsp32_message(__FUNCTION__, __LINE__, (type), ## args) -#define nsp32_dbg(mask, args...) \ - nsp32_dmessage(__FUNCTION__, __LINE__, (mask), ## args) - #ifndef NSP32_DEBUG -# define NSP32_DEBUG_MASK 0x000000 +# define NSP32_DEBUG_MASK 0x000000 +# define nsp32_msg(type, args...) nsp32_message ("", 0, (type), args) +# define nsp32_dbg(mask, args...) /* */ #else -# define NSP32_DEBUG_MASK 0xffffff +# define NSP32_DEBUG_MASK 0xffffff +# define nsp32_msg(type, args...) \ + nsp32_message (__FUNCTION__, __LINE__, (type), args) +# define nsp32_dbg(mask, args...) \ + nsp32_dmessage(__FUNCTION__, __LINE__, (mask), args) #endif -#define NSP32_DEBUG_QUEUECOMMAND 0x000001 -#define NSP32_DEBUG_REGISTER 0x000002 -#define NSP32_DEBUG_AUTOSCSI 0x000004 -#define NSP32_DEBUG_INTR 0x000008 -#define NSP32_DEBUG_SGLIST 0x000010 -#define NSP32_DEBUG_BUSFREE 0x000020 -#define NSP32_DEBUG_CDB_CONTENTS 0x000040 -#define NSP32_DEBUG_RESELECTION 0x000080 -#define NSP32_DEBUG_MSGINOCCUR 0x000100 -#define NSP32_DEBUG_EEPROM 0x000200 -#define NSP32_DEBUG_MSGOUTOCCUR 0x000400 -#define NSP32_DEBUG_BUSRESET 0x000800 -#define NSP32_DEBUG_RESTART 0x001000 -#define NSP32_DEBUG_SYNC 0x002000 -#define NSP32_DEBUG_WAIT 0x004000 -#define NSP32_DEBUG_TARGETFLAG 0x008000 -#define NSP32_DEBUG_PROC 0x010000 -#define NSP32_DEBUG_INIT 0x020000 -#define NSP32_SPECIAL_PRINT_REGISTER 0x100000 +#define NSP32_DEBUG_QUEUECOMMAND BIT(0) +#define NSP32_DEBUG_REGISTER BIT(1) +#define NSP32_DEBUG_AUTOSCSI BIT(2) +#define NSP32_DEBUG_INTR BIT(3) +#define NSP32_DEBUG_SGLIST BIT(4) +#define NSP32_DEBUG_BUSFREE BIT(5) +#define NSP32_DEBUG_CDB_CONTENTS BIT(6) +#define NSP32_DEBUG_RESELECTION BIT(7) +#define NSP32_DEBUG_MSGINOCCUR BIT(8) +#define NSP32_DEBUG_EEPROM BIT(9) +#define NSP32_DEBUG_MSGOUTOCCUR BIT(10) +#define NSP32_DEBUG_BUSRESET BIT(11) +#define NSP32_DEBUG_RESTART BIT(12) +#define NSP32_DEBUG_SYNC BIT(13) +#define NSP32_DEBUG_WAIT BIT(14) +#define NSP32_DEBUG_TARGETFLAG BIT(15) +#define NSP32_DEBUG_PROC BIT(16) +#define NSP32_DEBUG_INIT BIT(17) +#define NSP32_SPECIAL_PRINT_REGISTER BIT(20) #define NSP32_DEBUG_BUF_LEN 100 -static void nsp32_message(char *func, int line, char *type, char *fmt, ...) +static void nsp32_message(const char *func, int line, char *type, char *fmt, ...) { va_list args; char buf[NSP32_DEBUG_BUF_LEN]; va_start(args, fmt); - vsprintf(buf, fmt, args); + vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); #ifndef NSP32_DEBUG @@ -415,19 +379,21 @@ #endif } -static void nsp32_dmessage(char *func, int line, int mask, char *fmt, ...) +#ifdef NSP32_DEBUG +static void nsp32_dmessage(const char *func, int line, int mask, char *fmt, ...) { va_list args; char buf[NSP32_DEBUG_BUF_LEN]; va_start(args, fmt); - vsprintf(buf, fmt, args); + vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); if (mask & NSP32_DEBUG_MASK) { - printk("Ninja: %d %s (%d): %s\n", mask, func, line, buf); + printk("nsp32-debug: 0x%x %s (%d): %s\n", mask, func, line, buf); } } +#endif #ifdef NSP32_DEBUG # include "nsp32_debug.c" @@ -437,56 +403,51 @@ # define show_autophase(arg) /* */ #endif -#ifdef NSP32_DEBUG -static int pc_debug = NSP32_DEBUG; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(/*KERN_DEBUG*/ args) -#else -#define DEBUG(n, args...) -#endif - - /* * IDENTIFY Message */ -static void nsp32_build_identify(nsp32_hw_data *data, Scsi_Cmnd *SCpnt) +static void nsp32_build_identify(Scsi_Cmnd *SCpnt) { - int pos = data->msgoutlen; + nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; + int pos = data->msgout_len; + int mode = FALSE; - data->msgoutbuf[pos++] = - 0x80 | /* Identify */ -#if 0 - /* XXX: Auto DiscPriv detection is progressing... */ - 0x40 | /* DiscPriv */ -#endif - SCpnt->lun; /* LUNTRN */ + /* XXX: Auto DiscPriv detection is progressing... */ + if (disc_priv == 0) { + /* mode = TRUE; */ + } - data->msgoutlen = pos; + data->msgoutbuf[pos] = IDENTIFY(mode, SCpnt->device->lun); pos++; + + data->msgout_len = pos; } /* * SDTR Message Routine */ -static void nsp32_build_sdtr(nsp32_hw_data *data, - unsigned char period, unsigned char offset) -{ - int pos = data->msgoutlen; +static void nsp32_build_sdtr(Scsi_Cmnd *SCpnt, + unsigned char period, + unsigned char offset) +{ + nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; + int pos = data->msgout_len; + + data->msgoutbuf[pos] = EXTENDED_MESSAGE; pos++; + data->msgoutbuf[pos] = EXTENDED_SDTR_LEN; pos++; + data->msgoutbuf[pos] = EXTENDED_SDTR; pos++; + data->msgoutbuf[pos] = period; pos++; + data->msgoutbuf[pos] = offset; pos++; - data->msgoutbuf[pos++] = EXTENDED_MESSAGE; - data->msgoutbuf[pos++] = EXTENDED_SDTR_LEN; - data->msgoutbuf[pos++] = EXTENDED_SDTR; - data->msgoutbuf[pos++] = period; - data->msgoutbuf[pos++] = offset; - - data->msgoutlen = pos; + data->msgout_len = pos; } /* * No Operation Message */ -static void nsp32_build_nop(nsp32_hw_data *data) +static void nsp32_build_nop(Scsi_Cmnd *SCpnt) { - int pos = data->msgoutlen; + nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; + int pos = data->msgout_len; if (pos != 0) { nsp32_msg(KERN_WARNING, @@ -494,54 +455,97 @@ return; } - data->msgoutbuf[pos++] = NOP; - data->msgoutlen = pos; + data->msgoutbuf[pos] = NOP; pos++; + data->msgout_len = pos; } /* * Reject Message */ -static void nsp32_build_reject(nsp32_hw_data *data) +static void nsp32_build_reject(Scsi_Cmnd *SCpnt) { - int pos = data->msgoutlen; + nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; + int pos = data->msgout_len; - data->msgoutbuf[pos++] = MESSAGE_REJECT; - data->msgoutlen = pos; + data->msgoutbuf[pos] = MESSAGE_REJECT; pos++; + data->msgout_len = pos; } /* - * timer + * Start hardware timer */ #if 0 static void nsp32_start_timer(Scsi_Cmnd *SCpnt, int time) { unsigned int base = SCpnt->host->io_port; - DEBUG(0, __func__ " time=%d\n", time); + nsp32_dbg(NSP32_DEBUG_INTR, "timer=%d", time); if (time & (~TIMER_CNT_MASK)) { - printk("timer set overflow\n"); + nsp32_dbg(NSP32_DEBUG_INTR, "timer set overflow"); } nsp32_write2(base, TIMER_SET, time & TIMER_CNT_MASK); } #endif +/* + * Generate msgout register value based on the number of messages. + */ +static unsigned long nsp32_msgout_register(Scsi_Cmnd *SCpnt) +{ + nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; + unsigned long msgout; + int i; + + /* + * message out + * + * Note: If the range of msgout_len is 1 - 3, fill scsi_msgout. + * over 3 messages needs another routine. + */ + if (data->msgout_len > 0 && data->msgout_len <= 3) { + msgout = 0; + for (i = 0; i < data->msgout_len; i++) { + /* + * msgout register layout: + * bit: 31-24 23-16 15-08 07 06-02 01-00 + * MSG#2 MSG#1 MSG#0 MV len + * + * the sending order of the message is: + * len = 3: MSG#0 -> MSG#1 -> MSG#2 + * len = 2: MSG#1 -> MSG#2 + * len = 1: MSG#2 + */ + msgout >>= 8; + msgout |= ((unsigned int)(data->msgoutbuf[i]) << 24); + } + msgout |= MSGOUT_VALID; /* Message out Valid */ + msgout |= data->msgout_len; /* len */ + } else { + /* data->msgout_len > 3 || data->msgout_len <= 0*/ + msgout = 0; + } + + return msgout; +} /* * set SCSI command and other parameter to asic, and start selection phase */ -static int nsp32hw_start_selection(Scsi_Cmnd *SCpnt, nsp32_hw_data *data) +static int nsp32_selection_autopara(Scsi_Cmnd *SCpnt) { - unsigned int host_id = SCpnt->host->this_id; - unsigned int base = SCpnt->host->io_port; - unsigned char target = SCpnt->target; - unsigned char *param = data->autoparam; - unsigned char phase, arbit; - int i, time; - unsigned int msgout; - unsigned long l; - unsigned short s; + nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; + unsigned int base = SCpnt->device->host->io_port; + unsigned int host_id = SCpnt->device->host->this_id; + unsigned char target = SCpnt->device->id; + nsp32_autoparam *param = data->autoparam; + unsigned char phase; + int i, ret; + unsigned long msgout_reg; + unsigned short transfer_reg; + + nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "in"); /* * check bus free @@ -556,155 +560,106 @@ /* * message out - * - * Note: If the range of msgoutlen is 1 - 3, fill scsi_msgout. - * over 3 messages needs another routine. */ - if (data->msgoutlen == 0) { + if (data->msgout_len == 0) { nsp32_msg(KERN_ERR, "SCSI MsgOut without any message!"); SCpnt->result = DID_ERROR << 16; return FALSE; - } else if (data->msgoutlen > 0 && data->msgoutlen <= 3) { - msgout = 0; - for (i=0; imsgoutlen; i++) { - /* - * the sending order of the message is: - * MCNT 3: MSG#0 -> MSG#1 -> MSG#2 - * MCNT 2: MSG#1 -> MSG#2 - * MCNT 1: MSG#2 - */ - msgout >>= 8; - msgout |= (unsigned int)(data->msgoutbuf[i] << 24); - } - msgout |= MV_VALID; /* MV valid */ - msgout |= (unsigned int)data->msgoutlen; /* len */ } else { - /* data->msgoutlen > 3 */ - msgout = 0; + msgout_reg = nsp32_msgout_register(SCpnt); } + // nsp_dbg(NSP32_DEBUG_AUTOSCSI, "sel time out=0x%x\n", nsp32_read2(base, SEL_TIME_OUT)); + // nsp32_write2(base, SEL_TIME_OUT, SEL_TIMEOUT_TIME); + /* * setup asic parameter */ - memset(param, 0, AUTOPARAM_SIZE); + memset(param, 0, sizeof(nsp32_autoparam)); /* cdb */ - for (i=0; icmd_len; i++) { - param[4*i] = SCpnt->cmnd[i]; + for (i = 0; i < SCpnt->cmd_len; i++) { + param->cdb[4 * i] = SCpnt->cmnd[i]; } - /* message out */ - param[4*0x10 +0] = (msgout & 0x000000ff) >> 0; - param[4*0x10 +1] = (msgout & 0x0000ff00) >> 8; - param[4*0x10 +2] = (msgout & 0x00ff0000) >> 16; - param[4*0x10 +3] = (msgout & 0xff000000) >> 24; - - /* syncreg, ackwidth, target id, sampleing rate */ - param[4*0x11 +0] = data->curtarget->syncreg; - param[4*0x11 +1] = data->curtarget->ackwidth; - param[4*0x11 +2] = BIT(host_id) | BIT(target); - param[4*0x11 +3] = 0; + /* outgoing messages */ + param->msgout = cpu_to_le32(msgout_reg); + + /* syncreg, ackwidth, target id, SREQ sampling rate */ + param->syncreg = data->cur_target->syncreg; + param->ackwidth = data->cur_target->ackwidth; + param->target_id = BIT(host_id) | BIT(target); + param->sample_reg = data->cur_target->sample_reg; + + // nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "sample rate=0x%x\n", data->cur_target->sample_reg); /* command control */ - s = (CLEAR_CDB_FIFO_POINTER | AUTOSCSI_START | - AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02 | AUTO_ATN); - param[4*0x12 +0] = (s & 0x00ff) >> 0; - param[4*0x12 +1] = (s & 0xff00) >> 8; + param->command_control = cpu_to_le16(CLEAR_CDB_FIFO_POINTER | + AUTOSCSI_START | + AUTO_MSGIN_00_OR_04 | + AUTO_MSGIN_02 | + AUTO_ATN ); + /* transfer control */ - s = 0; + transfer_reg = 0; switch (data->trans_method) { case NSP32_TRANSFER_BUSMASTER: - s |= BM_START; + transfer_reg |= BM_START; break; case NSP32_TRANSFER_MMIO: - s |= CB_MMIO_MODE; + transfer_reg |= CB_MMIO_MODE; break; case NSP32_TRANSFER_PIO: - s |= CB_IO_MODE; + transfer_reg |= CB_IO_MODE; break; default: nsp32_msg(KERN_ERR, "unknown trans_method"); + break; } /* - * ORed BLIEND_MODE, FIFO intr is decreased, instead of PCI bus waits. + * OR-ed BLIEND_MODE, FIFO intr is decreased, instead of PCI bus waits. * For bus master transfer, it's taken off. */ - s |= (TRANSFER_GO | ALL_COUNTER_CLR); - param[4*0x12 +2] = (s & 0x00ff) >> 0; - param[4*0x12 +3] = (s & 0xff00) >> 8; + transfer_reg |= (TRANSFER_GO | ALL_COUNTER_CLR); + param->transfer_control = cpu_to_le16(transfer_reg); /* sg table addr */ - l = data->curlunt->sglun_paddr; - param[4*0x13 +0] = (l & 0x000000ff) >> 0; - param[4*0x13 +1] = (l & 0x0000ff00) >> 8; - param[4*0x13 +2] = (l & 0x00ff0000) >> 16; - param[4*0x13 +3] = (l & 0xff000000) >> 24; + param->sgt_pointer = cpu_to_le32(data->cur_lunt->sglun_paddr); /* - * transfer parameter to asic + * transfer parameter to ASIC */ - nsp32_write4(base, SGT_ADR, virt_to_bus(param)); + nsp32_write4(base, SGT_ADR, data->auto_paddr); nsp32_write2(base, COMMAND_CONTROL, CLEAR_CDB_FIFO_POINTER | AUTO_PARAMETER ); /* - * Arbitration Status Check - * - * Note: Arbitration counter is wait during ARBIT_GO is not lifting. - * Using udelay(1) consumes CPU time and system time, but - * arbitration delay time is defined minimal 2.4us in SCSI - * specification, thus udelay works as coarse grained wait timer. - */ - time = 0; - do { - arbit = nsp32_read1(base, ARBIT_STATUS); - nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "arbit=0x%x", arbit); - } while ((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 && - (time++ <= 1000)); - - nsp32_dbg(NSP32_DEBUG_AUTOSCSI, - "arbit: 0x%x, delay time: %d", arbit, time); - - if (arbit & ARBIT_WIN) { - SCpnt->result = DID_OK << 16; - /* PCI LED on! */ - nsp32_index_write1(base, EXT_PORT, LED_ON); - } else if (arbit & ARBIT_FAIL) { - SCpnt->result = DID_BUS_BUSY << 16; - nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR); - return FALSE; - } else { - /* unknown error or ARBIT_GO timeout */ - nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "arbit fail"); - SCpnt->result = DID_NO_CONNECT << 16; - nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR); - return FALSE; - } - - /* - * clear Arbit + * Check arbitration */ - nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR); + ret = nsp32_arbitration(SCpnt, base); - return TRUE; + return ret; } /* * Selection with AUTO SCSI (without AUTO PARAMETER) */ -static int nsp32_selection_autoscsi(Scsi_Cmnd *SCpnt, nsp32_hw_data *data) +static int nsp32_selection_autoscsi(Scsi_Cmnd *SCpnt) { + nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; + unsigned int base = SCpnt->device->host->io_port; + unsigned int host_id = SCpnt->device->host->this_id; + unsigned char target = SCpnt->device->id; unsigned char phase; - unsigned char arbit; int status; - int i; unsigned short command = 0; - int time = 0; - unsigned int msgout = 0; + unsigned long msgout = 0; unsigned short execph; - unsigned int base = data->BaseAddress; + int i; + + nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "in"); /* * IRQ disable @@ -715,8 +670,7 @@ * check bus line */ phase = nsp32_read1(base, SCSI_BUS_MONITOR); - if(((phase & BUSMON_BSY) == 1) || - (phase & BUSMON_SEL) == 1) { + if(((phase & BUSMON_BSY) == 1) || (phase & BUSMON_SEL) == 1) { nsp32_msg(KERN_WARNING, "bus busy"); SCpnt->result = DID_BUS_BUSY << 16; status = 1; @@ -736,95 +690,75 @@ /* * set CDB0 - CDB15 */ - for (i=0; icmd_len; i++) { + for (i = 0; i < SCpnt->cmd_len; i++) { nsp32_write1(base, COMMAND_DATA, SCpnt->cmnd[i]); } - nsp32_dbg(NSP32_DEBUG_CDB_CONTENTS, "CDB[0]=[0x%x]", SCpnt->cmnd[i]); + nsp32_dbg(NSP32_DEBUG_CDB_CONTENTS, "CDB[0]=[0x%x]", SCpnt->cmnd[0]); /* - * set SCSIOUT LATCH(initiator)/TARGET(target) (ORed) ID + * set SCSIOUT LATCH(initiator)/TARGET(target) (OR-ed) ID */ - nsp32_write1(base, SCSI_OUT_LATCH_TARGET_ID, - ((1 << NSP32_HOST_SCSIID) | (1 << SCpnt->target))); + nsp32_write1(base, SCSI_OUT_LATCH_TARGET_ID, BIT(host_id) | BIT(target)); /* * set SCSI MSGOUT REG - * - * Note: If the range of msgoutlen is 1 - 3, fill scsi_msgout. - * over 3 messages needs another routine. */ - if (data->msgoutlen == 0) { - nsp32_msg(KERN_ERR, - "SCSI MsgOut without any message!"); + if (data->msgout_len == 0) { + nsp32_msg(KERN_ERR, "SCSI MsgOut without any message!"); SCpnt->result = DID_ERROR << 16; status = 1; goto out; - } else if (data->msgoutlen > 0 && data->msgoutlen <= 3) { - msgout = 0; - for (i=0; imsgoutlen; i++) { - /* - * the sending order of the message is: - * MCNT 3: MSG#0 -> MSG#1 -> MSG#2 - * MCNT 2: MSG#1 -> MSG#2 - * MCNT 1: MSG#2 - */ - msgout >>= 8; - msgout |= (unsigned int)(data->msgoutbuf[i] << 24); - } - msgout |= MV_VALID; /* MV valid */ - msgout |= (unsigned int)data->msgoutlen; /* len */ - nsp32_write4(base, SCSI_MSG_OUT, msgout); } else { - /* data->msgoutlen > 3 */ - nsp32_write4(base, SCSI_MSG_OUT, 0); + msgout = nsp32_msgout_register(SCpnt); + nsp32_write4(base, SCSI_MSG_OUT, msgout); } /* * set selection timeout(= 250ms) */ - nsp32_write2(base, SEL_TIME_OUT, SEL_TIMEOUT_TIME); + nsp32_write2(base, SEL_TIME_OUT, SEL_TIMEOUT_TIME); /* - * set smpl rate + * set SREQ hazard killer sampling rate * - * TODO: smpl_rate (BASE+0F) is 0 when internal clock = 40MHz. + * TODO: sample_rate (BASE+0F) is 0 when internal clock = 40MHz. * check other internal clock! */ - nsp32_write1(base, SREQ_SMPL_RATE, 0); + nsp32_write1(base, SREQ_SMPL_RATE, data->cur_target->sample_reg); /* * clear Arbit */ - nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR); + nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR); /* * set SYNCREG * Don't set BM_START_ADR before setting this register. */ - nsp32_write1(base, SYNC_REG, data->curtarget->syncreg); + nsp32_write1(base, SYNC_REG, data->cur_target->syncreg); /* * set ACKWIDTH */ - nsp32_write1(base, ACK_WIDTH, data->curtarget->ackwidth); + nsp32_write1(base, ACK_WIDTH, data->cur_target->ackwidth); nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "syncreg=0x%x, ackwidth=0x%x, sgtpaddr=0x%x, id=0x%x", nsp32_read1(base, SYNC_REG), nsp32_read1(base, ACK_WIDTH), nsp32_read4(base, SGT_ADR), nsp32_read1(base, SCSI_OUT_LATCH_TARGET_ID)); - nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "msgoutlen=%d, msgout=0x%x", - data->msgoutlen, msgout); + nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "msgout_len=%d, msgout=0x%x", + data->msgout_len, msgout); /* * set SGT ADDR (physical address) */ - nsp32_write4(base, SGT_ADR, data->curlunt->sglun_paddr); + nsp32_write4(base, SGT_ADR, data->cur_lunt->sglun_paddr); /* * set TRANSFER CONTROL REG */ command = 0; - command |= ( TRANSFER_GO | ALL_COUNTER_CLR); + command |= (TRANSFER_GO | ALL_COUNTER_CLR); if (data->trans_method & NSP32_TRANSFER_BUSMASTER) { if (SCpnt->request_bufflen > 0) { command |= BM_START; @@ -839,73 +773,75 @@ /* * start AUTO SCSI, kick off arbitration */ - command = 0; - command |= (CLEAR_CDB_FIFO_POINTER - | AUTOSCSI_START - | AUTO_MSGIN_00_OR_04 - | AUTO_MSGIN_02 - | AUTO_ATN); + command = (CLEAR_CDB_FIFO_POINTER | + AUTOSCSI_START | + AUTO_MSGIN_00_OR_04 | + AUTO_MSGIN_02 | + AUTO_ATN ); nsp32_write2(base, COMMAND_CONTROL, command); /* - * Arbitration Status Check - * - * Note: Arbitration counter is wait during ARBIT_GO is not lifting. - * Using udelay(1) consumes CPU time and system time, but - * arbitration delay time is defined minimal 2.4us in SCSI - * specification, thus udelay works as coarse grained wait timer. + * Check arbitration */ - time = 0; - while(1) { - arbit = nsp32_read1(base, ARBIT_STATUS); - if(arbit & ARBIT_GO) { - udelay(1); - time++; - if ( time > ARBIT_TIMEOUT_TIME ) { - /* something lock up! guess no connection */ - SCpnt->result = DID_NO_CONNECT << 16; - status = FALSE; - goto out; - } - } else { - break; - } - }; - - nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "arbit: 0x%x, delay time: %d", arbit, time); + status = nsp32_arbitration(SCpnt, base); + out: /* - * check Arbitration Status Result + * IRQ enable */ - if(arbit & ARBIT_WIN) { + nsp32_write2(base, IRQ_CONTROL, 0); + + return status; +} + + +/* + * Arbitration Status Check + * + * Note: Arbitration counter is waited during ARBIT_GO is not lifting. + * Using udelay(1) consumes CPU time and system time, but + * arbitration delay time is defined minimal 2.4us in SCSI + * specification, thus udelay works as coarse grained wait timer. + */ +static int nsp32_arbitration(Scsi_Cmnd *SCpnt, unsigned int base) +{ + unsigned char arbit; + int status = TRUE; + int time = 0; + + do { + arbit = nsp32_read1(base, ARBIT_STATUS); + time++; + } while ((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 && + (time <= ARBIT_TIMEOUT_TIME)); + + nsp32_dbg(NSP32_DEBUG_AUTOSCSI, + "arbit: 0x%x, delay time: %d", arbit, time); + + if (arbit & ARBIT_WIN) { /* Arbitration succeeded */ - status = TRUE; SCpnt->result = DID_OK << 16; - /* PCI LED on! */ - nsp32_index_write1(base, EXT_PORT, LED_ON); - } else if(arbit & ARBIT_FAIL) { + nsp32_index_write1(base, EXT_PORT, LED_ON); /* PCI LED on */ + } else if (arbit & ARBIT_FAIL) { /* Arbitration failed */ - status = FALSE; SCpnt->result = DID_BUS_BUSY << 16; - } else { - /* unknown error? */ status = FALSE; - SCpnt->result = DID_ERROR << 16; + } else { + /* + * unknown error or ARBIT_GO timeout, + * something lock up! guess no connection. + */ + nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "arbit timeout"); SCpnt->result = DID_NO_CONNECT << 16; - } + status = FALSE; + } /* * clear Arbit */ nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR); - out: - /* - * IRQ enable - */ - nsp32_write2(base, IRQ_CONTROL, 0); - - return(status); + return status; } @@ -916,10 +852,12 @@ * reselection target id&lun must be already set. * SCSI-2 says IDENTIFY implies RESTORE_POINTER operation. */ -static int nsp32_reselection(nsp32_hw_data *data, unsigned char newlun) +static int nsp32_reselection(Scsi_Cmnd *SCpnt, unsigned char newlun) { - unsigned int base = data->BaseAddress; - unsigned char tmpid, newid; + nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; + unsigned int host_id = SCpnt->device->host->this_id; + unsigned int base = SCpnt->device->host->io_port; + unsigned char tmpid, newid; nsp32_dbg(NSP32_DEBUG_RESELECTION, "enter"); @@ -927,7 +865,7 @@ * calculate reselected SCSI ID */ tmpid = nsp32_read1(base, RESELECT_ID); - tmpid &= 0x7f; + tmpid &= (~BIT(host_id)); newid = 0; while (tmpid) { if (tmpid & 1) { @@ -940,20 +878,20 @@ /* * If reselected New ID:LUN is not existed * or current nexus is not existed, unexpected - * reselection is occured. Send reject message. + * reselection is occurred. Send reject message. */ - if (newid >= MAX_TARGET || newlun >= MAX_LUN) { + if (newid >= NUMBER(data->lunt) || newlun >= NUMBER(data->lunt[0])) { nsp32_msg(KERN_WARNING, "unknown id/lun"); return FALSE; - } else if(data->lunt[newid][newlun]->SCpnt == NULL) { + } else if(data->lunt[newid][newlun].SCpnt == NULL) { nsp32_msg(KERN_WARNING, "no SCSI command is processing"); return FALSE; } - data->pid = newid; - data->plun = newlun; - data->curtarget = &data->target[newid]; - data->curlunt = data->lunt[newid][newlun]; + data->cur_id = newid; + data->cur_lun = newlun; + data->cur_target = &(data->target[newid]); + data->cur_lunt = &(data->lunt[newid][newlun]); /* reset SACK/SavedACK counter (or ALL clear?) */ nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK); @@ -963,16 +901,18 @@ /* - * nsp32hw_setup_sg_table - build scatter gather list for transfer data + * nsp32_setup_sg_table - build scatter gather list for transfer data * with bus master. * * Note: NinjaSCSI-32Bi/UDE bus master can not transfer over 64KB at a time. */ -static int nsp32hw_setup_sg_table(Scsi_Cmnd *SCpnt, nsp32_hw_data *data) +static int nsp32_setup_sg_table(Scsi_Cmnd *SCpnt) { - struct scatterlist *sgl; - struct nsp32_sgtable *sgt = data->curlunt->sglun->sgt; + nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; + struct scatterlist *sgl; + nsp32_sgtable *sgt = data->cur_lunt->sglun->sgt; int num, i; + u32 l; if (SCpnt->request_bufflen == 0) { return TRUE; @@ -987,7 +927,7 @@ sgl = (struct scatterlist *)SCpnt->request_buffer; num = pci_map_sg(data->Pci, sgl, SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); - for (i=0; i 65536) { + if (le32_to_cpu(sgt[i].len) > 0x10000) { nsp32_msg(KERN_ERR, - "can't transfer over 64KB at a time"); + "can't transfer over 64KB at a time, size=0x%lx", le32_to_cpu(sgt[i].len)); return FALSE; } nsp32_dbg(NSP32_DEBUG_SGLIST, - "num 0x%x : addr 0x%lx len 0x%x", - i, sgt[i].addr, sgt[i].len); + "num 0x%x : addr 0x%lx len 0x%lx", + i, + le32_to_cpu(sgt[i].addr), + le32_to_cpu(sgt[i].len )); } - sgt[num-1].len |= NSP32_SG_END_SGT; /* set end mark */ + + /* set end mark */ + l = le32_to_cpu(sgt[num-1].len); + sgt[num-1].len = cpu_to_le32(l | SGTEND); + } else { SCpnt->SCp.have_data_in = pci_map_single(data->Pci, SCpnt->request_buffer, SCpnt->request_bufflen, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + sgt[0].addr = cpu_to_le32(SCpnt->SCp.have_data_in); - sgt[0].len = cpu_to_le32(SCpnt->request_bufflen); - sgt[0].len |= NSP32_SG_END_SGT; /* set end mark */ + sgt[0].len = cpu_to_le32(SCpnt->request_bufflen | SGTEND); /* set end mark */ - nsp32_dbg(NSP32_DEBUG_SGLIST, "single : addr 0x%lx len=0x%x", - sgt[0].addr, sgt[0].len); + if (SCpnt->request_bufflen > 0x10000) { + nsp32_msg(KERN_ERR, + "can't transfer over 64KB at a time, size=0x%lx", SCpnt->request_bufflen); + return FALSE; + } + nsp32_dbg(NSP32_DEBUG_SGLIST, "single : addr 0x%lx len=0x%lx", + le32_to_cpu(sgt[0].addr), + le32_to_cpu(sgt[0].len )); } return TRUE; @@ -1022,38 +974,40 @@ static int nsp32_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->host->hostdata; - struct nsp32_target *target; - struct nsp32_lunt *curlunt; + nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; + nsp32_target *target; + nsp32_lunt *cur_lunt; int ret; nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "enter. target: 0x%x LUN: 0x%x cmnd: 0x%x cmndlen: 0x%x " "use_sg: 0x%x reqbuf: 0x%lx reqlen: 0x%x", - SCpnt->target, SCpnt->lun, SCpnt->cmnd[0], SCpnt->cmd_len, + SCpnt->device->id, SCpnt->device->lun, SCpnt->cmnd[0], SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_buffer, SCpnt->request_bufflen); - if (data->CurrentSC != NULL ) { + if (data->CurrentSC != NULL) { nsp32_msg(KERN_ERR, "Currentsc != NULL. Cancel this command request"); data->CurrentSC = NULL; SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); - return 1; + return SCSI_MLQUEUE_HOST_BUSY; } /* check target ID is not same as this initiator ID */ - if (SCpnt->target == NSP32_HOST_SCSIID) { + if (SCpnt->device->id == SCpnt->device->host->this_id) { + nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "terget==host???"); SCpnt->result = DID_BAD_TARGET << 16; done(SCpnt); - return 1; + return SCSI_MLQUEUE_DEVICE_BUSY; } /* check target LUN is allowable value */ - if (SCpnt->lun >= MAX_LUN) { + if (SCpnt->device->lun >= MAX_LUN) { + nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "no more lun"); SCpnt->result = DID_BAD_TARGET << 16; done(SCpnt); - return 1; + return SCSI_MLQUEUE_DEVICE_BUSY; } show_command(SCpnt); @@ -1062,7 +1016,7 @@ data->CurrentSC = SCpnt; SCpnt->SCp.Status = CHECK_CONDITION; SCpnt->SCp.Message = 0; - SCpnt->resid = 0; //SCpnt->request_bufflen; + SCpnt->resid = SCpnt->request_bufflen; SCpnt->SCp.ptr = (char *) SCpnt->request_buffer; SCpnt->SCp.this_residual = SCpnt->request_bufflen; @@ -1070,39 +1024,41 @@ SCpnt->SCp.buffers_residual = 0; /* initialize data */ - data->msgoutlen = 0; - data->msginlen = 0; - curlunt = data->lunt[SCpnt->target][SCpnt->lun]; - curlunt->SCpnt = SCpnt; - curlunt->save_datp = 0; - curlunt->msgin03 = FALSE; - data->curlunt = curlunt; - data->pid = SCpnt->target; - data->plun = SCpnt->lun; + data->msgout_len = 0; + data->msgin_len = 0; + cur_lunt = &(data->lunt[SCpnt->device->id][SCpnt->device->lun]); + cur_lunt->SCpnt = SCpnt; + cur_lunt->save_datp = 0; + cur_lunt->msgin03 = FALSE; + data->cur_lunt = cur_lunt; + data->cur_id = SCpnt->device->id; + data->cur_lun = SCpnt->device->lun; - ret = nsp32hw_setup_sg_table(SCpnt, data); + ret = nsp32_setup_sg_table(SCpnt); if (ret == FALSE) { + nsp32_msg(KERN_ERR, "SGT fail"); SCpnt->result = DID_ERROR << 16; - nsp32_scsi_done(data, SCpnt); + nsp32_scsi_done(SCpnt); + return SCSI_MLQUEUE_HOST_BUSY; } /* Build IDENTIFY */ - nsp32_build_identify(data, SCpnt); + nsp32_build_identify(SCpnt); /* * If target is the first time to transfer after the reset * (target don't have SDTR_DONE and SDTR_INITIATOR), sync * message SDTR is needed to do synchronous transfer. */ - target = &data->target[SCpnt->target]; - data->curtarget = target; + target = &data->target[SCpnt->device->id]; + data->cur_target = target; if (!(target->sync_flag & (SDTR_DONE | SDTR_INITIATOR | SDTR_TARGET))) { unsigned char period, offset; if (trans_mode != ASYNC_MODE) { nsp32_set_max_sync(data, target, &period, &offset); - nsp32_build_sdtr(data, period, offset); + nsp32_build_sdtr(SCpnt, period, offset); target->sync_flag |= SDTR_INITIATOR; } else { nsp32_set_async(data, target); @@ -1140,32 +1096,32 @@ nsp32_dbg(NSP32_DEBUG_TARGETFLAG, "target: %d sync_flag: 0x%x syncreg: 0x%x ackwidth: 0x%x", - SCpnt->target, target->sync_flag, target->syncreg, + SCpnt->device->id, target->sync_flag, target->syncreg, target->ackwidth); /* Selection */ if (auto_param == 0) { - ret = nsp32hw_start_selection(SCpnt, data); + ret = nsp32_selection_autopara(SCpnt); } else { - ret = nsp32_selection_autoscsi(SCpnt, data); + ret = nsp32_selection_autoscsi(SCpnt); } if (ret != TRUE) { - nsp32_scsi_done(data, SCpnt); - return 1; + nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "selection fail"); + nsp32_scsi_done(SCpnt); + return SCSI_MLQUEUE_DEVICE_BUSY; } return 0; } /* initialize asic */ -static int nsp32hw_init(struct Scsi_Host *host) +static int nsp32hw_init(nsp32_hw_data *data) { - unsigned int base = host->io_port; + unsigned int base = data->BaseAddress; unsigned short irq_stat; - unsigned long lc_reg; - unsigned char power; - nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata; + unsigned long lc_reg; + unsigned char power; lc_reg = nsp32_index_read4(base, CFG_LATE_CACHE); if ((lc_reg & 0xff00) == 0) { @@ -1173,15 +1129,15 @@ nsp32_index_write2(base, CFG_LATE_CACHE, lc_reg & 0xffff); } - nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK); - nsp32_write2(base, TRANSFER_CONTROL, 0); - nsp32_write4(base, BM_CNT, 0); + nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK); + nsp32_write2(base, TRANSFER_CONTROL, 0); + nsp32_write4(base, BM_CNT, 0); nsp32_write2(base, SCSI_EXECUTE_PHASE, 0); do { irq_stat = nsp32_read2(base, IRQ_STATUS); + nsp32_dbg(NSP32_DEBUG_INIT, "irq_stat 0x%x", irq_stat); } while (irq_stat & IRQSTATUS_ANY_IRQ); - nsp32_dbg(NSP32_DEBUG_INIT, "irq_stat 0x%x", irq_stat); /* * Fill FIFO_FULL_SHLD, FIFO_EMPTY_SHLD. Below parameter is @@ -1189,22 +1145,25 @@ */ if ((data->trans_method & NSP32_TRANSFER_PIO) || (data->trans_method & NSP32_TRANSFER_MMIO)) { - nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT, 0x40); + nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT, 0x40); + nsp32_index_write1(base, FIFO_EMPTY_SHLD_COUNT, 0x40); } else if (data->trans_method & NSP32_TRANSFER_BUSMASTER) { - nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT, 0x10); + nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT, 0x10); + nsp32_index_write1(base, FIFO_EMPTY_SHLD_COUNT, 0x60); + } else { + nsp32_dbg(NSP32_DEBUG_INIT, "unknown transfer mode"); } - nsp32_index_write1(base, FIFO_EMPTY_SHLD_COUNT, 0x60); nsp32_dbg(NSP32_DEBUG_INIT, "full 0x%x emp 0x%x", nsp32_index_read1(base, FIFO_FULL_SHLD_COUNT), nsp32_index_read1(base, FIFO_EMPTY_SHLD_COUNT)); nsp32_index_write1(base, CLOCK_DIV, data->clock); - nsp32_index_write1(base, BM_CYCLE, MEMRD_CMD1 | SGT_AUTO_PARA_MEMED_CMD); + nsp32_index_write1(base, BM_CYCLE, MEMRD_CMD1 | SGT_AUTO_PARA_MEMED_CMD); nsp32_write1(base, PARITY_CONTROL, 0); /* parity check is disable */ /* - * initialize I_MISC_WRRD register + * initialize MISC_WRRD register * * Note: Designated parameters is obeyed as following: * MISC_SCSI_DIRECTION_DETECTOR_SELECT: It must be set. @@ -1220,10 +1179,10 @@ */ nsp32_index_write2(base, MISC_WR, (SCSI_DIRECTION_DETECTOR_SELECT | - DELAYED_BMSTART | - MASTER_TERMINATION_SELECT | - BMREQ_NEGATE_TIMING_SEL | - AUTOSEL_TIMING_SEL | + DELAYED_BMSTART | + MASTER_TERMINATION_SELECT | + BMREQ_NEGATE_TIMING_SEL | + AUTOSEL_TIMING_SEL | BMSTOP_CHANGE2_NONDATA_PHASE)); nsp32_index_write1(base, TERM_PWR_CONTROL, 0); @@ -1234,11 +1193,11 @@ } nsp32_write2(base, TIMER_SET, TIMER_STOP); - nsp32_write2(base, TIMER_SET, TIMER_STOP); + nsp32_write2(base, TIMER_SET, TIMER_STOP); /* Required 2 times */ - nsp32_write1(base, SYNC_REG, 0); - nsp32_write1(base, ACK_WIDTH, 0); - nsp32_write2(base, SEL_TIME_OUT, 10000); /* 25us x10000 = 250ms defined in SCSI */ + nsp32_write1(base, SYNC_REG, 0); + nsp32_write1(base, ACK_WIDTH, 0); + nsp32_write2(base, SEL_TIME_OUT, SEL_TIMEOUT_TIME); /* * enable to select designated IRQ (except for @@ -1250,21 +1209,21 @@ IRQSELECT_RESELECT_IRQ | IRQSELECT_PHASE_CHANGE_IRQ | IRQSELECT_AUTO_SCSI_SEQ_IRQ | - //IRQSELECT_BMCNTERR_IRQ | + // IRQSELECT_BMCNTERR_IRQ | IRQSELECT_TARGET_ABORT_IRQ | IRQSELECT_MASTER_ABORT_IRQ ); nsp32_write2(base, IRQ_CONTROL, 0); /* PCI LED off */ nsp32_index_write1(base, EXT_PORT_DDR, LED_OFF); - nsp32_index_write1(base, EXT_PORT, LED_OFF); + nsp32_index_write1(base, EXT_PORT, LED_OFF); return TRUE; } /* interrupt routine */ -static void do_nsp32_isr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t do_nsp32_isr(int irq, void *dev_id, struct pt_regs *regs) { nsp32_hw_data *data = dev_id; unsigned int base = data->BaseAddress; @@ -1273,13 +1232,9 @@ unsigned char busmon, busphase; unsigned long flags; int ret; + int handled = 0; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) - struct Scsi_Host *host = data->Host; - spin_lock_irqsave(host->host_lock, flags); -#else - spin_lock_irqsave(&io_request_lock, flags); -#endif + spin_lock_irqsave(HOST_LOCK, flags); /* * IRQ check, then enable IRQ mask @@ -1289,9 +1244,10 @@ "enter IRQ: %d, IRQstatus: 0x%x", irq, irq_stat); /* is this interrupt comes from Ninja asic? */ if ((irq_stat & IRQSTATUS_ANY_IRQ) == 0) { - nsp32_msg(KERN_INFO, "spurious interrupt: irq other 0x%x", irq_stat); + nsp32_dbg(NSP32_DEBUG_INTR, "shared interrupt: irq other 0x%x", irq_stat); goto out2; } + handled = 1; nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK); busmon = nsp32_read1(base, SCSI_BUS_MONITOR); @@ -1303,14 +1259,14 @@ if (data->CurrentSC != NULL) { nsp32_msg(KERN_INFO, "clean up current SCSI command"); SCpnt->result = DID_BAD_TARGET << 16; - nsp32_scsi_done(data, SCpnt); + nsp32_scsi_done(SCpnt); } goto out; } /* Timer IRQ */ if (irq_stat & IRQSTATUS_TIMER_IRQ) { - DEBUG(0, "timer stop\n"); + nsp32_dbg(NSP32_DEBUG_INTR, "timer stop"); nsp32_write2(base, TIMER_SET, TIMER_STOP); goto out; } @@ -1321,20 +1277,20 @@ nsp32_do_bus_reset(data); if (SCpnt != NULL) { SCpnt->result = DID_RESET << 16; - nsp32_scsi_done(data, SCpnt); + nsp32_scsi_done(SCpnt); } goto out; } - + if (SCpnt == NULL) { - nsp32_msg(KERN_WARNING, "SCpnt==NULL this can't be happen\n"); - nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x\n", irq_stat, trans_stat); + nsp32_msg(KERN_WARNING, "SCpnt==NULL this can't be happened"); + nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat); goto out; } /* * AutoSCSI Interrupt. - * Note: This interrupt is occured when AutoSCSI is finished. Then + * Note: This interrupt is occurred when AutoSCSI is finished. Then * check SCSIEXECUTEPHASE, and do appropriate action. Each phases are * recorded when AutoSCSI sequencer has been processed. */ @@ -1346,10 +1302,10 @@ /* Selection Timeout, go busfree phase. */ if (auto_stat & SELECTION_TIMEOUT) { nsp32_dbg(NSP32_DEBUG_INTR, - "selection timeout occured"); + "selection timeout occurred"); SCpnt->result = DID_TIME_OUT << 16; - nsp32_scsi_done(data, SCpnt); + nsp32_scsi_done(SCpnt); goto out; } @@ -1357,17 +1313,17 @@ /* * MsgOut phase was processed. * If MSG_IN_OCCUER is not set, then MsgOut phase is - * completed. Thus, msgoutlen must reset. Otherwise, - * nothing to do here. If MSG_OUT_OCCUER is occured, + * completed. Thus, msgout_len must reset. Otherwise, + * nothing to do here. If MSG_OUT_OCCUER is occurred, * then we will encounter the condition and check. */ if (!(auto_stat & MSG_IN_OCCUER) && - (data->msgoutlen <= 3)) { + (data->msgout_len <= 3)) { /* - * !MSG_IN_OCCUER && msgoutlen <=3 + * !MSG_IN_OCCUER && msgout_len <=3 * ---> AutoSCSI with MSGOUTreg is processed. */ - data->msgoutlen = 0; + data->msgout_len = 0; }; nsp32_dbg(NSP32_DEBUG_INTR, "MsgOut phase processed"); @@ -1394,28 +1350,29 @@ nsp32_read4(base, SACK_CNT)); nsp32_dbg(NSP32_DEBUG_INTR, "SSACK=0x%lx", nsp32_read4(base, SAVED_SACK_CNT)); - + + SCpnt->resid = 0; /* all data transfered! */ } /* * MsgIn Occur */ if (auto_stat & MSG_IN_OCCUER) { - nsp32_msgin_occur(data, irq_stat, auto_stat); + nsp32_msgin_occur(SCpnt, irq_stat, auto_stat); } /* * MsgOut Occur */ if (auto_stat & MSG_OUT_OCCUER) { - nsp32_msgout_occur(data); + nsp32_msgout_occur(SCpnt); } /* * Bus Free Occur */ if (auto_stat & BUS_FREE_OCCUER) { - ret = nsp32_busfree_occur(data, auto_stat); + ret = nsp32_busfree_occur(SCpnt, auto_stat); if (ret == TRUE) { goto out; } @@ -1466,28 +1423,28 @@ switch(busphase) { case BUSPHASE_DATA_OUT: - printk( "write\n"); + nsp32_dbg(NSP32_DEBUG_INTR, "fifo/write"); //nsp32_pio_write(SCpnt); break; case BUSPHASE_DATA_IN: - printk( "read\n"); + nsp32_dbg(NSP32_DEBUG_INTR, "fifo/read"); //nsp32_pio_read(SCpnt); break; case BUSPHASE_STATUS: - //DEBUG(0, "fifo/status\n"); + nsp32_dbg(NSP32_DEBUG_INTR, "fifo/status"); SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN); break; default: - printk("fifo/other phase?\n"); - printk("irq_stat=0x%x trans_stat=0x%x\n", irq_stat, trans_stat); + nsp32_dbg(NSP32_DEBUG_INTR, "fifo/other phase"); + nsp32_dbg(NSP32_DEBUG_INTR, "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat); show_busphase(busphase); break; } @@ -1502,7 +1459,7 @@ switch(busphase) { case BUSPHASE_MESSAGE_IN: nsp32_dbg(NSP32_DEBUG_INTR, "phase chg/msg in"); - nsp32_msgin_occur(data, irq_stat, 0); + nsp32_msgin_occur(SCpnt, irq_stat, 0); break; default: nsp32_msg(KERN_WARNING, "phase chg/other phase?"); @@ -1516,7 +1473,7 @@ /* PCI_IRQ */ if (irq_stat & IRQSTATUS_PCI_IRQ) { - nsp32_dbg(NSP32_DEBUG_INTR, "PCI IRQ occured"); + nsp32_dbg(NSP32_DEBUG_INTR, "PCI IRQ occurred"); /* Do nothing */ } @@ -1525,13 +1482,14 @@ nsp32_msg(KERN_ERR, "Received unexpected BMCNTERR IRQ! "); /* * TODO: To be implemented improving bus master - * transfer reliablity when BMCNTERR is occured in + * transfer reliablity when BMCNTERR is occurred in * AutoSCSI phase described in specification. */ } #if 0 - printk("irq_stat=0x%x trans_stat=0x%x\n", irq_stat, trans_stat); + nsp32_dbg(NSP32_DEBUG_INTR, + "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat); show_busphase(busphase); #endif @@ -1540,72 +1498,122 @@ nsp32_write2(base, IRQ_CONTROL, 0); out2: -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - spin_unlock_irqrestore(&io_request_lock, flags); -#else - spin_unlock_irqrestore(host->host_lock, flags); -#endif + spin_unlock_irqrestore(HOST_LOCK, flags); nsp32_dbg(NSP32_DEBUG_INTR, "exit"); - return; + return IRQ_RETVAL(handled); } #undef SPRINTF #define SPRINTF(args...) \ - do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0) -static int nsp32_proc_info(char *buffer, - char **start, - off_t offset, - int length, - int hostno, - int inout) + do { \ + if(length > (pos - buffer)) { \ + pos += snprintf(pos, length - (pos - buffer) + 1, ## args); \ + nsp32_dbg(NSP32_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length, length - (pos - buffer));\ + } \ + } while(0) +static int nsp32_proc_info( +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) + struct Scsi_Host *host, +#endif + char *buffer, + char **start, + off_t offset, + int length, +#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) + int hostno, +#endif + int inout) { - char *pos = buffer; - int thislength; - unsigned long flags; - nsp32_hw_data *data; - struct Scsi_Host *host = NULL; - unsigned int base; - unsigned char mode_reg; + char *pos = buffer; + int thislength; + unsigned long flags; + nsp32_hw_data *data; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) + int hostno; +#else + struct Scsi_Host *host; +#endif + unsigned int base; + unsigned char mode_reg; + int id, speed; + long model; /* Write is not supported, just return. */ if (inout == TRUE) { return -EINVAL; } +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) + hostno = host->host_no; +#else /* search this HBA host */ - for (host=scsi_hostlist; host; host=host->next) { - if (host->host_no == hostno) { - break; - } - } + host = scsi_host_hn_get(hostno); if (host == NULL) { return -ESRCH; } +#endif data = (nsp32_hw_data *)host->hostdata; base = host->io_port; SPRINTF("NinjaSCSI-32 status\n\n"); - SPRINTF("Driver version: %s\n", nsp32_release_version); + SPRINTF("Driver version: %s, $Revision: 1.34 $\n", nsp32_release_version); SPRINTF("SCSI host No.: %d\n", hostno); SPRINTF("IRQ: %d\n", host->irq); SPRINTF("IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1); - SPRINTF("MMIO(virtual address): 0x%lx\n", host->base); + SPRINTF("MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1); SPRINTF("sg_tablesize: %d\n", host->sg_tablesize); - SPRINTF("Chip revision: %d\n", (nsp32_read2(base, INDEX_REG) >> 8) - 0x4f); + SPRINTF("Chip revision: 0x%x\n", (nsp32_read2(base, INDEX_REG) >> 8) & 0xff); mode_reg = nsp32_index_read1(base, CHIP_MODE); + model = data->pci_devid->driver_data; #ifdef CONFIG_PM - //SPRINTF("Power Management: %s\n", (mode_reg & OPTF) ? "yes" : "no"); + SPRINTF("Power Management: %s\n", (mode_reg & OPTF) ? "yes" : "no"); #endif - SPRINTF("OEM: %s\n", nsp32_model[mode_reg & (OEM0|OEM1)]); + SPRINTF("OEM: %ld, %s\n", (mode_reg & (OEM0|OEM1)), nsp32_model[model]); spin_lock_irqsave(&(data->Lock), flags); SPRINTF("CurrentSC: 0x%p\n\n", data->CurrentSC); spin_unlock_irqrestore(&(data->Lock), flags); + + SPRINTF("SDTR status\n"); + for(id = 0; id < NUMBER(data->target); id++) { + + SPRINTF("id %d: ", id); + + if (id == host->this_id) { + SPRINTF("----- NinjaSCSI-32 host adapter\n"); + continue; + } + + if (data->target[id].sync_flag == SDTR_DONE) { + if (data->target[id].period == 0 && + data->target[id].offset == ASYNC_OFFSET ) { + SPRINTF("async"); + } else { + SPRINTF(" sync"); + } + } else { + SPRINTF(" none"); + } + + if (data->target[id].period != 0) { + + speed = 1000000 / (data->target[id].period * 4); + + SPRINTF(" transfer %d.%dMB/s, offset %d", + speed / 1000, + speed % 1000, + data->target[id].offset + ); + } + SPRINTF("\n"); + } + + thislength = pos - (buffer + offset); if(thislength < 0) { @@ -1621,1542 +1629,1452 @@ } #undef SPRINTF + + /* - * Note: n_io_port is defined as 0x7f because I/O register port is - * assigned as: - * 0x800-0x8ff: memory mapped I/O port - * 0x900-0xbff: (map same 0x800-0x8ff I/O port image repeatedly) - * 0xc00-0xfff: CardBus status registers + * Reset parameters and call scsi_done for data->cur_lunt. + * Be careful setting SCpnt->result = DID_* before calling this function. */ -static int nsp32_detect(Scsi_Host_Template *sht) +static void nsp32_scsi_done(Scsi_Cmnd *SCpnt) { - struct Scsi_Host *host; /* registered host structure */ - int ret; - nsp32_hw_data *data; - int i, j; - - nsp32_dbg(NSP32_DEBUG_REGISTER, "enter"); + nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; + unsigned int base = SCpnt->device->host->io_port; /* - * register this HBA as SCSI device + * unmap pci */ - host = scsi_register(sht, sizeof(nsp32_hw_data)); - if (host == NULL) { - nsp32_msg (KERN_ERR, "failed to scsi register"); - goto err; + if (SCpnt->request_bufflen == 0) { + goto skip; } - /* - * set nsp32_hw_data - */ - data = (nsp32_hw_data *)host->hostdata; - memset(data, 0, sizeof(nsp32_hw_data)); - - data->IrqNumber = nsp32_data_base.IrqNumber; - data->BaseAddress = nsp32_data_base.BaseAddress; - data->NumAddress = nsp32_data_base.NumAddress; - data->MmioAddress = nsp32_data_base.MmioAddress; - data->Pci = nsp32_data_base.Pci; - data->pci_devid = nsp32_data_base.pci_devid; - - host->irq = data->IrqNumber; - host->io_port = data->BaseAddress; - host->unique_id = data->BaseAddress; - host->n_io_port = data->NumAddress; - host->base = data->MmioAddress; - scsi_set_pci_device(host, data->Pci); - - data->Host = host; - spin_lock_init(&(data->Lock)); - - data->curlunt = NULL; - data->curtarget = NULL; + if (SCpnt->use_sg) { + pci_unmap_sg(data->Pci, + (struct scatterlist *)SCpnt->buffer, + SCpnt->use_sg, + scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + } else { + pci_unmap_single(data->Pci, + (u32)SCpnt->SCp.have_data_in, + SCpnt->request_bufflen, + scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + } + skip: /* - * Bus master transfer mode is supported currently. + * clear TRANSFERCONTROL_BM_START */ - data->trans_method = NSP32_TRANSFER_BUSMASTER; + nsp32_write2(base, TRANSFER_CONTROL, 0); + nsp32_write4(base, BM_CNT, 0); /* - * Set clock div, CLOCK_4 (HBA has external clock, and - * dividing * 100ns/4). - * Currently CLOCK_4 has only tested, not for CLOCK_2/PCICLK yet. + * call scsi_done */ - data->clock = CLOCK_4; + (*SCpnt->scsi_done)(SCpnt); /* - * Select appropriate nsp32_sync_table and set I_CLOCKDIV. + * reset parameters */ - switch (data->clock) { - case CLOCK_4: - /* If data->clock is CLOCK_4, then select 40M sync table. */ - data->synct = nsp32_sync_table_40M; - data->syncnum = nsp32_table_40M_num; - break; - case CLOCK_2: - /* If data->clock is CLOCK_2, then select 20M sync table. */ - data->synct = nsp32_sync_table_20M; - data->syncnum = nsp32_table_20M_num; - break; - case PCICLK: - /* If data->clock is PCICLK, then select pci sync table. */ - data->synct = nsp32_sync_table_pci; - data->syncnum = nsp32_table_pci_num; - break; - default: - nsp32_msg(KERN_WARNING, - "Invalid clock div is selected, set CLOCK_4."); - /* Use default value CLOCK_4 */ - data->clock = CLOCK_4; - data->synct = nsp32_sync_table_40M; - data->syncnum = nsp32_table_40M_num; - } + data->cur_lunt->SCpnt = NULL; + data->cur_lunt = NULL; + data->cur_target = NULL; + data->CurrentSC = NULL; +} - /* - * setup nsp32_lunt - */ - data->lunt_list = (struct nsp32_lunt *) - kmalloc(sizeof(struct nsp32_lunt) * MAX_TARGET * MAX_LUN, - GFP_KERNEL); - if (data->lunt_list == NULL) { - nsp32_msg(KERN_ERR, "cannot allocate LUN memory"); - goto scsi_unregister; - } - nsp32_dbg(NSP32_DEBUG_REGISTER, "0x%x 0x%x", - data->lunt_list, sizeof(struct nsp32_lunt)*MAX_TARGET*MAX_LUN); - /* - * setup DMA - */ - if (pci_set_dma_mask(data->Pci, 0xffffffffUL)) { - nsp32_msg (KERN_ERR, "failed to set PCI DMA mask"); - goto kfree_lunt; - } +/* + * Bus Free Occur + * + * Current Phase is BUSFREE. AutoSCSI is automatically execute BUSFREE phase + * with ACK reply when below condition is matched: + * MsgIn 00: Command Complete. + * MsgIn 02: Save Data Pointer. + * MsgIn 04: Diconnect. + * In other case, unexpected BUSFREE is detected. + */ +static int nsp32_busfree_occur(Scsi_Cmnd *SCpnt, unsigned short execph) +{ + nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; + unsigned int base = SCpnt->device->host->io_port; - /* - * allocate autoparam DMA resource. - */ - data->autoparam = pci_alloc_consistent(data->Pci, AUTOPARAM_SIZE, &data->apaddr); - if (data->autoparam == NULL) { - nsp32_msg(KERN_ERR, "failed to allocate DMA memory"); - goto kfree_lunt; - } + nsp32_dbg(NSP32_DEBUG_BUSFREE, "enter execph=0x%x", execph); + show_autophase(execph); + + nsp32_write4(base, BM_CNT, 0); + nsp32_write2(base, TRANSFER_CONTROL, 0); /* - * allocate scatter-gather DMA resource. + * MsgIn 02: Save Data Pointer + * + * VALID: + * Save Data Pointer is received. Adjust pointer. + * + * NO-VALID: + * SCSI-3 says if Save Data Pointer is not received, then we restart + * processing and we can't adjust any SCSI data pointer in next data + * phase. */ - data->sg_list = pci_alloc_consistent(data->Pci, - (sizeof(struct nsp32_sgtable) * NSP_SG_SIZE * MAX_TARGET * MAX_LUN), - &data->sgaddr); - if (data->sg_list == NULL) { - nsp32_msg(KERN_ERR, "failed to allocate DMA memory"); - goto free_autoparam; - } + if (execph & MSGIN_02_VALID) { + nsp32_dbg(NSP32_DEBUG_BUSFREE, "MsgIn02_Valid"); - for (i=0; ilunt[i][j] = data->lunt_list + (i * MAX_LUN + j); - } - } + /* + * Check sack_cnt/saved_sack_cnt, then adjust sg table if + * needed. + */ + if (!(execph & MSGIN_00_VALID) && + ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE))) { + unsigned int sacklen, s_sacklen; + + /* + * Read SACK count and SAVEDSACK count, then compare. + */ + sacklen = nsp32_read4(base, SACK_CNT ); + s_sacklen = nsp32_read4(base, SAVED_SACK_CNT); + + /* + * If SAVEDSACKCNT == 0, it means SavedDataPointer is + * come after data transfering. + */ + if (s_sacklen > 0) { + /* + * Comparing between sack and savedsack to + * check the condition of AutoMsgIn03. + * + * If they are same, set msgin03 == TRUE, + * COMMANDCONTROL_AUTO_MSGIN_03 is enabled at + * reselection. On the other hand, if they + * aren't same, set msgin03 == FALSE, and + * COMMANDCONTROL_AUTO_MSGIN_03 is disabled at + * reselection. + */ + if (sacklen != s_sacklen) { + data->cur_lunt->msgin03 = FALSE; + } else { + data->cur_lunt->msgin03 = TRUE; + } - for (i=0; ilunt[i][j]; - lp->sglun = (struct nsp32_sglun *) - (data->sg_list + (i * MAX_LUN + j)); - lp->sglun_paddr = data->sgaddr + - (long)((i * MAX_LUN + j) - * sizeof(struct nsp32_sglun)); - lp->SCpnt = NULL; - lp->save_datp = 0; - lp->msgin03 = FALSE; - lp->sg_num = 0; - lp->cur_entry = 0; + nsp32_adjust_busfree(SCpnt, s_sacklen); + } } + + /* This value has not substitude with valid value yet... */ + //data->cur_lunt->save_datp = data->cur_datp; + } else { + /* + * no processing. + */ + } + + if (execph & MSGIN_03_VALID) { + /* MsgIn03 was valid to be processed. No need processing. */ } /* - * setup target + * target SDTR check */ - for (i=0; itarget[i]; - - target->limit_entry = 0; - target->sync_flag = 0; - nsp32_set_async(data, target); + if (data->cur_target->sync_flag & SDTR_INITIATOR) { + /* + * SDTR negotiation pulled by the initiator has not + * finished yet. Fall back to ASYNC mode. + */ + nsp32_set_async(data, data->cur_target); + data->cur_target->sync_flag &= ~SDTR_INITIATOR; + data->cur_target->sync_flag |= SDTR_DONE; + } else if (data->cur_target->sync_flag & SDTR_TARGET) { + /* + * SDTR negotiation pulled by the target has been + * negotiating. + */ + if (execph & (MSGIN_00_VALID | MSGIN_04_VALID)) { + /* + * If valid message is received, then + * negotiation is succeeded. + */ + } else { + /* + * On the contrary, if unexpected bus free is + * occurred, then negotiation is failed. Fall + * back to ASYNC mode. + */ + nsp32_set_async(data, data->cur_target); + } + data->cur_target->sync_flag &= ~SDTR_TARGET; + data->cur_target->sync_flag |= SDTR_DONE; } /* - * EEPROM check + * It is always ensured by SCSI standard that initiator + * switches into Bus Free Phase after + * receiving message 00 (Command Complete), 04 (Disconnect). + * It's the reason that processing here is valid. */ - ret = nsp32_getprom_param(data); - if (ret == FALSE) { - data->resettime = 3; /* default 3 */ + if (execph & MSGIN_00_VALID) { + /* MsgIn 00: Command Complete */ + nsp32_dbg(NSP32_DEBUG_BUSFREE, "command complete"); + + SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN); + SCpnt->SCp.Message = 0; + nsp32_dbg(NSP32_DEBUG_BUSFREE, + "normal end stat=0x%x resid=0x%x\n", + SCpnt->SCp.Status, SCpnt->resid); + SCpnt->result = (DID_OK << 16) | + (SCpnt->SCp.Message << 8) | + (SCpnt->SCp.Status << 0); + nsp32_scsi_done(SCpnt); + /* All operation is done */ + return TRUE; + } else if (execph & MSGIN_04_VALID) { + /* MsgIn 04: Disconnect */ + SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN); + SCpnt->SCp.Message = 4; + + nsp32_dbg(NSP32_DEBUG_BUSFREE, "disconnect"); + return TRUE; + } else { + /* Unexpected bus free */ + nsp32_msg(KERN_WARNING, "unexpected bus free occurred"); + + /* DID_ERROR? */ + //SCpnt->result = (DID_OK << 16) | (SCpnt->SCp.Message << 8) | (SCpnt->SCp.Status << 0); + SCpnt->result = DID_ERROR << 16; + nsp32_scsi_done(SCpnt); + return TRUE; } + return FALSE; +} - /* - * setup HBA - */ - nsp32hw_init(host); - snprintf(data->info_str, sizeof(data->info_str), - "NinjaSCSI-32Bi/UDE: irq %d, io 0x%lx+0x%x", - host->irq, host->io_port, host->n_io_port); +/* + * nsp32_adjust_busfree - adjusting SG table + * + * Note: This driver adjust the SG table using SCSI ACK + * counter instead of BMCNT counter! + */ +static void nsp32_adjust_busfree(Scsi_Cmnd *SCpnt, unsigned int s_sacklen) +{ + nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; + int old_entry = data->cur_entry; + int new_entry; + int sg_num = data->cur_lunt->sg_num; + nsp32_sgtable *sgt = data->cur_lunt->sglun->sgt; + unsigned int restlen, sentlen; + u32 len, addr; - sht->name = data->info_str; + nsp32_dbg(NSP32_DEBUG_SGLIST, "old resid=0x%x", SCpnt->resid); + + /* adjust saved SACK count with 4 byte start address boundary */ + s_sacklen -= le32_to_cpu(sgt[old_entry].addr) & 3; /* - * SCSI bus reset - * - * Note: It's important to reset SCSI bus in initialization phase. - * NinjaSCSI-32Bi/UDE HBA EEPROM seems to exchange SDTR when system is - * coming up, so SCSI devices connected to HBA is set as - * un-asynchronous mode. It brings the merit that this HBA is - * ready to start synchronous transfer without any preparation, - * but we are difficult to control transfer speed. In addition, - * it prevents device transfer speed from effecting EEPROM start-up - * SDTR. NinjaSCSI-32Bi/UDE has the feature if EEPROM is set as Auto - * Mode, then FAST-10M is selected when SCSI devices are connected - * same or more than 4 devices. It should be avoided depending on - * this specification Thus, resetting the SCSI bus restores all - * connected SCSI devices to asynchronous mode, then this driver - * put SDTR safely later, and we can control all SCSI device - * transfer mode. + * calculate new_entry from sack count and each sgt[].len + * calculate the byte which is intent to send */ - nsp32_do_bus_reset(data); + sentlen = 0; + for (new_entry = old_entry; new_entry < sg_num; new_entry++) { + sentlen += (le32_to_cpu(sgt[new_entry].len) & ~SGTEND); + if (sentlen > s_sacklen) { + break; + } + } - ret = request_irq(host->irq, do_nsp32_isr, SA_SHIRQ, "nsp32", data); - if (ret < 0) { - nsp32_msg(KERN_ERR, "Unable to allocate IRQ for NSP32 " - "SCSI PCI controller. Interrupt: %d\n", host->irq); - goto free_sg_list; + /* all sgt is processed */ + if (new_entry == sg_num) { + goto last; } - /* - * PCI IO register - */ - if(!request_region(host->io_port, host->n_io_port, "nsp32")) { - nsp32_msg(KERN_ERR, - "I/O region 0x%lx+0x%lx is already used", - data->BaseAddress, data->length); - goto free_irq; - } + if (sentlen == s_sacklen) { + /* XXX: confirm it's ok or not */ + /* In this case, it's ok because we are at + the head element of the sg. restlen is correctly calculated. */ + } - return 1; + /* calculate the rest length for transfering */ + restlen = sentlen - s_sacklen; - free_irq: - free_irq(host->irq, data); - - free_autoparam: - pci_free_consistent(data->Pci, AUTOPARAM_SIZE, data->autoparam, data->apaddr); - - free_sg_list: - pci_free_consistent(data->Pci, - (sizeof(struct nsp32_sgtable) * NSP_SG_SIZE * MAX_TARGET * MAX_LUN), - data->sg_list, data->sgaddr); - - kfree_lunt: - kfree(data->lunt_list); - - scsi_unregister: - scsi_unregister(host); - - err: - return 0; -} - -static int nsp32_release(struct Scsi_Host *shpnt) -{ - nsp32_hw_data *data = (nsp32_hw_data *)shpnt->hostdata; - - if (data->lunt_list) { - kfree(data->lunt_list); - } - - if (data->autoparam) { - pci_free_consistent(data->Pci, AUTOPARAM_SIZE, - data->autoparam, data->apaddr); - } - - if (data->sg_list) { - pci_free_consistent(data->Pci, - (sizeof(struct nsp32_sgtable) * NSP_SG_SIZE * MAX_TARGET * MAX_LUN), - data->sg_list, data->sgaddr); - } - - DEBUG(0, "free irq\n"); - if (shpnt->irq) { - free_irq(shpnt->irq, data); - } + /* update adjusting current SG table entry */ + len = le32_to_cpu(sgt[new_entry].len); + addr = le32_to_cpu(sgt[new_entry].addr); + addr += (len - restlen); + sgt[new_entry].addr = cpu_to_le32(addr); + sgt[new_entry].len = cpu_to_le32(restlen); - DEBUG(0, "free io\n"); - if (shpnt->io_port && shpnt->n_io_port) { - release_region(shpnt->io_port, shpnt->n_io_port); - } + /* set cur_entry with new_entry */ + data->cur_entry = new_entry; + + return; - if (data->MmioAddress != 0) { - iounmap((void *)(data->MmioAddress)); + last: + if (SCpnt->resid < sentlen) { + nsp32_msg(KERN_ERR, "resid underflow"); } - return 0; -} + SCpnt->resid -= sentlen; + nsp32_dbg(NSP32_DEBUG_SGLIST, "new resid=0x%x", SCpnt->resid); -static const char *nsp32_info(struct Scsi_Host *shpnt) -{ - nsp32_hw_data *data = (nsp32_hw_data *)shpnt->hostdata; + /* update hostdata and lun */ - return data->info_str; + return; } /* - * error handler + * It's called MsgOut phase occur. + * NinjaSCSI-32Bi/UDE automatically processes up to 3 messages in + * message out phase. It, however, has more than 3 messages, + * HBA creates the interrupt and we have to process by hand. */ -static int nsp32_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) +static void nsp32_msgout_occur(Scsi_Cmnd *SCpnt) { - nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%p why=%d\n", SCpnt, reset_flags); + nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; + unsigned int base = SCpnt->device->host->io_port; + //unsigned short command; + long new_sgtp; + int i; + + nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, + "enter: msgout_len: 0x%x", data->msgout_len); - nsp32_eh_bus_reset(SCpnt); + /* + * If MsgOut phase is occurred without having any + * message, then No_Operation is sent (SCSI-2). + */ + if (data->msgout_len == 0) { + nsp32_build_nop(SCpnt); + } - return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET; -} + /* + * Set SGTP ADDR current entry for restarting AUTOSCSI, + * because SGTP is incremented next point. + * There is few statement in the specification... + */ + new_sgtp = data->cur_lunt->sglun_paddr + + (data->cur_lunt->cur_entry * sizeof(nsp32_sgtable)); -static int nsp32_eh_abort(Scsi_Cmnd *SCpnt) -{ - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->host->hostdata; - unsigned int base = data->BaseAddress; + /* + * send messages + */ + for (i = 0; i < data->msgout_len; i++) { + nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, + "%d : 0x%x", i, data->msgoutbuf[i]); - nsp32_msg(KERN_WARNING, "abort"); + /* + * Check REQ is asserted. + */ + nsp32_wait_req(data, ASSERT); - if (data->curlunt->SCpnt == NULL) { - return (FAILED); - } + if (i == (data->msgout_len - 1)) { + /* + * If the last message, set the AutoSCSI restart + * before send back the ack message. AutoSCSI + * restart automatically negate ATN signal. + */ + //command = (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02); + //nsp32_restart_autoscsi(SCpnt, command); + nsp32_write2(base, COMMAND_CONTROL, + (CLEAR_CDB_FIFO_POINTER | + AUTO_COMMAND_PHASE | + AUTOSCSI_RESTART | + AUTO_MSGIN_00_OR_04 | + AUTO_MSGIN_02 )); + } + /* + * Write data with SACK, then wait sack is + * automatically negated. + */ + nsp32_write1(base, SCSI_DATA_WITH_ACK, data->msgoutbuf[i]); + nsp32_wait_sack(data, NEGATE); - if (data->curtarget->sync_flag & (SDTR_INITIATOR | SDTR_TARGET)) { - /* reset SDTR negotiation */ - data->curtarget->sync_flag = 0; - } + nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "bus: 0x%x\n", + nsp32_read1(base, SCSI_BUS_MONITOR)); + }; - nsp32_write2(base, TRANSFER_CONTROL, 0); - nsp32_write2(base, BM_CNT, 0); + data->msgout_len = 0; - return (FAILED); + nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "exit"); } -static int nsp32_eh_bus_reset(Scsi_Cmnd *SCpnt) +/* + * Restart AutoSCSI + * + * Note: Restarting AutoSCSI needs set: + * SYNC_REG, ACK_WIDTH, SGT_ADR, TRANSFER_CONTROL + */ +static void nsp32_restart_autoscsi(Scsi_Cmnd *SCpnt, unsigned short command) { - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->host->hostdata; - unsigned int base = data->BaseAddress; + nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; + unsigned int base = data->BaseAddress; + unsigned short transfer = 0; - nsp32_msg(KERN_INFO, "Bus Reset"); - nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%x", SCpnt); + nsp32_dbg(NSP32_DEBUG_RESTART, "enter"); - nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK); - nsp32_do_bus_reset(data); - nsp32_write2(base, IRQ_CONTROL, 0); + if (data->cur_target == NULL || data->cur_lunt == NULL) { + nsp32_msg(KERN_ERR, "Target or Lun is invalid"); + } - return SUCCESS; /* SCSI bus reset is succeeded at any time. */ -} + /* + * set SYNC_REG + * Don't set BM_START_ADR before setting this register. + */ + nsp32_write1(base, SYNC_REG, data->cur_target->syncreg); -static void nsp32_do_bus_reset(nsp32_hw_data *data) -{ - unsigned int base = data->BaseAddress; - unsigned short intrdat; - int i; + /* + * set ACKWIDTH + */ + nsp32_write1(base, ACK_WIDTH, data->cur_target->ackwidth); /* - * stop all transfer - * clear TRANSFERCONTROL_BM_START - * clear counter + * set SREQ hazard killer sampling rate */ - nsp32_write2(base, TRANSFER_CONTROL, 0); - nsp32_write4(base, BM_CNT, 0); - nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK); + nsp32_write1(base, SREQ_SMPL_RATE, data->cur_target->sample_reg); /* - * fall back to asynchronous transfer mode - * initialize SDTR negotiation flag + * set SGT ADDR (physical address) */ - for (i=0; itarget[i]; + nsp32_write4(base, SGT_ADR, data->cur_lunt->sglun_paddr); - target->sync_flag = 0; - nsp32_set_async(data, target); + /* + * set TRANSFER CONTROL REG + */ + transfer = 0; + transfer |= (TRANSFER_GO | ALL_COUNTER_CLR); + if (data->trans_method & NSP32_TRANSFER_BUSMASTER) { + if (SCpnt->request_bufflen > 0) { + transfer |= BM_START; + } + } else if (data->trans_method & NSP32_TRANSFER_MMIO) { + transfer |= CB_MMIO_MODE; + } else if (data->trans_method & NSP32_TRANSFER_PIO) { + transfer |= CB_IO_MODE; } + nsp32_write2(base, TRANSFER_CONTROL, transfer); /* - * reset SCSI bus + * restart AutoSCSI + * + * TODO: COMMANDCONTROL_AUTO_COMMAND_PHASE is needed ? */ - nsp32_write1(base, SCSI_BUS_CONTROL, BUSCTL_RST); - udelay(RESET_HOLD_TIME); - nsp32_write1(base, SCSI_BUS_CONTROL, 0); - for(i = 0; i < 5; i++) { - intrdat = nsp32_read2(base, IRQ_STATUS); /* dummy read */ - nsp32_dbg(NSP32_DEBUG_BUSRESET, "irq:1: 0x%x", intrdat); - } + command |= (CLEAR_CDB_FIFO_POINTER | + AUTO_COMMAND_PHASE | + AUTOSCSI_RESTART ); + nsp32_write2(base, COMMAND_CONTROL, command); - data->CurrentSC = NULL; + nsp32_dbg(NSP32_DEBUG_RESTART, "exit"); } -static int nsp32_eh_host_reset(Scsi_Cmnd *SCpnt) -{ - struct Scsi_Host *host = SCpnt->host; - nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata; - unsigned int base = data->BaseAddress; - - nsp32_msg(KERN_INFO, "Host Reset"); - nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%x", SCpnt); - - nsp32hw_init(host); - nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK); - nsp32_do_bus_reset(data); - nsp32_write2(base, IRQ_CONTROL, 0); - - return SUCCESS; /* Host reset is succeeded at any time. */ -} /* - * PCI/Cardbus probe/remove routine + * cannot run automatically message in occur */ -static int __devinit nsp32_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - int ret; - nsp32_hw_data *data = &nsp32_data_base; - - nsp32_dbg(NSP32_DEBUG_REGISTER, "enter"); +static void nsp32_msgin_occur(Scsi_Cmnd *SCpnt, + unsigned long irq_status, + unsigned short execph) +{ + nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; + unsigned int base = SCpnt->device->host->io_port; + unsigned char msg; + unsigned char msgtype; + unsigned char newlun; + unsigned short command = 0; + int msgclear = TRUE; + long new_sgtp; + int ret; - ret = pci_enable_device(pdev); - if (ret) { - nsp32_msg(KERN_ERR, "failed to enable pci device"); - return ret; - } + /* + * read first message + * Use SCSIDATA_W_ACK instead of SCSIDATAIN, because the procedure + * of Message-In have to be processed before sending back SCSI ACK. + */ + msg = nsp32_read1(base, SCSI_DATA_IN); + data->msginbuf[(unsigned char)data->msgin_len] = msg; + msgtype = data->msginbuf[0]; + nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, + "enter: msglen: 0x%x msgin: 0x%x msgtype: 0x%x", + data->msgin_len, msg, msgtype); - data->Pci = pdev; - data->pci_devid = id; - data->IrqNumber = pdev->irq; - data->BaseAddress = pci_resource_start(pdev, 0); - data->NumAddress = pci_resource_len(pdev, 0); - data->MmioAddress = (unsigned long)ioremap_nocache( - pci_resource_start(pdev, 1), pci_resource_len(pdev, 1)); + /* + * TODO: We need checking whether bus phase is message in? + */ - pci_set_master(pdev); + /* + * assert SCSI ACK + */ + nsp32_sack_assert(data); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)) - scsi_register_host(&driver_template); -#else - scsi_register_module(MODULE_SCSI_HA, &driver_template); -#endif + /* + * processing IDENTIFY + */ + if (msgtype & 0x80) { + if (!(irq_status & IRQSTATUS_RESELECT_OCCUER)) { + /* Invalid (non reselect) phase */ + goto reject; + } - nsp32_msg(KERN_INFO, "nsp32 irq: %i mmio: 0x%lx slot: %s model: %s", - pdev->irq, data->MmioAddress, pdev->slot_name, - nsp32_model[id->driver_data]); + newlun = msgtype & 0x1f; /* TODO: SPI-3 compliant? */ + ret = nsp32_reselection(SCpnt, newlun); + if (ret == TRUE) { + goto restart; + } else { + goto reject; + } + } + + /* + * processing messages except for IDENTIFY + * + * TODO: Messages are all SCSI-2 terminology. SCSI-3 compliance is TODO. + */ + switch (msgtype) { + /* + * 1-byte message + */ + case COMMAND_COMPLETE: + case DISCONNECT: + /* + * These messages should not be occurred. + * They should be processed on AutoSCSI sequencer. + */ + nsp32_msg(KERN_WARNING, + "unexpected message of AutoSCSI MsgIn: 0x%x", msg); + break; + + case RESTORE_POINTERS: + /* + * AutoMsgIn03 is disabled, and HBA gets this message. + */ - nsp32_dbg(NSP32_DEBUG_REGISTER, "exit"); + if ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE)) { + unsigned int s_sacklen; - return 0; -} + s_sacklen = nsp32_read4(base, SAVED_SACK_CNT); + if ((execph & MSGIN_02_VALID) && (s_sacklen > 0)) { + nsp32_adjust_busfree(SCpnt, s_sacklen); + } else { + /* No need to rewrite SGT */ + } + } + data->cur_lunt->msgin03 = FALSE; -static void __devexit nsp32_remove(struct pci_dev *pdev) -{ - nsp32_dbg(NSP32_DEBUG_REGISTER, "enter"); - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)) - scsi_unregister_host(&driver_template); -#else - scsi_unregister_module(MODULE_SCSI_HA, &driver_template); -#endif -} + /* Update with the new value */ -static struct pci_device_id nsp32_pci_table[] __devinitdata = { - { - vendor: PCI_VENDOR_ID_IODATA, - device: PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II, - subvendor: PCI_ANY_ID, - subdevice: PCI_ANY_ID, - driver_data: MODEL_IODATA, - }, - { - vendor: PCI_VENDOR_ID_WORKBIT, - device: PCI_DEVICE_ID_NINJASCSI_32BI_KME, - subvendor: PCI_ANY_ID, - subdevice: PCI_ANY_ID, - driver_data: MODEL_KME, - }, - { - vendor: PCI_VENDOR_ID_WORKBIT, - device: PCI_DEVICE_ID_NINJASCSI_32BI_WBT, - subvendor: PCI_ANY_ID, - subdevice: PCI_ANY_ID, - driver_data: MODEL_WORKBIT, - }, - { - vendor: PCI_VENDOR_ID_WORKBIT, - device: PCI_DEVICE_ID_WORKBIT_STANDARD, - subvendor: PCI_ANY_ID, - subdevice: PCI_ANY_ID, - driver_data: MODEL_PCI_WORKBIT, - }, - { - vendor: PCI_VENDOR_ID_WORKBIT, - device: PCI_DEVICE_ID_NINJASCSI_32BI_LOGITEC, - subvendor: PCI_ANY_ID, - subdevice: PCI_ANY_ID, - driver_data: MODEL_EXT_ROM, - }, - { - vendor: PCI_VENDOR_ID_WORKBIT, - device: PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC, - subvendor: PCI_ANY_ID, - subdevice: PCI_ANY_ID, - driver_data: MODEL_PCI_LOGITEC, - }, - { - vendor: PCI_VENDOR_ID_WORKBIT, - device: PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO, - subvendor: PCI_ANY_ID, - subdevice: PCI_ANY_ID, - driver_data: MODEL_PCI_MELCO, - }, - {0,0,}, -}; -MODULE_DEVICE_TABLE(pci, nsp32_pci_table); + /* reset SACK/SavedACK counter (or ALL clear?) */ + nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK); -static struct pci_driver nsp32_driver = { - .name = "nsp32", - .id_table = nsp32_pci_table, - .probe = nsp32_probe, - .remove = __devexit_p(nsp32_remove), -#ifdef CONFIG_PM -/* .suspend = nsp32_suspend,*/ -/* .resume = nsp32_resume,*/ -#endif -}; + /* + * set new sg pointer + */ + new_sgtp = data->cur_lunt->sglun_paddr + + (data->cur_lunt->cur_entry * sizeof(nsp32_sgtable)); + nsp32_write4(base, SGT_ADR, new_sgtp); -static int __init init_nsp32(void) { - return pci_module_init(&nsp32_driver); -} + break; -static void __exit exit_nsp32(void) { - pci_unregister_driver(&nsp32_driver); -} + case SAVE_POINTERS: + /* + * These messages should not be occurred. + * They should be processed on AutoSCSI sequencer. + */ + nsp32_msg (KERN_WARNING, + "unexpected message of AutoSCSI MsgIn: SAVE_POINTERS"); + + break; + + case MESSAGE_REJECT: + /* If previous message_out is sending SDTR, and get + message_reject from target, SDTR negotiation is failed */ + if (data->cur_target->sync_flag & + (SDTR_INITIATOR | SDTR_TARGET)) { + /* + * Current target is negotiating SDTR, but it's + * failed. Fall back to async transfer mode, and set + * SDTR_DONE. + */ + nsp32_set_async(data, data->cur_target); + data->cur_target->sync_flag &= ~SDTR_INITIATOR; + data->cur_target->sync_flag |= SDTR_DONE; -module_init(init_nsp32); -module_exit(exit_nsp32); + } + break; + case LINKED_CMD_COMPLETE: + case LINKED_FLG_CMD_COMPLETE: + /* queue tag is not supported currently */ + nsp32_msg (KERN_WARNING, + "unsupported message: 0x%x", msgtype); + break; -/* - * Reset parameters and call scsi_done for data->curlunt. - * Be careful setting SCpnt->result = DID_* before calling this function. - */ -static void nsp32_scsi_done(nsp32_hw_data *data, Scsi_Cmnd *SCpnt) -{ - unsigned int base = data->BaseAddress; + case INITIATE_RECOVERY: + /* staring ECA (Extended Contingent Allegiance) state. */ + /* This message is declined in SPI2 or later. */ + + goto reject; /* - * unmap pci + * 2-byte message */ - if (SCpnt->request_bufflen == 0) { - goto skip; + case SIMPLE_QUEUE_TAG: + case 0x23: + /* + * 0x23: Ignore_Wide_Residue is not declared in scsi.h. + * No support is needed. + */ + if (data->msgin_len >= 1) { + goto reject; + } + + /* current position is 1-byte of 2 byte */ + msgclear = FALSE; + + break; + + /* + * extended message + */ + case EXTENDED_MESSAGE: + if (data->msgin_len < 1) { + /* + * Current position does not reach 2-byte + * (2-byte is extended message length). + */ + msgclear = FALSE; + break; + } + + if ((data->msginbuf[1] + 1) > data->msgin_len) { + /* + * Current extended message has msginbuf[1] + 2 + * (msgin_len starts counting from 0, so buf[1] + 1). + * If current message position is not finished, + * continue receiving message. + */ + msgclear = FALSE; + break; + } + + /* + * Reach here means regular length of each type of + * extended messages. + */ + switch (data->msginbuf[2]) { + case EXTENDED_MODIFY_DATA_POINTER: + /* TODO */ + goto reject; /* not implemented yet */ + break; + + case EXTENDED_SDTR: + /* + * Exchange this message between initiator and target. + */ + if (data->msgin_len != EXTENDED_SDTR_LEN + 1) { + /* + * received inappropriate message. + */ + goto reject; + break; + } + + nsp32_analyze_sdtr(SCpnt); + + break; + + case EXTENDED_EXTENDED_IDENTIFY: + /* SCSI-I only, not supported. */ + goto reject; /* not implemented yet */ + + break; + + case EXTENDED_WDTR: + goto reject; /* not implemented yet */ + + break; + + default: + goto reject; + } + break; + + default: + goto reject; } - if (SCpnt->use_sg) { - pci_unmap_sg(data->Pci, - (struct scatterlist *)SCpnt->buffer, - SCpnt->use_sg, - scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + restart: + if (msgclear == TRUE) { + data->msgin_len = 0; + + /* + * If restarting AutoSCSI, but there are some message to out + * (msgout_len > 0), set AutoATN, and set SCSIMSGOUT as 0 + * (MSGOUT_VALID = 0). When commandcontrol is written with + * AutoSCSI restart, at the same time MsgOutOccur should be + * happened (however, such situation is really possible...?). + */ + if (data->msgout_len > 0) { + nsp32_write4(base, SCSI_MSG_OUT, 0); + command |= AUTO_ATN; + } + + /* + * restart AutoSCSI + * If it's failed, COMMANDCONTROL_AUTO_COMMAND_PHASE is needed. + */ + command |= (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02); + + /* + * If current msgin03 is TRUE, then flag on. + */ + if (data->cur_lunt->msgin03 == TRUE) { + command |= AUTO_MSGIN_03; + } + data->cur_lunt->msgin03 = FALSE; } else { - pci_unmap_single(data->Pci, - (u32)SCpnt->SCp.have_data_in, - SCpnt->request_bufflen, - scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + data->msgin_len++; } - skip: /* - * clear TRANSFERCONTROL_BM_START + * restart AutoSCSI */ - nsp32_write2(base, TRANSFER_CONTROL, 0); - nsp32_write4(base, BM_CNT, 0); + nsp32_restart_autoscsi(SCpnt, command); /* - * call scsi_done + * wait SCSI REQ negate for REQ-ACK handshake */ - (*SCpnt->scsi_done)(SCpnt); + nsp32_wait_req(data, NEGATE); /* - * reset parameters + * negate SCSI ACK */ - data->curlunt->SCpnt = NULL; - data->curlunt = NULL; - data->curtarget = NULL; - data->CurrentSC = NULL; -} + nsp32_sack_negate(data); + + nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit"); + + return; + + reject: + nsp32_msg(KERN_WARNING, + "invalid or unsupported MessageIn, rejected. " + "current msg: 0x%x (len: 0x%x), processing msg: 0x%x", + msg, data->msgin_len, msgtype); + nsp32_build_reject(SCpnt); + data->msgin_len = 0; + goto restart; +} /* - * Bus Free Occur - * - * Current Phase is BUSFREE. AutoSCSI is automatically execute BUSFREE phase - * with ACK reply when below condition is matched: - * MsgIn 00: Command Complete. - * MsgIn 02: Save Data Pointer. - * MsgIn 04: Diconnect. - * In other case, unexpected BUSFREE is detected. + * */ -static int nsp32_busfree_occur(nsp32_hw_data *data, unsigned short execph) +static void nsp32_analyze_sdtr(Scsi_Cmnd *SCpnt) { - Scsi_Cmnd *SCpnt = data->curlunt->SCpnt; - unsigned int base = data->BaseAddress; + nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; + nsp32_target *target = data->cur_target; + nsp32_sync_table *synct; + unsigned char get_period = data->msginbuf[3]; + unsigned char get_offset = data->msginbuf[4]; + int entry; + int syncnum; - nsp32_dbg(NSP32_DEBUG_BUSFREE, "enter"); + nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "enter"); - nsp32_write4(base, BM_CNT, 0); - nsp32_write2(base, TRANSFER_CONTROL, 0); + synct = data->synct; + syncnum = data->syncnum; /* - * MsgIn 02: Save Data Pointer - * - * VALID: - * Save Data Pointer is received. Adjust pointer. - * - * NO-VALID: - * SCSI-3 says if Save Data Pointer is not received, then we restart - * processing and we can't adjust any SCSI data pointer in next data - * phase. - */ - if (execph & MSGIN_02_VALID) { - nsp32_dbg(NSP32_DEBUG_BUSFREE, "MsgIn02_Valid"); - + * If this inititor sent the SDTR message, then target responds SDTR, + * initiator SYNCREG, ACKWIDTH from SDTR parameter. + * Messages are not appropriate, then send back reject message. + * If initiator did not send the SDTR, but target sends SDTR, + * initiator calculator the appropriate parameter and send back SDTR. + */ + if (target->sync_flag & SDTR_INITIATOR) { /* - * Check sack_cnt/saved_sack_cnt, then adjust sg table if - * needed. + * Initiator sent SDTR, the target responds and + * send back negotiation SDTR. */ - if (!(execph & MSGIN_00_VALID) && - ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE))) { - unsigned int sacklen, s_sacklen; + nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target responds SDTR"); + + target->sync_flag &= ~SDTR_INITIATOR; + target->sync_flag |= SDTR_DONE; + /* + * offset: + */ + if (get_offset > MAX_OFFSET) { /* - * Read SACK count and SAVEDSACK count, then compare. + * Negotiation is failed, the target send back + * unexpected offset value. */ - sacklen = nsp32_read4(base, SACK_CNT); - s_sacklen = nsp32_read4(base, SAVED_SACK_CNT); + goto reject; + } + + if (get_offset == ASYNC_OFFSET) { + /* + * Negotiation is succeeded, the target want + * to fall back into asynchronous transfer mode. + */ + goto async; + } + /* + * period: + * Check whether sync period is too short. If too short, + * fall back to async mode. If it's ok, then investigate + * the received sync period. If sync period is acceptable + * between sync table start_period and end_period, then + * set this I_T nexus as sent offset and period. + * If it's not acceptable, send back reject and fall back + * to async mode. + */ + if (get_period < data->synct[0].period_num) { /* - * If SAVEDSACKCNT == 0, it means SavedDataPointer is - * come after data transfering. + * Negotiation is failed, the target send back + * unexpected period value. */ - if (s_sacklen > 0) { - /* - * Comparing between sack and savedsack to - * check the condition of AutoMsgIn03. - * - * If they are same, set msgin03 == TRUE, - * COMMANDCONTROL_AUTO_MSGIN_03 is enabled at - * reselection. On the other hand, if they - * aren't same, set msgin03 == FALSE, and - * COMMANDCONTROL_AUTO_MSGIN_03 is disabled at - * reselection. - */ - if (sacklen != s_sacklen) { - data->curlunt->msgin03 = FALSE; - } else { - data->curlunt->msgin03 = TRUE; - } + goto reject; + } - nsp32_adjust_busfree(data, s_sacklen); - } + entry = nsp32_search_period_entry(data, target, get_period); + + if (entry < 0) { + /* + * Target want to use long period which is not + * acceptable NinjaSCSI-32Bi/UDE. + */ + goto reject; } - /* This value has not substitude with valid value yet... */ - //data->curlunt->save_datp = data->cur_datp; - } else { /* - * no processing. + * Set new sync table and offset in this I_T nexus. */ - } + nsp32_set_sync_entry(data, target, entry, get_offset); + } else { + /* Target send SDTR to initiator. */ + nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target send SDTR"); - if (execph & MSGIN_03_VALID) { - /* MsgIn03 was valid to be processed. No need processing. */ - } + target->sync_flag |= SDTR_INITIATOR; - /* - * target SDTR check - */ - if (data->curtarget->sync_flag & SDTR_INITIATOR) { - /* - * SDTR negotiation pulled by the initiator has not - * finished yet. Fall back to ASYNC mode. - */ - nsp32_set_async(data, data->curtarget); - data->curtarget->sync_flag &= ~SDTR_INITIATOR; - data->curtarget->sync_flag |= SDTR_DONE; - } else if (data->curtarget->sync_flag & SDTR_TARGET) { - /* - * SDTR negotiation pulled by the target has been - * negotiating. - */ - if (execph & (MSGIN_00_VALID | MSGIN_04_VALID)) { - /* - * If valid message is received, then - * negotiation is succeeded. - */ + /* offset: */ + if (get_offset > MAX_OFFSET) { + /* send back as MAX_OFFSET */ + get_offset = MAX_OFFSET; + } + + /* period: */ + if (get_period < data->synct[0].period_num) { + get_period = data->synct[0].period_num; + } + + entry = nsp32_search_period_entry(data, target, get_period); + + if (get_offset == ASYNC_OFFSET || entry < 0) { + nsp32_set_async(data, target); + nsp32_build_sdtr(SCpnt, 0, ASYNC_OFFSET); } else { - /* - * On the contrary, if unexpected bus free is - * occured, then negotiation is failed. Fall - * back to ASYNC mode. - */ - nsp32_set_async(data, data->curtarget); + nsp32_set_sync_entry(data, target, entry, get_offset); + nsp32_build_sdtr(SCpnt, get_period, get_offset); } - data->curtarget->sync_flag &= ~SDTR_TARGET; - data->curtarget->sync_flag |= SDTR_DONE; } - + + target->period = get_period; + nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit"); + return; + + reject: /* - * It is always ensured by SCSI standard that initiator - * switches into Bus Free Phase after - * receiving message 00 (Command Complete), 04 (Disconnect). - * It's the reason that processing here is valid. + * If the current message is unacceptable, send back to the target + * with reject message. */ - if (execph & MSGIN_00_VALID) { - /* MsgIn 00: Command Complete */ - nsp32_dbg(NSP32_DEBUG_BUSFREE, "command complete"); + nsp32_build_reject(SCpnt); - SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN); - SCpnt->SCp.Message = 0; - nsp32_dbg(NSP32_DEBUG_BUSFREE, - "normal end stat=0x%x resid=0x%x\n", - SCpnt->SCp.Status, SCpnt->resid); - SCpnt->result = - (DID_OK << 16) | (SCpnt->SCp.Message << 8) | (SCpnt->SCp.Status << 0); - nsp32_scsi_done(data, SCpnt); - /* All operation is done */ - return (TRUE); - } else if (execph & MSGIN_04_VALID) { - /* MsgIn 04: Disconnect */ - SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN); - SCpnt->SCp.Message = 4; - - nsp32_dbg(NSP32_DEBUG_BUSFREE, "disconnect"); - return (TRUE); - } else { - /* Unexpected bus free */ - nsp32_msg(KERN_WARNING, "unexpected bus free occured"); + async: + nsp32_set_async(data, target); /* set as ASYNC transfer mode */ - /* DID_ERROR? */ - //SCpnt->result = (DID_OK << 16) | (SCpnt->SCp.Message << 8) | (SCpnt->SCp.Status << 0); - SCpnt->result = DID_ERROR << 16; - nsp32_scsi_done(data, SCpnt); - return (TRUE); - } - return (FALSE); + target->period = 0; + nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit: set async"); + return; } /* - * nsp32_adjust_busfree - adjusting SG table - * - * Note: This driver adjust the SG table using SCSI ACK - * counter instead of BMCNT counter! + * Search config entry number matched in sync_table from given + * target and speed period value. If failed to search, return negative value. */ -static void nsp32_adjust_busfree(nsp32_hw_data *data, unsigned int s_sacklen) +static int nsp32_search_period_entry(nsp32_hw_data *data, + nsp32_target *target, + unsigned char period) { - int old_entry = data->cur_entry; - int new_entry; - struct nsp32_sgtable *sgt = data->curlunt->sglun->sgt; - unsigned int restlen, sentlen; - int sg_num = data->curlunt->sg_num; + int i; - /* adjust saved SACK count with 4 byte start address boundary */ - s_sacklen -= sgt[old_entry].addr & 3; + if (target->limit_entry >= data->syncnum) { + nsp32_msg(KERN_ERR, "limit_entry exceeds syncnum!"); + target->limit_entry = 0; + } - /* - * calculate new_entry from sack count and each sgt[].len - * calculate the byte which is intent to send - */ - sentlen = 0; - for (new_entry = old_entry; new_entry < sg_num; new_entry++) { - sentlen += (sgt[new_entry].len & ~NSP32_SG_END_SGT); - if (sentlen > s_sacklen) { - break; + for (i = target->limit_entry; i < data->syncnum; i++) { + if (period >= data->synct[i].start_period && + period <= data->synct[i].end_period) { + break; } } - /* all sgt is processed */ - if (new_entry == sg_num) { - goto last; + /* + * Check given period value is over the sync_table value. + * If so, return max value. + */ + if (i == data->syncnum) { + i = -1; } - if (sentlen == s_sacklen) { - /* XXX: confirm it's ok or not */ - /* In this case, it's ok because we are at - the head element of the sg. restlen is correctly calculated. */ - } + return i; +} - /* calculate the rest length for transfering */ - restlen = sentlen - s_sacklen; - - /* update adjusting current SG table entry */ - sgt[new_entry].addr += (sgt[new_entry].len - restlen); - sgt[new_entry].len = restlen; - /* set cur_entry with new_entry */ - data->cur_entry = new_entry; - - return; +/* + * target <-> initiator use ASYNC transfer + */ +static void nsp32_set_async(nsp32_hw_data *data, nsp32_target *target) +{ + unsigned char period = data->synct[target->limit_entry].period_num; - last: - /* update hostdata and lun */ + target->offset = ASYNC_OFFSET; + target->period = 0; + target->syncreg = TO_SYNCREG(period, ASYNC_OFFSET); + target->ackwidth = 0; + target->sample_reg = 0; - return; + nsp32_dbg(NSP32_DEBUG_SYNC, "set async"); } /* - * It's called MsgOut phase occur. - * NinjaSCSI-32Bi/UDE automatically processes up to 3 messages in - * message out phase. It, however, has more than 3 messages, - * HBA creates the interrupt and we have to process by hand. + * target <-> initiator use maximum SYNC transfer */ -static void nsp32_msgout_occur(nsp32_hw_data *data) +static void nsp32_set_max_sync(nsp32_hw_data *data, + nsp32_target *target, + unsigned char *period, + unsigned char *offset) { - unsigned int base = data->BaseAddress; - //unsigned short command; - long new_sgtp; - int i; - - nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, - "enter: msgoutlen: 0x%x", data->msgoutlen); + unsigned char period_num, ackwidth; - /* - * If MsgOut phase is occured without having any - * message, then No_Operation is sent (SCSI-2). - */ - if (data->msgoutlen == 0) { - nsp32_build_nop(data); - } + period_num = data->synct[target->limit_entry].period_num; + *period = data->synct[target->limit_entry].start_period; + ackwidth = data->synct[target->limit_entry].ackwidth; + *offset = MAX_OFFSET; - /* - * Set SGTP ADDR current entry for restarting AUTOSCSI, - * because SGTP is incremented next point. - * There is few statement in the specification... - */ - new_sgtp = data->curlunt->sglun_paddr - + data->curlunt->cur_entry * sizeof(struct nsp32_sgtable); + target->syncreg = TO_SYNCREG(period_num, *offset); + target->ackwidth = ackwidth; + target->offset = *offset; + target->sample_reg = 0; /* disable SREQ sampling */ +} - /* - * send messages - */ - for (i=0; imsgoutlen; i++) { - nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, - "%d : 0x%x", i, data->msgoutbuf[i]); - /* - * Check REQ is asserted. - */ - nsp32_wait_req(data, ASSERT); +/* + * target <-> initiator use entry number speed + */ +static void nsp32_set_sync_entry(nsp32_hw_data *data, + nsp32_target *target, + int entry, + unsigned char offset) +{ + unsigned char period, ackwidth, sample_rate; + + period = data->synct[entry].period_num; + ackwidth = data->synct[entry].ackwidth; + offset = offset; + sample_rate = data->synct[entry].sample_rate; + + target->syncreg = TO_SYNCREG(period, offset); + target->ackwidth = ackwidth; + target->offset = offset; + target->sample_reg = sample_rate | SAMPLING_ENABLE; - if (i == (data->msgoutlen - 1)) { - /* - * If the last message, set the AutoSCSI restart - * before send back the ack message. AutoSCSI - * restart automatically negate ATN signal. - */ - //command = (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02); - //nsp32_restart_autoscsi(data, command); - nsp32_write2(base, COMMAND_CONTROL, - (CLEAR_CDB_FIFO_POINTER | - AUTO_COMMAND_PHASE | - AUTOSCSI_RESTART | - AUTO_MSGIN_00_OR_04 | - AUTO_MSGIN_02 )); - } - /* - * Write data with SACK, then wait sack is - * automatically negated. - */ - nsp32_write1(base, SCSI_DATA_WITH_ACK, data->msgoutbuf[i]); - nsp32_wait_sack(data, NEGATE); - - nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "bus: 0x%x\n", - nsp32_read1(base, SCSI_BUS_MONITOR)); - }; - - data->msgoutlen = 0; - - nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "exit"); + nsp32_dbg(NSP32_DEBUG_SYNC, "set sync"); } + /* - * Restart AutoSCSI + * It waits until SCSI REQ becomes assertion or negation state. * - * Note: Restarting AutoSCSI needs set: - * SYNC_REG, ACK_WIDTH, SGT_ADR, TRANSFER_CONTROL + * Note: If nsp32_msgin_occur is called, we asserts SCSI ACK. Then + * connected target responds SCSI REQ negation. We have to wait + * SCSI REQ becomes negation in order to negate SCSI ACK signal for + * REQ-ACK handshake. */ -static void nsp32_restart_autoscsi(nsp32_hw_data *data, unsigned short command) +static void nsp32_wait_req(nsp32_hw_data *data, int state) { - unsigned int base = data->BaseAddress; - unsigned short transfer = 0; - Scsi_Cmnd *SCpnt = data->curlunt->SCpnt; + unsigned int base = data->BaseAddress; + int wait_time = 0; + unsigned char bus, req_bit; - nsp32_dbg(NSP32_DEBUG_RESTART, "enter"); - - if (data->curtarget == NULL || data->curlunt == NULL) { - nsp32_msg(KERN_ERR, "Target or Lun is invalid"); + if (!((state == ASSERT) || (state == NEGATE))) { + nsp32_msg(KERN_ERR, "unknown state designation"); } + /* REQ is BIT(5) */ + req_bit = (state == ASSERT ? BUSMON_REQ : 0); - /* - * set SYNC_REG - * Don't set BM_START_ADR before setting this register. - */ - nsp32_write1(base, SYNC_REG, data->curtarget->syncreg); - - /* - * set ACKWIDTH - */ - nsp32_write1(base, ACK_WIDTH, data->curtarget->ackwidth); - - /* - * set SGT ADDR (physical address) - */ - nsp32_write4(base, SGT_ADR, data->curlunt->sglun_paddr); - - /* - * set TRANSFER CONTROL REG - */ - transfer = 0; - transfer |= (TRANSFER_GO | ALL_COUNTER_CLR); - if (data->trans_method & NSP32_TRANSFER_BUSMASTER) { - if (SCpnt->request_bufflen > 0) { - transfer |= BM_START; + do { + bus = nsp32_read1(base, SCSI_BUS_MONITOR); + if ((bus & BUSMON_REQ) == req_bit) { + nsp32_dbg(NSP32_DEBUG_WAIT, + "wait_time: %d", wait_time); + return; } - } else if (data->trans_method & NSP32_TRANSFER_MMIO) { - transfer |= CB_MMIO_MODE; - } else if (data->trans_method & NSP32_TRANSFER_PIO) { - transfer |= CB_IO_MODE; - } - nsp32_write2(base, TRANSFER_CONTROL, transfer); - - /* - * restart AutoSCSI - * - * TODO: COMMANDCONTROL_AUTO_COMMAND_PHASE is needed ? - */ - command |= (CLEAR_CDB_FIFO_POINTER | - AUTO_COMMAND_PHASE | - AUTOSCSI_RESTART); - nsp32_write2(base, COMMAND_CONTROL, command); + udelay(1); + wait_time++; + } while (wait_time < REQSACK_TIMEOUT_TIME); - nsp32_dbg(NSP32_DEBUG_RESTART, "exit"); + nsp32_msg(KERN_WARNING, "wait REQ timeout, req_bit: 0x%x", req_bit); } - /* - * cannot run automatically message in occur + * It waits until SCSI SACK becomes assertion or negation state. */ -static void nsp32_msgin_occur(nsp32_hw_data *data, unsigned long irq_status, - unsigned short execph) +static void nsp32_wait_sack(nsp32_hw_data *data, int state) { - unsigned int base = data->BaseAddress; - unsigned char msg; - unsigned char msgtype; - unsigned char newlun; - unsigned short command = 0; - int msgclear = TRUE; - long new_sgtp; - int ret; + unsigned int base = data->BaseAddress; + int wait_time = 0; + unsigned char bus, ack_bit; - /* - * read first message - * Use SCSIDATA_W_ACK instead of SCSIDATAIN, because the procedure - * of Message-In have to be processed before sending back SCSI ACK. - */ - msg = nsp32_read1(base, SCSI_DATA_IN); - data->msginbuf[(unsigned char)data->msginlen] = msg; - msgtype = data->msginbuf[0]; - nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, - "enter: msglen: 0x%x msgin: 0x%x msgtype: 0x%x", - data->msginlen, msg, msgtype); - - /* - * TODO: We need checking whether bus phase is message in? - */ - - /* - * assert SCSI ACK - */ - nsp32_sack_assert(data); - - /* - * processing IDENTIFY - */ - if (msgtype & 0x80) { - if (!(irq_status & IRQSTATUS_RESELECT_OCCUER)) { - /* Invalid (non reselect) phase */ - goto reject; - } - - newlun = msgtype & 0x1f; /* TODO: SPI-3 compliant? */ - ret = nsp32_reselection(data, newlun); - if (ret == TRUE) { - goto restart; - } else { - goto reject; - } + if (!((state == ASSERT) || (state == NEGATE))) { + nsp32_msg(KERN_ERR, "unknown state designation"); } - - /* - * processing messages except for IDENTIFY - * - * TODO: Messages are all SCSI-2 terminology. SCSI-3 compliance is TODO. - */ - switch (msgtype) { - /* - * 1-byte message - */ - case COMMAND_COMPLETE: - case DISCONNECT: - /* - * These messages should not be occured. - * They should be processed on AutoSCSI sequencer. - */ - nsp32_msg(KERN_WARNING, - "unexpected message of AutoSCSI MsgIn: 0x%x", msg); - break; - - case RESTORE_POINTERS: - /* - * AutoMsgIn03 is disabled, and HBA gets this message. - */ + /* ACK is BIT(4) */ + ack_bit = (state == ASSERT ? BUSMON_ACK : 0); - if ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE)) { - unsigned int s_sacklen; - - s_sacklen = nsp32_read4(base, SAVED_SACK_CNT); - if ((execph & MSGIN_02_VALID) && (s_sacklen > 0)) { - nsp32_adjust_busfree(data, s_sacklen); - } else { - /* No need to rewrite SGT */ - } + do { + bus = nsp32_read1(base, SCSI_BUS_MONITOR); + if ((bus & BUSMON_ACK) == ack_bit) { + nsp32_dbg(NSP32_DEBUG_WAIT, + "wait_time: %d", wait_time); + return; } - data->curlunt->msgin03 = FALSE; + udelay(1); + wait_time++; + } while (wait_time < REQSACK_TIMEOUT_TIME); - /* Update with the new value */ + nsp32_msg(KERN_WARNING, "wait SACK timeout, ack_bit: 0x%x", ack_bit); +} - /* reset SACK/SavedACK counter (or ALL clear?) */ - nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK); +/* + * assert SCSI ACK + * + * Note: SCSI ACK assertion needs with ACKENB=1, AUTODIRECTION=1. + */ +static void nsp32_sack_assert(nsp32_hw_data *data) +{ + unsigned int base = data->BaseAddress; + unsigned char busctrl; - /* - * set new sg pointer - */ - new_sgtp = data->curlunt->sglun_paddr + - data->curlunt->cur_entry * sizeof(struct nsp32_sgtable); - nsp32_write4(base, SGT_ADR, new_sgtp); + busctrl = nsp32_read1(base, SCSI_BUS_CONTROL); + busctrl |= (BUSCTL_ACK | AUTODIRECTION | ACKENB); + nsp32_write1(base, SCSI_BUS_CONTROL, busctrl); +} - break; +/* + * negate SCSI ACK + */ +static void nsp32_sack_negate(nsp32_hw_data *data) +{ + unsigned int base = data->BaseAddress; + unsigned char busctrl; - case SAVE_POINTERS: - /* - * These messages should not be occured. - * They should be processed on AutoSCSI sequencer. - */ - nsp32_msg (KERN_WARNING, - "unexpected message of AutoSCSI MsgIn: SAVE_POINTERS"); - - break; - - case MESSAGE_REJECT: - /* If previous message_out is sending SDTR, and get - message_reject from target, SDTR negotiation is failed */ - if (data->curtarget->sync_flag & - (SDTR_INITIATOR | SDTR_TARGET)) { - /* - * Current target is negotiating SDTR, but it's - * failed. Fall back to async transfer mode, and set - * SDTR_DONE. - */ - nsp32_set_async(data, data->curtarget); - data->curtarget->sync_flag &= ~SDTR_INITIATOR; - data->curtarget->sync_flag |= SDTR_DONE; + busctrl = nsp32_read1(base, SCSI_BUS_CONTROL); + busctrl &= ~BUSCTL_ACK; + nsp32_write1(base, SCSI_BUS_CONTROL, busctrl); +} - } - break; - case LINKED_CMD_COMPLETE: - case LINKED_FLG_CMD_COMPLETE: - /* queue tag is not supported currently */ - nsp32_msg (KERN_WARNING, - "unsupported message: 0x%x", msgtype); - break; - case INITIATE_RECOVERY: - /* staring ECA (Extended Contingent Allegiance) state. */ - /* This message is declined in SPI2 or later. */ +/* + * Note: n_io_port is defined as 0x7f because I/O register port is + * assigned as: + * 0x800-0x8ff: memory mapped I/O port + * 0x900-0xbff: (map same 0x800-0x8ff I/O port image repeatedly) + * 0xc00-0xfff: CardBus status registers + */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) +#define DETECT_OK 0 +#define DETECT_NG 1 +#define PCIDEV pdev +static int nsp32_detect(struct pci_dev *pdev) +#else +#define DETECT_OK 1 +#define DETECT_NG 0 +#define PCIDEV (data->Pci) +static int nsp32_detect(Scsi_Host_Template *sht) +#endif +{ + struct Scsi_Host *host; /* registered host structure */ + struct resource *res; + nsp32_hw_data *data; + int ret; + int n_target, n_lun, i; - goto reject; + nsp32_dbg(NSP32_DEBUG_REGISTER, "enter"); /* - * 2-byte message + * register this HBA as SCSI device */ - case SIMPLE_QUEUE_TAG: - case 0x23: - /* - * 0x23: Ignore_Wide_Residue is not declared in scsi.h. - * No support is needed. - */ - if (data->msginlen >= 1) { - goto reject; - } - - /* current position is 1-byte of 2 byte */ - msgclear = FALSE; - - break; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) + host = scsi_host_alloc(&nsp32_template, sizeof(nsp32_hw_data)); +#else + host = scsi_register(sht, sizeof(nsp32_hw_data)); +#endif + if (host == NULL) { + nsp32_msg (KERN_ERR, "failed to scsi register"); + goto err; + } /* - * extended message + * set nsp32_hw_data */ - case EXTENDED_MESSAGE: - if (data->msginlen < 1) { - /* - * Current position does not reach 2-byte - * (2-byte is extended message length). - */ - msgclear = FALSE; - break; - } - - if ((data->msginbuf[1] + 1) > data->msginlen) { - /* - * Current extended message has msginbuf[1] + 2 - * (msginlen starts counting from 0, so buf[1] + 1). - * If current message position is not finished, - * continue receiving message. - */ - msgclear = FALSE; - break; - } - - /* - * Reach here means regular length of each type of - * extended messages. - */ - switch (data->msginbuf[2]) { - case EXTENDED_MODIFY_DATA_POINTER: - /* TODO */ - goto reject; /* not implemented yet */ - break; - - case EXTENDED_SDTR: - /* - * Exchange this message between initiator and target. - */ - if (data->msginlen != EXTENDED_SDTR_LEN + 1) { - /* - * received inappropriate message. - */ - goto reject; - break; - } - - nsp32_analyze_sdtr(data); - - break; - - case EXTENDED_EXTENDED_IDENTIFY: - /* SCSI-I only, not supported. */ - goto reject; /* not implemented yet */ - - break; - - case EXTENDED_WDTR: - goto reject; /* not implemented yet */ - - break; - - default: - goto reject; - } - break; - - default: - goto reject; - } - - restart: - if (msgclear == TRUE) { - data->msginlen = 0; - - /* - * If restarting AutoSCSI, but there are some message to out - * (msgoutlen > 0), set AutoATN, and set SCSIMSGOUT as 0 - * (MV_VALID = 0). When commandcontrol is written with - * AutoSCSI restart, at the same time MsgOutOccur should be - * happened (however, such situation is really possible...?). - */ - if (data->msgoutlen > 0) { - nsp32_write4(base, SCSI_MSG_OUT, 0); - command |= AUTO_ATN; - } + data = (nsp32_hw_data *)host->hostdata; - /* - * restart AutoSCSI - * If it's failed, COMMANDCONTROL_AUTO_COMMAND_PHASE is needed. - */ - command |= (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02); + *data = nsp32_data_base; - /* - * If current msgin03 is TRUE, then flag on. - */ - if (data->curlunt->msgin03 == TRUE) { - command |= AUTO_MSGIN_03; - } - data->curlunt->msgin03 = FALSE; - } else { - data->msginlen++; - } + host->irq = data->IrqNumber; + host->io_port = data->BaseAddress; + host->unique_id = data->BaseAddress; + host->n_io_port = data->NumAddress; + host->base = data->MmioAddress; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,63)) + scsi_set_device(host, &PCIDEV->dev); +#else + scsi_set_pci_device(host, PCIDEV); +#endif + + data->Host = host; + spin_lock_init(&(data->Lock)); + + data->cur_lunt = NULL; + data->cur_target = NULL; /* - * restart AutoSCSI + * Bus master transfer mode is supported currently. */ - nsp32_restart_autoscsi(data, command); + data->trans_method = NSP32_TRANSFER_BUSMASTER; /* - * wait SCSI REQ negate for REQ-ACK handshake + * Set clock div, CLOCK_4 (HBA has own external clock, and + * dividing * 100ns/4). + * Currently CLOCK_4 has only tested, not for CLOCK_2/PCICLK yet. */ - nsp32_wait_req(data, NEGATE); + data->clock = CLOCK_4; /* - * negate SCSI ACK + * Select appropriate nsp32_sync_table and set I_CLOCKDIV. */ - nsp32_sack_negate(data); - - nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit"); + switch (data->clock) { + case CLOCK_4: + /* If data->clock is CLOCK_4, then select 40M sync table. */ + data->synct = nsp32_sync_table_40M; + data->syncnum = NUMBER(nsp32_sync_table_40M); + break; + case CLOCK_2: + /* If data->clock is CLOCK_2, then select 20M sync table. */ + data->synct = nsp32_sync_table_20M; + data->syncnum = NUMBER(nsp32_sync_table_20M); + break; + case PCICLK: + /* If data->clock is PCICLK, then select pci sync table. */ + data->synct = nsp32_sync_table_pci; + data->syncnum = NUMBER(nsp32_sync_table_pci); + break; + default: + nsp32_msg(KERN_WARNING, + "Invalid clock div is selected, set CLOCK_4."); + /* Use default value CLOCK_4 */ + data->clock = CLOCK_4; + data->synct = nsp32_sync_table_40M; + data->syncnum = NUMBER(nsp32_sync_table_40M); + } - return; + /* + * setup nsp32_lunt + */ - reject: - nsp32_msg(KERN_WARNING, - "invalid or unsupported MessageIn, rejected. " - "current msg: 0x%x (len: 0x%x), processing msg: 0x%x", - msg, data->msginlen, msgtype); - nsp32_build_reject(data); - data->msginlen = 0; + /* + * setup DMA + */ + if (pci_set_dma_mask(PCIDEV, 0xffffffffUL) != 0) { + nsp32_msg (KERN_ERR, "failed to set PCI DMA mask"); + goto scsi_unregister; + } - goto restart; -} + /* + * allocate autoparam DMA resource. + */ + data->autoparam = pci_alloc_consistent(PCIDEV, sizeof(nsp32_autoparam), &(data->auto_paddr)); + if (data->autoparam == NULL) { + nsp32_msg(KERN_ERR, "failed to allocate DMA memory"); + goto scsi_unregister; + } -/* - * - */ -static void nsp32_analyze_sdtr(nsp32_hw_data *data) -{ - struct nsp32_target *target = data->curtarget; - struct nsp32_sync_table *synct; - unsigned char get_period = data->msginbuf[3]; - unsigned char get_offset = data->msginbuf[4]; - int entry; - int syncnum; + /* + * allocate scatter-gather DMA resource. + */ + data->sg_list = pci_alloc_consistent(PCIDEV, NSP32_SG_TABLE_SIZE, + &(data->sg_paddr)); + if (data->sg_list == NULL) { + nsp32_msg(KERN_ERR, "failed to allocate DMA memory"); + goto free_autoparam; + } - nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "enter"); + for (n_target = 0; n_target < NUMBER(data->lunt); n_target++) { + for (n_lun = 0; n_lun < NUMBER(data->lunt[0]); n_lun++) { + int offset = n_target * NUMBER(data->lunt[0]) + n_lun; + nsp32_lunt tmp = { + SCpnt: NULL, + save_datp: 0, + msgin03: FALSE, + sg_num: 0, + cur_entry: 0, + sglun: &(data->sg_list[offset]), + sglun_paddr: data->sg_paddr + ARRAY_OFFSET(nsp32_sglun, offset), + }; - synct = data->synct; - syncnum = data->syncnum; + data->lunt[n_target][n_lun] = tmp; + } + } /* - * If this inititor sent the SDTR message, then target responds SDTR, - * initiator SYNCREG, ACKWIDTH from SDTR parameter. - * Messages are not appropriate, then send back reject message. - * If initiator did not send the SDTR, but target sends SDTR, - * initiator calculator the appropriate parameter and send back SDTR. - */ - if (target->sync_flag & SDTR_INITIATOR) { - /* - * Initiator sent SDTR, the target responds and - * send back negotiation SDTR. - */ - nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target responds SDTR"); - - target->sync_flag &= ~SDTR_INITIATOR; - target->sync_flag |= SDTR_DONE; + * setup target + */ + for (i = 0; i < NUMBER(data->target); i++) { + nsp32_target *target = &(data->target[i]); - /* - * offset: - */ - if (get_offset > SYNC_OFFSET) { - /* - * Negotiation is failed, the target send back - * unexpected offset value. - */ - goto reject; - } - - if (get_offset == ASYNC_OFFSET) { - /* - * Negotiation is succeeded, the target want - * to fall back into asynchronous transfer mode. - */ - goto async; - } + target->limit_entry = 0; + target->sync_flag = SDTR_NONE; + nsp32_set_async(data, target); + } - /* - * period: - * Check whether sync period is too short. If too short, - * fall back to async mode. If it's ok, then investigate - * the received sync period. If sync period is acceptable - * between sync table start_period and end_period, then - * set this I_T nexus as sent offset and period. - * If it's not acceptable, send back reject and fall back - * to async mode. - */ - if (get_period < data->synct[0].period_num) { - /* - * Negotiation is failed, the target send back - * unexpected period value. - */ - goto reject; - } + /* + * EEPROM check + */ + ret = nsp32_getprom_param(data); + if (ret == FALSE) { + data->resettime = 3; /* default 3 */ + } - entry = nsp32_search_period_entry(data, target, get_period); + /* + * setup HBA + */ + nsp32hw_init(data); - if (entry < 0) { - /* - * Target want to use long period which is not - * acceptable NinjaSCSI-32Bi/UDE. - */ - goto reject; - } + snprintf(data->info_str, sizeof(data->info_str), + "NinjaSCSI-32Bi/UDE: irq %d, io 0x%lx+0x%x", + host->irq, host->io_port, host->n_io_port); - /* - * Set new sync table and offset in this I_T nexus. - */ - nsp32_set_sync_entry(data, target, entry, get_offset); - } else { - /* Target send SDTR to initiator. */ - nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target send SDTR"); - - target->sync_flag |= SDTR_INITIATOR; + /* + * SCSI bus reset + * + * Note: It's important to reset SCSI bus in initialization phase. + * NinjaSCSI-32Bi/UDE HBA EEPROM seems to exchange SDTR when + * system is coming up, so SCSI devices connected to HBA is set as + * un-asynchronous mode. It brings the merit that this HBA is + * ready to start synchronous transfer without any preparation, + * but we are difficult to control transfer speed. In addition, + * it prevents device transfer speed from effecting EEPROM start-up + * SDTR. NinjaSCSI-32Bi/UDE has the feature if EEPROM is set as + * Auto Mode, then FAST-10M is selected when SCSI devices are + * connected same or more than 4 devices. It should be avoided + * depending on this specification. Thus, resetting the SCSI bus + * restores all connected SCSI devices to asynchronous mode, then + * this driver set SDTR safely later, and we can control all SCSI + * device transfer mode. + */ + nsp32_do_bus_reset(data); - /* offset: */ - if (get_offset > SYNC_OFFSET) { - /* send back as SYNC_OFFSET */ - get_offset = SYNC_OFFSET; - } + ret = request_irq(host->irq, do_nsp32_isr, + SA_SHIRQ | SA_SAMPLE_RANDOM, "nsp32", data); + if (ret < 0) { + nsp32_msg(KERN_ERR, "Unable to allocate IRQ for NinjaSCSI32 " + "SCSI PCI controller. Interrupt: %d", host->irq); + goto free_sg_list; + } - /* period: */ - if (get_period < data->synct[0].period_num) { - get_period = data->synct[0].period_num; - } + /* + * PCI IO register + */ + res = request_region(host->io_port, host->n_io_port, "nsp32"); + if (res == NULL) { + nsp32_msg(KERN_ERR, + "I/O region 0x%lx+0x%lx is already used", + data->BaseAddress, data->NumAddress); + goto free_irq; + } - entry = nsp32_search_period_entry(data, target, get_period); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) + scsi_add_host (host, &PCIDEV->dev); + scsi_scan_host(host); +#endif + pci_set_drvdata(PCIDEV, host); + return DETECT_OK; - if (get_offset == ASYNC_OFFSET || entry < 0) { - nsp32_set_async(data, target); - nsp32_build_sdtr(data, 0, ASYNC_OFFSET); - } else { - nsp32_set_sync_entry(data, target, entry, get_offset); - nsp32_build_sdtr(data, get_period, get_offset); - } - } - - nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit"); - return; + free_irq: + free_irq(host->irq, data); - reject: - /* - * If the current message is unacceptable, send back to the target - * with reject message. - */ - nsp32_build_reject(data); + free_sg_list: + pci_free_consistent(PCIDEV, NSP32_SG_TABLE_SIZE, + data->sg_list, data->sg_paddr); - async: - nsp32_set_async(data, target); /* set as ASYNC transfer mode */ + free_autoparam: + pci_free_consistent(PCIDEV, sizeof(nsp32_autoparam), + data->autoparam, data->auto_paddr); + + scsi_unregister: + scsi_host_put(host); - nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit: set async"); - return; + err: + return DETECT_NG; } +#undef DETECT_OK +#undef DETECT_NG +#undef PCIDEV - -/* - * Search config entry number matched in sync_table from given - * target and speed period value. If failed to search, return negative value. - */ -static int nsp32_search_period_entry(nsp32_hw_data *data, - struct nsp32_target *target, - unsigned char period) +static int nsp32_release(struct Scsi_Host *host) { - int i; + nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata; - if (target->limit_entry >= data->syncnum) { - nsp32_msg(KERN_ERR, "limit_entry exceeds syncnum!"); - target->limit_entry = 0; + if (data->autoparam) { + pci_free_consistent(data->Pci, sizeof(nsp32_autoparam), + data->autoparam, data->auto_paddr); } - for (i=target->limit_entry; isyncnum; i++) { - if (period >= data->synct[i].start_period && - period <= data->synct[i].end_period) { - break; - } + if (data->sg_list) { + pci_free_consistent(data->Pci, NSP32_SG_TABLE_SIZE, + data->sg_list, data->sg_paddr); } - /* - * Check given period value is over the sync_table value. - * If so, return max value. - */ - if (i == data->syncnum) { - i = -1; + if (host->irq) { + free_irq(host->irq, data); } - return i; -} - - -/* - * target <-> initiator use ASYNC transfer - */ -static void nsp32_set_async(nsp32_hw_data *data, struct nsp32_target *target) -{ - unsigned char period = data->synct[target->limit_entry].period_num; + if (host->io_port && host->n_io_port) { + release_region(host->io_port, host->n_io_port); + } - target->offset = ASYNC_OFFSET; - target->syncreg = TO_SYNCREG(period, ASYNC_OFFSET); - target->ackwidth = 0; + if (data->MmioAddress != 0) { + iounmap((void *)(data->MmioAddress)); + } - nsp32_dbg(NSP32_DEBUG_SYNC, "set async"); + return 0; } +static const char *nsp32_info(struct Scsi_Host *shpnt) +{ + nsp32_hw_data *data = (nsp32_hw_data *)shpnt->hostdata; -/* - * target <-> initiator use maximum SYNC transfer - */ -static void nsp32_set_max_sync(nsp32_hw_data *data, - struct nsp32_target *target, - unsigned char *period, unsigned char *offset) -{ - unsigned char period_num, ackwidth; - - period_num = data->synct[target->limit_entry].period_num; - *period = data->synct[target->limit_entry].start_period; - ackwidth = data->synct[target->limit_entry].ackwidth; - *offset = SYNC_OFFSET; - - target->syncreg = TO_SYNCREG(period_num, *offset); - target->ackwidth = ackwidth; - target->offset = *offset; + return data->info_str; } -/* - * target <-> initiator use entry number speed +/**************************************************************************** + * error handler */ -static void nsp32_set_sync_entry(nsp32_hw_data *data, - struct nsp32_target *target, - int entry, unsigned char offset) +static int nsp32_eh_abort(Scsi_Cmnd *SCpnt) { - unsigned char period, ackwidth; + nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; + unsigned int base = SCpnt->device->host->io_port; - period = data->synct[entry].period_num; - ackwidth = data->synct[entry].ackwidth; - offset = offset; - - target->syncreg = TO_SYNCREG(period, offset); - target->ackwidth = ackwidth; - target->offset = offset; + nsp32_msg(KERN_WARNING, "abort"); - nsp32_dbg(NSP32_DEBUG_SYNC, "set sync"); -} + if (data->cur_lunt->SCpnt == NULL) { + nsp32_dbg(NSP32_DEBUG_BUSRESET, "abort failed"); + return FAILED; + } + if (data->cur_target->sync_flag & (SDTR_INITIATOR | SDTR_TARGET)) { + /* reset SDTR negotiation */ + data->cur_target->sync_flag = SDTR_NONE; + nsp32_set_async(data, data->cur_target); + } -/* - * It waits until SCSI REQ becomes assertion or negation state. - * - * Note: If nsp32_msgin_occur is called, we asserts SCSI ACK. Then - * connected target responds SCSI REQ negation. We have to wait - * SCSI REQ becomes negation in order to negate SCSI ACK signal for - * REQ-ACK handshake. - */ -static void nsp32_wait_req(nsp32_hw_data *data, int state) + nsp32_write2(base, TRANSFER_CONTROL, 0); + nsp32_write2(base, BM_CNT, 0); + + SCpnt->result = DID_ABORT << 16; + nsp32_scsi_done(SCpnt); + + nsp32_dbg(NSP32_DEBUG_BUSRESET, "abort success"); + return SUCCESS; +} + +static int nsp32_eh_bus_reset(Scsi_Cmnd *SCpnt) { - unsigned int base = data->BaseAddress; - int wait_time = 0; - unsigned char bus; + nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; + unsigned int base = SCpnt->device->host->io_port; - if (!((state == ASSERT) || (state == NEGATE))) { - nsp32_msg(KERN_ERR, "unknown state designation"); - } - state <<= 5; /* REQ is BIT(5) */ + nsp32_msg(KERN_INFO, "Bus Reset"); + nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%x", SCpnt); - do { - bus = nsp32_read1(base, SCSI_BUS_MONITOR); - if ((bus & BUSMON_REQ) == state) { - nsp32_dbg(NSP32_DEBUG_WAIT, - "wait_time: %d", wait_time); - return; - } - udelay(1); - wait_time++; - } while (wait_time < REQSACK_TIMEOUT_TIME); + nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK); + nsp32_do_bus_reset(data); + nsp32_write2(base, IRQ_CONTROL, 0); - nsp32_msg(KERN_WARNING, "wait REQ timeout, state: %d", state); + return SUCCESS; /* SCSI bus reset is succeeded at any time. */ } -/* - * It waits until SCSI SACK becomes assertion or negation state. - */ -static void nsp32_wait_sack(nsp32_hw_data *data, int state) +static void nsp32_do_bus_reset(nsp32_hw_data *data) { - unsigned int base = data->BaseAddress; - int wait_time = 0; - unsigned char bus; + unsigned int base = data->BaseAddress; + unsigned short intrdat; + int i; - if (!((state == ASSERT) || (state == NEGATE))) { - nsp32_msg(KERN_ERR, "unknown state designation"); + nsp32_dbg(NSP32_DEBUG_BUSRESET, "in"); + + /* + * stop all transfer + * clear TRANSFERCONTROL_BM_START + * clear counter + */ + nsp32_write2(base, TRANSFER_CONTROL, 0); + nsp32_write4(base, BM_CNT, 0); + nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK); + + /* + * fall back to asynchronous transfer mode + * initialize SDTR negotiation flag + */ + for (i = 0; i < NUMBER(data->target); i++) { + nsp32_target *target = &data->target[i]; + + target->sync_flag = SDTR_NONE; + nsp32_set_async(data, target); } - state <<= 4; /* ACK is BIT(4) */ - do { - bus = nsp32_read1(base, SCSI_BUS_MONITOR); - if ((bus & BUSMON_ACK) == state) { - nsp32_dbg(NSP32_DEBUG_WAIT, - "wait_time: %d", wait_time); - return; - } - udelay(1); - wait_time++; - } while (wait_time < REQSACK_TIMEOUT_TIME); + /* + * reset SCSI bus + */ + nsp32_write1(base, SCSI_BUS_CONTROL, BUSCTL_RST); + udelay(RESET_HOLD_TIME); + nsp32_write1(base, SCSI_BUS_CONTROL, 0); + for(i = 0; i < 5; i++) { + intrdat = nsp32_read2(base, IRQ_STATUS); /* dummy read */ + nsp32_dbg(NSP32_DEBUG_BUSRESET, "irq:1: 0x%x", intrdat); + } - nsp32_msg(KERN_WARNING, "wait SACK timeout, state: %d", state); + data->CurrentSC = NULL; } -/* - * assert SCSI ACK - * - * Note: SCSI ACK assertion needs with ACKENB=1, AUTODIRECTION=1. - */ -static void nsp32_sack_assert(nsp32_hw_data *data) +static int nsp32_eh_host_reset(Scsi_Cmnd *SCpnt) { - unsigned char busctrl; - unsigned int base = data->BaseAddress; + struct Scsi_Host *host = SCpnt->device->host; + unsigned int base = SCpnt->device->host->io_port; + nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata; - busctrl = nsp32_read1(base, SCSI_BUS_CONTROL); - busctrl |= (BUSCTL_ACK | AUTODIRECTION | ACKENB); - nsp32_write1(base, SCSI_BUS_CONTROL,busctrl); -} + nsp32_msg(KERN_INFO, "Host Reset"); + nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%x", SCpnt); -/* - * negate SCSI ACK - */ -static void nsp32_sack_negate(nsp32_hw_data *data) -{ - unsigned char busctrl; - unsigned int base = data->BaseAddress; + nsp32hw_init(data); + nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK); + nsp32_do_bus_reset(data); + nsp32_write2(base, IRQ_CONTROL, 0); - busctrl = nsp32_read1(base, SCSI_BUS_CONTROL); - busctrl &= ~BUSCTL_ACK; - nsp32_write1(base, SCSI_BUS_CONTROL, busctrl); + return SUCCESS; /* Host reset is succeeded at any time. */ } +/************************************************************************** + * EEPROM handler + */ /* * getting EEPROM parameter @@ -3165,7 +3083,12 @@ { int vendor = data->pci_devid->vendor; int device = data->pci_devid->device; - int ret, val, i; + int ret; +#ifdef NSP32_DEBUG + int i; +#define NSP32_DEBUG_PROM_BUF_SIZE 0x20 + unsigned char buf[NSP32_DEBUG_PROM_BUF_SIZE]; +#endif /* * EEPROM checking. @@ -3173,12 +3096,12 @@ ret = nsp32_prom_read(data, 0x7e); if (ret != 0x55) { nsp32_msg(KERN_INFO, "No EEPROM detected: 0x%x", ret); - return (FALSE); + return FALSE; } ret = nsp32_prom_read(data, 0x7f); if (ret != 0xaa) { nsp32_msg(KERN_INFO, "Invalid number: 0x%x", ret); - return (FALSE); + return FALSE; } /* @@ -3186,27 +3109,30 @@ */ if (vendor == PCI_VENDOR_ID_WORKBIT && device == PCI_DEVICE_ID_WORKBIT_STANDARD) { - ret = nsp32_getprom_standard(data); + ret = nsp32_getprom_c16(data); } else if (vendor == PCI_VENDOR_ID_WORKBIT && device == PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC) { - ret = nsp32_getprom_new(data); + ret = nsp32_getprom_at24(data); } else if (vendor == PCI_VENDOR_ID_WORKBIT && device == PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO ) { - ret = nsp32_getprom_new(data); + ret = nsp32_getprom_at24(data); } else { nsp32_msg(KERN_WARNING, "Unknown EEPROM"); ret = FALSE; } +#ifdef NSP32_DEBUG /* for debug : SPROM data full checking */ - for (i=0; i<=0x1f; i++) { - val = nsp32_prom_read(data, i); - nsp32_dbg(NSP32_DEBUG_EEPROM, - "rom address 0x%x : 0x%x", i, val); + nsp32_dbg(NSP32_DEBUG_EEPROM, "rom dump"); + for (i = 0; i < sizeof(buf); i++) { + buf[i] = nsp32_prom_read(data, i); } + nsp32_byte_dump(buf, 0, sizeof(buf)); +#endif - return (ret); + return ret; } +#undef NSP32_DEBUG_PROM_BUF_SIZE /* @@ -3233,15 +3159,15 @@ * 0x1c : Constant? (0x01) (clock div?) * 0x1d - 0x7c : Not Used (0xff) * 0x7d : Not Used? (0xff) - * 0x7e : Constant (0x55), HBA chip revision - * 0x7f : Constant (0xaa), HBA value + * 0x7e : Constant (0x55), Validity signature + * 0x7f : Constant (0xaa), Validity signature */ -static int nsp32_getprom_new(nsp32_hw_data *data) +static int nsp32_getprom_at24(nsp32_hw_data *data) { - int ret, i; - int auto_sync; - struct nsp32_target *target; - int entry; + int ret, i; + int auto_sync; + nsp32_target *target; + int entry; /* * Reset time which is designated by EEPROM. @@ -3273,8 +3199,7 @@ break; default: nsp32_msg(KERN_WARNING, - "Unsupported Auto Sync mode." - "Fall back to manual mode."); + "Unsupported Auto Sync mode. Fall back to manual mode."); auto_sync = TRUE; } @@ -3285,12 +3210,12 @@ /* * each device Synchronous Transfer Period */ - for (i=0; itarget[i]; if (auto_sync == TRUE) { target->limit_entry = 0; /* set as ULTRA20M */ } else { - ret = nsp32_prom_read(data, i); + ret = nsp32_prom_read(data, i); entry = nsp32_search_period_entry(data, target, ret); if (entry < 0) { /* search failed... set maximum speed */ @@ -3300,12 +3225,12 @@ } } - return (TRUE); + return TRUE; } /* - * ? (I-O Data: SC-NBD) data map: + * C16 110 (I-O Data: SC-NBD) data map: * * ROMADDR * 0x00 - 0x06 : Device Synchronous Transfer Period (SCSI ID 0 - 6) @@ -3321,14 +3246,14 @@ * Value 0: Disable, 1: Enable * 0x1a - 0x7c : Not Used? (0) * 0x7d : Not Used? (0xf8) - * 0x7e : Constant (0x55), HBA chip revision - * 0x7f : Constant (0xaa), HBA value + * 0x7e : Constant (0x55), Validity signature + * 0x7f : Constant (0xaa), Validity signature */ -static int nsp32_getprom_standard(nsp32_hw_data *data) +static int nsp32_getprom_c16(nsp32_hw_data *data) { - int ret, i; - struct nsp32_target *target; - int entry, val; + int ret, i; + nsp32_target *target; + int entry, val; /* * Reset time which is designated by EEPROM. @@ -3340,7 +3265,7 @@ /* * each device Synchronous Transfer Period */ - for (i=0; itarget[i]; ret = nsp32_prom_read(data, i); switch (ret) { @@ -3354,10 +3279,11 @@ val = 0x32; break; case 3: /* ASYNC */ - val = 0x0; + val = 0x00; break; default: /* default 20MB/s */ val = 0x0c; + break; } entry = nsp32_search_period_entry(data, target, val); if (entry < 0 || trans_mode == ULTRA20M_MODE) { @@ -3367,7 +3293,7 @@ target->limit_entry = entry; } - return (TRUE); + return TRUE; } @@ -3382,145 +3308,314 @@ nsp32_prom_start(data); /* device address */ - nsp32_prom_write(data, 1); /* 1 */ - nsp32_prom_write(data, 0); /* 0 */ - nsp32_prom_write(data, 1); /* 1 */ - nsp32_prom_write(data, 0); /* 0 */ - nsp32_prom_write(data, 0); /* A2: 0 (GND) */ - nsp32_prom_write(data, 0); /* A1: 0 (GND) */ - nsp32_prom_write(data, 0); /* A0: 0 (GND) */ + nsp32_prom_write_bit(data, 1); /* 1 */ + nsp32_prom_write_bit(data, 0); /* 0 */ + nsp32_prom_write_bit(data, 1); /* 1 */ + nsp32_prom_write_bit(data, 0); /* 0 */ + nsp32_prom_write_bit(data, 0); /* A2: 0 (GND) */ + nsp32_prom_write_bit(data, 0); /* A1: 0 (GND) */ + nsp32_prom_write_bit(data, 0); /* A0: 0 (GND) */ /* R/W: W for dummy write */ - nsp32_prom_write(data, 0); + nsp32_prom_write_bit(data, 0); /* ack */ - nsp32_prom_write(data, 0); + nsp32_prom_write_bit(data, 0); /* word address */ - for (i=7; i>=0; i--) { - nsp32_prom_write(data, ((romaddr >> i) & 1)); + for (i = 7; i >= 0; i--) { + nsp32_prom_write_bit(data, ((romaddr >> i) & 1)); } /* ack */ - nsp32_prom_write(data, 0); + nsp32_prom_write_bit(data, 0); /* start condition */ nsp32_prom_start(data); /* device address */ - nsp32_prom_write(data, 1); /* 1 */ - nsp32_prom_write(data, 0); /* 0 */ - nsp32_prom_write(data, 1); /* 1 */ - nsp32_prom_write(data, 0); /* 0 */ - nsp32_prom_write(data, 0); /* A2: 0 (GND) */ - nsp32_prom_write(data, 0); /* A1: 0 (GND) */ - nsp32_prom_write(data, 0); /* A0: 0 (GND) */ + nsp32_prom_write_bit(data, 1); /* 1 */ + nsp32_prom_write_bit(data, 0); /* 0 */ + nsp32_prom_write_bit(data, 1); /* 1 */ + nsp32_prom_write_bit(data, 0); /* 0 */ + nsp32_prom_write_bit(data, 0); /* A2: 0 (GND) */ + nsp32_prom_write_bit(data, 0); /* A1: 0 (GND) */ + nsp32_prom_write_bit(data, 0); /* A0: 0 (GND) */ /* R/W: R */ - nsp32_prom_write(data, 1); + nsp32_prom_write_bit(data, 1); /* ack */ - nsp32_prom_write(data, 0); + nsp32_prom_write_bit(data, 0); /* data... */ val = 0; - for (i=7; i>=0; i--) { - val += (nsp32_prom_fetch(data) << i); + for (i = 7; i >= 0; i--) { + int bit = nsp32_prom_read_bit(data) ? 1 : 0; + + val |= (bit << i); } /* no ack */ - nsp32_prom_write(data, 1); + nsp32_prom_write_bit(data, 1); /* stop condition */ nsp32_prom_stop(data); - return (val); + return val; } static void nsp32_prom_start (nsp32_hw_data *data) { /* start condition */ - nsp32_prom_set(data, SCL, 1); - nsp32_prom_set(data, SDA, 1); - nsp32_prom_set(data, ENA, 1); /* output mode */ - nsp32_prom_set(data, SDA, 0); /* keeping SCL=1 and transiting - * SDA 1->0 is start condition */ - nsp32_prom_set(data, SCL, 0); + nsp32_prom_set(data, SROM_CTL, 1); + nsp32_prom_set(data, SROM_DATA, 1); + nsp32_prom_set(data, SROM_ENABLE, 1); /* output mode */ + nsp32_prom_set(data, SROM_DATA, 0); /* keeping SROM_CTL=1 and transiting + * SROM_DATA 1->0 is start condition */ + nsp32_prom_set(data, SROM_CTL, 0); } static void nsp32_prom_stop (nsp32_hw_data *data) { /* stop condition */ - nsp32_prom_set(data, SCL, 1); - nsp32_prom_set(data, SDA, 0); - nsp32_prom_set(data, ENA, 1); /* output mode */ - nsp32_prom_set(data, SDA, 1); - nsp32_prom_set(data, SCL, 0); + nsp32_prom_set(data, SROM_CTL, 1); + nsp32_prom_set(data, SROM_DATA, 0); + nsp32_prom_set(data, SROM_ENABLE, 1); /* output mode */ + nsp32_prom_set(data, SROM_DATA, 1); + nsp32_prom_set(data, SROM_CTL, 0); } -static void nsp32_prom_write (nsp32_hw_data *data, int val) +static void nsp32_prom_write_bit(nsp32_hw_data *data, int val) { /* write */ - nsp32_prom_set(data, SDA, val); - nsp32_prom_set(data, SCL, 1); - nsp32_prom_set(data, SCL, 0); + nsp32_prom_set(data, SROM_DATA, val); + nsp32_prom_set(data, SROM_CTL, 1 ); + nsp32_prom_set(data, SROM_CTL, 0 ); } -static int nsp32_prom_fetch (nsp32_hw_data *data) +static int nsp32_prom_read_bit(nsp32_hw_data *data) { int val; /* read */ - nsp32_prom_set(data, ENA, 0); /* input mode */ - nsp32_prom_set(data, SCL, 1); - val = nsp32_prom_get(data, SDA); - nsp32_prom_set(data, SCL, 0); - nsp32_prom_set(data, ENA, 1); /* output mode */ - return (val); + nsp32_prom_set(data, SROM_ENABLE, 0); /* input mode */ + nsp32_prom_set(data, SROM_CTL, 1); + + val = nsp32_prom_get(data, SROM_DATA); + + nsp32_prom_set(data, SROM_CTL, 0); + nsp32_prom_set(data, SROM_ENABLE, 1); /* output mode */ + + return val; } static inline void nsp32_prom_set(nsp32_hw_data *data, int bit, int val) { - int cur; - int base = data->BaseAddress; + unsigned int base = data->BaseAddress; + int tmp; - switch(val) { - case 0: - cur = nsp32_index_read1(base, SERIAL_ROM_CTL); - nsp32_index_write1(base, SERIAL_ROM_CTL, cur & ~bit); - break; - case 1: - cur = nsp32_index_read1(base, SERIAL_ROM_CTL); - nsp32_index_write1(base, SERIAL_ROM_CTL, cur | bit); - break; - default: - nsp32_msg(KERN_ERR, "val must be 0 or 1"); - return; + tmp = nsp32_index_read1(base, SERIAL_ROM_CTL); + + if (val == 0) { + tmp &= ~bit; + } else { + tmp |= bit; } + nsp32_index_write1(base, SERIAL_ROM_CTL, tmp); + udelay(10); } static inline int nsp32_prom_get(nsp32_hw_data *data, int bit) { - int ret; - int base = data->BaseAddress; + unsigned int base = data->BaseAddress; + int tmp, ret; - ret = nsp32_index_read1(base, SERIAL_ROM_CTL) & bit; - switch (ret) { - case 0: + if (bit != SROM_DATA) { + nsp32_msg(KERN_ERR, "return value is not appropriate"); + return 0; + } + + + tmp = nsp32_index_read1(base, SERIAL_ROM_CTL) & bit; + + if (tmp == 0) { ret = 0; - break; - case SDA: + } else { ret = 1; - break; - default: - nsp32_msg(KERN_ERR, "return value is not appropriate"); } udelay(10); - return (ret); + return ret; +} + + +/************************************************************************** + * Power Management + */ +#ifdef CONFIG_PM +/* Save Device Context */ +static int nsp32_save_state(struct pci_dev *pdev, u32 state) +{ + struct Scsi_Host *host = pci_get_drvdata(pdev); + + nsp32_msg(KERN_INFO, "pci-save_state: stub, pdev=0x%p, state=%ld, slot=%s, host=0x%p", pdev, state, pci_name(pdev), host); + + return 0; +} + +/* Device suspended */ +static int nsp32_suspend(struct pci_dev *pdev, u32 state) +{ + struct Scsi_Host *host = pci_get_drvdata(pdev); + nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata; + + nsp32_msg(KERN_INFO, "pci-suspend: pdev=0x%p, state=%ld, slot=%s, host=0x%p", pdev, state, pci_name(pdev), host); + + pci_save_state (pdev, data->PciState); + pci_disable_device (pdev); + pci_set_power_state(pdev, state); + + return 0; +} + +/* Device woken up */ +static int nsp32_resume(struct pci_dev *pdev) +{ + struct Scsi_Host *host = pci_get_drvdata(pdev); + nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata; + unsigned short reg; + + nsp32_msg(KERN_INFO, "pci-resume: pdev=0x%p, slot=%s, host=0x%p", pdev, pci_name(pdev), host); + + pci_set_power_state(pdev, 0); + pci_enable_wake (pdev, 0, 0); + pci_restore_state (pdev, data->PciState); + + reg = nsp32_read2(data->BaseAddress, INDEX_REG); + + nsp32_msg(KERN_INFO, "io=0x%x reg=0x%x", data->BaseAddress, reg); + + if (reg == 0xffff) { + nsp32_msg(KERN_INFO, "missing device. abort resume."); + return 0; + } + + nsp32hw_init (data); + nsp32_do_bus_reset(data); + + nsp32_msg(KERN_INFO, "resume success"); + + return 0; +} + +/* Enable wake event */ +static int nsp32_enable_wake(struct pci_dev *pdev, u32 state, int enable) +{ + struct Scsi_Host *host = pci_get_drvdata(pdev); + + nsp32_msg(KERN_INFO, "pci-enable_wake: stub, pdev=0x%p, enable=%d, slot=%s, host=0x%p", pdev, enable, pci_name(pdev), host); + + return 0; +} +#endif + +/************************************************************************ + * PCI/Cardbus probe/remove routine + */ +static int __devinit nsp32_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + int ret; + nsp32_hw_data *data = &nsp32_data_base; + + nsp32_dbg(NSP32_DEBUG_REGISTER, "enter"); + + ret = pci_enable_device(pdev); + if (ret) { + nsp32_msg(KERN_ERR, "failed to enable pci device"); + return ret; + } + + data->Pci = pdev; + data->pci_devid = id; + data->IrqNumber = pdev->irq; + data->BaseAddress = pci_resource_start(pdev, 0); + data->NumAddress = pci_resource_len (pdev, 0); + data->MmioAddress = + (unsigned long)ioremap_nocache(pci_resource_start(pdev, 1), + pci_resource_len (pdev, 1)); + data->MmioLength = pci_resource_len (pdev, 1); + + pci_set_master(pdev); + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) + ret = nsp32_detect(pdev); +#else + ret = scsi_register_host(&nsp32_template); +#endif + + nsp32_msg(KERN_INFO, "irq: %i mmio: 0x%lx+0x%lx slot: %s model: %s", + pdev->irq, + data->MmioAddress, data->MmioLength, + pci_name(pdev), + nsp32_model[id->driver_data]); + + nsp32_dbg(NSP32_DEBUG_REGISTER, "exit %d", ret); + + return ret; +} + +static void __devexit nsp32_remove(struct pci_dev *pdev) +{ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) + struct Scsi_Host *host = pci_get_drvdata(pdev); +#endif + + nsp32_dbg(NSP32_DEBUG_REGISTER, "enter"); + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) + scsi_remove_host(host); + + nsp32_release(host); + + scsi_host_put(host); +#else + scsi_unregister_host(&nsp32_template); +#endif +} + + + +static struct pci_driver nsp32_driver = { + .name = "nsp32", + .id_table = nsp32_pci_table, + .probe = nsp32_probe, + .remove = __devexit_p(nsp32_remove), +#ifdef CONFIG_PM + .save_state = nsp32_save_state, + .suspend = nsp32_suspend, + .resume = nsp32_resume, + .enable_wake = nsp32_enable_wake, +#endif +}; + +/********************************************************************* + * Moule entry point + */ +static int __init init_nsp32(void) { + nsp32_msg(KERN_INFO, "loading..."); + return pci_module_init(&nsp32_driver); +} + +static void __exit exit_nsp32(void) { + nsp32_msg(KERN_INFO, "unloading..."); + pci_unregister_driver(&nsp32_driver); } +module_init(init_nsp32); +module_exit(exit_nsp32); + /* end */ diff -urN linux-2.4.22-bk29/drivers/scsi/nsp32.h linux-2.4.22-bk30/drivers/scsi/nsp32.h --- linux-2.4.22-bk29/drivers/scsi/nsp32.h 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.22-bk30/drivers/scsi/nsp32.h 2003-10-07 02:50:34.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus SCSI Host Bus Adapter driver + * Workbit NinjaSCSI-32Bi/UDE PCI/CardBus SCSI Host Bus Adapter driver * Basic data header * * This program is free software; you can redistribute it and/or modify @@ -16,61 +16,68 @@ #ifndef _NSP32_H #define _NSP32_H - //#define NSP32_DEBUG 9 - /* * VENDOR/DEVICE ID */ #define PCI_VENDOR_ID_IODATA 0x10fc #define PCI_VENDOR_ID_WORKBIT 0x1145 -#define PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II 0x0005 -#define PCI_DEVICE_ID_NINJASCSI_32BI_KME 0xf007 -#define PCI_DEVICE_ID_NINJASCSI_32BI_WBT 0x8007 -#define PCI_DEVICE_ID_WORKBIT_STANDARD 0xf010 -#define PCI_DEVICE_ID_WORKBIT_DUALEDGE 0xf011 -#define PCI_DEVICE_ID_NINJASCSI_32BI_LOGITEC 0xf012 -#define PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC 0xf013 -#define PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO 0xf015 +#define PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II 0x0005 +#define PCI_DEVICE_ID_NINJASCSI_32BI_KME 0xf007 +#define PCI_DEVICE_ID_NINJASCSI_32BI_WBT 0x8007 +#define PCI_DEVICE_ID_WORKBIT_STANDARD 0xf010 +#define PCI_DEVICE_ID_WORKBIT_DUALEDGE 0xf011 +#define PCI_DEVICE_ID_NINJASCSI_32BI_LOGITEC 0xf012 +#define PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC 0xf013 +#define PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO 0xf015 +#define PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO_II 0x8009 /* - * MODEL + * MODEL NAME + * + * note: Model number and model string must be same order. */ enum { MODEL_IODATA = 0, MODEL_KME = 1, MODEL_WORKBIT = 2, - MODEL_EXT_ROM = 3, + MODEL_LOGITEC = 3, MODEL_PCI_WORKBIT = 4, MODEL_PCI_LOGITEC = 5, MODEL_PCI_MELCO = 6, }; static char * nsp32_model[] = { - "I-O DATA CBSC-II", - "KME SCSI card", - "Workbit duo SCSI card", - "External ROM", - "Workbit Standard/IO Data PCI card", - "Logitec PCI card", - "Melco PCI card", + "I-O DATA CBSC-II CardBus card", + "KME SCSI CardBus card", + "Workbit duo SCSI CardBus card", + "Logitec CardBus card with external ROM", + "Workbit / I-O DATA PCI card", + "Logitec PCI card with external ROM", + "Melco CardBus/PCI card with external ROM", }; /* - * SCSI Generic Definitions + * SCSI generic message definitions */ #define EXTENDED_SDTR_LEN 0x03 +/* Little Endian */ +typedef u32 u32_le; +typedef u16 u16_le; /* * MACRO */ -#define BIT(x) (1UL << (x)) +/* from X11/Intrinsic.h */ +#define NUMBER(arr) ((int) (sizeof(arr) / sizeof(arr[0]))) +#define ARRAY_OFFSET(type,num) ((int) (((type *) 0) + (num))) +#define BIT(x) (1UL << (x)) #ifndef MIN -# define MIN(a,b) ((a) > (b) ? (b) : (a)) +# define MIN(a,b) ((a) > (b) ? (b) : (a)) #endif /* @@ -111,7 +118,10 @@ # define TIMER_IRQ_MASK BIT(13) # define FIFO_IRQ_MASK BIT(14) # define SCSI_IRQ_MASK BIT(15) -# define IRQ_CONTROL_ALL_IRQ_MASK 0xf000 +# define IRQ_CONTROL_ALL_IRQ_MASK (PCI_IRQ_MASK | \ + TIMER_IRQ_MASK | \ + FIFO_IRQ_MASK | \ + SCSI_IRQ_MASK ) # define IRQSTATUS_ANY_IRQ (IRQSTATUS_RESELECT_OCCUER | \ IRQSTATUS_PHASE_CHANGE_IRQ | \ IRQSTATUS_SCSIRESET_IRQ | \ @@ -121,8 +131,8 @@ IRQSTATUS_BMCNTERR_IRQ | \ IRQSTATUS_AUTOSCSI_IRQ ) -#define TRANSFER_CONTROL 0x02 /* BASE+02, W, W */ -#define TRANSFER_STATUS 0x02 /* BASE+02, W, R */ +#define TRANSFER_CONTROL 0x02 /* BASE+02, W, W */ +#define TRANSFER_STATUS 0x02 /* BASE+02, W, R */ # define CB_MMIO_MODE BIT(0) # define CB_IO_MODE BIT(1) # define BM_TEST BIT(2) @@ -139,26 +149,29 @@ # define ALL_COUNTER_CLR BIT(14) # define FIFOTEST BIT(15) -#define INDEX_REG 0x04 /* BASE+04, Byte(R/W), Word(R) */ +#define INDEX_REG 0x04 /* BASE+04, Byte(R/W), Word(R) */ -#define TIMER_SET 0x06 /* BASE+06, W, R/W */ -# define TIMER_CNT_MASK 0xff +#define TIMER_SET 0x06 /* BASE+06, W, R/W */ +# define TIMER_CNT_MASK (0xff) # define TIMER_STOP BIT(8) -#define DATA_REG_LOW 0x08 /* BASE+08, LowW, R/W */ -#define DATA_REG_HI 0x0a /* BASE+0a, Hi-W, R/W */ +#define DATA_REG_LOW 0x08 /* BASE+08, LowW, R/W */ +#define DATA_REG_HI 0x0a /* BASE+0a, Hi-W, R/W */ -#define FIFO_REST_CNT 0x0c /* BASE+0c, W, R/W */ +#define FIFO_REST_CNT 0x0c /* BASE+0c, W, R/W */ # define FIFO_REST_MASK 0x1ff # define FIFO_EMPTY_SHLD_FLAG BIT(14) # define FIFO_FULL_SHLD_FLAG BIT(15) -#define SREQ_SMPL_RATE 0x0f /* BASE+0f, B, R/W */ +#define SREQ_SMPL_RATE 0x0f /* BASE+0f, B, R/W */ # define SREQSMPLRATE_RATE0 BIT(0) # define SREQSMPLRATE_RATE1 BIT(1) # define SAMPLING_ENABLE BIT(2) +# define SMPL_40M (0) /* 40MHz: 0-100ns/period */ +# define SMPL_20M (SREQSMPLRATE_RATE0) /* 20MHz: 100-200ns/period */ +# define SMPL_10M (SREQSMPLRATE_RATE1) /* 10Mhz: 200- ns/period */ -#define SCSI_BUS_CONTROL 0x10 /* BASE+10, B, R/W */ +#define SCSI_BUS_CONTROL 0x10 /* BASE+10, B, R/W */ # define BUSCTL_SEL BIT(0) # define BUSCTL_RST BIT(1) # define BUSCTL_DATAOUT_ENB BIT(2) @@ -168,16 +181,21 @@ # define AUTODIRECTION BIT(6) # define ACKENB BIT(7) -#define CLR_COUNTER 0x12 /* BASE+12, B, W */ +#define CLR_COUNTER 0x12 /* BASE+12, B, W */ # define ACK_COUNTER_CLR BIT(0) # define SREQ_COUNTER_CLR BIT(1) # define FIFO_HOST_POINTER_CLR BIT(2) # define FIFO_REST_COUNT_CLR BIT(3) # define BM_COUNTER_CLR BIT(4) # define SAVED_ACK_CLR BIT(5) -# define CLRCOUNTER_ALLMASK (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5)) +# define CLRCOUNTER_ALLMASK (ACK_COUNTER_CLR | \ + SREQ_COUNTER_CLR | \ + FIFO_HOST_POINTER_CLR | \ + FIFO_REST_COUNT_CLR | \ + BM_COUNTER_CLR | \ + SAVED_ACK_CLR ) -#define SCSI_BUS_MONITOR 0x12 /* BASE+12, B, R */ +#define SCSI_BUS_MONITOR 0x12 /* BASE+12, B, R */ # define BUSMON_MSG BIT(0) # define BUSMON_IO BIT(1) # define BUSMON_CD BIT(2) @@ -187,20 +205,20 @@ # define BUSMON_SEL BIT(6) # define BUSMON_ATN BIT(7) -#define COMMAND_DATA 0x14 /* BASE+14, B, R/W */ +#define COMMAND_DATA 0x14 /* BASE+14, B, R/W */ -#define PARITY_CONTROL 0x16 /* BASE+16, B, R/W */ +#define PARITY_CONTROL 0x16 /* BASE+16, B, W */ # define PARITY_CHECK_ENABLE BIT(0) # define PARITY_ERROR_CLEAR BIT(1) -#define PARITY_STATUS 0x16 +#define PARITY_STATUS 0x16 /* BASE+16, B, R */ //# define PARITY_CHECK_ENABLE BIT(0) # define PARITY_ERROR_NORMAL BIT(1) # define PARITY_ERROR_LSB BIT(1) # define PARITY_ERROR_MSB BIT(2) -#define RESELECT_ID 0x18 /* BASE+18, B, R */ +#define RESELECT_ID 0x18 /* BASE+18, B, R */ -#define COMMAND_CONTROL 0x18 /* BASE+18, W, W */ +#define COMMAND_CONTROL 0x18 /* BASE+18, W, W */ # define CLEAR_CDB_FIFO_POINTER BIT(0) # define AUTO_COMMAND_PHASE BIT(1) # define AUTOSCSI_START BIT(2) @@ -211,27 +229,27 @@ # define AUTO_MSGIN_02 BIT(7) # define AUTO_MSGIN_03 BIT(8) -#define SET_ARBIT 0x1a /* BASE+1a, B, W */ +#define SET_ARBIT 0x1a /* BASE+1a, B, W */ # define ARBIT_GO BIT(0) # define ARBIT_CLEAR BIT(1) -#define ARBIT_STATUS 0x1a /* BASE+1a, B, R */ +#define ARBIT_STATUS 0x1a /* BASE+1a, B, R */ //# define ARBIT_GO BIT(0) # define ARBIT_WIN BIT(1) # define ARBIT_FAIL BIT(2) # define AUTO_PARAMETER_VALID BIT(3) # define SGT_VALID BIT(4) -#define SYNC_REG 0x1c /* BASE+1c, B, R/W */ +#define SYNC_REG 0x1c /* BASE+1c, B, R/W */ -#define ACK_WIDTH 0x1d /* BASE+1d, B, R/W */ +#define ACK_WIDTH 0x1d /* BASE+1d, B, R/W */ -#define SCSI_DATA_WITH_ACK 0x20 /* BASE+20, B, R/W */ +#define SCSI_DATA_WITH_ACK 0x20 /* BASE+20, B, R/W */ #define SCSI_OUT_LATCH_TARGET_ID 0x22 /* BASE+22, B, W */ -#define SCSI_DATA_IN 0x22 /* BASE+22, B, R */ +#define SCSI_DATA_IN 0x22 /* BASE+22, B, R */ -#define SCAM_CONTROL 0x24 /* BASE+24, B, W */ -#define SCAM_STATUS 0x24 /* BASE+24, B, R */ +#define SCAM_CONTROL 0x24 /* BASE+24, B, W */ +#define SCAM_STATUS 0x24 /* BASE+24, B, R */ # define SCAM_MSG BIT(0) # define SCAM_IO BIT(1) # define SCAM_CD BIT(2) @@ -239,31 +257,31 @@ # define SCAM_SEL BIT(4) # define SCAM_XFEROK BIT(5) -#define SCAM_DATA 0x26 /* BASE+26, B, R/W */ -# define SD0 BIT(0) -# define SD1 BIT(1) -# define SD2 BIT(2) -# define SD3 BIT(3) -# define SD4 BIT(4) -# define SD5 BIT(5) -# define SD6 BIT(6) -# define SD7 BIT(7) - -#define SACK_CNT 0x28 /* BASE+28, DW, R/W */ -#define SREQ_CNT 0x2c /* BASE+2c, DW, R/W */ - -#define FIFO_DATA_LOW 0x30 /* BASE+30, B/W/DW, R/W */ -#define FIFO_DATA_HIGH 0x32 /* BASE+32, B/W, R/W */ -#define BM_START_ADR 0x34 /* BASE+34, DW, R/W */ - -#define BM_CNT 0x38 /* BASE+38, DW, R/W */ -# define BM_COUNT_MASK 0x0001ffff -# define SGTEND BIT(31) +#define SCAM_DATA 0x26 /* BASE+26, B, R/W */ +# define SD0 BIT(0) +# define SD1 BIT(1) +# define SD2 BIT(2) +# define SD3 BIT(3) +# define SD4 BIT(4) +# define SD5 BIT(5) +# define SD6 BIT(6) +# define SD7 BIT(7) + +#define SACK_CNT 0x28 /* BASE+28, DW, R/W */ +#define SREQ_CNT 0x2c /* BASE+2c, DW, R/W */ + +#define FIFO_DATA_LOW 0x30 /* BASE+30, B/W/DW, R/W */ +#define FIFO_DATA_HIGH 0x32 /* BASE+32, B/W, R/W */ +#define BM_START_ADR 0x34 /* BASE+34, DW, R/W */ + +#define BM_CNT 0x38 /* BASE+38, DW, R/W */ +# define BM_COUNT_MASK 0x0001ffffUL +# define SGTEND BIT(31) /* Last SGT marker */ -#define SGT_ADR 0x3c /* BASE+3c, DW, R/W */ -#define WAIT_REG 0x40 /* Bi only */ +#define SGT_ADR 0x3c /* BASE+3c, DW, R/W */ +#define WAIT_REG 0x40 /* Bi only */ -#define SCSI_EXECUTE_PHASE 0x40 /* BASE+40, W, R */ +#define SCSI_EXECUTE_PHASE 0x40 /* BASE+40, W, R */ # define COMMAND_PHASE BIT(0) # define DATA_IN_PHASE BIT(1) # define DATA_OUT_PHASE BIT(2) @@ -280,14 +298,14 @@ # define MSGIN_04_VALID BIT(13) # define AUTOSCSI_BUSY BIT(15) -#define SCSI_CSB_IN 0x42 /* BASE+42, B, R */ +#define SCSI_CSB_IN 0x42 /* BASE+42, B, R */ -#define SCSI_MSG_OUT 0x44 /* BASE+44, DW, R/W */ +#define SCSI_MSG_OUT 0x44 /* BASE+44, DW, R/W */ # define MSGOUT_COUNT_MASK (BIT(0)|BIT(1)) -# define MV_VALID BIT(7) +# define MSGOUT_VALID BIT(7) -#define SEL_TIME_OUT 0x48 /* BASE+48, W, R/W */ -#define SAVED_SACK_CNT 0x4c /* BASE+4c, DW, R */ +#define SEL_TIME_OUT 0x48 /* BASE+48, W, R/W */ +#define SAVED_SACK_CNT 0x4c /* BASE+4c, DW, R */ #define HTOSDATADELAY 0x50 /* BASE+50, B, R/W */ #define STOHDATADELAY 0x54 /* BASE+54, B, R/W */ @@ -299,21 +317,21 @@ /* indexed register */ /********************/ -#define CLOCK_DIV 0x00 /* BASE+08, IDX+00, B, R/W */ -# define CLOCK_2 BIT(0) /* MCLK/2 */ -# define CLOCK_4 BIT(1) /* MCLK/4 */ -# define PCICLK BIT(7) /* PCICLK (33MHz) */ +#define CLOCK_DIV 0x00 /* BASE+08, IDX+00, B, R/W */ +# define CLOCK_2 BIT(0) /* MCLK/2 */ +# define CLOCK_4 BIT(1) /* MCLK/4 */ +# define PCICLK BIT(7) /* PCICLK (33MHz) */ -#define TERM_PWR_CONTROL 0x01 /* BASE+08, IDX+01, B, R/W */ +#define TERM_PWR_CONTROL 0x01 /* BASE+08, IDX+01, B, R/W */ # define BPWR BIT(0) # define SENSE BIT(1) /* Read Only */ -#define EXT_PORT_DDR 0x02 /* BASE+08, IDX+02, B, R/W */ -#define EXT_PORT 0x03 /* BASE+08, IDX+03, B, R/W */ -# define LED_ON 0 -# define LED_OFF 1 +#define EXT_PORT_DDR 0x02 /* BASE+08, IDX+02, B, R/W */ +#define EXT_PORT 0x03 /* BASE+08, IDX+03, B, R/W */ +# define LED_ON (0) +# define LED_OFF BIT(0) -#define IRQ_SELECT 0x04 /* BASE+08, IDX+04, W, R/W */ +#define IRQ_SELECT 0x04 /* BASE+08, IDX+04, W, R/W */ # define IRQSELECT_RESELECT_IRQ BIT(0) # define IRQSELECT_PHASE_CHANGE_IRQ BIT(1) # define IRQSELECT_SCSIRESET_IRQ BIT(2) @@ -326,32 +344,35 @@ # define IRQSELECT_BMCNTERR_IRQ BIT(9) # define IRQSELECT_AUTO_SCSI_SEQ_IRQ BIT(10) -#define OLD_SCSI_PHASE 0x05 /* BASE+08, IDX+05, B, R */ +#define OLD_SCSI_PHASE 0x05 /* BASE+08, IDX+05, B, R */ # define OLD_MSG BIT(0) # define OLD_IO BIT(1) # define OLD_CD BIT(2) # define OLD_BUSY BIT(3) -#define FIFO_FULL_SHLD_COUNT 0x06 /* BASE+08, IDX+06, B, R/W */ -#define FIFO_EMPTY_SHLD_COUNT 0x07 /* BASE+08, IDX+07, B, R/W */ +#define FIFO_FULL_SHLD_COUNT 0x06 /* BASE+08, IDX+06, B, R/W */ +#define FIFO_EMPTY_SHLD_COUNT 0x07 /* BASE+08, IDX+07, B, R/W */ -#define EXP_ROM_CONTROL 0x08 /* BASE+08, IDX+08, B, R/W */ +#define EXP_ROM_CONTROL 0x08 /* BASE+08, IDX+08, B, R/W */ /* external ROM control */ +# define ROM_WRITE_ENB BIT(0) +# define IO_ACCESS_ENB BIT(1) +# define ROM_ADR_CLEAR BIT(2) -#define EXP_ROM_ADRL 0x09 /* BASE+08, IDX+09, W, R/W */ +#define EXP_ROM_ADR 0x09 /* BASE+08, IDX+09, W, R/W */ #define EXP_ROM_DATA 0x0a /* BASE+08, IDX+0a, B, R/W */ -#define CHIP_MODE 0x0b /* Bi only */ -# define OEM0 BIT(1) -# define OEM1 BIT(2) -# define OPTB BIT(3) -# define OPTC BIT(4) -# define OPTD BIT(5) -# define OPTE BIT(6) -# define OPTF BIT(7) +#define CHIP_MODE 0x0b /* BASE+08, IDX+0b, B, R */ /* NinjaSCSI-32Bi only */ +# define OEM0 BIT(1) /* OEM select */ /* 00=I-O DATA, 01=KME, 10=Workbit, 11=Ext ROM */ +# define OEM1 BIT(2) /* OEM select */ +# define OPTB BIT(3) /* KME mode select */ +# define OPTC BIT(4) /* KME mode select */ +# define OPTD BIT(5) /* KME mode select */ +# define OPTE BIT(6) /* KME mode select */ +# define OPTF BIT(7) /* Power management */ -#define MISC_WR 0x0c /* BASE+08, IDX+0c, W, R/W */ -#define MISC_RD 0x0c +#define MISC_WR 0x0c /* BASE+08, IDX+0c, W, R/W */ +#define MISC_RD 0x0c # define SCSI_DIRECTION_DETECTOR_SELECT BIT(0) # define SCSI2_HOST_DIRECTION_VALID BIT(1) /* Read only */ # define HOST2_SCSI_DIRECTION_VALID BIT(2) /* Read only */ @@ -362,7 +383,7 @@ # define MISC_MABORT_MASK BIT(7) # define BMSTOP_CHANGE2_NONDATA_PHASE BIT(8) -#define BM_CYCLE 0x0d /* BASE+08, IDX+0d, B, R/W */ +#define BM_CYCLE 0x0d /* BASE+08, IDX+0d, B, R/W */ # define BM_CYCLE0 BIT(0) # define BM_CYCLE1 BIT(1) # define BM_FRAME_ASSERT_TIMING BIT(2) @@ -373,20 +394,26 @@ # define MEMRD_CMD1 BIT(7) -#define SREQ_EDGH 0x0e /* BASE+08, IDX+0e, B, W */ +#define SREQ_EDGH 0x0e /* BASE+08, IDX+0e, B, W */ # define SREQ_EDGH_SELECT BIT(0) -#define UP_CNT 0x0f /* BASE+08, IDX+0f, B, W */ -#define CFG_CMD_STR 0x10 /* BASE+08, IDX+10, W, R */ -#define CFG_LATE_CACHE 0x11 /* BASE+08, IDX+11, W, R/W */ -#define CFG_BASE_ADR_1 0x12 /* BASE+08, IDX+12, W, R */ -#define CFG_BASE_ADR_2 0x13 /* BASE+08, IDX+13, W, R */ -#define CFG_INLINE 0x14 /* BASE+08, IDX+14, W, R */ - -#define SERIAL_ROM_CTL 0x15 /* BASE+08, IDX+15, B, R */ -# define SCL BIT(0) -# define ENA BIT(1) -# define SDA BIT(2) +#define UP_CNT 0x0f /* BASE+08, IDX+0f, B, W */ /* For hardware testing. Don't use it. */ +# define REQCNT_UP BIT(0) +# define ACKCNT_UP BIT(1) +# define BMADR_UP BIT(4) +# define BMCNT_UP BIT(5) +# define SGT_CNT_UP BIT(7) + +#define CFG_CMD_STR 0x10 /* BASE+08, IDX+10, W, R */ +#define CFG_LATE_CACHE 0x11 /* BASE+08, IDX+11, W, R/W */ +#define CFG_BASE_ADR_1 0x12 /* BASE+08, IDX+12, W, R */ +#define CFG_BASE_ADR_2 0x13 /* BASE+08, IDX+13, W, R */ +#define CFG_INLINE 0x14 /* BASE+08, IDX+14, W, R */ + +#define SERIAL_ROM_CTL 0x15 /* BASE+08, IDX+15, B, R */ +# define SROM_CTL BIT(0) +# define SROM_ENABLE BIT(1) +# define SROM_DATA BIT(2) #define FIFO_HST_POINTER 0x16 /* BASE+08, IDX+16, B, R/W */ #define SREQ_DELAY 0x17 /* BASE+08, IDX+17, B, R/W */ @@ -425,5 +452,237 @@ #define BUSPHASE_STATUS ( BUSMON_STATUS & BUSMON_PHASE_MASK ) #define BUSPHASE_SELECT ( BUSMON_SEL | BUSMON_IO ) + +/************************************************************************ + * structure for DMA/Scatter Gather list + */ +#define NSP32_SG_SIZE SG_ALL + +/* All values must be little endian */ +typedef struct _nsp32_sgtable { + u32_le addr; /* transfer address */ + u32_le len; /* transfer length. BIT(31) is for SGTEND mark */ +} __attribute__ ((packed)) nsp32_sgtable; + +/* All values must be little endian */ +typedef struct _nsp32_sglun { + nsp32_sgtable sgt[NSP32_SG_SIZE+1]; /* SG table */ +} __attribute__ ((packed)) nsp32_sglun; +#define NSP32_SG_TABLE_SIZE (sizeof(nsp32_sgtable) * NSP32_SG_SIZE * MAX_TARGET * MAX_LUN) + +/* Auto parameter mode memory map. */ +/* All values must be little endian. */ +typedef struct _nsp32_autoparam { + u8 cdb[4 * 0x10]; /* SCSI Command */ + u32_le msgout; /* outgoing messages */ + u8 syncreg; /* sync register value */ + u8 ackwidth; /* ack width register value */ + u8 target_id; /* target/host device id */ + u8 sample_reg; /* hazard killer sampling rate */ + u16_le command_control; /* command control register */ + u16_le transfer_control; /* transfer control register */ + u32_le sgt_pointer; /* SG table physical address for DMA */ + u32_le dummy[2]; +} __attribute__ ((packed)) nsp32_autoparam; /* must be packed struct */ + +/* + * host data structure + */ +/* message in/out buffer */ +#define MSGOUTBUF_MAX 20 +#define MSGINBUF_MAX 20 + +/* flag for trans_method */ +#define NSP32_TRANSFER_BUSMASTER BIT(0) +#define NSP32_TRANSFER_MMIO BIT(1) /* Not supported yet */ +#define NSP32_TRANSFER_PIO BIT(2) /* Not supported yet */ + + +/* + * structure for connected LUN dynamic data + * + * Note: Currently tagged queuing is disabled, each nsp32_lunt holds + * one SCSI command and one state. + */ +#define DISCPRIV_OK BIT(0) /* DISCPRIV Enable mode */ +#define MSGIN03 BIT(1) /* Auto Msg In 03 Flag */ + +typedef struct _nsp32_lunt { + Scsi_Cmnd *SCpnt; /* Current Handling Scsi_Cmnd */ + unsigned long save_datp; /* Save Data Pointer - saved position from initial address */ + int msgin03; /* auto msg in 03 flag */ + unsigned int sg_num; /* Total number of SG entries */ + int cur_entry; /* Current SG entry number */ + nsp32_sglun *sglun; /* sg table per lun */ + dma_addr_t sglun_paddr; /* sglun physical address */ +} nsp32_lunt; + + +/* + * SCSI TARGET/LUN definition + */ +#define NSP32_HOST_SCSIID 7 /* SCSI initiator is everytime defined as 7 */ +#define MAX_TARGET 8 +#define MAX_LUN 8 /* XXX: In SPI3, max number of LUN is 64. */ + + +typedef struct _nsp32_sync_table { + unsigned char period_num; /* period number */ + unsigned char ackwidth; /* ack width designated by period */ + unsigned char start_period; /* search range - start period */ + unsigned char end_period; /* search range - end period */ + unsigned char sample_rate; /* hazard killer parameter */ +} nsp32_sync_table; + + +/* + * structure for target device static data + */ +/* flag for nsp32_target.sync_flag */ +#define SDTR_NONE 0 /* initial state */ +#define SDTR_INITIATOR BIT(0) /* sending SDTR from initiator */ +#define SDTR_TARGET BIT(1) /* sending SDTR from target */ +#define SDTR_DONE BIT(2) /* exchanging SDTR has been processed */ + +/* syncronous period value for nsp32_target.config_max */ +#define FAST5M 0x32 +#define FAST10M 0x19 +#define ULTRA20M 0x0c + +/* flag for nsp32_target.{sync_offset, period} */ +#define ASYNC_OFFSET 0 /* asynchronous transfer */ +#define MAX_OFFSET 0xf /* synchronous transfer max offset */ + +/* syncreg: + bit:07 06 05 04 03 02 01 00 + ---PERIOD-- ---OFFSET-- */ +#define TO_SYNCREG(period, offset) (((period) & 0x0f) << 4 | ((offset) & 0x0f)) + +typedef struct _nsp32_target { + unsigned char syncreg; /* value for SYNCREG */ + unsigned char ackwidth; /* value for ACKWIDTH */ + unsigned char period; /* sync period (0-255) */ + unsigned char offset; /* sync offset (0-15) */ + int sync_flag; /* SDTR_*, 0 */ + int limit_entry; /* max speed limit entry designated + by EEPROM configuration */ + unsigned char sample_reg; /* SREQ hazard killer register */ +} nsp32_target; + +typedef struct _nsp32_hw_data { + int IrqNumber; + int BaseAddress; + int NumAddress; + unsigned long MmioAddress; +#define NSP32_MMIO_OFFSET 0x0800 + unsigned long MmioLength; + + Scsi_Cmnd *CurrentSC; + + struct pci_dev *Pci; + const struct pci_device_id *pci_devid; + struct Scsi_Host *Host; + spinlock_t Lock; + + char info_str[100]; + + /* allocated memory region */ + nsp32_sglun *sg_list; /* sglist virtuxal address */ + dma_addr_t sg_paddr; /* physical address of hw_sg_table */ + nsp32_autoparam *autoparam; /* auto parameter transfer region */ + dma_addr_t auto_paddr; /* physical address of autoparam */ + int cur_entry; /* current sgt entry */ + + /* target/LUN */ + nsp32_lunt *cur_lunt; /* Current connected LUN table */ + nsp32_lunt lunt[MAX_TARGET][MAX_LUN]; /* All LUN table */ + + nsp32_target *cur_target; /* Current connected SCSI ID */ + nsp32_target target[MAX_TARGET]; /* SCSI ID */ + int cur_id; /* Current connected target ID */ + int cur_lun; /* Current connected target LUN */ + + /* behavior setting parameters */ + int trans_method; /* transfer method flag */ + int resettime; /* Reset time */ + int clock; /* clock dividing flag */ + nsp32_sync_table *synct; /* sync_table determined by clock */ + int syncnum; /* the max number of synct element */ + + /* message buffer */ + unsigned char msgoutbuf[MSGOUTBUF_MAX]; /* msgout buffer */ + char msgout_len; /* msgoutbuf length */ + unsigned char msginbuf [MSGINBUF_MAX]; /* megin buffer */ + char msgin_len; /* msginbuf length */ + +#ifdef CONFIG_PM + u32 PciState[16]; /* save PCI state to this area */ +#endif +} nsp32_hw_data; + +/* + * TIME definition + */ +#define RESET_HOLD_TIME 10000 /* reset time in us (SCSI-2 says the + minimum is 25us) */ +#define SEL_TIMEOUT_TIME 10000 /* 250ms defined in SCSI specification + (25.6us/1unit) */ +#define ARBIT_TIMEOUT_TIME 100 /* 100us */ +#define REQSACK_TIMEOUT_TIME 10000 /* max wait time for REQ/SACK assertion + or negation, 10000us == 10ms */ + +/************************************************************************** + * Compatibility functions + */ + +/* for Kernel 2.4 */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) +# define scsi_register_host(template) scsi_register_module(MODULE_SCSI_HA, template) +# define scsi_unregister_host(template) scsi_unregister_module(MODULE_SCSI_HA, template) +# define scsi_host_put(host) scsi_unregister(host) +# define pci_name(pci_dev) ((pci_dev)->slot_name) + +typedef void irqreturn_t; +# define IRQ_NONE /* */ +# define IRQ_HANDLED /* */ +# define IRQ_RETVAL(x) /* */ + +/* This is ad-hoc version of scsi_host_get_next() */ +static inline struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *host) +{ + if (host == NULL) { + return scsi_hostlist; + } else { + return host->next; + } +} + +/* This is ad-hoc version of scsi_host_hn_get() */ +static inline struct Scsi_Host *scsi_host_hn_get(unsigned short hostno) +{ + struct Scsi_Host *host; + + for (host = scsi_host_get_next(NULL); host != NULL; + host = scsi_host_get_next(host)) { + if (host->host_no == hostno) { + break; + } + } + + return host; +} + +/* host spin lock */ +# define HOST_LOCK (&io_request_lock) +#endif + +/* for Kernel 2.6 */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) +# define __devinitdata /* */ + +/* host spin lock */ +# define HOST_LOCK (data->Host->host_lock) +#endif + #endif /* _NSP32_H */ /* end */ diff -urN linux-2.4.22-bk29/drivers/scsi/nsp32_debug.c linux-2.4.22-bk30/drivers/scsi/nsp32_debug.c --- linux-2.4.22-bk29/drivers/scsi/nsp32_debug.c 2003-06-13 07:51:36.000000000 -0700 +++ linux-2.4.22-bk30/drivers/scsi/nsp32_debug.c 2003-10-07 02:50:34.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus SCSI Host Bus Adapter driver + * Workbit NinjaSCSI-32Bi/UDE PCI/CardBus SCSI Host Bus Adapter driver * Debug routine * * This software may be used and distributed according to the terms of @@ -85,22 +85,22 @@ static void print_commandk (unsigned char *command) { - int i,s; + int i, size; // printk(KERN_DEBUG); print_opcodek(command[0]); - /*printk(KERN_DEBUG __func__ " ");*/ + /*printk(KERN_DEBUG "%s ", __FUNCTION__);*/ if ((command[0] >> 5) == 6 || (command[0] >> 5) == 7 ) { - s = 12; /* vender specific */ + size = 12; /* vender specific */ } else { - s = COMMAND_SIZE(command[0]); + size = COMMAND_SIZE(command[0]); } for ( i = 1; i < s; ++i) { printk("%02x ", command[i]); } - switch (s) { + switch (size) { case 6: printk("LBA=%d len=%d", (((unsigned int)command[1] & 0x0f) << 16) | @@ -137,9 +137,9 @@ printk("\n"); } -static void show_command(Scsi_Cmnd *ptr) +static void show_command(Scsi_Cmnd *SCpnt) { - print_commandk(ptr->cmnd); + print_commandk(SCpnt->cmnd); } static void show_busphase(unsigned char stat) @@ -260,3 +260,45 @@ } } +/* + * Byte dumper + * + * ptr: start address + * offset: offset value for address section + * size: dump size in byte + */ +static void nsp32_byte_dump(void *ptr, int offset, int size) +{ + unsigned char *tmp = ptr; + int pos; + + if (size == 0) { + return; + } + + pos = 0; + while(pos < size) { + /* address */ + if (pos % 16 == 0) { + printk(/*KERN_DEBUG*/ "%08x:", pos + offset); + } + + /* half separator */ + if (pos % 16 == 8) { + printk(" -"); + } + + printk(" %02x", tmp[pos]); + + /* Don't print "\n" at last line. + Because we can get one more "\n". */ + if ((pos % 16 == 15) && (pos + 1 != size)) { + printk("\n"); + } + + pos ++; + } + printk("\n"); +} + +/* end */ diff -urN linux-2.4.22-bk29/drivers/scsi/nsp32_io.h linux-2.4.22-bk30/drivers/scsi/nsp32_io.h --- linux-2.4.22-bk29/drivers/scsi/nsp32_io.h 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.22-bk30/drivers/scsi/nsp32_io.h 2003-10-07 02:50:34.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus SCSI Host Bus Adapter driver + * Workbit NinjaSCSI-32Bi/UDE PCI/CardBus SCSI Host Bus Adapter driver * I/O routine * * This software may be used and distributed according to the terms of @@ -22,30 +22,30 @@ return inb(base + index); } -static inline void nsp32_write2(unsigned int base, - unsigned int index, +static inline void nsp32_write2(unsigned int base, + unsigned int index, unsigned short val) { - outw(cpu_to_le16(val), (base + index)); + outw(val, (base + index)); } static inline unsigned short nsp32_read2(unsigned int base, unsigned int index) { - return le16_to_cpu(inw(base + index)); + return inw(base + index); } static inline void nsp32_write4(unsigned int base, unsigned int index, unsigned long val) { - outl(cpu_to_le32(val), (base + index)); + outl(val, (base + index)); } static inline unsigned long nsp32_read4(unsigned int base, unsigned int index) { - return le32_to_cpu(inl(base + index)); + return inl(base + index); } /*==============================================*/ @@ -58,7 +58,7 @@ ptr = (unsigned char *)(base + NSP32_MMIO_OFFSET + index); - *ptr = val; + writeb(val, ptr); } static inline unsigned char nsp32_mmio_read1(unsigned long base, @@ -68,18 +68,18 @@ ptr = (unsigned char *)(base + NSP32_MMIO_OFFSET + index); - return *ptr; + return readb(ptr); } -static inline void nsp32_mmio_write2(unsigned long base, - unsigned int index, +static inline void nsp32_mmio_write2(unsigned long base, + unsigned int index, unsigned short val) { volatile unsigned short *ptr; ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + index); - *ptr = cpu_to_le16(val); + writew(cpu_to_le16(val), ptr); } static inline unsigned short nsp32_mmio_read2(unsigned long base, @@ -87,11 +87,9 @@ { volatile unsigned short *ptr; - //printk(__FUNCTION__ "\n"); - ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + index); - return le16_to_cpu(*ptr); + return le16_to_cpu(readw(ptr)); } static inline void nsp32_mmio_write4(unsigned long base, @@ -102,7 +100,7 @@ ptr = (unsigned long *)(base + NSP32_MMIO_OFFSET + index); - *ptr = cpu_to_le32(val); + writel(cpu_to_le32(val), ptr); } static inline unsigned long nsp32_mmio_read4(unsigned long base, @@ -110,16 +108,12 @@ { volatile unsigned long *ptr; - //printk(__FUNCTION__ "\n"); - ptr = (unsigned long *)(base + NSP32_MMIO_OFFSET + index); - return le32_to_cpu(*ptr); + return le32_to_cpu(readl(ptr)); } - -/*=============================================*/ - +/*==============================================*/ static inline unsigned char nsp32_index_read1(unsigned int base, unsigned int reg) @@ -132,7 +126,7 @@ unsigned int reg, unsigned char val) { - outb(reg, base + INDEX_REG); + outb(reg, base + INDEX_REG ); outb(val, base + DATA_REG_LOW); } @@ -140,15 +134,15 @@ unsigned int reg) { outb(reg, base + INDEX_REG); - return le16_to_cpu(inw(base + DATA_REG_LOW)); + return inw(base + DATA_REG_LOW); } -static inline void nsp32_index_write2(unsigned int base, - unsigned int reg, +static inline void nsp32_index_write2(unsigned int base, + unsigned int reg, unsigned short val) { - outb(reg, base + INDEX_REG); - outw(cpu_to_le16(val), base + DATA_REG_LOW); + outb(reg, base + INDEX_REG ); + outw(val, base + DATA_REG_LOW); } static inline unsigned long nsp32_index_read4(unsigned int base, @@ -157,8 +151,8 @@ unsigned long h,l; outb(reg, base + INDEX_REG); - l = le16_to_cpu(inw(base + DATA_REG_LOW)); - h = le16_to_cpu(inw(base + DATA_REG_HI )); + l = inw(base + DATA_REG_LOW); + h = inw(base + DATA_REG_HI ); return ((h << 16) | l); } @@ -170,15 +164,14 @@ unsigned long h,l; h = (val & 0xffff0000) >> 16; - l = (val & 0x0000ffff) >> 0; + l = (val & 0x0000ffff) >> 0; - outb(reg, base + INDEX_REG); - outw(cpu_to_le16(l), base + DATA_REG_LOW); - outw(cpu_to_le16(h), base + DATA_REG_HI); + outb(reg, base + INDEX_REG ); + outw(l, base + DATA_REG_LOW); + outw(h, base + DATA_REG_HI ); } - -/* ===================================*/ +/*==============================================*/ static inline unsigned char nsp32_mmio_index_read1(unsigned int base, unsigned int reg) @@ -188,13 +181,12 @@ index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG); data_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW); - *index_ptr = reg; - - return ((*data_ptr) & 0xff); + writeb(reg, index_ptr); + return readb(data_ptr); } -static inline void nsp32_mmio_index_write1(unsigned int base, - unsigned int reg, +static inline void nsp32_mmio_index_write1(unsigned int base, + unsigned int reg, unsigned char val) { volatile unsigned short *index_ptr, *data_ptr; @@ -202,8 +194,8 @@ index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG); data_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW); - *index_ptr = reg; - *data_ptr = (unsigned short)val; + writeb(reg, index_ptr); + writeb(val, data_ptr ); } static inline unsigned short nsp32_mmio_index_read2(unsigned int base, @@ -214,13 +206,12 @@ index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG); data_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW); - *index_ptr = reg; - - return le16_to_cpu(*data_ptr); + writeb(reg, index_ptr); + return le16_to_cpu(readw(data_ptr)); } -static inline void nsp32_mmio_index_write2(unsigned int base, - unsigned int reg, +static inline void nsp32_mmio_index_write2(unsigned int base, + unsigned int reg, unsigned short val) { volatile unsigned short *index_ptr, *data_ptr; @@ -228,34 +219,33 @@ index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG); data_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW); - *index_ptr = reg; - *data_ptr = val; + writeb(reg, index_ptr); + writew(cpu_to_le16(val), data_ptr ); } -/*-------------------------------------------------------------------*/ +/*==============================================*/ -static inline void nsp32_multi_read4(unsigned int BaseAddr, - unsigned int Register, +static inline void nsp32_multi_read4(unsigned int base, + unsigned int reg, void *buf, unsigned long count) { - insl(BaseAddr + Register, buf, count); + insl(base + reg, buf, count); } static inline void nsp32_fifo_read(unsigned int base, void *buf, unsigned long count) { - //DEBUG(0, __FUNCTION__ "() buf=0x%p, count=0x%lx*4\n", buf, count); nsp32_multi_read4(base, FIFO_DATA_LOW, buf, count); } -static inline void nsp32_multi_write4(unsigned int BaseAddr, - unsigned int Register, +static inline void nsp32_multi_write4(unsigned int base, + unsigned int reg, void *buf, unsigned long count) { - outsl(BaseAddr + Register, buf, count); + outsl(base + reg, buf, count); } static inline void nsp32_fifo_write(unsigned int base, diff -urN linux-2.4.22-bk29/drivers/scsi/pcmcia/nsp_cs.c linux-2.4.22-bk30/drivers/scsi/pcmcia/nsp_cs.c --- linux-2.4.22-bk29/drivers/scsi/pcmcia/nsp_cs.c 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.22-bk30/drivers/scsi/pcmcia/nsp_cs.c 2003-10-07 02:50:34.000000000 -0700 @@ -1,8 +1,10 @@ /*====================================================================== - NinjaSCSI-3 / NinjaSCSI-32Bi PCMCIA SCSI hostadapter card driver + NinjaSCSI-3 / NinjaSCSI-32Bi PCMCIA SCSI host adapter card driver By: YOKOTA Hiroshi + Ver.2.8 Support 32bit MMIO mode + Support Synchronous Data Transfer Request (SDTR) mode Ver.2.0 Support 32bit PIO mode Ver.1.1.2 Fix for scatter list buffer exceeds Ver.1.1 Support scatter list @@ -23,34 +25,32 @@ ***********************************************************************/ -/* $Id: nsp_cs.c,v 1.42 2001/09/10 10:30:58 elca Exp $ */ - -#ifdef NSP_KERNEL_2_2 -#include -#include -#endif +/* $Id: nsp_cs.c,v 1.25 2003/09/24 10:38:18 elca Exp $ */ +#include #include #include #include #include #include #include +#include #include #include -#include #include #include #include -#include +#include #include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) +# include +#endif #include #include #include <../drivers/scsi/scsi.h> #include <../drivers/scsi/hosts.h> -#include <../drivers/scsi/sd.h> #include #include @@ -59,138 +59,192 @@ #include #include #include +#include #include #include "nsp_cs.h" MODULE_AUTHOR("YOKOTA Hiroshi "); -MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module"); +MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module $Revision: 1.25 $"); MODULE_SUPPORTED_DEVICE("sd,sr,sg,st"); MODULE_LICENSE("GPL"); -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -MODULE_PARM(pc_debug, "i"); -MODULE_PARM_DESC(pc_debug, "set debug level"); -static char *version = "$Id: nsp_cs.c,v 1.42 2001/09/10 10:30:58 elca Exp $"; -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -#else -#define DEBUG(n, args...) /* */ -#endif - #include "nsp_io.h" /*====================================================================*/ +/* Parameters that can be set with 'insmod' */ -typedef struct scsi_info_t { - dev_link_t link; - struct Scsi_Host *host; - int ndev; - dev_node_t node[8]; - int stop; - struct bus_operations *bus; -} scsi_info_t; +static unsigned int irq_mask = 0xffff; +MODULE_PARM (irq_mask, "i"); +MODULE_PARM_DESC(irq_mask, "IRQ mask bits (default: 0xffff)"); +static int irq_list[4] = { -1 }; +MODULE_PARM (irq_list, "1-4i"); +MODULE_PARM_DESC(irq_list, "Use specified IRQ number. (default: auto select)"); + +static int nsp_burst_mode = BURST_MEM32; +MODULE_PARM (nsp_burst_mode, "i"); +MODULE_PARM_DESC(nsp_burst_mode, "Burst transfer mode (0=io8, 1=io32, 2=mem32(default))"); + +/* Release IO ports after configuration? */ +static int free_ports = 0; +MODULE_PARM (free_ports, "i"); +MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))"); -/*----------------------------------------------------------------*/ - -#if (KERNEL_VERSION(2,4,0) > LINUX_VERSION_CODE) -#define PROC_SCSI_NSP PROC_SCSI_IBMMCA /* bad hack... */ -static struct proc_dir_entry proc_scsi_nsp = { - PROC_SCSI_NSP, 6, "nsp_cs", - S_IFDIR | S_IRUGO | S_IXUGO, 2 -}; +/* /usr/src/linux/drivers/scsi/hosts.h */ +static Scsi_Host_Template nsp_driver_template = { + .proc_name = "nsp_cs", + .proc_info = nsp_proc_info, + .name = "WorkBit NinjaSCSI-3/32Bi(16bit)", +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + .detect = nsp_detect_old, + .release = nsp_release_old, +#endif + .info = nsp_info, + .queuecommand = nsp_queuecommand, +/* .eh_strategy_handler = nsp_eh_strategy,*/ +/* .eh_abort_handler = nsp_eh_abort,*/ +/* .eh_device_reset_handler = nsp_eh_device_reset,*/ + .eh_bus_reset_handler = nsp_eh_bus_reset, + .eh_host_reset_handler = nsp_eh_host_reset, + .can_queue = 1, + .this_id = NSP_INITIATOR_ID, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = DISABLE_CLUSTERING, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2)) + .use_new_eh_code = 1, #endif +}; -/*====================================================================*/ -/* Parameters that can be set with 'insmod' */ +static dev_link_t *dev_list = NULL; +static dev_info_t dev_info = "nsp_cs"; -static unsigned int irq_mask = 0xffff; -MODULE_PARM(irq_mask, "i"); -MODULE_PARM_DESC(irq_mask, "IRQ mask bits"); +static nsp_hw_data nsp_data_base; /* attach <-> detect glue */ -static int irq_list[4] = { -1 }; -MODULE_PARM(irq_list, "1-4i"); -MODULE_PARM_DESC(irq_list, "IRQ number list"); -/*----------------------------------------------------------------*/ -/* driver state info, local to driver */ -static char nspinfo[100]; /* description */ -/* /usr/src/linux/drivers/scsi/hosts.h */ -static Scsi_Host_Template driver_template = { -/* next: NULL,*/ -#if (KERNEL_VERSION(2,3,99) > LINUX_VERSION_CODE) - proc_dir: &proc_scsi_nsp, /* kernel 2.2 */ +/****************************************************************** + * debug, error print + */ +#ifdef NSP_DEBUG +# include "nsp_debug.c" +#endif /* NSP_DEBUG */ + +#ifndef NSP_DEBUG +# define NSP_DEBUG_MASK 0x000000 +# define nsp_msg(type, args...) nsp_cs_message("", 0, (type), args) +# define nsp_dbg(mask, args...) /* */ #else - proc_name: "nsp_cs", /* kernel 2.4 */ +# define NSP_DEBUG_MASK 0xffffff +# define nsp_msg(type, args...) \ + nsp_cs_message (__FUNCTION__, __LINE__, (type), args) +# define nsp_dbg(mask, args...) \ + nsp_cs_dmessage(__FUNCTION__, __LINE__, (mask), args) #endif -/* proc_info: NULL,*/ - name: "WorkBit NinjaSCSI-3/32Bi", - detect: nsp_detect, - release: nsp_release, - info: nsp_info, -/* command: NULL,*/ - queuecommand: nsp_queuecommand, -/* eh_strategy_handler: nsp_eh_strategy,*/ - eh_abort_handler: nsp_eh_abort, - eh_device_reset_handler: nsp_eh_device_reset, - eh_bus_reset_handler: nsp_eh_bus_reset, - eh_host_reset_handler: nsp_eh_host_reset, - abort: nsp_abort, - reset: nsp_reset, -/* slave_attach: NULL,*/ -/* bios_param: NULL,*/ - can_queue: 1, - this_id: SCSI_INITIATOR_ID, - sg_tablesize: SG_ALL, - cmd_per_lun: 1, -/* present: 0,*/ -/* unchecked_isa_dma: 0,*/ - use_clustering: DISABLE_CLUSTERING, - use_new_eh_code: 0, -/* emulated: 0,*/ -}; -static dev_link_t *dev_list = NULL; -static dev_info_t dev_info = {"nsp_cs"}; +#define NSP_DEBUG_QUEUECOMMAND BIT(0) +#define NSP_DEBUG_REGISTER BIT(1) +#define NSP_DEBUG_AUTOSCSI BIT(2) +#define NSP_DEBUG_INTR BIT(3) +#define NSP_DEBUG_SGLIST BIT(4) +#define NSP_DEBUG_BUSFREE BIT(5) +#define NSP_DEBUG_CDB_CONTENTS BIT(6) +#define NSP_DEBUG_RESELECTION BIT(7) +#define NSP_DEBUG_MSGINOCCUR BIT(8) +#define NSP_DEBUG_EEPROM BIT(9) +#define NSP_DEBUG_MSGOUTOCCUR BIT(10) +#define NSP_DEBUG_BUSRESET BIT(11) +#define NSP_DEBUG_RESTART BIT(12) +#define NSP_DEBUG_SYNC BIT(13) +#define NSP_DEBUG_WAIT BIT(14) +#define NSP_DEBUG_TARGETFLAG BIT(15) +#define NSP_DEBUG_PROC BIT(16) +#define NSP_DEBUG_INIT BIT(17) +#define NSP_DEBUG_DATA_IO BIT(18) +#define NSP_SPECIAL_PRINT_REGISTER BIT(20) + +#define NSP_DEBUG_BUF_LEN 150 + +static void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...) +{ + va_list args; + char buf[NSP_DEBUG_BUF_LEN]; + + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); -static nsp_hw_data nsp_data; +#ifndef NSP_DEBUG + printk("%snsp_cs: %s\n", type, buf); +#else + printk("%snsp_cs: %s (%d): %s\n", type, func, line, buf); +#endif +} + +#ifdef NSP_DEBUG +static void nsp_cs_dmessage(const char *func, int line, int mask, char *fmt, ...) +{ + va_list args; + char buf[NSP_DEBUG_BUF_LEN]; + + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + if (mask & NSP_DEBUG_MASK) { + printk("nsp_cs-debug: 0x%x %s (%d): %s\n", mask, func, line, buf); + } +} +#endif /***********************************************************/ +/*==================================================== + * Clenaup parameters and call done() functions. + * You must be set SCpnt->result before call this function. + */ +static void nsp_scsi_done(Scsi_Cmnd *SCpnt) +{ + nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; + + data->CurrentSC = NULL; + + SCpnt->scsi_done(SCpnt); +} + static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { -#ifdef PCMCIA_DEBUG - //unsigned int host_id = SCpnt->host->this_id; - //unsigned int base = SCpnt->host->io_port; - unsigned char target = SCpnt->target; -#endif - nsp_hw_data *data = &nsp_data; - - DEBUG(0, __FUNCTION__ "() SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d\n", - SCpnt, target, SCpnt->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg); - //DEBUG(0, " before CurrentSC=0x%p\n", data->CurrentSC); - - if(data->CurrentSC != NULL) { - printk(KERN_DEBUG " " __FUNCTION__ "() CurrentSC!=NULL this can't be happen\n"); - data->CurrentSC = NULL; +#ifdef NSP_DEBUG + /*unsigned int host_id = SCpnt->device->host->this_id;*/ + /*unsigned int base = SCpnt->device->host->io_port;*/ + unsigned char target = SCpnt->device->id; +#endif + nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; + + nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d", + SCpnt, target, SCpnt->device->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg); + //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC); + + SCpnt->scsi_done = done; + + if (data->CurrentSC != NULL) { + nsp_msg(KERN_WARNING, "CurrentSC!=NULL this can't be happen"); SCpnt->result = DID_BAD_TARGET << 16; - done(SCpnt); - return -1; + nsp_scsi_done(SCpnt); + return SCSI_MLQUEUE_HOST_BUSY; } show_command(SCpnt); - SCpnt->scsi_done = done; data->CurrentSC = SCpnt; - RESID = SCpnt->request_bufflen; - SCpnt->SCp.Status = -1; - SCpnt->SCp.Message = -1; + SCpnt->SCp.Status = CHECK_CONDITION; + SCpnt->SCp.Message = 0; SCpnt->SCp.have_data_in = IO_UNKNOWN; SCpnt->SCp.sent_command = 0; SCpnt->SCp.phase = PH_UNDETERMINED; + SCpnt->resid = SCpnt->request_bufflen; /* setup scratch area SCp.ptr : buffer pointer @@ -200,7 +254,7 @@ SCp.phase : current state of the command */ if (SCpnt->use_sg) { SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; - SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; + SCpnt->SCp.ptr = SG_ADDRESS(SCpnt->SCp.buffer); SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; } else { @@ -210,16 +264,18 @@ SCpnt->SCp.buffers_residual = 0; } - if(nsphw_start_selection(SCpnt, data) == FALSE) { - DEBUG(0, " selection fail\n"); - data->CurrentSC = NULL; - SCpnt->result = DID_NO_CONNECT << 16; - done(SCpnt); - return -1; + if (nsphw_start_selection(SCpnt) == FALSE) { + nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "selection fail"); + SCpnt->result = DID_BUS_BUSY << 16; + nsp_scsi_done(SCpnt); + return SCSI_MLQUEUE_DEVICE_BUSY; } - //DEBUG(0, __FUNCTION__ "() out\n"); + //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "out"); +#ifdef NSP_DEBUG + data->CmdId++; +#endif return 0; } @@ -231,7 +287,7 @@ unsigned int base = data->BaseAddress; unsigned char transfer_mode_reg; - //DEBUG(0, __FUNCTION__ "() enabled=%d\n", enabled); + //nsp_dbg(NSP_DEBUG_DATA_IO, "enabled=%d", enabled); if (enabled != FALSE) { transfer_mode_reg = TRANSFER_GO | BRAIND; @@ -244,37 +300,45 @@ nsp_index_write(base, TRANSFERMODE, transfer_mode_reg); } +static void nsphw_init_sync(nsp_hw_data *data) +{ + sync_data tmp_sync = { .SyncNegotiation = SYNC_NOT_YET, + .SyncPeriod = 0, + .SyncOffset = 0 + }; + int i; + + /* setup sync data */ + for ( i = 0; i < NUMBER(data->Sync); i++ ) { + data->Sync[i] = tmp_sync; + } +} + /* * Initialize Ninja hardware */ static int nsphw_init(nsp_hw_data *data) { unsigned int base = data->BaseAddress; - int i, j; - sync_data tmp_sync = { SyncNegotiation: SYNC_NOT_YET, - SyncPeriod: 0, - SyncOffset: 0 - }; - DEBUG(0, __FUNCTION__ "() in base=0x%x\n", base); + nsp_dbg(NSP_DEBUG_INIT, "in base=0x%x", base); - data->ScsiClockDiv = CLOCK_40M; + data->ScsiClockDiv = CLOCK_40M | FAST_20; data->CurrentSC = NULL; data->FifoCount = 0; data->TransferMode = MODE_IO8; - /* setup sync data */ - for ( i = 0; i < N_TARGET; i++ ) { - for ( j = 0; j < N_LUN; j++ ) { - data->Sync[i][j] = tmp_sync; - } - } + nsphw_init_sync(data); + /* block all interrupts */ - nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK); + nsp_write(base, IRQCONTROL, IRQCONTROL_ALL_CLEAR_AND_MASK); + + nsp_write(base, IFSELECT, 0); + data->ChipRev = nsp_read(base, FIFOSTATUS); /* setup SCSI interface */ - nsp_write(base, IFSELECT, IF_IFSEL); + nsp_write(base, IFSELECT, IF_REGSEL); nsp_index_write(base, SCSIIRQMODE, 0); @@ -291,7 +355,7 @@ nsp_write(base, IFSELECT, IF_REGSEL); nsp_index_write(base, TERMPWRCTRL, 0); if ((nsp_index_read(base, OTHERCONTROL) & TPWR_SENSE) == 0) { - printk(KERN_INFO "nsp_cs: terminator power on\n"); + nsp_msg(KERN_INFO, "terminator power on"); nsp_index_write(base, TERMPWRCTRL, POWER_ON); } @@ -305,7 +369,7 @@ nsp_index_write(base, SCSIIRQMODE, SCSI_PHASE_CHANGE_EI | RESELECT_EI | SCSI_RESET_IRQ_EI ); - nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR); + nsp_write(base, IRQCONTROL, IRQCONTROL_ALL_CLEAR); nsp_setup_fifo(data, FALSE); @@ -315,110 +379,147 @@ /* * Start selection phase */ -static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt, - nsp_hw_data *data) +static int nsphw_start_selection(Scsi_Cmnd *SCpnt) { - unsigned int host_id = SCpnt->host->this_id; - unsigned int base = SCpnt->host->io_port; - unsigned char target = SCpnt->target; - int wait_count; + unsigned int host_id = SCpnt->device->host->this_id; + unsigned int base = SCpnt->device->host->io_port; + unsigned char target = SCpnt->device->id; + nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; + int time_out; unsigned char phase, arbit; - //DEBUG(0, __FUNCTION__ "()in\n"); + //nsp_dbg(NSP_DEBUG_RESELECTION, "in"); phase = nsp_index_read(base, SCSIBUSMON); if(phase != BUSMON_BUS_FREE) { - //DEBUG(0, " bus busy\n"); + //nsp_dbg(NSP_DEBUG_RESELECTION, "bus busy"); return FALSE; } /* start arbitration */ - //DEBUG(0, " start arbit\n"); + //nsp_dbg(NSP_DEBUG_RESELECTION, "start arbit"); SCpnt->SCp.phase = PH_ARBSTART; nsp_index_write(base, SETARBIT, ARBIT_GO); - wait_count = jiffies + 10 * HZ; + time_out = 1000; do { /* XXX: what a stupid chip! */ arbit = nsp_index_read(base, ARBITSTATUS); - //DEBUG(0, " arbit=%d, wait_count=%d\n", arbit, wait_count); + //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit=%d, wait_count=%d", arbit, wait_count); udelay(1); /* hold 1.2us */ } while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 && - time_before(jiffies, wait_count)); + (time_out-- != 0)); - if((arbit & ARBIT_WIN) == 0) { - //DEBUG(0, " arbit fail\n"); + if (!(arbit & ARBIT_WIN)) { + //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit fail"); nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR); return FALSE; } /* assert select line */ - //DEBUG(0, " assert SEL line\n"); + //nsp_dbg(NSP_DEBUG_RESELECTION, "assert SEL line"); SCpnt->SCp.phase = PH_SELSTART; - udelay(3); - nsp_index_write(base, SCSIDATALATCH, (1 << host_id) | (1 << target)); - nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_ATN); - udelay(3); + udelay(3); /* wait 2.4us */ + nsp_index_write(base, SCSIDATALATCH, BIT(host_id) | BIT(target)); + nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_ATN); + udelay(2); /* wait >1.2us */ nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN); nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR); - udelay(3); - nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN); + /*udelay(1);*/ /* wait >90ns */ + nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN); /* check selection timeout */ - nsp_start_timer(SCpnt, data, 1000/51); + nsp_start_timer(SCpnt, 1000/51); data->SelectionTimeOut = 1; return TRUE; } +/*********************************************************************** + * Period/AckWidth speed conversion table + * + * Note: This period/ackwidth speed table must be in descending order. + ***********************************************************************/ struct nsp_sync_table { - unsigned int min_period; - unsigned int max_period; unsigned int chip_period; unsigned int ack_width; + unsigned int min_period; + unsigned int max_period; }; static struct nsp_sync_table nsp_sync_table_40M[] = { - {0x0c,0x0c,0x1,0}, /* 20MB 50ns*/ - {0x19,0x19,0x3,1}, /* 10MB 100ns*/ - {0x1a,0x25,0x5,2}, /* 7.5MB 150ns*/ - {0x26,0x32,0x7,3}, /* 5MB 200ns*/ - {0x0, 0, 0, 0} + /* {PNo, AW, SP, EP} Speed(MB/s) Period AckWidth */ + {0x1, 0, 0x0c, 0x0c}, /* 20.0 : 50ns, 25ns */ + {0x2, 0, 0x0d, 0x18}, /* 13.3 : 75ns, 25ns */ + {0x3, 1, 0x19, 0x19}, /* 10.0 : 100ns, 50ns */ + {0x4, 1, 0x1a, 0x1f}, /* 8.0 : 125ns, 50ns */ + {0x5, 2, 0x20, 0x25}, /* 7.5 : 150ns, 75ns */ + {0x6, 2, 0x26, 0x31}, /* 5.71: 175ns, 75ns */ + {0x7, 3, 0x32, 0x32}, /* 5.0 : 200ns, 100ns */ + {0x8, 3, 0x33, 0x38}, /* 4.44: 225ns, 100ns */ + {0x9, 3, 0x39, 0x3e}, /* 4.0 : 250ns, 100ns */ + {0xa, 3, 0x3f, 0x44}, /* 3.64: 275ns, 100ns */ + {0xb, 3, 0x45, 0x4b}, /* 3.33: 300ns, 100ns */ + {0xc, 3, 0x4c, 0x53}, /* 3.01: 325ns, 100ns */ + {0xd, 3, 0x54, 0x57}, /* 2.86: 350ns, 100ns */ + {0xe, 3, 0x58, 0x5d}, /* 2.67: 375ns, 100ns */ + {0xf, 3, 0x5e, 0x64}, /* 2.5 : 400ns, 100ns */ + {0,0,0,0}, }; static struct nsp_sync_table nsp_sync_table_20M[] = { - {0x19,0x19,0x1,0}, /* 10MB 100ns*/ - {0x1a,0x25,0x2,0}, /* 7.5MB 150ns*/ - {0x26,0x32,0x3,1}, /* 5MB 200ns*/ - {0x0, 0, 0, 0} + {0x1, 0, 0x19, 0x19}, /* 10.0 : 100ns, 50ns */ + {0x2, 0, 0x1a, 0x25}, /* 6.7 : 150ns, 50ns */ + {0x3, 1, 0x26, 0x32}, /* 5.0 : 200ns, 100ns */ + {0x4, 1, 0x33, 0x3e}, /* 4.0 : 250ns, 100ns */ + {0x5, 2, 0x3f, 0x4b}, /* 3.3 : 300ns, 150ns */ + {0x6, 2, 0x4c, 0x57}, /* 2.8 : 350ns, 150ns */ + {0x7, 3, 0x58, 0x64}, /* 2.5 : 400ns, 200ns */ + {0x8, 3, 0x65, 0x70}, /* 2.2 : 450ns, 200ns */ + {0x9, 3, 0x71, 0x7d}, /* 2.0 : 500ns, 200ns */ + {0xa, 3, 0x7e, 0x89}, /* 1.82: 550ns, 200ns */ + {0xb, 3, 0x8a, 0x95}, /* 1.67: 550ns, 200ns */ + {0xc, 3, 0x96, 0xa2}, /* 1.54: 550ns, 200ns */ + {0xd, 3, 0xa3, 0xae}, /* 1.43: 550ns, 200ns */ + {0xe, 3, 0xaf, 0xbb}, /* 1.33: 550ns, 200ns */ + {0xf, 3, 0xbc, 0xc8}, /* 1.25: 550ns, 200ns */ + {0,0,0,0}, }; /* * setup synchronous data transfer mode */ -static int nsp_msg(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +static int nsp_analyze_sdtr(Scsi_Cmnd *SCpnt) { - unsigned char target = SCpnt->target; - unsigned char lun = SCpnt->lun; - sync_data *sync = &(data->Sync[target][lun]); + unsigned char target = SCpnt->device->id; +// unsigned char lun = SCpnt->device->lun; + nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; + sync_data *sync = &(data->Sync[target]); struct nsp_sync_table *sync_table; unsigned int period, offset; int i; - DEBUG(0, __FUNCTION__ "()\n"); - -/**!**/ + nsp_dbg(NSP_DEBUG_SYNC, "in"); period = sync->SyncPeriod; offset = sync->SyncOffset; - DEBUG(0, " period=0x%x, offset=0x%x\n", period, offset); + nsp_dbg(NSP_DEBUG_SYNC, "period=0x%x, offset=0x%x", period, offset); - if (data->ScsiClockDiv == CLOCK_20M) { - sync_table = &nsp_sync_table_20M[0]; - } else { - sync_table = &nsp_sync_table_40M[0]; + switch (data->ScsiClockDiv) { + case CLOCK_20M: + case CLOCK_40M: + sync_table = nsp_sync_table_20M; + break; + case CLOCK_40M | FAST_20: + sync_table = nsp_sync_table_40M; + break; + default: + nsp_msg(KERN_WARNING, + "Invalid clock div is selected, set 20M."); + sync_table = nsp_sync_table_20M; + break; } for ( i = 0; sync_table->max_period != 0; i++, sync_table++) { @@ -432,13 +533,12 @@ /* * No proper period/offset found */ - DEBUG(0, " no proper period/offset\n"); + nsp_dbg(NSP_DEBUG_SYNC, "no proper period/offset"); sync->SyncPeriod = 0; sync->SyncOffset = 0; sync->SyncRegister = 0; sync->AckWidth = 0; - sync->SyncNegotiation = SYNC_OK; return FALSE; } @@ -446,9 +546,8 @@ sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) | (offset & SYNCREG_OFFSET_MASK); sync->AckWidth = sync_table->ack_width; - sync->SyncNegotiation = SYNC_OK; - DEBUG(0, " sync_reg=0x%x, ack_width=0x%x\n", sync->SyncRegister, sync->AckWidth); + nsp_dbg(NSP_DEBUG_SYNC, "sync_reg=0x%x, ack_width=0x%x", sync->SyncRegister, sync->AckWidth); return TRUE; } @@ -457,11 +556,12 @@ /* * start ninja hardware timer */ -static void nsp_start_timer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int time) +static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time) { - unsigned int base = SCpnt->host->io_port; + unsigned int base = SCpnt->device->host->io_port; + nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; - //DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p, time=%d\n", SCpnt, time); + //nsp_dbg(NSP_DEBUG_INTR, "in SCpnt=0x%p, time=%d", SCpnt, time); data->TimerCount = time; nsp_index_write(base, TIMERCOUNT, time); } @@ -471,23 +571,23 @@ */ static int nsp_negate_signal(Scsi_Cmnd *SCpnt, unsigned char mask, char *str) { - unsigned int base = SCpnt->host->io_port; + unsigned int base = SCpnt->device->host->io_port; unsigned char reg; - int count, i = TRUE; + int time_out; - //DEBUG(0, __FUNCTION__ "()\n"); + //nsp_dbg(NSP_DEBUG_INTR, "in"); - count = jiffies + HZ; + time_out = 100; do { reg = nsp_index_read(base, SCSIBUSMON); if (reg == 0xff) { break; } - } while ((i = time_before(jiffies, count)) && (reg & mask) != 0); + } while ((time_out-- != 0) && (reg & mask) != 0); - if (!i) { - printk(KERN_DEBUG __FUNCTION__ " %s signal off timeut\n", str); + if (time_out == 0) { + nsp_msg(KERN_DEBUG, " %s signal off timeut", str); } return 0; @@ -500,51 +600,52 @@ unsigned char current_phase, unsigned char mask) { - unsigned int base = SCpnt->host->io_port; - int wait_count; + unsigned int base = SCpnt->device->host->io_port; + int time_out; unsigned char phase, i_src; - //DEBUG(0, __FUNCTION__ "() current_phase=0x%x, mask=0x%x\n", current_phase, mask); + //nsp_dbg(NSP_DEBUG_INTR, "current_phase=0x%x, mask=0x%x", current_phase, mask); - wait_count = jiffies + HZ; + time_out = 100; do { phase = nsp_index_read(base, SCSIBUSMON); if (phase == 0xff) { - //DEBUG(0, " ret -1\n"); + //nsp_dbg(NSP_DEBUG_INTR, "ret -1"); return -1; } i_src = nsp_read(base, IRQSTATUS); if (i_src & IRQSTATUS_SCSI) { - //DEBUG(0, " ret 0 found scsi signal\n"); + //nsp_dbg(NSP_DEBUG_INTR, "ret 0 found scsi signal"); return 0; } if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) { - //DEBUG(0, " ret 1 phase=0x%x\n", phase); + //nsp_dbg(NSP_DEBUG_INTR, "ret 1 phase=0x%x", phase); return 1; } - } while(time_before(jiffies, wait_count)); + } while(time_out-- != 0); - //DEBUG(0, __FUNCTION__ " : " __FUNCTION__ " timeout\n"); + //nsp_dbg(NSP_DEBUG_INTR, "timeout"); return -1; } /* * transfer SCSI message */ -static int nsp_xfer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int phase) +static int nsp_xfer(Scsi_Cmnd *SCpnt, int phase) { - unsigned int base = SCpnt->host->io_port; + unsigned int base = SCpnt->device->host->io_port; + nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; char *buf = data->MsgBuffer; int len = MIN(MSGBUF_SIZE, data->MsgLen); int ptr; int ret; - //DEBUG(0, __FUNCTION__ "()\n"); - for (ptr = 0; len > 0; len --, ptr ++) { + //nsp_dbg(NSP_DEBUG_DATA_IO, "in"); + for (ptr = 0; len > 0; len--, ptr++) { ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ); if (ret <= 0) { - DEBUG(0, " xfer quit\n"); + nsp_dbg(NSP_DEBUG_DATA_IO, "xfer quit"); return 0; } @@ -555,10 +656,10 @@ /* read & write message */ if (phase & BUSMON_IO) { - DEBUG(0, " read msg\n"); + nsp_dbg(NSP_DEBUG_DATA_IO, "read msg"); buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK); } else { - DEBUG(0, " write msg\n"); + nsp_dbg(NSP_DEBUG_DATA_IO, "write msg"); nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]); } nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer"); @@ -570,11 +671,12 @@ /* * get extra SCSI data from fifo */ -static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt) { + nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; unsigned int count; - //DEBUG(0, __FUNCTION__ "()\n"); + //nsp_dbg(NSP_DEBUG_DATA_IO, "in"); if (SCpnt->SCp.have_data_in != IO_IN) { return 0; @@ -582,7 +684,7 @@ count = nsp_fifo_count(SCpnt); if (data->FifoCount == count) { - //DEBUG(0, " not use bypass quirk\n"); + //nsp_dbg(NSP_DEBUG_DATA_IO, "not use bypass quirk"); return 0; } @@ -590,30 +692,49 @@ * XXX: NSP_QUIRK * data phase skip only occures in case of SCSI_LOW_READ */ + nsp_dbg(NSP_DEBUG_DATA_IO, "use bypass quirk"); SCpnt->SCp.phase = PH_DATA; - nsp_pio_read(SCpnt, data); + nsp_pio_read(SCpnt); nsp_setup_fifo(data, FALSE); - DEBUG(0, " use bypass quirk\n"); return 0; } /* * accept reselection */ -static int nsp_reselected(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +static int nsp_reselected(Scsi_Cmnd *SCpnt) { - unsigned int base = SCpnt->host->io_port; - unsigned char reg; + unsigned int base = SCpnt->device->host->io_port; + unsigned int host_id = SCpnt->device->host->this_id; + //nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; + unsigned char bus_reg; + unsigned char id_reg, tmp; + int target; + + nsp_dbg(NSP_DEBUG_RESELECTION, "in"); + + id_reg = nsp_index_read(base, RESELECTID); + tmp = id_reg & (~BIT(host_id)); + target = 0; + while(tmp != 0) { + if (tmp & BIT(0)) { + break; + } + tmp >>= 1; + target++; + } - //DEBUG(0, __FUNCTION__ "()\n"); + if (SCpnt->device->id != target) { + nsp_msg(KERN_ERR, "XXX: reselect ID must be %d in this implementation.", target); + } nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect"); - nsp_nexus(SCpnt, data); - reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN); - nsp_index_write(base, SCSIBUSCTRL, reg); - nsp_index_write(base, SCSIBUSCTRL, reg | AUTODIRECTION | ACKENB); + nsp_nexus(SCpnt); + bus_reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN); + nsp_index_write(base, SCSIBUSCTRL, bus_reg); + nsp_index_write(base, SCSIBUSCTRL, bus_reg | AUTODIRECTION | ACKENB); return TRUE; } @@ -623,19 +744,20 @@ */ static int nsp_fifo_count(Scsi_Cmnd *SCpnt) { - unsigned int base = SCpnt->host->io_port; + unsigned int base = SCpnt->device->host->io_port; unsigned int count; - unsigned int l, m, h; + unsigned int l, m, h, dummy; - nsp_index_write(base, POINTERCLR, POINTER_CLEAR); + nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER); - l = (unsigned int)nsp_read(base, DATAREG); - m = (unsigned int)nsp_read(base, DATAREG); - h = (unsigned int)nsp_read(base, DATAREG); + l = nsp_index_read(base, TRANSFERCOUNT); + m = nsp_index_read(base, TRANSFERCOUNT); + h = nsp_index_read(base, TRANSFERCOUNT); + dummy = nsp_index_read(base, TRANSFERCOUNT); /* required this! */ count = (h << 16) | (m << 8) | (l << 0); - //DEBUG(0, __FUNCTION__ "() =0x%x\n", count); + //nsp_dbg(NSP_DEBUG_DATA_IO, "count=0x%x", count); return count; } @@ -647,34 +769,37 @@ /* * read data in DATA IN phase */ -static void nsp_pio_read(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +static void nsp_pio_read(Scsi_Cmnd *SCpnt) { - unsigned int base = SCpnt->host->io_port; - int time_out, i; + unsigned int base = SCpnt->device->host->io_port; + unsigned long mmio_base = SCpnt->device->host->base; + nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; + long time_out; int ocount, res; unsigned char stat, fifo_stat; ocount = data->FifoCount; - DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d\n", SCpnt, RESID, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual); + nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d", + SCpnt, SCpnt->resid, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual); - time_out = jiffies + 10 * HZ; + time_out = 1000; - while ((i = time_before(jiffies,time_out)) && + while ((time_out-- != 0) && (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0 ) ) { stat = nsp_index_read(base, SCSIBUSMON); stat &= BUSMON_PHASE_MASK; - res = nsp_fifo_count(SCpnt) - ocount; - //DEBUG(0, " ptr=0x%p this=0x%x ocount=0x%x res=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount, res); + res = nsp_fifo_count(SCpnt) - ocount; + //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x ocount=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount, res); if (res == 0) { /* if some data avilable ? */ if (stat == BUSPHASE_DATA_IN) { /* phase changed? */ - //DEBUG(0, " wait for data this=%d\n", SCpnt->SCp.this_residual); + //nsp_dbg(NSP_DEBUG_DATA_IO, " wait for data this=%d", SCpnt->SCp.this_residual); continue; } else { - DEBUG(0, " phase changed stat=0x%x\n", stat); + nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x", stat); break; } } @@ -695,72 +820,93 @@ case MODE_IO8: nsp_fifo8_read (base, SCpnt->SCp.ptr, res ); break; - default: - DEBUG(0, "unknown read mode\n"); + + case MODE_MEM32: + res &= ~(BIT(1)|BIT(0)); /* align 4 */ + nsp_mmio_fifo32_read(mmio_base, SCpnt->SCp.ptr, res >> 2); break; + + default: + nsp_dbg(NSP_DEBUG_DATA_IO, "unknown read mode"); + return; } - RESID -= res; + SCpnt->resid -= res; SCpnt->SCp.ptr += res; SCpnt->SCp.this_residual -= res; ocount += res; - //DEBUG(0, " ptr=0x%p this_residual=0x%x ocount=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount); + //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this_residual=0x%x ocount=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount); /* go to next scatter list if available */ if (SCpnt->SCp.this_residual == 0 && SCpnt->SCp.buffers_residual != 0 ) { - //DEBUG(0, " scatterlist next timeout=%d\n", time_out); + //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out); SCpnt->SCp.buffers_residual--; SCpnt->SCp.buffer++; - SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; + SCpnt->SCp.ptr = SG_ADDRESS(SCpnt->SCp.buffer); SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; - } + time_out = 1000; - time_out = jiffies + 10 * HZ; + //nsp_dbg(NSP_DEBUG_DATA_IO, "page: 0x%p, off: 0x%x", SCpnt->SCp.buffer->page, SCpnt->SCp.buffer->offset); + } } data->FifoCount = ocount; - if (!i) { - printk(KERN_DEBUG __FUNCTION__ "() pio read timeout resid=%d this_residual=%d buffers_residual=%d\n", RESID, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual); + if (time_out == 0) { + nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d", + SCpnt->resid, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual); } - DEBUG(0, " read ocount=0x%x\n", ocount); + nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount); + nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid); } /* * write data in DATA OUT phase */ -static void nsp_pio_write(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +static void nsp_pio_write(Scsi_Cmnd *SCpnt) { - unsigned int base = SCpnt->host->io_port; - int time_out, i; - unsigned int ocount, res; + unsigned int base = SCpnt->device->host->io_port; + unsigned long mmio_base = SCpnt->device->host->base; + nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; + int time_out; + int ocount, res; unsigned char stat; ocount = data->FifoCount; - DEBUG(0, __FUNCTION__ "() in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x\n", data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, RESID); + nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x", + data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, SCpnt->resid); - time_out = jiffies + 10 * HZ; + time_out = 1000; - while ((i = time_before(jiffies, time_out)) && + while ((time_out-- != 0) && (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0)) { stat = nsp_index_read(base, SCSIBUSMON); stat &= BUSMON_PHASE_MASK; + if (stat != BUSPHASE_DATA_OUT) { - DEBUG(0, " phase changed stat=0x%x\n", stat); + res = ocount - nsp_fifo_count(SCpnt); + + nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res); + /* Put back pointer */ + SCpnt->resid += res; + SCpnt->SCp.ptr -= res; + SCpnt->SCp.this_residual += res; + ocount -= res; + break; } res = ocount - nsp_fifo_count(SCpnt); if (res > 0) { /* write all data? */ - DEBUG(0, " wait for all data out. ocount=0x%x res=%d\n", ocount, res); + nsp_dbg(NSP_DEBUG_DATA_IO, "wait for all data out. ocount=0x%x res=%d", ocount, res); continue; } res = MIN(SCpnt->SCp.this_residual, WFIFO_CRIT); - //DEBUG(0, " ptr=0x%p this=0x%x res=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res); + //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res); switch (data->TransferMode) { case MODE_IO32: res &= ~(BIT(1)|BIT(0)); /* align 4 */ @@ -769,12 +915,18 @@ case MODE_IO8: nsp_fifo8_write (base, SCpnt->SCp.ptr, res ); break; + + case MODE_MEM32: + res &= ~(BIT(1)|BIT(0)); /* align 4 */ + nsp_mmio_fifo32_write(mmio_base, SCpnt->SCp.ptr, res >> 2); + break; + default: - DEBUG(0, "unknown write mode\n"); + nsp_dbg(NSP_DEBUG_DATA_IO, "unknown write mode"); break; } - RESID -= res; + SCpnt->resid -= res; SCpnt->SCp.ptr += res; SCpnt->SCp.this_residual -= res; ocount += res; @@ -782,55 +934,60 @@ /* go to next scatter list if available */ if (SCpnt->SCp.this_residual == 0 && SCpnt->SCp.buffers_residual != 0 ) { - //DEBUG(0, " scatterlist next\n"); + //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next"); SCpnt->SCp.buffers_residual--; SCpnt->SCp.buffer++; - SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; + SCpnt->SCp.ptr = SG_ADDRESS(SCpnt->SCp.buffer); SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + time_out = 1000; } - - time_out = jiffies + 10 * HZ; } data->FifoCount = ocount; - if (!i) { - printk(KERN_DEBUG __FUNCTION__ "() pio write timeout resid=%d\n", RESID); + if (time_out == 0) { + nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x", SCpnt->resid); } - //DEBUG(0, " write ocount=%d\n", ocount); + nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount); + nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid); } - #undef RFIFO_CRIT #undef WFIFO_CRIT /* * setup synchronous/asynchronous data transfer mode */ -static int nsp_nexus(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +static int nsp_nexus(Scsi_Cmnd *SCpnt) { - unsigned int base = SCpnt->host->io_port; - unsigned char target = SCpnt->target; - unsigned char lun = SCpnt->lun; - sync_data *sync = &(data->Sync[target][lun]); + unsigned int base = SCpnt->device->host->io_port; + unsigned char target = SCpnt->device->id; +// unsigned char lun = SCpnt->device->lun; + nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; + sync_data *sync = &(data->Sync[target]); - //DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p\n", SCpnt); + //nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p", SCpnt); /* setup synch transfer registers */ nsp_index_write(base, SYNCREG, sync->SyncRegister); nsp_index_write(base, ACKWIDTH, sync->AckWidth); - if (RESID % 4 != 0 || - RESID <= 256 ) { + if (SCpnt->use_sg == 0 || + SCpnt->resid % 4 != 0 || + SCpnt->resid <= PAGE_SIZE ) { data->TransferMode = MODE_IO8; - } else { + } else if (nsp_burst_mode == BURST_MEM32) { + data->TransferMode = MODE_MEM32; + } else if (nsp_burst_mode == BURST_IO32) { data->TransferMode = MODE_IO32; + } else { + data->TransferMode = MODE_IO8; } /* setup pdma fifo */ nsp_setup_fifo(data, TRUE); /* clear ack counter */ - data->FifoCount = 0; + data->FifoCount = 0; nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER_CLEAR | REQ_COUNTER_CLEAR | @@ -843,111 +1000,126 @@ /* * interrupt handler */ -static void nspintr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t nspintr(int irq, void *dev_id, struct pt_regs *regs) { unsigned int base; - unsigned char i_src, irq_phase, phase; + unsigned char irq_status, irq_phase, phase; Scsi_Cmnd *tmpSC; - int len; unsigned char target, lun; unsigned int *sync_neg; int i, tmp; + unsigned long flags; nsp_hw_data *data; + int handled = 0; - //printk("&nsp_data=0x%p, dev_id=0x%p\n", &nsp_data, dev_id); + //nsp_dbg(NSP_DEBUG_INTR, "dev_id=0x%p", dev_id); + //nsp_dbg(NSP_DEBUG_INTR, "host=0x%p", ((scsi_info_t *)dev_id)->host); - /* sanity check */ - if (&nsp_data != dev_id) { - DEBUG(0, " irq conflict? this can't happen\n"); - return; - } - data = dev_id; - if (irq != data->IrqNumber) { - return; + if ( dev_id != NULL && + ((scsi_info_t *)dev_id)->host != NULL ) { + scsi_info_t *info = (scsi_info_t *)dev_id; + + data = (nsp_hw_data *)(info->host->hostdata); + } else { + nsp_dbg(NSP_DEBUG_INTR, "host data wrong"); + return IRQ_NONE; } + spin_lock_irqsave(HOST_LOCK, flags); + + //nsp_dbg(NSP_DEBUG_INTR, "&nsp_data_base=0x%p, dev_id=0x%p", &nsp_data_base, dev_id); + base = data->BaseAddress; - //DEBUG(0, " base=0x%x\n", base); + //nsp_dbg(NSP_DEBUG_INTR, "base=0x%x", base); /* * interrupt check */ - nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE); - i_src = nsp_read(base, IRQSTATUS); - if (i_src == 0xff || (i_src & IRQSTATUS_MASK) == 0) { - nsp_write(base, IRQCONTROL, 0); - //DEBUG(0, " no irq\n"); - return; + nsp_write(base, IRQCONTROL, IRQCONTROL_ALL_MASK); + irq_status = nsp_read(base, IRQSTATUS); + //nsp_dbg(NSP_DEBUG_INTR, "irq_status=0x%x", irq_status); + if ((irq_status == 0xff) || ((irq_status & IRQSTATUS_MASK) == 0)) { + //nsp_dbg(NSP_DEBUG_INTR, "no irq/shared irq"); + goto out; } - - //DEBUG(0, " i_src=0x%x\n", i_src); + handled = 1; /* XXX: IMPORTANT * Do not read an irq_phase register if no scsi phase interrupt. * Unless, you should lose a scsi phase interrupt. */ phase = nsp_index_read(base, SCSIBUSMON); - if((i_src & IRQSTATUS_SCSI) != 0) { + if((irq_status & IRQSTATUS_SCSI) != 0) { irq_phase = nsp_index_read(base, IRQPHASESENCE); } else { irq_phase = 0; } - //DEBUG(0, " irq_phase=0x%x\n", irq_phase); + //nsp_dbg(NSP_DEBUG_INTR, "irq_phase=0x%x", irq_phase); /* * timer interrupt handler (scsi vs timer interrupts) */ - //DEBUG(0, " timercount=%d\n", data->TimerCount); + //nsp_dbg(NSP_DEBUG_INTR, "timercount=%d", data->TimerCount); if (data->TimerCount != 0) { - //DEBUG(0, " stop timer\n"); + //nsp_dbg(NSP_DEBUG_INTR, "stop timer"); nsp_index_write(base, TIMERCOUNT, 0); nsp_index_write(base, TIMERCOUNT, 0); data->TimerCount = 0; } - if ((i_src & IRQSTATUS_MASK) == IRQSTATUS_TIMER && + if ((irq_status & IRQSTATUS_MASK) == IRQSTATUS_TIMER && data->SelectionTimeOut == 0) { - //DEBUG(0, " timer start\n"); + //nsp_dbg(NSP_DEBUG_INTR, "timer start"); nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR); - return; + goto out; } nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR); + if ((irq_status & IRQSTATUS_SCSI) && + (irq_phase & SCSI_RESET_IRQ)) { + nsp_msg(KERN_ERR, "bus reset (power off?)"); + + nsphw_init(data); + nsp_bus_reset(data); + + if(data->CurrentSC != NULL) { + tmpSC = data->CurrentSC; + tmpSC->result = (DID_RESET << 16) | + ((tmpSC->SCp.Message & 0xff) << 8) | + ((tmpSC->SCp.Status & 0xff) << 0); + nsp_scsi_done(tmpSC); + } + goto out; + } + if (data->CurrentSC == NULL) { - printk(KERN_DEBUG __FUNCTION__ " CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x this can't be happen\n", i_src, phase, irq_phase); - return; - } else { - tmpSC = data->CurrentSC; - target = tmpSC->target; - lun = tmpSC->lun; - sync_neg = &(data->Sync[target][lun].SyncNegotiation); + nsp_msg(KERN_ERR, "CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x this can't be happen. reset everything", irq_status, phase, irq_phase); + nsphw_init(data); + nsp_bus_reset(data); + goto out; } + tmpSC = data->CurrentSC; + target = tmpSC->device->id; + lun = tmpSC->device->lun; + sync_neg = &(data->Sync[target].SyncNegotiation); + /* * parse hardware SCSI irq reasons register */ - if ((i_src & IRQSTATUS_SCSI) != 0) { - if ((irq_phase & SCSI_RESET_IRQ) != 0) { - printk(KERN_DEBUG " " __FUNCTION__ "() bus reset (power off?)\n"); - *sync_neg = SYNC_NOT_YET; - data->CurrentSC = NULL; - tmpSC->result = DID_RESET << 16; - tmpSC->scsi_done(tmpSC); - return; - } - - if ((irq_phase & RESELECT_IRQ) != 0) { - DEBUG(0, " reselect\n"); + if (irq_status & IRQSTATUS_SCSI) { + if (irq_phase & RESELECT_IRQ) { + nsp_dbg(NSP_DEBUG_INTR, "reselect"); nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR); - if (nsp_reselected(tmpSC, data) != FALSE) { - return; + if (nsp_reselected(tmpSC) != FALSE) { + goto out; } } if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) { - return; + goto out; } } @@ -955,50 +1127,48 @@ switch(tmpSC->SCp.phase) { case PH_SELSTART: - *sync_neg = SYNC_NOT_YET; + // *sync_neg = SYNC_NOT_YET; if ((phase & BUSMON_BSY) == 0) { - //DEBUG(0, " selection count=%d\n", data->SelectionTimeOut); + //nsp_dbg(NSP_DEBUG_INTR, "selection count=%d", data->SelectionTimeOut); if (data->SelectionTimeOut >= NSP_SELTIMEOUT) { - DEBUG(0, " selection time out\n"); + nsp_dbg(NSP_DEBUG_INTR, "selection time out"); data->SelectionTimeOut = 0; nsp_index_write(base, SCSIBUSCTRL, 0); - data->CurrentSC = NULL; - tmpSC->result = DID_NO_CONNECT << 16; - tmpSC->scsi_done(tmpSC); + tmpSC->result = DID_TIME_OUT << 16; + nsp_scsi_done(tmpSC); - return; + goto out; } data->SelectionTimeOut += 1; - nsp_start_timer(tmpSC, data, 1000/51); - return; + nsp_start_timer(tmpSC, 1000/51); + goto out; } /* attention assert */ - //DEBUG(0, " attention assert\n"); + //nsp_dbg(NSP_DEBUG_INTR, "attention assert"); data->SelectionTimeOut = 0; tmpSC->SCp.phase = PH_SELECTED; nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN); udelay(1); nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB); - return; + goto out; break; case PH_RESELECT: - //DEBUG(0, " phase reselect\n"); - *sync_neg = SYNC_NOT_YET; + //nsp_dbg(NSP_DEBUG_INTR, "phase reselect"); + // *sync_neg = SYNC_NOT_YET; if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) { - data->CurrentSC = NULL; tmpSC->result = DID_ABORT << 16; - tmpSC->scsi_done(tmpSC); - return; + nsp_scsi_done(tmpSC); + goto out; } /* fall thru */ default: - if ((i_src & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) { - return; + if ((irq_status & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) { + goto out; } break; } @@ -1006,140 +1176,153 @@ /* * SCSI sequencer */ - //DEBUG(0, " start scsi seq\n"); + //nsp_dbg(NSP_DEBUG_INTR, "start scsi seq"); /* normal disconnect */ - if ((irq_phase & LATCHED_BUS_FREE) != 0) { - //DEBUG(0, " normal disconnect i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", i_src, phase, irq_phase); + if (((tmpSC->SCp.phase == PH_MSG_IN) || (tmpSC->SCp.phase == PH_MSG_OUT)) && + (irq_phase & LATCHED_BUS_FREE) != 0 ) { + nsp_dbg(NSP_DEBUG_INTR, "normal disconnect irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase); + + // *sync_neg = SYNC_NOT_YET; + if ((tmpSC->SCp.Message == MSG_COMMAND_COMPLETE)) { /* all command complete and return status */ - *sync_neg = SYNC_NOT_YET; - data->CurrentSC = NULL; - tmpSC->result = (DID_OK << 16) | - (tmpSC->SCp.Message << 8) | - (tmpSC->SCp.Status << 0); - DEBUG(0, " command complete result=0x%x\n", tmpSC->result); - tmpSC->scsi_done(tmpSC); - return; + tmpSC->result = (DID_OK << 16) | + ((tmpSC->SCp.Message & 0xff) << 8) | + ((tmpSC->SCp.Status & 0xff) << 0); + nsp_dbg(NSP_DEBUG_INTR, "command complete result=0x%x", tmpSC->result); + nsp_scsi_done(tmpSC); + + goto out; } - return; + goto out; } /* check unexpected bus free state */ if (phase == 0) { - printk(KERN_DEBUG " " __FUNCTION__ " unexpected bus free. i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", i_src, phase, irq_phase); + nsp_msg(KERN_DEBUG, "unexpected bus free. irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase); - *sync_neg = SYNC_NOT_YET; - data->CurrentSC = NULL; + *sync_neg = SYNC_NG; tmpSC->result = DID_ERROR << 16; - tmpSC->scsi_done(tmpSC); - return; + nsp_scsi_done(tmpSC); + goto out; } switch (phase & BUSMON_PHASE_MASK) { case BUSPHASE_COMMAND: - DEBUG(0, " BUSPHASE_COMMAND\n"); + nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_COMMAND"); if ((phase & BUSMON_REQ) == 0) { - DEBUG(0, " REQ == 0\n"); - return; + nsp_dbg(NSP_DEBUG_INTR, "REQ == 0"); + goto out; } tmpSC->SCp.phase = PH_COMMAND; - nsp_nexus(tmpSC, data); + nsp_nexus(tmpSC); /* write scsi command */ + nsp_dbg(NSP_DEBUG_INTR, "cmd_len=%d", tmpSC->cmd_len); nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER); - for (len = 0; len < COMMAND_SIZE(tmpSC->cmnd[0]); len++) { - nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[len]); + for (i = 0; i < tmpSC->cmd_len; i++) { + nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[i]); } nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO); break; case BUSPHASE_DATA_OUT: - DEBUG(0, " BUSPHASE_DATA_OUT\n"); + nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_OUT"); - tmpSC->SCp.phase = PH_DATA; + tmpSC->SCp.phase = PH_DATA; tmpSC->SCp.have_data_in = IO_OUT; - nsp_pio_write(tmpSC, data); + nsp_pio_write(tmpSC); break; case BUSPHASE_DATA_IN: - DEBUG(0, " BUSPHASE_DATA_IN\n"); + nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_IN"); - tmpSC->SCp.phase = PH_DATA; + tmpSC->SCp.phase = PH_DATA; tmpSC->SCp.have_data_in = IO_IN; - nsp_pio_read(tmpSC, data); + nsp_pio_read(tmpSC); break; case BUSPHASE_STATUS: - nsp_dataphase_bypass(tmpSC, data); - DEBUG(0, " BUSPHASE_STATUS\n"); + nsp_dataphase_bypass(tmpSC); + nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_STATUS"); tmpSC->SCp.phase = PH_STATUS; tmpSC->SCp.Status = nsp_index_read(base, SCSIDATAWITHACK); - //DEBUG(0, " message=0x%x status=0x%x\n", tmpSC->SCp.Message, tmpSC->SCp.Status); + nsp_dbg(NSP_DEBUG_INTR, "message=0x%x status=0x%x", tmpSC->SCp.Message, tmpSC->SCp.Status); break; case BUSPHASE_MESSAGE_OUT: - DEBUG(0, " BUSPHASE_MESSAGE_OUT\n"); + nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_OUT"); if ((phase & BUSMON_REQ) == 0) { goto timer_out; } tmpSC->SCp.phase = PH_MSG_OUT; - data->MsgLen = len = 0; + // *sync_neg = SYNC_NOT_YET; + + data->MsgLen = i = 0; + data->MsgBuffer[i] = IDENTIFY(TRUE, lun); i++; + if (*sync_neg == SYNC_NOT_YET) { - data->Sync[target][lun].SyncPeriod = 0; - data->Sync[target][lun].SyncOffset = 0; - nsp_msg(tmpSC, data); - - data->MsgBuffer[len] = IDENTIFY(TRUE, lun); len++; - /* - data->MsgBuffer[len] = MSG_EXTENDED; len++; - data->MsgBuffer[len] = 3; len++; - data->MsgBuffer[len] = MSG_EXT_SDTR; len++; - data->MsgBuffer[len] = 0x0c; len++; - data->MsgBuffer[len] = 15; len++; - */ - } - if (len == 0) { - data->MsgBuffer[len] = MSG_NO_OPERATION; len++; + data->Sync[target].SyncPeriod = 0; + data->Sync[target].SyncOffset = 0; + + /**/ + data->MsgBuffer[i] = MSG_EXTENDED; i++; + data->MsgBuffer[i] = 3; i++; + data->MsgBuffer[i] = MSG_EXT_SDTR; i++; + data->MsgBuffer[i] = 0x0c; i++; + data->MsgBuffer[i] = 15; i++; + /**/ } - data->MsgLen = len; + data->MsgLen = i; + nsp_analyze_sdtr(tmpSC); show_message(data); - nsp_message_out(tmpSC, data); + nsp_message_out(tmpSC); break; case BUSPHASE_MESSAGE_IN: - nsp_dataphase_bypass(tmpSC, data); - DEBUG(0, " BUSPHASE_MESSAGE_IN\n"); + nsp_dataphase_bypass(tmpSC); + nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_IN"); if ((phase & BUSMON_REQ) == 0) { goto timer_out; } tmpSC->SCp.phase = PH_MSG_IN; - nsp_message_in(tmpSC, data); + nsp_message_in(tmpSC); - /* - if (data->MsgLen >= 5 && - data->MsgBuffer[0] == MSG_EXTENDED && - data->MsgBuffer[1] == 3 && - data->MsgBuffer[2] == MSG_EXT_SDTR ) { - data->Sync[target][lun].SyncPeriod = data->MsgBuffer[3]; - data->Sync[target][lun].SyncOffset = data->MsgBuffer[4]; - nsp_msg(tmpSC, data); + /**/ + if (*sync_neg == SYNC_NOT_YET) { + //nsp_dbg(NSP_DEBUG_INTR, "sync target=%d,lun=%d",target,lun); + + if (data->MsgLen >= 5 && + data->MsgBuffer[0] == MSG_EXTENDED && + data->MsgBuffer[1] == 3 && + data->MsgBuffer[2] == MSG_EXT_SDTR ) { + data->Sync[target].SyncPeriod = data->MsgBuffer[3]; + data->Sync[target].SyncOffset = data->MsgBuffer[4]; + //nsp_dbg(NSP_DEBUG_INTR, "sync ok, %d %d", data->MsgBuffer[3], data->MsgBuffer[4]); + *sync_neg = SYNC_OK; + } else { + data->Sync[target].SyncPeriod = 0; + data->Sync[target].SyncOffset = 0; + *sync_neg = SYNC_NG; + } + nsp_analyze_sdtr(tmpSC); } - */ + /**/ /* search last messeage byte */ tmp = -1; @@ -1151,134 +1334,291 @@ } tmpSC->SCp.Message = tmp; - DEBUG(0, " message=0x%x len=%d\n", tmpSC->SCp.Message, data->MsgLen); + nsp_dbg(NSP_DEBUG_INTR, "message=0x%x len=%d", tmpSC->SCp.Message, data->MsgLen); show_message(data); break; case BUSPHASE_SELECT: default: - DEBUG(0, " BUSPHASE other\n"); + nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE other"); break; } - //DEBUG(0, __FUNCTION__ "() out\n"); - return; + goto out; + timer_out: - nsp_start_timer(tmpSC, data, 1000/102); - return; + nsp_start_timer(tmpSC, 1000/102); + out: + nsp_write(base, IRQCONTROL, 0); /* clear IRQ mask */ + spin_unlock_irqrestore(HOST_LOCK, flags); + //nsp_dbg(NSP_DEBUG_INTR, "out"); + return IRQ_RETVAL(handled); } -#ifdef PCMCIA_DEBUG -#include "nsp_debug.c" -#endif /* DBG_SHOWCOMMAND */ /*----------------------------------------------------------------*/ /* look for ninja3 card and init if found */ /*----------------------------------------------------------------*/ -static int nsp_detect(Scsi_Host_Template *sht) +static struct Scsi_Host *nsp_detect(Scsi_Host_Template *sht) { struct Scsi_Host *host; /* registered host structure */ - nsp_hw_data *data = &nsp_data; + nsp_hw_data *data; - DEBUG(0, __FUNCTION__ " this_id=%d\n", sht->this_id); + nsp_dbg(NSP_DEBUG_INIT, "this_id=%d", sht->this_id); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) + host = scsi_host_alloc(&nsp_driver_template, sizeof(nsp_hw_data)); +#else + host = scsi_register(sht, sizeof(nsp_hw_data)); +#endif + if (host == NULL) { + nsp_dbg(NSP_DEBUG_INIT, "host failed"); + return NULL; + } - request_region(data->BaseAddress, data->NumAddress, "nsp_cs"); - host = scsi_register(sht, 0); - host->io_port = data->BaseAddress; - host->unique_id = data->BaseAddress; - host->n_io_port = data->NumAddress; - host->irq = data->IrqNumber; - host->dma_channel = 0xff; /* not use dms */ + /* Copy global variable to driver specific area */ + data = (nsp_hw_data *)host->hostdata; + *data = nsp_data_base; + + data->ScsiInfo->host = host; +#ifdef NSP_DEBUG + data->CmdId = 0; +#endif - sprintf(nspinfo, -/* Buffer size is 100 bytes */ -/* 0 1 2 3 4 5 6 7 8 9 0*/ -/* 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890*/ - "NinjaSCSI-3/32Bi Driver $Revision: 1.42 $, I/O 0x%04lx-0x%04lx IRQ %2d", - host->io_port, host->io_port + host->n_io_port, - host->irq); - sht->name = nspinfo; + nsp_dbg(NSP_DEBUG_INIT, "irq base=0x%p,%d data=0x%p,%d", &nsp_data_base, (&nsp_data_base)->IrqNumber, data, data->IrqNumber); - DEBUG(0, __FUNCTION__ " end\n"); + host->unique_id = data->BaseAddress; + host->io_port = data->BaseAddress; + host->n_io_port = data->NumAddress; + host->irq = data->IrqNumber; + host->base = data->MmioAddress; - return 1; /* detect done. */ + spin_lock_init(&(data->Lock)); + + snprintf(data->nspinfo, + sizeof(data->nspinfo), + "NinjaSCSI-3/32Bi Driver $Revision: 1.25 $ IO:0x%04lx-0x%04lx MMIO(virt addr):0x%04lx IRQ:%02d", + host->io_port, host->io_port + host->n_io_port - 1, + host->base, + host->irq); + sht->name = data->nspinfo; + + nsp_dbg(NSP_DEBUG_INIT, "end"); + + + return host; /* detect done. */ } -/* nsp_cs requires own release handler because its uses dev_id (=data) */ -static int nsp_release(struct Scsi_Host *shpnt) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +/*----------------------------------------*/ +/* Compatibility functions for 2.4 kernel */ +/*----------------------------------------*/ +static int nsp_detect_old(Scsi_Host_Template *sht) { - nsp_hw_data *data = &nsp_data; - - if (shpnt->irq) { - free_irq(shpnt->irq, data); - } - if (shpnt->io_port && shpnt->n_io_port) { - release_region(shpnt->io_port, shpnt->n_io_port); + if (nsp_detect(sht) == NULL) { + return 0; + } else { + return 1; /* detects 1 Ninja host card */ } +} + +static int nsp_release_old(struct Scsi_Host *shpnt) +{ + //nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata; + + /* PCMCIA Card Service dose same things below. */ + /* So we do nothing. */ + //if (shpnt->irq) { + // free_irq(shpnt->irq, data->ScsiInfo); + //} + //if (shpnt->io_port) { + // release_region(shpnt->io_port, shpnt->n_io_port); + //} + return 0; } +#endif /*----------------------------------------------------------------*/ /* return info string */ /*----------------------------------------------------------------*/ static const char *nsp_info(struct Scsi_Host *shpnt) { - return nspinfo; + nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata; + + return data->nspinfo; } -/*---------------------------------------------------------------*/ -/* error handler */ -/*---------------------------------------------------------------*/ -static int nsp_reset(Scsi_Cmnd *SCpnt, unsigned int why) +#undef SPRINTF +#define SPRINTF(args...) \ + do { \ + if(length > (pos - buffer)) { \ + pos += snprintf(pos, length - (pos - buffer) + 1, ## args); \ + nsp_dbg(NSP_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length, length - (pos - buffer));\ + } \ + } while(0) + +/* Shows Ninja host card information for user. */ +static int +nsp_proc_info( +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) + struct Scsi_Host *host, +#endif + char *buffer, + char **start, + off_t offset, + int length, +#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) + int hostno, +#endif + int inout) { - DEBUG(0, __FUNCTION__ " SCpnt=0x%p why=%d\n", SCpnt, why); + int id; + char *pos = buffer; + int thislength; + int speed; + unsigned long flags; + nsp_hw_data *data; +#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) + struct Scsi_Host *host; +#else + int hostno; +#endif + if (inout) { + return -EINVAL; + } - nsp_eh_bus_reset(SCpnt); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) + hostno = host->host_no; +#else + /* search this HBA host */ + host = scsi_host_hn_get(hostno); + if (host == NULL) { + return -ESRCH; + } +#endif + data = (nsp_hw_data *)host->hostdata; - return SCSI_RESET_SUCCESS; -} -static int nsp_abort(Scsi_Cmnd *SCpnt) -{ - DEBUG(0, __FUNCTION__ " SCpnt=0x%p\n", SCpnt); + SPRINTF("NinjaSCSI status\n\n"); + SPRINTF("Driver version: $Revision: 1.25 $\n"); + SPRINTF("SCSI host No.: %d\n", hostno); + SPRINTF("IRQ: %d\n", host->irq); + SPRINTF("IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1); + SPRINTF("MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1); + SPRINTF("sg_tablesize: %d\n", host->sg_tablesize); + + SPRINTF("burst transfer mode: "); + switch (nsp_burst_mode) { + case BURST_IO8: + SPRINTF("io8"); + break; + case BURST_IO32: + SPRINTF("io32"); + break; + case BURST_MEM32: + SPRINTF("mem32"); + break; + default: + SPRINTF("???"); + break; + } + SPRINTF("\n"); + SPRINTF("Chip ID: %d\n", data->ChipRev >> 4); + SPRINTF("Chip revision: %d\n", data->ChipRev & 0x0f); + + + spin_lock_irqsave(&(data->Lock), flags); + SPRINTF("CurrentSC: 0x%p\n\n", data->CurrentSC); + spin_unlock_irqrestore(&(data->Lock), flags); + + SPRINTF("SDTR status\n"); + for(id = 0; id < NUMBER(data->Sync); id++) { + + SPRINTF("id %d: ", id); + + if (id == host->this_id) { + SPRINTF("----- NinjaSCSI-3 host adapter\n"); + continue; + } - nsp_eh_bus_reset(SCpnt); + switch(data->Sync[id].SyncNegotiation) { + case SYNC_OK: + SPRINTF(" sync"); + break; + case SYNC_NG: + SPRINTF("async"); + break; + case SYNC_NOT_YET: + SPRINTF(" none"); + break; + default: + SPRINTF("?????"); + break; + } + + if (data->Sync[id].SyncPeriod != 0) { + speed = 1000000 / (data->Sync[id].SyncPeriod * 4); + + SPRINTF(" transfer %d.%dMB/s, offset %d", + speed / 1000, + speed % 1000, + data->Sync[id].SyncOffset + ); + } + SPRINTF("\n"); + } - return SCSI_ABORT_SUCCESS; + thislength = pos - (buffer + offset); + + if(thislength < 0) { + *start = 0; + return 0; + } + + + thislength = MIN(thislength, length); + *start = buffer + offset; + + return thislength; } +#undef SPRINTF + +/*---------------------------------------------------------------*/ +/* error handler */ +/*---------------------------------------------------------------*/ /*static int nsp_eh_strategy(struct Scsi_Host *Shost) { return FAILED; }*/ +/* static int nsp_eh_abort(Scsi_Cmnd *SCpnt) { - DEBUG(0, __FUNCTION__ " SCpnt=0x%p\n", SCpnt); - - nsp_eh_bus_reset(SCpnt); + nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt); - return SUCCESS; -} + return nsp_eh_bus_reset(SCpnt); +}*/ +/* static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt) { - DEBUG(0, __FUNCTION__ " SCpnt=0x%p\n", SCpnt); + nsp_dbg(NSP_DEBUG_BUSRESET, "%s: SCpnt=0x%p", SCpnt); return FAILED; -} +}*/ -static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt) +/* Do bus reset. This function uses in low-level initialize functions. */ +static int nsp_bus_reset(nsp_hw_data *data) { - unsigned int base = SCpnt->host->io_port; + unsigned int base = data->BaseAddress; int i; - DEBUG(0, __FUNCTION__ "() SCpnt=0x%p base=0x%x\n", SCpnt, base); - - nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK); + nsp_msg(KERN_WARNING, "Bus reset"); + nsp_write(base, IRQCONTROL, IRQCONTROL_ALL_CLEAR_AND_MASK); nsp_index_write(base, SCSIBUSCTRL, SCSI_RST); mdelay(100); /* 100ms */ @@ -1287,33 +1627,46 @@ nsp_index_read(base, IRQPHASESENCE); /* dummy read */ } - nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR); + nsphw_init_sync(data); + + nsp_write(base, IRQCONTROL, IRQCONTROL_ALL_CLEAR); + + if (data->CurrentSC != NULL) { + nsp_msg(KERN_WARNING, "clean up current scsi command."); + data->CurrentSC->result = DID_ERROR << 16; + nsp_scsi_done(data->CurrentSC); + } return SUCCESS; } +/* Do bus reset. This function uses in high-level SCSI driver. */ +static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt) +{ + nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; + + nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt); + + return nsp_bus_reset(data); +} + +/* Initialise Ninja host adapter. */ static int nsp_eh_host_reset(Scsi_Cmnd *SCpnt) { - nsp_hw_data *data = &nsp_data; + nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; - DEBUG(0, __FUNCTION__ "\n"); + nsp_dbg(NSP_DEBUG_BUSRESET, "in"); + nsp_msg(KERN_DEBUG, "host reset"); nsphw_init(data); - return nsp_eh_bus_reset(SCpnt); + return SUCCESS; } /********************************************************************** PCMCIA functions - *********************************************************************/ - -/*====================================================================*/ -static void cs_error(client_handle_t handle, int func, int ret) -{ - error_info_t err = { func, ret }; - CardServices(ReportError, handle, &err); -} +**********************************************************************/ /*====================================================================== nsp_cs_attach() creates an "instance" of the driver, allocating @@ -1330,15 +1683,19 @@ client_reg_t client_reg; dev_link_t *link; int ret, i; + nsp_hw_data *data = &nsp_data_base; - DEBUG(0, __FUNCTION__ "()\n"); + nsp_dbg(NSP_DEBUG_INIT, "in"); /* Create new SCSI device */ info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) { return NULL; } + if (info == NULL) { return NULL; } memset(info, 0, sizeof(*info)); link = &info->link; link->priv = info; + data->ScsiInfo = info; + + nsp_dbg(NSP_DEBUG_INIT, "info=0x%p", info); /* The io structure describes IO port mapping */ link->io.NumPorts1 = 0x10; @@ -1352,11 +1709,14 @@ link->irq.IRQInfo2 = irq_mask; } else { for (i = 0; i < 4; i++) { - link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.IRQInfo2 |= BIT(irq_list[i]); } } + + /* Interrupt handler */ link->irq.Handler = &nspintr; - link->irq.Instance = &nsp_data; + link->irq.Instance = info; + link->irq.Attributes |= (SA_SHIRQ | SA_SAMPLE_RANDOM); /* General socket configuration */ link->conf.Attributes = CONF_ENABLE_IRQ; @@ -1384,6 +1744,8 @@ return NULL; } + + nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link); return link; } /* nsp_cs_attach */ @@ -1398,8 +1760,8 @@ { dev_link_t **linkp; - DEBUG(0, __FUNCTION__ "(0x%p)\n", link); - + nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link); + /* Locate device structure */ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) { if (*linkp == link) { @@ -1411,11 +1773,7 @@ } if (link->state & DEV_CONFIG) { - nsp_cs_release((u_long)link); - if (link->state & DEV_STALE_CONFIG) { - link->state |= DEV_STALE_LINK; - return; - } + nsp_cs_release(link); } /* Break the link with Card Services */ @@ -1426,6 +1784,7 @@ /* Unlink device structure, free bits */ *linkp = link->next; kfree(link->priv); + link->priv = NULL; } /* nsp_cs_detach */ @@ -1440,22 +1799,26 @@ #define CFG_CHECK(fn, args...) \ if (CardServices(fn, args) != 0) goto next_entry /*====================================================================*/ - static void nsp_cs_config(dev_link_t *link) { client_handle_t handle = link->handle; scsi_info_t *info = link->priv; tuple_t tuple; cisparse_t parse; - int i, last_ret, last_fn; - u_char tuple_data[64]; + int last_ret, last_fn; + unsigned char tuple_data[64]; config_info_t conf; + win_req_t req; + memreq_t map; + cistpl_cftable_entry_t dflt = { 0 }; + struct Scsi_Host *host; + nsp_hw_data *data = &nsp_data_base; +#if !(LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74)) Scsi_Device *dev; dev_node_t **tail, *node; - struct Scsi_Host *host; - nsp_hw_data *data = &nsp_data; +#endif - DEBUG(0, __FUNCTION__ "() in\n"); + nsp_dbg(NSP_DEBUG_INIT, "in"); tuple.DesiredTuple = CISTPL_CONFIG; tuple.Attributes = 0; @@ -1469,7 +1832,6 @@ link->conf.Present = parse.config.rmask[0]; /* Configure card */ - driver_template.module = &__this_module; link->state |= DEV_CONFIG; /* Look up the current Vcc */ @@ -1479,81 +1841,195 @@ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; CS_CHECK(GetFirstTuple, handle, &tuple); while (1) { + cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); + CFG_CHECK(GetTupleData, handle, &tuple); CFG_CHECK(ParseTuple, handle, &tuple, &parse); - link->conf.ConfigIndex = parse.cftable_entry.index; - link->io.BasePort1 = parse.cftable_entry.io.win[0].base; - i = CardServices(RequestIO, handle, &link->io); - if (i == CS_SUCCESS) { - break; + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) { dflt = *cfg; } + if (cfg->index == 0) { goto next_entry; } + link->conf.ConfigIndex = cfg->index; + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1<vcc.param[CISTPL_POWER_VNOM]/10000) { + goto next_entry; + } + } else if (dflt.vcc.present & (1<vpp1.present & (1 << CISTPL_POWER_VNOM)) { + link->conf.Vpp1 = link->conf.Vpp2 = + cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; + } else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) { + link->conf.Vpp1 = link->conf.Vpp2 = + dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; + } + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) { + link->conf.Attributes |= CONF_ENABLE_IRQ; + } + + /* IO window settings */ + link->io.NumPorts1 = link->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; + link->io.BasePort1 = io->win[0].base; + link->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + link->io.Attributes2 = link->io.Attributes1; + link->io.BasePort2 = io->win[1].base; + link->io.NumPorts2 = io->win[1].len; + } + /* This reserves IO space but doesn't actually enable it */ + CFG_CHECK(RequestIO, link->handle, &link->io); + } + + if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { + cistpl_mem_t *mem = + (cfg->mem.nwin) ? &cfg->mem : &dflt.mem; + req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; + req.Attributes |= WIN_ENABLE; + req.Base = mem->win[0].host_addr; + req.Size = mem->win[0].len; + if (req.Size < 0x1000) { + req.Size = 0x1000; + } + req.AccessSpeed = 0; + link->win = (window_handle_t)link->handle; + CFG_CHECK(RequestWindow, &link->win, &req); + map.Page = 0; map.CardOffset = mem->win[0].card_addr; + CFG_CHECK(MapMemPage, link->win, &map); + + data->MmioAddress = (unsigned long)ioremap_nocache(req.Base, req.Size); + data->MmioLength = req.Size; + } + /* If we got this far, we're cool! */ + break; + next_entry: - DEBUG(0, __FUNCTION__ " next\n"); + nsp_dbg(NSP_DEBUG_INIT, "next"); + + if (link->io.NumPorts1) { + CardServices(ReleaseIO, link->handle, &link->io); + } CS_CHECK(GetNextTuple, handle, &tuple); } - CS_CHECK(RequestIRQ, handle, &link->irq); + if (link->conf.Attributes & CONF_ENABLE_IRQ) { + CS_CHECK(RequestIRQ, link->handle, &link->irq); + } CS_CHECK(RequestConfiguration, handle, &link->conf); - /* A bad hack... */ - release_region(link->io.BasePort1, link->io.NumPorts1); + if (free_ports) { + if (link->io.BasePort1) { + release_region(link->io.BasePort1, link->io.NumPorts1); + } + if (link->io.BasePort2) { + release_region(link->io.BasePort2, link->io.NumPorts2); + } + } /* Set port and IRQ */ data->BaseAddress = link->io.BasePort1; data->NumAddress = link->io.NumPorts1; data->IrqNumber = link->irq.AssignedIRQ; - DEBUG(0, __FUNCTION__ " I/O[0x%x+0x%x] IRQ %d\n", - data->BaseAddress, data->NumAddress, data->IrqNumber); + nsp_dbg(NSP_DEBUG_INIT, "I/O[0x%x+0x%x] IRQ %d", + data->BaseAddress, data->NumAddress, data->IrqNumber); if(nsphw_init(data) == FALSE) { goto cs_failed; } - scsi_register_module(MODULE_SCSI_HA, &driver_template); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)) + host = nsp_detect(&nsp_driver_template); +#else + scsi_register_host(&nsp_driver_template); + for (host = scsi_host_get_next(NULL); host != NULL; + host = scsi_host_get_next(host)) { + if (host->hostt == &nsp_driver_template) { + break; + } + } +#endif - DEBUG(0, "GET_SCSI_INFO\n"); + if (host == NULL) { + nsp_dbg(NSP_DEBUG_INIT, "detect failed"); + goto cs_failed; + } + + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74)) + scsi_add_host (host, NULL); + scsi_scan_host(host); + + snprintf(info->node.dev_name, sizeof(info->node.dev_name), "scsi%d", host->host_no); + link->dev = &info->node; + info->host = host; + +#else + nsp_dbg(NSP_DEBUG_INIT, "GET_SCSI_INFO"); tail = &link->dev; info->ndev = 0; - for (host = scsi_hostlist; host != NULL; host = host->next) { - if (host->hostt == &driver_template) { - for (dev = host->host_queue; dev != NULL; dev = dev->next) { - u_long arg[2], id; - kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg); - id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) + - ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000); - node = &info->node[info->ndev]; - node->minor = 0; - switch (dev->type) { - case TYPE_TAPE: - node->major = SCSI_TAPE_MAJOR; - sprintf(node->dev_name, "st#%04lx", id); - break; - case TYPE_DISK: - case TYPE_MOD: - node->major = SCSI_DISK0_MAJOR; - sprintf(node->dev_name, "sd#%04lx", id); - break; - case TYPE_ROM: - case TYPE_WORM: - node->major = SCSI_CDROM_MAJOR; - sprintf(node->dev_name, "sr#%04lx", id); - break; - default: - node->major = SCSI_GENERIC_MAJOR; - sprintf(node->dev_name, "sg#%04lx", id); - break; - } - *tail = node; tail = &node->next; - info->ndev++; - info->host = dev->host; - } + + nsp_dbg(NSP_DEBUG_INIT, "host=0x%p", host); + + for (dev = host->host_queue; dev != NULL; dev = dev->next) { + unsigned long arg[2], id; + kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg); + id = (arg[0] & 0x0f) + ((arg[0] >> 4) & 0xf0) + + ((arg[0] >> 8) & 0xf00) + ((arg[0] >> 12) & 0xf000); + node = &info->node[info->ndev]; + node->minor = 0; + switch (dev->type) { + case TYPE_TAPE: + node->major = SCSI_TAPE_MAJOR; + snprintf(node->dev_name, sizeof(node->dev_name), "st#%04lx", id); + break; + case TYPE_DISK: + case TYPE_MOD: + node->major = SCSI_DISK0_MAJOR; + snprintf(node->dev_name, sizeof(node->dev_name), "sd#%04lx", id); + break; + case TYPE_ROM: + case TYPE_WORM: + node->major = SCSI_CDROM_MAJOR; + snprintf(node->dev_name, sizeof(node->dev_name), "sr#%04lx", id); + break; + default: + node->major = SCSI_GENERIC_MAJOR; + snprintf(node->dev_name, sizeof(node->dev_name), "sg#%04lx", id); + break; } + *tail = node; tail = &node->next; + info->ndev++; + info->host = dev->host; } + *tail = NULL; if (info->ndev == 0) { - printk(KERN_INFO "nsp_cs: no SCSI devices found\n"); + nsp_msg(KERN_INFO, "no SCSI devices found"); } + nsp_dbg(NSP_DEBUG_INIT, "host=0x%p", host); +#endif /* Finally, report what we've done */ printk(KERN_INFO "nsp_cs: index 0x%02x: Vcc %d.%d", @@ -1569,47 +2045,60 @@ printk(", io 0x%04x-0x%04x", link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1-1); } + if (link->io.NumPorts2) + printk(" & 0x%04x-0x%04x", link->io.BasePort2, + link->io.BasePort2+link->io.NumPorts2-1); + if (link->win) + printk(", mem 0x%06lx-0x%06lx", req.Base, + req.Base+req.Size-1); printk("\n"); link->state &= ~DEV_CONFIG_PENDING; return; -cs_failed: + cs_failed: + nsp_dbg(NSP_DEBUG_INIT, "config fail"); cs_error(link->handle, last_fn, last_ret); - nsp_cs_release((u_long)link); - return; + nsp_cs_release(link); + return; } /* nsp_cs_config */ #undef CS_CHECK #undef CFG_CHECK + /*====================================================================== After a card is removed, nsp_cs_release() will unregister the net device, and release the PCMCIA configuration. If the device is still open, this will be postponed until it is closed. ======================================================================*/ -static void nsp_cs_release(u_long arg) +static void nsp_cs_release(dev_link_t *link) { - dev_link_t *link = (dev_link_t *)arg; - - DEBUG(0, __FUNCTION__ "(0x%p)\n", link); + scsi_info_t *info = link->priv; + nsp_hw_data *data = NULL; - /* - * If the device is currently in use, we won't release until it - * is actually closed. - */ - if (link->open) { - DEBUG(1, "nsp_cs: release postponed, '%s' still open\n", - link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; + if (info->host == NULL) { + nsp_msg(KERN_DEBUG, "unexpected card release call."); + } else { + data = (nsp_hw_data *)info->host->hostdata; } + nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link); + /* Unlink the device chain */ - scsi_unregister_module(MODULE_SCSI_HA, &driver_template); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2)) + if (info->host != NULL) { + scsi_remove_host(info->host); + } +#else + scsi_unregister_host(&nsp_driver_template); +#endif link->dev = NULL; if (link->win) { + if (data != NULL) { + iounmap((void *)(data->MmioAddress)); + } CardServices(ReleaseWindow, link->win); } CardServices(ReleaseConfiguration, link->handle); @@ -1620,10 +2109,11 @@ CardServices(ReleaseIRQ, link->handle, &link->irq); } link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_LINK) { - nsp_cs_detach(link); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2)) + if (info->host != NULL) { + scsi_host_put(info->host); } +#endif } /* nsp_cs_release */ /*====================================================================== @@ -1637,39 +2127,53 @@ to block future accesses to this device. All the functions that actually access the device should check this flag to make sure the card is still present. - + ======================================================================*/ -static int nsp_cs_event(event_t event, - int priority, - event_callback_args_t *args) +static int nsp_cs_event(event_t event, + int priority, + event_callback_args_t *args) { dev_link_t *link = args->client_data; scsi_info_t *info = link->priv; + nsp_hw_data *data; - DEBUG(1, __FUNCTION__ "(0x%06x)\n", event); + nsp_dbg(NSP_DEBUG_INIT, "in, event=0x%08x", event); switch (event) { case CS_EVENT_CARD_REMOVAL: - DEBUG(0, " event: remove\n"); + nsp_dbg(NSP_DEBUG_INIT, "event: remove"); link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { ((scsi_info_t *)link->priv)->stop = 1; - nsp_cs_release((u_long)link); + nsp_cs_release(link); } break; case CS_EVENT_CARD_INSERTION: - DEBUG(0, " event: insert\n"); + nsp_dbg(NSP_DEBUG_INIT, "event: insert"); link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,68)) info->bus = args->bus; +#endif nsp_cs_config(link); break; case CS_EVENT_PM_SUSPEND: + nsp_dbg(NSP_DEBUG_INIT, "event: suspend"); link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: /* Mark the device as stopped, to block IO until later */ + nsp_dbg(NSP_DEBUG_INIT, "event: reset physical"); + + if (info->host != NULL) { + nsp_msg(KERN_INFO, "clear SDTR status"); + + data = (nsp_hw_data *)info->host->hostdata; + + nsphw_init_sync(data); + } + info->stop = 1; if (link->state & DEV_CONFIG) { CardServices(ReleaseConfiguration, link->handle); @@ -1677,68 +2181,92 @@ break; case CS_EVENT_PM_RESUME: + nsp_dbg(NSP_DEBUG_INIT, "event: resume"); link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: - DEBUG(0, " event: reset\n"); + nsp_dbg(NSP_DEBUG_INIT, "event: reset"); if (link->state & DEV_CONFIG) { - Scsi_Cmnd tmp; - CardServices(RequestConfiguration, link->handle, &link->conf); - tmp.host = info->host; - nsp_eh_host_reset(&tmp); } info->stop = 0; + + if (info->host != NULL) { + nsp_msg(KERN_INFO, "reset host and bus"); + + data = (nsp_hw_data *)info->host->hostdata; + + nsphw_init (data); + nsp_bus_reset(data); + } + break; default: - DEBUG(0, " event: unknown\n"); + nsp_dbg(NSP_DEBUG_INIT, "event: unknown"); break; } - DEBUG(0, __FUNCTION__ " end\n"); + nsp_dbg(NSP_DEBUG_INIT, "end"); return 0; } /* nsp_cs_event */ /*======================================================================* * module entry point *====================================================================*/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68)) +static struct pcmcia_driver nsp_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "nsp_cs", + }, + .attach = nsp_cs_attach, + .detach = nsp_cs_detach, +}; +#endif + static int __init nsp_cs_init(void) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68)) + nsp_msg(KERN_INFO, "loading..."); + + return pcmcia_register_driver(&nsp_driver); +#else servinfo_t serv; - DEBUG(0, __FUNCTION__ "() in\n"); - DEBUG(0, "%s\n", version); + nsp_msg(KERN_INFO, "loading..."); CardServices(GetCardServicesInfo, &serv); if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_DEBUG "nsp_cs: Card Services release " - "does not match!\n"); - return -1; + nsp_msg(KERN_DEBUG, "Card Services release does not match!"); + return -EINVAL; } register_pcmcia_driver(&dev_info, &nsp_cs_attach, &nsp_cs_detach); - DEBUG(0, __FUNCTION__ "() out\n"); + nsp_dbg(NSP_DEBUG_INIT, "out"); return 0; +#endif } - -static void __exit nsp_cs_cleanup(void) +static void __exit nsp_cs_exit(void) { - DEBUG(0, __FUNCTION__ "() unloading\n"); + nsp_msg(KERN_INFO, "unloading..."); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68)) + pcmcia_unregister_driver(&nsp_driver); +#else unregister_pcmcia_driver(&dev_info); +#endif + + /* XXX: this really needs to move into generic code.. */ while (dev_list != NULL) { if (dev_list->state & DEV_CONFIG) { - nsp_cs_release((u_long)dev_list); + nsp_cs_release(dev_list); } nsp_cs_detach(dev_list); } } -module_init(nsp_cs_init); -module_exit(nsp_cs_cleanup); -/* - * - * - */ +module_init(nsp_cs_init) +module_exit(nsp_cs_exit) /* end */ diff -urN linux-2.4.22-bk29/drivers/scsi/pcmcia/nsp_cs.h linux-2.4.22-bk30/drivers/scsi/pcmcia/nsp_cs.h --- linux-2.4.22-bk29/drivers/scsi/pcmcia/nsp_cs.h 2001-10-11 09:04:57.000000000 -0700 +++ linux-2.4.22-bk30/drivers/scsi/pcmcia/nsp_cs.h 2003-10-07 02:50:34.000000000 -0700 @@ -10,13 +10,13 @@ =========================================================*/ -/* $Id: nsp_cs.h,v 1.27 2001/09/10 10:31:13 elca Exp $ */ +/* $Id: nsp_cs.h,v 1.20 2003/09/24 10:38:18 elca Exp $ */ #ifndef __nsp_cs__ #define __nsp_cs__ /* for debugging */ -/*#define PCMCIA_DEBUG 9*/ +//#define NSP_DEBUG 9 /* #define static @@ -26,64 +26,83 @@ /************************************ * Some useful macros... */ -#define Number(arr) ((int) (sizeof(arr) / sizeof(arr[0]))) -#define BIT(x) (1<<(x)) +#define NUMBER(arr) ((int) (sizeof(arr) / sizeof(arr[0]))) /* from XtNumber() in /usr/X11R6/include/X11/Intrinsic.h */ +#define BIT(x) (1L << (x)) #define MIN(a,b) ((a) > (b) ? (b) : (a)) -/* SCSI initiator must be 7 */ -#define SCSI_INITIATOR_ID 7 +/* SCSI initiator must be ID 7 */ +#define NSP_INITIATOR_ID 7 #define NSP_SELTIMEOUT 200 -/* base register */ -#define IRQCONTROL 0x00 +/*************************************************************************** + * register definitions + ***************************************************************************/ +/*======================================================================== + * base register + ========================================================================*/ +#define IRQCONTROL 0x00 /* R */ # define IRQCONTROL_RESELECT_CLEAR BIT(0) # define IRQCONTROL_PHASE_CHANGE_CLEAR BIT(1) # define IRQCONTROL_TIMER_CLEAR BIT(2) # define IRQCONTROL_FIFO_CLEAR BIT(3) -# define IRQCONTROL_ALLMASK 0xff -# define IRQCONTROL_ALLCLEAR 0x0f -# define IRQCONTROL_IRQDISABLE 0xf0 +# define IRQCONTROL_SCSI_IRQ_MASK BIT(4) +# define IRQCONTROL_EXT_IRQ_MASK BIT(5) +# define IRQCONTROL_TIMER_IRQ_MASK BIT(6) +# define IRQCONTROL_FIFO_IRQ_MASK BIT(7) +# define IRQCONTROL_ALL_MASK (IRQCONTROL_SCSI_IRQ_MASK | \ + IRQCONTROL_EXT_IRQ_MASK | \ + IRQCONTROL_TIMER_IRQ_MASK | \ + IRQCONTROL_FIFO_IRQ_MASK ) +# define IRQCONTROL_ALL_CLEAR (IRQCONTROL_RESELECT_CLEAR | \ + IRQCONTROL_PHASE_CHANGE_CLEAR | \ + IRQCONTROL_TIMER_CLEAR | \ + IRQCONTROL_FIFO_CLEAR ) +# define IRQCONTROL_ALL_CLEAR_AND_MASK (IRQCONTROL_ALL_MASK | \ + IRQCONTROL_ALL_CLEAR) -#define IRQSTATUS 0x00 +#define IRQSTATUS 0x00 /* W */ # define IRQSTATUS_SCSI BIT(0) # define IRQSTATUS_TIMER BIT(2) # define IRQSTATUS_FIFO BIT(3) # define IRQSTATUS_MASK 0x0f -#define IFSELECT 0x01 +#define IFSELECT 0x01 /* W */ # define IF_IFSEL BIT(0) # define IF_REGSEL BIT(2) -#define FIFOSTATUS 0x01 -# define FIFOSTATUS_CHIP_REVISION 0x0f -# define FIFOSTATUS_CHIP_ID 0x70 -# define FIFOSTATUS_FULL_EMPTY 0x80 - -#define INDEXREG 0x02 -#define DATAREG 0x03 -#define FIFODATA 0x04 -#define FIFODATA1 0x05 -#define FIFODATA2 0x06 -#define FIFODATA3 0x07 +#define FIFOSTATUS 0x01 /* R */ +# define FIFOSTATUS_CHIP_REVISION_MASK 0x0f +# define FIFOSTATUS_CHIP_ID_MASK 0x70 +# define FIFOSTATUS_FULL_EMPTY BIT(7) + +#define INDEXREG 0x02 /* R/W */ +#define DATAREG 0x03 /* R/W */ +#define FIFODATA 0x04 /* R/W */ +#define FIFODATA1 0x05 /* R/W */ +#define FIFODATA2 0x06 /* R/W */ +#define FIFODATA3 0x07 /* R/W */ + +/*==================================================================== + * indexed register + ====================================================================*/ +#define EXTBUSCTRL 0x10 /* R/W,deleted */ -/* indexed register */ -#define EXTBUSCTRL 0x10 - -#define CLOCKDIV 0x11 +#define CLOCKDIV 0x11 /* R/W */ # define CLOCK_40M 0x02 # define CLOCK_20M 0x01 +# define FAST_20 BIT(2) -#define TERMPWRCTRL 0x13 +#define TERMPWRCTRL 0x13 /* R/W */ # define POWER_ON BIT(0) -#define SCSIIRQMODE 0x15 +#define SCSIIRQMODE 0x15 /* R/W */ # define SCSI_PHASE_CHANGE_EI BIT(0) # define RESELECT_EI BIT(4) # define FIFO_IRQ_EI BIT(5) # define SCSI_RESET_IRQ_EI BIT(6) -#define IRQPHASESENCE 0x16 +#define IRQPHASESENCE 0x16 /* R */ # define LATCHED_MSG BIT(0) # define LATCHED_IO BIT(1) # define LATCHED_CD BIT(2) @@ -93,9 +112,9 @@ # define FIFO_IRQ BIT(6) # define SCSI_RESET_IRQ BIT(7) -#define TIMERCOUNT 0x17 +#define TIMERCOUNT 0x17 /* R/W */ -#define SCSIBUSCTRL 0x18 +#define SCSIBUSCTRL 0x18 /* R/W */ # define SCSI_SEL BIT(0) # define SCSI_RST BIT(1) # define SCSI_DATAOUT_ENB BIT(2) @@ -105,13 +124,13 @@ # define AUTODIRECTION BIT(6) # define ACKENB BIT(7) -#define SCSIBUSMON 0x19 +#define SCSIBUSMON 0x19 /* R */ -#define SETARBIT 0x1A +#define SETARBIT 0x1A /* W */ # define ARBIT_GO BIT(0) # define ARBIT_FLAG_CLEAR BIT(1) -#define ARBITSTATUS 0x1A +#define ARBITSTATUS 0x1A /* R */ /*# define ARBIT_GO BIT(0)*/ # define ARBIT_WIN BIT(1) # define ARBIT_FAIL BIT(2) @@ -124,90 +143,110 @@ # define CLEAR_COMMAND_POINTER BIT(0) # define AUTO_COMMAND_GO BIT(1) -#define RESELECTID 0x1C /* R */ -#define COMMANDDATA 0x1D +#define RESELECTID 0x1C /* R */ +#define COMMANDDATA 0x1D /* R/W */ -#define POINTERCLR 0x1E /* W */ +#define POINTERCLR 0x1E /* W */ # define POINTER_CLEAR BIT(0) # define ACK_COUNTER_CLEAR BIT(1) # define REQ_COUNTER_CLEAR BIT(2) # define HOST_COUNTER_CLEAR BIT(3) -# define READ_SOURCE 0x30 - -#define TRANSFERCOUNT 0x1E /* R */ - -#define TRANSFERMODE 0x20 -# define MODE_MEM8 BIT(0) -# define MODE_MEM32 BIT(1) -# define MODE_ADR24 BIT(2) -# define MODE_ADR32 BIT(3) -# define MODE_IO8 BIT(4) -# define MODE_IO32 BIT(5) -# define TRANSFER_GO BIT(6) -# define BRAIND BIT(7) +# define READ_SOURCE (BIT(4) | BIT(5)) +# define ACK_COUNTER (0) +# define REQ_COUNTER (BIT(4)) +# define HOST_COUNTER (BIT(5)) + +#define TRANSFERCOUNT 0x1E /* R */ + +#define TRANSFERMODE 0x20 /* R/W */ +# define MODE_MEM8 BIT(0) +# define MODE_MEM32 BIT(1) +# define MODE_ADR24 BIT(2) +# define MODE_ADR32 BIT(3) +# define MODE_IO8 BIT(4) +# define MODE_IO32 BIT(5) +# define TRANSFER_GO BIT(6) +# define BRAIND BIT(7) -#define SYNCREG 0x21 +#define SYNCREG 0x21 /* R/W */ # define SYNCREG_OFFSET_MASK 0x0f # define SYNCREG_PERIOD_MASK 0xf0 # define SYNCREG_PERIOD_SHIFT 4 -#define SCSIDATALATCH 0x22 -#define SCSIDATAIN 0x22 -#define SCSIDATAWITHACK 0x23 -#define SCAMCONTROL 0x24 -#define SCAMSTATUS 0x24 -#define SCAMDATA 0x25 +#define SCSIDATALATCH 0x22 /* W */ +#define SCSIDATAIN 0x22 /* R */ +#define SCSIDATAWITHACK 0x23 /* R/W */ +#define SCAMCONTROL 0x24 /* W */ +#define SCAMSTATUS 0x24 /* R */ +#define SCAMDATA 0x25 /* R/W */ -#define OTHERCONTROL 0x26 +#define OTHERCONTROL 0x26 /* R/W */ # define TPL_ROM_WRITE_EN BIT(0) # define TPWR_OUT BIT(1) # define TPWR_SENSE BIT(2) # define RA8_CONTROL BIT(3) -#define ACKWIDTH 0x27 -#define CLRTESTPNT 0x28 -#define ACKCNTLD 0x29 -#define REQCNTLD 0x2A -#define HSTCNTLD 0x2B -#define CHECKSUM 0x2C +#define ACKWIDTH 0x27 /* R/W */ +#define CLRTESTPNT 0x28 /* W */ +#define ACKCNTLD 0x29 /* W */ +#define REQCNTLD 0x2A /* W */ +#define HSTCNTLD 0x2B /* W */ +#define CHECKSUM 0x2C /* R/W */ -/* +/************************************************************************ * Input status bit definitions. - */ -#define S_ATN 0x80 /**/ -#define S_SELECT 0x40 /**/ -#define S_REQUEST 0x20 /* Request line from SCSI bus*/ -#define S_ACK 0x10 /* Acknowlege line from SCSI bus*/ -#define S_BUSY 0x08 /* Busy line from SCSI bus*/ -#define S_CD 0x04 /* Command/Data line from SCSI bus*/ -#define S_IO 0x02 /* Input/Output line from SCSI bus*/ -#define S_MESSAGE 0x01 /* Message line from SCSI bus*/ + ************************************************************************/ +#define S_MESSAGE BIT(0) /* Message line from SCSI bus */ +#define S_IO BIT(1) /* Input/Output line from SCSI bus */ +#define S_CD BIT(2) /* Command/Data line from SCSI bus */ +#define S_BUSY BIT(3) /* Busy line from SCSI bus */ +#define S_ACK BIT(4) /* Acknowlege line from SCSI bus */ +#define S_REQUEST BIT(5) /* Request line from SCSI bus */ +#define S_SELECT BIT(6) /* */ +#define S_ATN BIT(7) /* */ -/* +/*********************************************************************** * Useful Bus Monitor status combinations. - */ + ***********************************************************************/ #define BUSMON_SEL S_SELECT #define BUSMON_BSY S_BUSY #define BUSMON_REQ S_REQUEST #define BUSMON_IO S_IO #define BUSMON_ACK S_ACK #define BUSMON_BUS_FREE 0 -#define BUSMON_COMMAND ( S_BUSY | S_CD | S_REQUEST ) -#define BUSMON_MESSAGE_IN ( S_BUSY | S_MESSAGE | S_IO | S_CD | S_REQUEST ) -#define BUSMON_MESSAGE_OUT ( S_BUSY | S_MESSAGE | S_CD | S_REQUEST ) -#define BUSMON_DATA_IN ( S_BUSY | S_IO | S_REQUEST ) -#define BUSMON_DATA_OUT ( S_BUSY | S_REQUEST ) -#define BUSMON_STATUS ( S_BUSY | S_IO | S_CD | S_REQUEST ) -#define BUSMON_RESELECT ( S_SELECT | S_IO ) -#define BUSMON_PHASE_MASK ( S_SELECT | S_CD | S_MESSAGE | S_IO ) +#define BUSMON_COMMAND ( S_BUSY | S_CD | S_REQUEST ) +#define BUSMON_MESSAGE_IN ( S_BUSY | S_CD | S_IO | S_MESSAGE | S_REQUEST ) +#define BUSMON_MESSAGE_OUT ( S_BUSY | S_CD | S_MESSAGE | S_REQUEST ) +#define BUSMON_DATA_IN ( S_BUSY | S_IO | S_REQUEST ) +#define BUSMON_DATA_OUT ( S_BUSY | S_REQUEST ) +#define BUSMON_STATUS ( S_BUSY | S_CD | S_IO | S_REQUEST ) +#define BUSMON_SELECT ( S_IO | S_SELECT ) +#define BUSMON_RESELECT ( S_IO | S_SELECT ) +#define BUSMON_PHASE_MASK ( S_CD | S_IO | S_MESSAGE | S_SELECT ) +#define BUSPHASE_SELECT ( BUSMON_SELECT & BUSMON_PHASE_MASK ) #define BUSPHASE_COMMAND ( BUSMON_COMMAND & BUSMON_PHASE_MASK ) #define BUSPHASE_MESSAGE_IN ( BUSMON_MESSAGE_IN & BUSMON_PHASE_MASK ) #define BUSPHASE_MESSAGE_OUT ( BUSMON_MESSAGE_OUT & BUSMON_PHASE_MASK ) #define BUSPHASE_DATA_IN ( BUSMON_DATA_IN & BUSMON_PHASE_MASK ) #define BUSPHASE_DATA_OUT ( BUSMON_DATA_OUT & BUSMON_PHASE_MASK ) #define BUSPHASE_STATUS ( BUSMON_STATUS & BUSMON_PHASE_MASK ) -#define BUSPHASE_SELECT ( S_SELECT | S_IO ) + +/*====================================================================*/ + +typedef struct scsi_info_t { + dev_link_t link; + struct Scsi_Host *host; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74)) + dev_node_t node; +#else + int ndev; + dev_node_t node[8]; + struct bus_operations *bus; +#endif + int stop; +} scsi_info_t; + /* synchronous transfer negotiation data */ typedef struct _sync_data { @@ -222,67 +261,116 @@ unsigned char AckWidth; } sync_data; -typedef struct _nsp_data { +typedef struct _nsp_hw_data { unsigned int BaseAddress; unsigned int NumAddress; unsigned int IrqNumber; - unsigned char ScsiClockDiv; + unsigned long MmioAddress; +#define NSP_MMIO_OFFSET 0x0800 + unsigned long MmioLength; + unsigned char ScsiClockDiv; unsigned char TransferMode; + unsigned char ChipRev; int TimerCount; int SelectionTimeOut; Scsi_Cmnd *CurrentSC; + //int CurrnetTarget; int FifoCount; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) - int Residual; -#define RESID data->Residual -#else -#define RESID SCpnt->resid -#endif #define MSGBUF_SIZE 20 unsigned char MsgBuffer[MSGBUF_SIZE]; int MsgLen; #define N_TARGET 8 -#define N_LUN 8 - sync_data Sync[N_TARGET][N_LUN]; + sync_data Sync[N_TARGET]; + + char nspinfo[110]; /* description */ + spinlock_t Lock; + + scsi_info_t *ScsiInfo; /* attach <-> detect glue */ + + +#ifdef NSP_DEBUG + int CmdId; /* Accepted command serial number. + Used for debugging. */ +#endif } nsp_hw_data; -static void nsp_cs_release(u_long arg); -static int nsp_cs_event(event_t event, int priority, event_callback_args_t *args); -static dev_link_t *nsp_cs_attach(void); -static void nsp_cs_detach(dev_link_t *); - -static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt, nsp_hw_data *data); -static void nsp_start_timer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int time); - -static int nsp_detect(Scsi_Host_Template * ); -static int nsp_release(struct Scsi_Host *shpnt); -static const char * nsp_info(struct Scsi_Host *shpnt); -static int nsp_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); - -static int nsp_abort(Scsi_Cmnd *); -static int nsp_reset(Scsi_Cmnd *, unsigned int); - -static int nsp_eh_abort(Scsi_Cmnd * SCpnt); -static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt); -static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt); -static int nsp_eh_host_reset(Scsi_Cmnd *SCpnt); - -static int nsp_fifo_count(Scsi_Cmnd *SCpnt); -static void nsp_pio_read(Scsi_Cmnd *SCpnt, nsp_hw_data *data); -static int nsp_nexus(Scsi_Cmnd *SCpnt, nsp_hw_data *data); - -#ifdef PCMCIA_DEBUG -static void show_command(Scsi_Cmnd *ptr); -static void show_phase(Scsi_Cmnd *SCpnt); +/**************************************************************************** + * + */ + +/* Card service functions */ +static dev_link_t *nsp_cs_attach (void); +static void nsp_cs_detach (dev_link_t *link); +static void nsp_cs_release(dev_link_t *link); +static void nsp_cs_config (dev_link_t *link); +static int nsp_cs_event (event_t event, int priority, event_callback_args_t *args); + +/* Linux SCSI subsystem specific functions */ +static struct Scsi_Host *nsp_detect (Scsi_Host_Template *sht); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +static int nsp_detect_old (Scsi_Host_Template *sht); +static int nsp_release_old(struct Scsi_Host *shpnt); +#endif +static const char *nsp_info (struct Scsi_Host *shpnt); +static int nsp_proc_info ( +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) + struct Scsi_Host *host, +#endif + char *buffer, + char **start, + off_t offset, + int length, +#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) + int hostno, +#endif + int inout); +static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (* done)(Scsi_Cmnd *SCpnt)); + +/* Error handler */ +/*static int nsp_eh_abort (Scsi_Cmnd *SCpnt);*/ +/*static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt);*/ +static int nsp_eh_bus_reset (Scsi_Cmnd *SCpnt); +static int nsp_eh_host_reset (Scsi_Cmnd *SCpnt); +static int nsp_bus_reset (nsp_hw_data *data); + +/* */ +static int nsphw_init (nsp_hw_data *data); +static int nsphw_start_selection(Scsi_Cmnd *SCpnt); +static void nsp_start_timer (Scsi_Cmnd *SCpnt, int time); +static int nsp_fifo_count (Scsi_Cmnd *SCpnt); +static void nsp_pio_read (Scsi_Cmnd *SCpnt); +static void nsp_pio_write (Scsi_Cmnd *SCpnt); +static int nsp_nexus (Scsi_Cmnd *SCpnt); +static void nsp_scsi_done (Scsi_Cmnd *SCpnt); +static int nsp_analyze_sdtr (Scsi_Cmnd *SCpnt); +static int nsp_negate_signal (Scsi_Cmnd *SCpnt, unsigned char mask, char *str); +static int nsp_expect_signal (Scsi_Cmnd *SCpnt, unsigned char current_phase, unsigned char mask); +static int nsp_xfer (Scsi_Cmnd *SCpnt, int phase); +static int nsp_dataphase_bypass (Scsi_Cmnd *SCpnt); +static int nsp_reselected (Scsi_Cmnd *SCpnt); +static struct Scsi_Host *nsp_detect(Scsi_Host_Template *sht); + +/* Interrupt handler */ +//static irqreturn_t nspintr(int irq, void *dev_id, struct pt_regs *regs); + +/* Module entry point*/ +static int __init nsp_cs_init(void); +static void __exit nsp_cs_exit(void); + + +/* Debug */ +#ifdef NSP_DEBUG +static void show_command (Scsi_Cmnd *SCpnt); +static void show_phase (Scsi_Cmnd *SCpnt); static void show_busphase(unsigned char stat); -static void show_message(nsp_hw_data *data); +static void show_message (nsp_hw_data *data); #else # define show_command(ptr) /* */ # define show_phase(SCpnt) /* */ @@ -294,17 +382,19 @@ * SCSI phase */ enum _scsi_phase { - PH_UNDETERMINED, - PH_ARBSTART, - PH_SELSTART, - PH_SELECTED, - PH_COMMAND, - PH_DATA, - PH_STATUS, - PH_MSG_IN, - PH_MSG_OUT, - PH_DISCONNECT, - PH_RESELECT + PH_UNDETERMINED , + PH_ARBSTART , + PH_SELSTART , + PH_SELECTED , + PH_COMMAND , + PH_DATA , + PH_STATUS , + PH_MSG_IN , + PH_MSG_OUT , + PH_DISCONNECT , + PH_RESELECT , + PH_ABORT , + PH_RESET }; enum _data_in_out { @@ -313,12 +403,86 @@ IO_OUT }; +enum _burst_mode { + BURST_IO8 = 0, + BURST_IO32 = 1, + BURST_MEM32 = 2, +}; -/* SCSI messaage */ + +/************************************************************************** + * SCSI messaage + */ #define MSG_COMMAND_COMPLETE 0x00 #define MSG_EXTENDED 0x01 +#define MSG_ABORT 0x06 #define MSG_NO_OPERATION 0x08 +#define MSG_BUS_DEVICE_RESET 0x0c #define MSG_EXT_SDTR 0x01 + +/************************************************************************** + * Compatibility functions + */ + +/* for Kernel 2.4 */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) +# define scsi_register_host(template) scsi_register_module(MODULE_SCSI_HA, template) +# define scsi_unregister_host(template) scsi_unregister_module(MODULE_SCSI_HA, template) +# define scsi_host_put(host) scsi_unregister(host) + +typedef void irqreturn_t; +# define IRQ_NONE /* */ +# define IRQ_HANDLED /* */ +# define IRQ_RETVAL(x) /* */ + +/* This is ad-hoc version of scsi_host_get_next() */ +static inline struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *host) +{ + if (host == NULL) { + return scsi_hostlist; + } else { + return host->next; + } +} + +/* This is ad-hoc version of scsi_host_hn_get() */ +static inline struct Scsi_Host *scsi_host_hn_get(unsigned short hostno) +{ + struct Scsi_Host *host; + + for (host = scsi_host_get_next(NULL); host != NULL; + host = scsi_host_get_next(host)) { + if (host->host_no == hostno) { + break; + } + } + + return host; +} + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/* scatter-gather table */ +# define SG_ADDRESS(buffer) ((buffer)->address) + +/* host spin lock */ +# define HOST_LOCK (&io_request_lock) +#endif + +/* for Kernel 2.6 */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) +/* scatter-gather table */ +# define SG_ADDRESS(buffer) ((char *) (page_address((buffer)->page)+(buffer)->offset)) + +/* host spin lock */ +# define HOST_LOCK (((scsi_info_t *)dev_id)->host->host_lock) +#endif + #endif /*__nsp_cs__*/ +/* end */ diff -urN linux-2.4.22-bk29/drivers/scsi/pcmcia/nsp_debug.c linux-2.4.22-bk30/drivers/scsi/pcmcia/nsp_debug.c --- linux-2.4.22-bk29/drivers/scsi/pcmcia/nsp_debug.c 2001-10-11 09:04:57.000000000 -0700 +++ linux-2.4.22-bk30/drivers/scsi/pcmcia/nsp_debug.c 2003-10-07 02:50:34.000000000 -0700 @@ -6,7 +6,7 @@ the GNU General Public License. =========================================================================*/ -/* $Id: nsp_debug.c,v 1.8 2001/09/07 04:32:28 elca Exp $ */ +/* $Id: nsp_debug.c,v 1.3 2003/07/26 14:21:09 elca Exp $ */ /* * Show the command data of a command @@ -87,14 +87,21 @@ static void print_commandk (unsigned char *command) { - int i,s; + int i, s; printk(KERN_DEBUG); print_opcodek(command[0]); /*printk(KERN_DEBUG __FUNCTION__ " ");*/ - for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) { + if ((command[0] >> 5) == 6 || + (command[0] >> 5) == 7 ) { + s = 12; /* vender specific */ + } else { + s = COMMAND_SIZE(command[0]); + } + for ( i = 1; i < s; ++i) { printk("%02x ", command[i]); } - switch (COMMAND_SIZE(command[0])) { + + switch (s) { case 6: printk("LBA=%d len=%d", (((unsigned int)command[1] & 0x0f) << 16) | @@ -131,9 +138,9 @@ printk("\n"); } -static void show_command(Scsi_Cmnd *ptr) +static void show_command(Scsi_Cmnd *SCpnt) { - print_commandk(ptr->cmnd); + print_commandk(SCpnt->cmnd); } static void show_phase(Scsi_Cmnd *SCpnt) diff -urN linux-2.4.22-bk29/drivers/scsi/pcmcia/nsp_io.h linux-2.4.22-bk30/drivers/scsi/pcmcia/nsp_io.h --- linux-2.4.22-bk29/drivers/scsi/pcmcia/nsp_io.h 2001-10-11 09:04:57.000000000 -0700 +++ linux-2.4.22-bk30/drivers/scsi/pcmcia/nsp_io.h 2003-10-07 02:50:34.000000000 -0700 @@ -7,7 +7,7 @@ */ -/* $Id: nsp_io.h,v 1.9 2001/09/07 04:32:42 elca Exp $ */ +/* $Id: nsp_io.h,v 1.3 2003/08/04 21:15:26 elca Exp $ */ #ifndef __NSP_IO_H__ #define __NSP_IO_H__ @@ -76,7 +76,7 @@ void *buf, unsigned long count) { - //DEBUG(0, __FUNCTION__ "() buf=0x%p, count=0x%lx\n", buf, count); + /*nsp_dbg(NSP_DEBUG_DATA_IO, "buf=0x%p, count=0x%lx", buf, count);*/ nsp_multi_read_1(base, FIFODATA, buf, count); } @@ -95,7 +95,7 @@ void *buf, unsigned long count) { - //DEBUG(0, __FUNCTION__ "() buf=0x%p, count=0x%lx*2\n", buf, count); + //nsp_dbg(NSP_DEBUG_DATA_IO, "buf=0x%p, count=0x%lx*2", buf, count); nsp_multi_read_2(base, FIFODATA, buf, count); } @@ -114,7 +114,7 @@ void *buf, unsigned long count) { - //DEBUG(0, __FUNCTION__ "() buf=0x%p, count=0x%lx*4\n", buf, count); + //nsp_dbg(NSP_DEBUG_DATA_IO, "buf=0x%p, count=0x%lx*4", buf, count); nsp_multi_read_4(base, FIFODATA, buf, count); } @@ -172,5 +172,103 @@ nsp_multi_write_4(base, FIFODATA, buf, count); } + +/*====================================================================*/ + +static inline void nsp_mmio_write(unsigned long base, + unsigned int index, + unsigned char val) +{ + unsigned char *ptr = (unsigned char *)(base + NSP_MMIO_OFFSET + index); + + writeb(val, ptr); +} + +static inline unsigned char nsp_mmio_read(unsigned long base, + unsigned int index) +{ + unsigned char *ptr = (unsigned char *)(base + NSP_MMIO_OFFSET + index); + + return readb(ptr); +} + +/*-----------*/ + +static inline unsigned char nsp_mmio_index_read(unsigned long base, + unsigned int reg) +{ + unsigned char *index_ptr = (unsigned char *)(base + NSP_MMIO_OFFSET + INDEXREG); + unsigned char *data_ptr = (unsigned char *)(base + NSP_MMIO_OFFSET + DATAREG); + + writeb((unsigned char)reg, index_ptr); + return readb(data_ptr); +} + +static inline void nsp_mmio_index_write(unsigned long base, + unsigned int reg, + unsigned char val) +{ + unsigned char *index_ptr = (unsigned char *)(base + NSP_MMIO_OFFSET + INDEXREG); + unsigned char *data_ptr = (unsigned char *)(base + NSP_MMIO_OFFSET + DATAREG); + + writeb((unsigned char)reg, index_ptr); + writeb(val, data_ptr); +} + +/* read 32bit FIFO */ +static inline void nsp_mmio_multi_read_4(unsigned long base, + unsigned int Register, + void *buf, + unsigned long count) +{ + unsigned long *ptr = (unsigned long *)(base + Register); + unsigned long *tmp = (unsigned long *)buf; + int i; + + //nsp_dbg(NSP_DEBUG_DATA_IO, "base 0x%0lx ptr 0x%p",base,ptr); + + for (i = 0; i < count; i++) { + *tmp = readl(ptr); + //nsp_dbg(NSP_DEBUG_DATA_IO, "<%d,%p,%p,%lx>", i, ptr, tmp, *tmp); + tmp++; + } +} + +static inline void nsp_mmio_fifo32_read(unsigned int base, + void *buf, + unsigned long count) +{ + //nsp_dbg(NSP_DEBUG_DATA_IO, "buf=0x%p, count=0x%lx*4", buf, count); + nsp_mmio_multi_read_4(base, FIFODATA, buf, count); +} + +static inline void nsp_mmio_multi_write_4(unsigned long base, + unsigned int Register, + void *buf, + unsigned long count) +{ + unsigned long *ptr = (unsigned long *)(base + Register); + unsigned long *tmp = (unsigned long *)buf; + int i; + + //nsp_dbg(NSP_DEBUG_DATA_IO, "base 0x%0lx ptr 0x%p",base,ptr); + + for (i = 0; i < count; i++) { + writel(*tmp, ptr); + //nsp_dbg(NSP_DEBUG_DATA_IO, "<%d,%p,%p,%lx>", i, ptr, tmp, *tmp); + tmp++; + } +} + +static inline void nsp_mmio_fifo32_write(unsigned int base, + void *buf, + unsigned long count) +{ + //nsp_dbg(NSP_DEBUG_DATA_IO, "buf=0x%p, count=0x%lx*4", buf, count); + nsp_mmio_multi_write_4(base, FIFODATA, buf, count); +} + + + #endif /* end */ diff -urN linux-2.4.22-bk29/drivers/scsi/pcmcia/nsp_message.c linux-2.4.22-bk30/drivers/scsi/pcmcia/nsp_message.c --- linux-2.4.22-bk29/drivers/scsi/pcmcia/nsp_message.c 2001-10-11 09:04:57.000000000 -0700 +++ linux-2.4.22-bk30/drivers/scsi/pcmcia/nsp_message.c 2003-10-07 02:50:34.000000000 -0700 @@ -6,11 +6,12 @@ the GNU General Public License. */ -/* $Id: nsp_message.c,v 1.7 2001/09/07 04:33:01 elca Exp $ */ +/* $Id: nsp_message.c,v 1.6 2003/07/26 14:21:09 elca Exp $ */ -static void nsp_message_in(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +static void nsp_message_in(Scsi_Cmnd *SCpnt) { - unsigned int base = SCpnt->host->io_port; + unsigned int base = SCpnt->device->host->io_port; + nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; unsigned char data_reg, control_reg; int ret, len; @@ -23,7 +24,7 @@ ret = 16; len = 0; - DEBUG(0, " msgin loop\n"); + nsp_dbg(NSP_DEBUG_MSGINOCCUR, "msgin loop"); do { /* read data */ data_reg = nsp_index_read(base, SCSIDATAIN); @@ -49,8 +50,9 @@ } -static void nsp_message_out(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +static void nsp_message_out(Scsi_Cmnd *SCpnt) { + nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; int ret = 1; int len = data->MsgLen; @@ -61,10 +63,10 @@ * the next "msg out" if exists (no scsi phase changes). */ - DEBUG(0, " msgout loop\n"); + nsp_dbg(NSP_DEBUG_MSGOUTOCCUR, "msgout loop"); do { - if (nsp_xfer(SCpnt, data, BUSPHASE_MESSAGE_OUT)) { - printk(KERN_DEBUG " " __FUNCTION__ " msgout: xfer short\n"); + if (nsp_xfer(SCpnt, BUSPHASE_MESSAGE_OUT)) { + nsp_msg(KERN_DEBUG, "msgout: xfer short"); } /* catch a next signal */ diff -urN linux-2.4.22-bk29/drivers/video/q40fb.c linux-2.4.22-bk30/drivers/video/q40fb.c --- linux-2.4.22-bk29/drivers/video/q40fb.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.22-bk30/drivers/video/q40fb.c 2003-10-07 02:50:34.000000000 -0700 @@ -148,6 +148,8 @@ return -EINVAL; if(var->activate!=FB_ACTIVATE_NOW) return -EINVAL; +// ignore broken tools trying to set these values +#if 0 if(var->pixclock!=0) return -EINVAL; if(var->left_margin!=0) @@ -162,6 +164,7 @@ return -EINVAL; if(var->vmode!=FB_VMODE_NONINTERLACED) return -EINVAL; +#endif return 0; diff -urN linux-2.4.22-bk29/fs/Config.in linux-2.4.22-bk30/fs/Config.in --- linux-2.4.22-bk29/fs/Config.in 2003-08-25 04:44:43.000000000 -0700 +++ linux-2.4.22-bk30/fs/Config.in 2003-10-07 02:50:35.000000000 -0700 @@ -72,9 +72,13 @@ bool '/proc file system support' CONFIG_PROC_FS +# For some reason devfs corrupts memory badly on x86-64. Disable it +# for now. +if [ "$CONFIG_X86_64" != "y" ] ; then dep_bool '/dev file system support (EXPERIMENTAL)' CONFIG_DEVFS_FS $CONFIG_EXPERIMENTAL dep_bool ' Automatically mount at boot' CONFIG_DEVFS_MOUNT $CONFIG_DEVFS_FS dep_bool ' Debug devfs' CONFIG_DEVFS_DEBUG $CONFIG_DEVFS_FS +fi # It compiles as a module for testing only. It should not be used # as a module in general. If we make this "tristate", a bunch of people diff -urN linux-2.4.22-bk29/fs/namespace.c linux-2.4.22-bk30/fs/namespace.c --- linux-2.4.22-bk29/fs/namespace.c 2003-10-07 02:50:31.000000000 -0700 +++ linux-2.4.22-bk30/fs/namespace.c 2003-10-07 02:50:35.000000000 -0700 @@ -110,7 +110,7 @@ mnt->mnt_parent = mntget(nd->mnt); mnt->mnt_mountpoint = dget(nd->dentry); list_add(&mnt->mnt_hash, mount_hashtable+hash(nd->mnt, nd->dentry)); - list_add(&mnt->mnt_child, &nd->mnt->mnt_mounts); + list_add_tail(&mnt->mnt_child, &nd->mnt->mnt_mounts); nd->dentry->d_mounted++; } diff -urN linux-2.4.22-bk29/fs/proc/proc_devtree.c linux-2.4.22-bk30/fs/proc/proc_devtree.c --- linux-2.4.22-bk29/fs/proc/proc_devtree.c 2000-05-21 20:34:37.000000000 -0700 +++ linux-2.4.22-bk30/fs/proc/proc_devtree.c 2003-10-07 02:50:35.000000000 -0700 @@ -59,11 +59,14 @@ * Unfortunately proc_register puts each new entry * at the beginning of the list. So we rearrange them. */ - ent = create_proc_read_entry(pp->name, S_IRUGO, de, - property_read_proc, pp); + ent = create_proc_read_entry(pp->name, strncmp(pp->name, "security-", 9) ? + S_IRUGO : S_IRUSR, de, property_read_proc, pp); if (ent == 0) break; - ent->size = pp->length; + if (!strncmp(pp->name, "security-", 9)) + ent->size = 0; /* don't leak number of password chars */ + else + ent->size = pp->length; *lastp = ent; lastp = &ent->next; } diff -urN linux-2.4.22-bk29/fs/proc/proc_misc.c linux-2.4.22-bk30/fs/proc/proc_misc.c --- linux-2.4.22-bk29/fs/proc/proc_misc.c 2003-10-07 02:50:31.000000000 -0700 +++ linux-2.4.22-bk30/fs/proc/proc_misc.c 2003-10-07 02:50:35.000000000 -0700 @@ -430,6 +430,9 @@ }; #endif /* !CONFIG_X86 */ +extern struct file_operations proc_ioports_operations; +extern struct file_operations proc_iomem_operations; + static int filesystems_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -444,13 +447,6 @@ return proc_calc_metrics(page, start, off, count, eof, len); } -static int ioports_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = get_ioport_list(page); - return proc_calc_metrics(page, start, off, count, eof, len); -} - static int cmdline_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -495,13 +491,6 @@ return proc_calc_metrics(page, start, off, count, eof, len); } -static int memory_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = get_mem_list(page); - return proc_calc_metrics(page, start, off, count, eof, len); -} - /* * This function accesses profiling information. The returned data is * binary: the sampling step and the actual contents of the profile @@ -625,14 +614,12 @@ #endif {"filesystems", filesystems_read_proc}, {"dma", dma_read_proc}, - {"ioports", ioports_read_proc}, {"cmdline", cmdline_read_proc}, #ifdef CONFIG_SGI_DS1286 {"rtc", ds1286_read_proc}, #endif {"locks", locks_read_proc}, {"swaps", swaps_read_proc}, - {"iomem", memory_read_proc}, {"execdomains", execdomains_read_proc}, {NULL,} }; @@ -649,6 +636,8 @@ #if defined(CONFIG_X86) create_seq_entry("interrupts", 0, &proc_interrupts_operations); #endif + create_seq_entry("ioports", 0, &proc_ioports_operations); + create_seq_entry("iomem", 0, &proc_iomem_operations); create_seq_entry("partitions", 0, &proc_partitions_operations); create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations); #ifdef CONFIG_MODULES diff -urN linux-2.4.22-bk29/include/asm-m68k/dvma.h linux-2.4.22-bk30/include/asm-m68k/dvma.h --- linux-2.4.22-bk29/include/asm-m68k/dvma.h 2003-06-13 07:51:38.000000000 -0700 +++ linux-2.4.22-bk30/include/asm-m68k/dvma.h 2003-10-07 02:50:35.000000000 -0700 @@ -110,7 +110,7 @@ /* Linux DMA information structure, filled during probe. */ struct Linux_SBus_DMA { struct Linux_SBus_DMA *next; - struct linux_sbus_device *SBus_dev; + struct sbus_dev *SBus_dev; struct sparc_dma_registers *regs; /* Status, misc info */ diff -urN linux-2.4.22-bk29/include/asm-m68k/system.h linux-2.4.22-bk30/include/asm-m68k/system.h --- linux-2.4.22-bk29/include/asm-m68k/system.h 2003-06-13 07:51:38.000000000 -0700 +++ linux-2.4.22-bk30/include/asm-m68k/system.h 2003-10-07 02:50:35.000000000 -0700 @@ -42,8 +42,9 @@ register void *_next __asm__ ("a1") = (next); \ register void *_last __asm__ ("d1"); \ __asm__ __volatile__("jbsr " SYMBOL_NAME_STR(resume) \ - : "=d" (_last) : "a" (_prev), "a" (_next) \ - : "d0", /* "d1", */ "d2", "d3", "d4", "d5", "a0", "a1"); \ + : "=a" (_prev), "=a" (_next), "=d" (_last) \ + : "0" (_prev), "1" (_next) \ + : "d0", "d2", "d3", "d4", "d5"); \ (last) = _last; \ } diff -urN linux-2.4.22-bk29/include/linux/ioport.h linux-2.4.22-bk30/include/linux/ioport.h --- linux-2.4.22-bk29/include/linux/ioport.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.22-bk30/include/linux/ioport.h 2003-10-07 02:50:35.000000000 -0700 @@ -83,8 +83,6 @@ extern struct resource ioport_resource; extern struct resource iomem_resource; -extern int get_resource_list(struct resource *, char *buf, int size); - extern int check_resource(struct resource *root, unsigned long, unsigned long); extern int request_resource(struct resource *root, struct resource *new); extern int release_resource(struct resource *new); @@ -111,9 +109,6 @@ extern int __check_region(struct resource *, unsigned long, unsigned long); extern void __release_region(struct resource *, unsigned long, unsigned long); -#define get_ioport_list(buf) get_resource_list(&ioport_resource, buf, PAGE_SIZE) -#define get_mem_list(buf) get_resource_list(&iomem_resource, buf, PAGE_SIZE) - #define HAVE_AUTOIRQ extern void autoirq_setup(int waittime); extern int autoirq_report(int waittime); diff -urN linux-2.4.22-bk29/kernel/resource.c linux-2.4.22-bk30/kernel/resource.c --- linux-2.4.22-bk29/kernel/resource.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.22-bk30/kernel/resource.c 2003-10-07 02:50:35.000000000 -0700 @@ -13,6 +13,7 @@ #include #include #include +#include #include struct resource ioport_resource = { "PCI IO", 0x0000, IO_SPACE_LIMIT, IORESOURCE_IO }; @@ -20,48 +21,92 @@ static rwlock_t resource_lock = RW_LOCK_UNLOCKED; -/* - * This generates reports for /proc/ioports and /proc/iomem - */ -static char * do_resource_list(struct resource *entry, const char *fmt, int offset, char *buf, char *end) +enum { MAX_IORES_LEVEL = 5 }; + +static void *r_next(struct seq_file *m, void *v, loff_t *pos) { - if (offset < 0) - offset = 0; + struct resource *p = v; + (*pos)++; + if (p->child) + return p->child; + while (!p->sibling && p->parent) + p = p->parent; + return p->sibling; +} - while (entry) { - const char *name = entry->name; - unsigned long from, to; - - if ((int) (end-buf) < 80) - return buf; - - from = entry->start; - to = entry->end; - if (!name) - name = ""; - - buf += sprintf(buf, fmt + offset, from, to, name); - if (entry->child) - buf = do_resource_list(entry->child, fmt, offset-2, buf, end); - entry = entry->sibling; - } +static void *r_start(struct seq_file *m, loff_t *pos) +{ + struct resource *p = m->private; + loff_t l = 0; + read_lock(&resource_lock); + for (p = p->child; p && l < *pos; p = r_next(m, p, &l)) + ; + return p; +} - return buf; +static void r_stop(struct seq_file *m, void *v) +{ + read_unlock(&resource_lock); } -int get_resource_list(struct resource *root, char *buf, int size) +static int r_show(struct seq_file *m, void *v) { - char *fmt; - int retval; + struct resource *root = m->private; + struct resource *r = v, *p; + int width = root->end < 0x10000 ? 4 : 8; + int depth; - fmt = " %08lx-%08lx : %s\n"; - if (root->end < 0x10000) - fmt = " %04lx-%04lx : %s\n"; - read_lock(&resource_lock); - retval = do_resource_list(root->child, fmt, 8, buf, buf + size) - buf; - read_unlock(&resource_lock); - return retval; -} + for (depth = 0, p = r; depth < MAX_IORES_LEVEL; depth++, p = p->parent) + if (p->parent == root) + break; + seq_printf(m, "%*s%0*lx-%0*lx : %s\n", + depth * 2, "", + width, r->start, + width, r->end, + r->name ? r->name : ""); + return 0; +} + +static struct seq_operations resource_op = { + .start = r_start, + .next = r_next, + .stop = r_stop, + .show = r_show, +}; + +static int ioports_open(struct inode *inode, struct file *file) +{ + int res = seq_open(file, &resource_op); + if (!res) { + struct seq_file *m = file->private_data; + m->private = &ioport_resource; + } + return res; +} + +static int iomem_open(struct inode *inode, struct file *file) +{ + int res = seq_open(file, &resource_op); + if (!res) { + struct seq_file *m = file->private_data; + m->private = &iomem_resource; + } + return res; +} + +struct file_operations proc_ioports_operations = { + .open = ioports_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +struct file_operations proc_iomem_operations = { + .open = iomem_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; /* Return the conflict entry if you can't request it */ static struct resource * __request_resource(struct resource *root, struct resource *new) diff -urN linux-2.4.22-bk29/scripts/mkuboot.sh linux-2.4.22-bk30/scripts/mkuboot.sh --- linux-2.4.22-bk29/scripts/mkuboot.sh 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.22-bk30/scripts/mkuboot.sh 2003-10-07 02:50:36.000000000 -0700 @@ -0,0 +1,16 @@ +#!/bin/bash + +# +# Build U-Boot image when `mkimage' tool is available. +# + +MKIMAGE=$(type -path mkimage) + +if [ -z "${MKIMAGE}" ]; then + # Doesn't exist + echo '"mkimage" command not found - U-Boot images will not be built' >&2 + exit 0; +fi + +# Call "mkimage" to create U-Boot image +${MKIMAGE} "$@"