diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/scsi/sgiwd93.c linux-2.5/drivers/scsi/sgiwd93.c --- bk-linus/drivers/scsi/sgiwd93.c 2002-11-21 02:18:23.000000000 +0000 +++ linux-2.5/drivers/scsi/sgiwd93.c 2002-11-21 18:00:56.000000000 +0000 @@ -4,10 +4,13 @@ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * 1999 Andrew R. Baker (andrewb@uab.edu) * - Support for 2nd SCSI controller on Indigo2 + * 2001 Florian Lohoff (flo@rfc822.org) + * - Delete HPC scatter gather (Read corruption on + * multiple disks) + * - Cleanup wback cache handling * * (In all truth, Jed Schimmel wrote all this code.) * - * $Id: sgiwd93.c,v 1.19 2000/02/04 07:40:47 ralf Exp $ */ #include #include @@ -36,32 +39,13 @@ struct hpc_chunk { struct hpc_dma_desc desc; - unsigned long padding; + u32 _padding; /* align to quadword boundary */ }; struct Scsi_Host *sgiwd93_host = NULL; struct Scsi_Host *sgiwd93_host1 = NULL; /* Wuff wuff, wuff, wd33c93.c, wuff wuff, object oriented, bow wow. */ -static inline void write_wd33c93_count(const wd33c93_regs regs, - unsigned long value) -{ - *regs.SASR = WD_TRANSFER_COUNT_MSB; - *regs.SCMD = ((value >> 16) & 0xff); - *regs.SCMD = ((value >> 8) & 0xff); - *regs.SCMD = ((value >> 0) & 0xff); -} - -static inline unsigned long read_wd33c93_count(const wd33c93_regs regs) -{ - unsigned long value; - - *regs.SASR = WD_TRANSFER_COUNT_MSB; - value = (*regs.SCMD << 16); - value |= (*regs.SCMD << 8); - value |= (*regs.SCMD << 0); - return value; -} /* XXX woof! */ static void sgiwd93_intr(int irq, void *dev_id, struct pt_regs *regs) @@ -82,7 +66,6 @@ void fill_hpc_entries (struct hpc_chunk unsigned long physaddr; unsigned long count; - dma_cache_wback_inv((unsigned long)addr,len); physaddr = PHYSADDR(addr); while (len) { /* @@ -101,7 +84,6 @@ void fill_hpc_entries (struct hpc_chunk static int dma_setup(Scsi_Cmnd *cmd, int datainp) { struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)cmd->host->hostdata; - const wd33c93_regs regs = hdata->regs; struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) cmd->host->base; struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->dma_bounce_buffer; @@ -112,46 +94,17 @@ static int dma_setup(Scsi_Cmnd *cmd, int hdata->dma_dir = datainp; - if(cmd->SCp.buffers_residual) { - struct scatterlist *slp = cmd->SCp.buffer; - int i, totlen = 0; + /* + * wd33c93 shouldn't pass us bogus dma_setups, but + * it does:-( The other wd33c93 drivers deal with + * it the same way (which isn't that obvious). + * IMHO a better fix would be, not to do these + * dma setups in the first place + */ + if (cmd->SCp.ptr == NULL) + return 1; -#ifdef DEBUG_DMA - printk("SCLIST<"); -#endif - for(i = 0; i <= cmd->SCp.buffers_residual; i++) { -#ifdef DEBUG_DMA - printk("[%p,%d]", - page_address(slp[i].page) + slp[i].offset, - slp[i].length); -#endif - fill_hpc_entries (&hcp, - page_address(slp[i].page) + slp[i].offset, - slp[i].length); - totlen += slp[i].length; - } -#ifdef DEBUG_DMA - printk(">tlen<%d>", totlen); -#endif - hdata->dma_bounce_len = totlen; /* a trick... */ - write_wd33c93_count(regs, totlen); - } else { - /* Non-scattered dma. */ -#ifdef DEBUG_DMA - printk("ONEBUF<%p,%d>", cmd->SCp.ptr, cmd->SCp.this_residual); -#endif - /* - * wd33c93 shouldn't pass us bogus dma_setups, but - * it does:-( The other wd33c93 drivers deal with - * it the same way (which isn't that obvious). - * IMHO a better fix would be, not to do these - * dma setups in the first place - */ - if (cmd->SCp.ptr == NULL) - return 1; - fill_hpc_entries (&hcp, cmd->SCp.ptr,cmd->SCp.this_residual); - write_wd33c93_count(regs, cmd->SCp.this_residual); - } + fill_hpc_entries (&hcp, cmd->SCp.ptr,cmd->SCp.this_residual); /* To make sure, if we trip an HPC bug, that we transfer * every single byte, we tag on an extra zero length dma @@ -166,10 +119,14 @@ static int dma_setup(Scsi_Cmnd *cmd, int /* Start up the HPC. */ hregs->ndptr = PHYSADDR(hdata->dma_bounce_buffer); - if(datainp) + if(datainp) { + dma_cache_inv((unsigned long) cmd->SCp.ptr, cmd->SCp.this_residual); hregs->ctrl = (HPC3_SCTRL_ACTIVE); - else + } else { + dma_cache_wback_inv((unsigned long) cmd->SCp.ptr, cmd->SCp.this_residual); hregs->ctrl = (HPC3_SCTRL_ACTIVE | HPC3_SCTRL_DIR); + } + return 0; } @@ -177,7 +134,6 @@ static void dma_stop(struct Scsi_Host *i int status) { struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)instance->hostdata; - const wd33c93_regs regs = hdata->regs; struct hpc3_scsiregs *hregs; if (!SCpnt) @@ -197,44 +153,6 @@ static void dma_stop(struct Scsi_Host *i } hregs->ctrl = 0; - /* See how far we got and update scatterlist state if necessary. */ - if(SCpnt->SCp.buffers_residual) { - struct scatterlist *slp = SCpnt->SCp.buffer; - int totlen, wd93_residual, transferred, i; - - /* Yep, we were doing the scatterlist thang. */ - totlen = hdata->dma_bounce_len; - wd93_residual = read_wd33c93_count(regs); - transferred = totlen - wd93_residual; - -#ifdef DEBUG_DMA - printk("tlen<%d>resid<%d>transf<%d> ", - totlen, wd93_residual, transferred); -#endif - - /* Avoid long winded partial-transfer search for common case. */ - if(transferred != totlen) { - /* This is the nut case. */ -#ifdef DEBUG_DMA - printk("Jed was here..."); -#endif - for(i = 0; i <= SCpnt->SCp.buffers_residual; i++) { - if(slp[i].length >= transferred) - break; - transferred -= slp[i].length; - } - } else { - /* This is the common case. */ -#ifdef DEBUG_DMA - printk("did it all..."); -#endif - i = SCpnt->SCp.buffers_residual; - } - SCpnt->SCp.buffer = &slp[i]; - SCpnt->SCp.buffers_residual = SCpnt->SCp.buffers_residual - i; - SCpnt->SCp.ptr = (char *) page_address(slp[i].page) + slp[i].offset; - SCpnt->SCp.this_residual = slp[i].length; - } #ifdef DEBUG_DMA printk("\n"); #endif @@ -264,6 +182,9 @@ static inline void init_hpc_chain(uchar }; hcp--; hcp->desc.pnext = PHYSADDR(buf); + + /* Force flush to memory */ + dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); } int __init sgiwd93_detect(Scsi_Host_Template *SGIblows) @@ -273,8 +194,8 @@ int __init sgiwd93_detect(Scsi_Host_Temp struct hpc3_scsiregs *hregs1 = &hpc3c0->scsi_chan1; struct WD33C93_hostdata *hdata; struct WD33C93_hostdata *hdata1; - uchar *buf; wd33c93_regs regs; + uchar *buf; if(called) return 0; /* Should bitch on the console about this... */ @@ -294,10 +215,10 @@ int __init sgiwd93_detect(Scsi_Host_Temp return 0; } init_hpc_chain(buf); - dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); + /* HPC_SCSI_REG0 | 0x03 | KSEG1 */ - regs.SASR = (volatile unsigned char *)KSEG1ADDR (0x1fbc0003); - regs.SCMD = (volatile unsigned char *)KSEG1ADDR (0x1fbc0007); + regs.SASR = (unsigned char*) KSEG1ADDR (0x1fbc0003); + regs.SCMD = (unsigned char*) KSEG1ADDR (0x1fbc0007); wd33c93_init(sgiwd93_host, regs, dma_setup, dma_stop, WD33C93_FS_16_20); hdata = (struct WD33C93_hostdata *)sgiwd93_host->hostdata; @@ -329,17 +250,16 @@ int __init sgiwd93_detect(Scsi_Host_Temp return 1; /* We registered host0 so return success*/ } init_hpc_chain(buf); - dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); + /* HPC_SCSI_REG1 | 0x03 | KSEG1 */ - regs.SASR = (volatile unsigned char *)KSEG1ADDR (0x1fbc8003); - regs.SCMD = (volatile unsigned char *)KSEG1ADDR (0x1fbc8007); + regs.SASR = (unsigned char*) KSEG1ADDR(0x1fbc8003); + regs.SCMD = (unsigned char*) KSEG1ADDR(0x1fbc8007); wd33c93_init(sgiwd93_host1, regs, dma_setup, dma_stop, - WD33C93_FS_16_20); + WD33C93_FS_16_20); hdata1 = (struct WD33C93_hostdata *)sgiwd93_host1->hostdata; hdata1->no_sync = 0; hdata1->dma_bounce_buffer = (uchar *) (KSEG1ADDR(buf)); - dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); if (request_irq(SGI_WD93_1_IRQ, sgiwd93_intr, 0, "SGI WD93", (void *) sgiwd93_host1)) { printk(KERN_WARNING "sgiwd93: Could not allocate irq %d (for host1).\n", SGI_WD93_1_IRQ);