Index: linux/2.4/MAINTAINERS diff -u linux/2.4/MAINTAINERS:1.1.1.23 linux/2.4/MAINTAINERS:1.1.1.23.2.1 --- linux/2.4/MAINTAINERS:1.1.1.23 Sat Sep 1 20:49:53 2001 +++ linux/2.4/MAINTAINERS Sun Sep 2 22:18:29 2001 @@ -843,6 +843,12 @@ L: linux-x25@vger.kernel.org S: Maintained +LASI 53c700 driver for PARISC +P: James E.J. Bottomley +M: James.Bottomley@HansenPartnership.com +L: linux-scsi@vger.kernel.org +S: Maintained + LINUX FOR IBM pSERIES (RS/6000) P: Paul Mackerras M: paulus@au.ibm.com Index: linux/2.4/drivers/scsi/53c700.c diff -u linux/2.4/drivers/scsi/53c700.c:1.1.1.2 linux/2.4/drivers/scsi/53c700.c:1.1.1.2.2.4 --- linux/2.4/drivers/scsi/53c700.c:1.1.1.2 Sat Sep 1 21:03:09 2001 +++ linux/2.4/drivers/scsi/53c700.c Tue Sep 4 10:07:45 2001 @@ -51,12 +51,33 @@ /* CHANGELOG * + * Version 2.3 + * + * More endianness/cache coherency changes. + * + * Better bad device handling (handles devices lying about tag + * queueing support and devices which fail to provide sense data on + * contingent allegiance conditions) + * + * Many thanks to Richard Hirst for patiently + * debugging this driver on the parisc architecture and suggesting + * many improvements and bug fixes. + * + * Thanks also go to Linuxcare Inc. for providing several PARISC + * machines for me to debug the driver on. + * + * Version 2.2 + * + * Made the driver mem or io mapped; added endian invariance; added + * dma cache flushing operations for architectures which need it; + * added support for more varied clocking speeds. + * * Version 2.1 * * Initial modularisation from the D700. See NCR_D700.c for the rest of * the changelog. * */ -#define NCR_700_VERSION "2.1" +#define NCR_700_VERSION "2.3" #include #include @@ -92,6 +113,7 @@ MODULE_AUTHOR("James Bottomley"); MODULE_DESCRIPTION("53c700 and 53c700-66 Driver"); +MODULE_LICENSE("GPL"); /* This is the script */ #include "53c700_d.h" @@ -198,7 +220,8 @@ tpnt->proc_name = "53c700"; - host = scsi_register(tpnt, 4); + if((host = scsi_register(tpnt, 4)) == NULL) + return NULL; if(script == NULL) { printk(KERN_ERR "53c700: Failed to allocate script, detatching\n"); scsi_unregister(host); @@ -220,12 +243,14 @@ hostdata->slots[j].state = NCR_700_SLOT_FREE; } host->hostdata[0] = (__u32)hostdata; - memcpy(script, SCRIPT, sizeof(SCRIPT)); + 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]] += pScript; + script[LABELPATCHES[j]] = bS_to_host(pScript + SCRIPT[LABELPATCHES[j]]); } /* now patch up fixed addresses */ script_patch_32(script, MessageLocation, @@ -233,8 +258,9 @@ script_patch_32(script, StatusAddress, virt_to_bus(&hostdata->status)); script_patch_32(script, ReceiveMsgAddress, - virt_to_bus(&hostdata->msgin[0])) - hostdata->script = script; + virt_to_bus(&hostdata->msgin[0])); + + hostdata->script = script; hostdata->pScript = pScript; hostdata->state = NCR_700_HOST_FREE; spin_lock_init(&hostdata->lock); @@ -245,9 +271,9 @@ host->base = hostdata->base; host->hostdata[0] = (unsigned long)hostdata; /* kick the chip */ - outb(0xff, host->base + CTEST9_REG); - hostdata->rev = (inb(host->base + CTEST7_REG)<<4) & 0x0f; - hostdata->fast = (inb(host->base + CTEST9_REG) == 0); + NCR_700_writeb(0xff, host, CTEST9_REG); + 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; @@ -258,7 +284,7 @@ "(Differential)" : ""); /* reset the chip */ NCR_700_chip_reset(host); - outb(ASYNC_OPERATION , host->base + SXFER_REG); + NCR_700_writeb(ASYNC_OPERATION , host, SXFER_REG); return host; } @@ -295,25 +321,25 @@ NCR_700_data_residual (struct Scsi_Host *host) { int count, synchronous; unsigned int ddir; - - count = ((inb(host->base + DFIFO_REG) & 0x3f) - - (inl(host->base + DBC_REG) & 0x3f)) & 0x3f; + + count = ((NCR_700_readb(host, DFIFO_REG) & 0x3f) - + (NCR_700_readl(host, DBC_REG) & 0x3f)) & 0x3f; - synchronous = inb(host->base + SXFER_REG) & 0x0f; + synchronous = NCR_700_readb(host, SXFER_REG) & 0x0f; /* get the data direction */ - ddir = inb(host->base + CTEST0_REG) & 0x01; + ddir = NCR_700_readb(host, CTEST0_REG) & 0x01; if (ddir) { /* Receive */ if (synchronous) - count += (inb(host->base + SSTAT2_REG) & 0xf0) >> 4; + count += (NCR_700_readb(host, SSTAT2_REG) & 0xf0) >> 4; else - if (inb(host->base + SSTAT1_REG) & SIDL_REG_FULL) + if (NCR_700_readb(host, SSTAT1_REG) & SIDL_REG_FULL) ++count; } else { /* Send */ - __u8 sstat = inb(host->base + SSTAT1_REG); + __u8 sstat = NCR_700_readb(host, SSTAT1_REG); if (sstat & SODL_REG_FULL) ++count; if (synchronous && (sstat & SODR_REG_FULL)) @@ -390,10 +416,10 @@ if((slot->state & NCR_700_SLOT_MASK) != NCR_700_SLOT_MAGIC) { - printk(" SLOT %p is not MAGIC!!!\n", slot); + printk(KERN_ERR "53c700: SLOT %p is not MAGIC!!!\n", slot); } if(slot->state == NCR_700_SLOT_FREE) { - printk(" SLOT %p is FREE!!!\n", slot); + printk(KERN_ERR "53c700: SLOT %p is FREE!!!\n", slot); } /* remove from queues */ if(slot->tag != NCR_700_NO_TAG) { @@ -484,7 +510,7 @@ if(n != NULL && n->cmnd->target == pun && n->cmnd->lun == lun && n->tag == tag) { - printk("\n\n**WARNING: DUPLICATE tag %d\n", + printk(KERN_WARNING "53c700: WARNING: DUPLICATE tag %d\n", tag); } } @@ -497,15 +523,19 @@ /* This translates the SDTR message offset and period to a value * which can be loaded into the SXFER_REG. * - * NOTE: According to SCSI-2, the true transfer period is actually - * four times this period value (in ns) */ + * NOTE: According to SCSI-2, the true transfer period (in ns) is + * actually four times this period value */ STATIC inline __u8 NCR_700_offset_period_to_sxfer(struct NCR_700_Host_Parameters *hostdata, __u8 offset, __u8 period) { int XFERP; - XFERP = (period*4 * hostdata->clock)/1000 - 4; + 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; + } + 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); @@ -552,7 +582,7 @@ NCR_700_get_depth(SCp->device)); NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) - 1); } else { - printk(KERN_ERR " SCSI DONE HAS NULL SCp\n"); + printk(KERN_ERR "53c700: SCSI DONE HAS NULL SCp\n"); } } @@ -561,9 +591,9 @@ NCR_700_internal_bus_reset(struct Scsi_Host *host) { /* Bus reset */ - outb(ASSERT_RST, host->base + SCNTL1_REG); + NCR_700_writeb(ASSERT_RST, host, SCNTL1_REG); udelay(50); - outb(0, host->base + SCNTL1_REG); + NCR_700_writeb(0, host, SCNTL1_REG); } @@ -573,37 +603,63 @@ struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)host->hostdata[0]; - outb(1 << host->this_id, host->base + SCID_REG); - outb(0, host->base + SBCL_REG); - outb(0, host->base + SXFER_REG); - - outb(PHASE_MM_INT | SEL_TIMEOUT_INT | GROSS_ERR_INT | UX_DISC_INT - | RST_INT | PAR_ERR_INT | SELECT_INT, host->base + SIEN_REG); - - outb(ABORT_INT | INT_INST_INT | ILGL_INST_INT, host->base + DIEN_REG); - outb(BURST_LENGTH_8, host->base + DMODE_REG); - outb(FULL_ARBITRATION | PARITY | AUTO_ATN, host->base + SCNTL0_REG); - outb(LAST_DIS_ENBL | ENABLE_ACTIVE_NEGATION|GENERATE_RECEIVE_PARITY, - host->base + CTEST8_REG); - outb(ENABLE_SELECT, host->base + SCNTL1_REG); - if(hostdata->clock > 50) - printk(KERN_ERR "53c700: Clock speed %dMHz is too high: contact James.Bottomley@HansenPartnership.com to modify the divider\n", hostdata->clock); - /* Set the synchronous SCSI divider to 1 so we drive the - * synchronous command clock at this speed */ - outb(1, host->base + SBCL_REG); - /* set the clock bits to 0 which is a divider of 2 so the - * async frequency is exactly half this speed */ - outb(0x00, host->base + DCNTL_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(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); + /* do the best we can, but the async clock will be out + * 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); + 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); + hostdata->sync_clock = hostdata->clock*2; + hostdata->sync_clock /= 3; + + } else if(hostdata->clock > 37 && hostdata->clock <= 50) { + /* 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); + 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); + 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); + /* sync divider 1, async divider 1 */ + } } STATIC void NCR_700_chip_reset(struct Scsi_Host *host) { /* Chip reset */ - outb(SOFTWARE_RESET, host->base + DCNTL_REG); + NCR_700_writeb(SOFTWARE_RESET, host, DCNTL_REG); udelay(100); - outb(0, host->base + DCNTL_REG); + NCR_700_writeb(0, host, DCNTL_REG); mdelay(1000); @@ -653,14 +709,15 @@ NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC); NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); - outb(NCR_700_get_SXFER(SCp->device), - host->base + SXFER_REG); + NCR_700_writeb(NCR_700_get_SXFER(SCp->device), + host, SXFER_REG); } else { /* SDTR message out of the blue, reject it */ 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)); script_patch_16(hostdata->script, MessageCount, 1); /* SendMsgOut returns, so set up the return * address */ @@ -672,6 +729,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)); script_patch_16(hostdata->script, MessageCount, 1); resume_offset = hostdata->pScript + Ent_SendMessageWithATN; @@ -685,12 +743,13 @@ printk("\n"); /* just reject it */ hostdata->msgout[0] = A_REJECT_MSG; + dma_cache_wback((unsigned long)hostdata->msgout, sizeof(hostdata->msgout)); script_patch_16(hostdata->script, MessageCount, 1); /* SendMsgOut returns, so set up the return * address */ resume_offset = hostdata->pScript + Ent_SendMessageWithATN; } - outl(temp, host->base + TEMP_REG); + NCR_700_writel(temp, host, TEMP_REG); return resume_offset; } @@ -702,6 +761,8 @@ __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; @@ -726,6 +787,11 @@ NCR_700_set_SXFER(SCp->device, 0); NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC); NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); + } else if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING)) { + /* rejected our first simple tag message */ + 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); } else { printk(KERN_WARNING "scsi%d (%d:%d) Unexpected REJECT Message %s\n", host->host_no, pun, lun, @@ -735,12 +801,12 @@ break; case A_PARITY_ERROR_MSG: - printk("scsi%d (%d:%d) Parity Error!\n", host->host_no, + printk(KERN_ERR "scsi%d (%d:%d) Parity Error!\n", host->host_no, pun, lun); NCR_700_internal_bus_reset(host); break; case A_SIMPLE_TAG_MSG: - printk("scsi%d (%d:%d) SIMPLE TAG %d %s\n", host->host_no, + printk(KERN_INFO "scsi%d (%d:%d) SIMPLE TAG %d %s\n", host->host_no, pun, lun, hostdata->msgin[1], NCR_700_phase[(dsps & 0xf00) >> 8]); /* just ignore it */ @@ -754,6 +820,7 @@ printk("\n"); /* just reject it */ hostdata->msgout[0] = A_REJECT_MSG; + dma_cache_wback((unsigned long)hostdata->msgout, sizeof(hostdata->msgout)); script_patch_16(hostdata->script, MessageCount, 1); /* SendMsgOut returns, so set up the return * address */ @@ -761,7 +828,7 @@ break; } - outl(temp, host->base + TEMP_REG); + NCR_700_writel(temp, host, TEMP_REG); return resume_offset; } @@ -779,43 +846,55 @@ } 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)); + /* 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) { 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); + } else { - DEBUG((" cmd %p has status %d, requesting sense\n", - SCp, hostdata->status)); - /* we can destroy the command here because the - * contingent allegiance condition will cause a - * retry which will re-copy the command from the - * saved data_cmnd */ - SCp->cmnd[0] = REQUEST_SENSE; - SCp->cmnd[1] = (SCp->lun & 0x7) << 5; - SCp->cmnd[2] = 0; - SCp->cmnd[3] = 0; - SCp->cmnd[4] = sizeof(SCp->sense_buffer); - SCp->cmnd[5] = 0; - SCp->cmd_len = 6; - /* Here's a quiet hack: the REQUEST_SENSE command is - * six bytes, so store a flag indicating that this - * 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; - slot->SG[0].ins = SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer); - slot->SG[0].pAddr = virt_to_bus(SCp->sense_buffer); - slot->SG[1].ins = SCRIPT_RETURN; - slot->SG[1].pAddr = 0; - slot->resume_offset = hostdata->pScript; - - /* queue the command for reissue */ - slot->state = NCR_700_SLOT_QUEUED; - hostdata->state = NCR_700_HOST_FREE; - hostdata->cmd = NULL; + DEBUG((" cmd %p has status %d, requesting sense\n", + SCp, hostdata->status)); + /* we can destroy the command here because the + * contingent allegiance condition will cause a + * retry which will re-copy the command from the + * saved data_cmnd */ + SCp->cmnd[0] = REQUEST_SENSE; + SCp->cmnd[1] = (SCp->lun & 0x7) << 5; + SCp->cmnd[2] = 0; + SCp->cmnd[3] = 0; + SCp->cmnd[4] = sizeof(SCp->sense_buffer); + SCp->cmnd[5] = 0; + SCp->cmd_len = 6; + /* Here's a quiet hack: the REQUEST_SENSE command is + * six bytes, so store a flag indicating that this + * 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; + 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); + slot->SG[1].pAddr = 0; + slot->resume_offset = hostdata->pScript; + dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG[0])*2); + dma_cache_inv((unsigned long)SCp->sense_buffer, sizeof(SCp->sense_buffer)); + + /* queue the command for reissue */ + slot->state = NCR_700_SLOT_QUEUED; + hostdata->state = NCR_700_HOST_FREE; + hostdata->cmd = NULL; + } } else { if(status_byte(hostdata->status) == GOOD && SCp->cmnd[0] == INQUIRY && SCp->use_sg == 0) { @@ -824,7 +903,9 @@ 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); } } @@ -836,8 +917,8 @@ printk(KERN_ERR "scsi%d: (%d:%d), UNEXPECTED PHASE %s (%s)\n", host->host_no, pun, lun, NCR_700_phase[i], - sbcl_to_string(inb(host->base + SBCL_REG))); - printk(" len = %d, cmd =", SCp->cmd_len); + sbcl_to_string(NCR_700_readb(host, SBCL_REG))); + printk(KERN_ERR " len = %d, cmd =", SCp->cmd_len); print_command(SCp->cmnd); NCR_700_internal_bus_reset(host); @@ -862,10 +943,14 @@ save_for_reselection(hostdata, SCp, dsp); } else if(dsps == A_RESELECTION_IDENTIFIED) { - __u8 lun = hostdata->msgin[0] & 0x1f; + __u8 lun; 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; DEBUG(("scsi%d: (%d:%d) RESELECTED!\n", host->host_no, reselection_id, lun)); @@ -918,8 +1003,8 @@ * that ACK is still asserted when we process * the reselection message. The resume offset * should therefore always clear ACK */ - outb(NCR_700_get_SXFER(hostdata->cmd->device), - host->base + SXFER_REG); + NCR_700_writeb(NCR_700_get_SXFER(hostdata->cmd->device), + host, SXFER_REG); } } else if(dsps == A_RESELECTED_DURING_SELECTION) { @@ -931,13 +1016,13 @@ * selection interrupt before we manage to get to the * reselected script interrupt */ - __u8 reselection_id = inb(host->base + SFBR_REG); + __u8 reselection_id = NCR_700_readb(host, SFBR_REG); struct NCR_700_command_slot *slot; /* Take out our own ID */ reselection_id &= ~(1<this_id); - printk("scsi%d: (%d:%d) RESELECTION DURING SELECTION, dsp=%p[%04x] state=%d, count=%d\n", + 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); { @@ -950,7 +1035,7 @@ && SG <= (__u32)(&hostdata->slots[i].SG[NCR_700_SG_SEGMENTS])) break; } - printk("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 %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); SCp = hostdata->slots[i].cmnd; } @@ -977,6 +1062,7 @@ } hostdata->reselection_id = reselection_id; hostdata->msgin[1] = 0; + dma_cache_wback((unsigned long)hostdata->msgin, sizeof(hostdata->msgin)); if(hostdata->tag_negotiated & (1<pScript + Ent_GetReselectionWithTag; } else { @@ -1000,13 +1086,13 @@ if(SCp->use_sg) { for(i = 0; i < SCp->use_sg + 1; i++) { - printk(" SG[%d].length = %d, move_insn=%08x, addr %08x\n", i, ((struct scatterlist *)SCp->buffer)[i].length, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].ins, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].pAddr); + printk(KERN_INFO " SG[%d].length = %d, move_insn=%08x, addr %08x\n", i, ((struct scatterlist *)SCp->buffer)[i].length, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].ins, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].pAddr); } } } NCR_700_internal_bus_reset(host); } else if((dsps & 0xfffff000) == A_DEBUG_INTERRUPT) { - printk("scsi%d (%d:%d) DEBUG INTERRUPT %d AT %p[%04x], continuing\n", + 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); resume_offset = dsp; } else { @@ -1027,7 +1113,7 @@ STATIC inline __u32 process_selection(struct Scsi_Host *host, __u32 dsp) { - __u8 id; + __u8 id = 0; /* Squash compiler warning */ int count = 0; __u32 resume_offset = 0; struct NCR_700_Host_Parameters *hostdata = @@ -1036,7 +1122,7 @@ __u8 sbcl; for(count = 0; count < 5; count++) { - id = inb(host->base + SFBR_REG); + id = NCR_700_readb(host, SFBR_REG); /* Take out our own ID */ id &= ~(1<this_id); @@ -1044,7 +1130,7 @@ break; udelay(5); } - sbcl = inb(host->base + SBCL_REG); + sbcl = NCR_700_readb(host, SBCL_REG); if((sbcl & SBCL_IO) == 0) { /* mark as having been selected rather than reselected */ id = 0xff; @@ -1057,7 +1143,7 @@ if(hostdata->state == NCR_700_HOST_BUSY && SCp != NULL) { struct NCR_700_command_slot *slot = (struct NCR_700_command_slot *)SCp->host_scribble; - DEBUG((" ID %d WARNING: RESELECTION OF BUSY HOST, saving cmd %p, slot %p, addr %p [%04x], resume %p!\n", id, hostdata->cmd, slot, dsp, dsp - hostdata->pScript, resume_offset)); + DEBUG((" ID %d WARNING: RESELECTION OF BUSY HOST, saving cmd %p, slot %p, addr %x [%04x], resume %x!\n", id, hostdata->cmd, slot, dsp, dsp - hostdata->pScript, resume_offset)); switch(dsp - hostdata->pScript) { case Ent_Disconnect1: @@ -1089,6 +1175,7 @@ hostdata->state = NCR_700_HOST_BUSY; hostdata->cmd = NULL; hostdata->msgin[1] = 0; + dma_cache_wback((unsigned long)hostdata->msgin, sizeof(hostdata->msgin)); if(id == 0xff) { /* Selected as target, Ignore */ @@ -1157,6 +1244,8 @@ 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); @@ -1170,19 +1259,19 @@ * */ script_patch_32_abs(hostdata->script, SGScriptStartAddress, virt_to_bus(&slot->SG[0].ins)); - outb(CLR_FIFO, SCp->host->base + DFIFO_REG); + NCR_700_writeb(CLR_FIFO, SCp->host, DFIFO_REG); /* set the synchronous period/offset */ if(slot->resume_offset == 0) slot->resume_offset = hostdata->pScript; - outb(NCR_700_get_SXFER(SCp->device), - SCp->host->base + SXFER_REG); + NCR_700_writeb(NCR_700_get_SXFER(SCp->device), + SCp->host, SXFER_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 */ - outl(slot->temp, SCp->host->base + TEMP_REG); - outl(slot->resume_offset, SCp->host->base + DSP_REG); + NCR_700_writel(slot->temp, SCp->host, TEMP_REG); + NCR_700_writel(slot->resume_offset, SCp->host, DSP_REG); restore_flags(flags); return 1; @@ -1211,7 +1300,7 @@ * hostdata->lock would be the reverse of taking it in this * routine */ spin_lock_irqsave(&io_request_lock, flags); - if((istat = inb(host->base + ISTAT_REG)) + if((istat = NCR_700_readb(host, ISTAT_REG)) & (SCSI_INT_PENDING | DMA_INT_PENDING)) { __u32 dsps; __u8 sstat0 = 0, dstat = 0; @@ -1225,19 +1314,19 @@ if(istat & SCSI_INT_PENDING) { udelay(10); - sstat0 = inb(host->base + SSTAT0_REG); + sstat0 = NCR_700_readb(host, SSTAT0_REG); } if(istat & DMA_INT_PENDING) { udelay(10); - dstat = inb(host->base + DSTAT_REG); + dstat = NCR_700_readb(host, DSTAT_REG); } - dsps = inl(host->base + DSPS_REG); - dsp = inl(host->base + DSP_REG); + dsps = NCR_700_readl(host, DSPS_REG); + dsp = NCR_700_readl(host, DSP_REG); - DEBUG(("scsi%d: istat %02x sstat0 %02x dstat %02x dsp %04x[%08lx] dsps 0x%x\n", + DEBUG(("scsi%d: istat %02x sstat0 %02x dstat %02x dsp %04x[%08x] dsps 0x%x\n", host->host_no, istat, sstat0, dstat, (dsp - (__u32)virt_to_bus(hostdata->script))/4, dsp, dsps)); @@ -1301,14 +1390,15 @@ if(dsp == Ent_SendMessage + 8 + hostdata->pScript) { /* It wants to reply to some part of * our message */ - __u32 temp = inl(host->base + TEMP_REG); - - int count = (hostdata->script[Ent_SendMessage/4] & 0xffffff) - ((inl(host->base + DBC_REG) & 0xffffff) + NCR_700_data_residual(host)); - 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(inb(host->base + SBCL_REG))); +#ifdef NCR_700_DEBUG + __u32 temp = NCR_700_readl(host, TEMP_REG); + int count = (hostdata->script[Ent_SendMessage/4] & 0xffffff) - ((NCR_700_readl(host, DBC_REG) & 0xffffff) + NCR_700_data_residual(host)); + 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)) { - int data_transfer = inl(host->base + DBC_REG) & 0xffffff; + 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 residual = NCR_700_data_residual(host); int i; @@ -1327,24 +1417,29 @@ if(data_transfer != 0) { int count; + __u32 pAddr; + SGcount--; - count = (slot->SG[SGcount].ins & 0x00ffffff); + count = (bS_to_cpu(slot->SG[SGcount].ins) & 0x00ffffff); DEBUG(("DATA TRANSFER MISMATCH, count = %d, transferred %d\n", count, count-data_transfer)); - slot->SG[SGcount].ins &= 0xff000000; - slot->SG[SGcount].ins |= data_transfer; - slot->SG[SGcount].pAddr += (count - data_transfer); + slot->SG[SGcount].ins &= bS_to_host(0xff000000); + slot->SG[SGcount].ins |= bS_to_host(data_transfer); + pAddr = bS_to_cpu(slot->SG[SGcount].pAddr); + pAddr += (count - data_transfer); + slot->SG[SGcount].pAddr = bS_to_host(pAddr); } /* set the executed moves to nops */ for(i=0; iSG[i].ins = SCRIPT_NOP; + slot->SG[i].ins = bS_to_host(SCRIPT_NOP); slot->SG[i].pAddr = 0; } + dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG)); /* and pretend we disconnected after * the command phase */ resume_offset = hostdata->pScript + Ent_MsgInDuringData; } else { - __u8 sbcl = inb(host->base + SBCL_REG); + __u8 sbcl = NCR_700_readb(host, SBCL_REG); printk(KERN_ERR "scsi%d: (%d:%d) phase mismatch at %04x, phase %s\n", host->host_no, pun, lun, dsp - hostdata->pScript, sbcl_to_string(sbcl)); NCR_700_internal_bus_reset(host); @@ -1406,8 +1501,8 @@ } DEBUG(("Attempting to resume at %x\n", resume_offset)); - outb(CLR_FIFO, host->base + DFIFO_REG); - outl(resume_offset, host->base + DSP_REG); + NCR_700_writeb(CLR_FIFO, host, DFIFO_REG); + NCR_700_writel(resume_offset, host, DSP_REG); } /* There is probably a technical no-no about this: If we're a * shared interrupt and we got this interrupt because the @@ -1468,7 +1563,7 @@ Target Depth Active Next Tag\n\ ====== ===== ====== ========\n"); for(SDp = host->host_queue; SDp != NULL; SDp = SDp->next) { - len += sprintf(&buf[len],"%2d:%2d %4d %4d %4d\n", SDp->id, SDp->lun, SDp->queue_depth, NCR_700_get_depth(SDp), SDp->current_tag); + len += sprintf(&buf[len]," %2d:%2d %4d %4d %4d\n", SDp->id, SDp->lun, SDp->queue_depth, NCR_700_get_depth(SDp), SDp->current_tag); } if((len -= offset) <= 0) return 0; @@ -1653,15 +1748,17 @@ vPtr = SCp->request_buffer; count = SCp->request_bufflen; } - slot->SG[i].ins = move_ins | count; - DEBUG((" scatter block %d: move %d[%08lx] from 0x%lx\n", - i, count, slot->SG[i].move_ins, + 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))); - slot->SG[i].pAddr = virt_to_bus(vPtr); + dma_cache_wback_inv((unsigned long)vPtr, count); + slot->SG[i].pAddr = bS_to_host(virt_to_bus(vPtr)); } - slot->SG[i].ins = SCRIPT_RETURN; + slot->SG[i].ins = bS_to_host(SCRIPT_RETURN); slot->SG[i].pAddr = 0; - DEBUG((" SETTING %08x to %x\n", + dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG)); + DEBUG((" SETTING %08lx to %x\n", virt_to_bus(&slot->SG[i].ins), slot->SG[i].ins)); } @@ -1677,7 +1774,7 @@ struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)SCp->host->hostdata[0]; - printk("scsi%d (%d:%d) New error handler wants to abort command\n\t", + printk(KERN_INFO "scsi%d (%d:%d) New error handler wants to abort command\n\t", SCp->host->host_no, SCp->target, SCp->lun); print_command(SCp->cmnd); @@ -1709,7 +1806,7 @@ STATIC int NCR_700_bus_reset(Scsi_Cmnd * SCp) { - printk("scsi%d (%d:%d) New error handler wants BUS reset, cmd %p\n\t", + printk(KERN_INFO "scsi%d (%d:%d) New error handler wants BUS reset, cmd %p\n\t", SCp->host->host_no, SCp->target, SCp->lun, SCp); print_command(SCp->cmnd); NCR_700_internal_bus_reset(SCp->host); @@ -1719,7 +1816,7 @@ STATIC int NCR_700_dev_reset(Scsi_Cmnd * SCp) { - printk("scsi%d (%d:%d) New error handler wants device reset\n\t", + printk(KERN_INFO "scsi%d (%d:%d) New error handler wants device reset\n\t", SCp->host->host_no, SCp->target, SCp->lun); print_command(SCp->cmnd); @@ -1729,7 +1826,7 @@ STATIC int NCR_700_host_reset(Scsi_Cmnd * SCp) { - printk("scsi%d (%d:%d) New error handler wants HOST reset\n\t", + printk(KERN_INFO "scsi%d (%d:%d) New error handler wants HOST reset\n\t", SCp->host->host_no, SCp->target, SCp->lun); print_command(SCp->cmnd); Index: linux/2.4/drivers/scsi/53c700.h diff -u linux/2.4/drivers/scsi/53c700.h:1.1.1.1 linux/2.4/drivers/scsi/53c700.h:1.1.1.1.12.3 --- linux/2.4/drivers/scsi/53c700.h:1.1.1.1 Mon May 14 18:48:23 2001 +++ linux/2.4/drivers/scsi/53c700.h Sun Sep 2 22:18:30 2001 @@ -33,7 +33,14 @@ /* magic byte identifying an internally generated REQUEST_SENSE command */ #define NCR_700_INTERNAL_SENSE_MAGIC 0x42 +/* 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 +#endif + struct NCR_700_Host_Parameters; /* These are the externally used routines */ @@ -78,7 +85,7 @@ * 18 device supports tag queueing */ #define NCR_700_DEV_NEGOTIATED_SYNC (1<<16) #define NCR_700_DEV_BEGIN_SYNC_NEGOTIATION (1<<17) -#define NCR_700_DEV_USES_TAG_QUEUEING (1<<18) +#define NCR_700_DEV_BEGIN_TAG_QUEUEING (1<<18) static inline void NCR_700_set_SXFER(Scsi_Device *SDp, __u8 sxfer) @@ -180,11 +187,18 @@ int clock; /* board clock speed in MHz */ __u32 base; /* the base for the port (copied to host) */ __u8 differential:1; /* if we are differential */ +#ifdef __hppa__ + /* 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 /* NOTHING BELOW HERE NEEDS ALTERING */ __u8 fast:1; /* if we can alter the SCSI bus clock speed (so can negiotiate sync) */ + int sync_clock; /* The speed of the SYNC core */ + __u32 *script; /* pointer to script location */ __u32 pScript; /* physical mem addr of script */ @@ -196,7 +210,6 @@ Scsi_Cmnd *cmd; __u8 msgout[8]; - __u8 msgout_size; __u8 tag_negotiated; __u8 status; __u8 msgin[8]; @@ -224,7 +237,23 @@ /* * 53C700 Register Interface - the offset from the Selected base * I/O address */ +#ifdef __hppa__ +#define bE (hostdata->force_le_on_be ? 0 : 3) +#define bSWAP (hostdata->force_le_on_be) +#elif defined(__BIG_ENDIAN) +#define bE 3 +#define bSWAP 0 +#elif defined(__LITTLE_ENDIAN) +#define bE 0 +#define bSWAP 0 +#else +#error "__BIG_ENDIAN or __LITTLE_ENDIAN must be defined, did you include byteorder.h?" +#endif +#define bS_to_cpu(x) (bSWAP ? le32_to_cpu(x) : (x)) +#define bS_to_host(x) (bSWAP ? cpu_to_le32(x) : (x)) +/* NOTE: These registers are in the LE register space only, the required byte + * swapping is done by the NCR_700_{read|write}[b] functions */ #define SCNTL0_REG 0x00 #define FULL_ARBITRATION 0xc0 #define PARITY 0x08 @@ -254,7 +283,13 @@ #define SIDL_REG 0x09 #define SBDL_REG 0x0A #define SBCL_REG 0x0B +/* read bits */ #define SBCL_IO 0x01 +/*write bits */ +#define SYNC_DIV_AS_ASYNC 0x00 +#define SYNC_DIV_1_0 0x01 +#define SYNC_DIV_1_5 0x02 +#define SYNC_DIV_2_0 0x03 #define DSTAT_REG 0x0C #define ILGL_INST_DETECTED 0x01 #define WATCH_DOG_INTERRUPT 0x02 @@ -322,6 +357,10 @@ #define DCNTL_REG 0x3B #define SOFTWARE_RESET 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 BURST_LENGTH_1 0x00 #define BURST_LENGTH_2 0x40 @@ -345,8 +384,10 @@ { \ int i; \ for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \ - (script)[A_##symbol##_used[i]] += (value); \ - DEBUG((" script, patching %s at %ld to 0x%lx\n", \ + __u32 val = bS_to_cpu((script)[A_##symbol##_used[i]]) + value; \ + (script)[A_##symbol##_used[i]] = bS_to_host(val); \ + dma_cache_wback((unsigned long)&(script)[A_##symbol##_used[i]], 4); \ + DEBUG((" script, patching %s at %d to 0x%lx\n", \ #symbol, A_##symbol##_used[i], (value))); \ } \ } @@ -355,8 +396,9 @@ { \ int i; \ for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \ - (script)[A_##symbol##_used[i]] = (value); \ - DEBUG((" script, patching %s at %ld to 0x%lx\n", \ + (script)[A_##symbol##_used[i]] = bS_to_host(value); \ + dma_cache_wback((unsigned long)&(script)[A_##symbol##_used[i]], 4); \ + DEBUG((" script, patching %s at %d to 0x%lx\n", \ #symbol, A_##symbol##_used[i], (value))); \ } \ } @@ -366,11 +408,12 @@ { \ int i; \ for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \ - __u32 val = (script)[A_##symbol##_used[i]]; \ + __u32 val = bS_to_cpu((script)[A_##symbol##_used[i]]); \ val &= 0xff00ffff; \ val |= ((value) & 0xff) << 16; \ - (script)[A_##symbol##_used[i]] = val; \ - DEBUG((" script, patching ID field %s at %ld to 0x%lx\n", \ + (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", \ #symbol, A_##symbol##_used[i], val)); \ } \ } @@ -379,13 +422,113 @@ { \ int i; \ for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \ - __u32 val = (script)[A_##symbol##_used[i]]; \ + __u32 val = bS_to_cpu((script)[A_##symbol##_used[i]]); \ val &= 0xffff0000; \ val |= ((value) & 0xffff); \ - (script)[A_##symbol##_used[i]] = val; \ - DEBUG((" script, patching ID field %s at %ld to 0x%lx\n", \ + (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", \ #symbol, A_##symbol##_used[i], val)); \ } \ } +#endif + +#ifdef MEM_MAPPED +static inline __u8 +NCR_700_readb(struct Scsi_Host *host, __u32 reg) +{ + const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) + = (struct NCR_700_Host_Parameters *)host->hostdata[0]; + + return readb(host->base + (reg^bE)); +} + +static inline __u32 +NCR_700_readl(struct Scsi_Host *host, __u32 reg) +{ + __u32 value = readl(host->base + reg); + const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) + = (struct NCR_700_Host_Parameters *)host->hostdata[0]; +#if 1 + /* sanity check the register */ + if((reg & 0x3) != 0) + BUG(); +#endif + + return bS_to_cpu(value); +} + +static inline void +NCR_700_writeb(__u8 value, struct Scsi_Host *host, __u32 reg) +{ + const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) + = (struct NCR_700_Host_Parameters *)host->hostdata[0]; + + writeb(value, host->base + (reg^bE)); +} + +static inline void +NCR_700_writel(__u32 value, struct Scsi_Host *host, __u32 reg) +{ + const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) + = (struct NCR_700_Host_Parameters *)host->hostdata[0]; + +#if 1 + /* sanity check the register */ + if((reg & 0x3) != 0) + BUG(); +#endif + + writel(bS_to_host(value), host->base + reg); +} +#elif defined(IO_MAPPED) +static inline __u8 +NCR_700_readb(struct Scsi_Host *host, __u32 reg) +{ + const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) + = (struct NCR_700_Host_Parameters *)host->hostdata[0]; + + return inb(host->base + (reg^bE)); +} + +static inline __u32 +NCR_700_readl(struct Scsi_Host *host, __u32 reg) +{ + __u32 value = inl(host->base + reg); + const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) + = (struct NCR_700_Host_Parameters *)host->hostdata[0]; + +#if 1 + /* sanity check the register */ + if((reg & 0x3) != 0) + BUG(); +#endif + + return bS_to_cpu(value); +} + +static inline void +NCR_700_writeb(__u8 value, struct Scsi_Host *host, __u32 reg) +{ + const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) + = (struct NCR_700_Host_Parameters *)host->hostdata[0]; + + outb(value, host->base + (reg^bE)); +} + +static inline void +NCR_700_writel(__u32 value, struct Scsi_Host *host, __u32 reg) +{ + const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) + = (struct NCR_700_Host_Parameters *)host->hostdata[0]; + +#if 1 + /* sanity check the register */ + if((reg & 0x3) != 0) + BUG(); +#endif + + outl(bS_to_host(value), host->base + reg); +} #endif Index: linux/2.4/drivers/scsi/Config.in diff -u linux/2.4/drivers/scsi/Config.in:1.1.1.17 linux/2.4/drivers/scsi/Config.in:1.1.1.17.2.1 --- linux/2.4/drivers/scsi/Config.in:1.1.1.17 Sat Sep 1 21:03:21 2001 +++ linux/2.4/drivers/scsi/Config.in Sat Sep 1 23:10:54 2001 @@ -116,6 +116,7 @@ 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 +dep_tristate 'HP LASI SCSI support for 53c700' CONFIG_SCSI_LASI700 $CONFIG_SCSI $CONFIG_PARISC dep_tristate 'NCR53c7,8xx SCSI support' CONFIG_SCSI_NCR53C7xx $CONFIG_SCSI $CONFIG_PCI if [ "$CONFIG_SCSI_NCR53C7xx" != "n" ]; then bool ' always negotiate synchronous transfers' CONFIG_SCSI_NCR53C7xx_sync Index: linux/2.4/drivers/scsi/Makefile diff -u linux/2.4/drivers/scsi/Makefile:1.1.1.16 linux/2.4/drivers/scsi/Makefile:1.1.1.16.2.2 --- linux/2.4/drivers/scsi/Makefile:1.1.1.16 Sat Sep 1 21:02:26 2001 +++ linux/2.4/drivers/scsi/Makefile Sun Sep 2 22:18:30 2001 @@ -31,7 +31,7 @@ endif endif -export-objs := scsi_syms.o 53c700.o +export-objs := scsi_syms.o 53c700.o 53c700-mem.o CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS @@ -125,6 +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 ifeq ($(CONFIG_ARCH_ACORN),y) mod-subdirs += ../acorn/scsi @@ -200,13 +201,19 @@ 53c700_d.h: 53c700.scr script_asm.pl $(PERL) -s script_asm.pl -ncr7x0_family < 53c700.scr + rm -f scriptu.h mv script.h 53c700_d.h - mv scriptu.h 53c700_u.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 $< >> $@ + cpqfc.o: cpqfcTSinit.o cpqfcTScontrol.o cpqfcTSi2c.o cpqfcTSworker.o \ cpqfcTStrigger.o $(LD) -r -o cpqfc.o cpqfcTSinit.o cpqfcTScontrol.o \ cpqfcTSi2c.o cpqfcTSworker.o cpqfcTStrigger.o - Index: linux/2.4/drivers/scsi/NCR_D700.c diff -u linux/2.4/drivers/scsi/NCR_D700.c:1.1.1.1 linux/2.4/drivers/scsi/NCR_D700.c:1.1.1.1.12.3 --- linux/2.4/drivers/scsi/NCR_D700.c:1.1.1.1 Mon May 14 18:48:23 2001 +++ linux/2.4/drivers/scsi/NCR_D700.c Tue Sep 4 10:07:46 2001 @@ -126,16 +126,13 @@ #define STATIC static #endif -#ifdef MODULE - char *NCR_D700; /* command line from insmod */ MODULE_AUTHOR("James Bottomley"); MODULE_DESCRIPTION("NCR Dual700 SCSI Driver"); +MODULE_LICENSE("GPL"); MODULE_PARM(NCR_D700, "s"); -#endif - static __u8 __initdata id_array[2*(MCA_MAX_SLOT_NR + 1)] = { [0 ... 2*(MCA_MAX_SLOT_NR + 1)-1] = 7 }; @@ -274,7 +271,11 @@ continue; } memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters)); - request_region(region, 64, "NCR_D700"); + if(request_region(region, 64, "NCR_D700") == NULL) { + printk(KERN_ERR "NCR D700: Failed to reserve IO region 0x%x\n", region); + kfree(hostdata); + continue; + } /* Fill in the three required pieces of hostdata */ hostdata->base = region; @@ -283,6 +284,7 @@ /* and register the chip */ if((host = NCR_700_detect(tpnt, hostdata)) == NULL) { kfree(hostdata); + release_region(host->base, 64); continue; } host->irq = irq; @@ -292,8 +294,8 @@ i, host->this_id); if(request_irq(irq, NCR_700_intr, SA_SHIRQ, "NCR_D700", host)) { printk(KERN_ERR "NCR D700, channel %d: irq problem, detatching\n", i); + scsi_unregister(host); NCR_700_release(host); - release_region(host->base, 64); continue; } found++; Index: linux/2.4/drivers/scsi/lasi700.c diff -u /dev/null linux/2.4/drivers/scsi/lasi700.c:1.1.4.4 --- /dev/null Fri Sep 7 09:20:20 2001 +++ linux/2.4/drivers/scsi/lasi700.c Fri Sep 7 09:16:27 2001 @@ -0,0 +1,188 @@ +/* -*- mode: c; c-basic-offset: 8 -*- */ + +/* PARISC LASI driver for the 53c700 chip + * + * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com +**----------------------------------------------------------------------------- +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +**----------------------------------------------------------------------------- + */ + +/* + * Many thanks to Richard Hirst for patiently + * debugging this driver on the parisc architecture and suggesting + * many improvements and bug fixes. + * + * Thanks also go to Linuxcare Inc. for providing several PARISC + * machines for me to debug the driver on. + */ + +#ifndef __hppa__ +#error "lasi700 only compiles on hppa architecture" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "scsi.h" +#include "hosts.h" +#include "constants.h" + +#include "lasi700.h" +#include "53c700.h" + +#ifdef MODULE + +char *lasi700; /* command line from insmod */ + +MODULE_AUTHOR("James Bottomley"); +MODULE_DESCRIPTION("lasi700 SCSI Driver"); +MODULE_LICENSE("GPL"); +MODULE_PARM(lasi700, "s"); + +#endif + +#ifdef MODULE +#define ARG_SEP ' ' +#else +#define ARG_SEP ',' +#endif + +static unsigned long __initdata opt_base; +static int __initdata opt_irq; + +static int __init +param_setup(char *string) +{ + char *pos = string, *next; + + while(pos != NULL && (next = strchr(pos, ':')) != NULL) { + int val = (int)simple_strtoul(++next, NULL, 0); + + if(!strncmp(pos, "addr:", 5)) + opt_base = val; + else if(!strncmp(pos, "irq:", 4)) + opt_irq = val; + + if((pos = strchr(pos, ARG_SEP)) != NULL) + pos++; + } + return 1; +} + +#ifndef MODULE +__setup("lasi700=", param_setup); +#endif + +static Scsi_Host_Template __initdata *host_tpnt = NULL; +static int __initdata host_count = 0; +static struct parisc_device_id lasi700_scsi_tbl[] = { + LASI700_ID_TABLE, + { 0 } +}; + +MODULE_DEVICE_TABLE(parisc, lasi700_scsi_tbl); + +static struct parisc_driver lasi700_driver = LASI700_DRIVER; + +static int __init +lasi700_detect(Scsi_Host_Template *tpnt) +{ + host_tpnt = tpnt; + +#ifdef MODULE + if(lasi700) + param_setup(lasi700); +#endif + + register_parisc_driver(&lasi700_driver); + + return (host_count != 0); +} + +static int __init +lasi700_driver_callback(struct parisc_device *dev) +{ + unsigned long base = dev->hpa + LASI_SCSI_CORE_OFFSET; + int irq = busdevice_alloc_irq(dev); + struct Scsi_Host *host; + struct NCR_700_Host_Parameters *hostdata = + kmalloc(sizeof(struct NCR_700_Host_Parameters), + GFP_KERNEL); + if(hostdata == NULL) { + printk(KERN_ERR "lasi700: Failed to allocate host data\n"); + 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"); + kfree(hostdata); + return 1; + } + hostdata->base = base; + hostdata->differential = 0; + hostdata->clock = LASI700_CLOCK; + hostdata->force_le_on_be = 1; + 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"); + scsi_unregister(host); + NCR_700_release(host); + return 1; + } + host_count++; + return 0; +} + +static int +lasi700_release(struct Scsi_Host *host) +{ + struct D700_Host_Parameters *hostdata = + (struct D700_Host_Parameters *)host->hostdata[0]; + + NCR_700_release(host); + kfree(hostdata); + free_irq(host->irq, host); + release_mem_region(host->base, 64); + return 1; +} + +static Scsi_Host_Template driver_template = LASI700_SCSI; + +#include "scsi_module.c" Index: linux/2.4/drivers/scsi/lasi700.h diff -u /dev/null linux/2.4/drivers/scsi/lasi700.h:1.1.4.3 --- /dev/null Fri Sep 7 09:20:20 2001 +++ linux/2.4/drivers/scsi/lasi700.h Fri Sep 7 09:16:27 2001 @@ -0,0 +1,57 @@ +/* -*- mode: c; c-basic-offset: 8 -*- */ + +/* PARISC LASI driver for the 53c700 chip + * + * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com +**----------------------------------------------------------------------------- +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +**----------------------------------------------------------------------------- + */ + +#ifndef _LASI700_H +#define _LASI700_H + +static int lasi700_detect(Scsi_Host_Template *); +static int lasi700_driver_callback(struct parisc_device *dev); +static int lasi700_release(struct Scsi_Host *host); + + +#define LASI700_SCSI { \ + name: "LASI SCSI 53c700", \ + proc_name: "lasi700", \ + detect: lasi700_detect, \ + release: lasi700_release, \ + this_id: 7, \ +} + +#define LASI700_ID_TABLE { \ + hw_type: HPHW_FIO, \ + sversion: 0x071, \ + hversion: HVERSION_ANY_ID, \ + hversion_rev: HVERSION_REV_ANY_ID, \ +} + +#define LASI700_DRIVER { \ + name: "Lasi SCSI", \ + id_table: lasi700_scsi_tbl, \ + probe: lasi700_driver_callback,\ +} + +#define LASI700_CLOCK 25 +#define LASI_SCSI_CORE_OFFSET 0x100 + +#endif