diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-04-28 01:09:25 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-04-28 01:09:25 +0000 |
commit | b9ba7aeb165cffecdffb60aec8c3fa8d590d9ca9 (patch) | |
tree | 42d07b0c7246ae2536a702e7c5de9e2732341116 /drivers/scsi/pci2000.c | |
parent | 7406b0a326f2d70ade2671c37d1beef62249db97 (diff) |
Merge with 2.3.99-pre6.
Diffstat (limited to 'drivers/scsi/pci2000.c')
-rw-r--r-- | drivers/scsi/pci2000.c | 197 |
1 files changed, 116 insertions, 81 deletions
diff --git a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c index d111eba9d..94007c5a8 100644 --- a/drivers/scsi/pci2000.c +++ b/drivers/scsi/pci2000.c @@ -29,8 +29,11 @@ * Revisions 1.12 Mar-26-1999 * - Fixed spinlock and PCI configuration. * + * Revisions 1.20 Mar-27-2000 + * - Added support for dynamic DMA + * ****************************************************************************/ -#define PCI2000_VERSION "1.12" +#define PCI2000_VERSION "1.20" #include <linux/module.h> @@ -67,32 +70,37 @@ typedef struct { - ULONG address; - ULONG length; + unsigned int address; + unsigned int length; } SCATGATH, *PSCATGATH; typedef struct { - Scsi_Cmnd *SCpnt; - SCATGATH scatGath[16]; - UCHAR tag; + Scsi_Cmnd *SCpnt; + PSCATGATH scatGath; + dma_addr_t scatGathDma; + UCHAR *cdb; + dma_addr_t cdbDma; + UCHAR tag; } DEV2000, *PDEV2000; typedef struct { - USHORT basePort; - USHORT mb0; - USHORT mb1; - USHORT mb2; - USHORT mb3; - USHORT mb4; - USHORT cmd; - USHORT tag; - ULONG irqOwned; - DEV2000 dev[MAX_BUS][MAX_UNITS]; + ULONG basePort; + ULONG mb0; + ULONG mb1; + ULONG mb2; + ULONG mb3; + ULONG mb4; + ULONG cmd; + ULONG tag; + ULONG irqOwned; + struct pci_dev *pdev; + DEV2000 dev[MAX_BUS][MAX_UNITS]; } ADAPTER2000, *PADAPTER2000; #define HOSTDATA(host) ((PADAPTER2000)&host->hostdata) +#define consistentLen (MAX_BUS * MAX_UNITS * (16 * sizeof (SCATGATH) + MAX_COMMAND_SIZE)) static struct Scsi_Host *PsiHost[MAXADAPTER] = {NULL,}; // One for each adapter @@ -193,20 +201,31 @@ static UCHAR Command (PADAPTER2000 padapter, UCHAR cmd) ****************************************************************/ static int BuildSgList (Scsi_Cmnd *SCpnt, PADAPTER2000 padapter, PDEV2000 pdev) { - int z; + int z; + int zc; + struct scatterlist *sg; if ( SCpnt->use_sg ) { - for ( z = 0; z < SCpnt->use_sg; z++ ) + sg = (struct scatterlist *)SCpnt->request_buffer; + zc = pci_map_sg (padapter->pdev, sg, SCpnt->use_sg, scsi_to_pci_dma_dir (SCpnt->sc_data_direction)); + for ( z = 0; z < zc; z++ ) { - pdev->scatGath[z].address = virt_to_bus (((struct scatterlist *)SCpnt->request_buffer)[z].address); - pdev->scatGath[z].length = ((struct scatterlist *)SCpnt->request_buffer)[z].length; + pdev->scatGath[z].address = cpu_to_le32 (sg_dma_address (sg)); + pdev->scatGath[z].length = cpu_to_le32 (sg_dma_len (sg++)); } - outl (virt_to_bus (pdev->scatGath), padapter->mb2); - outl ((SCpnt->use_sg << 24) | SCpnt->request_bufflen, padapter->mb3); + outl (pdev->scatGathDma, padapter->mb2); + outl ((zc << 24) | SCpnt->request_bufflen, padapter->mb3); return FALSE; } - outl (virt_to_bus (SCpnt->request_buffer), padapter->mb2); + if ( !SCpnt->request_bufflen) + { + outl (0, padapter->mb2); + outl (0, padapter->mb3); + return TRUE; + } + SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer, SCpnt->request_bufflen, scsi_to_pci_dma_dir (SCpnt->sc_data_direction)); + outl (SCpnt->SCp.have_data_in, padapter->mb2); outl (SCpnt->request_bufflen, padapter->mb3); return TRUE; } @@ -254,23 +273,13 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs) int pun; int bus; int z; -#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) - int flags; -#else /* version >= v2.1.95 */ unsigned long flags; -#endif /* version >= v2.1.95 */ -#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) - /* Disable interrupts, if they aren't already disabled. */ - save_flags (flags); - cli (); -#else /* version >= v2.1.95 */ /* * Disable interrupts, if they aren't already disabled and acquire * the I/O spinlock. */ spin_lock_irqsave (&io_request_lock, flags); -#endif /* version >= v2.1.95 */ DEB(printk ("\npci2000 recieved interrupt ")); for ( z = 0; z < NumAdapters; z++ ) // scan for interrupt to process @@ -306,14 +315,39 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs) { pdev->tag = 0; SCpnt = pdev->SCpnt; - goto irqProceed; + goto unmapProceed; } } } outb_p (0xFF, padapter->tag); // clear the op interrupt outb_p (CMD_DONE, padapter->cmd); // complete the op - goto irq_return;; // done, but, with what? + goto irq_return;; // done, but, with what? + +unmapProceed:; + if ( !bus ) + { + switch ( SCpnt->cmnd[0] ) + { + case SCSIOP_TEST_UNIT_READY: + pci_unmap_single (padapter->pdev, SCpnt->SCp.have_data_in, sizeof (SCpnt->sense_buffer), PCI_DMA_FROMDEVICE); + goto irqProceed; + case SCSIOP_READ_CAPACITY: + pci_unmap_single (padapter->pdev, SCpnt->SCp.have_data_in, 8, PCI_DMA_FROMDEVICE); + goto irqProceed; + case SCSIOP_VERIFY: + case SCSIOP_START_STOP_UNIT: + case SCSIOP_MEDIUM_REMOVAL: + goto irqProceed; + } + } + if ( SCpnt->SCp.have_data_in ) + pci_unmap_single (padapter->pdev, SCpnt->SCp.have_data_in, SCpnt->request_bufflen, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + else + { + if ( SCpnt->use_sg ) + pci_unmap_sg (padapter->pdev, (struct scatterlist *)SCpnt->request_buffer, SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + } irqProceed:; if ( tag & ERR08_TAGGED ) // is there an error here? @@ -359,20 +393,12 @@ irqProceed:; OpDone (SCpnt, DID_OK << 16); irq_return:; -#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) - /* - * Restore the original flags which will enable interrupts - * if and only if they were enabled on entry. - */ - restore_flags (flags); -#else /* version >= v2.1.95 */ /* * Release the I/O spinlock and restore the original flags * which will enable interrupts if and only if they were * enabled on entry. */ spin_unlock_irqrestore (&io_request_lock, flags); -#endif /* version >= v2.1.95 */ } /**************************************************************** * Name: Pci2000_QueueCommand @@ -403,6 +429,7 @@ int Pci2000_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) } SCpnt->scsi_done = done; + SCpnt->SCp.have_data_in = 0; pdev->SCpnt = SCpnt; // Save this command data if ( WaitReady (padapter) ) @@ -428,7 +455,9 @@ int Pci2000_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) outw_p (pun | (lun << 8), padapter->mb0); outw_p (SCpnt->cmd_len << 8, padapter->mb0 + 2); - outl (virt_to_bus (cdb), padapter->mb1); + memcpy (pdev->cdb, cdb, MAX_COMMAND_SIZE); + + outl (pdev->cdbDma, padapter->mb1); if ( BuildSgList (SCpnt, padapter, pdev) ) cmd = CMD_SCSI_THRU; else @@ -469,7 +498,11 @@ int Pci2000_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) goto finished; } else - outl (virt_to_bus (SCpnt->request_buffer), padapter->mb2); + { + SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer, SCpnt->request_bufflen, + scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + outl (SCpnt->SCp.have_data_in, padapter->mb2); + } outl (cdb[5], padapter->mb0); outl (cdb[3], padapter->mb3); cmd = CMD_DASD_RAID_RQ; @@ -480,31 +513,35 @@ int Pci2000_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) if ( SCpnt->use_sg ) { - outl (virt_to_bus (((struct scatterlist *)(SCpnt->request_buffer))->address), padapter->mb2); + SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, ((struct scatterlist *)SCpnt->request_buffer)->address, + SCpnt->request_bufflen, scsi_to_pci_dma_dir (SCpnt->sc_data_direction)); } else { - outl (virt_to_bus (SCpnt->request_buffer), padapter->mb2); + SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer, + SCpnt->request_bufflen, scsi_to_pci_dma_dir (SCpnt->sc_data_direction)); } + outl (SCpnt->SCp.have_data_in, padapter->mb2); outl (SCpnt->request_bufflen, padapter->mb3); cmd = CMD_DASD_SCSI_INQ; break; case SCSIOP_TEST_UNIT_READY: // test unit ready CDB - outl (virt_to_bus (SCpnt->sense_buffer), padapter->mb2); + SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->sense_buffer, sizeof (SCpnt->sense_buffer), PCI_DMA_FROMDEVICE); + outl (SCpnt->SCp.have_data_in, padapter->mb2); outl (sizeof (SCpnt->sense_buffer), padapter->mb3); cmd = CMD_TEST_READY; break; - case SCSIOP_READ_CAPACITY: // read capctiy CDB + case SCSIOP_READ_CAPACITY: // read capacity CDB if ( SCpnt->use_sg ) { - outl (virt_to_bus (((struct scatterlist *)(SCpnt->request_buffer))->address), padapter->mb2); + SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, ((struct scatterlist *)(SCpnt->request_buffer))->address, + 8, PCI_DMA_FROMDEVICE); } else - { - outl (virt_to_bus (SCpnt->request_buffer), padapter->mb2); - } + SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer, 8, PCI_DMA_FROMDEVICE); + outl (SCpnt->SCp.have_data_in, padapter->mb2); outl (8, padapter->mb3); cmd = CMD_DASD_CAP; break; @@ -629,37 +666,23 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt) PADAPTER2000 padapter; int z, zz; int setirq; -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) struct pci_dev *pdev = NULL; -#else - UCHAR pci_bus, pci_device_fn; -#endif + UCHAR *consistent; + dma_addr_t consistentDma; + -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) if ( !pci_present () ) -#else - if ( !pcibios_present () ) -#endif { printk ("pci2000: PCI BIOS not present\n"); return 0; } -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) while ( (pdev = pci_find_device (VENDOR_PSI, DEVICE_ROY_1, pdev)) != NULL ) -#else - while ( !pcibios_find_device (VENDOR_PSI, DEVICE_ROY_1, found, &pci_bus, &pci_device_fn) ) -#endif { pshost = scsi_register (tpnt, sizeof(ADAPTER2000)); padapter = HOSTDATA(pshost); -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) - padapter->basePort = pci_resource_start (pdev, 1); -#else - pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &padapter->basePort); - padapter->basePort &= 0xFFFE; -#endif + padapter->basePort = pdev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK; DEB (printk ("\nBase Regs = %#04X", padapter->basePort)); // get the base I/O port address padapter->mb0 = padapter->basePort + RTR_MAILBOX; // get the 32 bit mail boxes padapter->mb1 = padapter->basePort + RTR_MAILBOX + 4; @@ -668,6 +691,7 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt) padapter->mb4 = padapter->basePort + RTR_MAILBOX + 16; padapter->cmd = padapter->basePort + RTR_LOCAL_DOORBELL; // command register padapter->tag = padapter->basePort + RTR_PCI_DOORBELL; // tag/response register + padapter->pdev = pdev; if ( WaitReady (padapter) ) goto unregister; @@ -676,11 +700,14 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt) if ( WaitReady (padapter) ) goto unregister; -#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) + consistent = pci_alloc_consistent (pdev, consistentLen, &consistentDma); + if ( !consistent ) + { + printk ("Unable to allocate DMA memory for PCI-2000 controller.\n"); + goto unregister; + } + pshost->irq = pdev->irq; -#else - pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq); -#endif setirq = 1; padapter->irqOwned = 0; for ( z = 0; z < installed; z++ ) // scan for shared interrupts @@ -695,6 +722,7 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt) if ( request_irq (pshost->irq, Irq_Handler, SA_INTERRUPT | SA_SHIRQ, "pci2000", padapter) < 0 ) { printk ("Unable to allocate IRQ for PCI-2000 controller.\n"); + pci_free_consistent (pdev, consistentLen, consistent, consistentDma); goto unregister; } } @@ -710,9 +738,19 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt) for ( zz = 0; zz < MAX_BUS; zz++ ) for ( z = 0; z < MAX_UNITS; z++ ) + { padapter->dev[zz][z].tag = 0; + padapter->dev[zz][z].scatGath = (PSCATGATH)consistent; + padapter->dev[zz][z].scatGathDma = consistentDma; + consistent += 16 * sizeof (SCATGATH); + consistentDma += 16 * sizeof (SCATGATH); + padapter->dev[zz][z].cdb = (UCHAR *)consistent; + padapter->dev[zz][z].cdbDma = consistentDma; + consistent += MAX_COMMAND_SIZE; + consistentDma += MAX_COMMAND_SIZE; + } - printk("\nPSI-2000 Intelligent Storage SCSI CONTROLLER: at I/O = %X IRQ = %d\n", padapter->basePort, pshost->irq); + printk("\nPSI-2000 Intelligent Storage SCSI CONTROLLER: at I/O = %lX IRQ = %d\n", padapter->basePort, pshost->irq); printk("Version %s, Compiled %s %s\n\n", PCI2000_VERSION, __DATE__, __TIME__); found++; if ( ++installed < MAXADAPTER ) @@ -774,12 +812,9 @@ int Pci2000_Release (struct Scsi_Host *pshost) PADAPTER2000 padapter = HOSTDATA (pshost); if ( padapter->irqOwned ) -#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70) - free_irq (pshost->irq); -#else /* version >= v1.3.70 */ free_irq (pshost->irq, padapter); -#endif /* version >= v1.3.70 */ - release_region (pshost->io_port, pshost->n_io_port); + pci_free_consistent (padapter->pdev, consistentLen, padapter->dev[0][0].scatGath, padapter->dev[0][0].scatGathDma); + release_region (pshost->io_port, pshost->n_io_port); scsi_unregister(pshost); return 0; } |