patch-2.4.13 linux/drivers/scsi/53c700.c
Next file: linux/drivers/scsi/53c700.h
Previous file: linux/drivers/sbus/char/zs.c
Back to the patch index
Back to the overall index
- Lines: 465
- Date:
Thu Oct 11 09:43:29 2001
- Orig file:
v2.4.12/linux/drivers/scsi/53c700.c
- Orig date:
Tue Oct 9 17:06:52 2001
diff -u --recursive --new-file v2.4.12/linux/drivers/scsi/53c700.c linux/drivers/scsi/53c700.c
@@ -51,6 +51,12 @@
/* CHANGELOG
*
+ * Version 2.6
+ *
+ * Following test of the 64 bit parisc kernel by Richard Hirst,
+ * several problems have now been corrected. Also adds support for
+ * consistent memory allocation.
+ *
* Version 2.5
*
* More Compatibility changes for 710 (now actually works). Enhanced
@@ -90,7 +96,7 @@
* Initial modularisation from the D700. See NCR_D700.c for the rest of
* the changelog.
* */
-#define NCR_700_VERSION "2.5"
+#define NCR_700_VERSION "2.6"
#include <linux/config.h>
#include <linux/version.h>
@@ -217,18 +223,39 @@
NCR_700_detect(Scsi_Host_Template *tpnt,
struct NCR_700_Host_Parameters *hostdata)
{
- dma_addr_t pScript, pSlots;
+ dma_addr_t pScript, pMemory, pSlots;
+ __u8 *memory;
__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);
+#ifdef CONFIG_53C700_USE_CONSISTENT
+ memory = pci_alloc_consistent(hostdata->pci_dev, TOTAL_MEM_SIZE,
+ &pMemory);
+ hostdata->consistent = 1;
+ if(memory == NULL ) {
+ printk(KERN_WARNING "53c700: consistent memory allocation failed\n");
+#endif
+ memory = kmalloc(TOTAL_MEM_SIZE, GFP_KERNEL);
+ if(memory == NULL) {
+ printk(KERN_ERR "53c700: Failed to allocate memory for driver, detatching\n");
+ return NULL;
+ }
+ pMemory = pci_map_single(hostdata->pci_dev, memory,
+ TOTAL_MEM_SIZE, PCI_DMA_BIDIRECTIONAL);
+#ifdef CONFIG_53C700_USE_CONSISTENT
+ hostdata->consistent = 0;
+ }
+#endif
+ script = (__u32 *)memory;
+ pScript = pMemory;
+ hostdata->msgin = memory + MSGIN_OFFSET;
+ hostdata->msgout = memory + MSGOUT_OFFSET;
+ hostdata->status = memory + STATUS_OFFSET;
+ hostdata->slots = (struct NCR_700_command_slot *)(memory + SLOTS_OFFSET);
+
+ pSlots = pMemory + SLOTS_OFFSET;
/* Fill in the missing routines from the host template */
tpnt->queuecommand = NCR_700_queuecommand;
@@ -251,29 +278,6 @@
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);
- return NULL;
- }
-
- /* 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);
for(j = 0; j < NCR_700_COMMAND_SLOTS_PER_HOST; j++) {
@@ -295,19 +299,17 @@
for(j = 0; j < PATCHES; j++) {
script[LABELPATCHES[j]] = bS_to_host(pScript + SCRIPT[LABELPATCHES[j]]);
}
- /* now patch up fixed addresses.
- * NOTE: virt_to_bus may be wrong if consistent memory is used
- * for these in the future */
+ /* now patch up fixed addresses. */
script_patch_32(script, MessageLocation,
- virt_to_bus(&hostdata->msgout[0]));
+ pScript + MSGOUT_OFFSET);
script_patch_32(script, StatusAddress,
- virt_to_bus(&hostdata->status[0]));
+ pScript + STATUS_OFFSET);
script_patch_32(script, ReceiveMsgAddress,
- virt_to_bus(&hostdata->msgin[0]));
+ pScript + MSGIN_OFFSET);
hostdata->script = script;
hostdata->pScript = pScript;
- dma_cache_wback((unsigned long)script, sizeof(SCRIPT));
+ NCR_700_dma_cache_wback((unsigned long)script, sizeof(SCRIPT));
hostdata->state = NCR_700_HOST_FREE;
spin_lock_init(&hostdata->lock);
hostdata->cmd = NULL;
@@ -344,13 +346,18 @@
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);
+#ifdef CONFIG_53C700_USE_CONSISTENT
+ if(hostdata->consistent) {
+ pci_free_consistent(hostdata->pci_dev, TOTAL_MEM_SIZE,
+ hostdata->script, hostdata->pScript);
+ } else {
+#endif
+ pci_unmap_single(hostdata->pci_dev, hostdata->pScript,
+ TOTAL_MEM_SIZE, PCI_DMA_BIDIRECTIONAL);
+ kfree(hostdata->script);
+#ifdef CONFIG_53C700_USE_CONSISTENT
+ }
+#endif
return 1;
}
@@ -620,7 +627,25 @@
}
return (offset & 0x0f) | (XFERP & 0x07)<<4;
}
-
+
+STATIC inline void
+NCR_700_unmap(struct NCR_700_Host_Parameters *hostdata, Scsi_Cmnd *SCp,
+ struct NCR_700_command_slot *slot)
+{
+ 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);
+ }
+ }
+}
STATIC inline void
NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
@@ -632,31 +657,22 @@
if(SCp != NULL) {
struct NCR_700_command_slot *slot =
(struct NCR_700_command_slot *)SCp->host_scribble;
-
+
+ NCR_700_unmap(hostdata, SCp, slot);
+ pci_unmap_single(hostdata->pci_dev, slot->pCmd,
+ sizeof(SCp->cmnd), PCI_DMA_TODEVICE);
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\n",
SCp, SCp->cmnd[7], result);
print_sense("53c700", SCp);
+
#endif
+ SCp->use_sg = SCp->cmnd[8];
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;
@@ -850,7 +866,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, 1);
+ NCR_700_dma_cache_wback((unsigned long)hostdata->msgout, 1);
script_patch_16(hostdata->script, MessageCount, 1);
/* SendMsgOut returns, so set up the return
* address */
@@ -862,7 +878,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, 1);
+ NCR_700_dma_cache_wback((unsigned long)hostdata->msgout, 1);
script_patch_16(hostdata->script, MessageCount, 1);
resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
@@ -876,7 +892,7 @@
printk("\n");
/* just reject it */
hostdata->msgout[0] = A_REJECT_MSG;
- dma_cache_wback((unsigned long)hostdata->msgout, 1);
+ NCR_700_dma_cache_wback((unsigned long)hostdata->msgout, 1);
script_patch_16(hostdata->script, MessageCount, 1);
/* SendMsgOut returns, so set up the return
* address */
@@ -954,7 +970,7 @@
printk("\n");
/* just reject it */
hostdata->msgout[0] = A_REJECT_MSG;
- dma_cache_wback((unsigned long)hostdata->msgout, 1);
+ NCR_700_dma_cache_wback((unsigned long)hostdata->msgout, 1);
script_patch_16(hostdata->script, MessageCount, 1);
/* SendMsgOut returns, so set up the return
* address */
@@ -964,7 +980,7 @@
}
NCR_700_writel(temp, host, TEMP_REG);
/* set us up to receive another message */
- dma_cache_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE);
+ NCR_700_dma_cache_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE);
return resume_offset;
}
@@ -1002,10 +1018,15 @@
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
- * saved data_cmnd */
+ /* 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. We also unmap any
+ * data associated with the command
+ * here */
+ NCR_700_unmap(hostdata, SCp, slot);
+
SCp->cmnd[0] = REQUEST_SENSE;
SCp->cmnd[1] = (SCp->lun & 0x7) << 5;
SCp->cmnd[2] = 0;
@@ -1013,21 +1034,29 @@
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 */
+ /* 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[0];
+ SCp->cmnd[8] = SCp->use_sg;
+ SCp->use_sg = 0;
SCp->sc_data_direction = SCSI_DATA_READ;
- dma_cache_wback((unsigned long)SCp->cmnd, SCp->cmd_len);
+ pci_dma_sync_single(hostdata->pci_dev,
+ slot->pCmd,
+ SCp->cmd_len,
+ PCI_DMA_TODEVICE);
+ slot->dma_handle = pci_map_single(hostdata->pci_dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), PCI_DMA_FROMDEVICE);
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[0].pAddr = bS_to_host(slot->dma_handle);
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));
+ NCR_700_dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG[0])*2);
+ NCR_700_dma_cache_inv((unsigned long)SCp->sense_buffer, sizeof(SCp->sense_buffer));
/* queue the command for reissue */
slot->state = NCR_700_SLOT_QUEUED;
@@ -1136,7 +1165,7 @@
/* re-patch for this command */
script_patch_32_abs(hostdata->script, CommandAddress,
- virt_to_bus(slot->cmnd->cmnd));
+ slot->pCmd);
script_patch_16(hostdata->script,
CommandCount, slot->cmnd->cmd_len);
script_patch_32_abs(hostdata->script, SGScriptStartAddress,
@@ -1149,13 +1178,13 @@
* 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,
+ NCR_700_dma_cache_inv((unsigned long)hostdata->msgin,
MSG_ARRAY_SIZE);
- dma_cache_wback((unsigned long)hostdata->msgout,
+ NCR_700_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,
+ NCR_700_dma_cache_wback((unsigned long)slot->cmnd->cmnd,
slot->cmnd->cmd_len);
@@ -1219,7 +1248,8 @@
hostdata->reselection_id = reselection_id;
/* just in case we have a stale simple tag message, clear it */
hostdata->msgin[1] = 0;
- dma_cache_wback_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE);
+ NCR_700_dma_cache_wback_inv((unsigned long)hostdata->msgin,
+ MSG_ARRAY_SIZE);
if(hostdata->tag_negotiated & (1<<reselection_id)) {
resume_offset = hostdata->pScript + Ent_GetReselectionWithTag;
} else {
@@ -1334,7 +1364,7 @@
hostdata->cmd = NULL;
/* clear any stale simple tag message */
hostdata->msgin[1] = 0;
- dma_cache_wback_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE);
+ NCR_700_dma_cache_wback_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE);
if(id == 0xff) {
/* Selected as target, Ignore */
@@ -1404,7 +1434,7 @@
* set up so we cannot take a selection interrupt */
hostdata->msgout[0] = NCR_700_identify(SCp->cmnd[0] != REQUEST_SENSE,
- SCp->lun);
+ SCp->lun);
/* for INQUIRY or REQUEST_SENSE commands, we cannot be sure
* if the negotiated transfer parameters still hold, so
* always renegotiate them */
@@ -1437,7 +1467,7 @@
Device_ID, 1<<SCp->target);
script_patch_32_abs(hostdata->script, CommandAddress,
- virt_to_bus(SCp->cmnd));
+ slot->pCmd);
script_patch_16(hostdata->script, CommandCount, SCp->cmd_len);
/* finally plumb the beginning of the SG list into the script
* */
@@ -1448,10 +1478,10 @@
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);
+ NCR_700_dma_cache_wback((unsigned long)hostdata->msgout, count);
+ NCR_700_dma_cache_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE);
+ NCR_700_dma_cache_wback((unsigned long)SCp->cmnd, SCp->cmd_len);
+ NCR_700_dma_cache_inv((unsigned long)hostdata->status, 1);
/* set the synchronous period/offset */
NCR_700_writeb(NCR_700_get_SXFER(SCp->device),
@@ -1519,7 +1549,7 @@
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 - (__u32)(hostdata->pScript))/4,
dsp, dsps));
if(SCp != NULL) {
@@ -1632,7 +1662,7 @@
slot->SG[i].ins = bS_to_host(SCRIPT_NOP);
slot->SG[i].pAddr = 0;
}
- dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG));
+ NCR_700_dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG));
/* and pretend we disconnected after
* the command phase */
resume_offset = hostdata->pScript + Ent_MsgInDuringData;
@@ -1847,7 +1877,13 @@
#endif
if(old != NULL && old->tag == SCp->device->current_tag) {
- printk(KERN_WARNING "scsi%d (%d:%d) Tag clock back to current, queueing\n", SCp->host->host_no, SCp->target, SCp->lun);
+ /* On some badly starving drives, this can be
+ * a frequent occurance, so print the message
+ * only once */
+ if(NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_TAG_STARVATION_WARNED)) {
+ printk(KERN_WARNING "scsi%d (%d:%d) Target is suffering from tag starvation.\n", SCp->host->host_no, SCp->target, SCp->lun);
+ NCR_700_set_flag(SCp->device, NCR_700_DEV_TAG_STARVATION_WARNED);
+ }
return 1;
}
slot->tag = SCp->device->current_tag++;
@@ -1900,6 +1936,18 @@
hostdata->ITL_Hash_back[hash] = slot;
slot->ITL_back = NULL;
+ /* sanity check: some of the commands generated by the mid-layer
+ * have an eccentric idea of their sc_data_direction */
+ if(!SCp->use_sg && !SCp->request_bufflen
+ && SCp->sc_data_direction != SCSI_DATA_NONE) {
+#ifdef NCR_700_DEBUG
+ printk("53c700: Command");
+ print_command(SCp->cmnd);
+ printk("Has wrong data direction %d\n", SCp->sc_data_direction);
+#endif
+ SCp->sc_data_direction = SCSI_DATA_NONE;
+ }
+
switch (SCp->cmnd[0]) {
case REQUEST_SENSE:
/* clear the internal sense magic */
@@ -1965,12 +2013,14 @@
}
slot->SG[i].ins = bS_to_host(SCRIPT_RETURN);
slot->SG[i].pAddr = 0;
- dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG));
+ NCR_700_dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG));
DEBUG((" SETTING %08lx to %x\n",
- virt_to_bus(&slot->SG[i].ins),
+ (&slot->pSG[i].ins),
slot->SG[i].ins));
}
slot->resume_offset = 0;
+ slot->pCmd = pci_map_single(hostdata->pci_dev, SCp->cmnd,
+ sizeof(SCp->cmnd), PCI_DMA_TODEVICE);
NCR_700_start_command(SCp);
return 0;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)