These are the diffs required to make loadable low-level scsi drivers work. I have tested this on my system with the 1542 driver, and it seems to do the right thing. The access count is keyed upon the mount/open count of all associated devices, and if you unmount everything then you cqn remove the drivers and reload ifyou want. There are undoubtably bugs left in this, but it is good enough that it scans the partition table on my disk and I can mount a disk partition. I can also use my scsi tape drive and mount the cdrom, so the basic functionality is covered. -Eric --- ./init/main.c.~1~ Sun Nov 13 12:49:26 1994 +++ ./init/main.c Sun Nov 13 12:56:01 1994 @@ -93,6 +93,7 @@ extern void pas16_setup(char *str, int *ints); extern void generic_NCR5380_setup(char *str, int *intr); extern void aha152x_setup(char *str, int *ints); +extern void aha1542_setup(char *str, int *ints); extern void aha274x_setup(char *str, int *ints); extern void scsi_luns_setup(char *str, int *ints); extern void sound_setup(char *str, int *ints); @@ -211,6 +212,9 @@ #endif #ifdef CONFIG_SCSI_AHA152X { "aha152x=", aha152x_setup}, +#endif +#ifdef CONFIG_SCSI_AHA1542 + { "aha1542=", aha1542_setup}, #endif #ifdef CONFIG_SCSI_AHA274X { "aha274x=", aha274x_setup}, --- ./kernel/ioport.c.~1~ Sun Nov 13 12:46:33 1994 +++ ./kernel/ioport.c Sun Nov 13 12:54:14 1994 @@ -165,6 +165,16 @@ return; } +void release_region(unsigned int from, unsigned int num) +{ + if (from > IO_BITMAP_SIZE*32) + return; + if (from + num > IO_BITMAP_SIZE*32) + num = IO_BITMAP_SIZE*32 - from; + set_bitmap(ioport_registrar, from, num, 0); + return; +} + int check_region(unsigned int from, unsigned int num) { if (from > IO_BITMAP_SIZE*32) --- ./kernel/ksyms.c.~1~ Sun Nov 13 12:50:12 1994 +++ ./kernel/ksyms.c Sun Nov 13 12:57:59 1994 @@ -35,6 +35,10 @@ #include #endif +#ifdef CONFIG_SCSI +#include +#endif + #include extern void *sys_call_table; @@ -47,6 +51,15 @@ extern void (*do_floppy)(void); #endif +#ifdef CONFIG_SCSI +extern int scsi_register_module(int, void *); +extern void scsi_unregister_module(int, void *); +extern void * scsi_malloc(unsigned int); +extern int scsi_free(void *, unsigned int); +extern struct Scsi_Host * scsi_register(struct SHT *, int); +extern void scsi_unregister(struct Scsi_Host *); +#endif + extern int sys_tz; extern int request_dma(unsigned int dmanr, char * deviceID); extern void free_dma(unsigned int dmanr); @@ -217,6 +230,19 @@ X(dev_ioctl), X(dev_queue_xmit), X(dev_base), +#endif +#ifdef CONFIG_SCSI + /* Supports loadable scsi drivers */ + X(scsi_register_module), + X(scsi_unregister_module), + X(snarf_region), + X(release_region), + X(check_region), + X(loops_per_sec), + X(scsi_free), + X(scsi_malloc), + X(scsi_register), + X(scsi_unregister), #endif /* Added to make file system as module */ X(set_writetime), --- ./mm/swap.c.~1~ Sun Nov 13 12:50:13 1994 +++ ./mm/swap.c Sun Nov 13 23:34:18 1994 @@ -19,6 +19,7 @@ #include #include +#include #include /* for cli()/sti() */ #include @@ -648,16 +649,16 @@ */ unsigned long __get_dma_pages(int priority, unsigned long order) { - unsigned long list = 0; + unsigned long list = 0; unsigned long result; - unsigned long limit = 16*1024*1024; - + unsigned long limit = MAX_DMA_ADDRESS; + /* if (EISA_bus) limit = ~0UL; */ if (priority != GFP_ATOMIC) priority = GFP_BUFFER; for (;;) { result = __get_free_pages(priority, order); - if (result < limit) /* covers failure as well */ + if (result <= limit - (1<<(order+12))) /* covers failure as well */ break; *(unsigned long *) result = list; list = result; @@ -991,3 +992,5 @@ } return start_mem; } + + --- ./mm/kmalloc.c.~1~ Sun Nov 13 12:46:34 1994 +++ ./mm/kmalloc.c Sun Nov 13 12:54:15 1994 @@ -84,6 +84,7 @@ */ struct size_descriptor { struct page_descriptor *firstfree; + struct page_descriptor *dmafree; /* DMA-able memory */ int size; int nblocks; @@ -100,20 +101,20 @@ */ struct size_descriptor sizes[] = { - { NULL, 32,127, 0,0,0,0, 0}, - { NULL, 64, 63, 0,0,0,0, 0 }, - { NULL, 128, 31, 0,0,0,0, 0 }, - { NULL, 252, 16, 0,0,0,0, 0 }, - { NULL, 508, 8, 0,0,0,0, 0 }, - { NULL,1020, 4, 0,0,0,0, 0 }, - { NULL,2040, 2, 0,0,0,0, 0 }, - { NULL,4096-16, 1, 0,0,0,0, 0 }, - { NULL,8192-16, 1, 0,0,0,0, 1 }, - { NULL,16384-16, 1, 0,0,0,0, 2 }, - { NULL,32768-16, 1, 0,0,0,0, 3 }, - { NULL,65536-16, 1, 0,0,0,0, 4 }, - { NULL,131072-16, 1, 0,0,0,0, 5 }, - { NULL, 0, 0, 0,0,0,0, 0 } + { NULL, NULL, 32,127, 0,0,0,0, 0}, + { NULL, NULL, 64, 63, 0,0,0,0, 0 }, + { NULL, NULL, 128, 31, 0,0,0,0, 0 }, + { NULL, NULL, 252, 16, 0,0,0,0, 0 }, + { NULL, NULL, 508, 8, 0,0,0,0, 0 }, + { NULL, NULL,1020, 4, 0,0,0,0, 0 }, + { NULL, NULL,2040, 2, 0,0,0,0, 0 }, + { NULL, NULL,4096-16, 1, 0,0,0,0, 0 }, + { NULL, NULL,8192-16, 1, 0,0,0,0, 1 }, + { NULL, NULL,16384-16, 1, 0,0,0,0, 2 }, + { NULL, NULL,32768-16, 1, 0,0,0,0, 3 }, + { NULL, NULL,65536-16, 1, 0,0,0,0, 4 }, + { NULL, NULL,131072-16, 1, 0,0,0,0, 5 }, + { NULL, NULL, 0, 0, 0,0,0,0, 0 } }; @@ -164,9 +165,13 @@ { unsigned long flags; int order,tries,i,sz; + int dma_flag; struct block_header *p; struct page_descriptor *page; + dma_flag = (priority & GFP_DMA); + priority &= GFP_LEVEL_MASK; + /* Sanity check... */ if (intr_count && priority != GFP_ATOMIC) { static int count = 0; @@ -193,7 +198,7 @@ { /* Try to allocate a "recently" freed memory block */ cli (); - if ((page = sizes[order].firstfree) && + if ((page = (dma_flag ? sizes[order].dmafree : sizes[order].firstfree)) && (p = page->firstfree)) { if (p->bh_flags == MF_FREE) @@ -224,7 +229,11 @@ sz = BLOCKSIZE(order); /* sz is the size of the blocks we're dealing with */ /* This can be done with ints on: This is private to this invocation */ - page = (struct page_descriptor *) __get_free_pages (priority & GFP_LEVEL_MASK, sizes[order].gfporder); + if (dma_flag) + page = (struct page_descriptor *) __get_dma_pages (priority & GFP_LEVEL_MASK, sizes[order].gfporder); + else + page = (struct page_descriptor *) __get_free_pages (priority & GFP_LEVEL_MASK, sizes[order].gfporder); + if (!page) { static unsigned long last = 0; if (last + 10*HZ < jiffies) { @@ -262,7 +271,10 @@ * here, but you never know.... */ page->next = sizes[order].firstfree; - sizes[order].firstfree = page; + if (dma_flag) + sizes[order].dmafree = page; + else + sizes[order].firstfree = page; restore_flags(flags); } @@ -280,7 +292,6 @@ return NULL; } - void kfree_s (void *ptr,int size) { unsigned long flags; @@ -315,7 +326,8 @@ page->nfree ++; if (page->nfree == 1) - { /* Page went from full to one free block: put it on the freelist */ + { /* Page went from full to one free block: put it on the freelist. Do not bother + trying to put it on the DMA list. */ if (page->next) { printk ("Page %p already on freelist dazed and confused....\n", page); @@ -337,11 +349,20 @@ { sizes[order].firstfree = page->next; } + else if (sizes[order].dmafree == page) + { + sizes[order].dmafree = page->next; + } else { for (pg2=sizes[order].firstfree; (pg2 != NULL) && (pg2->next != page); pg2=pg2->next) + /* Nothing */; + if (!pg2) + for (pg2=sizes[order].dmafree; + (pg2 != NULL) && (pg2->next != page); + pg2=pg2->next) /* Nothing */; if (pg2 != NULL) pg2->next = page->next; --- ./include/linux/ioport.h.~1~ Sun Nov 13 12:46:34 1994 +++ ./include/linux/ioport.h Sun Nov 13 12:54:15 1994 @@ -14,10 +14,12 @@ /* * Call check_region() before probing for your hardware. * Once you have found you hardware, register it with snarf_region(). + * If you unload the driver, use release_region to free ports. */ extern void reserve_setup(char *str, int *ints); extern int check_region(unsigned int from, unsigned int extent); extern void snarf_region(unsigned int from, unsigned int extent); +extern void release_region(unsigned int from, unsigned int extent); #define HAVE_AUTOIRQ --- ./include/linux/mm.h.~1~ Sun Nov 13 12:50:07 1994 +++ ./include/linux/mm.h Sun Nov 13 13:02:19 1994 @@ -235,6 +235,11 @@ #define GFP_NOBUFFER 0x04 #define GFP_NFS 0x05 +/* Flag - indicates that the buffer will be suitable for DMA. Ignored on some + platforms, used as appropriate on others */ + +#define GFP_DMA 0x80 + /* * vm_ops not present page codes for shared memory. * --- ./include/asm-i386/dma.h.~1~ Sun Nov 13 12:46:34 1994 +++ ./include/asm-i386/dma.h Sun Nov 13 12:54:15 1994 @@ -67,6 +67,9 @@ #define MAX_DMA_CHANNELS 8 +/* The maximum address that we can perform a DMA transfer to on this platform */ +#define MAX_DMA_ADDRESS 0xffffff + /* 8237 DMA controllers */ #define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */ #define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */ --- ./drivers/scsi/ChangeLog.~1~ Sun Nov 13 12:48:57 1994 +++ ./drivers/scsi/ChangeLog Mon Nov 14 21:47:44 1994 @@ -1,145 +1,158 @@ -Tue Aug 2 11:29:14 1994 Eric Youngdale (eric@esp22) +Mon Nov 14 21:43:28 1994 Eric Youngdale (eric@andante) - * Linux 1.1.38 released. + Got loadable low level scsi fully working with scsi_debug. Next + step - try it on a live system with the 1542 driver. - Lots of changes in 1.1.38. All from Drew unless otherwise noted. + * sd.c, sr.c, st.c: Decrement *_template.dev_noticed when we + disconnect a device. - * 53c7,8xx.c: New file from Drew. PCI driver. + * sd.c: When detaching a device, make sure that it is synced + first. Then invalidate the buffers and inodes, and finally clean + up a lot of the pointer and table entries to avoid all confusion. - * 53c7,8xx.h: Likewise. +Sun Oct 30 13:46:20 1994 Eric Youngdale (eric@andante) - * 53c7,8xx.scr: Likewise. + Patches to *finish* support for loadable low level scsi drivers. + In theory it should all work now - I just need to upload the + patches from my laptop and actually try them out. At some + point I need to somehow figure out how to work around the + S?_EXTRA_DEVS limitation, but that will wait until later. Some + devices will be easier than others, I fear. - * 53c8xx_d.h, 53c8xx_u.h, script_asm.pl: Likewise. + * hosts.c: Resize DMA buffer pool when we load a low level driver. + + * scsi.c: Redo scsi_malloc so that instead of using one large chunk + of DMA accessible memory, we use an array of pointers to DMA + accsssible pages. - * scsicam.c: New file from Drew. Read block 0 on the disk and - read the partition table. Attempt to deduce the geometry from - the partition table if possible. Only used by 53c[7,8]xx right - now, but could be used by any device for which we have no way - of identifying the geometry. + * scsi_module.c: Explain the caveat about unchecked_isa_dma. - * sd.c: Use device letters instead of sd%d in a lot of messages. + * sd.c (sd_init): Allow loadable disks. Add SD_EXTRA_DEVS when + sizing rscsi_disks. Do not call sd_init_onedisk if we already have + a capacity for this drive. - * seagate.c: Fix bug that resulted in lockups with some devices. + * sr.c, st.c: Likewise. - * sr.c (sr_open): Return -EROFS, not -EACCES if we attempt to open - device for write. + * sd.c (sd_detect, sd_attach): Allow loadable disk drives. - * hosts.c, Makefile: Update for new driver. + * sr.c, st.c: Likewise. - * NCR5380.c, NCR5380.h, g_NCR5380.h: Update from Drew to support - 53C400 chip. + * sr.c (sr_detach): New function - detach device from tables. - * constants.c: Define CONST_CMND and CONST_MSG. Other minor - cleanups along the way. Improve handling of CONST_MSG. + * st.c (st_detach): Likewise. - * fdomain.c, fdomain.h: New version from Rik Faith. Update to - 5.18. Should now support TMC-3260 PCI card with 18C30 chip. + * sd.c (sd_detach): Likewise. - * pas16.c: Update with new irq initialization. +Wed Oct 26 20:04:13 1994 Eric Youngdale (eric@andante) - * t128.c: Update with minor cleanups. + Patches to add more support for low-level loadable scsi drivers. + Only scsi_debug can be loaded, and the "devices" are accessible only + through the scsi_generics driver. Rest should be relatively easy. + The 1542 driver works as a loadable module if you access the + devices through the sg interface. - * scsi.c (scsi_pid): New variable - gives each command a unique - id. Add Quantum LPS5235S to blacklist. Change in_scan to - in_scan_scsis and make global. + * st.c: Patches from Kai - return more status bits in the MTIOCGET ioctl. - * scsi.h: Add some defines for extended message handling, - INITIATE/RELEASE_RECOVERY. Add a few new fields to support sync - transfers. + * sg.c: Add support for 12 byte commands in the vendor specific group 6 + and 7 commands. - * scsi_ioctl.h: Add ioctl to request synchronous transfers. + * sg.c: Add support for attach/detach as we load and unload low-level drivers + at runtime. + * sg.c, sr.c, sd.c, st.c: Change s?_attach.c to return an int. -Tue Jul 26 21:36:58 1994 Eric Youngdale (eric@esp22) + * sd.c: Add a little idiot checking before we examine rscsi_disks[0], + and prevent kernel mode segfault.(used where we bump read-ahead if sg capable) - * Linux 1.1.37 released. + * Throughout: Change info function to accept Scsi_Host * argument. Thus we + can return information that is specific to the host adapter. - * aha1542.c: Always call aha1542_mbenable, use new udelay - mechanism so we do not wait a long time if the board does not - implement this command. + * All low-level drivers: Add NULL in initializers for host template - holds + usage count used in loadable modules. - * g_NCR5380.c: Remove #include and #if - defined(CONFIG_SCSI_*). + * hosts.h: Add cmd_per_lun in Scsi_Host structure. - * seagate.c: Likewise. + * hosts.c: Initialize cmd_per_lun in Scsi_Host structure from host template. - Next round of changes to support loadable modules. Getting closer - now, still not possible to do anything remotely usable. + * scsi.c: Initialize SCpnt->timeout to 0 when we generate command structures. + Only build command structures for which SDpnt->attached != 0. - hosts.c: Create a linked list of detected high level devices. - (scsi_register_device): New function to insert into this list. - (scsi_init): Call scsi_register_device for each of the known high - level drivers. + * scsi.c (scsi_init_free): Use kfree if ptr > scsi_init_memory_start, not + loadable_module_flag. - hosts.h: Add prototype for linked list header. Add structure - definition for device template structure which defines the linked - list. + * scsi.c (request_queueable): Change panic messages to print correct function name. - scsi.c: (scan_scsis): Use linked list instead of knowledge about - existing high level device drivers. - (scsi_dev_init): Use init functions for drivers on linked list - instead of explicit list to initialize and attach devices to high - level drivers. + * scsi.c (scan_scsis): Make global, not static. If we are running after system + is booted, do not use busy waiting - use mutex instead. - scsi.h: Add new field "attached" to scsi_device - count of number - of high level devices attached. + * scsi.c (scan_scsis_done): If request.sem is set, then wake up process + that is waiting. - sd.c, sr.c, sg.c, st.c: Adjust init/attach functions to use new - scheme. + * Makefile: Add support for loadable low-level drivers. -Sat Jul 23 13:03:17 1994 Eric Youngdale (eric@esp22) + * pas16.c: Remove redundant pas16_info function. Upper level code will use + text string from host template instead. - * Linux 1.1.35 released. + * aha1740.c: Likewise. - * ultrastor.c: Change constraint on asm() operand so that it works - with gcc 2.6.0. + * aha152x.c: Likewise. -Thu Jul 21 10:37:39 1994 Eric Youngdale (eric@esp22) + * NCR53c7,8xx.c: Likewise (who named this damn file, anyway?). - * Linux 1.1.33 released. + * aha1542.c: Likewise. - * sr.c(sr_open): Do not allow opens with write access. + * t128.c: Likewise. -Mon Jul 18 09:51:22 1994 1994 Eric Youngdale (eric@esp22) + * wd7000.c: Likewise. - * Linux 1.1.31 released. + * aha1542.c: Add support for command line boot options to override I/O port, + buson/off, and dma speed. - * sd.c: Increase SD_TIMEOUT from 300 to 600. + * hosts.c: Add functions for loading and unloading a host adapter template. - * sr.c: Remove stray task_struct* variable that was no longer - used. + * scsi_debug.c: Add support for being loaded as a loadable module. Fake 3 devices + (disk, cdrom and tape). - * sr_ioctl.c: Fix typo in up() call. + * hosts.h: Add macros S?_EXTRA_DEVS. -Sun Jul 17 16:25:29 1994 Eric Youngdale (eric@esp22) - * Linux 1.1.30 released. +Sun Oct 29 20:57:36 1994 Eric Youngdale (eric@andante.aib.com) - * scsi.c (scan_scsis): Fix detection of some Toshiba CDROM drives - that report themselves as disk drives. + * Linux 1.1.62 released. - * (Throughout): Use request.sem instead of request.waiting. - Should fix swap problem with fdomain. + * st.[c,h]: Update from Kai Makisara - support filemarks better. -Thu Jul 14 10:51:42 1994 Eric Youngdale (eric@esp22) + * fdomain.c: Add support for v3.5 of bios (v5.20 of driver). +Sun Oct 29 20:57:36 1994 Eric Youngdale (eric@andante.aib.com) - * Linux 1.1.29 released. + * Linux 1.1.60 released. - * scsi.c (scan_scsis): Add new devices to end of linked list, not - to the beginning. + * aha274x*: New files to support new Adaptec cards. - * scsi.h (SCSI_SLEEP): Remove brain dead hack to try and save - the task state before sleeping. + * u14-u34f.c: New version of driver from Dario Ballabio. + + * hosts.c, hosts.h: Add required changes for new drivers. Tue Oct 11 08:47:39 1994 Eric Youngdale (eric@andante) * Linux 1.1.54 released. - * Add third PCI chip id. [Drew] + * Add third PCI chip id. - * buslogic.c: Set BUSLOGIC_CMDLUN back to 1 [Eric]. + * buslogic.h: Set BUSLOGIC_CMDLUN back to 1. + * scsi.c: Always create a Scsi_Device, even if we have no idea + what the actual device is. + + * scsi.h (end_scsi_request): Return SCpnt if there is still + something to be done with this command, otherwise return NULL. + Used to fix race condition. + + * sd.c, sr.c: Use new end_scsi_request. + + * ultrastor.c: Fix __asm__ directive so that it works with new + GCC. + Sun Oct 9 20:23:14 1994 Eric Youngdale (eric@andante) * Linux 1.1.53 released. @@ -152,7 +165,7 @@ * Linux 1.1.51 released. * aha152x.c: Add support for disabling the parity check. Update - to version 1.4. [Juergen]. + to version 1.4. * seagate.c: Tweak debugging message. @@ -160,7 +173,7 @@ * Linux 1.1.50 released. - * aha152x.c: Add eb800 for Vtech Platinum SMP boards. [Juergen]. + * aha152x.c: Add eb800 for Vtech Platinum SMP boards. * scsi.c: Add Quantum PD1225S to blacklist. @@ -190,7 +203,7 @@ * constants.h: Add prototype for print_Scsi_Cmnd. * pas16.c: Some more minor tweaks. Test for Mediavision board. - Allow for disks > 1Gb. [Drew??] + Allow for disks > 1Gb. * sr.c: Set SCpnt->transfersize. @@ -218,10 +231,10 @@ * Linux 1.1.43 released. - * Throughout: Spelling cleanups. [??] + * Throughout: Spelling cleanups. * aha152x.c, NCR53*.c, fdomain.c, g_NCR5380.c, pas16.c, seagate.c, - t128.c: Use request_irq, not irqaction. [??] + t128.c: Use request_irq, not irqaction. * aha1542.c: Move test for shost before we start to use shost. @@ -240,7 +253,7 @@ for. * ultrastor.c: Tweak some __asm__ directives so that it works - with newer compilers. [??] + with newer compilers. Sat Aug 6 21:29:36 1994 Eric Youngdale (eric@andante) @@ -265,7 +278,7 @@ * st.c: Initialize STp->device. - * seagate.c: Fix bug. [Drew] + * seagate.c: Fix bug. Thu Aug 4 08:47:27 1994 Eric Youngdale (eric@andante) @@ -274,6 +287,140 @@ * Makefile: Fix typo in NCR53C7xx. * st.c: Print correct number for device. + +Tue Aug 2 11:29:14 1994 Eric Youngdale (eric@esp22) + + * Linux 1.1.38 released. + + Lots of changes in 1.1.38. All from Drew unless otherwise noted. + + * 53c7,8xx.c: New file from Drew. PCI driver. + + * 53c7,8xx.h: Likewise. + + * 53c7,8xx.scr: Likewise. + + * 53c8xx_d.h, 53c8xx_u.h, script_asm.pl: Likewise. + + * scsicam.c: New file from Drew. Read block 0 on the disk and + read the partition table. Attempt to deduce the geometry from + the partition table if possible. Only used by 53c[7,8]xx right + now, but could be used by any device for which we have no way + of identifying the geometry. + + * sd.c: Use device letters instead of sd%d in a lot of messages. + + * seagate.c: Fix bug that resulted in lockups with some devices. + + * sr.c (sr_open): Return -EROFS, not -EACCES if we attempt to open + device for write. + + * hosts.c, Makefile: Update for new driver. + + * NCR5380.c, NCR5380.h, g_NCR5380.h: Update from Drew to support + 53C400 chip. + + * constants.c: Define CONST_CMND and CONST_MSG. Other minor + cleanups along the way. Improve handling of CONST_MSG. + + * fdomain.c, fdomain.h: New version from Rik Faith. Update to + 5.18. Should now support TMC-3260 PCI card with 18C30 chip. + + * pas16.c: Update with new irq initialization. + + * t128.c: Update with minor cleanups. + + * scsi.c (scsi_pid): New variable - gives each command a unique + id. Add Quantum LPS5235S to blacklist. Change in_scan to + in_scan_scsis and make global. + + * scsi.h: Add some defines for extended message handling, + INITIATE/RELEASE_RECOVERY. Add a few new fields to support sync + transfers. + + * scsi_ioctl.h: Add ioctl to request synchronous transfers. + + +Tue Jul 26 21:36:58 1994 Eric Youngdale (eric@esp22) + + * Linux 1.1.37 released. + + * aha1542.c: Always call aha1542_mbenable, use new udelay + mechanism so we do not wait a long time if the board does not + implement this command. + + * g_NCR5380.c: Remove #include and #if + defined(CONFIG_SCSI_*). + + * seagate.c: Likewise. + + Next round of changes to support loadable modules. Getting closer + now, still not possible to do anything remotely usable. + + hosts.c: Create a linked list of detected high level devices. + (scsi_register_device): New function to insert into this list. + (scsi_init): Call scsi_register_device for each of the known high + level drivers. + + hosts.h: Add prototype for linked list header. Add structure + definition for device template structure which defines the linked + list. + + scsi.c: (scan_scsis): Use linked list instead of knowledge about + existing high level device drivers. + (scsi_dev_init): Use init functions for drivers on linked list + instead of explicit list to initialize and attach devices to high + level drivers. + + scsi.h: Add new field "attached" to scsi_device - count of number + of high level devices attached. + + sd.c, sr.c, sg.c, st.c: Adjust init/attach functions to use new + scheme. + +Sat Jul 23 13:03:17 1994 Eric Youngdale (eric@esp22) + + * Linux 1.1.35 released. + + * ultrastor.c: Change constraint on asm() operand so that it works + with gcc 2.6.0. + +Thu Jul 21 10:37:39 1994 Eric Youngdale (eric@esp22) + + * Linux 1.1.33 released. + + * sr.c(sr_open): Do not allow opens with write access. + +Mon Jul 18 09:51:22 1994 1994 Eric Youngdale (eric@esp22) + + * Linux 1.1.31 released. + + * sd.c: Increase SD_TIMEOUT from 300 to 600. + + * sr.c: Remove stray task_struct* variable that was no longer + used. + + * sr_ioctl.c: Fix typo in up() call. + +Sun Jul 17 16:25:29 1994 Eric Youngdale (eric@esp22) + + * Linux 1.1.30 released. + + * scsi.c (scan_scsis): Fix detection of some Toshiba CDROM drives + that report themselves as disk drives. + + * (Throughout): Use request.sem instead of request.waiting. + Should fix swap problem with fdomain. + +Thu Jul 14 10:51:42 1994 Eric Youngdale (eric@esp22) + + * Linux 1.1.29 released. + + * scsi.c (scan_scsis): Add new devices to end of linked list, not + to the beginning. + + * scsi.h (SCSI_SLEEP): Remove brain dead hack to try and save + the task state before sleeping. Sat Jul 9 15:01:03 1994 Eric Youngdale (eric@esp22) --- ./drivers/scsi/u14-34f.h.~1~ Sun Nov 13 12:49:23 1994 +++ ./drivers/scsi/u14-34f.h Sun Nov 13 13:47:08 1994 @@ -15,6 +15,7 @@ #define ULTRASTOR_14_34F { \ NULL, \ + NULL, \ "UltraStor 14F/34F rev. " U14_34F_VERSION " by " \ "Dario_Ballabio@milano.europe.dg.com.",\ u14_34f_detect, \ --- ./drivers/scsi/wd7000.c.~1~ Sun Nov 13 12:46:35 1994 +++ ./drivers/scsi/wd7000.c Sun Nov 13 12:54:15 1994 @@ -900,7 +900,7 @@ register short cdblen; Adapter *host = (Adapter *) SCpnt->host->hostdata; - cdblen = COMMAND_SIZE(cdb[0]); + cdblen = SCpnt->cmd_len; idlun = ((SCpnt->target << 5) & 0xe0) | (SCpnt->lun & 7); SCpnt->scsi_done = done; SCpnt->SCp.phase = 1; @@ -1203,18 +1203,6 @@ int wd7000_reset(Scsi_Cmnd * SCpnt) { return SCSI_RESET_PUNT; -} - - -/* - * The info routine in the WD7000 structure isn't per-adapter, so it can't - * really return any useful information about an adapter. Because of this, - * I'm no longer using it to return rev. level. - */ -const char *wd7000_info(void) -{ - static char info[] = "Western Digital WD-7000"; - return info; } --- ./drivers/scsi/wd7000.h.~1~ Sun Nov 13 12:46:35 1994 +++ ./drivers/scsi/wd7000.h Sun Nov 13 12:54:15 1994 @@ -16,7 +16,6 @@ int wd7000_command(Scsi_Cmnd *); int wd7000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int wd7000_abort(Scsi_Cmnd *); -const char *wd7000_info(void); int wd7000_reset(Scsi_Cmnd *); int wd7000_biosparam(Disk *, int, int*); @@ -38,11 +37,11 @@ #define WD7000_Q 16 #define WD7000_SG 16 -#define WD7000 { NULL, \ +#define WD7000 { NULL, NULL, \ "Western Digital WD-7000", \ wd7000_detect, \ NULL, \ - wd7000_info, \ + NULL, \ wd7000_command, \ wd7000_queuecommand, \ wd7000_abort, \ --- ./drivers/scsi/ultrastor.h.~1~ Sun Nov 13 12:46:35 1994 +++ ./drivers/scsi/ultrastor.h Sun Nov 13 12:54:15 1994 @@ -14,7 +14,7 @@ #define _ULTRASTOR_H int ultrastor_detect(Scsi_Host_Template *); -const char *ultrastor_info(void); +const char *ultrastor_info(struct Scsi_Host * shpnt); int ultrastor_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int ultrastor_abort(Scsi_Cmnd *); int ultrastor_reset(Scsi_Cmnd *); @@ -29,8 +29,8 @@ #define ULTRASTOR_24F_PORT 0xC80 -#define ULTRASTOR_14F { NULL, /* Ptr for modules*/ \ - "UltraStor 14F/24F/34F", \ +#define ULTRASTOR_14F { NULL, NULL, /* Ptr for modules*/ \ + NULL, \ ultrastor_detect, \ NULL, /* Release */ \ ultrastor_info, \ --- ./drivers/scsi/ultrastor.c.~1~ Sun Nov 13 12:46:35 1994 +++ ./drivers/scsi/ultrastor.c Sun Nov 13 12:54:16 1994 @@ -620,7 +620,7 @@ return ultrastor_14f_detect(tpnt) || ultrastor_24f_detect(tpnt); } -const char *ultrastor_info(void) +const char *ultrastor_info(struct Scsi_Host * shpnt) { static char buf[64]; @@ -714,7 +714,7 @@ my_mscp->command_link = 0; /*???*/ my_mscp->scsi_command_link_id = 0; /*???*/ my_mscp->length_of_sense_byte = sizeof SCpnt->sense_buffer; - my_mscp->length_of_scsi_cdbs = COMMAND_SIZE(*(unsigned char *)SCpnt->cmnd); + my_mscp->length_of_scsi_cdbs = SCpnt->cmd_len; memcpy(my_mscp->scsi_cdbs, SCpnt->cmnd, my_mscp->length_of_scsi_cdbs); my_mscp->adapter_status = 0; my_mscp->target_status = 0; --- ./drivers/scsi/t128.h.~1~ Sun Nov 13 12:46:35 1994 +++ ./drivers/scsi/t128.h Sun Nov 13 12:54:16 1994 @@ -94,7 +94,6 @@ int t128_abort(Scsi_Cmnd *); int t128_biosparam(Disk *, int, int*); int t128_detect(Scsi_Host_Template *); -const char *t128_info(void); int t128_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int t128_reset(Scsi_Cmnd *); @@ -118,8 +117,8 @@ #ifdef HOSTS_C -#define TRANTOR_T128 {NULL, "Trantor T128/T128F/T228", t128_detect, NULL, \ - t128_info, \ +#define TRANTOR_T128 {NULL, NULL, "Trantor T128/T128F/T228", t128_detect, NULL, \ + NULL, \ NULL, t128_queue_command, t128_abort, t128_reset, NULL, \ t128_biosparam, \ /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL, \ --- ./drivers/scsi/t128.c.~1~ Sun Nov 13 12:46:35 1994 +++ ./drivers/scsi/t128.c Sun Nov 13 12:54:16 1994 @@ -385,17 +385,4 @@ return 0; } -/* - * Function : const char *t128_info(void) - * - * Purpose : provide further information about this driver. - * - * Returns : an empty string. - */ - -const char *t128_info (void) { - static const char string[]=""; - return string; -} - #include "NCR5380.c" --- ./drivers/scsi/hosts.h.~1~ Sun Nov 13 12:46:36 1994 +++ ./drivers/scsi/hosts.h Sun Nov 13 14:01:10 1994 @@ -52,6 +52,9 @@ /* Used with loadable modules so we can construct a linked list. */ struct SHT * next; + /* Used with loadable modules so that we know when it is safe to unload */ + int * usage_count; + /* The name pointer is a pointer to the name of the SCSI device detected. @@ -77,14 +80,18 @@ int (* detect)(struct SHT *); - /* Used with loadable modules to unload the host structures */ + /* Used with loadable modules to unload the host structures. Note: + there is a default action built into the modules code which may + be sufficient for most host adapters. Thus you may not have to supply + this at all. */ int (*release)(struct Scsi_Host *); /* The info function will return whatever useful - information the developer sees fit. + information the developer sees fit. If not provided, then + the name field will be used instead. */ - const char *(* info)(void); + const char *(* info)(struct Scsi_Host *); /* The command function takes a target, a command (this is a SCSI @@ -235,6 +242,7 @@ /* These parameters should be set by the detect routine */ unsigned char *base; short unsigned int io_port; + unsigned char n_io_port; unsigned char irq; unsigned char dma_channel; /* @@ -243,6 +251,7 @@ */ int this_id; + short cmd_per_lun; short unsigned int sg_tablesize; unsigned unchecked_isa_dma:1; /* @@ -268,15 +277,28 @@ looks normal. Also, it makes it possible to use the same code for a loadable module. */ -extern void * scsi_init_malloc(unsigned int size); +extern void * scsi_init_malloc(unsigned int size, int priority); extern void scsi_init_free(char * ptr, unsigned int size); +void scan_scsis (struct Scsi_Host * shpnt); + +extern int next_scsi_host; extern int scsi_loadable_module_flag; unsigned int scsi_init(void); extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int j); extern void scsi_unregister(struct Scsi_Host * i); +/* These are used by loadable modules */ +extern int scsi_register_module(int, void *); +extern void scsi_unregister_module(int, void *); + +/* The different types of modules that we can load and unload */ +#define MODULE_SCSI_HA 1 +#define MODULE_SCSI_CONST 2 +#define MODULE_SCSI_IOCTL 3 +#define MODULE_SCSI_DEV 4 + #define BLANK_HOST {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} struct Scsi_Device_Template @@ -293,7 +315,7 @@ int (*detect)(Scsi_Device *); /* Returns 1 if we can attach this device */ void (*init)(void); /* Sizes arrays based upon number of devices detected */ void (*finish)(void); /* Perform initialization after attachment */ - void (*attach)(Scsi_Device *); /* Attach devices to arrays */ + int (*attach)(Scsi_Device *); /* Attach devices to arrays */ void (*detach)(Scsi_Device *); }; @@ -303,5 +325,16 @@ extern struct Scsi_Device_Template sg_template; int scsi_register_device(struct Scsi_Device_Template * sdpnt); + +/* + * This is an ugly hack. If we expect to be able to load devices at run time, we need + * to leave extra room in some of the data structures. Doing a realloc to enlarge + * the structures would be riddled with race conditions, so until a better solution + * is discovered, we use this crude approach + */ +#define SD_EXTRA_DEVS 2 +#define ST_EXTRA_DEVS 2 +#define SR_EXTRA_DEVS 2 +#define SG_EXTRA_DEVS (SD_EXTRA_DEVS + SR_EXTRA_DEVS + ST_EXTRA_DEVS) #endif --- ./drivers/scsi/seagate.h.~1~ Sun Nov 13 12:46:36 1994 +++ ./drivers/scsi/seagate.h Sun Nov 13 12:54:16 1994 @@ -17,7 +17,7 @@ int seagate_st0x_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int seagate_st0x_abort(Scsi_Cmnd *); -const char *seagate_st0x_info(void); +const char *seagate_st0x_info(struct Scsi_Host *); int seagate_st0x_reset(Scsi_Cmnd *); #ifndef NULL @@ -26,7 +26,7 @@ int seagate_st0x_biosparam(Disk *, int, int*); -#define SEAGATE_ST0X {NULL, "Seagate ST-01/ST-02", seagate_st0x_detect, \ +#define SEAGATE_ST0X {NULL, NULL, NULL, seagate_st0x_detect, \ NULL, \ seagate_st0x_info, seagate_st0x_command, \ seagate_st0x_queue_command, seagate_st0x_abort, \ --- ./drivers/scsi/hosts.c.~1~ Sun Nov 13 12:49:21 1994 +++ ./drivers/scsi/hosts.c Sun Nov 13 14:00:55 1994 @@ -87,6 +87,10 @@ #include "wd7000.h" #endif +#ifdef CONFIG_SCSI_EATA +#include "eata.h" +#endif + #ifdef CONFIG_SCSI_DEBUG #include "scsi_debug.h" #endif @@ -170,6 +174,9 @@ #ifdef CONFIG_SCSI_7000FASST WD7000, #endif +#ifdef CONFIG_SCSI_EATA + EATA, +#endif #ifdef CONFIG_SCSI_DEBUG SCSI_DEBUG, #endif @@ -185,8 +192,9 @@ struct Scsi_Device_Template * scsi_devicelist; int max_scsi_hosts = 0; -static int next_host = 0; +int next_scsi_host = 0; + void scsi_unregister(struct Scsi_Host * sh){ struct Scsi_Host * shpnt; @@ -201,7 +209,7 @@ while(shpnt->next != sh) shpnt = shpnt->next; shpnt->next = shpnt->next->next; }; - next_host--; + next_scsi_host--; scsi_init_free((char *) sh, sizeof(struct Scsi_Host) + j); } @@ -211,16 +219,20 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){ struct Scsi_Host * retval, *shpnt; - retval = (struct Scsi_Host *)scsi_init_malloc(sizeof(struct Scsi_Host) + j); + retval = (struct Scsi_Host *)scsi_init_malloc(sizeof(struct Scsi_Host) + j, + (tpnt->unchecked_isa_dma && j ? GFP_DMA : 0) | GFP_ATOMIC); retval->host_busy = 0; if(j > 0xffff) panic("Too many extra bytes requested\n"); retval->extra_bytes = j; retval->loaded_as_module = scsi_loadable_module_flag; - retval->host_no = next_host++; + retval->host_no = next_scsi_host++; retval->host_queue = NULL; retval->host_wait = NULL; retval->last_reset = 0; retval->irq = 0; + retval->dma_channel = 0xff; + retval->io_port = 0; + retval->n_io_port = 0; retval->hostt = tpnt; retval->next = NULL; #ifdef DEBUG @@ -231,6 +243,7 @@ if need be */ retval->this_id = tpnt->this_id; retval->sg_tablesize = tpnt->sg_tablesize; + retval->cmd_per_lun = tpnt->cmd_per_lun; retval->unchecked_isa_dma = tpnt->unchecked_isa_dma; if(!scsi_hostlist) @@ -257,9 +270,10 @@ unsigned int scsi_init() { static int called = 0; - int i, j, count, pcount; + int i, pcount; Scsi_Host_Template * tpnt; - count = 0; + struct Scsi_Host * shpnt; + const char * name; if(called) return 0; @@ -271,7 +285,7 @@ * "inactive" - where as 0 will indicate a time out condition. */ - pcount = next_host; + pcount = next_scsi_host; if ((tpnt->detect) && (tpnt->present = tpnt->detect(tpnt))) @@ -278,7 +292,7 @@ { /* The only time this should come up is when people use some kind of patched driver of some kind or another. */ - if(pcount == next_host) { + if(pcount == next_scsi_host) { if(tpnt->present > 1) panic("Failure to register low-level scsi driver"); /* The low-level driver failed to register a driver. We @@ -287,12 +301,20 @@ }; tpnt->next = scsi_hosts; scsi_hosts = tpnt; - for(j = 0; j < tpnt->present; j++) - printk ("scsi%d : %s\n", - count++, tpnt->name); } } - printk ("scsi : %d hosts.\n", count); + for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) + { + if(shpnt->hostt->info) + name = shpnt->hostt->info(shpnt); + else + name = shpnt->hostt->name; + printk ("scsi%d : %s\n", /* And print a little message */ + shpnt->host_no, name); + } + + printk ("scsi : %d hosts.\n", next_scsi_host); + /* Now attach the high level drivers */ #ifdef CONFIG_BLK_DEV_SD @@ -308,6 +330,7 @@ scsi_register_device(&sg_template); #endif - max_scsi_hosts = count; + max_scsi_hosts = next_scsi_host; return 0; } + --- ./drivers/scsi/seagate.c.~1~ Sun Nov 13 12:46:36 1994 +++ ./drivers/scsi/seagate.c Sun Nov 13 12:54:16 1994 @@ -362,7 +362,7 @@ } } -const char *seagate_st0x_info(void) { +const char *seagate_st0x_info(struct Scsi_Host * shpnt) { static char buffer[256]; sprintf(buffer, "scsi%d : %s at irq %d address %p options :" #ifdef ARBITRATE @@ -525,7 +525,7 @@ * Set linked command bit in control field of SCSI command. */ - current_cmnd[COMMAND_SIZE(current_cmnd[0])] |= 0x01; + current_cmnd[SCpnt->cmd_len] |= 0x01; if (linked_connected) { #if (DEBUG & DEBUG_LINKED) printk("scsi%d : using linked commands, current I_T_L nexus is ", --- ./drivers/scsi/scsi_debug.h.~1~ Sun Nov 13 12:46:36 1994 +++ ./drivers/scsi/scsi_debug.h Sun Nov 13 12:54:16 1994 @@ -7,7 +7,6 @@ int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int scsi_debug_abort(Scsi_Cmnd *); int scsi_debug_biosparam(Disk *, int, int[]); -const char *scsi_debug_info(void); int scsi_debug_reset(Scsi_Cmnd *); #ifndef NULL @@ -16,8 +15,8 @@ #define SCSI_DEBUG_MAILBOXES 8 -#define SCSI_DEBUG {NULL, "SCSI DEBUG", scsi_debug_detect, NULL, \ - scsi_debug_info, scsi_debug_command, \ +#define SCSI_DEBUG {NULL, NULL, "SCSI DEBUG", scsi_debug_detect, NULL, \ + NULL, scsi_debug_command, \ scsi_debug_queuecommand, \ scsi_debug_abort, \ scsi_debug_reset, \ --- ./drivers/scsi/scsi_debug.c.~1~ Sun Nov 13 12:46:36 1994 +++ ./drivers/scsi/scsi_debug.c Mon Nov 14 21:15:19 1994 @@ -31,7 +31,7 @@ #define IMMEDIATE /* Skip some consistency checking. Good for benchmarking */ -#define SPEEDY +/* #define SPEEDY */ /* Number of real scsi disks that will be detected ahead of time */ static int NR_REAL=-1; @@ -56,11 +56,10 @@ #define DEB(x) #endif -#ifdef SPEEDY #define VERIFY1_DEBUG(RW) 1 #define VERIFY_DEBUG(RW) 1 -#else +#if 0 #define VERIFY1_DEBUG(RW) \ if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");}; \ start = 0; \ @@ -100,7 +99,7 @@ #endif static volatile void (*do_done[SCSI_DEBUG_MAILBOXES])(Scsi_Cmnd *) = {NULL, }; -extern void scsi_debug_interrupt(); +extern void scsi_debug_interrupt(void); volatile Scsi_Cmnd * SCint[SCSI_DEBUG_MAILBOXES] = {NULL,}; static volatile unsigned int timeout[SCSI_DEBUG_MAILBOXES] ={0,}; @@ -149,7 +148,9 @@ }; printk("\n"); #endif +#ifndef MODULE printk("DMA free %d sectors.\n", dma_free_sectors); +#endif } int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) @@ -163,7 +164,7 @@ int scsi_debug_errsts; struct scatterlist * sgpnt; int target = SCpnt->target; - int bufflen = SCpnt->request_bufflen; + unsigned int bufflen = SCpnt->request_bufflen; int i; sgcount = 0; sgpnt = NULL; @@ -172,12 +173,15 @@ buff = (unsigned char *) SCpnt->request_buffer; - if(target>=1 || SCpnt->lun != 0) { + if(target>=3 || SCpnt->lun != 0) { SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; }; + printk("Scsi debug target %d lun %d op %d len %d\n", target, SCpnt->lun, + *cmd, SCpnt->cmd_len); + switch(*cmd){ case REQUEST_SENSE: printk("Request sense...\n"); @@ -202,13 +206,35 @@ case INQUIRY: printk("Inquiry...(%x %d)\n", buff, bufflen); memset(buff, 0, bufflen); - buff[0] = TYPE_DISK; - buff[1] = 0x80; /* Removable disk */ - buff[2] = 1; - buff[4] = 33 - 5; - memcpy(&buff[8],"Foo Inc",7); - memcpy(&buff[16],"XYZZY",5); - memcpy(&buff[32],"1",1); + switch(target) { + case 0: + buff[0] = TYPE_DISK; + buff[1] = 0x80; /* Removable disk */ + buff[2] = 1; + buff[4] = 33 - 5; + memcpy(&buff[8],"Foo Inc",7); + memcpy(&buff[16],"XYZZY",5); + memcpy(&buff[32],"1",1); + break; + case 1: + buff[0] = TYPE_ROM; + buff[1] = 0x80; /* Removable disk */ + buff[2] = 1; + buff[4] = 33 - 5; + memcpy(&buff[8],"Bar Inc",7); + memcpy(&buff[16],"XYZZY",5); + memcpy(&buff[32],"2",1); + break; + case 2: + buff[0] = TYPE_TAPE; + buff[1] = 0x80; /* Removable disk */ + buff[2] = 1; + buff[4] = 33 - 5; + memcpy(&buff[8],"ABC Inc",7); + memcpy(&buff[16],"XYZZY",5); + memcpy(&buff[32],"2",1); + break; + } scsi_debug_errsts = 0; break; case TEST_UNIT_READY: @@ -569,10 +595,11 @@ return 0; } -const char *scsi_debug_info(void) -{ - static char buffer[] = " "; /* looks nicer without anything here */ - return buffer; -} +#ifdef MODULE +/* Eventually this will go into an include file, but this will be later */ +Scsi_Host_Template driver_template = SCSI_DEBUG; + +#include "scsi_module.c" +#endif --- ./drivers/scsi/aha152x.h.~1~ Sun Nov 13 12:46:37 1994 +++ ./drivers/scsi/aha152x.h Sun Nov 13 12:54:17 1994 @@ -11,7 +11,6 @@ #include int aha152x_detect(Scsi_Host_Template *); -const char *aha152x_info(void); int aha152x_command(Scsi_Cmnd *); int aha152x_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int aha152x_abort(Scsi_Cmnd *); @@ -26,10 +25,11 @@ /* Initial value of Scsi_Host entry */ #define AHA152X { /* next */ NULL, \ + /* usage_count */ NULL, \ /* name */ AHA152X_REVID, \ /* detect */ aha152x_detect, \ /* release */ NULL, \ - /* info */ aha152x_info, \ + /* info */ NULL, \ /* command */ aha152x_command, \ /* queuecommand */ aha152x_queue, \ /* abort */ aha152x_abort, \ --- ./drivers/scsi/pas16.h.~1~ Sun Nov 13 12:46:37 1994 +++ ./drivers/scsi/pas16.h Sun Nov 13 12:54:17 1994 @@ -117,7 +117,6 @@ int pas16_abort(Scsi_Cmnd *); int pas16_biosparam(Disk *, int, int*); int pas16_detect(Scsi_Host_Template *); -const char *pas16_info(void); int pas16_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int pas16_reset(Scsi_Cmnd *); @@ -141,8 +140,8 @@ #ifdef HOSTS_C -#define MV_PAS16 {NULL, "Pro Audio Spectrum-16 SCSI", \ - pas16_detect, NULL, pas16_info, \ +#define MV_PAS16 {NULL, NULL, "Pro Audio Spectrum-16 SCSI", \ + pas16_detect, NULL, NULL, \ NULL, pas16_queue_command, pas16_abort, pas16_reset, NULL, \ pas16_biosparam, \ /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL, \ --- ./drivers/scsi/buslogic.h.~1~ Sun Nov 13 12:46:37 1994 +++ ./drivers/scsi/buslogic.h Sun Nov 13 12:54:17 1994 @@ -15,7 +15,7 @@ int buslogic_detect(Scsi_Host_Template *); int buslogic_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int buslogic_abort(Scsi_Cmnd *); -const char *buslogic_info(void); +const char *buslogic_info(struct Scsi_Host *); int buslogic_reset(Scsi_Cmnd *); int buslogic_biosparam(Disk *, int, int *); @@ -28,8 +28,8 @@ 10/8/94 ERY */ -#define BUSLOGIC { NULL, \ - "BusLogic", \ +#define BUSLOGIC { NULL, NULL, \ + NULL, \ buslogic_detect, \ NULL, \ buslogic_info, \ --- ./drivers/scsi/aha1542.h.~1~ Sun Nov 13 12:46:38 1994 +++ ./drivers/scsi/aha1542.h Sun Nov 13 12:54:17 1994 @@ -69,6 +69,7 @@ #define CMD_EMBOI 0x05 /* Enable MailBox Out Interrupt */ #define CMD_BUSON_TIME 0x07 /* Set Bus-On Time */ #define CMD_BUSOFF_TIME 0x08 /* Set Bus-Off Time */ +#define CMD_DMASPEED 0x09 /* Set AT Bus Transfer Speed */ #define CMD_RETDEVS 0x0a /* Return Installed Devices */ #define CMD_RETCONF 0x0b /* Return Configuration Data */ #define CMD_RETSETUP 0x0d /* Return Setup Data */ @@ -132,7 +133,6 @@ int aha1542_command(Scsi_Cmnd *); int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int aha1542_abort(Scsi_Cmnd *); -const char *aha1542_info(void); int aha1542_reset(Scsi_Cmnd *); int aha1542_biosparam(Disk *, int, int*); @@ -144,11 +144,11 @@ #define NULL 0 #endif -#define AHA1542 { NULL, \ +#define AHA1542 { NULL, NULL, \ "Adaptec 1542", \ aha1542_detect, \ NULL, \ - aha1542_info, \ + NULL, \ aha1542_command, \ aha1542_queuecommand, \ aha1542_abort, \ --- ./drivers/scsi/aha1740.h.~1~ Sun Nov 13 12:46:38 1994 +++ ./drivers/scsi/aha1740.h Sun Nov 13 12:54:17 1994 @@ -156,7 +156,6 @@ int aha1740_command(Scsi_Cmnd *); int aha1740_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int aha1740_abort(Scsi_Cmnd *); -const char *aha1740_info(void); int aha1740_reset(Scsi_Cmnd *); int aha1740_biosparam(Disk *, int, int*); @@ -167,11 +166,11 @@ #define NULL 0 #endif -#define AHA1740 {NULL, \ - "Adaptec 1740", \ +#define AHA1740 {NULL, NULL, \ + "Adaptec 174x (EISA)", \ aha1740_detect, \ NULL, \ - aha1740_info, \ + NULL, \ aha1740_command, \ aha1740_queuecommand, \ aha1740_abort, \ --- ./drivers/scsi/fdomain.h.~1~ Sun Nov 13 12:46:38 1994 +++ ./drivers/scsi/fdomain.h Sun Nov 13 12:54:17 1994 @@ -28,13 +28,13 @@ int fdomain_16x0_detect( Scsi_Host_Template * ); int fdomain_16x0_command( Scsi_Cmnd * ); int fdomain_16x0_abort( Scsi_Cmnd * ); -const char *fdomain_16x0_info( void ); +const char *fdomain_16x0_info( struct Scsi_Host * ); int fdomain_16x0_reset( Scsi_Cmnd * ); int fdomain_16x0_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) ); int fdomain_16x0_biosparam( Disk *, int, int * ); -#define FDOMAIN_16X0 { NULL, \ - "Future Domain TMC-16x0", \ +#define FDOMAIN_16X0 { NULL, NULL, \ + NULL, \ fdomain_16x0_detect, \ NULL, \ fdomain_16x0_info, \ --- ./drivers/scsi/53c7,8xx.h.~1~ Sun Nov 13 12:46:38 1994 +++ ./drivers/scsi/53c7,8xx.h Sun Nov 13 12:54:17 1994 @@ -50,12 +50,11 @@ #include extern int NCR53c7xx_abort(Scsi_Cmnd *); extern int NCR53c7xx_detect(Scsi_Host_Template *tpnt); -extern const char *NCR53c7xx_info(void); extern int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); extern int NCR53c7xx_reset(Scsi_Cmnd *); -#define NCR53c7xx {NULL, "NCR53c{7,8}xx (rel 3)", NCR53c7xx_detect, \ - NULL, NCR53c7xx_info, \ +#define NCR53c7xx {NULL, NULL, "NCR53c{7,8}xx (rel 3)", NCR53c7xx_detect, \ + NULL, NULL, \ NULL, NCR53c7xx_queue_command, NCR53c7xx_abort, NCR53c7xx_reset,\ NULL, scsicam_bios_param, \ /* can queue */ 1, /* id */ 7, 255 /* old SG_ALL */, \ --- ./drivers/scsi/g_NCR5380.h.~1~ Sun Nov 13 12:46:38 1994 +++ ./drivers/scsi/g_NCR5380.h Sun Nov 13 12:54:17 1994 @@ -35,7 +35,6 @@ #ifndef ASM int generic_NCR5380_abort(Scsi_Cmnd *); int generic_NCR5380_detect(Scsi_Host_Template *); -const char *generic_NCR5380_info(void); int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int generic_NCR5380_reset(Scsi_Cmnd *); @@ -54,8 +53,8 @@ #ifdef HOSTS_C -#define GENERIC_NCR5380 {NULL, "Trantor T128/T128F/T228", \ - generic_NCR5380_detect, NULL, generic_NCR5380_info, NULL, \ +#define GENERIC_NCR5380 {NULL, NULL, "Trantor T128/T128F/T228", \ + generic_NCR5380_detect, NULL, NULL, NULL, \ generic_NCR5380_queue_command, generic_NCR5380_abort, \ generic_NCR5380_reset, NULL, \ NULL, /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL, \ --- ./drivers/scsi/aha1542.c.~1~ Sun Nov 13 12:46:39 1994 +++ ./drivers/scsi/aha1542.c Tue Nov 15 20:42:58 1994 @@ -10,6 +10,8 @@ * have the bios enabled to use the aha1542. * Modified by David Gentzel * Don't call request_dma if dma mask is 0 (for BusLogic BT-445S VL-Bus controller). + * Modified by Matti Aarnio + * Accept parameters from LILO cmd-line. -- 1-Oct-94 */ #include @@ -43,10 +45,39 @@ /* The adaptec can be configured for quite a number of addresses, but I generally do not want the card poking around at random. We allow two addresses - this allows people to use the Adaptec with a Midi -card, which also used 0x330 */ +card, which also used 0x330 -- can be overriden with LILO! */ -static unsigned int bases[]={0x330, 0x334}; +#define MAXBOARDS 2 /* Increase this and the sizes of the + arrays below, if you need more.. */ +static unsigned int bases[MAXBOARDS]={0x330, 0x334}; + +/* set by aha1542_setup according to the command line */ +static int setup_called[MAXBOARDS] = {0,0}; +static int setup_buson[MAXBOARDS] = {0,0}; +static int setup_busoff[MAXBOARDS] = {0,0}; +static int setup_dmaspeed[MAXBOARDS] = {-1,-1}; + +static char *setup_str[MAXBOARDS] = {(char *)NULL,(char *)NULL}; + +/* + * LILO params: aha1542=[,,[,]] + * + * Where: is any of the valid AHA addresses: + * 0x130, 0x134, 0x230, 0x234, 0x330, 0x334 + * is the time (in microsecs) that AHA spends on the AT-bus + * when transferring data. 1542A power-on default is 11us, + * valid values are in range: 2..15 (decimal) + * is the time that AHA spends OFF THE BUS after while + * it is transferring data (not to monopolize the bus). + * Power-on default is 4us, valid range: 1..64 microseconds. + * Default is jumper selected (1542A: on the J1), + * but experimenter can alter it with this. + * Valid values: 5, 6, 7, 8, 10 (MB/s) + * Factory default is 5 MB/s. + */ + + /* The DMA-Controller. We need to fool with this because we want to be able to use the aha1542 without having to have the bios enabled */ #define DMA_MODE_REG 0xd6 @@ -253,6 +284,7 @@ /* In case some other card was probing here, reset interrupts */ aha1542_intr_reset(bse); /* reset interrupts, so they don't block */ + outb(SRST|IRST/*|SCRST*/, CONTROL(bse)); i = jiffies + 2; @@ -302,14 +334,6 @@ return 0; /* 0 = not ok */ } -static const char aha_ident[] = "Adaptec 1542"; - -/* What's this little function for? */ -const char *aha1542_info(void) -{ - return aha_ident; -} - /* A "high" level interrupt handler */ static void aha1542_intr_handle(int foo) { @@ -513,7 +537,7 @@ printk("aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen); aha1542_stat(); printk("aha1542_queuecommand: dumping scsi cmd:"); - for (i = 0; i < (COMMAND_SIZE(*cmd)); i++) printk("%02x ", cmd[i]); + for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]); printk("\n"); if (*cmd == WRITE_10 || *cmd == WRITE_6) return 0; /* we are still testing, so *don't* write */ @@ -549,7 +573,7 @@ memset(&ccb[mbo], 0, sizeof(struct ccb)); - ccb[mbo].cdblen = COMMAND_SIZE(*cmd); /* SCSI Command Descriptor Block Length */ + ccb[mbo].cdblen = SCpnt->cmd_len; direction = 0; if (*cmd == READ_10 || *cmd == READ_6) @@ -590,7 +614,6 @@ any2scsi(cptr[i].datalen, sgpnt[i].length); }; any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain)); - if(((unsigned int) buff & 0xff000000)) goto baddma; any2scsi(ccb[mbo].dataptr, cptr); #ifdef DEBUG printk("cptr %x: ",cptr); @@ -601,6 +624,7 @@ ccb[mbo].op = 0; /* SCSI Initiator Command */ SCpnt->host_scribble = NULL; any2scsi(ccb[mbo].datalen, bufflen); + if(((unsigned int) buff & 0xff000000)) goto baddma; any2scsi(ccb[mbo].dataptr, buff); }; ccb[mbo].idlun = (target&7)<<5 | direction | (lun & 7); /*SCSI Target Id*/ @@ -813,6 +837,66 @@ return 0; } +/* called from init/main.c */ +void aha1542_setup( char *str, int *ints) +{ + char *ahausage = "aha1542: usage: aha1542=[,,[,]]\n"; + static int setup_idx = 0; + int setup_portbase; + + if(setup_idx >= MAXBOARDS) + { + printk("aha1542: aha1542_setup called too many times! Bad LILO params ?\n"); + printk(" Entryline 1: %s\n",setup_str[0]); + printk(" Entryline 2: %s\n",setup_str[1]); + printk(" This line: %s\n",str); + return; + } + if (ints[0] < 1 || ints[0] > 4) + { + printk("aha1542: %s\n", str ); + printk(ahausage); + printk("aha1542: Wrong parameters may cause system malfunction.. We try anyway..\n"); + } + + setup_called[setup_idx]=ints[0]; + setup_str[setup_idx]=str; + + setup_portbase = ints[0] >= 1 ? ints[1] : 0; /* Preserve the default value.. */ + setup_buson [setup_idx] = ints[0] >= 2 ? ints[2] : 7; + setup_busoff [setup_idx] = ints[0] >= 3 ? ints[3] : 5; + if (ints[0] >= 4) { + int atbt = -1; + switch (ints[4]) { + case 5: + atbt = 0x00; + break; + case 6: + atbt = 0x04; + break; + case 7: + atbt = 0x01; + break; + case 8: + atbt = 0x02; + break; + case 10: + atbt = 0x03; + break; + default: + printk("aha1542: %s\n", str ); + printk(ahausage); + printk("aha1542: Valid values for DMASPEED are 5-8, 10 MB/s. Using jumper defaults.\n"); + break; + } + setup_dmaspeed[setup_idx] = atbt; + } + + if (setup_portbase != 0) + bases[setup_idx] = setup_portbase; + + ++setup_idx; +} /* return non-zero on detection */ int aha1542_detect(Scsi_Host_Template * tpnt) @@ -826,12 +910,19 @@ int indx; DEB(printk("aha1542_detect: \n")); - + for(indx = 0; indx < sizeof(bases)/sizeof(bases[0]); indx++) - if(!check_region(bases[indx], 4)) { + if(bases[indx] != 0 && !check_region(bases[indx], 4)) { shpnt = scsi_register(tpnt, sizeof(struct aha1542_hostdata)); + /* For now we do this - until kmalloc is more intelligent + we are resigned to stupid hacks like this */ + if ((unsigned int) shpnt > 0xffffff) { + printk("Invalid address for shpnt with 1542.\n"); + goto unregister; + } + if(!aha1542_test_port(bases[indx], shpnt)) goto unregister; @@ -841,6 +932,12 @@ { unchar oncmd[] = {CMD_BUSON_TIME, 7}; unchar offcmd[] = {CMD_BUSOFF_TIME, 5}; + + if(setup_called[indx]) + { + oncmd[1] = setup_buson[indx]; + offcmd[1] = setup_busoff[indx]; + } aha1542_intr_reset(base_io); aha1542_out(base_io, oncmd, 2); @@ -848,6 +945,14 @@ aha1542_intr_reset(base_io); aha1542_out(base_io, offcmd, 2); WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0); + if (setup_dmaspeed[indx] >= 0) + { + unchar dmacmd[] = {CMD_DMASPEED, 0}; + dmacmd[1] = setup_dmaspeed[indx]; + aha1542_intr_reset(base_io); + aha1542_out(base_io, dmacmd, 2); + WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0); + } while (0) { fail: printk("aha1542_detect: setting bus on/off-time failed\n"); @@ -889,6 +994,7 @@ } aha_host[irq_level - 9] = shpnt; shpnt->io_port = base_io; + shpnt->n_io_port = 4; /* Number of bytes of I/O space used */ shpnt->dma_channel = dma_chan; shpnt->irq = irq_level; HOSTDATA(shpnt)->bios_translation = trans; @@ -1120,3 +1226,12 @@ /* if (ip[2] >= 1024) ip[2] = 1024; */ return 0; } + + +#ifdef MODULE +/* Eventually this will go into an include file, but this will be later */ +Scsi_Host_Template driver_template = AHA1542; + +#include "scsi_module.c" +#endif + --- ./drivers/scsi/53c7,8xx.c.~1~ Sun Nov 13 12:46:40 1994 +++ ./drivers/scsi/53c7,8xx.c Sun Nov 13 12:54:18 1994 @@ -2424,7 +2424,7 @@ tmp->select[0] = IDENTIFY (0, cmd->lun); #endif patch_dsa_32(tmp->dsa, dsa_msgout, 1, tmp->select); - patch_dsa_32(tmp->dsa, dsa_cmdout, 0, COMMAND_SIZE(cmd->cmnd[0])); + patch_dsa_32(tmp->dsa, dsa_cmdout, 0, cmd->cmd_len); patch_dsa_32(tmp->dsa, dsa_cmdout, 1, cmd->cmnd); patch_dsa_32(tmp->dsa, dsa_dataout, 0, cmd_dataout ? cmd_dataout : hostdata->script + hostdata->E_other_transfer / @@ -3740,10 +3740,6 @@ printk ("scsi%d : DANGER : NCR53c7xx_reset is NOP\n", cmd->host->host_no); return SCSI_RESET_SNOOZE; -} - -const char *NCR53c7xx_info (void) { - return("More info here\n"); } /* --- ./drivers/scsi/aha152x.c.~1~ Sun Nov 13 12:46:40 1994 +++ ./drivers/scsi/aha152x.c Sun Nov 13 12:54:18 1994 @@ -258,8 +258,6 @@ #define P_BUSFREE 1 #define P_PARITY 2 -static char *aha152x_id = AHA152X_REVID; - static int port_base = 0; static int this_host = 0; static int can_disconnect = 0; @@ -703,14 +701,6 @@ return 1; } -/* - * return the name of the thing - */ -const char *aha152x_info(void) -{ - return(aha152x_id); -} - /* * Queue a command and setup interrupts for a free bus. */ @@ -1504,13 +1494,13 @@ #if defined(DEBUG_CMD) printk("DFIFOEMP, outsw (%d words), ", - COMMAND_SIZE(current_SC->cmnd[0])>>1); + current_SC->cmd_len >> 1); disp_ports(); #endif outsw( DATAPORT, ¤t_SC->cmnd, - COMMAND_SIZE(current_SC->cmnd[0])>>1 ); + current_SC->cmd_len >> 1); #if defined(DEBUG_CMD) printk("FCNT=%d, STCNT=%d, ", GETPORT(FIFOSTAT), GETSTCNT() ); @@ -1531,7 +1521,7 @@ #if defined(DEBUG_CMD) || defined(DEBUG_INTR) printk("sent %d/%d command bytes, ", GETSTCNT(), - COMMAND_SIZE(current_SC->cmnd[0])); + current_SC->cmd_len); #endif } @@ -2359,7 +2349,7 @@ printk("0x%08x: target=%d; lun=%d; cmnd=( ", (unsigned int) ptr, ptr->target, ptr->lun); - for(i=0; icmnd[0]); i++) + for(i=0; icmd_len; i++) printk("%02x ", ptr->cmnd[i]); printk("); residual=%d; buffers=%d; phase |", --- ./drivers/scsi/aha1740.c.~1~ Sun Nov 13 12:46:40 1994 +++ ./drivers/scsi/aha1740.c Sun Nov 13 12:54:19 1994 @@ -163,12 +163,6 @@ return 0; } -const char *aha1740_info(void) -{ - static char buffer[] = "Adaptec 174x (EISA)"; - return buffer; -} - /* A "high" level interrupt handler */ void aha1740_intr_handle(int foo) { @@ -267,7 +261,7 @@ i = -1; printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen); printk("scsi cmd:"); - for (i = 0; i < (COMMAND_SIZE(*cmd)); i++) printk("%02x ", cmd[i]); + for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]); printk("\n"); #endif @@ -296,7 +290,7 @@ printk("Sending command (%d %x)...",ecbno, done); #endif - ecb[ecbno].cdblen = COMMAND_SIZE(*cmd); /* SCSI Command Descriptor Block Length */ + ecb[ecbno].cdblen = SCpnt->cmd_len; /* SCSI Command Descriptor Block Length */ direction = 0; if (*cmd == READ_10 || *cmd == READ_6) --- ./drivers/scsi/pas16.c.~1~ Sun Nov 13 12:46:40 1994 +++ ./drivers/scsi/pas16.c Sun Nov 13 12:54:19 1994 @@ -525,17 +525,4 @@ return 0; } -/* - * Function : const char *pas16_info(void) - * - * Purpose : provide further information about this driver. - * - * Returns : an empty string. - */ - -const char *pas16_info (void) { - static const char string[]=""; - return string; -} - #include "NCR5380.c" --- ./drivers/scsi/Makefile.~1~ Sun Nov 13 12:49:18 1994 +++ ./drivers/scsi/Makefile Tue Nov 15 11:35:15 1994 @@ -1,6 +1,8 @@ # Makefile for kernel/blk_drv/scsi # +# Use "make MODULES=true" to build loadable modules. +# # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DONT put your own dependencies here # unless its something special (ie not a .c file). @@ -20,118 +22,109 @@ endif SCSI_OBJS = -SCSI_SRCS = + +SCSI_MODULE_OBJS = ifdef CONFIG_SCSI SCSI_OBJS := hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o -SCSI_SRCS := hosts.c scsi.c scsi_ioctl.c constants.c scsicam.c ifdef CONFIG_CHR_DEV_ST SCSI_OBJS := $(SCSI_OBJS) st.o -SCSI_SRCS := $(SCSI_SRCS) st.c endif ifdef CONFIG_BLK_DEV_SD SCSI_OBJS := $(SCSI_OBJS) sd.o sd_ioctl.o -SCSI_SRCS := $(SCSI_SRCS) sd.c sd_ioctl.c endif ifdef CONFIG_BLK_DEV_SR SCSI_OBJS := $(SCSI_OBJS) sr.o sr_ioctl.o -SCSI_SRCS := $(SCSI_SRCS) sr.c sr_ioctl.c endif ifdef CONFIG_CHR_DEV_SG SCSI_OBJS := $(SCSI_OBJS) sg.o -SCSI_SRCS := $(SCSI_SRCS) sg.c endif ifdef CONFIG_SCSI_AHA152X SCSI_OBJS := $(SCSI_OBJS) aha152x.o -SCSI_SRCS := $(SCSI_SRCS) aha152x.c endif ifdef CONFIG_SCSI_AHA1542 SCSI_OBJS := $(SCSI_OBJS) aha1542.o -SCSI_SRCS := $(SCSI_SRCS) aha1542.c +else +SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) aha1542.o endif ifdef CONFIG_SCSI_AHA1740 SCSI_OBJS := $(SCSI_OBJS) aha1740.o -SCSI_SRCS := $(SCSI_SRCS) aha1740.c endif ifdef CONFIG_SCSI_AHA274X SCSI_OBJS := $(SCSI_OBJS) aha274x.o -SCSI_SRCS := $(SCSI_SRCS) aha274x.c endif ifdef CONFIG_SCSI_BUSLOGIC SCSI_OBJS := $(SCSI_OBJS) buslogic.o -SCSI_SRCS := $(SCSI_SRCS) buslogic.c endif ifdef CONFIG_SCSI_U14_34F SCSI_OBJS := $(SCSI_OBJS) u14-34f.o -SCSI_SRCS := $(SCSI_SRCS) u14-34f.c endif ifdef CONFIG_SCSI_DEBUG SCSI_OBJS := $(SCSI_OBJS) scsi_debug.o -SCSI_SRCS := $(SCSI_SRCS) scsi_debug.c +else +SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) scsi_debug.o endif ifdef CONFIG_SCSI_FUTURE_DOMAIN SCSI_OBJS := $(SCSI_OBJS) fdomain.o -SCSI_SRCS := $(SCSI_SRCS) fdomain.c endif ifdef CONFIG_SCSI_IN2000 SCSI_OBJS := $(SCSI_OBJS) in2000.o -SCSI_SRCS := $(SCSI_SRCS) in2000.c +else +SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) in2000.o endif ifdef CONFIG_SCSI_GENERIC_NCR5380 SCSI_OBJS := $(SCSI_OBJS) g_NCR5380.o -SCSI_SRCS := $(SCSI_SRCS) g_NCR5380.c endif ifdef CONFIG_SCSI_NCR53C7xx SCSI_OBJS := $(SCSI_OBJS) 53c7,8xx.o -SCSI_SRCS := $(SCSI_SRCS) 53c7,8xx.c endif ifdef CONFIG_SCSI_PAS16 SCSI_OBJS := $(SCSI_OBJS) pas16.o -SCSI_SRCS := $(SCSI_SRCS) pas16.c endif ifdef CONFIG_SCSI_SEAGATE SCSI_OBJS := $(SCSI_OBJS) seagate.o -SCSI_SRCS := $(SCSI_SRCS) seagate.c else ifdef CONFIG_SCSI_FD_8xx SCSI_OBJS := $(SCSI_OBJS) seagate.o -SCSI_SRCS := $(SCSI_SRCS) seagate.c endif endif ifdef CONFIG_SCSI_7000FASST SCSI_OBJS := $(SCSI_OBJS) wd7000.o -SCSI_SRCS := $(SCSI_SRCS) wd7000.c endif ifdef CONFIG_SCSI_T128 SCSI_OBJS := $(SCSI_OBJS) t128.o -SCSI_SRCS := $(SCSI_SRCS) t128.c endif ifdef CONFIG_SCSI_ULTRASTOR SCSI_OBJS := $(SCSI_OBJS) ultrastor.o -SCSI_SRCS := $(SCSI_SRCS) ultrastor.c endif +ifdef CONFIG_SCSI_EATA +SCSI_OBJS := $(SCSI_OBJS) eata.o +endif + +all: scsi.a modules + scsi.a: $(SCSI_OBJS) @@ -162,8 +155,21 @@ mv scriptu.h 53c8xx_u.h rm fake.c +ifdef MODULES + +modules: + echo $(SCSI_MODULE_OBJS) > ../../modules/SCSI_MODULES + $(MAKE) CFLAGS="$(CFLAGS) -DMODULE" $(SCSI_MODULE_OBJS) + (cd ../../modules;for i in $(SCSI_MODULE_OBJS); do ln -sf ../drivers/scsi/$$i .; done) + +else + +modules: + +endif + dep: - $(CPP) -M $(AHA152X) $(SCSI_SRCS) > .depend + $(CPP) -M $(AHA152X) *.c > .depend else --- ./drivers/scsi/sd.c.~1~ Sun Nov 13 12:46:45 1994 +++ ./drivers/scsi/sd.c Tue Nov 15 16:34:14 1994 @@ -46,7 +46,9 @@ struct hd_struct * sd; -Scsi_Disk * rscsi_disks; +int revalidate_scsidisk(int dev, int maxusage); + +Scsi_Disk * rscsi_disks = NULL; static int * sd_sizes; static int * sd_blocksizes; @@ -61,13 +63,16 @@ static void sd_init(void); static void sd_finish(void); -static void sd_attach(Scsi_Device *); +static int sd_attach(Scsi_Device *); static int sd_detect(Scsi_Device *); +static void sd_detach(Scsi_Device *); +static void sd_geninit(void); + struct Scsi_Device_Template sd_template = {NULL, "disk", "sd", TYPE_DISK, SCSI_DISK_MAJOR, 0, 0, 0, 1, sd_detect, sd_init, - sd_finish, sd_attach, NULL}; + sd_finish, sd_attach, sd_detach}; static int sd_open(struct inode * inode, struct file * filp) { @@ -89,6 +94,8 @@ sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0); }; rscsi_disks[target].device->access_count++; + if (rscsi_disks[target].device->host->hostt->usage_count) + (*rscsi_disks[target].device->host->hostt->usage_count)++; return 0; } @@ -100,6 +107,8 @@ target = DEVICE_NR(MINOR(inode->i_rdev)); rscsi_disks[target].device->access_count--; + if (rscsi_disks[target].device->host->hostt->usage_count) + (*rscsi_disks[target].device->host->hostt->usage_count)--; if(rscsi_disks[target].device->removable) { if(!rscsi_disks[target].device->access_count) @@ -107,8 +116,6 @@ }; } -static void sd_geninit(void); - static struct file_operations sd_fops = { NULL, /* lseek - default */ block_read, /* read - general block-dev read */ @@ -146,7 +153,10 @@ for (i = 0; i < sd_template.dev_max; ++i) if(rscsi_disks[i].device) sd[i << 4].nr_sects = rscsi_disks[i].capacity; - sd_gendisk.nr_real = sd_template.dev_max; +#if 0 + /* No longer needed - we keep track of this as we attach/detach */ + sd_gendisk.nr_real = sd_template.nr_dev; +#endif } /* @@ -411,6 +421,7 @@ return; } + dev = MINOR(SCpnt->request.dev); block = SCpnt->request.sector; this_count = 0; @@ -871,7 +882,6 @@ } }; /* current == task[0] */ - retries = 3; do { cmd[0] = READ_CAPACITY; @@ -879,6 +889,7 @@ memset ((void *) &cmd[2], 0, 8); memset ((void *) buffer, 0, 8); SCpnt->request.dev = 0xffff; /* Mark as really busy again */ + SCpnt->cmd_len = 0; SCpnt->sense_buffer[0] = 0; SCpnt->sense_buffer[2] = 0; @@ -906,7 +917,6 @@ SCpnt->request.dev = -1; /* Mark as not busy */ wake_up(&SCpnt->device->device_wait); - /* Wake up a process waiting for device*/ /* @@ -1007,25 +1017,25 @@ } /* We do not support attaching loadable devices yet. */ - if(scsi_loadable_module_flag) return; + if(rscsi_disks) return; - sd_template.dev_max = sd_template.dev_noticed; + sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS; rscsi_disks = (Scsi_Disk *) - scsi_init_malloc(sd_template.dev_max * sizeof(Scsi_Disk)); + scsi_init_malloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC); memset(rscsi_disks, 0, sd_template.dev_max * sizeof(Scsi_Disk)); sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * - sizeof(int)); + sizeof(int), GFP_ATOMIC); memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int)); sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * - sizeof(int)); + sizeof(int), GFP_ATOMIC); for(i=0;i<(sd_template.dev_max << 4);i++) sd_blocksizes[i] = 1024; blksize_size[MAJOR_NR] = sd_blocksizes; sd = (struct hd_struct *) scsi_init_malloc((sd_template.dev_max << 4) * - sizeof(struct hd_struct)); + sizeof(struct hd_struct), GFP_ATOMIC); sd_gendisk.max_nr = sd_template.dev_max; @@ -1039,28 +1049,37 @@ { int i; - for (i = 0; i < sd_template.dev_max; ++i) - if (rscsi_disks[i].device) i = sd_init_onedisk(i); - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + sd_gendisk.next = gendisk_head; + gendisk_head = &sd_gendisk; + + for (i = 0; i < sd_template.dev_max; ++i) + if (!rscsi_disks[i].capacity && + rscsi_disks[i].device) + { + i = sd_init_onedisk(i); + if (scsi_loadable_module_flag + && !rscsi_disks[i].has_part_table) { + sd_sizes[i << 4] = rscsi_disks[i].capacity; + revalidate_scsidisk(i << 4, 0); + } + rscsi_disks[i].has_part_table = 1; + } + /* If our host adapter is capable of scatter-gather, then we increase the read-ahead to 16 blocks (32 sectors). If not, we use a two block (4 sector) read ahead. */ - if(rscsi_disks[0].device->host->sg_tablesize) + if(rscsi_disks[0].device && rscsi_disks[0].device->host->sg_tablesize) read_ahead[MAJOR_NR] = 120; /* 64 sector read-ahead */ else read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */ - sd_gendisk.next = gendisk_head; - gendisk_head = &sd_gendisk; return; } static int sd_detect(Scsi_Device * SDp){ - /* We do not support attaching loadable devices yet. */ - if(scsi_loadable_module_flag) return 0; if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0; printk("Detected scsi disk sd%c at scsi%d, id %d, lun %d\n", @@ -1071,17 +1090,17 @@ } -static void sd_attach(Scsi_Device * SDp){ +static int sd_attach(Scsi_Device * SDp){ Scsi_Disk * dpnt; int i; - /* We do not support attaching loadable devices yet. */ - if(scsi_loadable_module_flag) return; - if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return; - - if(sd_template.nr_dev >= sd_template.dev_max) - panic ("scsi_devices corrupt (sd)"); + if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0; + if(sd_template.nr_dev >= sd_template.dev_max) { + SDp->attached--; + return 1; + } + for(dpnt = rscsi_disks, i=0; idevice) break; @@ -1089,7 +1108,10 @@ SDp->scsi_request_fn = do_sd_request; rscsi_disks[i].device = SDp; + rscsi_disks[i].has_part_table = 0; sd_template.nr_dev++; + sd_gendisk.nr_real++; + return 0; }; #define DEVICE_BUSY rscsi_disks[target].device->busy @@ -1150,4 +1172,44 @@ static int fop_revalidate_scsidisk(dev_t dev){ return revalidate_scsidisk(dev, 0); } + + +static void sd_detach(Scsi_Device * SDp) +{ + Scsi_Disk * dpnt; + int i; + int max_p; + int major; + int start; + + for(dpnt = rscsi_disks, i=0; idevice == SDp) { + + /* If we are disconnecting a disk driver, sync and invalidate everything */ + max_p = sd_gendisk.max_p; + start = i << sd_gendisk.minor_shift; + major = MAJOR_NR << 8; + + for (i=max_p - 1; i >=0 ; i--) { + sync_dev(major | start | i); + invalidate_inodes(major | start | i); + invalidate_buffers(major | start | i); + sd_gendisk.part[start+i].start_sect = 0; + sd_gendisk.part[start+i].nr_sects = 0; + sd_sizes[start+i] = 0; + }; + + dpnt->has_part_table = 0; + dpnt->device = NULL; + dpnt->capacity = 0; + SDp->attached--; + sd_template.dev_noticed--; + sd_template.nr_dev--; + sd_gendisk.nr_real--; + return; + } + return; +} + + --- ./drivers/scsi/scsi.c.~1~ Sun Nov 13 12:50:03 1994 +++ ./drivers/scsi/scsi.c Tue Nov 15 22:16:46 1994 @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include "../block/blk.h" #include "scsi.h" @@ -195,8 +197,13 @@ printk ("scan_scsis_done(%d, %06x)\n", SCpnt->host, SCpnt->result); #endif SCpnt->request.dev = 0xfffe; + + if (SCpnt->request.sem != NULL) { + up(SCpnt->request.sem); } + } + #ifdef NO_MULTI_LUN static int max_scsi_luns = 1; #else @@ -218,11 +225,12 @@ * devices to the disk driver. */ -static void scan_scsis (struct Scsi_Host * shpnt) +void scan_scsis (struct Scsi_Host * shpnt) { int dev, lun, type; unsigned char scsi_cmd [12]; - unsigned char scsi_result [256]; + unsigned char scsi_result0 [256]; + unsigned char * scsi_result; Scsi_Device * SDpnt, *SDtail; struct Scsi_Device_Template * sdtpnt; Scsi_Cmnd SCmd; @@ -232,12 +240,16 @@ type = -1; SCmd.next = NULL; SCmd.prev = NULL; - SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device)); + SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC); SDtail = scsi_devices; if(scsi_devices) { while(SDtail->next) SDtail = SDtail->next; } + /* Make sure we have something that is valid for DMA purposes */ + scsi_result = ((current == task[0] || !shpnt->unchecked_isa_dma) + ? &scsi_result0[0] : scsi_malloc(512)); + shpnt->host_queue = &SCmd; /* We need this so that commands can time out */ for (dev = 0; dev < 8; ++dev) @@ -270,7 +282,9 @@ SCmd.lun = lun; SCmd.request.dev = 0xffff; /* Mark not busy */ + SCmd.request.sem = NULL; /* Used for mutex if loading devices after boot */ SCmd.use_sg = 0; + SCmd.cmd_len = 0; SCmd.old_use_sg = 0; SCmd.transfersize = 0; SCmd.underflow = 0; @@ -280,7 +294,21 @@ scsi_result, 256, scan_scsis_done, SCSI_TIMEOUT + 400, 5); - while (SCmd.request.dev != 0xfffe); + /* Wait for command to finish. Use simple wait if we are booting, else + do it right and use a mutex */ + + if (current == task[0]){ + while (SCmd.request.dev != 0xfffe); + } else { + if (SCmd.request.dev != 0xfffe){ + struct semaphore sem = MUTEX_LOCKED; + SCmd.request.sem = &sem; + down(&sem); + /* Hmm.. Have to ask about this one */ + while (SCmd.request.dev != 0xfffe) schedule(); + } + } + #if defined(DEBUG) || defined(DEBUG_INIT) printk("scsi: scan SCSIS id %d lun %d\n", dev, lun); printk("scsi: return code %08x\n", SCmd.result); @@ -316,6 +344,7 @@ scsi_cmd[5] = 0; SCmd.request.dev = 0xffff; /* Mark not busy */ + SCmd.cmd_len = 0; scsi_do_cmd (&SCmd, (void *) scsi_cmd, (void *) @@ -322,8 +351,18 @@ scsi_result, 256, scan_scsis_done, SCSI_TIMEOUT, 3); - while (SCmd.request.dev != 0xfffe); - + if (current == task[0]){ + while (SCmd.request.dev != 0xfffe); + } else { + if (SCmd.request.dev != 0xfffe){ + struct semaphore sem = MUTEX_LOCKED; + SCmd.request.sem = &sem; + down(&sem); + /* Hmm.. Have to ask about this one */ + while (SCmd.request.dev != 0xfffe) schedule(); + } + } + the_result = SCmd.result; #if defined(DEBUG) || defined(DEBUG_INIT) @@ -455,6 +494,7 @@ scsi_cmd[5] = 0; SCmd.request.dev = 0xffff; /* Mark not busy */ + SCmd.cmd_len = 0; scsi_do_cmd (&SCmd, (void *) scsi_cmd, (void *) @@ -461,8 +501,18 @@ scsi_result, 0x2a, scan_scsis_done, SCSI_TIMEOUT, 3); - while (SCmd.request.dev != 0xfffe); - }; + if (current == task[0]){ + while (SCmd.request.dev != 0xfffe); + } else { + if (SCmd.request.dev != 0xfffe){ + struct semaphore sem = MUTEX_LOCKED; + SCmd.request.sem = &sem; + down(&sem); + /* Hmm.. Have to ask about this one */ + while (SCmd.request.dev != 0xfffe) schedule(); + } + } + } /* Add this device to the linked list at the end */ if(SDtail) SDtail->next = SDpnt; @@ -470,7 +520,7 @@ scsi_devices = SDpnt; SDtail = SDpnt; - SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device)); + SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC); /* Some scsi devices cannot be polled for lun != 0 due to firmware bugs */ if(blacklisted(scsi_result)) break; @@ -496,7 +546,10 @@ /* Last device block does not exist. Free memory. */ scsi_init_free((char *) SDpnt, sizeof(Scsi_Device)); - + + /* If we allocated a buffer so we could do DMA, free it now */ + if (scsi_result != &scsi_result0[0]) scsi_free(scsi_result, 512); + in_scan_scsis = 0; } /* scan_scsis ends */ @@ -565,10 +618,10 @@ struct buffer_head * bh, *bhp; if (!device) - panic ("No device passed to allocate_device().\n"); + panic ("No device passed to request_queueable().\n"); if (req && req->dev <= 0) - panic("Invalid device in allocate_device"); + panic("Invalid device in request_queueable"); SCpnt = device->host->host_queue; while(SCpnt){ @@ -622,6 +675,7 @@ SCpnt->old_use_sg = 0; SCpnt->transfersize = 0; SCpnt->underflow = 0; + SCpnt->cmd_len = 0; return SCpnt; } @@ -725,6 +779,7 @@ }; SCpnt->use_sg = 0; /* Reset the scatter-gather flag */ + SCpnt->cmd_len = 0; SCpnt->old_use_sg = 0; SCpnt->transfersize = 0; /* No default transfer size */ SCpnt->underflow = 0; /* Do not flag underflow conditions */ @@ -825,8 +880,11 @@ SCpnt->request_buffer = &SCpnt->sense_buffer; SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer); SCpnt->use_sg = 0; + if (SCpnt->cmd_len == 0) + SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); internal_cmnd (SCpnt); SCpnt->use_sg = SCpnt->old_use_sg; + SCpnt->cmd_len = SCpnt->old_cmd_len; } @@ -917,6 +975,9 @@ SCpnt->request_buffer = buffer; SCpnt->request_bufflen = bufflen; SCpnt->old_use_sg = SCpnt->use_sg; + if (SCpnt->cmd_len == 0) + SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); + SCpnt->old_cmd_len = SCpnt->cmd_len; /* Start the timer ticking. */ @@ -1322,6 +1383,7 @@ SCpnt->request_buffer = SCpnt->buffer; SCpnt->request_bufflen = SCpnt->bufflen; SCpnt->use_sg = SCpnt->old_use_sg; + SCpnt->cmd_len = SCpnt->old_cmd_len; internal_cmnd (SCpnt); }; break; @@ -1338,6 +1400,7 @@ wake_up(&host->host_wait); SCpnt->result = result | ((exit & 0xff) << 24); SCpnt->use_sg = SCpnt->old_use_sg; + SCpnt->cmd_len = SCpnt->old_cmd_len; SCpnt->done (SCpnt); } @@ -1633,17 +1696,22 @@ } -static unsigned short * dma_malloc_freelist = NULL; +static unsigned char * dma_malloc_freelist = NULL; +static int scsi_need_isa_bounce_buffers; static unsigned int dma_sectors = 0; unsigned int dma_free_sectors = 0; unsigned int need_isa_buffer = 0; -static unsigned char * dma_malloc_buffer = NULL; +static unsigned char ** dma_malloc_pages = NULL; +#define MALLOC_PAGEBITS 12 + +static int scsi_register_host(Scsi_Host_Template *); +static void scsi_unregister_host(Scsi_Host_Template *); void *scsi_malloc(unsigned int len) { unsigned int nbits, mask; int i, j; - if((len & 0x1ff) || len > 8192) + if((len & 0x1ff) || len > (1<> 9; mask = (1 << nbits) - 1; - for(i=0;i < (dma_sectors >> 4); i++) - for(j=0; j<17-nbits; j++){ + for(i=0;i < (dma_sectors >> (MALLOC_PAGEBITS - 9)); i++) + for(j=0; j<=(sizeof(*dma_malloc_freelist) * 8) - nbits; j++){ if ((dma_malloc_freelist[i] & (mask << j)) == 0){ dma_malloc_freelist[i] |= (mask << j); sti(); dma_free_sectors -= nbits; #ifdef DEBUG - printk("SMalloc: %d %x ",len, dma_malloc_buffer + (i << 13) + (j << 9)); + printk("SMalloc: %d %x ",len, dma_malloc_pages[i] + (j << 9)); #endif - return (void *) ((unsigned long) dma_malloc_buffer + (i << 13) + (j << 9)); + return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9)); }; }; sti(); @@ -1675,14 +1743,21 @@ printk("Sfree %x %d\n",obj, len); #endif - offset = ((int) obj) - ((int) dma_malloc_buffer); + offset = -1; + for (page = 0; page < (dma_sectors >> 3); page++) + if ((int) obj >= (int) dma_malloc_pages[page] && + (int) obj < (int) dma_malloc_pages[page] + (1 << MALLOC_PAGEBITS)) + { + offset = ((int) obj) - ((int)dma_malloc_pages[page]); + break; + } + + if (page == (dma_sectors >> 3)) panic("Bad offset"); - if (offset < 0) panic("Bad offset"); - page = offset >> 13; sector = offset >> 9; if(sector >= dma_sectors) panic ("Bad page"); - sector = (offset >> 9) & 15; + sector = (offset >> 9) & (sizeof(*dma_malloc_freelist) * 8 - 1); nbits = len >> 9; mask = (1 << nbits) - 1; @@ -1706,11 +1781,11 @@ static unsigned int scsi_init_memory_start = 0; int scsi_loadable_module_flag; /* Set after we scan builtin drivers */ -void * scsi_init_malloc(unsigned int size) +void * scsi_init_malloc(unsigned int size, int priority) { unsigned int retval; if(scsi_loadable_module_flag) { - retval = (unsigned int) kmalloc(size, GFP_ATOMIC); + retval = (unsigned int) kmalloc(size, priority); } else { retval = scsi_init_memory_start; scsi_init_memory_start += size; @@ -1722,7 +1797,7 @@ void scsi_init_free(char * ptr, unsigned int size) { /* FIXME - not right. We need to compare addresses to see whether this was kmalloc'd or not */ - if((unsigned int) ptr < scsi_loadable_module_flag) { + if((unsigned int) ptr > scsi_init_memory_start) { kfree(ptr); } else { if(((unsigned int) ptr) + size == scsi_init_memory_start) @@ -1743,6 +1818,7 @@ struct Scsi_Host * shpnt; struct Scsi_Device_Template * sdtpnt; Scsi_Cmnd * SCpnt; + int i; #ifdef FOO_ON_YOU return; #endif @@ -1763,16 +1839,17 @@ scan_scsis(shpnt); /* scan for scsi devices */ for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)(); + if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)(); for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) { int j; SDpnt->scsi_request_fn = NULL; for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt); - if(SDpnt->type != -1){ - for(j=0;jhost->hostt->cmd_per_lun;j++){ - SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd)); + if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt); + + if(SDpnt->attached){ + for(j=0;jhost->cmd_per_lun;j++){ + SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), GFP_ATOMIC); SCpnt->host = SDpnt->host; SCpnt->device = SDpnt; SCpnt->target = SDpnt->id; @@ -1780,6 +1857,8 @@ SCpnt->request.dev = -1; /* Mark not busy */ SCpnt->use_sg = 0; SCpnt->old_use_sg = 0; + SCpnt->old_cmd_len = 0; + SCpnt->timeout = 0; SCpnt->underflow = 0; SCpnt->transfersize = 0; SCpnt->host_scribble = NULL; @@ -1796,6 +1875,12 @@ if (scsi_devicelist) dma_sectors = 16; /* Base value we use */ + if (memory_end-1 > ISA_DMA_THRESHOLD) + scsi_need_isa_bounce_buffers = 1; + else + scsi_need_isa_bounce_buffers = 0; + + for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) { host = SDpnt->host; @@ -1802,13 +1887,14 @@ if(SDpnt->type != TYPE_TAPE) dma_sectors += ((host->sg_tablesize * sizeof(struct scatterlist) + 511) >> 9) * - host->hostt->cmd_per_lun; + host->cmd_per_lun; + if(host->unchecked_isa_dma && memory_end - 1 > ISA_DMA_THRESHOLD && SDpnt->type != TYPE_TAPE) { dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize * - host->hostt->cmd_per_lun; + host->cmd_per_lun; need_isa_buffer++; }; }; @@ -1817,22 +1903,27 @@ dma_free_sectors = dma_sectors; /* This must be a multiple of 16 */ scsi_init_memory_start = (scsi_init_memory_start + 3) & 0xfffffffc; - dma_malloc_freelist = (unsigned short *) - scsi_init_malloc(dma_sectors >> 3); + dma_malloc_freelist = (unsigned char *) + scsi_init_malloc(dma_sectors >> 3, GFP_ATOMIC); memset(dma_malloc_freelist, 0, dma_sectors >> 3); + dma_malloc_pages = (unsigned char **) + scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC); + memset(dma_malloc_pages, 0, dma_sectors >> 1); + /* Some host adapters require buffers to be word aligned */ if(scsi_init_memory_start & 1) scsi_init_memory_start++; - dma_malloc_buffer = (unsigned char *) - scsi_init_malloc(dma_sectors << 9); - + for(i=0; i< dma_sectors >> 3; i++) + dma_malloc_pages[i] = (unsigned char *) + scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); + /* OK, now we finish the initialization by doing spin-up, read capacity, etc, etc */ for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if(sdtpnt->finish && sdtpnt->nr_dev) - (*sdtpnt->finish)(); - + if(sdtpnt->finish && sdtpnt->nr_dev) + (*sdtpnt->finish)(); + scsi_loadable_module_flag = 1; return scsi_init_memory_start; } @@ -1879,6 +1970,310 @@ printk(" CCS\n"); else printk("\n"); +} + +/* + * This entry point should be called by a loadable module if it is trying + * add a low level scsi driver to the system. + */ +static int scsi_register_host(Scsi_Host_Template * tpnt) +{ + int pcount; + struct Scsi_Host * shpnt; + struct Scsi_Host * host = NULL; + Scsi_Device * SDpnt; + Scsi_Cmnd * SCpnt; + struct Scsi_Device_Template * sdtpnt; + int j, i; + char * name; + + if (tpnt->next || !tpnt->detect) return 1; /* Must be already loaded, or + no detect routine available */ + pcount = next_scsi_host; + if ((tpnt->present = tpnt->detect(tpnt))) + { + if(pcount == next_scsi_host) { + if(tpnt->present > 1) { + printk("Failure to register low-level scsi driver"); + scsi_unregister_host(tpnt); + return 1; + } + /* The low-level driver failed to register a driver. We + can do this now. */ + scsi_register(tpnt,0); + } + tpnt->next = scsi_hosts; /* Add to the linked list */ + scsi_hosts = tpnt; + + for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) + if(shpnt->hostt == tpnt) + { + if(tpnt->info) + name = tpnt->info(shpnt); + else + name = tpnt->name; + printk ("scsi%d : %s\n", /* And print a little message */ + shpnt->host_no, name); + } + /* The next step is to call scan_scsis here. This generates the + Scsi_Devices entries */ + + for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) + if(shpnt->hostt == tpnt) scan_scsis(shpnt); + + for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) + if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)(); + + /* Next we create the Scsi_Cmnd structures for this host */ + + for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next) + if(SDpnt->host->hostt == tpnt) + { + for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) + if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt); + if(SDpnt->attached){ + for(j=0;jhost->cmd_per_lun;j++){ + SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), GFP_ATOMIC); + SCpnt->host = SDpnt->host; + SCpnt->device = SDpnt; + SCpnt->target = SDpnt->id; + SCpnt->lun = SDpnt->lun; + SCpnt->request.dev = -1; /* Mark not busy */ + SCpnt->request.sem = NULL; + SCpnt->use_sg = 0; + SCpnt->old_use_sg = 0; + SCpnt->underflow = 0; + SCpnt->timeout = 0; + SCpnt->transfersize = 0; + SCpnt->host_scribble = NULL; + host = SDpnt->host; + SCpnt->next = host->host_queue; + SCpnt->prev = NULL; + host->host_queue = SCpnt; + if(host->host_queue) + host->host_queue->prev = SCpnt; + }; + }; + } + /* Next, check to see if we need to extend the DMA buffer pool */ + { + unsigned char * new_dma_malloc_freelist = NULL; + unsigned int new_dma_sectors = 0; + unsigned int new_need_isa_buffer = 0; + unsigned char ** new_dma_malloc_pages = NULL; + + if (scsi_devicelist) + new_dma_sectors = 16; /* Base value we use */ + + for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) { + host = SDpnt->host; + + if(SDpnt->type != TYPE_TAPE) + new_dma_sectors += ((host->sg_tablesize * + sizeof(struct scatterlist) + 511) >> 9) * + host->cmd_per_lun; + + if(host->unchecked_isa_dma && + scsi_need_isa_bounce_buffers && + SDpnt->type != TYPE_TAPE) { + new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize * + host->cmd_per_lun; + new_need_isa_buffer++; + }; + }; + + new_dma_sectors = (new_dma_sectors + 15) & 0xfff0; + + new_dma_malloc_freelist = (unsigned char *) + scsi_init_malloc(new_dma_sectors >> 3, GFP_ATOMIC); + memset(new_dma_malloc_freelist, 0, new_dma_sectors >> 3); + + new_dma_malloc_pages = (unsigned char **) + scsi_init_malloc(new_dma_sectors >> 1, GFP_ATOMIC); + memset(new_dma_malloc_pages, 0, new_dma_sectors >> 1); + + for(i=dma_sectors >> 3; i< new_dma_sectors >> 3; i++) + new_dma_malloc_pages[i] = (unsigned char *) + scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); + + + /* When we dick with the actual DMA list, we need to protect things */ + cli(); + memcpy(new_dma_malloc_freelist, dma_malloc_freelist, dma_sectors >> 3); + scsi_init_free(dma_malloc_freelist, dma_sectors>>3); + dma_malloc_freelist = new_dma_malloc_freelist; + + memcpy(new_dma_malloc_pages, dma_malloc_pages, dma_sectors >> 1); + scsi_init_free((char *) dma_malloc_pages, dma_sectors>>1); + + dma_free_sectors += new_dma_sectors - dma_sectors; + dma_malloc_pages = new_dma_malloc_pages; + dma_sectors = new_dma_sectors; + need_isa_buffer = new_need_isa_buffer; + sti(); + + + } + /* This does any final handling that is required. */ + for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) + if(sdtpnt->finish) (*sdtpnt->finish)(); + } + return 0; +} + +/* + * Similarily, this entry point should be called by a loadable module if it + * is trying to remove a low level scsi driver from the system. + */ +static void scsi_unregister_host(Scsi_Host_Template * tpnt) +{ + Scsi_Host_Template * SHT, *SHTp; + Scsi_Device *sdpnt, * sdppnt, * sdpnt1; + Scsi_Cmnd * SCpnt; + struct Scsi_Device_Template * sdtpnt; + struct Scsi_Host * shpnt, *sh1; + int pcount; + + /* First verify that this host adapter is completely free with no pending + commands */ + + for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next) + if(sdpnt->host->hostt == tpnt && *sdpnt->host->hostt->usage_count) return; + + for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) + { + if (shpnt->hostt != tpnt) continue; + for(SCpnt = shpnt->host_queue; SCpnt; SCpnt = SCpnt->next) + { + cli(); + if(SCpnt->request.dev != -1) { + sti(); + for(SCpnt = shpnt->host_queue; SCpnt; SCpnt = SCpnt->next) + if(SCpnt->request.dev == 0xffe0) SCpnt->request.dev = -1; + printk("Device busy???\n"); + return; + } + SCpnt->request.dev = 0xffe0; /* Mark as busy */ + } + } + /* Next we detach the high level drivers from the Scsi_Device structures */ + + for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next) + if(sdpnt->host->hostt == tpnt) + { + for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) + if(sdtpnt->detach) (*sdtpnt->detach)(sdpnt); + /* If something still attached, punt */ + if (sdpnt->attached) { + printk("Attached usage count = %d\n", sdpnt->attached); + return; + } + } + + /* Next we free up the Scsi_Cmnd structures for this host */ + + for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next) + if(sdpnt->host->hostt == tpnt) + while (sdpnt->host->host_queue) { + SCpnt = sdpnt->host->host_queue->next; + scsi_init_free((char *) sdpnt->host->host_queue, sizeof(Scsi_Cmnd)); + sdpnt->host->host_queue = SCpnt; + if (SCpnt) SCpnt->prev = NULL; + } + + /* Next free up the Scsi_Device structures for this host */ + + sdppnt = NULL; + for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt1) + { + sdpnt1 = sdpnt->next; + if (sdpnt->host->hostt == tpnt) { + if (sdppnt) + sdppnt->next = sdpnt->next; + else + scsi_devices = sdpnt->next; + scsi_init_free((char *) sdpnt, sizeof (Scsi_Device)); + } else + sdppnt = sdpnt; + } + + /* Next we go through and remove the instances of the individual hosts + that were detected */ + + shpnt = scsi_hostlist; + while(shpnt) { + sh1 = shpnt->next; + if(shpnt->hostt == tpnt) { + if(shpnt->loaded_as_module) { + pcount = next_scsi_host; + if(tpnt->release) + (*tpnt->release)(shpnt); + else { + /* This is the default case for the release function. It should do the right + thing for most correctly written host adapters. */ + if (shpnt->irq) free_irq(shpnt->irq); + if (shpnt->dma_channel != 0xff) free_dma(shpnt->dma_channel); + if (shpnt->io_port && shpnt->n_io_port) + release_region(shpnt->io_port, shpnt->n_io_port); + } + if(pcount == next_scsi_host) scsi_unregister(shpnt); + tpnt->present--; + } + } + shpnt = sh1; + } + + /* There were some hosts that were loaded at boot time, so we cannot + do any more than this */ + if (tpnt->present) return; + + /* OK, this is the very last step. Remove this host adapter from the + linked list. */ + for(SHTp=NULL, SHT=scsi_hosts; SHT; SHTp=SHT, SHT=SHT->next) + if(SHT == tpnt) { + if(SHTp) + SHTp->next = SHT->next; + else + scsi_hosts = SHT->next; + SHT->next = NULL; + break; + } +} + +int scsi_register_module(int module_type, void * ptr) +{ + switch(module_type){ + case MODULE_SCSI_HA: + return scsi_register_host((Scsi_Host_Template *) ptr); + /* The rest of these are not yet implemented */ + + /* Load constants.o */ + case MODULE_SCSI_CONST: + + /* Load specialized ioctl handler for some device. Intended for cdroms that + have non-SCSI2 audio command sets. */ + case MODULE_SCSI_IOCTL: + + /* Load upper level device handler of some kind */ + case MODULE_SCSI_DEV: + default: + return 1; + } +} + +void scsi_unregister_module(int module_type, void * ptr) +{ + switch(module_type) { + case MODULE_SCSI_HA: + scsi_unregister_host((Scsi_Host_Template *) ptr); + break; + /* The rest of these are not yet implemented. */ + case MODULE_SCSI_CONST: + case MODULE_SCSI_IOCTL: + case MODULE_SCSI_DEV: + default: + } + return; } #ifdef DEBUG_TIMEOUT --- ./drivers/scsi/sd.h.~1~ Mon Sep 12 21:10:03 1994 +++ ./drivers/scsi/sd.h Mon Nov 14 15:02:27 1994 @@ -39,6 +39,7 @@ unsigned char sector_bit_shift; /* power of 2 sectors per FS block */ unsigned ten:1; /* support ten byte read / write */ unsigned remap:1; /* support remapping */ + unsigned has_part_table:1; /* has partition table */ } Scsi_Disk; extern Scsi_Disk * rscsi_disks; --- ./drivers/scsi/scsi_ioctl.c.~1~ Sun Nov 13 12:46:43 1994 +++ ./drivers/scsi/scsi_ioctl.c Sun Nov 13 12:54:19 1994 @@ -33,7 +33,7 @@ if ((temp = host->hostt->present) && buffer) { len = get_fs_long ((unsigned long *) buffer); - string = host->hostt->info(); + string = host->hostt->info(host); slen = strlen(string); if (len > slen) len = slen + 1; --- ./drivers/scsi/buslogic.c.~1~ Sun Nov 13 12:46:44 1994 +++ ./drivers/scsi/buslogic.c Sun Nov 13 12:54:20 1994 @@ -413,7 +413,7 @@ return TRUE; /* 1 = not ok */ } -const char *buslogic_info(void) +const char *buslogic_info(struct Scsi_Host * shpnt) { return "BusLogic SCSI Driver version " BUSLOGIC_VERSION; } @@ -642,7 +642,7 @@ target, *cmd, i, bufflen); buslogic_stat(scpnt->host->io_port); buslogic_printk("buslogic_queuecommand: dumping scsi cmd:"); - for (i = 0; i < (COMMAND_SIZE(*cmd)); i++) + for (i = 0; i < scpnt->cmd_len; i++) printk(" %02X", cmd[i]); printk("\n"); if (*cmd == WRITE_10 || *cmd == WRITE_6) @@ -695,7 +695,7 @@ memset(&ccb[mbo], 0, sizeof (struct ccb)); - ccb[mbo].cdblen = COMMAND_SIZE(*cmd); /* SCSI Command Descriptor + ccb[mbo].cdblen = scpnt->cmd_len; /* SCSI Command Descriptor Block Length */ direction = 0; --- ./drivers/scsi/fdomain.c.~1~ Sun Nov 13 12:50:02 1994 +++ ./drivers/scsi/fdomain.c Sun Nov 13 12:54:20 1994 @@ -375,9 +375,9 @@ #define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature )) -static void print_banner( void ) +static void print_banner( struct Scsi_Host * shpnt ) { - printk( "%s", fdomain_16x0_info() ); + printk( "%s", fdomain_16x0_info(shpnt) ); printk( "Future Domain: BIOS version %d.%d, %s\n", bios_major, bios_minor, chip == tmc1800 ? "TMC-1800" @@ -637,7 +637,7 @@ return 0; /* Cannot find valid set of ports */ } - print_banner(); + print_banner(NULL); SCSI_Mode_Cntl_port = port_base + SCSI_Mode_Cntl; FIFO_Data_Count_port = port_base + FIFO_Data_Count; @@ -755,7 +755,7 @@ return 1; } -const char *fdomain_16x0_info(void) +const char *fdomain_16x0_info(struct Scsi_Host * shpnt) { static char buffer[80]; char *pt; @@ -1014,7 +1014,7 @@ if (chip == tmc1800 && !current_SC->SCp.have_data_in && (current_SC->SCp.sent_command - >= COMMAND_SIZE( current_SC->cmnd[ 0 ] ))) { + >= current_SC->cmd_len)) { /* We have to get the FIFO direction correct, so I've made a table based on the SCSI Standard of which commands @@ -1376,7 +1376,7 @@ unsigned int irr; unsigned int isr; - print_banner(); + print_banner(SCpnt->host); switch (SCpnt->SCp.phase) { case in_arbitration: printk( "arbitration " ); break; case in_selection: printk( "selection " ); break; --- ./drivers/scsi/in2000.h.~1~ Mon Nov 14 14:49:56 1994 +++ ./drivers/scsi/in2000.h Sun Nov 13 12:54:20 1994 @@ -0,0 +1,124 @@ +#ifndef _IN2000_H + +/* $Id: in2000.h,v 1.1 1994/03/14 06:27:38 root Exp root $ + * + * Header file for the Always IN 2000 driver for Linux + * + */ + +#include +#include + +/* The IN-2000 is based on a WD33C93 */ + +#define INSTAT (base + 0x0) /* R: Auxiliary Status; W: register select */ +#define INDATA (base + 0x1) /* R/W: Data port */ +#define INFIFO (base + 0x2) /* R/W FIFO, Word access only */ +#define INREST (base + 0x3) /* W: Reset everything */ +#define INFCNT (base + 0x4) /* R: FIFO byte count */ +#define INFRST (base + 0x5) /* W: Reset Fifo count and to write */ +#define INFWRT (base + 0x7) /* W: Set FIFO to read */ +#define INFLED (base + 0x8) /* W: Set LED; R: Dip Switch settings */ +#define INNLED (base + 0x9) /* W: reset LED */ +#define INVERS (base + 0xa) /* R: Read hw version, end-reset */ +#define ININTR (base + 0xc) /* W: Interrupt Mask Port */ +#define G2CNTRL_HRDY 0x20 /* Sets HOST ready */ + +/* WD33C93 defines */ +#define OWNID 0 +#define CONTROL 1 +#define TIMEOUT 2 +#define TOTSECT 3 +#define TOTHEAD 4 +#define TOTCYLH 5 +#define TOTCYLL 6 +#define LADRSHH 7 +#define LADRSHL 8 +#define LADRSLH 9 +#define LADRSLL 10 +#define SECTNUM 11 +#define HEADNUM 12 +#define CYLNUMH 13 +#define CYLNUML 14 +#define TARGETU 15 +#define CMDPHAS 16 +#define SYNCTXR 17 +#define TXCNTH 18 +#define TXCNTM 19 +#define TXCNTL 20 +#define DESTID 21 +#define SRCID 22 +#define SCSIST 23 +#define COMMAND 24 +#define WDDATA 25 +#define AUXSTAT 31 + +/* OWNID Register Bits */ +#define OWN_EAF 0x08 +#define OWN_EHP 0x10 +#define OWN_FS0 0x40 +#define OWN_FS1 0x80 +/* AUX Register Bits */ +#define AUX_DBR 0 +#define AUX_PE 1 +#define AUX_CIP 0x10 +#define AUX_BSY 0x20 +#define AUX_LCI 0x40 +#define AUX_INT 0x80 + +/* Select timeout const, 1 count = 8ms */ +#define IN2000_TMOUT 0x1f + +#if 0 +/* This is used with scatter-gather */ +struct in2000_chain { + ulong dataptr; /* Location of data */ + ulong datalen; /* Size of this part of chain */ +}; +#endif + +/* These belong in scsi.h also */ +#define any2scsi(up, p) \ +(up)[0] = (((unsigned long)(p)) >> 16); \ +(up)[1] = (((unsigned long)(p)) >> 8); \ +(up)[2] = ((unsigned long)(p)); + +#define scsi2int(up) ( ((((long)*(up))&0x1f) << 16) + (((long)(up)[1]) << 8) + ((long)(up)[2]) ) + +#define xany2scsi(up, p) \ +(up)[0] = ((long)(p)) >> 24; \ +(up)[1] = ((long)(p)) >> 16; \ +(up)[2] = ((long)(p)) >> 8; \ +(up)[3] = ((long)(p)); + +#define xscsi2int(up) ( (((long)(up)[0]) << 24) + (((long)(up)[1]) << 16) \ + + (((long)(up)[2]) << 8) + ((long)(up)[3]) ) + +#define MAX_CDB 12 +#define MAX_SENSE 14 +#define MAX_STATUS 32 + +static int in2000_detect(Scsi_Host_Template *); +static int in2000_command(Scsi_Cmnd *); +static int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +static int in2000_abort(Scsi_Cmnd *); +static int in2000_reset(Scsi_Cmnd *); +static int in2000_biosparam(Disk *, int, int*); + + +#ifndef NULL + #define NULL 0 +#endif + +/* next may be "SG_NONE" or "SG_ALL" or nr. of (1k) blocks per R/W Cmd. */ +#define IN2000_SG SG_ALL +#define IN2000 {NULL, NULL, "Always IN2000", in2000_detect, NULL, \ + NULL, in2000_command, \ + in2000_queuecommand, \ + in2000_abort, \ + in2000_reset, \ + NULL, \ + in2000_biosparam, \ + 1, 7, IN2000_SG, 1, 0, 0} + +#endif --- ./drivers/scsi/in2000.c.~1~ Mon Nov 14 14:49:42 1994 +++ ./drivers/scsi/in2000.c Sun Nov 13 12:54:20 1994 @@ -0,0 +1,686 @@ +/* + * This file is in2000.c, written and + * Copyright (C) 1993 Brad McLean + * Last edit 07/19/94 WDE + * Disclaimer: + * Note: This is ugly. I know it, I wrote it, but my whole + * focus was on getting the damn thing up and out quickly. + * Future stuff that would be nice: Command chaining, and + * a local queue of commands would speed stuff up considerably. + * Disconnection needs some supporting code. All of this + * is beyond the scope of what I wanted to address, but if you + * have time and patience, more power to you. + * Also, there are some constants scattered throughout that + * should have defines, and I should have built functions to + * address the registers on the WD chip. + * Oh well, I'm out of time for this project. + * The one good thing to be said is that you can use the card. + */ + +/* + * This module was updated by Shaun Savage first on 5-13-93 + * At that time the write was fixed, irq detection, and some + * timing stuff. since that time other problems were fixed. + * On 7-20-93 this file was updated for patch level 11 + * There are still problems with it but it work on 95% of + * the machines. There are still problems with it working with + * IDE drives, as swap drive and HD that support reselection. + * But for most people it will work. + */ +/* More changes by Bill Earnest, wde@aluxpo.att.com + * through 4/07/94. Includes rewrites of FIFO routines, + * length-limited commands to make swap partitions work. + * Merged the changes released by Larry Doolittle, based on input + * from Jon Luckey, Roger Sunshine, John Shifflett. The FAST_FIFO + * doesn't work for me. Scatter-gather code from Eric. The change to + * an IF stmt. in the interrupt routine finally made it stable. + * Limiting swap request size patch to ll_rw_blk.c not needed now. + * Please ignore the clutter of debug stmts., pretty can come later. + */ +/* Merged code from Matt Postiff improving the auto-sense validation + * for all I/O addresses. Some reports of problems still come in, but + * have been unable to reproduce or localize the cause. Some are from + * LUN > 0 problems, but that is not host specific. Now 6/6/94. + */ +/* Changes for 1.1.28 kernel made 7/19/94, code not affected. (WDE) + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include "../block/blk.h" +#include "scsi.h" +#include "hosts.h" +#include "sd.h" + +#include "in2000.h" + +/*#define FAST_FIFO_IO*/ + +/*#define DEBUG*/ +#ifdef DEBUG +#define DEB(x) x +#else +#define DEB(x) +#endif + +/* These functions are based on include/asm/io.h */ +#ifndef inw +inline static unsigned short inw( unsigned short port ) +{ + unsigned short _v; + + __asm__ volatile ("inw %1,%0" + :"=a" (_v):"d" ((unsigned short) port)); + return _v; +} +#endif + +#ifndef outw +inline static void outw( unsigned short value, unsigned short port ) +{ + __asm__ volatile ("outw %0,%1" + : /* no outputs */ + :"a" ((unsigned short) value), + "d" ((unsigned short) port)); +} +#endif + +/* These functions are lifted from drivers/block/hd.c */ + +#define port_read(port,buf,nr) \ +__asm__("cld;rep;insw": :"d" (port),"D" (buf),"c" (nr):"cx","di") + +#define port_write(port,buf,nr) \ +__asm__("cld;rep;outsw": :"d" (port),"S" (buf),"c" (nr):"cx","si") + +static unsigned int base; +static unsigned int ficmsk; +static unsigned char irq_level; +static int in2000_datalen; +static unsigned int in2000_nsegment; +static unsigned int in2000_current_segment; +static unsigned short *in2000_dataptr; +static char in2000_datawrite; +static struct scatterlist * in2000_scatter; +static Scsi_Cmnd *in2000_SCptr = 0; + +static void (*in2000_done)(Scsi_Cmnd *); + +static int in2000_test_port(int index) +{ + static const int *bios_tab[] = { + (int *) 0xc8000, (int *) 0xd0000, (int *) 0xd8000 }; + int i; + char tmp; + + tmp = inb(INFLED); + /* First, see if the DIP switch values are valid */ + /* The test of B7 may fail on some early boards, mine works. */ + if (((~tmp & 0x3) != index ) || (tmp & 0x80) || !(tmp & 0x4) ) + return 0; + printk("IN-2000 probe got dip setting of %02X\n", tmp); + tmp = inb(INVERS); +/* Add some extra sanity checks here */ + for(i=0; i < 3; i++) + if(*(bios_tab[i]+0x04) == 0x41564f4e) { + printk("IN-2000 probe found hdw. vers. %02x, BIOS at %06x\n", + tmp, (unsigned int)bios_tab[i]); + return 1; + } + printk("in2000 BIOS not found.\n"); + return 0; +} + + +/* + * retreive the current transaction counter from the WD + */ + +static unsigned in2000_txcnt(void) +{ + unsigned total=0; + + if(inb(INSTAT) & 0x20) return 0xffffff; /* not readable now */ + outb(TXCNTH,INSTAT); /* then autoincrement */ + total = (inb(INDATA) & 0xff) << 16; + outb(TXCNTM,INSTAT); + total += (inb(INDATA) & 0xff) << 8; + outb(TXCNTL,INSTAT); + total += (inb(INDATA) & 0xff); + return total; +} + +/* + * Note: the FIFO is screwy, and has a counter granularity of 16 bytes, so + * we have to reconcile the FIFO counter, the transaction byte count from the + * WD chip, and of course, our desired transaction size. It may look strange, + * and could probably use improvement, but it works, for now. + */ + +static void in2000_fifo_out(void) /* uses FIFOCNTR */ +{ + unsigned count, infcnt, txcnt; + + infcnt = inb(INFCNT)& 0xfe; /* FIFO counter */ + do { + txcnt = in2000_txcnt(); +/*DEB(printk("FIw:%d %02x %d\n", in2000_datalen, infcnt, txcnt));*/ + count = (infcnt << 3) - 32; /* dont fill completely */ + if ( count > in2000_datalen ) + count = in2000_datalen; /* limit to actual data on hand */ + count >>= 1; /* Words, not bytes */ +#ifdef FAST_FIFO_IO + if ( count ) { + port_write(INFIFO, in2000_dataptr, count); + in2000_datalen -= (count<<1); + } +#else + while ( count-- ) + { + outw(*in2000_dataptr++, INFIFO); + in2000_datalen -= 2; + } +#endif + } while((in2000_datalen > 0) && ((infcnt = (inb(INFCNT)) & 0xfe) >= 0x20) ); + /* If scatter-gather, go on to next segment */ + if( !in2000_datalen && in2000_current_segment < in2000_nsegment) + { + in2000_scatter++; + in2000_current_segment++; + in2000_datalen = in2000_scatter->length; + in2000_dataptr = (unsigned short*)in2000_scatter->address; + } + if ( in2000_datalen <= 0 ) + { + ficmsk = 0; + count = 32; /* Always says to use this much flush */ + while ( count-- ) + outw(0, INFIFO); + outb(2, ININTR); /* Mask FIFO Interrupts when done */ + } +} + +static void in2000_fifo_in(void) /* uses FIFOCNTR */ +{ + unsigned fic, count, count2; + + count = inb(INFCNT) & 0xe1; + do{ + count2 = count; + count = (fic = inb(INFCNT)) & 0xe1; + } while ( count != count2 ); +DEB(printk("FIir:%d %02x %08x\n", in2000_datalen,fic,(unsigned int )in2000_dataptr)); + do { + count2 = in2000_txcnt(); /* bytes yet to come over SCSI bus */ +DEB(printk("FIr:%d %02x %08x %08x\n", in2000_datalen,fic,count2,(unsigned int)in2000_dataptr)); + if(count2 > 65536) count2 = 0; + if(fic > 128) count = 1024; + else if(fic > 64) count = 512; + else if (fic > 32) count = 256; + else if ( count2 < in2000_datalen ) /* if drive has < what we want */ + count = in2000_datalen - count2; /* FIFO has the rest */ + if ( count > in2000_datalen ) /* count2 is lesser of FIFO & rqst */ + count2 = in2000_datalen >> 1; /* converted to word count */ + else + count2 = count >> 1; + count >>= 1; /* also to words */ + count -= count2; /* extra left over in FIFO */ +#ifdef FAST_FIFO_IO + if ( count2 ) { + port_read(INFIFO, in2000_dataptr, count2); + in2000_datalen -= (count2<<1); + } +#else + while ( count2-- ) + { + *in2000_dataptr++ = inw(INFIFO); + in2000_datalen -=2; + } +#endif + } while((in2000_datalen > 0) && (fic = inb(INFCNT)) ); +DEB(printk("FIer:%d %02x %08x\n", in2000_datalen,fic,(unsigned int )in2000_dataptr)); +/* while ( count-- ) + inw(INFIFO);*/ /* Throw away some extra stuff */ + if( !in2000_datalen && in2000_current_segment < in2000_nsegment) + { + in2000_scatter++; + in2000_current_segment++; + in2000_datalen = in2000_scatter->length; + in2000_dataptr = (unsigned short*)in2000_scatter->address; + } + if ( ! in2000_datalen ){ + outb(2, ININTR); /* Mask FIFO Interrupts when done */ + ficmsk = 0;} +} + +static void in2000_intr_handle(int foo) +{ + int result=0; + unsigned int count,auxstatus,scsistatus,cmdphase,scsibyte; + int action=0; + Scsi_Cmnd *SCptr; + + DEB(printk("INT:%d %02x %08x\n", in2000_datalen, inb(INFCNT),(unsigned int)in2000_dataptr)); + + if (( (ficmsk & (count = inb(INFCNT))) == 0xfe ) || + ( (inb(INSTAT) & 0x8c) == 0x80)) + { /* FIFO interrupt or WD interrupt */ + auxstatus = inb(INSTAT); /* need to save now */ + outb(SCSIST,INSTAT); + scsistatus = inb(INDATA); /* This clears the WD intrpt bit */ + outb(TARGETU,INSTAT); /* then autoincrement */ + scsibyte = inb(INDATA); /* Get the scsi status byte */ + outb(CMDPHAS,INSTAT); + cmdphase = inb(INDATA); + DEB(printk("(int2000:%02x %02x %02x %02x %02x)\n",count,auxstatus, + scsistatus,cmdphase,scsibyte)); + + /* Why do we assume that we need to send more data here??? ERY */ + if ( in2000_datalen && in2000_dataptr ) /* data xfer pending */ + { + if ( in2000_datawrite ) + in2000_fifo_out(); + else + in2000_fifo_in(); + } else ficmsk = 0; + if ( (auxstatus & 0x8c) == 0x80 ) + { /* There is a WD Chip interrupt & register read good */ + outb(2,ININTR); /* Disable fifo interrupts */ + ficmsk = 0; + result = DID_OK << 16; + /* 16=Select & transfer complete, 85=got disconnect */ + if ((scsistatus != 0x16) && (scsistatus != 0x85) + && (scsistatus != 0x42)){ +/* printk("(WDi2000:%02x %02x %02x %02x %02x)\n",count,auxstatus, + scsistatus,cmdphase,scsibyte);*/ +/* printk("QDAT:%d %08x %02x\n", + in2000_datalen,(unsigned int)in2000_dataptr,ficmsk);*/ + ; + } + switch ( scsistatus & 0xf0 ) + { + case 0x00: /* Card Reset Completed */ + action = 3; + break; + case 0x10: /* Successful Command Completion */ + if ( scsistatus & 0x8 ) + action = 1; + break; + case 0x20: /* Command Paused or Aborted */ + if ( (scsistatus & 0x8) ) + action = 1; + else if ( (scsistatus & 7) < 2 ) + action = 2; + else + result = DID_ABORT << 16; + break; + case 0x40: /* Terminated early */ + if ( scsistatus & 0x8 ) + action = 1; + else if ( (scsistatus & 7) > 2 ) + action = 2; + else + result = DID_TIME_OUT << 16; + break; + case 0x80: /* Service Required from SCSI bus */ + if ( scsistatus & 0x8 ) + action = 1; + else + action = 2; + break; + } /* end switch(scsistatus) */ + outb(0,INFLED); + switch ( action ) + { + case 0x02: /* Issue an abort */ + outb(COMMAND,INSTAT); + outb(1,INDATA); /* ABORT COMMAND */ + result = DID_ABORT << 16; + case 0x00: /* Basically all done */ + if ( ! in2000_SCptr ) + return; + in2000_SCptr->result = result | scsibyte; + SCptr = in2000_SCptr; + in2000_SCptr = 0; + if ( in2000_done ) + (*in2000_done)(SCptr); + break; + case 0x01: /* We need to reissue a command */ + outb(CMDPHAS,INSTAT); + switch ( scsistatus & 7 ) + { + case 0: /* Data out phase */ + case 1: /* Data in phase */ + case 4: /* Unspec info out phase */ + case 5: /* Unspec info in phase */ + case 6: /* Message in phase */ + case 7: /* Message in phase */ + outb(0x41,INDATA); /* rdy to disconn */ + break; + case 2: /* command phase */ + outb(0x30,INDATA); /* rdy to send cmd bytes */ + break; + case 3: /* status phase */ + outb(0x45,INDATA); /* To go to status phase,*/ + outb(TXCNTH,INSTAT); /* elim. data, autoinc */ + outb(0,INDATA); + outb(0,INDATA); + outb(0,INDATA); + in2000_datalen = 0; + in2000_dataptr = 0; + break; + } /* end switch(scsistatus) */ + outb(COMMAND,INSTAT); + outb(8,INDATA); /* RESTART THE COMMAND */ + break; + case 0x03: /* Finish up a Card Reset */ + outb(TIMEOUT,INSTAT); /* I got these values */ + /* by reverse Engineering */ + outb(IN2000_TMOUT,INDATA); /* the Always' bios. */ + outb(CONTROL,INSTAT); + outb(0,INDATA); + outb(SYNCTXR,INSTAT); + outb(0x40,INDATA); /* async, 4 cyc xfer per. */ + break; + } /* end switch(action) */ + } /* end if auxstatus for WD int */ + } /* end while intrpt active */ +} + +static int in2000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) +{ + unchar direction; + unchar *cmd = (unchar *) SCpnt->cmnd; + unchar target = SCpnt->target; + void *buff = SCpnt->request_buffer; + int bufflen = SCpnt->request_bufflen; + int timeout, size, loop; + int i; + + /* + * This SCSI command has no data phase, but unfortunately the mid-level + * SCSI drivers ask for 256 bytes of data xfer. Our card hangs if you + * do this, so we protect against it here. It would be nice if the mid- + * level could be changed, but who knows if that would break other host + * adapter drivers. + */ + if ( *cmd == TEST_UNIT_READY ) + bufflen = 0; + + /* + * What it looks like. Boy did I get tired of reading it's output. + */ + if (*cmd == READ_10 || *cmd == WRITE_10) { + i = xscsi2int((cmd+1)); + } else if (*cmd == READ_6 || *cmd == WRITE_6) { + i = scsi2int((cmd+1)); + } else { + i = -1; + } +#ifdef DEBUG + printk("in2000qcmd: pos %d len %d ", i, bufflen); + printk("scsi cmd:"); + for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]); + printk("\n"); +#endif + direction = 1; /* assume for most commands */ + if (*cmd == WRITE_10 || *cmd == WRITE_6) + direction = 0; + size = SCpnt->cmd_len; /* CDB length */ + /* + * Setup our current pointers + * This is where you would allocate a control structure in a queue, + * If you were going to upgrade this to do multiple issue. + * Note that datalen and dataptr exist because we can change the + * values during the course of the operation, while managing the + * FIFO. + * Note the nasty little first clause. In theory, the mid-level + * drivers should never hand us more than one command at a time, + * but just in case someone gets cute in configuring the driver, + * we'll protect them, although not very politely. + */ + if ( in2000_SCptr ) + { + printk("in2000_queue_command waiting for free command block!\n"); + while ( in2000_SCptr ); + } + for ( timeout = jiffies + 5; timeout > jiffies; ) + { + if ( ! ( inb(INSTAT) & 0xb0 ) ) + { + timeout = 0; + break; + } + else + { + inb(INSTAT); + outb(SCSIST,INSTAT); + inb(INDATA); + outb(TARGETU,INSTAT); /* then autoinc */ + inb(INDATA); + inb(INDATA); + } + } + if ( timeout ) + { + printk("in2000_queue_command timeout!\n"); + SCpnt->result = DID_TIME_OUT << 16; + (*done)(SCpnt); + return 1; + } + /* Added for scatter-gather support */ + in2000_nsegment = SCpnt->use_sg; + in2000_current_segment = 0; + if(SCpnt->use_sg){ + in2000_scatter = (struct scatterlist *) buff; + in2000_datalen = in2000_scatter->length; + in2000_dataptr = (unsigned short*)in2000_scatter->address; + } else { + in2000_scatter = NULL; + in2000_datalen = bufflen; + in2000_dataptr = (unsigned short*) buff; + }; + in2000_done = done; + in2000_SCptr = SCpnt; + /* + * Write the CDB to the card, then the LUN, the length, and the target. + */ + outb(TOTSECT, INSTAT); /* start here then autoincrement */ + for ( loop=0; loop < size; loop++ ) + outb(cmd[loop],INDATA); + outb(TARGETU,INSTAT); + outb(SCpnt->lun & 7,INDATA); + SCpnt->host_scribble = NULL; + outb(TXCNTH,INSTAT); /* then autoincrement */ + outb(bufflen>>16,INDATA); + outb(bufflen>>8,INDATA); + outb(bufflen,INDATA); + outb(target&7,INDATA); + /* + * Set up the FIFO + */ + cli(); /* so FIFO init waits till WD set */ + outb(0,INFRST); + if ( direction == 1 ) + { + in2000_datawrite = 0; + outb(0,INFWRT); + } + else + { + in2000_datawrite = 1; + for ( loop=16; --loop; ) /* preload the outgoing fifo */ + { + outw(*in2000_dataptr++,INFIFO); + if(in2000_datalen > 0) in2000_datalen-=2; + } + } + ficmsk = 0xff; + /* + * Start it up + */ + outb(CONTROL,INSTAT); /* WD BUS Mode */ + outb(0x4C,INDATA); + if ( in2000_datalen ) /* if data xfer cmd */ + outb(0,ININTR); /* Enable FIFO intrpt some boards? */ + outb(COMMAND,INSTAT); + outb(0,INNLED); + outb(8,INDATA); /* Select w/ATN & Transfer */ + sti(); /* let the intrpt rip */ + return 0; +} + +static volatile int internal_done_flag = 0; +static volatile int internal_done_errcode = 0; + +static void internal_done(Scsi_Cmnd * SCpnt) +{ + internal_done_errcode = SCpnt->result; + ++internal_done_flag; +} + +static int in2000_command(Scsi_Cmnd * SCpnt) +{ + in2000_queuecommand(SCpnt, internal_done); + + while (!internal_done_flag); + internal_done_flag = 0; + return internal_done_errcode; +} + +static int in2000_detect(Scsi_Host_Template * tpnt) +{ +/* Order chosen to reduce conflicts with some multi-port serial boards */ + int base_tab[] = { 0x220,0x200,0x110,0x100 }; + int int_tab[] = { 15,14,11,10 }; + struct Scsi_Host * shpnt; + int loop, tmp; + + DEB(printk("in2000_detect: \n")); + + for ( loop=0; loop < 4; loop++ ) + { + base = base_tab[loop]; + if ( in2000_test_port(loop)) break; + } + if ( loop == 4 ) + return 0; + + /* Read the dip switch values again for miscellaneous checking and + informative messages */ + tmp = inb(INFLED); + + /* Bit 2 tells us if interrupts are disabled */ + if ( (tmp & 0x4) == 0 ) { + printk("The IN-2000 is not configured for interrupt operation\n"); + printk("Change the DIP switch settings to enable interrupt operation\n"); + } + + /* Bit 6 tells us about floppy controller */ + printk("IN-2000 probe found floppy controller on IN-2000 "); + if ( (tmp & 0x40) == 0) + printk("enabled\n"); + else + printk("disabled\n"); + + /* Bit 5 tells us about synch/asynch mode */ + printk("IN-2000 probe found IN-2000 in "); + if ( (tmp & 0x20) == 0) + printk("synchronous mode\n"); + else + printk("asynchronous mode\n"); + + irq_level = int_tab [ ((~inb(INFLED)>>3)&0x3) ]; + + printk("Configuring IN2000 at IO:%x, IRQ %d" +#ifdef FAST_FIFO_IO + " (using fast FIFO I/O code)" +#endif + "\n",base, irq_level); + + outb(2,ININTR); /* Shut off the FIFO first, so it won't ask for data.*/ + if (request_irq(irq_level,in2000_intr_handle, 0, "in2000")) + { + printk("in2000_detect: Unable to allocate IRQ.\n"); + return 0; + } + outb(0,INFWRT); /* read mode so WD can intrpt */ + outb(SCSIST,INSTAT); + inb(INDATA); /* free status reg, clear WD intrpt */ + outb(OWNID,INSTAT); + outb(0x7,INDATA); /* we use addr 7 */ + outb(COMMAND,INSTAT); + outb(0,INDATA); /* do chip reset */ + shpnt = scsi_register(tpnt, 0); + /* Set these up so that we can unload the driver properly. */ + shpnt->io_port = base; + shpnt->n_io_port = 12; + shpnt->irq = irq_level; + snarf_region(base, 12); /* Prevent other drivers from using this space */ + return 1; +} + +static int in2000_abort(Scsi_Cmnd * SCpnt) +{ + DEB(printk("in2000_abort\n")); + /* + * Ask no stupid questions, just order the abort. + */ + outb(COMMAND,INSTAT); + outb(1,INDATA); /* Abort Command */ + return 0; +} + +static inline void delay( unsigned how_long ) +{ + unsigned long time = jiffies + how_long; + while (jiffies < time) ; +} + +static int in2000_reset(Scsi_Cmnd * SCpnt) +{ + DEB(printk("in2000_reset called\n")); + /* + * Note: this is finished off by an incoming interrupt + */ + outb(0,INFWRT); /* read mode so WD can intrpt */ + outb(SCSIST,INSTAT); + inb(INDATA); + outb(OWNID,INSTAT); + outb(0x7,INDATA); /* ID=7,noadv, no parity, clk div=2 (8-10Mhz clk) */ + outb(COMMAND,INSTAT); + outb(0,INDATA); /* reset WD chip */ + delay(2); +#ifdef SCSI_RESET_PENDING + return SCSI_RESET_PENDING; +#else + if(SCpnt) SCpnt->flags |= NEEDS_JUMPSTART; + return 0; +#endif +} + +static int in2000_biosparam(Disk * disk, int dev, int* iinfo) + { + int size = disk->capacity; + DEB(printk("in2000_biosparam\n")); + iinfo[0] = 64; + iinfo[1] = 32; + iinfo[2] = size >> 11; + return 0; + } + +#ifdef MODULE +/* Eventually this will go into an include file, but this will be later */ +Scsi_Host_Template driver_template = IN2000; + +#include "scsi_module.c" +#endif + --- ./drivers/scsi/sr.c.~1~ Sun Nov 13 12:46:45 1994 +++ ./drivers/scsi/sr.c Tue Nov 15 20:43:16 1994 @@ -34,13 +34,14 @@ static void sr_init(void); static void sr_finish(void); -static void sr_attach(Scsi_Device *); +static int sr_attach(Scsi_Device *); static int sr_detect(Scsi_Device *); +static void sr_detach(Scsi_Device *); struct Scsi_Device_Template sr_template = {NULL, "cdrom", "sr", TYPE_ROM, SCSI_CDROM_MAJOR, 0, 0, 0, 1, sr_detect, sr_init, - sr_finish, sr_attach, NULL}; + sr_finish, sr_attach, sr_detach}; Scsi_CD * scsi_CDs; static int * sr_sizes; @@ -60,6 +61,8 @@ sync_dev(inode->i_rdev); if(! --scsi_CDs[MINOR(inode->i_rdev)].device->access_count) sr_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0); + if (scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count) + (*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)--; } static struct file_operations sr_fops = @@ -283,6 +286,8 @@ if(!scsi_CDs[MINOR(inode->i_rdev)].device->access_count++) sr_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0); + if (scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count) + (*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)++; /* If this device did not have media in the drive at boot time, then we would have been unable to get the sector size. Check to see if @@ -649,8 +654,6 @@ static int sr_detect(Scsi_Device * SDp){ - /* We do not support attaching loadable devices yet. */ - if(scsi_loadable_module_flag) return 0; if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 0; printk("Detected scsi CD-ROM sr%d at scsi%d, id %d, lun %d\n", @@ -660,17 +663,17 @@ return 1; } -static void sr_attach(Scsi_Device * SDp){ +static int sr_attach(Scsi_Device * SDp){ Scsi_CD * cpnt; int i; - /* We do not support attaching loadable devices yet. */ + if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 1; - if(scsi_loadable_module_flag) return; - if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return; - if (sr_template.nr_dev >= sr_template.dev_max) - panic ("scsi_devices corrupt (sr)"); + { + SDp->attached--; + return 1; + } for(cpnt = scsi_CDs, i=0; idevice) break; @@ -682,8 +685,25 @@ sr_template.nr_dev++; if(sr_template.nr_dev > sr_template.dev_max) panic ("scsi_devices corrupt (sr)"); + return 0; } +static void sr_detach(Scsi_Device * SDp) +{ + Scsi_CD * cpnt; + int i; + + for(cpnt = scsi_CDs, i=0; idevice == SDp) { + cpnt->device = NULL; + SDp->attached--; + sr_template.nr_dev--; + sr_template.dev_noticed--; + sr_sizes[i] = 0; + return; + } + return; +} static void sr_init_done (Scsi_Cmnd * SCpnt) { @@ -699,16 +719,18 @@ static void get_sectorsize(int i){ unsigned char cmd[10]; - unsigned char buffer[513]; + unsigned char *buffer; int the_result, retries; Scsi_Cmnd * SCpnt; SCpnt = allocate_device(NULL, scsi_CDs[i].device, 1); + buffer = (unsigned char *) scsi_malloc(512); retries = 3; do { cmd[0] = READ_CAPACITY; cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0; + SCpnt->cmd_len = 0; memset ((void *) &cmd[2], 0, 8); SCpnt->request.dev = 0xffff; /* Mark as really busy */ @@ -760,6 +782,7 @@ scsi_CDs[i].capacity *= 4; scsi_CDs[i].needs_sector_size = 0; }; + scsi_free(buffer, 512); } static void sr_init() @@ -774,20 +797,19 @@ printk("Unable to get major %d for SCSI-CD\n",MAJOR_NR); return; } + sr_registered++; } - - /* We do not support attaching loadable devices yet. */ - if(scsi_loadable_module_flag) return; - - sr_template.dev_max = sr_template.dev_noticed; - scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD)); + + if (scsi_CDs) return; + sr_template.dev_max = sr_template.dev_noticed + SR_EXTRA_DEVS; + scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC); memset(scsi_CDs, 0, sr_template.dev_max * sizeof(Scsi_CD)); - sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int)); + sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC); memset(sr_sizes, 0, sr_template.dev_max * sizeof(int)); sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max * - sizeof(int)); + sizeof(int), GFP_ATOMIC); for(i=0;ihost->sg_tablesize) + if(scsi_CDs[0].device && scsi_CDs[0].device->host->sg_tablesize) read_ahead[MAJOR_NR] = 32; /* 32 sector read-ahead. Always removable. */ else read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */ --- ./drivers/scsi/sg.c.~1~ Sun Nov 13 12:46:45 1994 +++ ./drivers/scsi/sg.c Sun Nov 13 12:54:21 1994 @@ -26,14 +26,15 @@ #include "sg.h" static void sg_init(void); -static void sg_attach(Scsi_Device *); +static int sg_attach(Scsi_Device *); static int sg_detect(Scsi_Device *); +static void sg_detach(Scsi_Device *); struct Scsi_Device_Template sg_template = {NULL, NULL, "sg", 0xff, SCSI_GENERIC_MAJOR, 0, 0, 0, 0, sg_detect, sg_init, - NULL, sg_attach, NULL}; + NULL, sg_attach, sg_detach}; #ifdef SG_BIG_BUFF static char *big_buff; @@ -113,6 +114,8 @@ } if (!scsi_generics[dev].users) scsi_generics[dev].timeout=SG_DEFAULT_TIMEOUT; + if (scsi_generics[dev].device->host->hostt->usage_count) + (*scsi_generics[dev].device->host->hostt->usage_count)++; scsi_generics[dev].users++; return 0; } @@ -121,6 +124,8 @@ { int dev=MINOR(inode->i_rdev); scsi_generics[dev].users--; + if (scsi_generics[dev].device->host->hostt->usage_count) + (*scsi_generics[dev].device->host->hostt->usage_count)--; scsi_generics[dev].exclude=0; wake_up(&scsi_generics[dev].generic_wait); } @@ -220,6 +225,7 @@ int dev=MINOR(inode->i_rdev); Scsi_Cmnd *SCpnt; int bsize,size,amt,i; + unsigned char opcode; unsigned char cmnd[MAX_COMMAND_SIZE]; struct scsi_generic *device=&scsi_generics[dev]; @@ -273,7 +279,10 @@ /* now issue command */ SCpnt->request.dev=dev; SCpnt->sense_buffer[0]=0; - size=COMMAND_SIZE(get_fs_byte(buf)); + opcode = get_fs_byte(buf); + size=COMMAND_SIZE(opcode); + if (opcode >= 0xc0 && device->header.twelve_byte) size = 12; + SCpnt->cmd_len = size; memcpy_fromfs(cmnd,buf,size); buf+=size; memcpy_fromfs(device->buff,buf,device->header.pack_len-size-sizeof(struct sg_header)); @@ -305,7 +314,6 @@ static int sg_detect(Scsi_Device * SDp){ /* We do not support attaching loadable devices yet. */ - if(scsi_loadable_module_flag) return 0; ++sg_template.dev_noticed; return 1; @@ -328,33 +336,37 @@ sg_registered++; } - /* We do not support attaching loadable devices yet. */ - if(scsi_loadable_module_flag) return; + /* If we have already been through here, return */ + if(scsi_generics) return; + #ifdef DEBUG printk("sg: Init generic device.\n"); #endif #ifdef SG_BIG_BUFF - big_buff= (char *) scsi_init_malloc(SG_BIG_BUFF); + big_buff= (char *) scsi_init_malloc(SG_BIG_BUFF, GFP_ATOMIC | GFP_DMA); #endif scsi_generics = (struct scsi_generic *) - scsi_init_malloc(sg_template.dev_noticed * sizeof(struct scsi_generic)); - memset(scsi_generics, 0, sg_template.dev_noticed * sizeof(struct scsi_generic)); + scsi_init_malloc((sg_template.dev_noticed + SG_EXTRA_DEVS) + * sizeof(struct scsi_generic), GFP_ATOMIC); + memset(scsi_generics, 0, (sg_template.dev_noticed + SG_EXTRA_DEVS) + * sizeof(struct scsi_generic)); - sg_template.dev_max = sg_template.dev_noticed; + sg_template.dev_max = sg_template.dev_noticed + SG_EXTRA_DEVS; } -static void sg_attach(Scsi_Device * SDp) +static int sg_attach(Scsi_Device * SDp) { struct scsi_generic * gpnt; int i; - /* We do not support attaching loadable devices yet. */ - if(scsi_loadable_module_flag) return; - + /* If we have filled up all of our slots, do not attempt to attach */ if(sg_template.nr_dev >= sg_template.dev_max) - panic ("scsi_devices corrupt (sg)"); + { + SDp->attached--; + return 1; + } for(gpnt = scsi_generics, i=0; idevice) break; @@ -370,4 +382,20 @@ scsi_generics[i].pending=0; scsi_generics[i].timeout=SG_DEFAULT_TIMEOUT; sg_template.nr_dev++; + return 0; }; + +static void sg_detach(Scsi_Device * SDp) +{ + struct scsi_generic * gpnt; + int i; + + for(gpnt = scsi_generics, i=0; idevice == SDp) { + gpnt->device = NULL; + SDp->attached--; + sg_template.nr_dev--; + return; + } + return; +} --- ./drivers/scsi/st.c.~1~ Sun Nov 13 12:50:03 1994 +++ ./drivers/scsi/st.c Tue Nov 15 16:38:54 1994 @@ -86,13 +86,14 @@ static Scsi_Tape * scsi_tapes; static void st_init(void); -static void st_attach(Scsi_Device *); +static int st_attach(Scsi_Device *); static int st_detect(Scsi_Device *); +static void st_detach(Scsi_Device *); struct Scsi_Device_Template st_template = {NULL, "tape", "st", TYPE_TAPE, SCSI_TAPE_MAJOR, 0, 0, 0, 0, st_detect, st_init, - NULL, st_attach, NULL}; + NULL, st_attach, st_detach}; static int st_int_ioctl(struct inode * inode,struct file * file, unsigned int cmd_in, unsigned long arg); @@ -405,6 +406,7 @@ printk("st%d: No free buffers.\n", dev); return (-EBUSY); } + STp->buffer = st_buffers[i]; (STp->buffer)->in_use = 1; (STp->buffer)->writing = 0; @@ -577,6 +579,9 @@ #endif } + if (scsi_tapes[dev].device->host->hostt->usage_count) + (*scsi_tapes[dev].device->host->hostt->usage_count)++; + return 0; } @@ -654,6 +659,9 @@ (STp->buffer)->in_use = 0; STp->in_use = 0; + if (scsi_tapes[dev].device->host->hostt->usage_count) + (*scsi_tapes[dev].device->host->hostt->usage_count)--; + return; } @@ -1748,17 +1756,19 @@ NULL /* fsync */ }; -static void st_attach(Scsi_Device * SDp){ +static int st_attach(Scsi_Device * SDp){ Scsi_Tape * tpnt; int i; /* We do not support attaching loadable devices yet. */ - if(scsi_loadable_module_flag) return; - if(SDp->type != TYPE_TAPE) return; + if(SDp->type != TYPE_TAPE) return 1; if(st_template.nr_dev >= st_template.dev_max) - panic ("scsi_devices corrupt (st)"); - + { + SDp->attached--; + return 1; + } + for(tpnt = scsi_tapes, i=0; idevice) break; @@ -1765,13 +1775,18 @@ if(i >= st_template.dev_max) panic ("scsi_devices corrupt (st)"); scsi_tapes[i].device = SDp; + + if (SDp->scsi_level <= 2) + scsi_tapes[i].mt_status->mt_type = MT_ISSCSI1; + else + scsi_tapes[i].mt_status->mt_type = MT_ISSCSI2; + st_template.nr_dev++; + return 0; }; static int st_detect(Scsi_Device * SDp){ - /* We do not support attaching loadable devices yet. */ - if(scsi_loadable_module_flag) return 0; if(SDp->type != TYPE_TAPE) return 0; printk("Detected scsi tape st%d at scsi%d, id %d, lun %d\n", @@ -1800,11 +1815,12 @@ } /* We do not support attaching loadable devices yet. */ - if(scsi_loadable_module_flag) return; + if(scsi_tapes) return; - scsi_tapes = (Scsi_Tape *) scsi_init_malloc(st_template.dev_noticed * - sizeof(Scsi_Tape)); - st_template.dev_max = st_template.dev_noticed; + scsi_tapes = (Scsi_Tape *) scsi_init_malloc( + (st_template.dev_noticed + ST_EXTRA_DEVS) * + sizeof(Scsi_Tape), GFP_ATOMIC); + st_template.dev_max = st_template.dev_noticed + ST_EXTRA_DEVS; #ifdef DEBUG printk("st: Buffer size %d bytes, write threshold %d bytes.\n", @@ -1811,7 +1827,7 @@ st_buffer_size, st_write_threshold); #endif - for (i=0, SDp = scsi_devices; i < st_template.dev_noticed; ++i) { + for (i=0; i < st_template.dev_max; ++i) { STp = &(scsi_tapes[i]); STp->device = NULL; STp->capacity = 0xfffff; @@ -1829,21 +1845,9 @@ STp->write_threshold = st_write_threshold; STp->drv_block = 0; STp->moves_after_eof = 1; - STp->mt_status = (struct mtget *) scsi_init_malloc(sizeof(struct mtget)); + STp->mt_status = (struct mtget *) scsi_init_malloc(sizeof(struct mtget), GFP_ATOMIC); /* Initialize status */ memset((void *) scsi_tapes[i].mt_status, 0, sizeof(struct mtget)); - for (; SDp; SDp = SDp->next) - if (SDp->type == TYPE_TAPE) - break; - if (!SDp) - printk("st%d: ERROR: Not found in scsi chain.\n", i); - else { - if (SDp->scsi_level <= 2) - STp->mt_status->mt_type = MT_ISSCSI1; - else - STp->mt_status->mt_type = MT_ISSCSI2; - } - SDp = SDp->next; } /* Allocate the buffers */ @@ -1851,10 +1855,15 @@ if (st_nbr_buffers > st_max_buffers) st_nbr_buffers = st_max_buffers; st_buffers = (ST_buffer **) scsi_init_malloc(st_nbr_buffers * - sizeof(ST_buffer *)); + sizeof(ST_buffer *), GFP_ATOMIC); + /* FIXME - if we are hitting this because we are loading a tape module + as a loadable driver, we should not use kmalloc - it will allocate + a 64Kb region in order to buffer about 32Kb. Try using 31 blocks + instead. */ + for (i=0; i < st_nbr_buffers; i++) { st_buffers[i] = (ST_buffer *) scsi_init_malloc(sizeof(ST_buffer) - - 1 + st_buffer_size); + 1 + st_buffer_size, GFP_ATOMIC | GFP_DMA); #ifdef DEBUG /* printk("st: Buffer address: %p\n", st_buffers[i]); */ #endif @@ -1863,3 +1872,21 @@ } return; } + +static void st_detach(Scsi_Device * SDp) +{ + Scsi_Tape * tpnt; + int i; + + for(tpnt = scsi_tapes, i=0; idevice == SDp) { + tpnt->device = NULL; + SDp->attached--; + st_template.nr_dev--; + st_template.dev_noticed--; + return; + } + return; +} + + --- ./drivers/scsi/sg.h.~1~ Sun Nov 13 12:46:46 1994 +++ ./drivers/scsi/sg.h Sun Nov 13 12:54:21 1994 @@ -17,7 +17,8 @@ int reply_len; /* maximum length <4096 of expected reply */ int pack_id; /* id number of packet */ int result; /* 0==ok, otherwise refer to errno codes */ - int flags; /* for future use */ + unsigned int twelve_byte:1; /* Force 12 byte command length for group 6 & 7 commands */ + unsigned int other_flags:31; /* for future use */ unsigned char sense_buffer[16]; /* used only by reads */ /* command follows then data for command */ }; --- ./drivers/scsi/ChangeLog.new.~1~ Sun Nov 13 12:46:48 1994 +++ ./drivers/scsi/ChangeLog.new Sun Nov 13 12:54:29 1994 @@ -1,3 +1,74 @@ +Wed Oct 26 20:04:13 1994 Eric Youngdale (eric@andante) + + Patches to add more support for low-level loadable scsi drivers. + Only scsi_debug can be loaded, and the "devices" are accessible only + through the scsi_generics driver. Rest should be relatively easy. + + * st.c: Patches from Kai - return more status bits in the MTIOCGET ioctl. + + * sg.c: Add support for 12 byte commands in the vendor specific group 6 + and 7 commands. + + * sg.c: Add support for attach/detach as we load and unload low-level drivers + at runtime. + + * sg.c, sr.c, sd.c, st.c: Change s?_attach.c to return an int. + + * sd.c: Add a little idiot checking before we examine rscsi_disks[0], + and prevent kernel mode segfault.(used where we bump read-ahead if sg capable) + + * Throughout: Change info function to accept Scsi_Host * argument. Thus we + can return information that is specific to the host adapter. + + * All low-level drivers: Add NULL in initializers for host template - holds + usage count used in loadable modules. + + * hosts.h: Add cmd_per_lun in Scsi_Host structure. + + * hosts.c: Initialize cmd_per_lun in Scsi_Host structure from host template. + + * scsi.c: Initialize SCpnt->timeout to 0 when we generate command structures. + Only build command structures for which SDpnt->attached != 0. + + * scsi.c (scsi_init_free): Use kfree if ptr > scsi_init_memory_start, not + loadable_module_flag. + + * scsi.c (request_queueable): Change panic messages to print correct function name. + + * scsi.c (scan_scsis): Make global, not static. If we are running after system + is booted, do not use busy waiting - use mutex instead. + + * scsi.c (scan_scsis_done): If request.sem is set, then wake up process + that is waiting. + + * Makefile: Add support for loadable low-level drivers. + + * pas16.c: Remove redundant pas16_info function. Upper level code will use + text string from host template instead. + + * aha1740.c: Likewise. + + * aha152x.c: Likewise. + + * NCR53c7,8xx.c: Likewise (who named this damn file, anyway?). + + * aha1542.c: Likewise. + + * t128.c: Likewise. + + * wd7000.c: Likewise. + + * aha1542.c: Add support for command line boot options to override I/O port, + buson/off, and dma speed. + + * hosts.c: Add functions for loading and unloading a host adapter template. + + * scsi_debug.c: Add support for being loaded as a loadable module. Fake 3 devices + (disk, cdrom and tape). + + * hosts.h: Add macros S?_EXTRA_DEVS. + + Tue Oct 11 08:47:39 1994 Eric Youngdale (eric@andante) * Linux 1.1.54 released. --- ./drivers/scsi/NCR5380.c.~1~ Sun Nov 13 12:46:48 1994 +++ ./drivers/scsi/NCR5380.c Sun Nov 13 12:54:30 1994 @@ -2306,7 +2306,7 @@ msgout = NOP; break; case PHASE_CMDOUT: - len = COMMAND_SIZE(cmd->cmnd[0]); + len = cmd->cmd_len; data = cmd->cmnd; /* * XXX for performance reasons, on machines with a --- ./drivers/scsi/scsi.h.~1~ Sun Nov 13 12:46:48 1994 +++ ./drivers/scsi/scsi.h Sun Nov 13 12:54:30 1994 @@ -420,6 +420,8 @@ struct Scsi_Host * host; Scsi_Device * device; unsigned char target, lun; + unsigned char cmd_len; + unsigned char old_cmd_len; struct scsi_cmnd *next, *prev; /* These elements define the operation we are about to perform */ --- ./drivers/scsi/scsi_module.c.~1~ Sun Nov 13 12:54:30 1994 +++ ./drivers/scsi/scsi_module.c Sun Nov 13 13:27:22 1994 @@ -0,0 +1,49 @@ +/* + * scsi_module.c Copyright (C) 1994 Eric Youngdale + * + * Support for loading low-level scsi drivers using the linux kernel loadable + * module interface. + * + * To use, the host adapter should first define and initialize the variable + * driver_template (datatype Scsi_Host_Template), and then include this file. + * This should also be wrapped in a #ifdef MODULE/#endif. + * + * The low -level driver must also define a release function which will + * free any irq assignments, release any dma channels, release any I/O + * address space that might be reserved, and otherwise clean up after itself. + * The idea is that the same driver should be able to be reloaded without + * any difficulty. This makes debugging new drivers easier, as you should + * be able to load the driver, test it, unload, modify and reload. + * + * One *very* important caveat. If the driver may need to do DMA on the + * ISA bus, you must have unchecked_isa_dma set in the device template, + * even if this might be changed during the detect routine. This is + * because the shpnt structure will be allocated in a special way so that + * it will be below the appropriate DMA limit - thus if your driver uses + * the hostdata field of shpnt, and the board must be able to access this + * via DMA, the shpnt structure must be in a DMA accessible region of + * memory. This comment would be relevant for something like the buslogic + * driver where there are many boards, only some of which do DMA onto the + * ISA bus. There is no convenient way of specifying whether the host + * needs to be in a ISA DMA accessible region of memory when you call + * scsi_register. + */ + +#include +#include "../../tools/version.h" + +char kernel_version[] = UTS_RELEASE; + +int init_module(void) { + driver_template.usage_count = &mod_use_count_; + scsi_register_module(MODULE_SCSI_HA, &driver_template); + return (driver_template.present == 0); +} + +void cleanup_module( void) { + if (MOD_IN_USE) { + printk(KERN_INFO __FILE__ ": module is in use, remove rejected\n"); + } + scsi_unregister_module(MODULE_SCSI_HA, &driver_template); +} + --- ./drivers/scsi/aha274x.h.~1~ Sun Nov 13 12:49:20 1994 +++ ./drivers/scsi/aha274x.h Sun Nov 13 13:17:49 1994 @@ -32,6 +32,7 @@ */ #define AHA274X { \ NULL, \ + NULL, \ "", \ aha274x_detect, \ NULL, \ --- ./modules/cdwrite1.c.~1~ Tue Nov 15 19:49:37 1994 +++ ./modules/cdwrite1.c Tue Nov 15 20:24:49 1994 @@ -127,16 +127,23 @@ } int -capacity (int fd) { +capacity (int fd,int *reply_len, struct sg_reply *rep) { int result; + int answer; int i; char * reply; *reply_len = sizeof( struct sg_reply ); - result = send_request (fd, "capacity", reply_len, rep, 0, + result = send_request (fd, "capacity", reply_len, rep, 10, READ_CAPACITY, /* 0 */ 0,0,0,255,0); - for(i=0; i<8; i++) - printf("%d %x\n", i, rep->bytes[i]); + answer = rep->bytes[3] | (rep->bytes[2] << 8) | (rep->bytes[1] << 16) | + (rep->bytes[0] << 24); + printf("capacity = %d\n ", answer); + + answer = rep->bytes[7] | (rep->bytes[6] << 8) | (rep->bytes[5] << 16) | + (rep->bytes[4] << 24); + + printf("sectorsize = %d\n ", answer); return result; } @@ -220,6 +227,8 @@ /* First make sure we know how to talk to this writer */ inquiry (fd, &reply_len, &reply, &manufacturer[0], &model[0]); + + capacity (fd, &reply_len, &reply); printf("Manufacturer = %s\n", manufacturer); } --- ./config.in.~1~ Sun Nov 13 12:46:49 1994 +++ ./config.in Tue Nov 15 13:19:24 1994 @@ -48,20 +48,20 @@ comment 'SCSI low-level drivers' -bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X y -bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 y -bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 y -bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC y -bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN y -bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 y -bool 'NCR53c7,8xx SCSI support' CONFIG_SCSI_NCR53C7xx y +bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X n +bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 n +bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 n +bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n +bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n +bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n +bool 'NCR53c7,8xx SCSI support' CONFIG_SCSI_NCR53C7xx n #bool 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 n -bool 'PAS16 SCSI support' CONFIG_SCSI_PAS16 y -bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE y -bool 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 y -bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR y -bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST y -#bool 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG n +bool 'PAS16 SCSI support' CONFIG_SCSI_PAS16 n +bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE n +bool 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 n +bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR n +bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST n +bool 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG n fi @@ -76,21 +76,21 @@ else bool 'Dummy net driver support' CONFIG_DUMMY y -bool 'SLIP (serial line) support' CONFIG_SLIP y +bool 'SLIP (serial line) support' CONFIG_SLIP n if [ "$CONFIG_SLIP" = "y" ]; then - bool ' CSLIP compressed headers' SL_COMPRESSED y + bool ' CSLIP compressed headers' SL_COMPRESSED n # bool ' SLIP debugging on' SL_DUMP y fi -bool 'PPP (point-to-point) support' CONFIG_PPP y -bool 'PLIP (parallel port) support' CONFIG_PLIP y -bool 'Load balancing support (experimental)' CONFIG_SLAVE_BALANCING y -bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA y -bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC y +bool 'PPP (point-to-point) support' CONFIG_PPP n +bool 'PLIP (parallel port) support' CONFIG_PLIP n +bool 'Load balancing support (experimental)' CONFIG_SLAVE_BALANCING n +bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA n +bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC n if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then bool 'WD80*3 support' CONFIG_WD80x3 y bool 'SMC Ultra support' CONFIG_ULTRA y fi -bool '3COM cards' CONFIG_NET_VENDOR_3COM y +bool '3COM cards' CONFIG_NET_VENDOR_3COM n if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then bool '3c501 support' CONFIG_EL1 y bool '3c503 support' CONFIG_EL2 n --- ./arch/i386/Makefile.~1~ Sun Nov 13 12:46:49 1994 +++ ./arch/i386/Makefile Sun Nov 13 12:54:30 1994 @@ -30,6 +30,7 @@ zImage: $(CONFIGURE) boot/bootsect boot/setup zBoot/zSystem tools/build tools/build boot/bootsect boot/setup zBoot/zSystem $(ROOT_DEV) > zImage + rdev -R zImage 1 sync zdisk: zImage