Index: Documentation/Configure.help =================================================================== RCS file: /home/jejb/CVSROOT/linux/2.4/Documentation/Configure.help,v retrieving revision 1.1.1.25 diff -u -r1.1.1.25 Configure.help --- Documentation/Configure.help 2001/09/21 19:07:16 1.1.1.25 +++ Documentation/Configure.help 2001/09/22 00:36:20 @@ -5991,6 +5991,23 @@ port or memory mapped. You should know what you have. The most common card, Trantor T130B, uses port mapped mode. +NCR Dual 700 MCA SCSI support +CONFIG_SCSI_NCR_D700 + This is a driver for the MicroChannel Dual 700 card produced by + NCR and commonly used in 345x/35xx/4100 class machines. It always + tries to negotiate sync and uses tag command queueing. + + Unless you have an NCR manufactured machine, the chances are that + you do not have this SCSI card, so say N. + +HP LASI SCSI support for 53c700 +CONFIG_SCSI_LASI700 + This is a driver for the lasi baseboard in some parisc machines + which is based on the 53c700 chip. Will also support LASI subsystems + based on the 710 chip using 700 emulation mode. + + Unless you know you have a 53c700 or 53c710 based lasi, say N here + NCR53c7,8xx SCSI support CONFIG_SCSI_NCR53C7xx This is a driver for the 53c7 and 8xx NCR family of SCSI Index: drivers/scsi/53c700.c =================================================================== RCS file: /home/jejb/CVSROOT/linux/2.4/drivers/scsi/53c700.c,v retrieving revision 1.1.1.3 diff -u -r1.1.1.3 53c700.c --- drivers/scsi/53c700.c 2001/09/08 01:39:47 1.1.1.3 +++ drivers/scsi/53c700.c 2001/09/22 00:36:28 @@ -51,6 +51,19 @@ /* CHANGELOG * + * Version 2.5 + * + * More Compatibility changes for 710 (now actually works). Enhanced + * support for odd clock speeds which constrain SDTR negotiations. + * correct cacheline separation for scsi messages and status for + * incoherent architectures. Use of the pci mapping functions on + * buffers to begin support for 64 bit drivers. + * + * Version 2.4 + * + * Added support for the 53c710 chip (in 53c700 emulation mode only---no + * special 53c710 instructions or registers are used). + * * Version 2.3 * * More endianness/cache coherency changes. @@ -77,7 +90,7 @@ * Initial modularisation from the D700. See NCR_D700.c for the rest of * the changelog. * */ -#define NCR_700_VERSION "2.3" +#define NCR_700_VERSION "2.5" #include #include @@ -98,6 +111,7 @@ #include #include #include +#include #include "scsi.h" #include "hosts.h" @@ -105,6 +119,14 @@ #include "53c700.h" +/* NOTE: For 64 bit drivers there are points in the code where we use + * a non dereferenceable pointer to point to a structure in dma-able + * memory (which is 32 bits) so that we can use all of the structure + * operations but take the address at the end. This macro allows us + * to truncate the 64 bit pointer down to 32 bits without the compiler + * complaining */ +#define to32bit(x) ((__u32)((unsigned long)(x))) + #ifdef NCR_700_DEBUG #define STATIC #else @@ -195,12 +217,19 @@ NCR_700_detect(Scsi_Host_Template *tpnt, struct NCR_700_Host_Parameters *hostdata) { - __u32 *script = kmalloc(sizeof(SCRIPT), GFP_KERNEL); - __u32 pScript; + dma_addr_t pScript, pSlots; + __u32 *script; struct Scsi_Host *host; static int banner = 0; int j; + /* This separation of pScript and script is not strictly + * necessay, but may be useful in architectures which can + * allocate consistent memory on which virt_to_bus will not + * work */ + script = kmalloc(sizeof(SCRIPT), GFP_KERNEL); + pScript = virt_to_bus(script); + /* Fill in the missing routines from the host template */ tpnt->queuecommand = NCR_700_queuecommand; tpnt->eh_abort_handler = NCR_700_abort; @@ -228,40 +257,57 @@ return NULL; } - hostdata->slots = kmalloc(sizeof(struct NCR_700_command_slot) * NCR_700_COMMAND_SLOTS_PER_HOST, GFP_KERNEL); - if(hostdata->slots == NULL) { - printk(KERN_ERR "53c700: Failed to allocate command slots, detatching\n"); + /* This separation of slots and pSlots may facilitate later + * migration to consistent memory on architectures which + * support it */ + hostdata->slots = kmalloc(sizeof(struct NCR_700_command_slot) + * NCR_700_COMMAND_SLOTS_PER_HOST, + GFP_KERNEL); + pSlots = virt_to_bus(hostdata->slots); + + hostdata->msgin = kmalloc(MSG_ARRAY_SIZE, GFP_KERNEL); + hostdata->msgout = kmalloc(MSG_ARRAY_SIZE, GFP_KERNEL); + hostdata->status = kmalloc(MSG_ARRAY_SIZE, GFP_KERNEL); + if(hostdata->slots == NULL || hostdata->msgin == NULL + || hostdata->msgout == NULL || hostdata->status==NULL) { + printk(KERN_ERR "53c700: Failed to allocate command slots or message buffers, detatching\n"); scsi_unregister(host); return NULL; } - memset(hostdata->slots, 0, sizeof(struct NCR_700_command_slot) * NCR_700_COMMAND_SLOTS_PER_HOST); + memset(hostdata->slots, 0, sizeof(struct NCR_700_command_slot) + * NCR_700_COMMAND_SLOTS_PER_HOST); for(j = 0; j < NCR_700_COMMAND_SLOTS_PER_HOST; j++) { + dma_addr_t offset = (dma_addr_t)((unsigned long)&hostdata->slots[j].SG[0] + - (unsigned long)&hostdata->slots[0].SG[0]); + hostdata->slots[j].pSG = (struct NCR_700_SG_List *)((unsigned long)(pSlots + offset)); if(j == 0) hostdata->free_list = &hostdata->slots[j]; else hostdata->slots[j-1].ITL_forw = &hostdata->slots[j]; hostdata->slots[j].state = NCR_700_SLOT_FREE; } - host->hostdata[0] = (__u32)hostdata; + for(j = 0; j < sizeof(SCRIPT)/sizeof(SCRIPT[0]); j++) { script[j] = bS_to_host(SCRIPT[j]); } - /* bus physical address of script */ - pScript = virt_to_bus(script); + /* adjust all labels to be bus physical */ for(j = 0; j < PATCHES; j++) { script[LABELPATCHES[j]] = bS_to_host(pScript + SCRIPT[LABELPATCHES[j]]); } - /* now patch up fixed addresses */ + /* now patch up fixed addresses. + * NOTE: virt_to_bus may be wrong if consistent memory is used + * for these in the future */ script_patch_32(script, MessageLocation, virt_to_bus(&hostdata->msgout[0])); script_patch_32(script, StatusAddress, - virt_to_bus(&hostdata->status)); + virt_to_bus(&hostdata->status[0])); script_patch_32(script, ReceiveMsgAddress, virt_to_bus(&hostdata->msgin[0])); hostdata->script = script; hostdata->pScript = pScript; + dma_cache_wback((unsigned long)script, sizeof(SCRIPT)); hostdata->state = NCR_700_HOST_FREE; spin_lock_init(&hostdata->lock); hostdata->cmd = NULL; @@ -272,19 +318,22 @@ host->hostdata[0] = (unsigned long)hostdata; /* kick the chip */ NCR_700_writeb(0xff, host, CTEST9_REG); - hostdata->rev = (NCR_700_readb(host, CTEST7_REG)<<4) & 0x0f; + if(hostdata->chip710) + hostdata->rev = (NCR_700_readb(host, CTEST8_REG)>>4) & 0x0f; + else + hostdata->rev = (NCR_700_readb(host, CTEST7_REG)>>4) & 0x0f; hostdata->fast = (NCR_700_readb(host, CTEST9_REG) == 0); if(banner == 0) { printk(KERN_NOTICE "53c700: Version " NCR_700_VERSION " By James.Bottomley@HansenPartnership.com\n"); banner = 1; } printk(KERN_NOTICE "scsi%d: %s rev %d %s\n", host->host_no, - hostdata->fast ? "53c700-66" : "53c700", + hostdata->chip710 ? "53c710" : + (hostdata->fast ? "53c700-66" : "53c700"), hostdata->rev, hostdata->differential ? "(Differential)" : ""); /* reset the chip */ NCR_700_chip_reset(host); - NCR_700_writeb(ASYNC_OPERATION , host, SXFER_REG); return host; } @@ -295,7 +344,13 @@ struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)host->hostdata[0]; + /* NOTE: these may be NULL if we weren't fully initialised before + * the scsi_unregister was called */ kfree(hostdata->script); + kfree(hostdata->slots); + kfree(hostdata->msgin); + kfree(hostdata->msgout); + kfree(hostdata->status); return 1; } @@ -308,24 +363,32 @@ } /* - * Function : static int datapath_residual (Scsi_Host *host) + * Function : static int data_residual (Scsi_Host *host) * * Purpose : return residual data count of what's in the chip. If you * really want to know what this function is doing, it's almost a * direct transcription of the algorithm described in the 53c710 * guide, except that the DBC and DFIFO registers are only 6 bits - * wide. + * wide on a 53c700. * * Inputs : host - SCSI host */ static inline int NCR_700_data_residual (struct Scsi_Host *host) { - int count, synchronous; + struct NCR_700_Host_Parameters *hostdata = + (struct NCR_700_Host_Parameters *)host->hostdata[0]; + int count, synchronous = 0; unsigned int ddir; - count = ((NCR_700_readb(host, DFIFO_REG) & 0x3f) - - (NCR_700_readl(host, DBC_REG) & 0x3f)) & 0x3f; + if(hostdata->chip710) { + count = ((NCR_700_readb(host, DFIFO_REG) & 0x7f) - + (NCR_700_readl(host, DBC_REG) & 0x7f)) & 0x7f; + } else { + count = ((NCR_700_readb(host, DFIFO_REG) & 0x3f) - + (NCR_700_readl(host, DBC_REG) & 0x3f)) & 0x3f; + } - synchronous = NCR_700_readb(host, SXFER_REG) & 0x0f; + if(hostdata->fast) + synchronous = NCR_700_readb(host, SXFER_REG) & 0x0f; /* get the data direction */ ddir = NCR_700_readb(host, CTEST0_REG) & 0x01; @@ -345,6 +408,10 @@ if (synchronous && (sstat & SODR_REG_FULL)) ++count; } +#ifdef NCR_700_DEBUG + if(count) + printk("RESIDUAL IS %d (ddir %d)\n", count, ddir); +#endif return count; } @@ -530,21 +597,26 @@ __u8 offset, __u8 period) { int XFERP; - - if(period*4 < NCR_700_MIN_PERIOD) { - printk(KERN_WARNING "53c700: Period %dns is less than SCSI-2 minimum, setting to %d\n", period*4, NCR_700_MIN_PERIOD); - period = NCR_700_MIN_PERIOD/4; + __u8 min_xferp = (hostdata->chip710 + ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP); + __u8 max_offset = (hostdata->chip710 + ? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET); + /* NOTE: NCR_700_SDTR_msg[3] contains our offer of the minimum + * period. It is set in NCR_700_chip_setup() */ + if(period < NCR_700_SDTR_msg[3]) { + printk(KERN_WARNING "53c700: Period %dns is less than this chip's minimum, setting to %d\n", period*4, NCR_700_SDTR_msg[3]*4); + period = NCR_700_SDTR_msg[3]; } XFERP = (period*4 * hostdata->sync_clock)/1000 - 4; - if(offset > NCR_700_MAX_OFFSET) { - printk(KERN_WARNING "53c700: Offset %d exceeds maximum, setting to %d\n", - offset, NCR_700_MAX_OFFSET); - offset = NCR_700_MAX_OFFSET; + if(offset > max_offset) { + printk(KERN_WARNING "53c700: Offset %d exceeds chip maximum, setting to %d\n", + offset, max_offset); + offset = max_offset; } - if(XFERP < NCR_700_MIN_XFERP) { + if(XFERP < min_xferp) { printk(KERN_WARNING "53c700: XFERP %d is less than minium, setting to %d\n", - XFERP, NCR_700_MIN_XFERP); - XFERP = NCR_700_MIN_XFERP; + XFERP, min_xferp); + XFERP = min_xferp; } return (offset & 0x0f) | (XFERP & 0x07)<<4; } @@ -563,14 +635,28 @@ if(SCp->cmnd[0] == REQUEST_SENSE && SCp->cmnd[6] == NCR_700_INTERNAL_SENSE_MAGIC) { #ifdef NCR_700_DEBUG - printk(" ORIGINAL CMD %p RETURNED %d, new return is %d sense is", + printk(" ORIGINAL CMD %p RETURNED %d, new return is %d sense is\n", SCp, SCp->cmnd[7], result); print_sense("53c700", SCp); #endif if(result == 0) result = SCp->cmnd[7]; } - + + if(SCp->sc_data_direction != SCSI_DATA_NONE && + SCp->sc_data_direction != SCSI_DATA_UNKNOWN) { + int pci_direction = scsi_to_pci_dma_dir(SCp->sc_data_direction); + if(SCp->use_sg) { + pci_unmap_sg(hostdata->pci_dev, SCp->buffer, + SCp->use_sg, pci_direction); + } else { + pci_unmap_single(hostdata->pci_dev, + slot->dma_handle, + SCp->request_bufflen, + pci_direction); + } + } + free_slot(slot, hostdata); SCp->host_scribble = NULL; @@ -602,19 +688,47 @@ { struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)host->hostdata[0]; + __u32 dcntl_extra = 0; + __u8 min_period; + __u8 min_xferp = (hostdata->chip710 ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP); + + if(hostdata->chip710) { + __u8 burst_disable = hostdata->burst_disable + ? BURST_DISABLE : 0; + dcntl_extra = COMPAT_700_MODE; + + NCR_700_writeb(dcntl_extra, host, DCNTL_REG); + NCR_700_writeb(BURST_LENGTH_8 | hostdata->dmode_extra, + host, DMODE_710_REG); + NCR_700_writeb(burst_disable | (hostdata->differential ? + DIFF : 0), host, CTEST7_REG); + NCR_700_writeb(BTB_TIMER_DISABLE, host, CTEST0_REG); + NCR_700_writeb(FULL_ARBITRATION | ENABLE_PARITY | PARITY + | AUTO_ATN, host, SCNTL0_REG); + } else { + NCR_700_writeb(BURST_LENGTH_8 | hostdata->dmode_extra, + host, DMODE_700_REG); + NCR_700_writeb(hostdata->differential ? + DIFF : 0, host, CTEST7_REG); + if(hostdata->fast) { + /* this is for 700-66, does nothing on 700 */ + NCR_700_writeb(LAST_DIS_ENBL | ENABLE_ACTIVE_NEGATION + | GENERATE_RECEIVE_PARITY, host, + CTEST8_REG); + } else { + NCR_700_writeb(FULL_ARBITRATION | ENABLE_PARITY + | PARITY | AUTO_ATN, host, SCNTL0_REG); + } + } NCR_700_writeb(1 << host->this_id, host, SCID_REG); NCR_700_writeb(0, host, SBCL_REG); - NCR_700_writeb(0, host, SXFER_REG); + NCR_700_writeb(ASYNC_OPERATION, host, SXFER_REG); NCR_700_writeb(PHASE_MM_INT | SEL_TIMEOUT_INT | GROSS_ERR_INT | UX_DISC_INT | RST_INT | PAR_ERR_INT | SELECT_INT, host, SIEN_REG); NCR_700_writeb(ABORT_INT | INT_INST_INT | ILGL_INST_INT, host, DIEN_REG); - NCR_700_writeb(BURST_LENGTH_8, host, DMODE_REG); - NCR_700_writeb(FULL_ARBITRATION | PARITY | AUTO_ATN, host, SCNTL0_REG); - NCR_700_writeb(LAST_DIS_ENBL | ENABLE_ACTIVE_NEGATION|GENERATE_RECEIVE_PARITY, - host, CTEST8_REG); NCR_700_writeb(ENABLE_SELECT, host, SCNTL1_REG); if(hostdata->clock > 75) { printk(KERN_ERR "53c700: Clock speed %dMHz is too high: 75Mhz is the maximum this chip can be driven at\n", hostdata->clock); @@ -622,13 +736,13 @@ * of spec: sync divider 2, async divider 3 */ DEBUG(("53c700: sync 2 async 3\n")); NCR_700_writeb(SYNC_DIV_2_0, host, SBCL_REG); - NCR_700_writeb(ASYNC_DIV_3_0, host, DCNTL_REG); + NCR_700_writeb(ASYNC_DIV_3_0 | dcntl_extra, host, DCNTL_REG); hostdata->sync_clock = hostdata->clock/2; } else if(hostdata->clock > 50 && hostdata->clock <= 75) { /* sync divider 1.5, async divider 3 */ DEBUG(("53c700: sync 1.5 async 3\n")); NCR_700_writeb(SYNC_DIV_1_5, host, SBCL_REG); - NCR_700_writeb(ASYNC_DIV_3_0, host, DCNTL_REG); + NCR_700_writeb(ASYNC_DIV_3_0 | dcntl_extra, host, DCNTL_REG); hostdata->sync_clock = hostdata->clock*2; hostdata->sync_clock /= 3; @@ -636,30 +750,49 @@ /* sync divider 1, async divider 2 */ DEBUG(("53c700: sync 1 async 2\n")); NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG); - NCR_700_writeb(ASYNC_DIV_2_0, host, DCNTL_REG); + NCR_700_writeb(ASYNC_DIV_2_0 | dcntl_extra, host, DCNTL_REG); hostdata->sync_clock = hostdata->clock; } else if(hostdata->clock > 25 && hostdata->clock <=37) { /* sync divider 1, async divider 1.5 */ DEBUG(("53c700: sync 1 async 1.5\n")); NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG); - NCR_700_writeb(ASYNC_DIV_1_5, host, DCNTL_REG); + NCR_700_writeb(ASYNC_DIV_1_5 | dcntl_extra, host, DCNTL_REG); hostdata->sync_clock = hostdata->clock; } else { DEBUG(("53c700: sync 1 async 1\n")); NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG); - NCR_700_writeb(ASYNC_DIV_1_0, host, DCNTL_REG); + NCR_700_writeb(ASYNC_DIV_1_0 | dcntl_extra, host, DCNTL_REG); /* sync divider 1, async divider 1 */ + hostdata->sync_clock = hostdata->clock; + } + /* Calculate the actual minimum period that can be supported + * by our synchronous clock speed. See the 710 manual for + * exact details of this calculation which is based on a + * setting of the SXFER register */ + min_period = 1000*(4+min_xferp)/(4*hostdata->sync_clock); + if(min_period > NCR_700_MIN_PERIOD) { + NCR_700_SDTR_msg[3] = min_period; } + if(hostdata->chip710) + NCR_700_SDTR_msg[4] = NCR_710_MAX_OFFSET; } STATIC void NCR_700_chip_reset(struct Scsi_Host *host) { - /* Chip reset */ - NCR_700_writeb(SOFTWARE_RESET, host, DCNTL_REG); - udelay(100); + struct NCR_700_Host_Parameters *hostdata = + (struct NCR_700_Host_Parameters *)host->hostdata[0]; + if(hostdata->chip710) { + NCR_700_writeb(SOFTWARE_RESET_710, host, ISTAT_REG); + udelay(100); - NCR_700_writeb(0, host, DCNTL_REG); + NCR_700_writeb(0, host, ISTAT_REG); + } else { + NCR_700_writeb(SOFTWARE_RESET, host, DCNTL_REG); + udelay(100); + + NCR_700_writeb(0, host, DCNTL_REG); + } mdelay(1000); @@ -717,7 +850,7 @@ printk(KERN_WARNING "scsi%d Unexpected SDTR msg\n", host->host_no); hostdata->msgout[0] = A_REJECT_MSG; - dma_cache_wback((unsigned long)hostdata->msgout, sizeof(hostdata->msgout)); + dma_cache_wback((unsigned long)hostdata->msgout, 1); script_patch_16(hostdata->script, MessageCount, 1); /* SendMsgOut returns, so set up the return * address */ @@ -729,7 +862,7 @@ printk(KERN_INFO "scsi%d: (%d:%d), Unsolicited WDTR after CMD, Rejecting\n", host->host_no, pun, lun); hostdata->msgout[0] = A_REJECT_MSG; - dma_cache_wback((unsigned long)hostdata->msgout, sizeof(hostdata->msgout)); + dma_cache_wback((unsigned long)hostdata->msgout, 1); script_patch_16(hostdata->script, MessageCount, 1); resume_offset = hostdata->pScript + Ent_SendMessageWithATN; @@ -743,7 +876,7 @@ printk("\n"); /* just reject it */ hostdata->msgout[0] = A_REJECT_MSG; - dma_cache_wback((unsigned long)hostdata->msgout, sizeof(hostdata->msgout)); + dma_cache_wback((unsigned long)hostdata->msgout, 1); script_patch_16(hostdata->script, MessageCount, 1); /* SendMsgOut returns, so set up the return * address */ @@ -761,8 +894,6 @@ __u32 temp = dsp + 8, resume_offset = dsp; __u8 pun = 0xff, lun = 0xff; - dma_cache_inv((unsigned long)hostdata->msgin, sizeof(hostdata->msgin)); - if(SCp != NULL) { pun = SCp->target; lun = SCp->lun; @@ -778,8 +909,9 @@ switch(hostdata->msgin[0]) { case A_EXTENDED_MSG: - return process_extended_message(host, hostdata, SCp, - dsp, dsps); + resume_offset = process_extended_message(host, hostdata, SCp, + dsp, dsps); + break; case A_REJECT_MSG: if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) { @@ -792,6 +924,8 @@ printk(KERN_WARNING "scsi%d (%d:%d) Rejected first tag queue attempt, turning off tag queueing\n", host->host_no, pun, lun); NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING); hostdata->tag_negotiated &= ~(1<target); + SCp->device->tagged_queue = 0; + SCp->device->tagged_supported = 0; } else { printk(KERN_WARNING "scsi%d (%d:%d) Unexpected REJECT Message %s\n", host->host_no, pun, lun, @@ -820,7 +954,7 @@ printk("\n"); /* just reject it */ hostdata->msgout[0] = A_REJECT_MSG; - dma_cache_wback((unsigned long)hostdata->msgout, sizeof(hostdata->msgout)); + dma_cache_wback((unsigned long)hostdata->msgout, 1); script_patch_16(hostdata->script, MessageCount, 1); /* SendMsgOut returns, so set up the return * address */ @@ -829,6 +963,8 @@ break; } NCR_700_writel(temp, host, TEMP_REG); + /* set us up to receive another message */ + dma_cache_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE); return resume_offset; } @@ -846,25 +982,26 @@ } if(dsps == A_GOOD_STATUS_AFTER_STATUS) { - dma_cache_inv((unsigned long)hostdata->status, sizeof(hostdata->status)); DEBUG((" COMMAND COMPLETE, status=%02x\n", - hostdata->status)); + hostdata->status[0])); /* OK, if TCQ still on, we know it works */ NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING); /* check for contingent allegiance contitions */ - if(status_byte(hostdata->status) == CHECK_CONDITION || - status_byte(hostdata->status) == COMMAND_TERMINATED) { + if(status_byte(hostdata->status[0]) == CHECK_CONDITION || + status_byte(hostdata->status[0]) == COMMAND_TERMINATED) { struct NCR_700_command_slot *slot = (struct NCR_700_command_slot *)SCp->host_scribble; if(SCp->cmnd[0] == REQUEST_SENSE) { /* OOPS: bad device, returning another * contingent allegiance condition */ printk(KERN_ERR "scsi%d (%d:%d) broken device is looping in contingent allegiance: ignoring\n", host->host_no, pun, lun); - NCR_700_scsi_done(hostdata, SCp, hostdata->status); + NCR_700_scsi_done(hostdata, SCp, hostdata->status[0]); } else { - - DEBUG((" cmd %p has status %d, requesting sense\n", - SCp, hostdata->status)); +#ifdef NCR_DEBUG + print_command(SCp->cmnd); + printk(" cmd %p has status %d, requesting sense\n", + SCp, hostdata->status[0]); +#endif /* we can destroy the command here because the * contingent allegiance condition will cause a * retry which will re-copy the command from the @@ -881,7 +1018,9 @@ * was an internal sense request and the original * status at the end of the command */ SCp->cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC; - SCp->cmnd[7] = hostdata->status; + SCp->cmnd[7] = hostdata->status[0]; + SCp->sc_data_direction = SCSI_DATA_READ; + dma_cache_wback((unsigned long)SCp->cmnd, SCp->cmd_len); slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer)); slot->SG[0].pAddr = bS_to_host(virt_to_bus(SCp->sense_buffer)); slot->SG[1].ins = bS_to_host(SCRIPT_RETURN); @@ -896,20 +1035,27 @@ hostdata->cmd = NULL; } } else { - if(status_byte(hostdata->status) == GOOD && - SCp->cmnd[0] == INQUIRY && SCp->use_sg == 0) { - /* Piggy back the tag queueing support - * on this command */ - if(((char *)SCp->request_buffer)[7] & 0x02) { - printk(KERN_INFO "scsi%d: (%d:%d) Enabling Tag Command Queuing\n", host->host_no, pun, lun); - hostdata->tag_negotiated |= (1<target); - NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING); - } else { - NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING); - hostdata->tag_negotiated &= ~(1<target); - } - } - NCR_700_scsi_done(hostdata, SCp, hostdata->status); + // Currently rely on the mid layer evaluation + // of the tag queuing capability + // + //if(status_byte(hostdata->status[0]) == GOOD && + // SCp->cmnd[0] == INQUIRY && SCp->use_sg == 0) { + // /* Piggy back the tag queueing support + // * on this command */ + // pci_dma_sync_single(hostdata->pci_dev, + // slot->dma_handle, + // SCp->request_bufflen, + // PCI_DMA_FROMDEVICE); + // if(((char *)SCp->request_buffer)[7] & 0x02) { + // printk(KERN_INFO "scsi%d: (%d:%d) Enabling Tag Command Queuing\n", host->host_no, pun, lun); + // hostdata->tag_negotiated |= (1<target); + // NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING); + // } else { + // NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING); + // hostdata->tag_negotiated &= ~(1<target); + // } + //} + NCR_700_scsi_done(hostdata, SCp, hostdata->status[0]); } } else if((dsps & 0xfffff0f0) == A_UNEXPECTED_PHASE) { __u8 i = (dsps & 0xf00) >> 8; @@ -947,8 +1093,6 @@ struct NCR_700_command_slot *slot; __u8 reselection_id = hostdata->reselection_id; - dma_cache_inv((unsigned long)hostdata->msgin, sizeof(hostdata->msgin)); - lun = hostdata->msgin[0] & 0x1f; hostdata->reselection_id = 0xff; @@ -996,7 +1140,7 @@ script_patch_16(hostdata->script, CommandCount, slot->cmnd->cmd_len); script_patch_32_abs(hostdata->script, SGScriptStartAddress, - virt_to_bus(&slot->SG[0].ins)); + to32bit(&slot->pSG[0].ins)); /* Note: setting SXFER only works if we're * still in the MESSAGE phase, so it is vital @@ -1005,6 +1149,16 @@ * should therefore always clear ACK */ NCR_700_writeb(NCR_700_get_SXFER(hostdata->cmd->device), host, SXFER_REG); + dma_cache_inv((unsigned long)hostdata->msgin, + MSG_ARRAY_SIZE); + dma_cache_wback((unsigned long)hostdata->msgout, + MSG_ARRAY_SIZE); + /* I'm just being paranoid here, the command should + * already have been flushed from the cache */ + dma_cache_wback((unsigned long)slot->cmnd->cmnd, + slot->cmnd->cmd_len); + + } } else if(dsps == A_RESELECTED_DURING_SELECTION) { @@ -1022,20 +1176,22 @@ /* Take out our own ID */ reselection_id &= ~(1<this_id); - printk(KERN_INFO "scsi%d: (%d:%d) RESELECTION DURING SELECTION, dsp=%p[%04x] state=%d, count=%d\n", - host->host_no, reselection_id, lun, (void *)dsp, dsp - hostdata->pScript, hostdata->state, hostdata->command_slot_count); + /* I've never seen this happen, so keep this as a printk rather + * than a debug */ + printk(KERN_INFO "scsi%d: (%d:%d) RESELECTION DURING SELECTION, dsp=%08x[%04x] state=%d, count=%d\n", + host->host_no, reselection_id, lun, dsp, dsp - hostdata->pScript, hostdata->state, hostdata->command_slot_count); { /* FIXME: DEBUGGING CODE */ - __u32 SG = (__u32)bus_to_virt(hostdata->script[A_SGScriptStartAddress_used[0]]); + __u32 SG = (__u32)bS_to_cpu(hostdata->script[A_SGScriptStartAddress_used[0]]); int i; for(i=0; i< NCR_700_COMMAND_SLOTS_PER_HOST; i++) { - if(SG >= (__u32)(&hostdata->slots[i].SG[0]) - && SG <= (__u32)(&hostdata->slots[i].SG[NCR_700_SG_SEGMENTS])) + if(SG >= to32bit(&hostdata->slots[i].pSG[0]) + && SG <= to32bit(&hostdata->slots[i].pSG[NCR_700_SG_SEGMENTS])) break; } - printk(KERN_INFO "IDENTIFIED SG segment as being %p in slot %p, cmd %p, slot->resume_offset=%p\n", (void *)SG, &hostdata->slots[i], hostdata->slots[i].cmnd, (void *)hostdata->slots[i].resume_offset); + printk(KERN_INFO "IDENTIFIED SG segment as being %08x in slot %p, cmd %p, slot->resume_offset=%08x\n", SG, &hostdata->slots[i], hostdata->slots[i].cmnd, hostdata->slots[i].resume_offset); SCp = hostdata->slots[i].cmnd; } @@ -1061,8 +1217,9 @@ reselection_id = bitmap_to_number(reselection_id); } hostdata->reselection_id = reselection_id; + /* just in case we have a stale simple tag message, clear it */ hostdata->msgin[1] = 0; - dma_cache_wback((unsigned long)hostdata->msgin, sizeof(hostdata->msgin)); + dma_cache_wback_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE); if(hostdata->tag_negotiated & (1<pScript + Ent_GetReselectionWithTag; } else { @@ -1092,8 +1249,8 @@ } NCR_700_internal_bus_reset(host); } else if((dsps & 0xfffff000) == A_DEBUG_INTERRUPT) { - printk(KERN_NOTICE "scsi%d (%d:%d) DEBUG INTERRUPT %d AT %p[%04x], continuing\n", - host->host_no, pun, lun, dsps & 0xfff, (void *)dsp, dsp - hostdata->pScript); + printk(KERN_NOTICE "scsi%d (%d:%d) DEBUG INTERRUPT %d AT %08x[%04x], continuing\n", + host->host_no, pun, lun, dsps & 0xfff, dsp, dsp - hostdata->pScript); resume_offset = dsp; } else { printk(KERN_ERR "scsi%d: (%d:%d), unidentified script interrupt 0x%x at %04x\n", @@ -1122,7 +1279,8 @@ __u8 sbcl; for(count = 0; count < 5; count++) { - id = NCR_700_readb(host, SFBR_REG); + id = NCR_700_readb(host, hostdata->chip710 ? + CTEST9_REG : SFBR_REG); /* Take out our own ID */ id &= ~(1<this_id); @@ -1174,8 +1332,9 @@ } hostdata->state = NCR_700_HOST_BUSY; hostdata->cmd = NULL; + /* clear any stale simple tag message */ hostdata->msgin[1] = 0; - dma_cache_wback((unsigned long)hostdata->msgin, sizeof(hostdata->msgin)); + dma_cache_wback_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE); if(id == 0xff) { /* Selected as target, Ignore */ @@ -1188,7 +1347,33 @@ return resume_offset; } +static inline void +NCR_700_clear_fifo(struct Scsi_Host *host) { + const struct NCR_700_Host_Parameters *hostdata + = (struct NCR_700_Host_Parameters *)host->hostdata[0]; + if(hostdata->chip710) { + NCR_700_writeb(CLR_FIFO_710, host, CTEST8_REG); + } else { + NCR_700_writeb(CLR_FIFO, host, DFIFO_REG); + } +} + +static inline void +NCR_700_flush_fifo(struct Scsi_Host *host) { + const struct NCR_700_Host_Parameters *hostdata + = (struct NCR_700_Host_Parameters *)host->hostdata[0]; + if(hostdata->chip710) { + NCR_700_writeb(FLUSH_DMA_FIFO_710, host, CTEST8_REG); + udelay(10); + NCR_700_writeb(0, host, CTEST8_REG); + } else { + NCR_700_writeb(FLUSH_DMA_FIFO, host, DFIFO_REG); + udelay(10); + NCR_700_writeb(0, host, DFIFO_REG); + } +} + STATIC int NCR_700_start_command(Scsi_Cmnd *SCp) { @@ -1227,9 +1412,10 @@ NCR_700_clear_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC); } - /* REQUEST_SENSE is asking for contingent I_T_L status. If a - * contingent allegiance condition exists, the device will - * refuse all tags, so send the request sense as untagged */ + /* REQUEST_SENSE is asking for contingent I_T_L(_Q) status. + * If a contingent allegiance condition exists, the device + * will refuse all tags, so send the request sense as untagged + * */ if((hostdata->tag_negotiated & (1<target)) && (slot->tag != NCR_700_NO_TAG && SCp->cmnd[0] != REQUEST_SENSE)) { hostdata->msgout[count++] = A_SIMPLE_TAG_MSG; @@ -1244,8 +1430,6 @@ NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); } - dma_cache_wback((unsigned long)hostdata->msgout, count); - script_patch_16(hostdata->script, MessageCount, count); @@ -1258,20 +1442,27 @@ /* finally plumb the beginning of the SG list into the script * */ script_patch_32_abs(hostdata->script, SGScriptStartAddress, - virt_to_bus(&slot->SG[0].ins)); - NCR_700_writeb(CLR_FIFO, SCp->host, DFIFO_REG); + to32bit(&slot->pSG[0].ins)); + NCR_700_clear_fifo(SCp->host); - /* set the synchronous period/offset */ if(slot->resume_offset == 0) slot->resume_offset = hostdata->pScript; + /* now perform all the writebacks and invalidates */ + dma_cache_wback((unsigned long)hostdata->msgout, count); + dma_cache_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE); + dma_cache_wback((unsigned long)SCp->cmnd, SCp->cmd_len); + dma_cache_inv((unsigned long)hostdata->status, 1); + + /* set the synchronous period/offset */ NCR_700_writeb(NCR_700_get_SXFER(SCp->device), - SCp->host, SXFER_REG); + SCp->host, SXFER_REG); + NCR_700_writel(slot->temp, SCp->host, TEMP_REG); + NCR_700_writel(slot->resume_offset, SCp->host, DSP_REG); + /* allow interrupts here so that if we're selected we can take * a selection interrupt. The script start may not be * effective in this case, but the selection interrupt will * save our command in that case */ - NCR_700_writel(slot->temp, SCp->host, TEMP_REG); - NCR_700_writel(slot->resume_offset, SCp->host, DSP_REG); restore_flags(flags); return 1; @@ -1342,8 +1533,8 @@ hostdata->state = NCR_700_HOST_BUSY; - printk(KERN_ERR "scsi%d: Bus Reset detected, executing command %p, slot %p, dsp %p[%04x]\n", - host->host_no, SCp, SCp == NULL ? NULL : SCp->host_scribble, (void *)dsp, dsp - hostdata->pScript); + printk(KERN_ERR "scsi%d: Bus Reset detected, executing command %p, slot %p, dsp %08x[%04x]\n", + host->host_no, SCp, SCp == NULL ? NULL : SCp->host_scribble, dsp, dsp - hostdata->pScript); /* clear all the negotiated parameters */ for(SDp = host->host_queue; SDp != NULL; SDp = SDp->next) @@ -1396,13 +1587,15 @@ printk("scsi%d (%d:%d) PHASE MISMATCH IN SEND MESSAGE %d remain, return %p[%04x], phase %s\n", host->host_no, pun, lun, count, (void *)temp, temp - hostdata->pScript, sbcl_to_string(NCR_700_readb(host, SBCL_REG))); #endif resume_offset = hostdata->pScript + Ent_SendMessagePhaseMismatch; - } else if(dsp >= virt_to_bus(&slot->SG[0].ins) && - dsp <= virt_to_bus(&slot->SG[NCR_700_SG_SEGMENTS].ins)) { + } else if(dsp >= to32bit(&slot->pSG[0].ins) && + dsp <= to32bit(&slot->pSG[NCR_700_SG_SEGMENTS].ins)) { int data_transfer = NCR_700_readl(host, DBC_REG) & 0xffffff; - int SGcount = (dsp - virt_to_bus(&slot->SG[0].ins))/sizeof(struct NCR_700_SG_List); + int SGcount = (dsp - to32bit(&slot->pSG[0].ins))/sizeof(struct NCR_700_SG_List); int residual = NCR_700_data_residual(host); int i; #ifdef NCR_700_DEBUG + __u32 naddr = NCR_700_readl(host, DNAD_REG); + printk("scsi%d: (%d:%d) Expected phase mismatch in slot->SG[%d], transferred 0x%x\n", host->host_no, pun, lun, SGcount, data_transfer); @@ -1427,6 +1620,11 @@ slot->SG[SGcount].ins |= bS_to_host(data_transfer); pAddr = bS_to_cpu(slot->SG[SGcount].pAddr); pAddr += (count - data_transfer); +#ifdef NCR_700_DEBUG + if(pAddr != naddr) { + printk("scsi%d (%d:%d) transfer mismatch pAddr=%lx, naddr=%lx, data_transfer=%d, residual=%d\n", host->host_no, pun, lun, (unsigned long)pAddr, (unsigned long)naddr, data_transfer, residual); + } +#endif slot->SG[SGcount].pAddr = bS_to_host(pAddr); } /* set the executed moves to nops */ @@ -1438,6 +1636,8 @@ /* and pretend we disconnected after * the command phase */ resume_offset = hostdata->pScript + Ent_MsgInDuringData; + /* make sure all the data is flushed */ + NCR_700_flush_fifo(host); } else { __u8 sbcl = NCR_700_readb(host, SBCL_REG); printk(KERN_ERR "scsi%d: (%d:%d) phase mismatch at %04x, phase %s\n", @@ -1449,15 +1649,19 @@ printk(KERN_ERR "scsi%d: (%d:%d) GROSS ERROR\n", host->host_no, pun, lun); NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16); + } else if(sstat0 & PARITY_ERROR) { + printk(KERN_ERR "scsi%d: (%d:%d) PARITY ERROR\n", + host->host_no, pun, lun); + NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16); } else if(dstat & SCRIPT_INT_RECEIVED) { DEBUG(("scsi%d: (%d:%d) ====>SCRIPT INTERRUPT<====\n", host->host_no, pun, lun)); resume_offset = process_script_interrupt(dsps, dsp, SCp, host, hostdata); } else if(dstat & (ILGL_INST_DETECTED)) { - printk(KERN_ERR "scsi%d: (%d:%d) Illegal Instruction detected at 0x%p[0x%x]!!!\n" + printk(KERN_ERR "scsi%d: (%d:%d) Illegal Instruction detected at 0x%08x[0x%x]!!!\n" " Please email James.Bottomley@HansenPartnership.com with the details\n", host->host_no, pun, lun, - (void *)dsp, dsp - hostdata->pScript); + dsp, dsp - hostdata->pScript); NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16); } else if(dstat & (WATCH_DOG_INTERRUPT|ABORTED)) { printk(KERN_ERR "scsi%d: (%d:%d) serious DMA problem, dstat=%02x\n", @@ -1495,13 +1699,13 @@ if(resume_offset) { if(hostdata->state != NCR_700_HOST_BUSY) { - printk(KERN_ERR "scsi%d: Driver error: resume at %p [%04x] with non busy host!\n", - host->host_no, (void *)resume_offset, resume_offset - hostdata->pScript); + printk(KERN_ERR "scsi%d: Driver error: resume at 0x%08x [0x%04x] with non busy host!\n", + host->host_no, resume_offset, resume_offset - hostdata->pScript); hostdata->state = NCR_700_HOST_BUSY; } DEBUG(("Attempting to resume at %x\n", resume_offset)); - NCR_700_writeb(CLR_FIFO, host, DFIFO_REG); + NCR_700_clear_fifo(host); NCR_700_writel(resume_offset, host, DSP_REG); } /* There is probably a technical no-no about this: If we're a @@ -1579,6 +1783,7 @@ struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)SCp->host->hostdata[0]; __u32 move_ins; + int pci_direction; struct NCR_700_command_slot *slot; int hash; @@ -1618,6 +1823,20 @@ printk("53c700: scsi%d, command ", SCp->host->host_no); print_command(SCp->cmnd); #endif + if(SCp->device->tagged_supported && !SCp->device->tagged_queue + && (hostdata->tag_negotiated &(1<target)) == 0 + && NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING)) { + /* upper layer has indicated tags are supported. We don't + * necessarily believe it yet. + * + * NOTE: There is a danger here: the mid layer supports + * tag queuing per LUN. We only support it per PUN because + * of potential reselection issues */ + printk(KERN_INFO "scsi%d: (%d:%d) Enabling Tag Command Queuing\n", SCp->device->host->host_no, SCp->target, SCp->lun); + hostdata->tag_negotiated |= (1<target); + NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING); + SCp->device->tagged_queue = 1; + } if(hostdata->tag_negotiated &(1<target)) { @@ -1681,36 +1900,11 @@ hostdata->ITL_Hash_back[hash] = slot; slot->ITL_back = NULL; - - /* This is f****g ridiculous; every low level HBA driver has - * to determine the direction of the commands, why isn't this - * done inside the scsi_lib !!??? */ switch (SCp->cmnd[0]) { case REQUEST_SENSE: /* clear the internal sense magic */ SCp->cmnd[6] = 0; /* fall through */ - case INQUIRY: - case MODE_SENSE: - case READ_6: - case READ_10: - case READ_12: - case READ_CAPACITY: - case READ_BLOCK_LIMITS: - case READ_TOC: - move_ins = SCRIPT_MOVE_DATA_IN; - break; - case MODE_SELECT: - case WRITE_6: - case WRITE_10: - case WRITE_12: - move_ins = SCRIPT_MOVE_DATA_OUT; - break; - case TEST_UNIT_READY: - case ALLOW_MEDIUM_REMOVAL: - case START_STOP: - move_ins = 0; - break; default: /* OK, get it from the command */ switch(SCp->sc_data_direction) { @@ -1734,26 +1928,40 @@ } /* now build the scatter gather list */ + pci_direction = scsi_to_pci_dma_dir(SCp->sc_data_direction); if(move_ins != 0) { int i; + int sg_count; + dma_addr_t vPtr = 0; + __u32 count = 0; + + if(SCp->use_sg) { + sg_count = pci_map_sg(hostdata->pci_dev, SCp->buffer, + SCp->use_sg, pci_direction); + } else { + vPtr = pci_map_single(hostdata->pci_dev, + SCp->request_buffer, + SCp->request_bufflen, + pci_direction); + count = SCp->request_bufflen; + slot->dma_handle = vPtr; + sg_count = 1; + } + - for(i = 0; i < (SCp->use_sg ? SCp->use_sg : 1); i++) { - void *vPtr; - __u32 count; + for(i = 0; i < sg_count; i++) { if(SCp->use_sg) { - vPtr = (((struct scatterlist *)SCp->buffer)[i].address); - count = ((struct scatterlist *)SCp->buffer)[i].length; - } else { - vPtr = SCp->request_buffer; - count = SCp->request_bufflen; + struct scatterlist *sg = SCp->buffer; + + vPtr = sg_dma_address(&sg[i]); + count = sg_dma_len(&sg[i]); } + slot->SG[i].ins = bS_to_host(move_ins | count); DEBUG((" scatter block %d: move %d[%08x] from 0x%lx\n", - i, count, slot->SG[i].ins, - virt_to_bus(vPtr))); - dma_cache_wback_inv((unsigned long)vPtr, count); - slot->SG[i].pAddr = bS_to_host(virt_to_bus(vPtr)); + i, count, slot->SG[i].ins, (unsigned long)vPtr)); + slot->SG[i].pAddr = bS_to_host(vPtr); } slot->SG[i].ins = bS_to_host(SCRIPT_RETURN); slot->SG[i].pAddr = 0; Index: drivers/scsi/53c700.h =================================================================== RCS file: /home/jejb/CVSROOT/linux/2.4/drivers/scsi/53c700.h,v retrieving revision 1.1.1.2 diff -u -r1.1.1.2 53c700.h --- drivers/scsi/53c700.h 2001/09/08 01:39:47 1.1.1.2 +++ drivers/scsi/53c700.h 2001/09/22 00:36:28 @@ -36,8 +36,8 @@ /* WARNING: Leave this in for now: the dependency preprocessor doesn't * pick up file specific flags, so must define here if they are not * set */ -#if !defined(IO_MAPPED) && !defined(MEM_MAPPED) -#define IO_MAPPED +#if !defined(CONFIG_53C700_IO_MAPPED) && !defined(CONFIG_53C700_MEM_MAPPED) +#error "Config.in must define either CONFIG_53C700_IO_MAPPED or CONFIG_53C700_MEM_MAPPED to use this scsi core." #endif @@ -90,43 +90,43 @@ static inline void NCR_700_set_SXFER(Scsi_Device *SDp, __u8 sxfer) { - ((__u32)SDp->hostdata) &= 0xffffff00; - ((__u32)SDp->hostdata) |= sxfer & 0xff; + ((unsigned long)SDp->hostdata) &= 0xffffff00; + ((unsigned long)SDp->hostdata) |= sxfer & 0xff; } static inline __u8 NCR_700_get_SXFER(Scsi_Device *SDp) { - return (((__u32)SDp->hostdata) & 0xff); + return (((unsigned long)SDp->hostdata) & 0xff); } static inline void NCR_700_set_depth(Scsi_Device *SDp, __u8 depth) { - ((__u32)SDp->hostdata) &= 0xffff00ff; - ((__u32)SDp->hostdata) |= (0xff00 & (depth << 8)); + ((unsigned long)SDp->hostdata) &= 0xffff00ff; + ((unsigned long)SDp->hostdata) |= (0xff00 & (depth << 8)); } static inline __u8 NCR_700_get_depth(Scsi_Device *SDp) { - return ((((__u32)SDp->hostdata) & 0xff00)>>8); + return ((((unsigned long)SDp->hostdata) & 0xff00)>>8); } static inline int NCR_700_is_flag_set(Scsi_Device *SDp, __u32 flag) { - return (((__u32)SDp->hostdata) & flag) == flag; + return (((unsigned long)SDp->hostdata) & flag) == flag; } static inline int NCR_700_is_flag_clear(Scsi_Device *SDp, __u32 flag) { - return (((__u32)SDp->hostdata) & flag) == 0; + return (((unsigned long)SDp->hostdata) & flag) == 0; } static inline void NCR_700_set_flag(Scsi_Device *SDp, __u32 flag) { - ((__u32)SDp->hostdata) |= (flag & 0xffff0000); + ((unsigned long)SDp->hostdata) |= (flag & 0xffff0000); } static inline void NCR_700_clear_flag(Scsi_Device *SDp, __u32 flag) { - ((__u32)SDp->hostdata) &= ~(flag & 0xffff0000); + ((unsigned long)SDp->hostdata) &= ~(flag & 0xffff0000); } /* These represent the Nexus hashing functions. A Nexus in SCSI terms @@ -162,6 +162,8 @@ } struct NCR_700_command_slot { + struct NCR_700_SG_List SG[NCR_700_SG_SEGMENTS+1]; + struct NCR_700_SG_List *pSG; #define NCR_700_SLOT_MASK 0xFC #define NCR_700_SLOT_MAGIC 0xb8 #define NCR_700_SLOT_FREE (0|NCR_700_SLOT_MAGIC) /* slot may be used */ @@ -170,10 +172,12 @@ __u8 state; #define NCR_700_NO_TAG 0xdead __u16 tag; - struct NCR_700_SG_List SG[NCR_700_SG_SEGMENTS+1]; __u32 resume_offset; Scsi_Cmnd *cmnd; __u32 temp; + /* if this command is a pci_single mapping, holds the dma address + * for later unmapping in the done routine */ + dma_addr_t dma_handle; /* Doubly linked ITL/ITLQ list kept in strict time order * (latest at the back) */ struct NCR_700_command_slot *ITL_forw; @@ -186,12 +190,16 @@ /* These must be filled in by the calling driver */ int clock; /* board clock speed in MHz */ __u32 base; /* the base for the port (copied to host) */ + struct pci_dev *pci_dev; + __u8 dmode_extra; /* adjustable bus settings */ __u8 differential:1; /* if we are differential */ -#ifdef __hppa__ +#ifdef CONFIG_53C700_LE_ON_BE /* This option is for HP only. Set it if your chip is wired for * little endian on this platform (which is big endian) */ __u8 force_le_on_be:1; #endif + __u8 chip710:1; /* set if really a 710 not 700 */ + __u8 burst_disable:1; /* set to 1 to disable 710 bursting */ /* NOTHING BELOW HERE NEEDS ALTERING */ __u8 fast:1; /* if we can alter the SCSI bus clock @@ -209,10 +217,11 @@ enum NCR_700_Host_State state; /* protected by state lock */ Scsi_Cmnd *cmd; - __u8 msgout[8]; + __u8 *msgout; +#define MSG_ARRAY_SIZE 16 __u8 tag_negotiated; - __u8 status; - __u8 msgin[8]; + __u8 *status; + __u8 *msgin; struct NCR_700_command_slot *slots; int saved_slot_position; int command_slot_count; /* protected by state lock */ @@ -237,7 +246,7 @@ /* * 53C700 Register Interface - the offset from the Selected base * I/O address */ -#ifdef __hppa__ +#ifdef CONFIG_53C700_LE_ON_BE #define bE (hostdata->force_le_on_be ? 0 : 3) #define bSWAP (hostdata->force_le_on_be) #elif defined(__BIG_ENDIAN) @@ -310,6 +319,7 @@ #define SODL_REG_FULL 0x20 #define SSTAT2_REG 0x0F #define CTEST0_REG 0x14 +#define BTB_TIMER_DISABLE 0x40 #define CTEST1_REG 0x15 #define CTEST2_REG 0x16 #define CTEST3_REG 0x17 @@ -327,6 +337,8 @@ #define MASTER_CONTROL 0x10 #define DMA_DIRECTION 0x08 #define CTEST7_REG 0x1B +#define BURST_DISABLE 0x80 /* 710 only */ +#define SEL_TIMEOUT_DISABLE 0x10 /* 710 only */ #define DFP 0x08 #define EVP 0x04 #define DIFF 0x01 @@ -337,6 +349,7 @@ #define CLR_FIFO 0x40 #define ISTAT_REG 0x21 #define ABORT_OPERATION 0x80 +#define SOFTWARE_RESET_710 0x40 #define DMA_INT_PENDING 0x01 #define SCSI_INT_PENDING 0x02 #define CONNECTED 0x08 @@ -345,27 +358,34 @@ #define SHORTEN_FILTERING 0x04 #define ENABLE_ACTIVE_NEGATION 0x10 #define GENERATE_RECEIVE_PARITY 0x20 +#define CLR_FIFO_710 0x04 +#define FLUSH_DMA_FIFO_710 0x08 #define CTEST9_REG 0x23 #define DBC_REG 0x24 #define DCMD_REG 0x27 #define DNAD_REG 0x28 #define DIEN_REG 0x39 +#define BUS_FAULT 0x20 #define ABORT_INT 0x10 #define INT_INST_INT 0x04 #define WD_INT 0x02 #define ILGL_INST_INT 0x01 #define DCNTL_REG 0x3B #define SOFTWARE_RESET 0x01 +#define COMPAT_700_MODE 0x01 #define SCRPTS_16BITS 0x20 #define ASYNC_DIV_2_0 0x00 -#define ASYNC_DIV_1_5 0x01 -#define ASYNC_DIV_1_0 0x02 -#define ASYNC_DIV_3_0 0x03 -#define DMODE_REG 0x34 +#define ASYNC_DIV_1_5 0x40 +#define ASYNC_DIV_1_0 0x80 +#define ASYNC_DIV_3_0 0xc0 +#define DMODE_710_REG 0x38 +#define DMODE_700_REG 0x34 #define BURST_LENGTH_1 0x00 #define BURST_LENGTH_2 0x40 #define BURST_LENGTH_4 0x80 #define BURST_LENGTH_8 0xC0 +#define DMODE_FC1 0x10 +#define DMODE_FC2 0x20 #define BW16 32 #define MODE_286 16 #define IO_XFER 8 @@ -377,7 +397,11 @@ /* Parameters to begin SDTR negotiations. Empirically, I find that * the 53c700-66 cannot handle an offset >8, so don't change this */ #define NCR_700_MAX_OFFSET 8 +/* Was hoping the max offset would be greater for the 710, but + * empirically it seems to be 8 also */ +#define NCR_710_MAX_OFFSET 8 #define NCR_700_MIN_XFERP 1 +#define NCR_710_MIN_XFERP 0 #define NCR_700_MIN_PERIOD 25 /* for SDTR message, 100ns */ #define script_patch_32(script, symbol, value) \ @@ -427,14 +451,14 @@ val |= ((value) & 0xffff); \ (script)[A_##symbol##_used[i]] = bS_to_host(val); \ dma_cache_wback((unsigned long)&(script)[A_##symbol##_used[i]], 4); \ - DEBUG((" script, patching ID field %s at %d to 0x%x\n", \ + DEBUG((" script, patching short field %s at %d to 0x%x\n", \ #symbol, A_##symbol##_used[i], val)); \ } \ } #endif -#ifdef MEM_MAPPED +#ifdef CONFIG_53C700_MEM_MAPPED static inline __u8 NCR_700_readb(struct Scsi_Host *host, __u32 reg) { @@ -482,7 +506,7 @@ writel(bS_to_host(value), host->base + reg); } -#elif defined(IO_MAPPED) +#elif defined(CONFIG_53C700_IO_MAPPED) static inline __u8 NCR_700_readb(struct Scsi_Host *host, __u32 reg) { Index: drivers/scsi/53c700.scr =================================================================== RCS file: /home/jejb/CVSROOT/linux/2.4/drivers/scsi/53c700.scr,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 53c700.scr --- drivers/scsi/53c700.scr 2001/05/14 23:48:23 1.1.1.1 +++ drivers/scsi/53c700.scr 2001/09/22 00:36:28 @@ -81,6 +81,7 @@ ABSOLUTE DISCONNECT_AFTER_CMD = 0x380 ABSOLUTE SDTR_MSG_AFTER_CMD = 0x360 ABSOLUTE WDTR_MSG_AFTER_CMD = 0x3A0 +ABSOLUTE MSG_IN_AFTER_STATUS = 0x440 ABSOLUTE DISCONNECT_AFTER_DATA = 0x580 ABSOLUTE MSG_IN_AFTER_DATA_IN = 0x550 ABSOLUTE MSG_IN_AFTER_DATA_OUT = 0x650 @@ -116,7 +117,8 @@ ; ; SCSI Messages we interpret in the script -; +; +ABSOLUTE COMMAND_COMPLETE_MSG = 0x00 ABSOLUTE EXTENDED_MSG = 0x01 ABSOLUTE SDTR_MSG = 0x01 ABSOLUTE SAVE_DATA_PTRS_MSG = 0x02 @@ -393,7 +395,12 @@ Finish: MOVE 1, StatusAddress, WHEN STATUS INT NOT_MSG_IN_AFTER_STATUS, WHEN NOT MSG_IN - CALL ReceiveMessage + MOVE 1, ReceiveMsgAddress, WHEN MSG_IN + JUMP FinishCommandComplete, IF COMMAND_COMPLETE_MSG + CALL ProcessReceiveMessage + INT MSG_IN_AFTER_STATUS + ENTRY FinishCommandComplete +FinishCommandComplete: CLEAR ACK WAIT DISCONNECT ENTRY Finish1 Index: drivers/scsi/Config.in =================================================================== RCS file: /home/jejb/CVSROOT/linux/2.4/drivers/scsi/Config.in,v retrieving revision 1.1.1.18 diff -u -r1.1.1.18 Config.in --- drivers/scsi/Config.in 2001/09/08 01:39:24 1.1.1.18 +++ drivers/scsi/Config.in 2001/09/22 00:36:28 @@ -115,9 +115,18 @@ fi fi dep_tristate 'NCR53c406a SCSI support' CONFIG_SCSI_NCR53C406A $CONFIG_SCSI -dep_tristate 'NCR Dual 700 MCA SCSI support' CONFIG_SCSI_NCR_D700 $CONFIG_SCSI $CONFIG_MCA +if [ "$CONFIG_MCA" = "y" ]; then + dep_tristate 'NCR Dual 700 MCA SCSI support' CONFIG_SCSI_NCR_D700 $CONFIG_SCSI + if [ "$CONFIG_SCSI_NCR_D700" != "n" ]; then + define_bool CONFIG_53C700_IO_MAPPED y + fi +fi if [ "$CONFIG_PARISC" = "y" ]; then - dep_tristate 'HP LASI SCSI support for 53c700' CONFIG_SCSI_LASI70 $CONFIG_SCSI + dep_tristate 'HP LASI SCSI support for 53c700' CONFIG_SCSI_LASI700 $CONFIG_SCSI + if [ "$CONFIG_SCSI_LASI700" != "n" ]; then + define_bool CONFIG_53C700_MEM_MAPPED y + define_bool CONFIG_53C700_LE_ON_BE y + fi fi dep_tristate 'NCR53c7,8xx SCSI support' CONFIG_SCSI_NCR53C7xx $CONFIG_SCSI $CONFIG_PCI if [ "$CONFIG_SCSI_NCR53C7xx" != "n" ]; then Index: drivers/scsi/Makefile =================================================================== RCS file: /home/jejb/CVSROOT/linux/2.4/drivers/scsi/Makefile,v retrieving revision 1.1.1.18 diff -u -r1.1.1.18 Makefile --- drivers/scsi/Makefile 2001/09/21 19:04:46 1.1.1.18 +++ drivers/scsi/Makefile 2001/09/22 00:36:28 @@ -31,7 +31,7 @@ endif endif -export-objs := scsi_syms.o 53c700.o 53c700-mem.o +export-objs := scsi_syms.o 53c700.o CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS @@ -125,7 +125,7 @@ obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o obj-$(CONFIG_SCSI_FCAL) += fcal.o obj-$(CONFIG_SCSI_CPQFCTS) += cpqfc.o -obj-$(CONFIG_SCSI_LASI700) += lasi700.o 53c700-mem.o +obj-$(CONFIG_SCSI_LASI700) += lasi700.o 53c700.o ifeq ($(CONFIG_ARCH_ACORN),y) mod-subdirs += ../acorn/scsi @@ -209,10 +209,3 @@ mv script.h 53c700_d.h 53c700.o: 53c700_d.h - -53c700-mem.o: 53c700_d.h - -53c700-mem.c: 53c700.c - echo "/* WARNING: GENERATED FILE (from $<), DO NOT MODIFY */" > $@ - echo "#define MEM_MAPPED" >> $@ - cat $< >> $@ Index: drivers/scsi/lasi700.c =================================================================== RCS file: /home/jejb/CVSROOT/linux/2.4/drivers/scsi/lasi700.c,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 lasi700.c --- drivers/scsi/lasi700.c 2001/09/08 01:39:48 1.1.1.1 +++ drivers/scsi/lasi700.c 2001/09/22 00:36:28 @@ -109,6 +109,7 @@ static int __initdata host_count = 0; static struct parisc_device_id lasi700_scsi_tbl[] = { LASI700_ID_TABLE, + LASI710_ID_TABLE, { 0 } }; @@ -136,32 +137,48 @@ { unsigned long base = dev->hpa + LASI_SCSI_CORE_OFFSET; int irq = busdevice_alloc_irq(dev); + char *driver_name; struct Scsi_Host *host; struct NCR_700_Host_Parameters *hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); + if(dev->id.sversion == LASI_700_SVERSION) { + driver_name = "lasi700"; + } else { + driver_name = "lasi710"; + } if(hostdata == NULL) { - printk(KERN_ERR "lasi700: Failed to allocate host data\n"); + printk(KERN_ERR "%s: Failed to allocate host data\n", + driver_name); return 1; } memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters)); - if(request_mem_region(base, 64, "lasi700") == NULL) { - printk(KERN_ERR "lasi700: Failed to claim memory region\n"); + if(request_mem_region(base, 64, driver_name) == NULL) { + printk(KERN_ERR "%s: Failed to claim memory region\n", + driver_name); kfree(hostdata); return 1; } hostdata->base = base; hostdata->differential = 0; - hostdata->clock = LASI700_CLOCK; - hostdata->force_le_on_be = 1; + if(dev->id.sversion == LASI_700_SVERSION) { + hostdata->clock = LASI700_CLOCK; + hostdata->force_le_on_be = 1; + } else { + hostdata->clock = LASI710_CLOCK; + hostdata->force_le_on_be = 0; + hostdata->chip710 = 1; + hostdata->dmode_extra = DMODE_FC2; + } if((host = NCR_700_detect(host_tpnt, hostdata)) == NULL) { kfree(hostdata); release_mem_region(host->base, 64); return 1; } host->irq = irq; - if(request_irq(irq, NCR_700_intr, SA_SHIRQ, "lasi700", host)) { - printk(KERN_ERR "lasi700: irq problem, detatching\n"); + if(request_irq(irq, NCR_700_intr, SA_SHIRQ, driver_name, host)) { + printk(KERN_ERR "%s: irq problem, detatching\n", + driver_name); scsi_unregister(host); NCR_700_release(host); return 1; Index: drivers/scsi/lasi700.h =================================================================== RCS file: /home/jejb/CVSROOT/linux/2.4/drivers/scsi/lasi700.h,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 lasi700.h --- drivers/scsi/lasi700.h 2001/09/08 01:39:48 1.1.1.1 +++ drivers/scsi/lasi700.h 2001/09/22 00:36:28 @@ -38,9 +38,19 @@ this_id: 7, \ } +#define LASI_710_SVERSION 0x082 +#define LASI_700_SVERSION 0x071 + #define LASI700_ID_TABLE { \ + hw_type: HPHW_FIO, \ + sversion: LASI_700_SVERSION, \ + hversion: HVERSION_ANY_ID, \ + hversion_rev: HVERSION_REV_ANY_ID, \ +} + +#define LASI710_ID_TABLE { \ hw_type: HPHW_FIO, \ - sversion: 0x071, \ + sversion: LASI_710_SVERSION, \ hversion: HVERSION_ANY_ID, \ hversion_rev: HVERSION_REV_ANY_ID, \ } @@ -52,6 +62,7 @@ } #define LASI700_CLOCK 25 +#define LASI710_CLOCK 40 #define LASI_SCSI_CORE_OFFSET 0x100 #endif