diff options
Diffstat (limited to 'drivers/scsi/sym53c8xx_2/sym_hipd.c')
| -rw-r--r-- | drivers/scsi/sym53c8xx_2/sym_hipd.c | 470 |
1 files changed, 283 insertions, 187 deletions
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index 8260f040d39..6b349e30186 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -40,7 +40,6 @@ #include <linux/slab.h> #include <asm/param.h> /* for timeouts in units of HZ */ -#include <scsi/scsi_dbg.h> #include "sym_glue.h" #include "sym_nvram.h" @@ -53,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); @@ -473,7 +472,7 @@ static int sym_getpciclock (struct sym_hcb *np) * calculations more simple. */ #define _5M 5000000 -static u32 div_10M[] = {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M}; +static const u32 div_10M[] = {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M}; /* * Get clock factor and sync divisor for a given @@ -600,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); @@ -646,19 +645,49 @@ static void sym_save_initial_setting (struct sym_hcb *np) } /* + * Set SCSI BUS mode. + * - LVD capable chips (895/895A/896/1010) report the current BUS mode + * through the STEST4 IO register. + * - For previous generation chips (825/825A/875), the user has to tell us + * how to check against HVD, since a 100% safe algorithm is not possible. + */ +static void sym_set_bus_mode(struct sym_hcb *np, struct sym_nvram *nvram) +{ + if (np->scsi_mode) + return; + + np->scsi_mode = SMODE_SE; + if (np->features & (FE_ULTRA2|FE_ULTRA3)) + np->scsi_mode = (np->sv_stest4 & SMODE); + else if (np->features & FE_DIFF) { + if (SYM_SETUP_SCSI_DIFF == 1) { + if (np->sv_scntl3) { + if (np->sv_stest2 & 0x20) + np->scsi_mode = SMODE_HVD; + } else if (nvram->type == SYM_SYMBIOS_NVRAM) { + if (!(INB(np, nc_gpreg) & 0x08)) + np->scsi_mode = SMODE_HVD; + } + } else if (SYM_SETUP_SCSI_DIFF == 2) + np->scsi_mode = SMODE_HVD; + } + if (np->scsi_mode == SMODE_HVD) + np->rv_stest2 |= 0x20; +} + +/* * Prepare io register values used by sym_start_up() * according to selected and supported features. */ 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; - /* - * Wide ? - */ - np->maxwide = (np->features & FE_WIDE)? 1 : 0; + np->maxwide = (np->features & FE_WIDE) ? 1 : 0; /* * Guess the frequency of the chip's clock. @@ -748,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); } /* @@ -774,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; /* @@ -798,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); /* @@ -839,6 +861,7 @@ static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, stru * Get parity checking, host ID and verbose mode from NVRAM */ np->myaddr = 255; + np->scsi_mode = 0; sym_nvram_setup_host(shost, np, nvram); /* @@ -855,33 +878,7 @@ static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, stru */ sym_init_burst(np, burst_max); - /* - * Set SCSI BUS mode. - * - LVD capable chips (895/895A/896/1010) report the - * current BUS mode through the STEST4 IO register. - * - For previous generation chips (825/825A/875), - * user has to tell us how to check against HVD, - * since a 100% safe algorithm is not possible. - */ - np->scsi_mode = SMODE_SE; - if (np->features & (FE_ULTRA2|FE_ULTRA3)) - np->scsi_mode = (np->sv_stest4 & SMODE); - else if (np->features & FE_DIFF) { - if (SYM_SETUP_SCSI_DIFF == 1) { - if (np->sv_scntl3) { - if (np->sv_stest2 & 0x20) - np->scsi_mode = SMODE_HVD; - } - else if (nvram->type == SYM_SYMBIOS_NVRAM) { - if (!(INB(np, nc_gpreg) & 0x08)) - np->scsi_mode = SMODE_HVD; - } - } - else if (SYM_SETUP_SCSI_DIFF == 2) - np->scsi_mode = SMODE_HVD; - } - if (np->scsi_mode == SMODE_HVD) - np->rv_stest2 |= 0x20; + sym_set_bus_mode(np, nvram); /* * Set LED support from SCRIPTS. @@ -892,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; @@ -919,6 +916,8 @@ static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, stru tp->usrflags |= (SYM_DISC_ENABLED | SYM_TAGS_ENABLED); tp->usrtags = SYM_SETUP_MAX_TAG; + tp->usr_width = np->maxwide; + tp->usr_period = 9; sym_nvram_setup_target(tp, i, nvram); @@ -972,8 +971,8 @@ static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, stru * * Has to be called with interrupts disabled. */ -#ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED -static int sym_regtest (struct sym_hcb *np) +#ifdef CONFIG_SCSI_SYM53C8XX_MMIO +static int sym_regtest(struct sym_hcb *np) { register volatile u32 data; /* @@ -991,20 +990,25 @@ static int sym_regtest (struct sym_hcb *np) #endif printf ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n", (unsigned) data); - return (0x10); + return 0x10; } - return (0); + return 0; +} +#else +static inline int sym_regtest(struct sym_hcb *np) +{ + return 0; } #endif -static int sym_snooptest (struct sym_hcb *np) +static int sym_snooptest(struct sym_hcb *np) { - u32 sym_rd, sym_wr, sym_bk, host_rd, host_wr, pc, dstat; - int i, err=0; -#ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED - err |= sym_regtest (np); - if (err) return (err); -#endif + u32 sym_rd, sym_wr, sym_bk, host_rd, host_wr, pc, dstat; + int i, err; + + err = sym_regtest(np); + if (err) + return err; restart_test: /* * Enable Master Parity Checking as we intend @@ -1093,7 +1097,7 @@ restart_test: err |= 4; } - return (err); + return err; } /* @@ -1123,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; @@ -1168,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[] = { @@ -1264,8 +1280,7 @@ static struct sym_chip sym_dev_table[] = { FE_RAM|FE_IO256|FE_LEDC} }; -#define sym_num_devs \ - (sizeof(sym_dev_table) / sizeof(sym_dev_table[0])) +#define sym_num_devs (ARRAY_SIZE(sym_dev_table)) /* * Look up the chip table. @@ -1301,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 */ @@ -1415,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; @@ -1430,29 +1444,18 @@ static int sym_prepare_nego(struct sym_hcb *np, struct sym_ccb *cp, u_char *msgp switch (nego) { case NS_SYNC: - msgptr[msglen++] = M_EXTENDED; - msgptr[msglen++] = 3; - msgptr[msglen++] = M_X_SYNC_REQ; - msgptr[msglen++] = goal->period; - msgptr[msglen++] = goal->offset; + msglen += spi_populate_sync_msg(msgptr + msglen, goal->period, + goal->offset); break; case NS_WIDE: - msgptr[msglen++] = M_EXTENDED; - msgptr[msglen++] = 2; - msgptr[msglen++] = M_X_WIDE_REQ; - msgptr[msglen++] = goal->width; + msglen += spi_populate_width_msg(msgptr + msglen, goal->width); break; case NS_PPR: - msgptr[msglen++] = M_EXTENDED; - msgptr[msglen++] = 6; - msgptr[msglen++] = M_X_PPR_REQ; - msgptr[msglen++] = goal->period; - msgptr[msglen++] = 0; - msgptr[msglen++] = goal->offset; - msgptr[msglen++] = goal->width; - msgptr[msglen++] = (goal->iu ? PPR_OPT_IU : 0) | + msglen += spi_populate_ppr_msg(msgptr + msglen, goal->period, + goal->offset, goal->width, + (goal->iu ? PPR_OPT_IU : 0) | (goal->dt ? PPR_OPT_DT : 0) | - (goal->qas ? PPR_OPT_QAS : 0); + (goal->qas ? PPR_OPT_QAS : 0)); break; } @@ -1474,7 +1477,7 @@ static int sym_prepare_nego(struct sym_hcb *np, struct sym_ccb *cp, u_char *msgp /* * Insert a job into the start queue. */ -static void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp) +void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp) { u_short qidx; @@ -1519,7 +1522,8 @@ static 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; } @@ -3588,7 +3658,7 @@ static int sym_evaluate_dp(struct sym_hcb *np, struct sym_ccb *cp, u32 scr, int if (pm) { dp_scr = scr_to_cpu(pm->ret); - dp_ofs -= scr_to_cpu(pm->sg.size); + dp_ofs -= scr_to_cpu(pm->sg.size) & 0x00ffffff; } /* @@ -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; } /* @@ -3948,11 +4018,7 @@ sym_sync_nego_check(struct sym_hcb *np, int req, struct sym_ccb *cp) /* * It was a request. Prepare an answer message. */ - np->msgout[0] = M_EXTENDED; - np->msgout[1] = 3; - np->msgout[2] = M_X_SYNC_REQ; - np->msgout[3] = per; - np->msgout[4] = ofs; + spi_populate_sync_msg(np->msgout, per, ofs); if (DEBUG_FLAGS & DEBUG_NEGO) { sym_print_nego_msg(np, target, "sync msgout", np->msgout); @@ -4078,14 +4144,7 @@ sym_ppr_nego_check(struct sym_hcb *np, int req, int target) /* * It was a request. Prepare an answer message. */ - np->msgout[0] = M_EXTENDED; - np->msgout[1] = 6; - np->msgout[2] = M_X_PPR_REQ; - np->msgout[3] = per; - np->msgout[4] = 0; - np->msgout[5] = ofs; - np->msgout[6] = wide; - np->msgout[7] = opts; + spi_populate_ppr_msg(np->msgout, per, ofs, wide, opts); if (DEBUG_FLAGS & DEBUG_NEGO) { sym_print_nego_msg(np, target, "ppr msgout", np->msgout); @@ -4197,10 +4256,7 @@ sym_wide_nego_check(struct sym_hcb *np, int req, struct sym_ccb *cp) /* * It was a request. Prepare an answer message. */ - np->msgout[0] = M_EXTENDED; - np->msgout[1] = 2; - np->msgout[2] = M_X_WIDE_REQ; - np->msgout[3] = wide; + spi_populate_width_msg(np->msgout, wide); np->msgin [0] = M_NOOP; @@ -4245,11 +4301,8 @@ static void sym_wide_nego(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb * a single SCSI command (Suggested by Justin Gibbs). */ if (tp->tgoal.offset) { - np->msgout[0] = M_EXTENDED; - np->msgout[1] = 3; - np->msgout[2] = M_X_SYNC_REQ; - np->msgout[3] = tp->tgoal.period; - np->msgout[4] = tp->tgoal.offset; + spi_populate_sync_msg(np->msgout, tp->tgoal.period, + tp->tgoal.offset); if (DEBUG_FLAGS & DEBUG_NEGO) { sym_print_nego_msg(np, cp->target, @@ -4321,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); @@ -4360,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; @@ -4397,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; @@ -4410,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 @@ -4508,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,"modify DP",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); @@ -4535,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,"ign wide residue", 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 @@ -4624,7 +4676,8 @@ struct sym_ccb *sym_get_ccb (struct sym_hcb *np, struct scsi_cmnd *cmd, u_char t * Debugging purpose. */ #ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING - assert(lp->busy_itl == 0); + if (lp->busy_itl != 0) + goto out_free; #endif /* * Allocate resources for tags if not yet. @@ -4669,7 +4722,8 @@ struct sym_ccb *sym_get_ccb (struct sym_hcb *np, struct scsi_cmnd *cmd, u_char t * Debugging purpose. */ #ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING - assert(lp->busy_itl == 0 && lp->busy_itlq == 0); + if (lp->busy_itl != 0 || lp->busy_itlq != 0) + goto out_free; #endif /* * Count this nexus for this LUN. @@ -4946,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; } @@ -4966,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. @@ -5043,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) @@ -5128,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); } @@ -5560,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; @@ -5593,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; } /* @@ -5725,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"); } @@ -5737,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 |
