summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/53c7,8xx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/53c7,8xx.c')
-rw-r--r--drivers/scsi/53c7,8xx.c733
1 files changed, 470 insertions, 263 deletions
diff --git a/drivers/scsi/53c7,8xx.c b/drivers/scsi/53c7,8xx.c
index 99a7d360d..764eb6fe0 100644
--- a/drivers/scsi/53c7,8xx.c
+++ b/drivers/scsi/53c7,8xx.c
@@ -5,8 +5,8 @@
* weed out brain damaged main boards.
*/
-#define PERM_OPTIONS (OPTION_IO_MAPPED|OPTION_DEBUG_TEST1)
+#define PERM_OPTIONS (OPTION_IO_MAPPED|OPTION_DEBUG_TEST1)
/*
* Define SCSI_MALLOC to use scsi_malloc instead of kmalloc. Other than
* preventing deadlock, I'm not sure why we'd want to do this.
@@ -20,7 +20,7 @@
* Hannover, Germany
* hm@ix.de
*
- * Copyright 1993, 1994 Drew Eckhardt
+ * Copyright 1993, 1994, 1995 Drew Eckhardt
* Visionary Computing
* (Unix and Linux consulting and custom programming)
* drew@Colorado.EDU
@@ -28,8 +28,6 @@
*
* TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
*
- * PRE-ALPHA
- *
* For more information, please consult
*
*
@@ -156,6 +154,11 @@
*
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#include <asm/dma.h>
#include <asm/io.h>
#include <asm/system.h>
#include <linux/delay.h>
@@ -165,6 +168,7 @@
#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/string.h>
+#include <linux/mm.h>
#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
@@ -175,7 +179,9 @@
static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int result);
static int NCR53c8xx_run_tests (struct Scsi_Host *host);
static int NCR53c8xx_script_len;
-static void NCR53c7x0_intr (int irq);
+static int NCR53c8xx_dsa_len;
+static void NCR53c7x0_intr(int irq, struct pt_regs * regs);
+static int halt (struct Scsi_Host *host);
static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd
*cmd);
static void intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd);
@@ -189,23 +195,11 @@ static int NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
NCR53c7x0_cmd *cmd);
static void NCR53c8x0_soft_reset (struct Scsi_Host *host);
+static int perm_options = PERM_OPTIONS;
+
static struct Scsi_Host *first_host = NULL; /* Head of list of NCR boards */
static Scsi_Host_Template *the_template = NULL;
-/* Allocate storage space for constant messages, etc. */
-
-static long NCR53c7xx_zero = 0;
-static long NCR53c7xx_sink;
-static char NCR53c7xx_msg_reject = MESSAGE_REJECT;
-static char NCR53c7xx_msg_abort = ABORT;
-static char NCR53c7xx_msg_nop = NOP;
-
-/* Buffer for commands run before *malloc() works */
-/*
- * XXX - if need be, replace this with normal wait.
- */
-static int scan_scsis_buf_busy = 0;
-static char scan_scsis_buf[512];
/*
* TODO :
@@ -267,8 +261,7 @@ static char scan_scsis_buf[512];
*
* For the very similar chips, we should probably hack the fixup code
* and interrupt code so that it works everywhere, but I suspect the
- * NCR53c700 is going
- * to need it's own fixup routine.
+ * NCR53c700 is going to need it's own fixup routine.
*/
/*
@@ -276,16 +269,17 @@ static char scan_scsis_buf[512];
*/
struct pci_chip {
- short pci_device_id;
+ unsigned short pci_device_id;
int chip;
int max_revision;
int min_revision;
};
-static struct pci_chip pci_chip_ids[3] = {
+static struct pci_chip pci_chip_ids[] = {
{PCI_DEVICE_ID_NCR_53C810, 810, 1, 1},
+ {PCI_DEVICE_ID_NCR_53C815, 815, 2, 3},
{PCI_DEVICE_ID_NCR_53C820, 820, -1, -1},
- {PCI_DEVICE_ID_NCR_53C825, 825, -1, -1},
+ {PCI_DEVICE_ID_NCR_53C825, 825, -1, -1}
};
#define NPCI_CHIP_IDS (sizeof (pci_chip_ids) / sizeof(pci_chip_ids[0]))
@@ -401,7 +395,8 @@ setup_wrapper(825)
* field of the hostdata structure MUST have been set.
*/
-static int NCR53c7x0_init (struct Scsi_Host *host) {
+static int
+NCR53c7x0_init (struct Scsi_Host *host) {
NCR53c7x0_local_declare();
/* unsigned char tmp; */
int i, j, ccf;
@@ -413,6 +408,7 @@ static int NCR53c7x0_init (struct Scsi_Host *host) {
switch (hostdata->chip) {
case 810:
case 815:
+ case 820:
case 825:
hostdata->dstat_sir_intr = NCR53c8x0_dstat_sir_intr;
hostdata->init_save_regs = NULL;
@@ -430,13 +426,19 @@ static int NCR53c7x0_init (struct Scsi_Host *host) {
return -1;
}
+ /* Assign constants accessed by NCR */
+ hostdata->NCR53c7xx_zero = 0;
+ hostdata->NCR53c7xx_msg_reject = MESSAGE_REJECT;
+ hostdata->NCR53c7xx_msg_abort = ABORT;
+ hostdata->NCR53c7xx_msg_nop = NOP;
+
/*
* Set up an interrupt handler if we aren't already sharing an IRQ
* with another board.
*/
- for (search = first_host; search && (search->hostt == the_template) &&
- (search->irq != host->irq); search=search->next);
+ for (search = first_host; search && ((search->hostt != the_template) ||
+ (search->irq != host->irq)); search=search->next);
if (!search) {
if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7,8xx")) {
@@ -459,6 +461,10 @@ static int NCR53c7x0_init (struct Scsi_Host *host) {
hostdata->istat = ((hostdata->chip / 100) == 8) ?
ISTAT_REG_800 : ISTAT_REG_700;
+/* Only the ISTAT register is readable when the NCR is running, so make
+ sure it's halted. */
+ halt(host);
+
/*
* XXX - the NCR53c700 uses bitfielded registers for SCID, SDID, etc,
* as does the 710 with one bit per SCSI ID. Conversely, the NCR
@@ -503,9 +509,9 @@ static int NCR53c7x0_init (struct Scsi_Host *host) {
hostdata->saved_dcntl = NCR53c7x0_read8(DCNTL_REG);
if ((hostdata->chip / 100) == 8)
- printk ("scsi%d : using %s interrupts.\n", host->host_no,
- (hostdata->saved_dcntl & DCNTL_800_IRQM) ? "level active" :
- "edge triggered");
+ printk ("scsi%d : using %s interrupts\n", host->host_no,
+ (hostdata->saved_dcntl & DCNTL_800_IRQM) ? "edge triggered" :
+ "level active");
/*
* DMODE controls DMA burst length, and on 700 series chips,
@@ -527,8 +533,9 @@ static int NCR53c7x0_init (struct Scsi_Host *host) {
case DMODE_BL_4: i = 4; break;
case DMODE_BL_8: i = 8; break;
case DMODE_BL_16: i = 16; break;
+ default: i = 0;
}
- printk ("scsi%d ; burst length %d\n", host->host_no, i);
+ printk ("scsi%d : burst length %d\n", host->host_no, i);
}
}
@@ -572,6 +579,7 @@ static int NCR53c7x0_init (struct Scsi_Host *host) {
*/
for (i = 0; i < 8; ++i) {
+ hostdata->cmd_allocated[i] = 0;
for (j = 0; j < 8; ++j)
hostdata->busy[i][j] = 0;
/*
@@ -600,8 +608,8 @@ static int NCR53c7x0_init (struct Scsi_Host *host) {
hostdata->issue_queue = hostdata->running_list =
hostdata->finished_queue = NULL;
- hostdata->issue_dsa_head =
- hostdata->issue_dsa_tail = NULL;
+ hostdata->issue_dsa_head = NULL;
+ hostdata->issue_dsa_tail = NULL;
if (hostdata->init_save_regs)
hostdata->init_save_regs (host);
@@ -668,11 +676,11 @@ static int normal_init (Scsi_Host_Template *tpnt, int board, int chip,
struct Scsi_Host *instance;
struct NCR53c7x0_hostdata *hostdata;
char chip_str[80];
- int script_len = 0, size = 0;
+ int script_len = 0, dsa_len = 0, size = 0, max_cmd_size = 0;
int ok = 0;
- options |= PERM_OPTIONS;
+ options |= perm_options;
switch (chip) {
case 825:
@@ -680,6 +688,7 @@ static int normal_init (Scsi_Host_Template *tpnt, int board, int chip,
case 815:
case 810:
script_len = NCR53c8xx_script_len;
+ dsa_len = NCR53c8xx_dsa_len;
options |= OPTION_INTFLY;
sprintf (chip_str, "NCR53c%d", chip);
break;
@@ -698,7 +707,7 @@ static int normal_init (Scsi_Host_Template *tpnt, int board, int chip,
if ((chip / 100 == 8) && !pci_valid)
printk ("scsi-ncr53c7,8xx : for better reliability and performance, please use the\n"
" PCI override instead.\n"
- " Syntax : ncr53c8{10,20,25}=pci,<bus>,<device>,<function>\n"
+ " Syntax : ncr53c8{10,15,20,25}=pci,<bus>,<device>,<function>\n"
" <bus> and <device> are usually 0.\n");
if (options & OPTION_DEBUG_PROBE_ONLY) {
@@ -706,9 +715,50 @@ static int normal_init (Scsi_Host_Template *tpnt, int board, int chip,
return -1;
}
- size = sizeof(struct NCR53c7x0_hostdata) + script_len;
+ max_cmd_size = sizeof(struct NCR53c7x0_cmd) + dsa_len +
+ /* Size of dynamic part of command structure : */
+ 2 * /* Worst case : we don't know if we need DATA IN or DATA out */
+ ( 2 * /* Current instructions per scatter/gather segment */
+ tpnt->sg_tablesize +
+ 3 /* Current startup / termination required per phase */
+ ) *
+ 8 /* Each instruction is eight bytes */;
+ /* Note that alignment will be guaranteed, since we put the command
+ allocated at probe time after the fixed-up SCSI script, which
+ consists of 32 bit words, aligned on a 32 bit boundary. */
+
+ /* Allocate fixed part of hostdata, dynamic part to hold appropriate
+ SCSI SCRIPT(tm) plus a single, maximum-sized NCR53c7x0_cmd structure.
+
+ We need a NCR53c7x0_cmd structure for scan_scsis() when we are
+ not loaded as a module, and when we're loaded as a module, we
+ can't use a non-dynamically allocated structure because modules
+ are vmalloc()'d, which can allow structures to cross page
+ boundaries and breaks our physical/virtual address assumptions
+ for DMA.
+
+ So, we stick it past the end of our hostdata structure.
+
+ ASSUMPTION :
+ Regardless of how many simultaneous SCSI commands we allow,
+ the probe code only executes a _single_ instruction at a time,
+ so we only need one here, and don't need to allocate NCR53c7x0_cmd
+ structures for each target until we are no longer in scan_scsis
+ and kmalloc() has become functional (memory_init() happens
+ after all device driver initialization).
+ */
+
+ size = sizeof(struct NCR53c7x0_hostdata) + script_len + max_cmd_size;
instance = scsi_register (tpnt, size);
+ if (!instance)
+ return -1;
+
+
+ /* FIXME : if we ever support an ISA NCR53c7xx based board, we
+ need to check if the chip is running in a 16 bit mode, and if so
+ unregister it if it is past the 16M (0x1000000) mark */
+
hostdata = (struct NCR53c7x0_hostdata *)
instance->hostdata;
hostdata->size = size;
@@ -764,19 +814,30 @@ static int normal_init (Scsi_Host_Template *tpnt, int board, int chip,
instance->dma_channel = dma;
hostdata->options = options;
-
+ hostdata->dsa_size = dsa_len;
+ hostdata->max_cmd_size = max_cmd_size;
+ hostdata->num_cmds = 1;
+ /* Initialize single command */
+ hostdata->free = (struct NCR53c7x0_cmd *)
+ (hostdata->script + hostdata->script_count);
+ hostdata->free->real = (void *) hostdata->free;
+ hostdata->free->size = max_cmd_size;
+ hostdata->free->free = NULL;
+ hostdata->free->next = NULL;
+
+
return NCR53c7x0_init(instance);
}
/*
- * Function : static int pci_init(Scsi_Host_Template *tpnt, int board,
+ * Function : static int ncr_init(Scsi_Host_Template *tpnt, int board,
* int chip, int bus, int device_fn, int options)
*
* Purpose : initializes a NCR53c800 family based on the PCI
* bus, device, and function location of it. Allows
* reprogramming of latency timer and determining addresses
- * and weather bus mastering, etc. are OK.
+ * and whether bus mastering, etc. are OK.
*
* Useful where a new NCR chip is backwards compatible with
* a supported chip, but the DEVICE ID has changed so it
@@ -790,12 +851,13 @@ static int normal_init (Scsi_Host_Template *tpnt, int board, int chip,
*
*/
-static int pci_init (Scsi_Host_Template *tpnt, int board, int chip,
+static int ncr_init (Scsi_Host_Template *tpnt, int board, int chip,
unsigned char bus, unsigned char device_fn, int options) {
unsigned short vendor_id, device_id, command;
unsigned long base, io_port;
unsigned char irq, revision;
- int error, expected_chip, expected_id, max_revision, min_revision;
+ int error, expected_chip;
+ int expected_id = -1, max_revision = -1, min_revision = -1;
int i;
printk("scsi-ncr53c7,8xx : at PCI bus %d, device %d, function %d\n",
@@ -850,6 +912,8 @@ static int pci_init (Scsi_Host_Template *tpnt, int board, int chip,
io_port = 0;
} else
io_port &= PCI_BASE_ADDRESS_IO_MASK;
+ } else {
+ io_port = 0;
}
if (command & PCI_COMMAND_MEMORY) {
@@ -859,6 +923,8 @@ static int pci_init (Scsi_Host_Template *tpnt, int board, int chip,
base = 0;
} else
base &= PCI_BASE_ADDRESS_MEM_MASK;
+ } else {
+ base = 0;
}
if (!io_port && !base) {
@@ -912,7 +978,6 @@ static int pci_init (Scsi_Host_Template *tpnt, int board, int chip,
*/
int NCR53c7xx_detect(Scsi_Host_Template *tpnt) {
- short current_chip;
int i;
int current_override;
int count; /* Number of boards detected */
@@ -923,7 +988,7 @@ int NCR53c7xx_detect(Scsi_Host_Template *tpnt) {
for (current_override = count = 0; current_override < OVERRIDE_LIMIT;
++current_override) {
if (overrides[current_override].pci ?
- !pci_init (tpnt, overrides[current_override].board,
+ !ncr_init (tpnt, overrides[current_override].board,
overrides[current_override].chip,
(unsigned char) overrides[current_override].data.pci.bus,
(((overrides[current_override].data.pci.device
@@ -948,7 +1013,7 @@ int NCR53c7xx_detect(Scsi_Host_Template *tpnt) {
!pcibios_find_device (PCI_VENDOR_ID_NCR,
pci_chip_ids[i].pci_device_id, pci_index, &pci_bus,
&pci_device_fn) &&
- !pci_init (tpnt, BOARD_GENERIC, pci_chip_ids[i].chip,
+ !ncr_init (tpnt, BOARD_GENERIC, pci_chip_ids[i].chip,
pci_bus, pci_device_fn, /* no options */ 0);
++count, ++pci_index);
}
@@ -959,6 +1024,7 @@ int NCR53c7xx_detect(Scsi_Host_Template *tpnt) {
#include "53c8xx_d.h"
static int NCR53c8xx_script_len = sizeof (SCRIPT);
+static int NCR53c8xx_dsa_len = A_dsa_end + Ent_dsa_zero - Ent_dsa_code_template;
/*
* Function : static void NCR53c8x0_init_fixup (struct Scsi_Host *host)
@@ -969,7 +1035,8 @@ static int NCR53c8xx_script_len = sizeof (SCRIPT);
*
*/
-static void NCR53c8x0_init_fixup (struct Scsi_Host *host) {
+static void
+NCR53c8x0_init_fixup (struct Scsi_Host *host) {
NCR53c7x0_local_declare();
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata;
@@ -988,6 +1055,16 @@ static void NCR53c8x0_init_fixup (struct Scsi_Host *host) {
for (i = 0; i < PATCHES; ++i)
hostdata->script[LABELPATCHES[i]] +=
(unsigned long) hostdata->script;
+ /* Fixup addresses of constants that used to be EXTERNAL */
+
+ patch_abs_32 (hostdata->script, 0, NCR53c7xx_msg_abort,
+ (long) &(hostdata->NCR53c7xx_msg_abort));
+ patch_abs_32 (hostdata->script, 0, NCR53c7xx_msg_reject,
+ (long) &(hostdata->NCR53c7xx_msg_reject));
+ patch_abs_32 (hostdata->script, 0, NCR53c7xx_zero,
+ (long) &(hostdata->NCR53c7xx_zero));
+ patch_abs_32 (hostdata->script, 0, NCR53c7xx_sink,
+ (long) &(hostdata->NCR53c7xx_sink));
/*
* Fixup absolutes set at boot-time.
@@ -1017,10 +1094,6 @@ static void NCR53c8x0_init_fixup (struct Scsi_Host *host) {
ncr_to_ncr = memory_to_ncr = ncr_to_memory = tmp;
}
- printk ("scsi%d : m_to_n = 0x%x, n_to_m = 0x%x, n_to_n = 0x%x\n",
- (int) host->host_no, (int) memory_to_ncr, (int)
- ncr_to_memory, ncr_to_ncr);
-
patch_abs_32 (hostdata->script, 0, addr_scratch, base + SCRATCHA_REG_800);
patch_abs_32 (hostdata->script, 0, addr_sfbr, base + SFBR_REG);
patch_abs_32 (hostdata->script, 0, addr_temp, base + TEMP_REG);
@@ -1039,11 +1112,15 @@ static void NCR53c8x0_init_fixup (struct Scsi_Host *host) {
patch_abs_rwri_data (hostdata->script, 0, dmode_ncr_to_memory, ncr_to_memory);
patch_abs_rwri_data (hostdata->script, 0, dmode_ncr_to_ncr, ncr_to_ncr);
- patch_abs_32 (hostdata->script, 0, issue_dsa_head, (long) &(hostdata->issue_dsa_head));
+ patch_abs_32 (hostdata->script, 0, issue_dsa_head,
+ (long) &(hostdata->issue_dsa_head));
patch_abs_32 (hostdata->script, 0, msg_buf, (long) &(hostdata->msg_buf));
- patch_abs_32 (hostdata->script, 0, reconnect_dsa_head, (long) &(hostdata->reconnect_dsa_head));
- patch_abs_32 (hostdata->script, 0, reselected_identify, (long) &(hostdata->reselected_identify));
- patch_abs_32 (hostdata->script, 0, reselected_tag, (long) &(hostdata->reselected_tag));
+ patch_abs_32 (hostdata->script, 0, reconnect_dsa_head,
+ (long) &(hostdata->reconnect_dsa_head));
+ patch_abs_32 (hostdata->script, 0, reselected_identify,
+ (long) &(hostdata->reselected_identify));
+ patch_abs_32 (hostdata->script, 0, reselected_tag,
+ (long) &(hostdata->reselected_tag));
patch_abs_32 (hostdata->script, 0, test_dest, (long) &(hostdata->test_dest));
patch_abs_32 (hostdata->script, 0, test_src, (long) &(hostdata->test_source));
@@ -1125,17 +1202,18 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host) {
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata;
unsigned long timeout, start;
- int old_level, failed, i;
+ int failed, i;
+ unsigned long flags;
+
NCR53c7x0_local_setup(host);
- printk("scsi%d : testing\n", host->host_no);
-
/* The NCR chip _must_ be idle to run the test scripts */
- old_level = splx(0);
+ save_flags(flags);
+ cli();
if (!hostdata->idle) {
printk ("scsi%d : chip not idle, aborting tests\n", host->host_no);
- splx(old_level);
+ restore_flags(flags);
return -1;
}
@@ -1161,10 +1239,11 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host) {
printk ("scsi%d : test 1", host->host_no);
NCR53c7x0_write32 (DSP_REG, start);
printk (" started\n");
- splx(7);
+ sti();
timeout = jiffies + 50; /* arbitrary */
- while ((hostdata->test_completed == -1) && jiffies < timeout);
+ while ((hostdata->test_completed == -1) && jiffies < timeout)
+ barrier();
failed = 1;
if (hostdata->test_completed == -1)
@@ -1197,7 +1276,7 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host) {
(unsigned long) hostdata->script, start);
printk ("scsi%d : DSPS = 0x%lx\n", host->host_no,
(unsigned long) NCR53c7x0_read32(DSPS_REG));
- splx(old_level);
+ restore_flags(flags);
return -1;
}
hostdata->test_running = 0;
@@ -1233,10 +1312,10 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host) {
dsa[11] = (unsigned long) &msg;
for (i = 0; i < 3; ++i) {
- splx(0);
+ cli();
if (!hostdata->idle) {
printk ("scsi%d : chip not idle, aborting tests\n", host->host_no);
- splx(old_level);
+ restore_flags(flags);
return -1;
}
@@ -1249,10 +1328,11 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host) {
hostdata->state = STATE_RUNNING;
NCR53c7x0_write32 (DSA_REG, (unsigned long) dsa);
NCR53c7x0_write32 (DSP_REG, start);
- splx(7);
+ sti();
timeout = jiffies + 500; /* arbitrary */
- while ((hostdata->test_completed == -1) && jiffies < timeout);
+ while ((hostdata->test_completed == -1) && jiffies < timeout)
+ barrier();
NCR53c7x0_write32 (DSA_REG, 0);
if (hostdata->test_completed == 2) {
@@ -1269,12 +1349,12 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host) {
host->host_no, i);
if (!hostdata->idle) {
printk("scsi%d : not idle\n", host->host_no);
- splx(old_level);
+ restore_flags(flags);
return -1;
}
} else if (hostdata->test_completed == -1) {
printk ("scsi%d : test 2 timed out\n", host->host_no);
- splx(old_level);
+ restore_flags(flags);
return -1;
}
hostdata->test_running = 0;
@@ -1285,9 +1365,8 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host) {
}
}
}
- printk ("scsi%d : tests complete.\n", host->host_no);
- splx(old_level);
+ restore_flags(flags);
return 0;
}
@@ -1344,11 +1423,12 @@ static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
struct Scsi_Host *host = c->host;
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata;
- int old_level;
+ unsigned long flags;
char **prev, *search;
int i;
- old_level = splx(0);
+ save_flags(flags);
+ cli();
for (i = 0; i < 2; ++i) {
for (search = (char *) (i ? hostdata->issue_dsa_head :
hostdata->reconnect_dsa_head), prev = (char **) (i ?
@@ -1370,21 +1450,14 @@ static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
if (hostdata->running_list == cmd)
hostdata->running_list = cmd->next;
- if (!scan_scsis_buf_busy) {
-#ifdef SCSI_MALLOC
- scsi_free ((void *) cmd->real, cmd->size);
-#else
- kfree_s (cmd->real, cmd->size);
-#endif
- } else {
- scan_scsis_buf_busy = 0;
- }
+ cmd->next = hostdata->free;
+ hostdata->free = cmd;
c->host_scribble = NULL;
c->result = result;
c->scsi_done(c);
- splx(old_level);
+ restore_flags(flags);
}
/*
@@ -1409,7 +1482,7 @@ static void intr_break (struct Scsi_Host *host, struct
unsigned long *dsp;
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata;
- int old_level;
+ unsigned long flags;
NCR53c7x0_local_setup(host);
/*
@@ -1417,8 +1490,8 @@ static void intr_break (struct Scsi_Host *host, struct
* dump the appropriate debugging information to standard
* output.
*/
-
- old_level = splx(0);
+ save_flags(flags);
+ cli();
dsp = (unsigned long *) NCR53c7x0_read32(DSP_REG);
for (bp = hostdata->breakpoints; bp && bp->address != dsp;
bp = bp->next);
@@ -1440,7 +1513,7 @@ static void intr_break (struct Scsi_Host *host, struct
* instruction in bytes.
*/
- splx(old_level);
+ restore_flags(flags);
}
/*
@@ -1555,7 +1628,7 @@ static void synchronous (struct Scsi_Host *host, int target, char *msg) {
hostdata->sync[target].select_indirect = (scntl3 << 24) | (target << 16) |
(sxfer << 8);
- script = hostdata->sync[target].script;
+ script = (long *) hostdata->sync[target].script;
/* XXX - add NCR53c7x0 code to reprogram SCF bits if we want to */
if ((hostdata->chip / 100) == 8) {
@@ -1610,7 +1683,7 @@ static int NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
printk ("scsi%d : message", host->host_no);
if (cmd)
printk (" from target %d lun %d", c->target, c->lun);
- print_msg (hostdata->msg_buf);
+ print_msg ((unsigned char *) hostdata->msg_buf);
printk("\n");
switch (hostdata->msg_buf[0]) {
/*
@@ -1645,7 +1718,8 @@ static int NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
*/
if (cmd->flags & CMD_FLAG_SDTR) {
cmd->flags &= ~CMD_FLAG_SDTR;
- synchronous (host, c->target, hostdata->msg_buf);
+ synchronous (host, c->target, (unsigned char *)
+ hostdata->msg_buf);
hostdata->dsp = hostdata->script + hostdata->E_accept_message /
sizeof(long);
hostdata->dsp_changed = 1;
@@ -1653,7 +1727,8 @@ static int NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
} else {
if (hostdata->options & OPTION_SYNCHRONOUS) {
cmd->flags |= CMD_FLAG_DID_SDTR;
- synchronous (host, c->target, hostdata->msg_buf);
+ synchronous (host, c->target, (unsigned char *)
+ hostdata->msg_buf);
} else {
hostdata->msg_buf[4] = 0; /* 0 offset = async */
}
@@ -1928,15 +2003,16 @@ static int debugger_fn_bc (struct Scsi_Host *host, struct debugger_token *token,
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
instance->hostdata;
struct NCR53c7x0_break *bp, **prev;
- int old_level;
- old_level = splx(0);
+ unsigned long flags;
+ save_flags(flags);
+ cli();
for (bp = (struct NCR53c7x0_break *) instance->breakpoints,
prev = (struct NCR53c7x0_break **) &instance->breakpoints;
bp; prev = (struct NCR53c7x0_break **) &(bp->next),
bp = (struct NCR53c7x0_break *) bp->next);
if (!bp) {
- splx(old_level);
+ restore_flags(flags);
return -EIO;
}
@@ -1949,7 +2025,7 @@ static int debugger_fn_bc (struct Scsi_Host *host, struct debugger_token *token,
if (prev)
*prev = bp->next;
- splx(old_level);
+ restore_flags(flags);
return 0;
}
@@ -1961,7 +2037,7 @@ static int debugger_fn_bl (struct Scsi_Host *host, struct debugger_token *token,
struct NCR53c7x0_break *bp;
char buf[80];
size_t len;
- int old_level;
+ unsigned long flags;
/*
* XXX - we need to insure that the processor is halted
* here in order to prevent a race condition. So, if the
@@ -1972,7 +2048,8 @@ static int debugger_fn_bl (struct Scsi_Host *host, struct debugger_token *token,
host->host_no);
debugger_kernel_write (host, buf, strlen(buf));
- old_level=splx(0);
+ save_flags(flags);
+ cli();
for (bp = (struct NCR53c7x0_break *) host->breakpoints;
bp; bp = (struct NCR53c7x0_break *) bp->next); {
sprintf (buf, "scsi%d : bp : success : at %08x, replaces %08x %08x",
@@ -1987,7 +2064,7 @@ static int debugger_fn_bl (struct Scsi_Host *host, struct debugger_token *token,
len = strlen(buf);
debugger_kernel_write (host, buf, len);
}
- splx(old_level);
+ restore_flags(flags);
return 0;
}
@@ -1998,20 +2075,21 @@ static int debugger_fn_bs (struct Scsi_Host *host, struct debugger_token *token,
struct NCR53c7x0_break *bp;
char buf[80];
size_t len;
- int old_level;
- old_level=splx(0);
+ unsigned long flags;
+ save_flags(flags);
+ cli();
if (hostdata->state != STATE_HALTED) {
sprintf (buf, "scsi%d : bs : failure : NCR not halted\n", host->host_no);
debugger_kernel_write (host, buf, strlen(buf));
- splx(old_level);
+ restore_flags(flags);
return -1;
}
if (!(bp = kmalloc (sizeof (struct NCR53c7x0_break)))) {
printk ("scsi%d : kmalloc(%d) of breakpoint structure failed, try again\n",
host->host_no, sizeof(struct NCR53c7x0_break));
- splx(old_level);
+ restore_flags(flags);
return -1;
}
@@ -2023,7 +2101,7 @@ static int debugger_fn_bs (struct Scsi_Host *host, struct debugger_token *token,
hostdata->breakpoints = bp->next;
memcpy ((void *) bp->address, (void *) hostdata->E_debug_break, 8);
- splx(old_level);
+ restore_flags(flags);
return 0;
}
@@ -2112,9 +2190,10 @@ static debugger_kernel_write (struct Scsi_Host *host, char *buf, size_t
buflen) {
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata;
- int copy, left, old_level;
-
- old_level = splx(0);
+ int copy, left;
+ unsigned long flags;
+ save_flags(flags);
+ cli();
while (buflen) {
left = (hostdata->debug_buf + hostdata->debug_size - 1) -
hostdata->debug_write;
@@ -2127,7 +2206,7 @@ static debugger_kernel_write (struct Scsi_Host *host, char *buf, size_t
(hostdata->debug_buf + hostdata->debug_size))
hosdata->debug_write = hostdata->debug_buf;
}
- (void) splx(old_level);
+ restore_flags(flags);
}
#endif /* def NCRDEBUG */
@@ -2144,7 +2223,8 @@ static debugger_kernel_write (struct Scsi_Host *host, char *buf, size_t
*
*/
-static void NCR53c8x0_soft_reset (struct Scsi_Host *host) {
+static void
+NCR53c8x0_soft_reset (struct Scsi_Host *host) {
NCR53c7x0_local_declare();
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata;
@@ -2167,14 +2247,18 @@ static void NCR53c8x0_soft_reset (struct Scsi_Host *host) {
/*
- * Respond to selection and reselection by targets and
- * use our _initiator_ SCSI ID for arbitration.
+ * Respond to reselection by targets and use our _initiator_ SCSI ID
+ * for arbitration. If notyet, also respond to SCSI selection.
*
* XXX - Note : we must reprogram this when reselecting as
* a target.
*/
+#ifdef notyet
NCR53c7x0_write8(SCID_REG, (host->this_id & 7)|SCID_800_RRE|SCID_800_SRE);
+#else
+ NCR53c7x0_write8(SCID_REG, (host->this_id & 7)|SCID_800_RRE);
+#endif
NCR53c7x0_write8(RESPID_REG_800, hostdata->this_id_mask);
/*
@@ -2202,8 +2286,7 @@ static void NCR53c8x0_soft_reset (struct Scsi_Host *host) {
NCR53c7x0_write8(SIEN0_REG_800, ((hostdata->options & OPTION_PARITY) ?
- SIEN_PAR : 0) | SIEN_RST | SIEN_UDC | SIEN_SGE | SIEN_800_SEL |
- SIEN_800_RESEL | SIEN_MA);
+ SIEN_PAR : 0) | SIEN_RST | SIEN_UDC | SIEN_SGE | SIEN_MA);
NCR53c7x0_write8(SIEN1_REG_800, SIEN1_800_STO | SIEN1_800_HTH);
/*
@@ -2223,11 +2306,13 @@ static void NCR53c8x0_soft_reset (struct Scsi_Host *host) {
/*
* Function static struct NCR53c7x0_cmd *create_cmd (Scsi_Cmnd *cmd)
*
- * Purpose : Using scsi_malloc() if the system is initialized,
- * scan_scsis_buf if not, allocate space to store the variable
- * length NCR53c7x0_cmd structure. Initialize it based on
- * the Scsi_Cmnd structure passed in, including dsa and
- * Linux field initialization, and dsa code relocation.
+ * Purpose : If we have not already allocated enough NCR53c7x0_cmd
+ * structures to satisfy any allowable number of simultaneous
+ * commands for this host; do so (using either scsi_malloc()
+ * or kmalloc() depending on configuration), and add them to the
+ * hostdata free list. Take the first structure off the free list,
+ * initialize it based on the Scsi_Cmnd structure passed in,
+ * including dsa and Linux field initialization, and dsa code relocation.
*
* Inputs : cmd - SCSI command
*
@@ -2235,26 +2320,86 @@ static void NCR53c8x0_soft_reset (struct Scsi_Host *host) {
* NULL on failure.
*/
-static struct NCR53c7x0_cmd *create_cmd (Scsi_Cmnd *cmd) {
+static struct NCR53c7x0_cmd *
+create_cmd (Scsi_Cmnd *cmd) {
NCR53c7x0_local_declare();
struct Scsi_Host *host = cmd->host;
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata;
- int size; /* Size of *tmp */
- struct NCR53c7x0_cmd *tmp; /* NCR53c7x0_cmd structure for this command */
+ struct NCR53c7x0_cmd *tmp = NULL; /* NCR53c7x0_cmd structure for this command */
int datain, /* Number of instructions per phase */
dataout;
int data_transfer_instructions, /* Count of dynamic instructions */
- i, /* Counter */
- alignment; /* Alignment adjustment (0 - 4) */
+ i; /* Counter */
unsigned long *cmd_datain, /* Address of datain/dataout code */
*cmd_dataout; /* Incremented as we assemble */
+#ifdef notyet
void *real; /* Real address */
+ int size; /* Size of *tmp */
+ int alignment; /* Alignment adjustment (0 - 4) */
+#endif
+ unsigned long flags;
NCR53c7x0_local_setup(cmd->host);
+/* FIXME : when we start doing multiple simultaneous commands per LUN,
+ we will need to either
+ - Do an attach_slave() and detach_slave() the right way (allocate
+ memory in attach_slave() as we do in scsi_register).
+ - Make sure this code works
+ with the former being cleaner. At the same time, we can also go with
+ a per-device host_scribble, and introduce a NCR53c7x0_device structure
+ to replace the messy fixed length arrays we're starting to use. */
+
+#ifdef notyet
+
+ if (hostdata->num_commands < host->can_queue &&
+ !in_scan_scsis &&
+ !(hostdata->cmd_allocated[cmd->target] & (1 << cmd->lun))) {
+ for (i = host->hostt->cmd_per_lun - 1; i >= 0 --i) {
+#ifdef SCSI_MALLOC
+ /* scsi_malloc must allocate with a 512 byte granularity, but always
+ returns buffers which are aligned on a 512 boundary */
+ size = (hostdata->max_cmd_size + 511) / 512 * 512;
+ tmp = (struct NCR53c7x0_cmd *) scsi_malloc (size);
+ if (!tmp)
+ break;
+ tmp->real = (void *) tmp;
+#else
+ /* kmalloc() can allocate any size, but historically has returned
+ unaligned addresses, so we need to allow for alignment */
+ size = hostdata->max_cmd_size + 4;
+ real = kmalloc (size, GFP_ATOMIC);
+ alignment = 4 - (((unsigned) real) & 3);
+ tmp = (struct NCR53c7x0_cmd *) (((char *) real) + alignment);
+ if (!tmp)
+ break;
+ tmp->real = real;
+#endif /* def SCSI_MALLOC */
+ tmp->size = size;
+ /* Insert all but last into list */
+ if (i > 0) {
+ tmp->next = hostdata->free;
+ hostdata->free = tmp;
+ }
+ }
+ }
+#endif /* def notyet */
+ if (!tmp) {
+ save_flags(flags);
+ cli();
+ tmp = (struct NCR53c7x0_cmd *) hostdata->free;
+ if (tmp) {
+ hostdata->free = tmp->next;
+ restore_flags(flags);
+ } else {
+ restore_flags(flags);
+ return NULL;
+ }
+ }
+
/*
- * Decide weather we need to generate commands for DATA IN,
+ * Decide whether we need to generate commands for DATA IN,
* DATA OUT, neither, or both based on the SCSI command
*/
@@ -2303,10 +2448,6 @@ static struct NCR53c7x0_cmd *create_cmd (Scsi_Cmnd *cmd) {
datain = dataout = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
}
- /*
- * Allocate memory for the NCR53c7x0_cmd structure.
- */
-
/*
* For each data phase implemented, we need a JUMP instruction
* to return control to other_transfer. We also need a MOVE
@@ -2324,63 +2465,11 @@ static struct NCR53c7x0_cmd *create_cmd (Scsi_Cmnd *cmd) {
if (data_transfer_instructions < 2)
data_transfer_instructions = 2;
- /*
- * We need enough space to store the base NCR53c7x0 structure,
- * DSA, and data transfer instructions at 2 long words each,
- * as well as padding out to the next 512 bytes for scsi_malloc.
- *
- * We also need to guarantee alignment of _4_ bytes.
- */
-
-#ifdef SCSI_MALLOC
- size = ((sizeof (struct NCR53c7x0_cmd) + (hostdata->dsa_end -
- hostdata->dsa_start) + 2 * sizeof(long) *
- data_transfer_instructions + 4 + 511) / 512) * 512;
-#else
- size = sizeof (struct NCR53c7x0_cmd) + (hostdata->dsa_end -
- hostdata->dsa_start) + 2 * sizeof(long) *
- data_transfer_instructions + 4;
-#endif
-
-
-#if 0
- if (size > 512) {
- printk("scsi%d : size = %d\n", host->host_no, size);
- }
-#endif
-
-#ifdef SCSI_MALLOC
- real = in_scan_scsis ? NULL : scsi_malloc (size);
-#else
- real = kmalloc (size, GFP_ATOMIC);
-#endif
-
- if (!real) {
- if (!scan_scsis_buf_busy && size <= sizeof(scan_scsis_buf)) {
- scan_scsis_buf_busy = 1;
- real = scan_scsis_buf;
- } else {
- panic ("scsi%d : scan_scsis_buf too small (need %d bytes)\n",
- host->host_no, size);
- }
- }
-
- alignment = 4 - (((unsigned) real) & 3);
-
- tmp = (struct NCR53c7x0_cmd *) (((char *) real) + alignment);
-
- tmp->real = real;
-
-
- if (((unsigned long) tmp->dsa) & 0x3)
- panic ("scsi%d : pid %d dsa structure not dword aligned!\n",
- host->host_no, cmd->pid);
/*
* Initialize Linux specific fields.
*/
- tmp->size = size;
tmp->cmd = cmd;
tmp->next = NULL;
tmp->prev = NULL;
@@ -2414,7 +2503,7 @@ static struct NCR53c7x0_cmd *create_cmd (Scsi_Cmnd *cmd) {
patch_dsa_32(tmp->dsa, dsa_select, 0, hostdata->sync[cmd->target].
select_indirect);
/*
- * XXX - we need to figure this size based on weather
+ * XXX - we need to figure this size based on whether
* or not we'll be using any additional messages.
*/
patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1);
@@ -2442,7 +2531,7 @@ static struct NCR53c7x0_cmd *create_cmd (Scsi_Cmnd *cmd) {
patch_dsa_32(tmp->dsa, dsa_status, 1, &cmd->result);
patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, 1);
patch_dsa_32(tmp->dsa, dsa_msgout_other, 1,
- &NCR53c7xx_msg_nop);
+ &(hostdata->NCR53c7xx_msg_nop));
/*
@@ -2466,8 +2555,8 @@ static struct NCR53c7x0_cmd *create_cmd (Scsi_Cmnd *cmd) {
#endif
/*
- * XXX - I'm undecided weather all of this nonsense is faster
- * in the long run, or weather I should just go and implement a loop
+ * XXX - I'm undecided whether all of this nonsense is faster
+ * in the long run, or whether I should just go and implement a loop
* on the NCR chip using table indirect mode?
*
* In any case, this is how it _must_ be done for 53c700/700-66 chips,
@@ -2496,8 +2585,8 @@ static struct NCR53c7x0_cmd *create_cmd (Scsi_Cmnd *cmd) {
cmd_datain[2] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
DCMD_TCI_CD | DCMD_TCI_IO | DCMD_TCI_MSG) << 24) |
DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE | DBC_TCI_TRUE;
- cmd_datain[3] = hostdata->script + hostdata->E_msg_in /
- sizeof(long);
+ cmd_datain[3] = (unsigned long) hostdata->script +
+ hostdata->E_msg_in;
#if 0
print_insn (host, cmd_datain, "dynamic ", 1);
print_insn (host, cmd_datain + 2, "dynamic ", 1);
@@ -2510,8 +2599,8 @@ static struct NCR53c7x0_cmd *create_cmd (Scsi_Cmnd *cmd) {
cmd_dataout[2] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
DCMD_TCI_CD | DCMD_TCI_IO | DCMD_TCI_MSG) << 24) |
DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE | DBC_TCI_TRUE;
- cmd_dataout[3] = hostdata->script + hostdata->E_msg_in /
- sizeof(long);
+ cmd_dataout[3] = (unsigned long) hostdata->script +
+ hostdata->E_msg_in;
#if 0
print_insn (host, cmd_dataout, "dynamic ", 1);
print_insn (host, cmd_dataout + 2, "dynamic ", 1);
@@ -2528,8 +2617,8 @@ static struct NCR53c7x0_cmd *create_cmd (Scsi_Cmnd *cmd) {
if (datain) {
cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
DBC_TCI_TRUE;
- cmd_datain[1] = hostdata->script + hostdata->E_other_transfer
- / sizeof(long);
+ cmd_datain[1] = (unsigned long) hostdata->script +
+ hostdata->E_other_transfer;
#if 0
print_insn (host, cmd_datain, "dynamic jump ", 1);
#endif
@@ -2547,8 +2636,8 @@ static struct NCR53c7x0_cmd *create_cmd (Scsi_Cmnd *cmd) {
if (dataout) {
cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
DBC_TCI_TRUE;
- cmd_dataout[1] = hostdata->script + hostdata->E_other_transfer
- / sizeof(long);
+ cmd_dataout[1] = (unsigned long) hostdata->script +
+ hostdata->E_other_transfer;
#if 0
print_insn (host, cmd_dataout, "dynamic jump ", 1);
#endif
@@ -2583,7 +2672,7 @@ int NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
struct Scsi_Host *host = cmd->host;
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata;
- int old_level;
+ unsigned long flags;
unsigned char target_was_busy;
NCR53c7x0_local_setup(host);
@@ -2651,7 +2740,8 @@ int NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
* valid while the condition exists.
*/
- old_level = splx(0);
+ save_flags(flags);
+ cli();
/*
* Consider a target busy if there are _any_ commands running
@@ -2744,7 +2834,7 @@ int NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
tmp->next; tmp = (struct NCR53c7x0_cmd *) tmp->next);
tmp->next = tmp;
}
- splx(old_level);
+ restore_flags(flags);
return 0;
}
@@ -2790,7 +2880,7 @@ static void intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
/* 250ms selection timeout */
if ((((hostdata->chip / 100) == 8) && (sist1 & SIST1_800_STO)) ||
- (((hostdata->chip / 100) != 8) && sstat0_sist0 && SSTAT0_700_STO)) {
+ (((hostdata->chip / 100) != 8) && (sstat0_sist0 & SSTAT0_700_STO))) {
fatal = 1;
if (hostdata->options & OPTION_DEBUG_INTR) {
printk ("scsi%d : Selection Timeout\n", host->host_no);
@@ -2828,9 +2918,9 @@ static void intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
if (sstat0_sist0 & SSTAT0_UDC) {
fatal = 1;
- printk("scsi%d : target %d lun %d unexpected disconnect\n",
- host->host_no, cmd->cmd->target, cmd->cmd->lun);
if (cmd) {
+ printk("scsi%d : target %d lun %d unexpected disconnect\n",
+ host->host_no, cmd->cmd->target, cmd->cmd->lun);
abnormal_finished(cmd, DID_ERROR << 16);
}
hostdata->dsp = hostdata->script + hostdata->E_schedule /
@@ -2908,7 +2998,7 @@ static void intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
}
/*
- * Function : static void NCR53c7x0_intr (int irq)
+ * Function : static void NCR53c7x0_intr (int irq, struct pt_regs * regs)
*
* Purpose : handle NCR53c7x0 interrupts for all NCR devices sharing
* the same IRQ line.
@@ -2918,7 +3008,7 @@ static void intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
* this handler.
*/
-static void NCR53c7x0_intr (int irq) {
+static void NCR53c7x0_intr (int irq, struct pt_regs * regs) {
NCR53c7x0_local_declare();
struct Scsi_Host *host; /* Host we are looking at */
unsigned char istat; /* Values of interrupt regs */
@@ -2930,7 +3020,7 @@ static void NCR53c7x0_intr (int irq) {
should terminate */
int interrupted = 0; /* This HA generated
an interrupt */
- int old_level;
+ unsigned long flags;
#ifdef NCR_DEBUG
char buf[80]; /* Debugging sprintf buffer */
@@ -2991,12 +3081,14 @@ static void NCR53c7x0_intr (int irq) {
*/
- old_level = splx(0);
+ save_flags(flags);
+ cli();
restart:
for (cmd_prev_ptr = (struct NCR53c7x0_cmd **)
- &(hostdata->running_list), cmd = (struct NCR53c7x0_cmd *)
- hostdata->running_list; cmd ; cmd_prev_ptr =
- &(cmd->next), cmd = (struct NCR53c7x0_cmd *) cmd->next) {
+ &(hostdata->running_list), cmd =
+ (struct NCR53c7x0_cmd *) hostdata->running_list; cmd ;
+ cmd_prev_ptr = (struct NCR53c7x0_cmd **) &(cmd->next),
+ cmd = (struct NCR53c7x0_cmd *) cmd->next) {
Scsi_Cmnd *tmp;
if (!cmd) {
@@ -3025,7 +3117,7 @@ restart:
if (cmd->prev)
cmd->prev->next = cmd->next;
if (cmd_prev_ptr)
- *cmd_prev_ptr = cmd->next;
+ *cmd_prev_ptr = (struct NCR53c7x0_cmd *) cmd->next;
#ifdef LUN_BUSY
/* Check for next command for target, add to issue queue */
@@ -3034,16 +3126,8 @@ restart:
#endif
- if (!scan_scsis_buf_busy) {
-#ifdef SCSI_MALLOC
- scsi_free ((void *) cmd->real, cmd->size);
-#else
- kfree_s ((void *) cmd->real, cmd->size);
-#endif
- } else {
- scan_scsis_buf_busy = 0;
- }
-
+ cmd->next = hostdata->free;
+ hostdata->free = cmd;
tmp->host_scribble = NULL;
@@ -3061,7 +3145,7 @@ restart:
goto restart;
}
- splx(old_level);
+ restore_flags(flags);
if (!search_found) {
printk ("scsi%d : WARNING : INTFLY with no completed commands.\n",
@@ -3184,7 +3268,8 @@ restart:
*
*/
-static int abort_connected (struct Scsi_Host *host) {
+static int
+abort_connected (struct Scsi_Host *host) {
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata;
@@ -3378,15 +3463,13 @@ static void intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
NCR53c7x0_local_declare();
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata;
- unsigned char dstat, /* DSTAT */
- dbc_dcmd; /* DCMD (high eight bits) + DBC */
+ unsigned char dstat; /* DSTAT */
unsigned long *dsp,
*next_dsp, /* Current dsp */
- *dsa;
-
-
- int ipl, /* Old ipl from splx(0) */
- tmp;
+ *dsa,
+ dbc_dcmd; /* DCMD (high eight bits) + DBC */
+ int tmp;
+ unsigned long flags;
NCR53c7x0_local_setup(host);
if (!hostdata->dstat_valid) {
@@ -3440,12 +3523,13 @@ static void intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
if (hostdata->options & OPTION_DEBUG_TRACE) {
} else if (hostdata->options & OPTION_DEBUG_SINGLE) {
print_insn (host, dsp, "s ", 0);
- ipl = splx(0);
+ save_flags(flags);
+ cli();
/* XXX - should we do this, or can we get away with writing dsp? */
NCR53c7x0_write8 (DCNTL_REG, (NCR53c7x0_read8(DCNTL_REG) &
~DCNTL_SSM) | DCNTL_STD);
- splx(ipl);
+ restore_flags(flags);
} else {
printk("scsi%d : unexpected single step interrupt at\n"
" ", host->host_no);
@@ -3634,9 +3718,10 @@ int NCR53c7xx_abort (Scsi_Cmnd *cmd) {
struct Scsi_Host *host = cmd->host;
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata;
- int old_level;
+ unsigned long flags;
struct NCR53c7x0_cmd *curr, **prev;
- old_level = splx(0);
+ save_flags(flags);
+ cli();
/*
* The command could be hiding in the issue_queue. This would be very
@@ -3648,28 +3733,23 @@ int NCR53c7xx_abort (Scsi_Cmnd *cmd) {
* pull the command out of the old queue, and call it aborted.
*/
- for (curr = hostdata->issue_queue, prev = &(hostdata->issue_queue);
- curr && curr->cmd != cmd; prev = &(curr->next), curr = curr->next);
+ for (curr = (struct NCR53c7x0_cmd *) hostdata->issue_queue,
+ prev = (struct NCR53c7x0_cmd **) &(hostdata->issue_queue);
+ curr && curr->cmd != cmd; prev = (struct NCR53c7x0_cmd **)
+ &(curr->next), curr = (struct NCR53c7x0_cmd *) curr->next);
if (curr) {
- *prev = curr->next;
+ *prev = (struct NCR53c7x0_cmd *) curr->next;
/* XXX - get rid of DLL ? */
if (curr->prev)
curr->prev->next = curr->next;
- if (!scan_scsis_buf_busy) {
-#ifdef SCSI_MALLOC
- scsi_free ((void *) curr->real, curr->size);
-#else
- kfree_s ((void *) curr->real, curr->size);
-#endif
- } else {
- scan_scsis_buf_busy = 0;
- }
+ curr->next = hostdata->free;
+ hostdata->free = curr;
cmd->result = 0;
cmd->scsi_done(cmd);
- splx(old_level);
+ restore_flags(flags);
return SCSI_ABORT_SUCCESS;
}
@@ -3678,11 +3758,13 @@ int NCR53c7xx_abort (Scsi_Cmnd *cmd) {
* commands. If this is the case, drastic measures are called for.
*/
- for (curr = hostdata->running_list, prev = &(hostdata->running_list);
- curr && curr->cmd != cmd; prev = &(curr->next), curr = curr->next);
+ for (curr = (struct NCR53c7x0_cmd *) hostdata->running_list,
+ prev = (struct NCR53c7x0_cmd **) &(hostdata->running_list);
+ curr && curr->cmd != cmd; prev = (struct NCR53c7x0_cmd **)
+ &(curr->next), curr = (struct NCR53c7x0_cmd *) curr->next);
if (curr) {
- splx(old_level);
+ restore_flags(flags);
printk ("scsi%d : DANGER : command in running list, can not abort.\n",
cmd->host->host_no);
return SCSI_ABORT_SNOOZE;
@@ -3695,16 +3777,8 @@ int NCR53c7xx_abort (Scsi_Cmnd *cmd) {
*/
curr = (struct NCR53c7x0_cmd *) cmd->host_scribble;
-
- if (!scan_scsis_buf_busy) {
-#ifdef SCSI_MALLOC
- scsi_free ((void *) curr->real, curr->size);
-#else
- kfree_s ((void *) curr->real, curr->size);
-#endif
- } else {
- scan_scsis_buf_busy = 0;
- }
+ curr->next = hostdata->free;
+ hostdata->free = curr;
if (((cmd->result & 0xff00) == 0xff00) ||
((cmd->result & 0xff) == 0xff)) {
@@ -3714,7 +3788,7 @@ int NCR53c7xx_abort (Scsi_Cmnd *cmd) {
host->host_no);
}
cmd->scsi_done(cmd);
- splx(old_level);
+ restore_flags(flags);
return SCSI_ABORT_SNOOZE;
}
@@ -3729,17 +3803,47 @@ int NCR53c7xx_abort (Scsi_Cmnd *cmd) {
* Returns : 0 on success.
*/
-int NCR53c7xx_reset (Scsi_Cmnd *cmd) {
+int
+NCR53c7xx_reset (Scsi_Cmnd *cmd) {
NCR53c7x0_local_declare();
- struct Scsi_Host *host = cmd ? cmd->host : NULL;
+ unsigned long flags;
+ int found;
+ struct NCR53c7x0_cmd * c;
+ Scsi_Cmnd *tmp;
+ struct Scsi_Host *host = cmd->host;
struct NCR53c7x0_hostdata *hostdata = host ?
- (struct NCR53c7x0_hostdata *) host->hostdata : NULL;
- if (host) NCR53c7x0_local_setup(host);
-
+ (struct NCR53c7x0_hostdata *) host->hostdata : NULL;
+ NCR53c7x0_local_setup(host);
+ save_flags(flags);
+ halt (host);
+ NCR53c7x0_write8(SCNTL1_REG, SCNTL1_RST);
+ udelay(25); /* Minimum amount of time to assert RST */
+ NCR53c7x0_write8(SCNTL1_REG, SCNTL1_RST);
+ for (c = (struct NCR53c7x0_cmd *) hostdata->running_list, found = 0; c;
+ c = (struct NCR53c7x0_cmd *) c->next) {
+ tmp = c->cmd;
+ c->next = hostdata->free;
+ hostdata->free = c;
+
+ if (tmp == cmd)
+ found = 1;
+ tmp->result = DID_RESET << 16;
+ tmp->scsi_done(tmp);
+ }
+ if (!found) {
+ c = (struct NCR53c7x0_cmd *) cmd->host_scribble;
+ if (c) {
+ c->next = hostdata->free;
+ hostdata->free = c;
+ }
+ cmd->result = DID_RESET << 16;
+ cmd->scsi_done(cmd);
+ }
+ restore_flags(flags);
printk ("scsi%d : DANGER : NCR53c7xx_reset is NOP\n",
cmd->host->host_no);
- return SCSI_RESET_SNOOZE;
+ return SCSI_RESET_SUCCESS;
}
/*
@@ -3750,13 +3854,11 @@ int NCR53c7xx_reset (Scsi_Cmnd *cmd) {
static void print_dsa (struct Scsi_Host *host, unsigned long *dsa) {
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata;
- Scsi_Cmnd * cmd;
- struct NCR53c7x0_cmd * c;
int i, len;
char *ptr;
printk("scsi%d : dsa at 0x%x\n"
- " + %d : dsa_msgout length = %d, data = 0x%x\n" ,
+ " + %ld : dsa_msgout length = %lu, data = 0x%lx\n" ,
host->host_no, (unsigned) dsa, hostdata->dsa_msgout,
dsa[hostdata->dsa_msgout / sizeof(long)],
dsa[hostdata->dsa_msgout / sizeof(long) + 1]);
@@ -3770,3 +3872,108 @@ static void print_dsa (struct Scsi_Host *host, unsigned long *dsa) {
}
}
+/*
+ * Function : static int shutdown (struct Scsi_Host *host)
+ *
+ * Purpose : does a clean (we hope) shutdown of the NCR SCSI
+ * chip. Use prior to dumping core, unloading the NCR driver,
+ * etc.
+ *
+ * Returns : 0 on success
+ */
+#ifdef MODULE
+static int
+shutdown (struct Scsi_Host *host) {
+ NCR53c7x0_local_declare();
+ unsigned long flags;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ NCR53c7x0_local_setup(host);
+ save_flags (flags);
+ cli();
+ halt (host);
+ hostdata->soft_reset(host);
+/*
+ * For now, we take the simplest solution : reset the SCSI bus. Eventually,
+ * - If a command is connected, kill it with an ABORT message
+ * - If commands are disconnected, connect to each target/LUN and
+ * do a ABORT, followed by a SOFT reset, followed by a hard
+ * reset.
+ */
+ NCR53c7x0_write8(SCNTL1_REG, SCNTL1_RST);
+ udelay(25); /* Minimum amount of time to assert RST */
+ NCR53c7x0_write8(SCNTL1_REG, SCNTL1_RST);
+ restore_flags (flags);
+ return 0;
+}
+#endif
+
+
+/*
+ * Function : static int halt (struct Scsi_Host *host)
+ *
+ * Purpose : halts the SCSI SCRIPTS(tm) processor on the NCR chip
+ *
+ * Inputs : host - SCSI chip to halt
+ *
+ * Returns : 0 on success
+ */
+
+static int
+halt (struct Scsi_Host *host) {
+ NCR53c7x0_local_declare();
+ unsigned long flags;
+ unsigned char istat, tmp;
+ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+ host->hostdata;
+ NCR53c7x0_local_setup(host);
+
+ save_flags(flags);
+ cli();
+ NCR53c7x0_write8(hostdata->istat, ISTAT_ABRT);
+ /* Eat interrupts until we find what we're looking for */
+ for (;;) {
+ istat = NCR53c7x0_read8 (hostdata->istat);
+ if (istat & ISTAT_SIP) {
+ if ((hostdata->chip / 100) == 8) {
+ tmp = NCR53c7x0_read8(SIST0_REG_800);
+ udelay(1);
+ tmp = NCR53c7x0_read8(SIST1_REG_800);
+ } else {
+ tmp = NCR53c7x0_read8(SSTAT0_REG);
+ }
+ } else if (istat & ISTAT_DIP) {
+ NCR53c7x0_write8(hostdata->istat, 0);
+ tmp = NCR53c7x0_read8(DSTAT_REG);
+ if (tmp & DSTAT_ABRT)
+ break;
+ else
+ panic("scsi%d: could not halt NCR chip\n", host->host_no);
+ }
+ }
+ hostdata->state = STATE_HALTED;
+ restore_flags(flags);
+ return 0;
+}
+
+#ifdef MODULE
+int NCR53c7x0_release(struct Scsi_Host *host) {
+ shutdown (host);
+/* FIXME : need to recursively free tpnt structure */
+ if (host->irq != IRQ_NONE)
+ {
+ int irq_count;
+ struct Scsi_Host *tmp;
+ for (irq_count = 0, tmp = first_host; tmp; tmp = tmp->next)
+ if (tmp->hostt == the_template && tmp->irq == host->irq)
+ ++irq_count;
+ if (irq_count == 1)
+ free_irq(host->irq);
+ }
+ if (host->dma_channel != DMA_NONE)
+ free_dma(host->dma_channel);
+ return 1;
+}
+Scsi_Host_Template driver_template = NCR53c7xx;
+#include "scsi_module.c"
+#endif /* def MODULE */