diff --git a/qla_isp/linux/isp_linux.c b/qla_isp/linux/isp_linux.c index 4b8506036..434ed136a 100644 --- a/qla_isp/linux/isp_linux.c +++ b/qla_isp/linux/isp_linux.c @@ -2958,14 +2958,12 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...) isp_dump_portdb(isp, bus); } } + isp_prt(isp, ISP_LOGCONFIG, prom0, bus, lp->portid, lp->handle, isp_class3_roles[lp->roles], "arrived", (ull) lp->node_wwn, (ull) lp->port_wwn); if (lp->dev_map_idx) { - unsigned long arg; - tgt = lp->dev_map_idx - 1; - isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, isp_class3_roles[lp->roles], "arrived at", tgt, (ull) lp->node_wwn, (ull) lp->port_wwn); - arg = tgt | (bus << 16); - isp_thread_event(isp, ISP_THREAD_SCSI_SCAN, (void *)arg, 0, __func__, __LINE__); - } else { - isp_prt(isp, ISP_LOGCONFIG, prom0, bus, lp->portid, lp->handle, isp_class3_roles[lp->roles], "arrived", (ull) lp->node_wwn, (ull) lp->port_wwn); + lp->dirty = 0; + if (isp->isp_osinfo.scan_timeout == 0) { + isp->isp_osinfo.scan_timeout = ISP_SCAN_TIMEOUT; + } } break; case ISPASYNC_DEV_CHANGED: @@ -3004,15 +3002,13 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...) va_end(ap); fcp = FCPARAM(isp, bus); if (lp->dev_map_idx) { - unsigned long arg; - tgt = lp->dev_map_idx - 1; - fcp->isp_dev_map[tgt] = 0; - lp->state = FC_PORTDB_STATE_NIL; - lp->dev_map_idx = 0; - isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, isp_class3_roles[lp->roles], "departed", tgt, (ull) lp->node_wwn, (ull) lp->port_wwn); - arg = tgt | (bus << 16) | (1 << 31); - isp_thread_event(isp, ISP_THREAD_SCSI_SCAN, (void *)arg, 0, __func__, __LINE__); - } else if (lp->reserved == 0) { + lp->reserved = 2; + if (isp->isp_osinfo.rescan_timeout == 0) { + isp->isp_osinfo.rescan_timeout = ISP_RESCAN_TIMEOUT; + } + isp_prt(isp, ISP_LOGCONFIG, prom0, bus, lp->portid, lp->handle, isp_class3_roles[lp->roles], "zombie", (ull) lp->node_wwn, (ull) lp->port_wwn); + lp->state = FC_PORTDB_STATE_ZOMBIE; + } else { isp_prt(isp, ISP_LOGCONFIG, prom0, bus, lp->portid, lp->handle, isp_class3_roles[lp->roles], "departed", (ull) lp->node_wwn, (ull) lp->port_wwn); } break; @@ -3786,6 +3782,16 @@ isplinux_timer(unsigned long arg) isp->isp_osinfo.dqnext = isp->isp_osinfo.dqtail = NULL; } + /* + * Check for any rescan activity that needs running + */ + if (isp->isp_osinfo.scan_timeout && --isp->isp_osinfo.scan_timeout == 0) { + isp_thread_event(isp, ISP_THREAD_SCSI_SCAN, (void *)1, 0, __func__, __LINE__); + } + if (isp->isp_osinfo.rescan_timeout && --isp->isp_osinfo.rescan_timeout == 0) { + isp_thread_event(isp, ISP_THREAD_SCSI_SCAN, (void *)0, 0, __func__, __LINE__); + } + /* * Set up the timer again */ @@ -4262,6 +4268,7 @@ isplinux_reinit(ispsoftc_t *isp, int doset_defaults) * Bus Reset delay handled by firmware. */ } + isp->mbintsok = 1; isp->isp_state = ISP_RUNSTATE; return (0); } @@ -4332,6 +4339,48 @@ isp_thread_event(ispsoftc_t *isp, int action, void *a, int dowait, const char *f return (0); } +static void +isp_scsi_scan(ispsoftc_t *isp) +{ + unsigned long flags; + int chan, tgt, i; + + if (!IS_FC(isp)) { + return; + } + + ISP_LOCKU_SOFTC(isp); + for (chan = 0; chan < isp->isp_nchan; chan++) { + fcparam *fcp = FCPARAM(isp, chan); + for (i = 0; i < MAX_FC_TARG; i++) { + fcportdb_t *lp = &fcp->portdb[i]; + if (lp->dev_map_idx == 0) { + continue; + } + tgt = lp->dev_map_idx - 1; + if (lp->state == FC_PORTDB_STATE_VALID && lp->dirty == 0) { + ISP_UNLKU_SOFTC(isp); + scsi_scan_target(&isp->isp_osinfo.host->shost_gendev, chan, tgt, 0, 0); + ISP_LOCKU_SOFTC(isp); + } else if (lp->state == FC_PORTDB_STATE_ZOMBIE) { + struct scsi_device *sdev; + fcp->isp_dev_map[tgt] = 0; + lp->state = FC_PORTDB_STATE_NIL; + lp->dev_map_idx = 0; + lp->dirty = 0; + ISP_UNLKU_SOFTC(isp); + sdev = scsi_device_lookup(isp->isp_osinfo.host, 0, tgt, 0); + if (sdev) { + scsi_remove_device(sdev); + scsi_device_put(sdev); + } + ISP_LOCKU_SOFTC(isp); + } + } + } + ISP_UNLKU_SOFTC(isp); +} + static int isp_task_thread(void *arg) { @@ -4365,24 +4414,8 @@ isp_task_thread(void *arg) case ISP_THREAD_NIL: break; case ISP_THREAD_SCSI_SCAN: - { - unsigned long arg = (unsigned long) tap->arg; - int tgt, chan, rescan; - tgt = arg & 0xffff; - chan = (arg >> 16) & 0xff; - rescan = (arg >> 31) & 1; - if (rescan == 0) { - scsi_scan_target(&isp->isp_osinfo.host->shost_gendev, chan, tgt, 0, rescan); - } else { - struct scsi_device *sdev; - sdev = scsi_device_lookup(isp->isp_osinfo.host, 0, tgt, 0); - if (sdev) { - scsi_remove_device(sdev); - scsi_device_put(sdev); - } - } + isp_scsi_scan(isp); break; - } case ISP_THREAD_REINIT: ISP_LOCKU_SOFTC(isp); if (isp->isp_dead) { diff --git a/qla_isp/linux/isp_linux.h b/qla_isp/linux/isp_linux.h index 02ef660a6..59a77a80a 100644 --- a/qla_isp/linux/isp_linux.h +++ b/qla_isp/linux/isp_linux.h @@ -1,4 +1,4 @@ -/* $Id: isp_linux.h,v 1.173 2009/05/10 16:25:09 mjacob Exp $ */ +/* $Id: isp_linux.h,v 1.174 2009/06/07 04:36:38 mjacob Exp $ */ /* * Copyright (c) 1997-2009 by Matthew Jacob * All rights reserved. @@ -339,6 +339,8 @@ struct isposinfo { mboxcmd_done : 1, mbintsok : 1, intsok : 1; + u16 scan_timeout; + u16 rescan_timeout; u16 frame_size; u16 exec_throttle; struct task_struct *thread_task; @@ -698,6 +700,8 @@ extern int api_channel; #define ISP_WATCH_TPS 10 #define ISP_WATCH_TIME (HZ / ISP_WATCH_TPS) +#define ISP_SCAN_TIMEOUT (2 * ISP_WATCH_TPS) +#define ISP_RESCAN_TIMEOUT ISP_WATCH_TPS #ifndef min #define min(a,b) (((a)<(b))?(a):(b)) diff --git a/qla_isp/linux/isp_pci.c b/qla_isp/linux/isp_pci.c index cf32e5bc5..afa5570b7 100644 --- a/qla_isp/linux/isp_pci.c +++ b/qla_isp/linux/isp_pci.c @@ -122,28 +122,52 @@ static int isplinux_pci_exclude(struct pci_dev *); #if defined(DISABLE_FW_LOADER) || !(defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)) #ifndef ISP_DISABLE_1020_SUPPORT #include "asm_1040.h" +#undef ISP_1040_RISC_CODE +#define ISP_1040_RISC_CODE (const uint16_t *) isp_1040_risc_code #endif #ifndef ISP_DISABLE_1080_SUPPORT #include "asm_1080.h" +#undef ISP_1080_RISC_CODE +#define ISP_1080_RISC_CODE (const uint16_t *) isp_1080_risc_code #endif #ifndef ISP_DISABLE_12160_SUPPORT #include "asm_12160.h" +#undef ISP_12160_RISC_CODE +#define ISP_12160_RISC_CODE (const uint16_t *) isp_12160_risc_code #endif #ifndef ISP_DISABLE_2100_SUPPORT #include "asm_2100.h" +#undef ISP_2100_RISC_CODE +#define ISP_2100_RISC_CODE (const uint16_t *) isp_2100_risc_code #endif #ifndef ISP_DISABLE_2200_SUPPORT #include "asm_2200.h" +#undef ISP_2200_RISC_CODE +#define ISP_2200_RISC_CODE (const uint16_t *) isp_2200_risc_code #endif #ifndef ISP_DISABLE_2300_SUPPORT #include "asm_2300.h" +#undef ISP_2300_RISC_CODE +#define ISP_2300_RISC_CODE (const uint16_t *) isp_2300_risc_code #endif #ifndef ISP_DISABLE_2322_SUPPORT #include "asm_2322.h" +#undef ISP_2322_RISC_CODE +#define ISP_2322_RISC_CODE (const uint16_t *) isp_2322_risc_code #endif #ifndef ISP_DISABLE_2400_SUPPORT +#define ISP_2400 +#define ISP_2400_MULTI +#define ISP_2500 +#define ISP_2500_MULTI #include "asm_2400.h" #include "asm_2500.h" +#undef ISP_2400_RISC_CODE +#undef ISP_2500_RISC_CODE +#define ISP_2400_RISC_CODE (const uint32_t *) isp_2400_risc_code +#define ISP_2500_RISC_CODE (const uint32_t *) isp_2500_risc_code +#define ISP_2400_MULTI_RISC_CODE (const uint32_t *) isp_2400_multi_risc_code +#define ISP_2500_MULTI_RISC_CODE (const uint32_t *) isp_2500_multi_risc_code #endif #endif @@ -939,6 +963,14 @@ isplinux_pci_init_one(struct Scsi_Host *host) isp->isp_osinfo.fwp = NULL; } } +#else + if (isp_vports) { + if (IS_25XX(isp)) { + isp->isp_mdvec->dv_ispfw = ISP_2500_MULTI_RISC_CODE; + } else if (IS_24XX(isp)) { + isp->isp_mdvec->dv_ispfw = ISP_2400_MULTI_RISC_CODE; + } + } #endif if (isplinux_common_init(isp)) { @@ -1855,7 +1887,10 @@ isp_pci_reset1(ispsoftc_t *isp) } ISP_ENABLE_INTS(isp); isp->intsok = 1; - isp->mbintsok = 1; + /* + * We used to enable mbintsok here. + * This seemed to nuke 24XX cards in some, but not all cases. + */ } static void @@ -2169,6 +2204,8 @@ isplinux_pci_init(void) ret = pci_register_driver(&isplinux_pci_driver); if (ret < 0) { printk(KERN_ERR "%s: unable to register driver (return value %d)", __func__, ret); + DESTROY_ISP_CLASS(isp_class); + cdev_del(&isp_cdev); unregister_chrdev_region(isp_dev, MAX_ISP); return (ret); }