aboutsummaryrefslogtreecommitdiff
path: root/drivers/scsi/sym53c8xx_2
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/sym53c8xx_2')
-rw-r--r--drivers/scsi/sym53c8xx_2/sym53c8xx.h1
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_fw.c18
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_fw.h2
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_fw1.h6
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_fw2.h8
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c982
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.h26
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_hipd.c311
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_hipd.h36
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_malloc.c4
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_misc.h22
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_nvram.c2
12 files changed, 741 insertions, 677 deletions
diff --git a/drivers/scsi/sym53c8xx_2/sym53c8xx.h b/drivers/scsi/sym53c8xx_2/sym53c8xx.h
index 7519728dfc3..62d29cfac9e 100644
--- a/drivers/scsi/sym53c8xx_2/sym53c8xx.h
+++ b/drivers/scsi/sym53c8xx_2/sym53c8xx.h
@@ -127,7 +127,6 @@ struct sym_driver_setup {
u_char settle_delay;
u_char use_nvram;
u_long excludes[8];
- char tag_ctrl[100];
};
#define SYM_SETUP_MAX_TAG sym_driver_setup.max_tag
diff --git a/drivers/scsi/sym53c8xx_2/sym_fw.c b/drivers/scsi/sym53c8xx_2/sym_fw.c
index 9916a2a2255..190770bdc19 100644
--- a/drivers/scsi/sym53c8xx_2/sym_fw.c
+++ b/drivers/scsi/sym53c8xx_2/sym_fw.c
@@ -104,8 +104,9 @@ static struct sym_fwz_ofs sym_fw2z_ofs = {
* Patch routine for firmware #1.
*/
static void
-sym_fw1_patch(struct sym_hcb *np)
+sym_fw1_patch(struct Scsi_Host *shost)
{
+ struct sym_hcb *np = sym_get_hcb(shost);
struct sym_fw1a_scr *scripta0;
struct sym_fw1b_scr *scriptb0;
@@ -145,8 +146,11 @@ sym_fw1_patch(struct sym_hcb *np)
* Patch routine for firmware #2.
*/
static void
-sym_fw2_patch(struct sym_hcb *np)
+sym_fw2_patch(struct Scsi_Host *shost)
{
+ struct sym_data *sym_data = shost_priv(shost);
+ struct pci_dev *pdev = sym_data->pdev;
+ struct sym_hcb *np = sym_data->ncb;
struct sym_fw2a_scr *scripta0;
struct sym_fw2b_scr *scriptb0;
@@ -167,7 +171,7 @@ sym_fw2_patch(struct sym_hcb *np)
* Remove useless 64 bit DMA specific SCRIPTS,
* when this feature is not available.
*/
- if (!np->use_dac) {
+ if (!use_dac(np)) {
scripta0->is_dmap_dirty[0] = cpu_to_scr(SCR_NO_OP);
scripta0->is_dmap_dirty[1] = 0;
scripta0->is_dmap_dirty[2] = cpu_to_scr(SCR_NO_OP);
@@ -205,14 +209,14 @@ sym_fw2_patch(struct sym_hcb *np)
* Remove a couple of work-arounds specific to C1010 if
* they are not desirable. See `sym_fw2.h' for more details.
*/
- if (!(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66 &&
- np->revision_id < 0x1 &&
+ if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_66 &&
+ pdev->revision < 0x1 &&
np->pciclk_khz < 60000)) {
scripta0->datao_phase[0] = cpu_to_scr(SCR_NO_OP);
scripta0->datao_phase[1] = cpu_to_scr(0);
}
- if (!(np->device_id == PCI_DEVICE_ID_LSI_53C1010_33 &&
- /* np->revision_id < 0xff */ 1)) {
+ if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_33 /* &&
+ pdev->revision < 0xff */)) {
scripta0->sel_done[0] = cpu_to_scr(SCR_NO_OP);
scripta0->sel_done[1] = cpu_to_scr(0);
}
diff --git a/drivers/scsi/sym53c8xx_2/sym_fw.h b/drivers/scsi/sym53c8xx_2/sym_fw.h
index 66ec35beab5..ae7e0f9e93f 100644
--- a/drivers/scsi/sym53c8xx_2/sym_fw.h
+++ b/drivers/scsi/sym53c8xx_2/sym_fw.h
@@ -143,7 +143,7 @@ struct sym_fw {
*z_ofs; /* Useful offsets in script Z */
/* Setup and patch methods for this firmware */
void (*setup)(struct sym_hcb *, struct sym_fw *);
- void (*patch)(struct sym_hcb *);
+ void (*patch)(struct Scsi_Host *);
};
/*
diff --git a/drivers/scsi/sym53c8xx_2/sym_fw1.h b/drivers/scsi/sym53c8xx_2/sym_fw1.h
index 7b39f4a35e9..63952ee300b 100644
--- a/drivers/scsi/sym53c8xx_2/sym_fw1.h
+++ b/drivers/scsi/sym53c8xx_2/sym_fw1.h
@@ -1020,7 +1020,7 @@ static struct SYM_FWA_SCR SYM_FWA_SCR = {
* It shall be a tagged command.
* Read SIMPLE+TAG.
* The C code will deal with errors.
- * Agressive optimization, is'nt it? :)
+ * Aggressive optimization, isn't it? :)
*/
SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
HADDR_1 (msgin),
@@ -1044,7 +1044,7 @@ static struct SYM_FWA_SCR SYM_FWA_SCR = {
RADDR_1 (dsa),
/*
* The SIDL still contains the TAG value.
- * Agressive optimization, isn't it? :):)
+ * Aggressive optimization, isn't it? :):)
*/
SCR_REG_SFBR (sidl, SCR_SHL, 0),
0,
@@ -1449,7 +1449,7 @@ static struct SYM_FWB_SCR SYM_FWB_SCR = {
PADDR_B (msg_weird_seen),
/*
* We donnot handle extended messages from SCRIPTS.
- * Read the amount of data correponding to the
+ * Read the amount of data corresponding to the
* message length and call the C code.
*/
SCR_COPY (1),
diff --git a/drivers/scsi/sym53c8xx_2/sym_fw2.h b/drivers/scsi/sym53c8xx_2/sym_fw2.h
index 851f2706f22..c87d72443a1 100644
--- a/drivers/scsi/sym53c8xx_2/sym_fw2.h
+++ b/drivers/scsi/sym53c8xx_2/sym_fw2.h
@@ -956,7 +956,7 @@ static struct SYM_FWA_SCR SYM_FWA_SCR = {
* It shall be a tagged command.
* Read SIMPLE+TAG.
* The C code will deal with errors.
- * Agressive optimization, is'nt it? :)
+ * Aggressive optimization, isn't it? :)
*/
SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
HADDR_1 (msgin),
@@ -968,7 +968,7 @@ static struct SYM_FWA_SCR SYM_FWA_SCR = {
offsetof(struct sym_lcb, head.itlq_tbl_sa),
/*
* The SIDL still contains the TAG value.
- * Agressive optimization, isn't it? :):)
+ * Aggressive optimization, isn't it? :):)
*/
SCR_REG_SFBR (sidl, SCR_SHL, 0),
0,
@@ -1326,7 +1326,7 @@ static struct SYM_FWB_SCR SYM_FWB_SCR = {
PADDR_B (msg_weird_seen),
/*
* We donnot handle extended messages from SCRIPTS.
- * Read the amount of data correponding to the
+ * Read the amount of data corresponding to the
* message length and call the C code.
*/
SCR_STORE_REL (scratcha, 1),
@@ -1781,7 +1781,7 @@ static struct SYM_FWB_SCR SYM_FWB_SCR = {
* While testing with bogus QUANTUM drives, the C1010
* sometimes raised a spurious phase mismatch with
* WSR and the CHMOV(1) triggered another PM.
- * Waiting explicitely for the PHASE seemed to avoid
+ * Waiting explicitly for the PHASE seemed to avoid
* the nested phase mismatch. Btw, this didn't happen
* using my IBM drives.
*/
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index 739d3ef46a4..6d3ee1ab636 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -39,7 +39,6 @@
*/
#include <linux/ctype.h>
#include <linux/init.h>
-#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
@@ -54,16 +53,12 @@
#define NAME53C "sym53c"
#define NAME53C8XX "sym53c8xx"
-#define IRQ_FMT "%d"
-#define IRQ_PRM(x) (x)
-
struct sym_driver_setup sym_driver_setup = SYM_LINUX_DRIVER_SETUP;
unsigned int sym_debug_flags = 0;
static char *excl_string;
static char *safe_string;
module_param_named(cmd_per_lun, sym_driver_setup.max_tag, ushort, 0);
-module_param_string(tag_ctrl, sym_driver_setup.tag_ctrl, 100, 0);
module_param_named(burst, sym_driver_setup.burst_order, byte, 0);
module_param_named(led, sym_driver_setup.scsi_led, byte, 0);
module_param_named(diff, sym_driver_setup.scsi_diff, byte, 0);
@@ -78,7 +73,6 @@ module_param_named(excl, excl_string, charp, 0);
module_param_named(safe, safe_string, charp, 0);
MODULE_PARM_DESC(cmd_per_lun, "The maximum number of tags to use by default");
-MODULE_PARM_DESC(tag_ctrl, "More detailed control over tags per LUN");
MODULE_PARM_DESC(burst, "Maximum burst. 0 to disable, 255 to read from registers");
MODULE_PARM_DESC(led, "Set to 1 to enable LED support");
MODULE_PARM_DESC(diff, "0 for no differential mode, 1 for BIOS, 2 for always, 3 for not GPIO3");
@@ -134,82 +128,26 @@ static struct scsi_transport_template *sym2_transport_template = NULL;
* Driver private area in the SCSI command structure.
*/
struct sym_ucmd { /* Override the SCSI pointer structure */
- dma_addr_t data_mapping;
- unsigned char data_mapped;
- unsigned char to_do; /* For error handling */
- void (*old_done)(struct scsi_cmnd *); /* For error handling */
- struct completion *eh_done; /* For error handling */
+ struct completion *eh_done; /* SCSI error handling */
};
#define SYM_UCMD_PTR(cmd) ((struct sym_ucmd *)(&(cmd)->SCp))
#define SYM_SOFTC_PTR(cmd) sym_get_hcb(cmd->device->host)
-static void __unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
-{
- int dma_dir = cmd->sc_data_direction;
-
- switch(SYM_UCMD_PTR(cmd)->data_mapped) {
- case 2:
- pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, dma_dir);
- break;
- case 1:
- pci_unmap_single(pdev, SYM_UCMD_PTR(cmd)->data_mapping,
- cmd->request_bufflen, dma_dir);
- break;
- }
- SYM_UCMD_PTR(cmd)->data_mapped = 0;
-}
-
-static dma_addr_t __map_scsi_single_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
-{
- dma_addr_t mapping;
- int dma_dir = cmd->sc_data_direction;
-
- mapping = pci_map_single(pdev, cmd->request_buffer,
- cmd->request_bufflen, dma_dir);
- if (mapping) {
- SYM_UCMD_PTR(cmd)->data_mapped = 1;
- SYM_UCMD_PTR(cmd)->data_mapping = mapping;
- }
-
- return mapping;
-}
-
-static int __map_scsi_sg_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
-{
- int use_sg;
- int dma_dir = cmd->sc_data_direction;
-
- use_sg = pci_map_sg(pdev, cmd->request_buffer, cmd->use_sg, dma_dir);
- if (use_sg > 0) {
- SYM_UCMD_PTR(cmd)->data_mapped = 2;
- SYM_UCMD_PTR(cmd)->data_mapping = use_sg;
- }
-
- return use_sg;
-}
-
-#define unmap_scsi_data(np, cmd) \
- __unmap_scsi_data(np->s.device, cmd)
-#define map_scsi_single_data(np, cmd) \
- __map_scsi_single_data(np->s.device, cmd)
-#define map_scsi_sg_data(np, cmd) \
- __map_scsi_sg_data(np->s.device, cmd)
/*
* Complete a pending CAM CCB.
*/
void sym_xpt_done(struct sym_hcb *np, struct scsi_cmnd *cmd)
{
- unmap_scsi_data(np, cmd);
- cmd->scsi_done(cmd);
-}
+ struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd);
+ BUILD_BUG_ON(sizeof(struct scsi_pointer) < sizeof(struct sym_ucmd));
-static void sym_xpt_done2(struct sym_hcb *np, struct scsi_cmnd *cmd, int cam_status)
-{
- sym_set_cam_status(cmd, cam_status);
- sym_xpt_done(np, cmd);
-}
+ if (ucmd->eh_done)
+ complete(ucmd->eh_done);
+ scsi_dma_unmap(cmd);
+ cmd->scsi_done(cmd);
+}
/*
* Tell the SCSI layer about a BUS RESET.
@@ -225,14 +163,6 @@ void sym_xpt_async_bus_reset(struct sym_hcb *np)
}
/*
- * Tell the SCSI layer about a BUS DEVICE RESET message sent.
- */
-void sym_xpt_async_sent_bdr(struct sym_hcb *np, int target)
-{
- printf_notice("%s: TARGET %d has been reset.\n", sym_name(np), target);
-}
-
-/*
* Choose the more appropriate CAM status if
* the IO encountered an extended error.
*/
@@ -277,10 +207,9 @@ void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid)
/*
* Bounce back the sense data to user.
*/
- memset(&cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+ memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
memcpy(cmd->sense_buffer, cp->sns_bbuf,
- min(sizeof(cmd->sense_buffer),
- (size_t)SYM_SNS_BBUF_LEN));
+ min(SCSI_SENSE_BUFFERSIZE, SYM_SNS_BBUF_LEN));
#if 0
/*
* If the device reports a UNIT ATTENTION condition
@@ -322,68 +251,33 @@ void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid)
*/
cam_status = sym_xerr_cam_status(DID_ERROR, cp->xerr_status);
}
- cmd->resid = resid;
+ scsi_set_resid(cmd, resid);
cmd->result = (drv_status << 24) + (cam_status << 16) + scsi_status;
}
-
-/*
- * Build the scatter/gather array for an I/O.
- */
-
-static int sym_scatter_no_sglist(struct sym_hcb *np, struct sym_ccb *cp, struct scsi_cmnd *cmd)
-{
- struct sym_tblmove *data = &cp->phys.data[SYM_CONF_MAX_SG-1];
- int segment;
- unsigned int len = cmd->request_bufflen;
-
- if (len) {
- dma_addr_t baddr = map_scsi_single_data(np, cmd);
- if (baddr) {
- if (len & 1) {
- struct sym_tcb *tp = &np->target[cp->target];
- if (tp->head.wval & EWS) {
- len++;
- cp->odd_byte_adjustment++;
- }
- }
- cp->data_len = len;
- sym_build_sge(np, data, baddr, len);
- segment = 1;
- } else {
- segment = -2;
- }
- } else {
- segment = 0;
- }
-
- return segment;
-}
-
static int sym_scatter(struct sym_hcb *np, struct sym_ccb *cp, struct scsi_cmnd *cmd)
{
int segment;
- int use_sg = (int) cmd->use_sg;
+ int use_sg;
cp->data_len = 0;
- if (!use_sg)
- segment = sym_scatter_no_sglist(np, cp, cmd);
- else if ((use_sg = map_scsi_sg_data(np, cmd)) > 0) {
- struct scatterlist *scatter = (struct scatterlist *)cmd->request_buffer;
+ use_sg = scsi_dma_map(cmd);
+ if (use_sg > 0) {
+ struct scatterlist *sg;
struct sym_tcb *tp = &np->target[cp->target];
struct sym_tblmove *data;
if (use_sg > SYM_CONF_MAX_SG) {
- unmap_scsi_data(np, cmd);
+ scsi_dma_unmap(cmd);
return -1;
}
data = &cp->phys.data[SYM_CONF_MAX_SG - use_sg];
- for (segment = 0; segment < use_sg; segment++) {
- dma_addr_t baddr = sg_dma_address(&scatter[segment]);
- unsigned int len = sg_dma_len(&scatter[segment]);
+ scsi_for_each_sg(cmd, sg, use_sg, segment) {
+ dma_addr_t baddr = sg_dma_address(sg);
+ unsigned int len = sg_dma_len(sg);
if ((len & 1) && (tp->head.wval & EWS)) {
len++;
@@ -412,15 +306,6 @@ static int sym_queue_command(struct sym_hcb *np, struct scsi_cmnd *cmd)
int order;
/*
- * Minimal checkings, so that we will not
- * go outside our tables.
- */
- if (sdev->id == np->myaddr) {
- sym_xpt_done2(np, cmd, DID_NO_CONNECT);
- return 0;
- }
-
- /*
* Retrieve the target descriptor.
*/
tp = &np->target[sdev->id];
@@ -494,7 +379,7 @@ int sym_setup_data_and_start(struct sym_hcb *np, struct scsi_cmnd *cmd, struct s
*/
switch (dir) {
case DMA_BIDIRECTIONAL:
- printk("%s: got DMA_BIDIRECTIONAL command", sym_name(np));
+ scmd_printk(KERN_INFO, cmd, "got DMA_BIDIRECTIONAL command");
sym_set_cam_status(cmd, DID_ERROR);
goto out_abort;
case DMA_TO_DEVICE:
@@ -603,14 +488,16 @@ static void sym_timer(struct sym_hcb *np)
/*
* PCI BUS error handler.
*/
-void sym_log_bus_error(struct sym_hcb *np)
+void sym_log_bus_error(struct Scsi_Host *shost)
{
- u_short pci_sts;
- pci_read_config_word(np->s.device, PCI_STATUS, &pci_sts);
+ struct sym_data *sym_data = shost_priv(shost);
+ struct pci_dev *pdev = sym_data->pdev;
+ unsigned short pci_sts;
+ pci_read_config_word(pdev, PCI_STATUS, &pci_sts);
if (pci_sts & 0xf900) {
- pci_write_config_word(np->s.device, PCI_STATUS, pci_sts);
- printf("%s: PCI STATUS = 0x%04x\n",
- sym_name(np), pci_sts & 0xf900);
+ pci_write_config_word(pdev, PCI_STATUS, pci_sts);
+ shost_printk(KERN_WARNING, shost,
+ "PCI bus error: status = 0x%04x\n", pci_sts & 0xf900);
}
}
@@ -618,22 +505,22 @@ void sym_log_bus_error(struct sym_hcb *np)
* queuecommand method. Entered with the host adapter lock held and
* interrupts disabled.
*/
-static int sym53c8xx_queue_command(struct scsi_cmnd *cmd,
+static int sym53c8xx_queue_command_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
struct sym_hcb *np = SYM_SOFTC_PTR(cmd);
struct sym_ucmd *ucp = SYM_UCMD_PTR(cmd);
int sts = 0;
- cmd->scsi_done = done;
+ cmd->scsi_done = done;
memset(ucp, 0, sizeof(*ucp));
/*
* Shorten our settle_time if needed for
* this command not to time out.
*/
- if (np->s.settle_time_valid && cmd->timeout_per_command) {
- unsigned long tlimit = jiffies + cmd->timeout_per_command;
+ if (np->s.settle_time_valid && cmd->request->timeout) {
+ unsigned long tlimit = jiffies + cmd->request->timeout;
tlimit -= SYM_CONF_TIMER_INTERVAL*2;
if (time_after(np->s.settle_time, tlimit)) {
np->s.settle_time = tlimit;
@@ -649,23 +536,30 @@ static int sym53c8xx_queue_command(struct scsi_cmnd *cmd,
return 0;
}
+static DEF_SCSI_QCMD(sym53c8xx_queue_command)
+
/*
* Linux entry point of the interrupt handler.
*/
-static irqreturn_t sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t sym53c8xx_intr(int irq, void *dev_id)
{
- unsigned long flags;
- struct sym_hcb *np = (struct sym_hcb *)dev_id;
+ struct Scsi_Host *shost = dev_id;
+ struct sym_data *sym_data = shost_priv(shost);
+ irqreturn_t result;
+
+ /* Avoid spinloop trying to handle interrupts on frozen device */
+ if (pci_channel_offline(sym_data->pdev))
+ return IRQ_NONE;
if (DEBUG_FLAGS & DEBUG_TINY) printf_debug ("[");
- spin_lock_irqsave(np->s.host->host_lock, flags);
- sym_interrupt(np);
- spin_unlock_irqrestore(np->s.host->host_lock, flags);
+ spin_lock(shost->host_lock);
+ result = sym_interrupt(shost);
+ spin_unlock(shost->host_lock);
if (DEBUG_FLAGS & DEBUG_TINY) printf_debug ("]\n");
- return IRQ_HANDLED;
+ return result;
}
/*
@@ -691,59 +585,63 @@ static void sym53c8xx_timer(unsigned long npref)
#define SYM_EH_HOST_RESET 3
/*
- * What we will do regarding the involved SCSI command.
- */
-#define SYM_EH_DO_IGNORE 0
-#define SYM_EH_DO_WAIT 2
-
-/*
- * scsi_done() alias when error recovery is in progress.
- */
-static void sym_eh_done(struct scsi_cmnd *cmd)
-{
- struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd);
- BUILD_BUG_ON(sizeof(struct scsi_pointer) < sizeof(struct sym_ucmd));
-
- cmd->scsi_done = ucmd->old_done;
-
- if (ucmd->to_do == SYM_EH_DO_WAIT)
- complete(ucmd->eh_done);
-}
-
-/*
* Generic method for our eh processing.
* The 'op' argument tells what we have to do.
*/
static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd)
{
- struct sym_hcb *np = SYM_SOFTC_PTR(cmd);
struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd);
- struct Scsi_Host *host = cmd->device->host;
+ struct Scsi_Host *shost = cmd->device->host;
+ struct sym_data *sym_data = shost_priv(shost);
+ struct pci_dev *pdev = sym_data->pdev;
+ struct sym_hcb *np = sym_data->ncb;
SYM_QUEHEAD *qp;
- int to_do = SYM_EH_DO_IGNORE;
+ int cmd_queued = 0;
int sts = -1;
struct completion eh_done;
- dev_warn(&cmd->device->sdev_gendev, "%s operation started.\n", opname);
+ scmd_printk(KERN_WARNING, cmd, "%s operation started\n", opname);
+
+ /* We may be in an error condition because the PCI bus
+ * went down. In this case, we need to wait until the
+ * PCI bus is reset, the card is reset, and only then
+ * proceed with the scsi error recovery. There's no
+ * point in hurrying; take a leisurely wait.
+ */
+#define WAIT_FOR_PCI_RECOVERY 35
+ if (pci_channel_offline(pdev)) {
+ int finished_reset = 0;
+ init_completion(&eh_done);
+ spin_lock_irq(shost->host_lock);
+ /* Make sure we didn't race */
+ if (pci_channel_offline(pdev)) {
+ BUG_ON(sym_data->io_reset);
+ sym_data->io_reset = &eh_done;
+ } else {
+ finished_reset = 1;
+ }
+ spin_unlock_irq(shost->host_lock);
+ if (!finished_reset)
+ finished_reset = wait_for_completion_timeout
+ (sym_data->io_reset,
+ WAIT_FOR_PCI_RECOVERY*HZ);
+ spin_lock_irq(shost->host_lock);
+ sym_data->io_reset = NULL;
+ spin_unlock_irq(shost->host_lock);
+ if (!finished_reset)
+ return SCSI_FAILED;
+ }
- spin_lock_irq(host->host_lock);
+ spin_lock_irq(shost->host_lock);
/* This one is queued in some place -> to wait for completion */
FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {
struct sym_ccb *cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
if (cp->cmd == cmd) {
- to_do = SYM_EH_DO_WAIT;
+ cmd_queued = 1;
break;
}
}
- if (to_do == SYM_EH_DO_WAIT) {
- init_completion(&eh_done);
- ucmd->old_done = cmd->scsi_done;
- ucmd->eh_done = &eh_done;
- wmb();
- cmd->scsi_done = sym_eh_done;
- }
-
/* Try to proceed the operation we have been asked for */
sts = -1;
switch(op) {
@@ -759,7 +657,7 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd)
break;
case SYM_EH_HOST_RESET:
sym_reset_scsi_bus(np, 0);
- sym_start_up (np, 1);
+ sym_start_up(shost, 1);
sts = 0;
break;
default:
@@ -767,21 +665,21 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd)
}
/* On error, restore everything and cross fingers :) */
- if (sts) {
- cmd->scsi_done = ucmd->old_done;
- to_do = SYM_EH_DO_IGNORE;
- }
-
- ucmd->to_do = to_do;
- spin_unlock_irq(host->host_lock);
+ if (sts)
+ cmd_queued = 0;
- if (to_do == SYM_EH_DO_WAIT) {
+ if (cmd_queued) {
+ init_completion(&eh_done);
+ ucmd->eh_done = &eh_done;
+ spin_unlock_irq(shost->host_lock);
if (!wait_for_completion_timeout(&eh_done, 5*HZ)) {
- ucmd->to_do = SYM_EH_DO_IGNORE;
- wmb();
+ ucmd->eh_done = NULL;
sts = -2;
}
+ } else {
+ spin_unlock_irq(shost->host_lock);
}
+
dev_warn(&cmd->device->sdev_gendev, "%s operation %s.\n", opname,
sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed");
return sts ? SCSI_FAILED : SCSI_SUCCESS;
@@ -836,69 +734,19 @@ static void sym_tune_dev_queuing(struct sym_tcb *tp, int lun, u_short reqtags)
}
}
-/*
- * Linux select queue depths function
- */
-#define DEF_DEPTH (sym_driver_setup.max_tag)
-#define ALL_TARGETS -2
-#define NO_TARGET -1
-#define ALL_LUNS -2
-#define NO_LUN -1
-
-static int device_queue_depth(struct sym_hcb *np, int target, int lun)
-{
- int c, h, t, u, v;
- char *p = sym_driver_setup.tag_ctrl;
- char *ep;
-
- h = -1;
- t = NO_TARGET;
- u = NO_LUN;
- while ((c = *p++) != 0) {
- v = simple_strtoul(p, &ep, 0);
- switch(c) {
- case '/':
- ++h;
- t = ALL_TARGETS;
- u = ALL_LUNS;
- break;
- case 't':
- if (t != target)
- t = (target == v) ? v : NO_TARGET;
- u = ALL_LUNS;
- break;
- case 'u':
- if (u != lun)
- u = (lun == v) ? v : NO_LUN;
- break;
- case 'q':
- if (h == np->s.unit &&
- (t == ALL_TARGETS || t == target) &&
- (u == ALL_LUNS || u == lun))
- return v;
- break;
- case '-':
- t = ALL_TARGETS;
- u = ALL_LUNS;
- break;
- default:
- break;
- }
- p = ep;
- }
- return DEF_DEPTH;
-}
-
static int sym53c8xx_slave_alloc(struct scsi_device *sdev)
{
struct sym_hcb *np = sym_get_hcb(sdev->host);
struct sym_tcb *tp = &np->target[sdev->id];
struct sym_lcb *lp;
+ unsigned long flags;
+ int error;
if (sdev->id >= SYM_CONF_MAX_TARGET || sdev->lun >= SYM_CONF_MAX_LUN)
return -ENXIO;
- tp->starget = sdev->sdev_target;
+ spin_lock_irqsave(np->s.host->host_lock, flags);
+
/*
* Fail the device init if the device is flagged NOSCAN at BOOT in
* the NVRAM. This may speed up boot and maintain coherency with
@@ -910,26 +758,37 @@ static int sym53c8xx_slave_alloc(struct scsi_device *sdev)
if (tp->usrflags & SYM_SCAN_BOOT_DISABLED) {
tp->usrflags &= ~SYM_SCAN_BOOT_DISABLED;
- starget_printk(KERN_INFO, tp->starget,
+ starget_printk(KERN_INFO, sdev->sdev_target,
"Scan at boot disabled in NVRAM\n");
- return -ENXIO;
+ error = -ENXIO;
+ goto out;
}
if (tp->usrflags & SYM_SCAN_LUNS_DISABLED) {
- if (sdev->lun != 0)
- return -ENXIO;
- starget_printk(KERN_INFO, tp->starget,
+ if (sdev->lun != 0) {
+ error = -ENXIO;
+ goto out;
+ }
+ starget_printk(KERN_INFO, sdev->sdev_target,
"Multiple LUNs disabled in NVRAM\n");
}
lp = sym_alloc_lcb(np, sdev->id, sdev->lun);
- if (!lp)
- return -ENOMEM;
+ if (!lp) {
+ error = -ENOMEM;
+ goto out;
+ }
+ if (tp->nlcb == 1)
+ tp->starget = sdev->sdev_target;
spi_min_period(tp->starget) = tp->usr_period;
spi_max_width(tp->starget) = tp->usr_width;
- return 0;
+ error = 0;
+out:
+ spin_unlock_irqrestore(np->s.host->host_lock, flags);
+
+ return error;
}
/*
@@ -949,25 +808,20 @@ static int sym53c8xx_slave_configure(struct scsi_device *sdev)
/*
* Select queue depth from driver setup.
- * Donnot use more than configured by user.
- * Use at least 2.
- * Donnot use more than our maximum.
+ * Do not use more than configured by user.
+ * Use at least 1.
+ * Do not use more than our maximum.
*/
- reqtags = device_queue_depth(np, sdev->id, sdev->lun);
+ reqtags = sym_driver_setup.max_tag;
if (reqtags > tp->usrtags)
reqtags = tp->usrtags;
if (!sdev->tagged_supported)
reqtags = 0;
-#if 1 /* Avoid to locally queue commands for no good reasons */
if (reqtags > SYM_CONF_MAX_TAG)
reqtags = SYM_CONF_MAX_TAG;
- depth_to_use = (reqtags ? reqtags : 2);
-#else
- depth_to_use = (reqtags ? SYM_CONF_MAX_TAG : 2);
-#endif
+ depth_to_use = reqtags ? reqtags : 1;
scsi_adjust_queue_depth(sdev,
- (sdev->tagged_supported ?
- MSG_SIMPLE_TAG : 0),
+ sdev->tagged_supported ? MSG_SIMPLE_TAG : 0,
depth_to_use);
lp->s.scdev_depth = depth_to_use;
sym_tune_dev_queuing(tp, sdev->lun, reqtags);
@@ -981,12 +835,38 @@ static int sym53c8xx_slave_configure(struct scsi_device *sdev)
static void sym53c8xx_slave_destroy(struct scsi_device *sdev)
{
struct sym_hcb *np = sym_get_hcb(sdev->host);
- struct sym_lcb *lp = sym_lp(&np->target[sdev->id], sdev->lun);
+ struct sym_tcb *tp = &np->target[sdev->id];
+ struct sym_lcb *lp = sym_lp(tp, sdev->lun);
+ unsigned long flags;
- if (lp->itlq_tbl)
- sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK * 4, "ITLQ_TBL");
- kfree(lp->cb_tags);
- sym_mfree_dma(lp, sizeof(*lp), "LCB");
+ /* if slave_alloc returned before allocating a sym_lcb, return */
+ if (!lp)
+ return;
+
+ spin_lock_irqsave(np->s.host->host_lock, flags);
+
+ if (lp->busy_itlq || lp->busy_itl) {
+ /*
+ * This really shouldn't happen, but we can't return an error
+ * so let's try to stop all on-going I/O.
+ */
+ starget_printk(KERN_WARNING, tp->starget,
+ "Removing busy LCB (%d)\n", sdev->lun);
+ sym_reset_scsi_bus(np, 1);
+ }
+
+ if (sym_free_lcb(np, sdev->id, sdev->lun) == 0) {
+ /*
+ * It was the last unit for this target.
+ */
+ tp->head.sval = 0;
+ tp->head.wval = np->rv_scntl3;
+ tp->head.uval = 0;
+ tp->tgoal.check_nego = 1;
+ tp->starget = NULL;
+ }
+
+ spin_unlock_irqrestore(np->s.host->host_lock, flags);
}
/*
@@ -1052,6 +932,8 @@ static void sym_exec_user_command (struct sym_hcb *np, struct sym_usrcmd *uc)
if (!((uc->target >> t) & 1))
continue;
tp = &np->target[t];
+ if (!tp->nlcb)
+ continue;
switch (uc->cmd) {
@@ -1108,7 +990,7 @@ static void sym_exec_user_command (struct sym_hcb *np, struct sym_usrcmd *uc)
}
}
-static int skip_spaces(char *ptr, int len)
+static int sym_skip_spaces(char *ptr, int len)
{
int cnt, c;
@@ -1136,7 +1018,7 @@ static int is_keyword(char *ptr, int len, char *verb)
}
#define SKIP_SPACES(ptr, len) \
- if ((arg_len = skip_spaces(ptr, len)) < 1) \
+ if ((arg_len = sym_skip_spaces(ptr, len)) < 1) \
return -EINVAL; \
ptr += arg_len; len -= arg_len;
@@ -1150,8 +1032,9 @@ static int is_keyword(char *ptr, int len, char *verb)
* Parse a control command
*/
-static int sym_user_command(struct sym_hcb *np, char *buffer, int length)
+static int sym_user_command(struct Scsi_Host *shost, char *buffer, int length)
{
+ struct sym_hcb *np = sym_get_hcb(shost);
char *ptr = buffer;
int len = length;
struct sym_usrcmd cmd, *uc = &cmd;
@@ -1278,9 +1161,9 @@ printk("sym_user_command: data=%ld\n", uc->data);
else {
unsigned long flags;
- spin_lock_irqsave(np->s.host->host_lock, flags);
- sym_exec_user_command (np, uc);
- spin_unlock_irqrestore(np->s.host->host_lock, flags);
+ spin_lock_irqsave(shost->host_lock, flags);
+ sym_exec_user_command(np, uc);
+ spin_unlock_irqrestore(shost->host_lock, flags);
}
return length;
}
@@ -1288,122 +1171,62 @@ printk("sym_user_command: data=%ld\n", uc->data);
#endif /* SYM_LINUX_USER_COMMAND_SUPPORT */
-#ifdef SYM_LINUX_USER_INFO_SUPPORT
/*
- * Informations through the proc file system.
+ * Copy formatted information into the input buffer.
*/
-struct info_str {
- char *buffer;
- int length;
- int offset;
- int pos;
-};
-
-static void copy_mem_info(struct info_str *info, char *data, int len)
+static int sym_show_info(struct seq_file *m, struct Scsi_Host *shost)
{
- if (info->pos + len > info->length)
- len = info->length - info->pos;
-
- if (info->pos + len < info->offset) {
- info->pos += len;
- return;
- }
- if (info->pos < info->offset) {
- data += (info->offset - info->pos);
- len -= (info->offset - info->pos);
- }
+#ifdef SYM_LINUX_USER_INFO_SUPPORT
+ struct sym_data *sym_data = shost_priv(shost);
+ struct pci_dev *pdev = sym_data->pdev;
+ struct sym_hcb *np = sym_data->ncb;
+
+ seq_printf(m, "Chip " NAME53C "%s, device id 0x%x, "
+ "revision id 0x%x\n", np->s.chip_name,
+ pdev->device, pdev->revision);
+ seq_printf(m, "At PCI address %s, IRQ %u\n",
+ pci_name(pdev), pdev->irq);
+ seq_printf(m, "Min. period factor %d, %s SCSI BUS%s\n",
+ (int) (np->minsync_dt ? np->minsync_dt : np->minsync),
+ np->maxwide ? "Wide" : "Narrow",
+ np->minsync_dt ? ", DT capable" : "");
+
+ seq_printf(m, "Max. started commands %d, "
+ "max. commands per LUN %d\n",
+ SYM_CONF_MAX_START, SYM_CONF_MAX_TAG);
- if (len > 0) {
- memcpy(info->buffer + info->pos, data, len);
- info->pos += len;
- }
+ return 0;
+#else
+ return -EINVAL;
+#endif /* SYM_LINUX_USER_INFO_SUPPORT */
}
-static int copy_info(struct info_str *info, char *fmt, ...)
-{
- va_list args;
- char buf[81];
- int len;
-
- va_start(args, fmt);
- len = vsprintf(buf, fmt, args);
- va_end(args);
-
- copy_mem_info(info, buf, len);
- return len;
-}
+#endif /* SYM_LINUX_PROC_INFO_SUPPORT */
/*
- * Copy formatted information into the input buffer.
+ * Free resources claimed by sym_iomap_device(). Note that
+ * sym_free_resources() should be used instead of this function after calling
+ * sym_attach().
*/
-static int sym_host_info(struct sym_hcb *np, char *ptr, off_t offset, int len)
+static void sym_iounmap_device(struct sym_device *device)
{
- struct info_str info;
-
- info.buffer = ptr;
- info.length = len;
- info.offset = offset;
- info.pos = 0;
-
- copy_info(&info, "Chip " NAME53C "%s, device id 0x%x, "
- "revision id 0x%x\n",
- np->s.chip_name, np->device_id, np->revision_id);
- copy_info(&info, "At PCI address %s, IRQ " IRQ_FMT "\n",
- pci_name(np->s.device), IRQ_PRM(np->s.irq));
- copy_info(&info, "Min. period factor %d, %s SCSI BUS%s\n",
- (int) (np->minsync_dt ? np->minsync_dt : np->minsync),
- np->maxwide ? "Wide" : "Narrow",
- np->minsync_dt ? ", DT capable" : "");
-
- copy_info(&info, "Max. started commands %d, "
- "max. commands per LUN %d\n",
- SYM_CONF_MAX_START, SYM_CONF_MAX_TAG);
-
- return info.pos > info.offset? info.pos - info.offset : 0;
+ if (device->s.ioaddr)
+ pci_iounmap(device->pdev, device->s.ioaddr);
+ if (device->s.ramaddr)
+ pci_iounmap(device->pdev, device->s.ramaddr);
}
-#endif /* SYM_LINUX_USER_INFO_SUPPORT */
-
-/*
- * Entry point of the scsi proc fs of the driver.
- * - func = 0 means read (returns adapter infos)
- * - func = 1 means write (not yet merget from sym53c8xx)
- */
-static int sym53c8xx_proc_info(struct Scsi_Host *host, char *buffer,
- char **start, off_t offset, int length, int func)
-{
- struct sym_hcb *np = sym_get_hcb(host);
- int retv;
-
- if (func) {
-#ifdef SYM_LINUX_USER_COMMAND_SUPPORT
- retv = sym_user_command(np, buffer, length);
-#else
- retv = -EINVAL;
-#endif
- } else {
- if (start)
- *start = buffer;
-#ifdef SYM_LINUX_USER_INFO_SUPPORT
- retv = sym_host_info(np, buffer, offset, length);
-#else
- retv = -EINVAL;
-#endif
- }
-
- return retv;
-}
-#endif /* SYM_LINUX_PROC_INFO_SUPPORT */
/*
* Free controller resources.
*/
-static void sym_free_resources(struct sym_hcb *np, struct pci_dev *pdev)
+static void sym_free_resources(struct sym_hcb *np, struct pci_dev *pdev,
+ int do_free_irq)
{
/*
* Free O/S specific resources.
*/
- if (np->s.irq)
- free_irq(np->s.irq, np);
+ if (do_free_irq)
+ free_irq(pdev->irq, np->s.host);
if (np->s.ioaddr)
pci_iounmap(pdev, np->s.ioaddr);
if (np->s.ramaddr)
@@ -1417,31 +1240,6 @@ static void sym_free_resources(struct sym_hcb *np, struct pci_dev *pdev)
}
/*
- * Ask/tell the system about DMA addressing.
- */
-static int sym_setup_bus_dma_mask(struct sym_hcb *np)
-{
-#if SYM_CONF_DMA_ADDRESSING_MODE > 0
-#if SYM_CONF_DMA_ADDRESSING_MODE == 1
-#define DMA_DAC_MASK DMA_40BIT_MASK
-#elif SYM_CONF_DMA_ADDRESSING_MODE == 2
-#define DMA_DAC_MASK DMA_64BIT_MASK
-#endif
- if ((np->features & FE_DAC) &&
- !pci_set_dma_mask(np->s.device, DMA_DAC_MASK)) {
- np->use_dac = 1;
- return 0;
- }
-#endif
-
- if (!pci_set_dma_mask(np->s.device, DMA_32BIT_MASK))
- return 0;
-
- printf_warning("%s: No suitable DMA available\n", sym_name(np));
- return -1;
-}
-
-/*
* Host attach and initialisations.
*
* Allocate host data and ncb structure.
@@ -1450,20 +1248,20 @@ static int sym_setup_bus_dma_mask(struct sym_hcb *np)
* If all is OK, install interrupt handling and
* start the timer daemon.
*/
-static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
- int unit, struct sym_device *dev)
+static struct Scsi_Host *sym_attach(struct scsi_host_template *tpnt, int unit,
+ struct sym_device *dev)
{
- struct host_data *host_data;
+ struct sym_data *sym_data;
struct sym_hcb *np = NULL;
- struct Scsi_Host *instance = NULL;
+ struct Scsi_Host *shost = NULL;
struct pci_dev *pdev = dev->pdev;
unsigned long flags;
struct sym_fw *fw;
+ int do_free_irq = 0;
- printk(KERN_INFO
- "sym%d: <%s> rev 0x%x at pci %s irq " IRQ_FMT "\n",
- unit, dev->chip.name, dev->chip.revision_id,
- pci_name(pdev), IRQ_PRM(pdev->irq));
+ printk(KERN_INFO "sym%d: <%s> rev 0x%x at pci %s irq %u\n",
+ unit, dev->chip.name, pdev->revision, pci_name(pdev),
+ pdev->irq);
/*
* Get the firmware for this chip.
@@ -1472,13 +1270,10 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
if (!fw)
goto attach_failed;
- /*
- * Allocate host_data structure
- */
- instance = scsi_host_alloc(tpnt, sizeof(*host_data));
- if (!instance)
+ shost = scsi_host_alloc(tpnt, sizeof(*sym_data));
+ if (!shost)
goto attach_failed;
- host_data = (struct host_data *) instance->hostdata;
+ sym_data = shost_priv(shost);
/*
* Allocate immediately the host control block,
@@ -1489,27 +1284,28 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
np = __sym_calloc_dma(&pdev->dev, sizeof(*np), "HCB");
if (!np)
goto attach_failed;
- np->s.device = pdev;
np->bus_dmat = &pdev->dev; /* Result in 1 DMA pool per HBA */
- host_data->ncb = np;
- np->s.host = instance;
+ sym_data->ncb = np;
+ sym_data->pdev = pdev;
+ np->s.host = shost;
- pci_set_drvdata(pdev, np);
+ pci_set_drvdata(pdev, shost);
/*
* Copy some useful infos to the HCB.
*/
np->hcb_ba = vtobus(np);
np->verbose = sym_driver_setup.verbose;
- np->s.device = pdev;
np->s.unit = unit;
- np->device_id = dev->chip.device_id;
- np->revision_id = dev->chip.revision_id;
np->features = dev->chip.features;
np->clock_divn = dev->chip.nr_divisor;
np->maxoffs = dev->chip.offset_max;
np->maxburst = dev->chip.burst_max;
np->myaddr = dev->host_id;
+ np->mmio_ba = (u32)dev->mmio_base;
+ np->ram_ba = (u32)dev->ram_base;
+ np->s.ioaddr = dev->s.ioaddr;
+ np->s.ramaddr = dev->s.ramaddr;
/*
* Edit its name.
@@ -1517,29 +1313,15 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
strlcpy(np->s.chip_name, dev->chip.name, sizeof(np->s.chip_name));
sprintf(np->s.inst_name, "sym%d", np->s.unit);
- if (sym_setup_bus_dma_mask(np))
+ if ((SYM_CONF_DMA_ADDRESSING_MODE > 0) && (np->features & FE_DAC) &&
+ !pci_set_dma_mask(pdev, DMA_DAC_MASK)) {
+ set_dac(np);
+ } else if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ printf_warning("%s: No suitable DMA available\n", sym_name(np));
goto attach_failed;
-
- /*
- * Try to map the controller chip to
- * virtual and physical memory.
- */
- np->mmio_ba = (u32)dev->mmio_base;
- np->s.ioaddr = dev->s.ioaddr;
- np->s.ramaddr = dev->s.ramaddr;
- np->s.io_ws = (np->features & FE_IO256) ? 256 : 128;
-
- /*
- * Map on-chip RAM if present and supported.
- */
- if (!(np->features & FE_RAM))
- dev->ram_base = 0;
- if (dev->ram_base) {
- np->ram_ba = (u32)dev->ram_base;
- np->ram_ws = (np->features & FE_RAM8K) ? 8192 : 4096;
}
- if (sym_hcb_attach(instance, fw, dev->nvram))
+ if (sym_hcb_attach(shost, fw, dev->nvram))
goto attach_failed;
/*
@@ -1547,25 +1329,26 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
* If we synchonize the C code with SCRIPTS on interrupt,
* we do not want to share the INTR line at all.
*/
- if (request_irq(pdev->irq, sym53c8xx_intr, IRQF_SHARED, NAME53C8XX, np)) {
- printf_err("%s: request irq %d failure\n",
+ if (request_irq(pdev->irq, sym53c8xx_intr, IRQF_SHARED, NAME53C8XX,
+ shost)) {
+ printf_err("%s: request irq %u failure\n",
sym_name(np), pdev->irq);
goto attach_failed;
}
- np->s.irq = pdev->irq;
+ do_free_irq = 1;
/*
* After SCSI devices have been opened, we cannot
* reset the bus safely, so we do it here.
*/
- spin_lock_irqsave(instance->host_lock, flags);
+ spin_lock_irqsave(shost->host_lock, flags);
if (sym_reset_scsi_bus(np, 0))
goto reset_failed;
/*
* Start the SCRIPTS.
*/
- sym_start_up (np, 1);
+ sym_start_up(shost, 1);
/*
* Start the timer daemon
@@ -1580,33 +1363,38 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
* Fill Linux host instance structure
* and return success.
*/
- instance->max_channel = 0;
- instance->this_id = np->myaddr;
- instance->max_id = np->maxwide ? 16 : 8;
- instance->max_lun = SYM_CONF_MAX_LUN;
- instance->unique_id = pci_resource_start(pdev, 0);
- instance->cmd_per_lun = SYM_CONF_MAX_TAG;
- instance->can_queue = (SYM_CONF_MAX_START-2);
- instance->sg_tablesize = SYM_CONF_MAX_SG;
- instance->max_cmd_len = 16;
+ shost->max_channel = 0;
+ shost->this_id = np->myaddr;
+ shost->max_id = np->maxwide ? 16 : 8;
+ shost->max_lun = SYM_CONF_MAX_LUN;
+ shost->unique_id = pci_resource_start(pdev, 0);
+ shost->cmd_per_lun = SYM_CONF_MAX_TAG;
+ shost->can_queue = (SYM_CONF_MAX_START-2);
+ shost->sg_tablesize = SYM_CONF_MAX_SG;
+ shost->max_cmd_len = 16;
BUG_ON(sym2_transport_template == NULL);
- instance->transportt = sym2_transport_template;
+ shost->transportt = sym2_transport_template;
- spin_unlock_irqrestore(instance->host_lock, flags);
+ /* 53c896 rev 1 errata: DMA may not cross 16MB boundary */
+ if (pdev->device == PCI_DEVICE_ID_NCR_53C896 && pdev->revision < 2)
+ shost->dma_boundary = 0xFFFFFF;
- return instance;
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ return shost;
reset_failed:
printf_err("%s: FATAL ERROR: CHECK SCSI BUS - CABLES, "
"TERMINATION, DEVICE POWER etc.!\n", sym_name(np));
- spin_unlock_irqrestore(instance->host_lock, flags);
+ spin_unlock_irqrestore(shost->host_lock, flags);
attach_failed:
- if (!instance)
- return NULL;
- printf_info("%s: giving up ...\n", sym_name(np));
+ printf_info("sym%d: giving up ...\n", unit);
if (np)
- sym_free_resources(np, pdev);
- scsi_host_put(instance);
+ sym_free_resources(np, pdev, do_free_irq);
+ else
+ sym_iounmap_device(dev);
+ if (shost)
+ scsi_host_put(shost);
return NULL;
}
@@ -1616,10 +1404,9 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
* Detect and try to read SYMBIOS and TEKRAM NVRAM.
*/
#if SYM_CONF_NVRAM_SUPPORT
-static void __devinit sym_get_nvram(struct sym_device *devp, struct sym_nvram *nvp)
+static void sym_get_nvram(struct sym_device *devp, struct sym_nvram *nvp)
{
devp->nvram = nvp;
- devp->device_id = devp->chip.device_id;
nvp->type = 0;
sym_read_nvram(devp, nvp);
@@ -1630,11 +1417,10 @@ static inline void sym_get_nvram(struct sym_device *devp, struct sym_nvram *nvp)
}
#endif /* SYM_CONF_NVRAM_SUPPORT */
-static int __devinit sym_check_supported(struct sym_device *device)
+static int sym_check_supported(struct sym_device *device)
{
struct sym_chip *chip;
struct pci_dev *pdev = device->pdev;
- u_char revision;
unsigned long io_port = pci_resource_start(pdev, 0);
int i;
@@ -1654,14 +1440,12 @@ static int __devinit sym_check_supported(struct sym_device *device)
* to our device structure so we can make it match the actual device
* and options.
*/
- pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
- chip = sym_lookup_chip_table(pdev->device, revision);
+ chip = sym_lookup_chip_table(pdev->device, pdev->revision);
if (!chip) {
dev_info(&pdev->dev, "device not supported\n");
return -ENODEV;
}
memcpy(&device->chip, chip, sizeof(device->chip));
- device->chip.revision_id = revision;
return 0;
}
@@ -1670,7 +1454,7 @@ static int __devinit sym_check_supported(struct sym_device *device)
* Ignore Symbios chips controlled by various RAID controllers.
* These controllers set value 0x52414944 at RAM end - 16.
*/
-static int __devinit sym_check_raid(struct sym_device *device)
+static int sym_check_raid(struct sym_device *device)
{
unsigned int ram_size, ram_val;
@@ -1691,7 +1475,7 @@ static int __devinit sym_check_raid(struct sym_device *device)
return -ENODEV;
}
-static int __devinit sym_set_workarounds(struct sym_device *device)
+static int sym_set_workarounds(struct sym_device *device)
{
struct sym_chip *chip = &device->chip;
struct pci_dev *pdev = device->pdev;
@@ -1702,7 +1486,7 @@ static int __devinit sym_set_workarounds(struct sym_device *device)
* We must ensure the chip will use WRITE AND INVALIDATE.
* The revision number limit is for now arbitrary.
*/
- if (pdev->device == PCI_DEVICE_ID_NCR_53C896 && chip->revision_id < 0x4) {
+ if (pdev->device == PCI_DEVICE_ID_NCR_53C896 && pdev->revision < 0x4) {
chip->features |= (FE_WRIE | FE_CLSE);
}
@@ -1739,30 +1523,28 @@ static int __devinit sym_set_workarounds(struct sym_device *device)
}
/*
- * Read and check the PCI configuration for any detected NCR
- * boards and save data for attaching after all boards have
- * been detected.
+ * Map HBA registers and on-chip SRAM (if present).
*/
-static void __devinit
-sym_init_device(struct pci_dev *pdev, struct sym_device *device)
+static int sym_iomap_device(struct sym_device *device)
{
- int i = 2;
+ struct pci_dev *pdev = device->pdev;
struct pci_bus_region bus_addr;
+ int i = 2;
- device->host_id = SYM_SETUP_HOST_ID;
- device->pdev = pdev;
-
- pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[1]);
+ pcibios_resource_to_bus(pdev->bus, &bus_addr, &pdev->resource[1]);
device->mmio_base = bus_addr.start;
- /*
- * If the BAR is 64-bit, resource 2 will be occupied by the
- * upper 32 bits
- */
- if (!pdev->resource[i].flags)
- i++;
- pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[i]);
- device->ram_base = bus_addr.start;
+ if (device->chip.features & FE_RAM) {
+ /*
+ * If the BAR is 64-bit, resource 2 will be occupied by the
+ * upper 32 bits
+ */
+ if (!pdev->resource[i].flags)
+ i++;
+ pcibios_resource_to_bus(pdev->bus, &bus_addr,
+ &pdev->resource[i]);
+ device->ram_base = bus_addr.start;
+ }
#ifdef CONFIG_SCSI_SYM53C8XX_MMIO
if (device->mmio_base)
@@ -1772,9 +1554,21 @@ sym_init_device(struct pci_dev *pdev, struct sym_device *device)
if (!device->s.ioaddr)
device->s.ioaddr = pci_iomap(pdev, 0,
pci_resource_len(pdev, 0));
- if (device->ram_base)
+ if (!device->s.ioaddr) {
+ dev_err(&pdev->dev, "could not map registers; giving up.\n");
+ return -EIO;
+ }
+ if (device->ram_base) {
device->s.ramaddr = pci_iomap(pdev, i,
pci_resource_len(pdev, i));
+ if (!device->s.ramaddr) {
+ dev_warn(&pdev->dev,
+ "could not map SRAM; continuing anyway.\n");
+ device->ram_base = 0;
+ }
+ }
+
+ return 0;
}
/*
@@ -1830,8 +1624,9 @@ static void sym_config_pqs(struct pci_dev *pdev, struct sym_device *sym_dev)
* Detach the host.
* We have to free resources and halt the NCR chip.
*/
-static int sym_detach(struct sym_hcb *np, struct pci_dev *pdev)
+static int sym_detach(struct Scsi_Host *shost, struct pci_dev *pdev)
{
+ struct sym_hcb *np = sym_get_hcb(shost);
printk("%s: detaching ...\n", sym_name(np));
del_timer_sync(&np->s.timer);
@@ -1847,7 +1642,8 @@ static int sym_detach(struct sym_hcb *np, struct pci_dev *pdev)
udelay(10);
OUTB(np, nc_istat, 0);
- sym_free_resources(np, pdev);
+ sym_free_resources(np, pdev, 1);
+ scsi_host_put(shost);
return 1;
}
@@ -1871,22 +1667,28 @@ static struct scsi_host_template sym2_template = {
.use_clustering = ENABLE_CLUSTERING,
.max_sectors = 0xFFFF,
#ifdef SYM_LINUX_PROC_INFO_SUPPORT
- .proc_info = sym53c8xx_proc_info,
+ .show_info = sym_show_info,
+#ifdef SYM_LINUX_USER_COMMAND_SUPPORT
+ .write_info = sym_user_command,
+#endif
.proc_name = NAME53C8XX,
#endif
};
static int attach_count;
-static int __devinit sym2_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int sym2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct sym_device sym_dev;
struct sym_nvram nvram;
- struct Scsi_Host *instance;
+ struct Scsi_Host *shost;
+ int do_iounmap = 0;
+ int do_disable_device = 1;
memset(&sym_dev, 0, sizeof(sym_dev));
memset(&nvram, 0, sizeof(nvram));
+ sym_dev.pdev = pdev;
+ sym_dev.host_id = SYM_SETUP_HOST_ID;
if (pci_enable_device(pdev))
goto leave;
@@ -1896,12 +1698,17 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
if (pci_request_regions(pdev, NAME53C8XX))
goto disable;
- sym_init_device(pdev, &sym_dev);
if (sym_check_supported(&sym_dev))
goto free;
- if (sym_check_raid(&sym_dev))
- goto leave; /* Don't disable the device */
+ if (sym_iomap_device(&sym_dev))
+ goto free;
+ do_iounmap = 1;
+
+ if (sym_check_raid(&sym_dev)) {
+ do_disable_device = 0; /* Don't disable the device */
+ goto free;
+ }
if (sym_set_workarounds(&sym_dev))
goto free;
@@ -1910,13 +1717,14 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
sym_get_nvram(&sym_dev, &nvram);
- instance = sym_attach(&sym2_template, attach_count, &sym_dev);
- if (!instance)
+ do_iounmap = 0; /* Don't sym_iounmap_device() after sym_attach(). */
+ shost = sym_attach(&sym2_template, attach_count, &sym_dev);
+ if (!shost)
goto free;
- if (scsi_add_host(instance, &pdev->dev))
+ if (scsi_add_host(shost, &pdev->dev))
goto detach;
- scsi_scan_host(instance);
+ scsi_scan_host(shost);
attach_count++;
@@ -1925,29 +1733,153 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
detach:
sym_detach(pci_get_drvdata(pdev), pdev);
free:
+ if (do_iounmap)
+ sym_iounmap_device(&sym_dev);
pci_release_regions(pdev);
disable:
- pci_disable_device(pdev);
+ if (do_disable_device)
+ pci_disable_device(pdev);
leave:
return -ENODEV;
}
-static void __devexit sym2_remove(struct pci_dev *pdev)
+static void sym2_remove(struct pci_dev *pdev)
{
- struct sym_hcb *np = pci_get_drvdata(pdev);
- struct Scsi_Host *host = np->s.host;
-
- scsi_remove_host(host);
- scsi_host_put(host);
-
- sym_detach(np, pdev);
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ scsi_remove_host(shost);
+ sym_detach(shost, pdev);
pci_release_regions(pdev);
pci_disable_device(pdev);
attach_count--;
}
+/**
+ * sym2_io_error_detected() - called when PCI error is detected
+ * @pdev: pointer to PCI device
+ * @state: current state of the PCI slot
+ */
+static pci_ers_result_t sym2_io_error_detected(struct pci_dev *pdev,
+ enum pci_channel_state state)
+{
+ /* If slot is permanently frozen, turn everything off */
+ if (state == pci_channel_io_perm_failure) {
+ sym2_remove(pdev);
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ disable_irq(pdev->irq);
+ pci_disable_device(pdev);
+
+ /* Request that MMIO be enabled, so register dump can be taken. */
+ return PCI_ERS_RESULT_CAN_RECOVER;
+}
+
+/**
+ * sym2_io_slot_dump - Enable MMIO and dump debug registers
+ * @pdev: pointer to PCI device
+ */
+static pci_ers_result_t sym2_io_slot_dump(struct pci_dev *pdev)
+{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+
+ sym_dump_registers(shost);
+
+ /* Request a slot reset. */
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * sym2_reset_workarounds - hardware-specific work-arounds
+ *
+ * This routine is similar to sym_set_workarounds(), except
+ * that, at this point, we already know that the device was
+ * successfully initialized at least once before, and so most
+ * of the steps taken there are un-needed here.
+ */
+static void sym2_reset_workarounds(struct pci_dev *pdev)
+{
+ u_short status_reg;
+ struct sym_chip *chip;
+
+ chip = sym_lookup_chip_table(pdev->device, pdev->revision);
+
+ /* Work around for errant bit in 895A, in a fashion
+ * similar to what is done in sym_set_workarounds().
+ */
+ pci_read_config_word(pdev, PCI_STATUS, &status_reg);
+ if (!(chip->features & FE_66MHZ) && (status_reg & PCI_STATUS_66MHZ)) {
+ status_reg = PCI_STATUS_66MHZ;
+ pci_write_config_word(pdev, PCI_STATUS, status_reg);
+ pci_read_config_word(pdev, PCI_STATUS, &status_reg);
+ }
+}
+
+/**
+ * sym2_io_slot_reset() - called when the pci bus has been reset.
+ * @pdev: pointer to PCI device
+ *
+ * Restart the card from scratch.
+ */
+static pci_ers_result_t sym2_io_slot_reset(struct pci_dev *pdev)
+{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct sym_hcb *np = sym_get_hcb(shost);
+
+ printk(KERN_INFO "%s: recovering from a PCI slot reset\n",
+ sym_name(np));
+
+ if (pci_enable_device(pdev)) {
+ printk(KERN_ERR "%s: Unable to enable after PCI reset\n",
+ sym_name(np));
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ pci_set_master(pdev);
+ enable_irq(pdev->irq);
+
+ /* If the chip can do Memory Write Invalidate, enable it */
+ if (np->features & FE_WRIE) {
+ if (pci_set_mwi(pdev))
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ /* Perform work-arounds, analogous to sym_set_workarounds() */
+ sym2_reset_workarounds(pdev);
+
+ /* Perform host reset only on one instance of the card */
+ if (PCI_FUNC(pdev->devfn) == 0) {
+ if (sym_reset_scsi_bus(np, 0)) {
+ printk(KERN_ERR "%s: Unable to reset scsi host\n",
+ sym_name(np));
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ sym_start_up(shost, 1);
+ }
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * sym2_io_resume() - resume normal ops after PCI reset
+ * @pdev: pointer to PCI device
+ *
+ * Called when the error recovery driver tells us that its
+ * OK to resume normal operation. Use completion to allow
+ * halted scsi ops to resume.
+ */
+static void sym2_io_resume(struct pci_dev *pdev)
+{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct sym_data *sym_data = shost_priv(shost);
+
+ spin_lock_irq(shost->host_lock);
+ if (sym_data->io_reset)
+ complete_all(sym_data->io_reset);
+ spin_unlock_irq(shost->host_lock);
+}
+
static void sym2_get_signalling(struct Scsi_Host *shost)
{
struct sym_hcb *np = sym_get_hcb(shost);
@@ -2070,7 +2002,7 @@ static struct spi_function_template sym2_transport_functions = {
.get_signalling = sym2_get_signalling,
};
-static struct pci_device_id sym2_id_table[] __devinitdata = {
+static struct pci_device_id sym2_id_table[] = {
{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C810,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C820,
@@ -2094,7 +2026,7 @@ static struct pci_device_id sym2_id_table[] __devinitdata = {
{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C875,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C1510,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, /* new */
+ PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_SCSI<<8, 0xffff00, 0UL }, /* new */
{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C895A,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C875A,
@@ -2110,11 +2042,19 @@ static struct pci_device_id sym2_id_table[] __devinitdata = {
MODULE_DEVICE_TABLE(pci, sym2_id_table);
+static const struct pci_error_handlers sym2_err_handler = {
+ .error_detected = sym2_io_error_detected,
+ .mmio_enabled = sym2_io_slot_dump,
+ .slot_reset = sym2_io_slot_reset,
+ .resume = sym2_io_resume,
+};
+
static struct pci_driver sym2_driver = {
.name = NAME53C8XX,
.id_table = sym2_id_table,
.probe = sym2_probe,
- .remove = __devexit_p(sym2_remove),
+ .remove = sym2_remove,
+ .err_handler = &sym2_err_handler,
};
static int __init sym2_init(void)
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.h b/drivers/scsi/sym53c8xx_2/sym_glue.h
index e022d3c71b5..805369521df 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.h
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.h
@@ -40,7 +40,9 @@
#ifndef SYM_GLUE_H
#define SYM_GLUE_H
+#include <linux/completion.h>
#include <linux/delay.h>
+#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/string.h>
@@ -172,19 +174,16 @@ struct sym_slcb {
*/
struct sym_shcb {
/*
- * Chip and controller indentification.
+ * Chip and controller identification.
*/
int unit;
char inst_name[16];
char chip_name[8];
- struct pci_dev *device;
struct Scsi_Host *host;
void __iomem * ioaddr; /* MMIO kernel io address */
void __iomem * ramaddr; /* RAM kernel io address */
- u_short io_ws; /* IO window size */
- int irq; /* IRQ number */
struct timer_list timer; /* Timer handler link header */
u_long lasttime;
@@ -212,20 +211,21 @@ struct sym_device {
} s;
struct sym_chip chip;
struct sym_nvram *nvram;
- u_short device_id;
u_char host_id;
};
/*
* Driver host data structure.
*/
-struct host_data {
+struct sym_data {
struct sym_hcb *ncb;
+ struct completion *io_reset; /* PCI error handling */
+ struct pci_dev *pdev;
};
static inline struct sym_hcb * sym_get_hcb(struct Scsi_Host *host)
{
- return ((struct host_data *)host->hostdata)->ncb;
+ return ((struct sym_data *)host->hostdata)->ncb;
}
#include "sym_fw.h"
@@ -234,7 +234,7 @@ static inline struct sym_hcb * sym_get_hcb(struct Scsi_Host *host)
/*
* Set the status field of a CAM CCB.
*/
-static __inline void
+static inline void
sym_set_cam_status(struct scsi_cmnd *cmd, int status)
{
cmd->result &= ~(0xff << 16);
@@ -244,7 +244,7 @@ sym_set_cam_status(struct scsi_cmnd *cmd, int status)
/*
* Get the status field of a CAM CCB.
*/
-static __inline int
+static inline int
sym_get_cam_status(struct scsi_cmnd *cmd)
{
return host_byte(cmd->result);
@@ -253,9 +253,9 @@ sym_get_cam_status(struct scsi_cmnd *cmd)
/*
* Build CAM result for a successful IO and for a failed IO.
*/
-static __inline void sym_set_cam_result_ok(struct sym_ccb *cp, struct scsi_cmnd *cmd, int resid)
+static inline void sym_set_cam_result_ok(struct sym_ccb *cp, struct scsi_cmnd *cmd, int resid)
{
- cmd->resid = resid;
+ scsi_set_resid(cmd, resid);
cmd->result = (((DID_OK) << 16) + ((cp->ssss_status) & 0x7f));
}
void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid);
@@ -263,8 +263,8 @@ void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid)
void sym_xpt_done(struct sym_hcb *np, struct scsi_cmnd *ccb);
#define sym_print_addr(cmd, arg...) dev_info(&cmd->device->sdev_gendev , ## arg)
void sym_xpt_async_bus_reset(struct sym_hcb *np);
-void sym_xpt_async_sent_bdr(struct sym_hcb *np, int target);
int sym_setup_data_and_start (struct sym_hcb *np, struct scsi_cmnd *csio, struct sym_ccb *cp);
-void sym_log_bus_error(struct sym_hcb *np);
+void sym_log_bus_error(struct Scsi_Host *);
+void sym_dump_registers(struct Scsi_Host *);
#endif /* SYM_GLUE_H */
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c
index 940fa1e6f99..6b349e30186 100644
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.c
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c
@@ -52,7 +52,7 @@
* Needed function prototypes.
*/
static void sym_int_ma (struct sym_hcb *np);
-static void sym_int_sir (struct sym_hcb *np);
+static void sym_int_sir(struct sym_hcb *);
static struct sym_ccb *sym_alloc_ccb(struct sym_hcb *np);
static struct sym_ccb *sym_ccb_from_dsa(struct sym_hcb *np, u32 dsa);
static void sym_alloc_lcb_tags (struct sym_hcb *np, u_char tn, u_char ln);
@@ -72,10 +72,7 @@ static void sym_printl_hex(u_char *p, int n)
static void sym_print_msg(struct sym_ccb *cp, char *label, u_char *msg)
{
- if (label)
- sym_print_addr(cp->cmd, "%s: ", label);
- else
- sym_print_addr(cp->cmd, "");
+ sym_print_addr(cp->cmd, "%s: ", label);
spi_print_msg(msg);
printf("\n");
@@ -602,7 +599,7 @@ sym_getsync(struct sym_hcb *np, u_char dt, u_char sfac, u_char *divp, u_char *fa
/*
* Set initial io register bits from burst code.
*/
-static __inline void sym_init_burst(struct sym_hcb *np, u_char bc)
+static inline void sym_init_burst(struct sym_hcb *np, u_char bc)
{
np->rv_ctest4 &= ~0x80;
np->rv_dmode &= ~(0x3 << 6);
@@ -684,6 +681,8 @@ static void sym_set_bus_mode(struct sym_hcb *np, struct sym_nvram *nvram)
*/
static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram)
{
+ struct sym_data *sym_data = shost_priv(shost);
+ struct pci_dev *pdev = sym_data->pdev;
u_char burst_max;
u32 period;
int i;
@@ -778,19 +777,12 @@ static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, stru
* 64 bit addressing (895A/896/1010) ?
*/
if (np->features & FE_DAC) {
-#if SYM_CONF_DMA_ADDRESSING_MODE == 0
- np->rv_ccntl1 |= (DDAC);
-#elif SYM_CONF_DMA_ADDRESSING_MODE == 1
- if (!np->use_dac)
- np->rv_ccntl1 |= (DDAC);
- else
- np->rv_ccntl1 |= (XTIMOD | EXTIBMV);
-#elif SYM_CONF_DMA_ADDRESSING_MODE == 2
- if (!np->use_dac)
- np->rv_ccntl1 |= (DDAC);
- else
- np->rv_ccntl1 |= (0 | EXTIBMV);
-#endif
+ if (!use_dac(np))
+ np->rv_ccntl1 |= (DDAC);
+ else if (SYM_CONF_DMA_ADDRESSING_MODE == 1)
+ np->rv_ccntl1 |= (XTIMOD | EXTIBMV);
+ else if (SYM_CONF_DMA_ADDRESSING_MODE == 2)
+ np->rv_ccntl1 |= (0 | EXTIBMV);
}
/*
@@ -804,8 +796,8 @@ static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, stru
* In dual channel mode, contention occurs if internal cycles
* are used. Disable internal cycles.
*/
- if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_33 &&
- np->revision_id < 0x1)
+ if (pdev->device == PCI_DEVICE_ID_LSI_53C1010_33 &&
+ pdev->revision < 0x1)
np->rv_ccntl0 |= DILS;
/*
@@ -828,10 +820,10 @@ static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, stru
* this driver. The generic ncr driver that does not use
* LOAD/STORE instructions does not need this work-around.
*/
- if ((np->device_id == PCI_DEVICE_ID_NCR_53C810 &&
- np->revision_id >= 0x10 && np->revision_id <= 0x11) ||
- (np->device_id == PCI_DEVICE_ID_NCR_53C860 &&
- np->revision_id <= 0x1))
+ if ((pdev->device == PCI_DEVICE_ID_NCR_53C810 &&
+ pdev->revision >= 0x10 && pdev->revision <= 0x11) ||
+ (pdev->device == PCI_DEVICE_ID_NCR_53C860 &&
+ pdev->revision <= 0x1))
np->features &= ~(FE_WRIE|FE_ERL|FE_ERMP);
/*
@@ -897,7 +889,7 @@ static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, stru
if ((SYM_SETUP_SCSI_LED ||
(nvram->type == SYM_SYMBIOS_NVRAM ||
(nvram->type == SYM_TEKRAM_NVRAM &&
- np->device_id == PCI_DEVICE_ID_NCR_53C895))) &&
+ pdev->device == PCI_DEVICE_ID_NCR_53C895))) &&
!(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01))
np->features |= FE_LED0;
@@ -1135,8 +1127,9 @@ restart_test:
* First 24 register of the chip:
* r0..rf
*/
-static void sym_log_hard_error(struct sym_hcb *np, u_short sist, u_char dstat)
+static void sym_log_hard_error(struct Scsi_Host *shost, u_short sist, u_char dstat)
{
+ struct sym_hcb *np = sym_get_hcb(shost);
u32 dsp;
int script_ofs;
int script_size;
@@ -1180,16 +1173,27 @@ static void sym_log_hard_error(struct sym_hcb *np, u_short sist, u_char dstat)
scr_to_cpu((int) *(u32 *)(script_base + script_ofs)));
}
- printf ("%s: regdump:", sym_name(np));
- for (i=0; i<24;i++)
- printf (" %02x", (unsigned)INB_OFF(np, i));
- printf (".\n");
+ printf("%s: regdump:", sym_name(np));
+ for (i = 0; i < 24; i++)
+ printf(" %02x", (unsigned)INB_OFF(np, i));
+ printf(".\n");
/*
* PCI BUS error.
*/
if (dstat & (MDPE|BF))
- sym_log_bus_error(np);
+ sym_log_bus_error(shost);
+}
+
+void sym_dump_registers(struct Scsi_Host *shost)
+{
+ struct sym_hcb *np = sym_get_hcb(shost);
+ u_short sist;
+ u_char dstat;
+
+ sist = INW(np, nc_sist);
+ dstat = INB(np, nc_dstat);
+ sym_log_hard_error(shost, sist, dstat);
}
static struct sym_chip sym_dev_table[] = {
@@ -1312,7 +1316,7 @@ int sym_lookup_dmap(struct sym_hcb *np, u32 h, int s)
{
int i;
- if (!np->use_dac)
+ if (!use_dac(np))
goto weird;
/* Look up existing mappings */
@@ -1426,13 +1430,12 @@ static int sym_prepare_nego(struct sym_hcb *np, struct sym_ccb *cp, u_char *msgp
* Many devices implement PPR in a buggy way, so only use it if we
* really want to.
*/
- if (goal->offset &&
- (goal->iu || goal->dt || goal->qas || (goal->period < 0xa))) {
+ if (goal->renego == NS_PPR || (goal->offset &&
+ (goal->iu || goal->dt || goal->qas || (goal->period < 0xa)))) {
nego = NS_PPR;
- } else if (spi_width(starget) != goal->width) {
+ } else if (goal->renego == NS_WIDE || goal->width) {
nego = NS_WIDE;
- } else if (spi_period(starget) != goal->period ||
- spi_offset(starget) != goal->offset) {
+ } else if (goal->renego == NS_SYNC || goal->offset) {
nego = NS_SYNC;
} else {
goal->check_nego = 0;
@@ -1519,7 +1522,8 @@ void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp)
np->squeueput = qidx;
if (DEBUG_FLAGS & DEBUG_QUEUE)
- printf ("%s: queuepos=%d.\n", sym_name (np), np->squeueput);
+ scmd_printk(KERN_DEBUG, cp->cmd, "queuepos=%d\n",
+ np->squeueput);
/*
* Script processor may be waiting for reselect.
@@ -1639,7 +1643,7 @@ static void sym_flush_comp_queue(struct sym_hcb *np, int cam_status)
SYM_QUEHEAD *qp;
struct sym_ccb *cp;
- while ((qp = sym_remque_head(&np->comp_ccbq)) != 0) {
+ while ((qp = sym_remque_head(&np->comp_ccbq)) != NULL) {
struct scsi_cmnd *cmd;
cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq);
@@ -1696,8 +1700,11 @@ static void sym_flush_busy_queue (struct sym_hcb *np, int cam_status)
* 1: SCSI BUS RESET delivered or received.
* 2: SCSI BUS MODE changed.
*/
-void sym_start_up (struct sym_hcb *np, int reason)
+void sym_start_up(struct Scsi_Host *shost, int reason)
{
+ struct sym_data *sym_data = shost_priv(shost);
+ struct pci_dev *pdev = sym_data->pdev;
+ struct sym_hcb *np = sym_data->ncb;
int i;
u32 phys;
@@ -1746,7 +1753,7 @@ void sym_start_up (struct sym_hcb *np, int reason)
* This also let point to first position the start
* and done queue pointers used from SCRIPTS.
*/
- np->fw_patch(np);
+ np->fw_patch(shost);
/*
* Wakeup all pending jobs.
@@ -1788,7 +1795,7 @@ void sym_start_up (struct sym_hcb *np, int reason)
/*
* For now, disable AIP generation on C1010-66.
*/
- if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)
+ if (pdev->device == PCI_DEVICE_ID_LSI_53C1010_66)
OUTB(np, nc_aipcntl1, DISAIP);
/*
@@ -1798,8 +1805,8 @@ void sym_start_up (struct sym_hcb *np, int reason)
* that from SCRIPTS for each selection/reselection, but
* I just don't want. :)
*/
- if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_33 &&
- np->revision_id < 1)
+ if (pdev->device == PCI_DEVICE_ID_LSI_53C1010_33 &&
+ pdev->revision < 1)
OUTB(np, nc_stest1, INB(np, nc_stest1) | 0x30);
/*
@@ -1807,9 +1814,9 @@ void sym_start_up (struct sym_hcb *np, int reason)
* Disable overlapped arbitration for some dual function devices,
* regardless revision id (kind of post-chip-design feature. ;-))
*/
- if (np->device_id == PCI_DEVICE_ID_NCR_53C875)
+ if (pdev->device == PCI_DEVICE_ID_NCR_53C875)
OUTB(np, nc_ctest0, (1<<5));
- else if (np->device_id == PCI_DEVICE_ID_NCR_53C896)
+ else if (pdev->device == PCI_DEVICE_ID_NCR_53C896)
np->rv_ccntl0 |= DPR;
/*
@@ -1827,7 +1834,7 @@ void sym_start_up (struct sym_hcb *np, int reason)
* Set up scratch C and DRS IO registers to map the 32 bit
* DMA address range our data structures are located in.
*/
- if (np->use_dac) {
+ if (use_dac(np)) {
np->dmap_bah[0] = 0; /* ??? */
OUTL(np, nc_scrx[0], np->dmap_bah[0]);
OUTL(np, nc_drs, np->dmap_bah[0]);
@@ -1886,6 +1893,15 @@ void sym_start_up (struct sym_hcb *np, int reason)
tp->head.sval = 0;
tp->head.wval = np->rv_scntl3;
tp->head.uval = 0;
+ if (tp->lun0p)
+ tp->lun0p->to_clear = 0;
+ if (tp->lunmp) {
+ int ln;
+
+ for (ln = 1; ln < SYM_CONF_MAX_LUN; ln++)
+ if (tp->lunmp[ln])
+ tp->lunmp[ln]->to_clear = 0;
+ }
}
/*
@@ -1900,7 +1916,7 @@ void sym_start_up (struct sym_hcb *np, int reason)
if (sym_verbose >= 2)
printf("%s: Downloading SCSI SCRIPTS.\n", sym_name(np));
memcpy_toio(np->s.ramaddr, np->scripta0, np->scripta_sz);
- if (np->ram_ws == 8192) {
+ if (np->features & FE_RAM8K) {
memcpy_toio(np->s.ramaddr + 4096, np->scriptb0, np->scriptb_sz);
phys = scr_to_cpu(np->scr_ram_seg);
OUTL(np, nc_mmws, phys);
@@ -2029,6 +2045,29 @@ static void sym_settrans(struct sym_hcb *np, int target, u_char opts, u_char ofs
}
}
+static void sym_announce_transfer_rate(struct sym_tcb *tp)
+{
+ struct scsi_target *starget = tp->starget;
+
+ if (tp->tprint.period != spi_period(starget) ||
+ tp->tprint.offset != spi_offset(starget) ||
+ tp->tprint.width != spi_width(starget) ||
+ tp->tprint.iu != spi_iu(starget) ||
+ tp->tprint.dt != spi_dt(starget) ||
+ tp->tprint.qas != spi_qas(starget) ||
+ !tp->tprint.check_nego) {
+ tp->tprint.period = spi_period(starget);
+ tp->tprint.offset = spi_offset(starget);
+ tp->tprint.width = spi_width(starget);
+ tp->tprint.iu = spi_iu(starget);
+ tp->tprint.dt = spi_dt(starget);
+ tp->tprint.qas = spi_qas(starget);
+ tp->tprint.check_nego = 1;
+
+ spi_display_xfer_agreement(starget);
+ }
+}
+
/*
* We received a WDTR.
* Let everything be aware of the changes.
@@ -2038,11 +2077,13 @@ static void sym_setwide(struct sym_hcb *np, int target, u_char wide)
struct sym_tcb *tp = &np->target[target];
struct scsi_target *starget = tp->starget;
- if (spi_width(starget) == wide)
- return;
-
sym_settrans(np, target, 0, 0, 0, wide, 0, 0);
+ if (wide)
+ tp->tgoal.renego = NS_WIDE;
+ else
+ tp->tgoal.renego = 0;
+ tp->tgoal.check_nego = 0;
tp->tgoal.width = wide;
spi_offset(starget) = 0;
spi_period(starget) = 0;
@@ -2052,7 +2093,7 @@ static void sym_setwide(struct sym_hcb *np, int target, u_char wide)
spi_qas(starget) = 0;
if (sym_verbose >= 3)
- spi_display_xfer_agreement(starget);
+ sym_announce_transfer_rate(tp);
}
/*
@@ -2069,6 +2110,12 @@ sym_setsync(struct sym_hcb *np, int target,
sym_settrans(np, target, 0, ofs, per, wide, div, fak);
+ if (wide)
+ tp->tgoal.renego = NS_WIDE;
+ else if (ofs)
+ tp->tgoal.renego = NS_SYNC;
+ else
+ tp->tgoal.renego = 0;
spi_period(starget) = per;
spi_offset(starget) = ofs;
spi_iu(starget) = spi_dt(starget) = spi_qas(starget) = 0;
@@ -2079,7 +2126,7 @@ sym_setsync(struct sym_hcb *np, int target,
tp->tgoal.check_nego = 0;
}
- spi_display_xfer_agreement(starget);
+ sym_announce_transfer_rate(tp);
}
/*
@@ -2095,6 +2142,10 @@ sym_setpprot(struct sym_hcb *np, int target, u_char opts, u_char ofs,
sym_settrans(np, target, opts, ofs, per, wide, div, fak);
+ if (wide || ofs)
+ tp->tgoal.renego = NS_PPR;
+ else
+ tp->tgoal.renego = 0;
spi_width(starget) = tp->tgoal.width = wide;
spi_period(starget) = tp->tgoal.period = per;
spi_offset(starget) = tp->tgoal.offset = ofs;
@@ -2103,7 +2154,7 @@ sym_setpprot(struct sym_hcb *np, int target, u_char opts, u_char ofs,
spi_qas(starget) = tp->tgoal.qas = !!(opts & PPR_OPT_QAS);
tp->tgoal.check_nego = 0;
- spi_display_xfer_agreement(starget);
+ sym_announce_transfer_rate(tp);
}
/*
@@ -2214,8 +2265,9 @@ static void sym_int_udc (struct sym_hcb *np)
* mode to eight bit asynchronous, etc...
* So, just reinitializing all except chip should be enough.
*/
-static void sym_int_sbmc (struct sym_hcb *np)
+static void sym_int_sbmc(struct Scsi_Host *shost)
{
+ struct sym_hcb *np = sym_get_hcb(shost);
u_char scsi_mode = INB(np, nc_stest4) & SMODE;
/*
@@ -2228,7 +2280,7 @@ static void sym_int_sbmc (struct sym_hcb *np)
* Should suspend command processing for a few seconds and
* reinitialize all except the chip.
*/
- sym_start_up (np, 2);
+ sym_start_up(shost, 2);
}
/*
@@ -2266,8 +2318,9 @@ static void sym_int_par (struct sym_hcb *np, u_short sist)
int phase = cmd & 7;
struct sym_ccb *cp = sym_ccb_from_dsa(np, dsa);
- printf("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n",
- sym_name(np), hsts, dbc, sbcl);
+ if (printk_ratelimit())
+ printf("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n",
+ sym_name(np), hsts, dbc, sbcl);
/*
* Check that the chip is connected to the SCSI BUS.
@@ -2404,7 +2457,7 @@ static void sym_int_ma (struct sym_hcb *np)
}
/*
- * The data in the dma fifo has not been transfered to
+ * The data in the dma fifo has not been transferred to
* the target -> add the amount to the rest
* and clear the data.
* Check the sstat2 register in case of wide transfer.
@@ -2636,7 +2689,7 @@ static void sym_int_ma (struct sym_hcb *np)
* we force a SIR_NEGO_PROTO interrupt (it is a hack that avoids
* bloat for such a should_not_happen situation).
* In all other situation, we reset the BUS.
- * Are these assumptions reasonnable ? (Wait and see ...)
+ * Are these assumptions reasonable ? (Wait and see ...)
*/
unexpected_phase:
dsp -= 8;
@@ -2756,8 +2809,11 @@ reset_all:
* Use at your own decision and risk.
*/
-void sym_interrupt (struct sym_hcb *np)
+irqreturn_t sym_interrupt(struct Scsi_Host *shost)
{
+ struct sym_data *sym_data = shost_priv(shost);
+ struct sym_hcb *np = sym_data->ncb;
+ struct pci_dev *pdev = sym_data->pdev;
u_char istat, istatc;
u_char dstat;
u_short sist;
@@ -2776,13 +2832,13 @@ void sym_interrupt (struct sym_hcb *np)
istat = INB(np, nc_istat);
if (istat & INTF) {
OUTB(np, nc_istat, (istat & SIGP) | INTF | np->istat_sem);
- istat = INB(np, nc_istat); /* DUMMY READ */
+ istat |= INB(np, nc_istat); /* DUMMY READ */
if (DEBUG_FLAGS & DEBUG_TINY) printf ("F ");
sym_wakeup_done(np);
}
if (!(istat & (SIP|DIP)))
- return;
+ return (istat & INTF) ? IRQ_HANDLED : IRQ_NONE;
#if 0 /* We should never get this one */
if (istat & CABRT)
@@ -2809,6 +2865,13 @@ void sym_interrupt (struct sym_hcb *np)
dstat |= INB(np, nc_dstat);
istatc = INB(np, nc_istat);
istat |= istatc;
+
+ /* Prevent deadlock waiting on a condition that may
+ * never clear. */
+ if (unlikely(sist == 0xffff && dstat == 0xff)) {
+ if (pci_channel_offline(pdev))
+ return IRQ_NONE;
+ }
} while (istatc & (SIP|DIP));
if (DEBUG_FLAGS & DEBUG_TINY)
@@ -2842,10 +2905,10 @@ void sym_interrupt (struct sym_hcb *np)
!(dstat & (MDPE|BF|ABRT|IID))) {
if (sist & PAR) sym_int_par (np, sist);
else if (sist & MA) sym_int_ma (np);
- else if (dstat & SIR) sym_int_sir (np);
+ else if (dstat & SIR) sym_int_sir(np);
else if (dstat & SSI) OUTONB_STD();
else goto unknown_int;
- return;
+ return IRQ_HANDLED;
}
/*
@@ -2861,8 +2924,8 @@ void sym_interrupt (struct sym_hcb *np)
*/
if (sist & RST) {
printf("%s: SCSI BUS reset detected.\n", sym_name(np));
- sym_start_up (np, 1);
- return;
+ sym_start_up(shost, 1);
+ return IRQ_HANDLED;
}
OUTB(np, nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo */
@@ -2870,11 +2933,11 @@ void sym_interrupt (struct sym_hcb *np)
if (!(sist & (GEN|HTH|SGE)) &&
!(dstat & (MDPE|BF|ABRT|IID))) {
- if (sist & SBMC) sym_int_sbmc (np);
+ if (sist & SBMC) sym_int_sbmc(shost);
else if (sist & STO) sym_int_sto (np);
else if (sist & UDC) sym_int_udc (np);
else goto unknown_int;
- return;
+ return IRQ_HANDLED;
}
/*
@@ -2884,12 +2947,12 @@ void sym_interrupt (struct sym_hcb *np)
* Reset everything.
*/
- sym_log_hard_error(np, sist, dstat);
+ sym_log_hard_error(shost, sist, dstat);
if ((sist & (GEN|HTH|SGE)) ||
(dstat & (MDPE|BF|ABRT|IID))) {
sym_start_reset(np);
- return;
+ return IRQ_HANDLED;
}
unknown_int:
@@ -2900,6 +2963,7 @@ unknown_int:
printf( "%s: unknown interrupt(s) ignored, "
"ISTAT=0x%x DSTAT=0x%x SIST=0x%x\n",
sym_name(np), istat, dstat, sist);
+ return IRQ_NONE;
}
/*
@@ -2936,7 +3000,11 @@ sym_dequeue_from_squeue(struct sym_hcb *np, int i, int target, int lun, int task
if ((target == -1 || cp->target == target) &&
(lun == -1 || cp->lun == lun) &&
(task == -1 || cp->tag == task)) {
+#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
sym_set_cam_status(cp->cmd, DID_SOFT_ERROR);
+#else
+ sym_set_cam_status(cp->cmd, DID_REQUEUE);
+#endif
sym_remque(&cp->link_ccbq);
sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq);
}
@@ -3145,7 +3213,7 @@ int sym_clear_tasks(struct sym_hcb *np, int cam_status, int target, int lun, int
* the COMP queue and put back other ones into
* the BUSY queue.
*/
- while ((qp = sym_remque_head(&qtmp)) != 0) {
+ while ((qp = sym_remque_head(&qtmp)) != NULL) {
struct scsi_cmnd *cmd;
cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
cmd = cp->cmd;
@@ -3493,6 +3561,7 @@ static void sym_sir_task_recovery(struct sym_hcb *np, int num)
spi_dt(starget) = 0;
spi_qas(starget) = 0;
tp->tgoal.check_nego = 1;
+ tp->tgoal.renego = 0;
}
/*
@@ -3520,7 +3589,8 @@ static void sym_sir_task_recovery(struct sym_hcb *np, int num)
* If we sent a BDR, make upper layer aware of that.
*/
if (np->abrt_msg[0] == M_RESET)
- sym_xpt_async_sent_bdr(np, target);
+ starget_printk(KERN_NOTICE, starget,
+ "has been reset\n");
break;
}
@@ -3818,7 +3888,7 @@ int sym_compute_residual(struct sym_hcb *np, struct sym_ccb *cp)
if (cp->startp == cp->phys.head.lastp ||
sym_evaluate_dp(np, cp, scr_to_cpu(cp->phys.head.lastp),
&dp_ofs) < 0) {
- return cp->data_len;
+ return cp->data_len - cp->odd_byte_adjustment;
}
/*
@@ -4304,7 +4374,7 @@ static void sym_nego_rejected(struct sym_hcb *np, struct sym_tcb *tp, struct sym
/*
* chip exception handler for programmed interrupts.
*/
-static void sym_int_sir (struct sym_hcb *np)
+static void sym_int_sir(struct sym_hcb *np)
{
u_char num = INB(np, nc_dsps);
u32 dsa = INL(np, nc_dsa);
@@ -4343,31 +4413,30 @@ static void sym_int_sir (struct sym_hcb *np)
return;
/*
* The device didn't go to MSG OUT phase after having
- * been selected with ATN. We donnot want to handle
- * that.
+ * been selected with ATN. We do not want to handle that.
*/
case SIR_SEL_ATN_NO_MSG_OUT:
- printf ("%s:%d: No MSG OUT phase after selection with ATN.\n",
- sym_name (np), target);
+ scmd_printk(KERN_WARNING, cp->cmd,
+ "No MSG OUT phase after selection with ATN\n");
goto out_stuck;
/*
* The device didn't switch to MSG IN phase after
- * having reseleted the initiator.
+ * having reselected the initiator.
*/
case SIR_RESEL_NO_MSG_IN:
- printf ("%s:%d: No MSG IN phase after reselection.\n",
- sym_name (np), target);
+ scmd_printk(KERN_WARNING, cp->cmd,
+ "No MSG IN phase after reselection\n");
goto out_stuck;
/*
* After reselection, the device sent a message that wasn't
* an IDENTIFY.
*/
case SIR_RESEL_NO_IDENTIFY:
- printf ("%s:%d: No IDENTIFY after reselection.\n",
- sym_name (np), target);
+ scmd_printk(KERN_WARNING, cp->cmd,
+ "No IDENTIFY after reselection\n");
goto out_stuck;
/*
- * The device reselected a LUN we donnot know about.
+ * The device reselected a LUN we do not know about.
*/
case SIR_RESEL_BAD_LUN:
np->msgout[0] = M_RESET;
@@ -4380,8 +4449,7 @@ static void sym_int_sir (struct sym_hcb *np)
np->msgout[0] = M_ABORT;
goto out;
/*
- * The device reselected for a tagged nexus that we donnot
- * have.
+ * The device reselected for a tagged nexus that we do not have.
*/
case SIR_RESEL_BAD_I_T_L_Q:
np->msgout[0] = M_ABORT_TAG;
@@ -4393,8 +4461,8 @@ static void sym_int_sir (struct sym_hcb *np)
case SIR_RESEL_ABORTED:
np->lastmsg = np->msgout[0];
np->msgout[0] = M_NOOP;
- printf ("%s:%d: message %x sent on bad reselection.\n",
- sym_name (np), target, np->lastmsg);
+ scmd_printk(KERN_WARNING, cp->cmd,
+ "message %x sent on bad reselection\n", np->lastmsg);
goto out;
/*
* The SCRIPTS let us know that a message has been
@@ -4491,7 +4559,8 @@ static void sym_int_sir (struct sym_hcb *np)
switch (np->msgin [2]) {
case M_X_MODIFY_DP:
if (DEBUG_FLAGS & DEBUG_POINTER)
- sym_print_msg(cp, NULL, np->msgin);
+ sym_print_msg(cp, "extended msg ",
+ np->msgin);
tmp = (np->msgin[3]<<24) + (np->msgin[4]<<16) +
(np->msgin[5]<<8) + (np->msgin[6]);
sym_modify_dp(np, tp, cp, tmp);
@@ -4518,7 +4587,7 @@ static void sym_int_sir (struct sym_hcb *np)
*/
case M_IGN_RESIDUE:
if (DEBUG_FLAGS & DEBUG_POINTER)
- sym_print_msg(cp, NULL, np->msgin);
+ sym_print_msg(cp, "1 or 2 byte ", np->msgin);
if (cp->host_flags & HF_SENSE)
OUTL_DSP(np, SCRIPTA_BA(np, clrack));
else
@@ -4931,7 +5000,7 @@ struct sym_lcb *sym_alloc_lcb (struct sym_hcb *np, u_char tn, u_char ln)
*/
if (ln && !tp->lunmp) {
tp->lunmp = kcalloc(SYM_CONF_MAX_LUN, sizeof(struct sym_lcb *),
- GFP_KERNEL);
+ GFP_ATOMIC);
if (!tp->lunmp)
goto fail;
}
@@ -4951,6 +5020,7 @@ struct sym_lcb *sym_alloc_lcb (struct sym_hcb *np, u_char tn, u_char ln)
tp->lun0p = lp;
tp->head.lun0_sa = cpu_to_scr(vtobus(lp));
}
+ tp->nlcb++;
/*
* Let the itl task point to error handling.
@@ -5028,6 +5098,43 @@ fail:
}
/*
+ * Lun control block deallocation. Returns the number of valid remaining LCBs
+ * for the target.
+ */
+int sym_free_lcb(struct sym_hcb *np, u_char tn, u_char ln)
+{
+ struct sym_tcb *tp = &np->target[tn];
+ struct sym_lcb *lp = sym_lp(tp, ln);
+
+ tp->nlcb--;
+
+ if (ln) {
+ if (!tp->nlcb) {
+ kfree(tp->lunmp);
+ sym_mfree_dma(tp->luntbl, 256, "LUNTBL");
+ tp->lunmp = NULL;
+ tp->luntbl = NULL;
+ tp->head.luntbl_sa = cpu_to_scr(vtobus(np->badluntbl));
+ } else {
+ tp->luntbl[ln] = cpu_to_scr(vtobus(&np->badlun_sa));
+ tp->lunmp[ln] = NULL;
+ }
+ } else {
+ tp->lun0p = NULL;
+ tp->head.lun0_sa = cpu_to_scr(vtobus(&np->badlun_sa));
+ }
+
+ if (lp->itlq_tbl) {
+ sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK*4, "ITLQ_TBL");
+ kfree(lp->cb_tags);
+ }
+
+ sym_mfree_dma(lp, sizeof(*lp), "LCB");
+
+ return tp->nlcb;
+}
+
+/*
* Queue a SCSI IO to the controller.
*/
int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp)
@@ -5113,9 +5220,14 @@ int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *
/*
* Build a negotiation message if needed.
* (nego_status is filled by sym_prepare_nego())
+ *
+ * Always negotiate on INQUIRY and REQUEST SENSE.
+ *
*/
cp->nego_status = 0;
- if (tp->tgoal.check_nego && !tp->nego_cp && lp) {
+ if ((tp->tgoal.check_nego ||
+ cmd->cmnd[0] == INQUIRY || cmd->cmnd[0] == REQUEST_SENSE) &&
+ !tp->nego_cp && lp) {
msglen += sym_prepare_nego(np, cp, msgptr + msglen);
}
@@ -5545,7 +5657,7 @@ int sym_hcb_attach(struct Scsi_Host *shost, struct sym_fw *fw, struct sym_nvram
/*
* Allocate the array of lists of CCBs hashed by DSA.
*/
- np->ccbh = kcalloc(sizeof(struct sym_ccb **), CCB_HASH_SIZE, GFP_KERNEL);
+ np->ccbh = kcalloc(CCB_HASH_SIZE, sizeof(struct sym_ccb **), GFP_KERNEL);
if (!np->ccbh)
goto attach_failed;
@@ -5578,16 +5690,13 @@ int sym_hcb_attach(struct Scsi_Host *shost, struct sym_fw *fw, struct sym_nvram
np->scriptz_ba = vtobus(np->scriptz0);
if (np->ram_ba) {
- np->scripta_ba = np->ram_ba;
+ np->scripta_ba = np->ram_ba;
if (np->features & FE_RAM8K) {
- np->ram_ws = 8192;
np->scriptb_ba = np->scripta_ba + 4096;
#if 0 /* May get useful for 64 BIT PCI addressing */
np->scr_ram_seg = cpu_to_scr(np->scripta_ba >> 32);
#endif
}
- else
- np->ram_ws = 4096;
}
/*
@@ -5710,7 +5819,7 @@ void sym_hcb_free(struct sym_hcb *np)
sym_mfree_dma(np->dqueue, sizeof(u32)*(MAX_QUEUE*2), "DQUEUE");
if (np->actccbs) {
- while ((qp = sym_remque_head(&np->free_ccbq)) != 0) {
+ while ((qp = sym_remque_head(&np->free_ccbq)) != NULL) {
cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
sym_mfree_dma(cp, sizeof(*cp), "CCB");
}
@@ -5722,6 +5831,8 @@ void sym_hcb_free(struct sym_hcb *np)
for (target = 0; target < SYM_CONF_MAX_TARGET ; target++) {
tp = &np->target[target];
+ if (tp->luntbl)
+ sym_mfree_dma(tp->luntbl, 256, "LUNTBL");
#if SYM_CONF_MAX_LUN > 1
kfree(tp->lunmp);
#endif
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.h b/drivers/scsi/sym53c8xx_2/sym_hipd.h
index 79ab6a17703..5a80cbac3f9 100644
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.h
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.h
@@ -54,7 +54,7 @@
*
* SYM_OPT_LIMIT_COMMAND_REORDERING
* When this option is set, the driver tries to limit tagged
- * command reordering to some reasonnable value.
+ * command reordering to some reasonable value.
* (set for Linux)
*/
#if 0
@@ -354,6 +354,7 @@ struct sym_trans {
unsigned int dt:1;
unsigned int qas:1;
unsigned int check_nego:1;
+ unsigned int renego:2;
};
/*
@@ -400,6 +401,7 @@ struct sym_tcb {
* An array of bus addresses is used on reselection.
*/
u32 *luntbl; /* LCBs bus address table */
+ int nlcb; /* Number of valid LCBs (including LUN #0) */
/*
* LUN table used by the C code.
@@ -419,6 +421,9 @@ struct sym_tcb {
/* Transfer goal */
struct sym_trans tgoal;
+ /* Last printed transfer speed */
+ struct sym_trans tprint;
+
/*
* Keep track of the CCB used for the negotiation in order
* to ensure that only 1 negotiation is queued at a time.
@@ -883,10 +888,7 @@ struct sym_hcb {
* Physical bus addresses of the chip.
*/
u32 mmio_ba; /* MMIO 32 bit BUS address */
- int mmio_ws; /* MMIO Window size */
-
u32 ram_ba; /* RAM 32 bit BUS address */
- int ram_ws; /* RAM window size */
/*
* SCRIPTS virtual and physical bus addresses.
@@ -912,14 +914,12 @@ struct sym_hcb {
struct sym_fwb_ba fwb_bas; /* Useful SCRIPTB bus addresses */
struct sym_fwz_ba fwz_bas; /* Useful SCRIPTZ bus addresses */
void (*fw_setup)(struct sym_hcb *np, struct sym_fw *fw);
- void (*fw_patch)(struct sym_hcb *np);
+ void (*fw_patch)(struct Scsi_Host *);
char *fw_name;
/*
* General controller parameters and configuration.
*/
- u_short device_id; /* PCI device id */
- u_char revision_id; /* PCI device revision id */
u_int features; /* Chip features map */
u_char myaddr; /* SCSI id of the adapter */
u_char maxburst; /* log base 2 of dwords burst */
@@ -1031,6 +1031,14 @@ struct sym_hcb {
#endif
};
+#if SYM_CONF_DMA_ADDRESSING_MODE == 0
+#define use_dac(np) 0
+#define set_dac(np) do { } while (0)
+#else
+#define use_dac(np) (np)->use_dac
+#define set_dac(np) (np)->use_dac = 1
+#endif
+
#define HCB_BA(np, lbl) (np->hcb_ba + offsetof(struct sym_hcb, lbl))
@@ -1052,12 +1060,13 @@ void sym_start_next_ccbs(struct sym_hcb *np, struct sym_lcb *lp, int maxn);
#else
void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp);
#endif
-void sym_start_up(struct sym_hcb *np, int reason);
-void sym_interrupt(struct sym_hcb *np);
+void sym_start_up(struct Scsi_Host *, int reason);
+irqreturn_t sym_interrupt(struct Scsi_Host *);
int sym_clear_tasks(struct sym_hcb *np, int cam_status, int target, int lun, int task);
struct sym_ccb *sym_get_ccb(struct sym_hcb *np, struct scsi_cmnd *cmd, u_char tag_order);
void sym_free_ccb(struct sym_hcb *np, struct sym_ccb *cp);
struct sym_lcb *sym_alloc_lcb(struct sym_hcb *np, u_char tn, u_char ln);
+int sym_free_lcb(struct sym_hcb *np, u_char tn, u_char ln);
int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *csio, struct sym_ccb *cp);
int sym_abort_scsiio(struct sym_hcb *np, struct scsi_cmnd *ccb, int timed_out);
int sym_reset_scsi_target(struct sym_hcb *np, int target);
@@ -1073,20 +1082,23 @@ int sym_hcb_attach(struct Scsi_Host *shost, struct sym_fw *fw, struct sym_nvram
*/
#if SYM_CONF_DMA_ADDRESSING_MODE == 0
+#define DMA_DAC_MASK DMA_BIT_MASK(32)
#define sym_build_sge(np, data, badd, len) \
do { \
(data)->addr = cpu_to_scr(badd); \
(data)->size = cpu_to_scr(len); \
} while (0)
#elif SYM_CONF_DMA_ADDRESSING_MODE == 1
+#define DMA_DAC_MASK DMA_BIT_MASK(40)
#define sym_build_sge(np, data, badd, len) \
do { \
(data)->addr = cpu_to_scr(badd); \
(data)->size = cpu_to_scr((((badd) >> 8) & 0xff000000) + len); \
} while (0)
#elif SYM_CONF_DMA_ADDRESSING_MODE == 2
+#define DMA_DAC_MASK DMA_BIT_MASK(64)
int sym_lookup_dmap(struct sym_hcb *np, u32 h, int s);
-static __inline void
+static inline void
sym_build_sge(struct sym_hcb *np, struct sym_tblmove *data, u64 badd, int len)
{
u32 h = (badd>>32);
@@ -1191,7 +1203,7 @@ dma_addr_t __vtobus(m_pool_ident_t dev_dmat, void *m);
#define sym_m_pool_match(mp_id1, mp_id2) (mp_id1 == mp_id2)
-static __inline void *sym_m_get_dma_mem_cluster(m_pool_p mp, m_vtob_p vbp)
+static inline void *sym_m_get_dma_mem_cluster(m_pool_p mp, m_vtob_p vbp)
{
void *vaddr = NULL;
dma_addr_t baddr = 0;
@@ -1205,7 +1217,7 @@ static __inline void *sym_m_get_dma_mem_cluster(m_pool_p mp, m_vtob_p vbp)
return vaddr;
}
-static __inline void sym_m_free_dma_mem_cluster(m_pool_p mp, m_vtob_p vbp)
+static inline void sym_m_free_dma_mem_cluster(m_pool_p mp, m_vtob_p vbp)
{
dma_free_coherent(mp->dev_dmat, SYM_MEM_CLUSTER_SIZE, vbp->vaddr,
vbp->baddr);
diff --git a/drivers/scsi/sym53c8xx_2/sym_malloc.c b/drivers/scsi/sym53c8xx_2/sym_malloc.c
index 92bf9b14a7a..6f9af0de7ec 100644
--- a/drivers/scsi/sym53c8xx_2/sym_malloc.c
+++ b/drivers/scsi/sym53c8xx_2/sym_malloc.c
@@ -50,7 +50,7 @@
* from the SCRIPTS code. In addition, cache line alignment
* is guaranteed for power of 2 cache line size.
*
- * This allocator has been developped for the Linux sym53c8xx
+ * This allocator has been developed for the Linux sym53c8xx
* driver, since this O/S does not provide naturally aligned
* allocations.
* It has the advantage of allowing the driver to use private
@@ -262,7 +262,7 @@ static void ___free_dma_mem_cluster(m_pool_p mp, void *m)
#endif
/* Fetch the memory pool for a given pool id (i.e. DMA constraints) */
-static __inline m_pool_p ___get_dma_pool(m_pool_ident_t dev_dmat)
+static inline m_pool_p ___get_dma_pool(m_pool_ident_t dev_dmat)
{
m_pool_p mp;
for (mp = mp0.next;
diff --git a/drivers/scsi/sym53c8xx_2/sym_misc.h b/drivers/scsi/sym53c8xx_2/sym_misc.h
index 0433d5d0caf..96c15145902 100644
--- a/drivers/scsi/sym53c8xx_2/sym_misc.h
+++ b/drivers/scsi/sym53c8xx_2/sym_misc.h
@@ -52,17 +52,17 @@ typedef struct sym_quehead {
(ptr)->flink = (ptr); (ptr)->blink = (ptr); \
} while (0)
-static __inline struct sym_quehead *sym_que_first(struct sym_quehead *head)
+static inline struct sym_quehead *sym_que_first(struct sym_quehead *head)
{
return (head->flink == head) ? 0 : head->flink;
}
-static __inline struct sym_quehead *sym_que_last(struct sym_quehead *head)
+static inline struct sym_quehead *sym_que_last(struct sym_quehead *head)
{
return (head->blink == head) ? 0 : head->blink;
}
-static __inline void __sym_que_add(struct sym_quehead * new,
+static inline void __sym_que_add(struct sym_quehead * new,
struct sym_quehead * blink,
struct sym_quehead * flink)
{
@@ -72,19 +72,19 @@ static __inline void __sym_que_add(struct sym_quehead * new,
blink->flink = new;
}
-static __inline void __sym_que_del(struct sym_quehead * blink,
+static inline void __sym_que_del(struct sym_quehead * blink,
struct sym_quehead * flink)
{
flink->blink = blink;
blink->flink = flink;
}
-static __inline int sym_que_empty(struct sym_quehead *head)
+static inline int sym_que_empty(struct sym_quehead *head)
{
return head->flink == head;
}
-static __inline void sym_que_splice(struct sym_quehead *list,
+static inline void sym_que_splice(struct sym_quehead *list,
struct sym_quehead *head)
{
struct sym_quehead *first = list->flink;
@@ -101,7 +101,7 @@ static __inline void sym_que_splice(struct sym_quehead *list,
}
}
-static __inline void sym_que_move(struct sym_quehead *orig,
+static inline void sym_que_move(struct sym_quehead *orig,
struct sym_quehead *dest)
{
struct sym_quehead *first, *last;
@@ -121,9 +121,7 @@ static __inline void sym_que_move(struct sym_quehead *orig,
}
}
-#define sym_que_entry(ptr, type, member) \
- ((type *)((char *)(ptr)-(unsigned int)(&((type *)0)->member)))
-
+#define sym_que_entry(ptr, type, member) container_of(ptr, type, member)
#define sym_insque(new, pos) __sym_que_add(new, pos, (pos)->flink)
@@ -131,7 +129,7 @@ static __inline void sym_que_move(struct sym_quehead *orig,
#define sym_insque_head(new, head) __sym_que_add(new, head, (head)->flink)
-static __inline struct sym_quehead *sym_remque_head(struct sym_quehead *head)
+static inline struct sym_quehead *sym_remque_head(struct sym_quehead *head)
{
struct sym_quehead *elem = head->flink;
@@ -144,7 +142,7 @@ static __inline struct sym_quehead *sym_remque_head(struct sym_quehead *head)
#define sym_insque_tail(new, head) __sym_que_add(new, (head)->blink, head)
-static __inline struct sym_quehead *sym_remque_tail(struct sym_quehead *head)
+static inline struct sym_quehead *sym_remque_tail(struct sym_quehead *head)
{
struct sym_quehead *elem = head->blink;
diff --git a/drivers/scsi/sym53c8xx_2/sym_nvram.c b/drivers/scsi/sym53c8xx_2/sym_nvram.c
index 15d69298ab6..5662fbb3ff6 100644
--- a/drivers/scsi/sym53c8xx_2/sym_nvram.c
+++ b/drivers/scsi/sym53c8xx_2/sym_nvram.c
@@ -696,7 +696,7 @@ static int sym_read_Tekram_nvram (struct sym_device *np, Tekram_nvram *nvram)
u_short csum;
int x;
- switch (np->device_id) {
+ switch (np->pdev->device) {
case PCI_DEVICE_ID_NCR_53C885:
case PCI_DEVICE_ID_NCR_53C895:
case PCI_DEVICE_ID_NCR_53C896: