1c3aac50fSPeter Wemm /* $FreeBSD$ */ 26054c3f6SMatt Jacob /* 36054c3f6SMatt Jacob * Platform (FreeBSD) dependent common attachment code for Qlogic adapters. 46054c3f6SMatt Jacob * 55f5aafe1SMatt Jacob * Copyright (c) 1997, 1998, 1999, 2000, 2001 by Matthew Jacob 66054c3f6SMatt Jacob * 76054c3f6SMatt Jacob * Redistribution and use in source and binary forms, with or without 86054c3f6SMatt Jacob * modification, are permitted provided that the following conditions 96054c3f6SMatt Jacob * are met: 106054c3f6SMatt Jacob * 1. Redistributions of source code must retain the above copyright 116054c3f6SMatt Jacob * notice immediately at the beginning of the file, without modification, 126054c3f6SMatt Jacob * this list of conditions, and the following disclaimer. 13aa57fd6fSMatt Jacob * 2. The name of the author may not be used to endorse or promote products 14aa57fd6fSMatt Jacob * derived from this software without specific prior written permission. 156054c3f6SMatt Jacob * 166054c3f6SMatt Jacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 176054c3f6SMatt Jacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 186054c3f6SMatt Jacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 196054c3f6SMatt Jacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 206054c3f6SMatt Jacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 216054c3f6SMatt Jacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 226054c3f6SMatt Jacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 236054c3f6SMatt Jacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 246054c3f6SMatt Jacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 256054c3f6SMatt Jacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 266054c3f6SMatt Jacob * SUCH DAMAGE. 276054c3f6SMatt Jacob */ 286054c3f6SMatt Jacob #include <dev/isp/isp_freebsd.h> 295d571944SMatt Jacob #include <sys/unistd.h> 305d571944SMatt Jacob #include <sys/kthread.h> 313ea883b4SMatt Jacob #include <machine/stdarg.h> /* for use by isp_prt below */ 325d571944SMatt Jacob #include <sys/conf.h> 334eb49427SMatt Jacob #include <sys/module.h> 345d571944SMatt Jacob #include <sys/ioccom.h> 355d571944SMatt Jacob #include <dev/isp/isp_ioctl.h> 366054c3f6SMatt Jacob 37a1bc34c6SMatt Jacob 384eb49427SMatt Jacob MODULE_VERSION(isp, 1); 3973030e03SMatt Jacob int isp_announced = 0; 4073030e03SMatt Jacob ispfwfunc *isp_get_firmware_p = NULL; 4173030e03SMatt Jacob 425d571944SMatt Jacob static d_ioctl_t ispioctl; 43f6e75de2SMatt Jacob static void isp_intr_enable(void *); 440470d791SMatt Jacob static void isp_cam_async(void *, u_int32_t, struct cam_path *, void *); 450470d791SMatt Jacob static void isp_poll(struct cam_sim *); 46b85389e1SMatt Jacob static timeout_t isp_watchdog; 475d571944SMatt Jacob static void isp_kthread(void *); 48d81ba9d5SMatt Jacob static void isp_action(struct cam_sim *, union ccb *); 490470d791SMatt Jacob 50cc8df88bSMatt Jacob 515d571944SMatt Jacob #define ISP_CDEV_MAJOR 248 525d571944SMatt Jacob static struct cdevsw isp_cdevsw = { 535d571944SMatt Jacob /* open */ nullopen, 545d571944SMatt Jacob /* close */ nullclose, 555d571944SMatt Jacob /* read */ noread, 565d571944SMatt Jacob /* write */ nowrite, 575d571944SMatt Jacob /* ioctl */ ispioctl, 585d571944SMatt Jacob /* poll */ nopoll, 595d571944SMatt Jacob /* mmap */ nommap, 605d571944SMatt Jacob /* strategy */ nostrategy, 615d571944SMatt Jacob /* name */ "isp", 625d571944SMatt Jacob /* maj */ ISP_CDEV_MAJOR, 635d571944SMatt Jacob /* dump */ nodump, 645d571944SMatt Jacob /* psize */ nopsize, 655d571944SMatt Jacob /* flags */ D_TAPE, 665d571944SMatt Jacob }; 675d571944SMatt Jacob 68d81ba9d5SMatt Jacob static struct ispsoftc *isplist = NULL; 69478f8a96SJustin T. Gibbs 70478f8a96SJustin T. Gibbs void 71c3055363SMatt Jacob isp_attach(struct ispsoftc *isp) 72478f8a96SJustin T. Gibbs { 73ea6f23cdSMatt Jacob int primary, secondary; 74478f8a96SJustin T. Gibbs struct ccb_setasync csa; 75478f8a96SJustin T. Gibbs struct cam_devq *devq; 76ea6f23cdSMatt Jacob struct cam_sim *sim; 77ea6f23cdSMatt Jacob struct cam_path *path; 78478f8a96SJustin T. Gibbs 79478f8a96SJustin T. Gibbs /* 80ea6f23cdSMatt Jacob * Establish (in case of 12X0) which bus is the primary. 81ea6f23cdSMatt Jacob */ 82ea6f23cdSMatt Jacob 83ea6f23cdSMatt Jacob primary = 0; 84ea6f23cdSMatt Jacob secondary = 1; 85ea6f23cdSMatt Jacob 86ea6f23cdSMatt Jacob /* 87ea6f23cdSMatt Jacob * Create the device queue for our SIM(s). 88478f8a96SJustin T. Gibbs */ 89ab6c4b31SMatt Jacob devq = cam_simq_alloc(isp->isp_maxcmds); 90478f8a96SJustin T. Gibbs if (devq == NULL) { 91478f8a96SJustin T. Gibbs return; 92478f8a96SJustin T. Gibbs } 93478f8a96SJustin T. Gibbs 94478f8a96SJustin T. Gibbs /* 95ea6f23cdSMatt Jacob * Construct our SIM entry. 96478f8a96SJustin T. Gibbs */ 9745c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 98ea6f23cdSMatt Jacob sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp, 993c75bb14SMatt Jacob device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq); 100ea6f23cdSMatt Jacob if (sim == NULL) { 101478f8a96SJustin T. Gibbs cam_simq_free(devq); 10245c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 103478f8a96SJustin T. Gibbs return; 104478f8a96SJustin T. Gibbs } 10545c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 106f6e75de2SMatt Jacob 107f6e75de2SMatt Jacob isp->isp_osinfo.ehook.ich_func = isp_intr_enable; 108f6e75de2SMatt Jacob isp->isp_osinfo.ehook.ich_arg = isp; 10945c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 110f6e75de2SMatt Jacob if (config_intrhook_establish(&isp->isp_osinfo.ehook) != 0) { 11145c9a36aSMatt Jacob cam_sim_free(sim, TRUE); 11245c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 113bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 114bfbab170SMatt Jacob "could not establish interrupt enable hook"); 115f6e75de2SMatt Jacob return; 116f6e75de2SMatt Jacob } 117f6e75de2SMatt Jacob 118ea6f23cdSMatt Jacob if (xpt_bus_register(sim, primary) != CAM_SUCCESS) { 119ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 12045c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 121478f8a96SJustin T. Gibbs return; 122478f8a96SJustin T. Gibbs } 123478f8a96SJustin T. Gibbs 124ea6f23cdSMatt Jacob if (xpt_create_path(&path, NULL, cam_sim_path(sim), 125478f8a96SJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 126ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 127ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 1285d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 12945c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 130478f8a96SJustin T. Gibbs return; 131478f8a96SJustin T. Gibbs } 132478f8a96SJustin T. Gibbs 133ea6f23cdSMatt Jacob xpt_setup_ccb(&csa.ccb_h, path, 5); 134478f8a96SJustin T. Gibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 135478f8a96SJustin T. Gibbs csa.event_enable = AC_LOST_DEVICE; 136cbf57b47SMatt Jacob csa.callback = isp_cam_async; 137ea6f23cdSMatt Jacob csa.callback_arg = sim; 138478f8a96SJustin T. Gibbs xpt_action((union ccb *)&csa); 13945c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 140ea6f23cdSMatt Jacob isp->isp_sim = sim; 141ea6f23cdSMatt Jacob isp->isp_path = path; 1425d571944SMatt Jacob /* 1435d571944SMatt Jacob * Create a kernel thread for fibre channel instances. We 1445d571944SMatt Jacob * don't have dual channel FC cards. 1455d571944SMatt Jacob */ 1465d571944SMatt Jacob if (IS_FC(isp)) { 14745c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 14845c9a36aSMatt Jacob /* XXX: LOCK VIOLATION */ 1495d571944SMatt Jacob cv_init(&isp->isp_osinfo.kthread_cv, "isp_kthread_cv"); 1505d571944SMatt Jacob if (kthread_create(isp_kthread, isp, &isp->isp_osinfo.kproc, 1515d571944SMatt Jacob RFHIGHPID, "%s: fc_thrd", 1525d571944SMatt Jacob device_get_nameunit(isp->isp_dev))) { 1535d571944SMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 1545d571944SMatt Jacob cam_sim_free(sim, TRUE); 1555d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 15645c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 15745c9a36aSMatt Jacob isp_prt(isp, ISP_LOGERR, "could not create kthread"); 1585d571944SMatt Jacob return; 1595d571944SMatt Jacob } 1608e6a12fcSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 1615d571944SMatt Jacob } 1625d571944SMatt Jacob 163478f8a96SJustin T. Gibbs 164ea6f23cdSMatt Jacob /* 165ea6f23cdSMatt Jacob * If we have a second channel, construct SIM entry for that. 166ea6f23cdSMatt Jacob */ 16722e1dc85SMatt Jacob if (IS_DUALBUS(isp)) { 16845c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 169ea6f23cdSMatt Jacob sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp, 1703c75bb14SMatt Jacob device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq); 171ea6f23cdSMatt Jacob if (sim == NULL) { 172ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 173ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 174ea6f23cdSMatt Jacob cam_simq_free(devq); 1755d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 176ea6f23cdSMatt Jacob return; 177ea6f23cdSMatt Jacob } 178ea6f23cdSMatt Jacob if (xpt_bus_register(sim, secondary) != CAM_SUCCESS) { 179ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 180ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 181ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 1825d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 18345c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 184ea6f23cdSMatt Jacob return; 185ea6f23cdSMatt Jacob } 186ea6f23cdSMatt Jacob 187ea6f23cdSMatt Jacob if (xpt_create_path(&path, NULL, cam_sim_path(sim), 188ea6f23cdSMatt Jacob CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 189ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 190ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 191ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 192ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 1935d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 19445c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 195ea6f23cdSMatt Jacob return; 196ea6f23cdSMatt Jacob } 197ea6f23cdSMatt Jacob 198ea6f23cdSMatt Jacob xpt_setup_ccb(&csa.ccb_h, path, 5); 199ea6f23cdSMatt Jacob csa.ccb_h.func_code = XPT_SASYNC_CB; 200ea6f23cdSMatt Jacob csa.event_enable = AC_LOST_DEVICE; 201ea6f23cdSMatt Jacob csa.callback = isp_cam_async; 202ea6f23cdSMatt Jacob csa.callback_arg = sim; 203ea6f23cdSMatt Jacob xpt_action((union ccb *)&csa); 20445c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 205ea6f23cdSMatt Jacob isp->isp_sim2 = sim; 206ea6f23cdSMatt Jacob isp->isp_path2 = path; 207ea6f23cdSMatt Jacob } 2085d571944SMatt Jacob 20964edff94SMatt Jacob #ifdef ISP_TARGET_MODE 21064edff94SMatt Jacob cv_init(&isp->isp_osinfo.tgtcv0[0], "isp_tgcv0a"); 21164edff94SMatt Jacob cv_init(&isp->isp_osinfo.tgtcv0[1], "isp_tgcv0b"); 21264edff94SMatt Jacob cv_init(&isp->isp_osinfo.tgtcv1[0], "isp_tgcv1a"); 21364edff94SMatt Jacob cv_init(&isp->isp_osinfo.tgtcv1[1], "isp_tgcv1b"); 21464edff94SMatt Jacob #endif 2155d571944SMatt Jacob /* 2165d571944SMatt Jacob * Create device nodes 2175d571944SMatt Jacob */ 2185d571944SMatt Jacob (void) make_dev(&isp_cdevsw, device_get_unit(isp->isp_dev), UID_ROOT, 2195d571944SMatt Jacob GID_OPERATOR, 0600, "%s", device_get_nameunit(isp->isp_dev)); 2205d571944SMatt Jacob 221d6e5500fSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE) { 222478f8a96SJustin T. Gibbs isp->isp_state = ISP_RUNSTATE; 223b85389e1SMatt Jacob ENABLE_INTS(isp); 224d6e5500fSMatt Jacob } 225d81ba9d5SMatt Jacob if (isplist == NULL) { 226d81ba9d5SMatt Jacob isplist = isp; 227d81ba9d5SMatt Jacob } else { 228d81ba9d5SMatt Jacob struct ispsoftc *tmp = isplist; 229d81ba9d5SMatt Jacob while (tmp->isp_osinfo.next) { 230d81ba9d5SMatt Jacob tmp = tmp->isp_osinfo.next; 231d81ba9d5SMatt Jacob } 232d81ba9d5SMatt Jacob tmp->isp_osinfo.next = isp; 233478f8a96SJustin T. Gibbs } 2345d571944SMatt Jacob 2355d571944SMatt Jacob } 2365d571944SMatt Jacob 237fdeb9f2fSMatt Jacob static __inline void 238fdeb9f2fSMatt Jacob isp_freeze_loopdown(struct ispsoftc *isp, char *msg) 239fdeb9f2fSMatt Jacob { 240fdeb9f2fSMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 241fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "%s: freeze simq (loopdown)", msg); 242fdeb9f2fSMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; 243fdeb9f2fSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 244fdeb9f2fSMatt Jacob xpt_freeze_simq(isp->isp_sim, 1); 245fdeb9f2fSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 246fdeb9f2fSMatt Jacob } else { 247fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "%s: mark frozen (loopdown)", msg); 248fdeb9f2fSMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; 249fdeb9f2fSMatt Jacob } 250fdeb9f2fSMatt Jacob } 251fdeb9f2fSMatt Jacob 2525d571944SMatt Jacob static int 253b40ce416SJulian Elischer ispioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 2545d571944SMatt Jacob { 2555d571944SMatt Jacob struct ispsoftc *isp; 2565d571944SMatt Jacob int retval = ENOTTY; 2575d571944SMatt Jacob 2585d571944SMatt Jacob isp = isplist; 2595d571944SMatt Jacob while (isp) { 2605d571944SMatt Jacob if (minor(dev) == device_get_unit(isp->isp_dev)) { 2615d571944SMatt Jacob break; 2625d571944SMatt Jacob } 2635d571944SMatt Jacob isp = isp->isp_osinfo.next; 2645d571944SMatt Jacob } 2655d571944SMatt Jacob if (isp == NULL) 2665d571944SMatt Jacob return (ENXIO); 2675d571944SMatt Jacob 2685d571944SMatt Jacob switch (cmd) { 269d134aa0bSMatt Jacob #ifdef ISP_FW_CRASH_DUMP 270d134aa0bSMatt Jacob case ISP_GET_FW_CRASH_DUMP: 271d134aa0bSMatt Jacob { 272d134aa0bSMatt Jacob u_int16_t *ptr = FCPARAM(isp)->isp_dump_data; 273d134aa0bSMatt Jacob size_t sz; 274d134aa0bSMatt Jacob 275d134aa0bSMatt Jacob retval = 0; 276d134aa0bSMatt Jacob if (IS_2200(isp)) 277d134aa0bSMatt Jacob sz = QLA2200_RISC_IMAGE_DUMP_SIZE; 278d134aa0bSMatt Jacob else 279d134aa0bSMatt Jacob sz = QLA2300_RISC_IMAGE_DUMP_SIZE; 280d134aa0bSMatt Jacob ISP_LOCK(isp); 281d134aa0bSMatt Jacob if (ptr && *ptr) { 282d134aa0bSMatt Jacob void *uaddr = *((void **) addr); 283d134aa0bSMatt Jacob if (copyout(ptr, uaddr, sz)) { 284d134aa0bSMatt Jacob retval = EFAULT; 285d134aa0bSMatt Jacob } else { 286d134aa0bSMatt Jacob *ptr = 0; 287d134aa0bSMatt Jacob } 288d134aa0bSMatt Jacob } else { 289d134aa0bSMatt Jacob retval = ENXIO; 290d134aa0bSMatt Jacob } 291d134aa0bSMatt Jacob ISP_UNLOCK(isp); 292d134aa0bSMatt Jacob break; 293d134aa0bSMatt Jacob } 294d134aa0bSMatt Jacob 295d134aa0bSMatt Jacob case ISP_FORCE_CRASH_DUMP: 296d134aa0bSMatt Jacob ISP_LOCK(isp); 297fdeb9f2fSMatt Jacob isp_freeze_loopdown(isp, "ispioctl(ISP_FORCE_CRASH_DUMP)"); 298d134aa0bSMatt Jacob isp_fw_dump(isp); 299d134aa0bSMatt Jacob isp_reinit(isp); 300d134aa0bSMatt Jacob ISP_UNLOCK(isp); 301d134aa0bSMatt Jacob retval = 0; 302d134aa0bSMatt Jacob break; 303d134aa0bSMatt Jacob #endif 3045d571944SMatt Jacob case ISP_SDBLEV: 3055d571944SMatt Jacob { 3065d571944SMatt Jacob int olddblev = isp->isp_dblev; 3075d571944SMatt Jacob isp->isp_dblev = *(int *)addr; 3085d571944SMatt Jacob *(int *)addr = olddblev; 3095d571944SMatt Jacob retval = 0; 3105d571944SMatt Jacob break; 3115d571944SMatt Jacob } 3125d571944SMatt Jacob case ISP_RESETHBA: 3135d571944SMatt Jacob ISP_LOCK(isp); 3145d571944SMatt Jacob isp_reinit(isp); 3155d571944SMatt Jacob ISP_UNLOCK(isp); 3165d571944SMatt Jacob retval = 0; 3175d571944SMatt Jacob break; 318f553351eSMatt Jacob case ISP_RESCAN: 3195d571944SMatt Jacob if (IS_FC(isp)) { 3205d571944SMatt Jacob ISP_LOCK(isp); 3215d571944SMatt Jacob if (isp_fc_runstate(isp, 5 * 1000000)) { 3225d571944SMatt Jacob retval = EIO; 3235d571944SMatt Jacob } else { 3245d571944SMatt Jacob retval = 0; 3255d571944SMatt Jacob } 3265d571944SMatt Jacob ISP_UNLOCK(isp); 3275d571944SMatt Jacob } 3285d571944SMatt Jacob break; 3295d571944SMatt Jacob case ISP_FC_LIP: 3305d571944SMatt Jacob if (IS_FC(isp)) { 3315d571944SMatt Jacob ISP_LOCK(isp); 3325d571944SMatt Jacob if (isp_control(isp, ISPCTL_SEND_LIP, 0)) { 3335d571944SMatt Jacob retval = EIO; 3345d571944SMatt Jacob } else { 3355d571944SMatt Jacob retval = 0; 3365d571944SMatt Jacob } 3375d571944SMatt Jacob ISP_UNLOCK(isp); 3385d571944SMatt Jacob } 3395d571944SMatt Jacob break; 3405d571944SMatt Jacob case ISP_FC_GETDINFO: 3415d571944SMatt Jacob { 3425d571944SMatt Jacob struct isp_fc_device *ifc = (struct isp_fc_device *) addr; 3435d571944SMatt Jacob struct lportdb *lp; 3445d571944SMatt Jacob 3455d571944SMatt Jacob if (ifc->loopid < 0 || ifc->loopid >= MAX_FC_TARG) { 3465d571944SMatt Jacob retval = EINVAL; 3475d571944SMatt Jacob break; 3485d571944SMatt Jacob } 3495d571944SMatt Jacob ISP_LOCK(isp); 3505d571944SMatt Jacob lp = &FCPARAM(isp)->portdb[ifc->loopid]; 3515d571944SMatt Jacob if (lp->valid) { 3525d571944SMatt Jacob ifc->loopid = lp->loopid; 3535d571944SMatt Jacob ifc->portid = lp->portid; 3545d571944SMatt Jacob ifc->node_wwn = lp->node_wwn; 3555d571944SMatt Jacob ifc->port_wwn = lp->port_wwn; 3565d571944SMatt Jacob retval = 0; 3575d571944SMatt Jacob } else { 3585d571944SMatt Jacob retval = ENODEV; 3595d571944SMatt Jacob } 3605d571944SMatt Jacob ISP_UNLOCK(isp); 3615d571944SMatt Jacob break; 3625d571944SMatt Jacob } 3632903b272SMatt Jacob case ISP_GET_STATS: 3642903b272SMatt Jacob { 3652903b272SMatt Jacob isp_stats_t *sp = (isp_stats_t *) addr; 3662903b272SMatt Jacob 3672903b272SMatt Jacob MEMZERO(sp, sizeof (*sp)); 3682903b272SMatt Jacob sp->isp_stat_version = ISP_STATS_VERSION; 3692903b272SMatt Jacob sp->isp_type = isp->isp_type; 3702903b272SMatt Jacob sp->isp_revision = isp->isp_revision; 3712903b272SMatt Jacob ISP_LOCK(isp); 3722903b272SMatt Jacob sp->isp_stats[ISP_INTCNT] = isp->isp_intcnt; 3732903b272SMatt Jacob sp->isp_stats[ISP_INTBOGUS] = isp->isp_intbogus; 3742903b272SMatt Jacob sp->isp_stats[ISP_INTMBOXC] = isp->isp_intmboxc; 3752903b272SMatt Jacob sp->isp_stats[ISP_INGOASYNC] = isp->isp_intoasync; 3762903b272SMatt Jacob sp->isp_stats[ISP_RSLTCCMPLT] = isp->isp_rsltccmplt; 3772903b272SMatt Jacob sp->isp_stats[ISP_FPHCCMCPLT] = isp->isp_fphccmplt; 3782903b272SMatt Jacob sp->isp_stats[ISP_RSCCHIWAT] = isp->isp_rscchiwater; 3792903b272SMatt Jacob sp->isp_stats[ISP_FPCCHIWAT] = isp->isp_fpcchiwater; 3802903b272SMatt Jacob ISP_UNLOCK(isp); 3812903b272SMatt Jacob retval = 0; 3822903b272SMatt Jacob break; 3832903b272SMatt Jacob } 3842903b272SMatt Jacob case ISP_CLR_STATS: 3852903b272SMatt Jacob ISP_LOCK(isp); 3862903b272SMatt Jacob isp->isp_intcnt = 0; 3872903b272SMatt Jacob isp->isp_intbogus = 0; 3882903b272SMatt Jacob isp->isp_intmboxc = 0; 3892903b272SMatt Jacob isp->isp_intoasync = 0; 3902903b272SMatt Jacob isp->isp_rsltccmplt = 0; 3912903b272SMatt Jacob isp->isp_fphccmplt = 0; 3922903b272SMatt Jacob isp->isp_rscchiwater = 0; 3932903b272SMatt Jacob isp->isp_fpcchiwater = 0; 3942903b272SMatt Jacob ISP_UNLOCK(isp); 3952903b272SMatt Jacob retval = 0; 3962903b272SMatt Jacob break; 397570c7a3fSMatt Jacob case ISP_FC_GETHINFO: 398570c7a3fSMatt Jacob { 399570c7a3fSMatt Jacob struct isp_hba_device *hba = (struct isp_hba_device *) addr; 400570c7a3fSMatt Jacob MEMZERO(hba, sizeof (*hba)); 401570c7a3fSMatt Jacob ISP_LOCK(isp); 402570c7a3fSMatt Jacob hba->fc_speed = FCPARAM(isp)->isp_gbspeed; 403570c7a3fSMatt Jacob hba->fc_scsi_supported = 1; 404570c7a3fSMatt Jacob hba->fc_topology = FCPARAM(isp)->isp_topo + 1; 405570c7a3fSMatt Jacob hba->fc_loopid = FCPARAM(isp)->isp_loopid; 406570c7a3fSMatt Jacob hba->active_node_wwn = FCPARAM(isp)->isp_nodewwn; 407570c7a3fSMatt Jacob hba->active_port_wwn = FCPARAM(isp)->isp_portwwn; 408570c7a3fSMatt Jacob ISP_UNLOCK(isp); 409570c7a3fSMatt Jacob retval = 0; 410570c7a3fSMatt Jacob break; 411570c7a3fSMatt Jacob } 412fdeb9f2fSMatt Jacob case ISP_GET_FC_PARAM: 413fdeb9f2fSMatt Jacob { 414fdeb9f2fSMatt Jacob struct isp_fc_param *f = (struct isp_fc_param *) addr; 415fdeb9f2fSMatt Jacob 416fdeb9f2fSMatt Jacob if (!IS_FC(isp)) { 417fdeb9f2fSMatt Jacob retval = EINVAL; 418fdeb9f2fSMatt Jacob break; 419fdeb9f2fSMatt Jacob } 420fdeb9f2fSMatt Jacob f->parameter = 0; 421fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "framelength") == 0) { 422fdeb9f2fSMatt Jacob f->parameter = FCPARAM(isp)->isp_maxfrmlen; 423fdeb9f2fSMatt Jacob retval = 0; 424fdeb9f2fSMatt Jacob break; 425fdeb9f2fSMatt Jacob } 426fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "exec_throttle") == 0) { 427fdeb9f2fSMatt Jacob f->parameter = FCPARAM(isp)->isp_execthrottle; 428fdeb9f2fSMatt Jacob retval = 0; 429fdeb9f2fSMatt Jacob break; 430fdeb9f2fSMatt Jacob } 431fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "fullduplex") == 0) { 432fdeb9f2fSMatt Jacob if (FCPARAM(isp)->isp_fwoptions & ICBOPT_FULL_DUPLEX) 433fdeb9f2fSMatt Jacob f->parameter = 1; 434fdeb9f2fSMatt Jacob retval = 0; 435fdeb9f2fSMatt Jacob break; 436fdeb9f2fSMatt Jacob } 437fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "loopid") == 0) { 438fdeb9f2fSMatt Jacob f->parameter = FCPARAM(isp)->isp_loopid; 439fdeb9f2fSMatt Jacob retval = 0; 440fdeb9f2fSMatt Jacob break; 441fdeb9f2fSMatt Jacob } 442fdeb9f2fSMatt Jacob retval = EINVAL; 443fdeb9f2fSMatt Jacob break; 444fdeb9f2fSMatt Jacob } 445fdeb9f2fSMatt Jacob case ISP_SET_FC_PARAM: 446fdeb9f2fSMatt Jacob { 447fdeb9f2fSMatt Jacob struct isp_fc_param *f = (struct isp_fc_param *) addr; 448fdeb9f2fSMatt Jacob u_int32_t param = f->parameter; 449fdeb9f2fSMatt Jacob 450fdeb9f2fSMatt Jacob if (!IS_FC(isp)) { 451fdeb9f2fSMatt Jacob retval = EINVAL; 452fdeb9f2fSMatt Jacob break; 453fdeb9f2fSMatt Jacob } 454fdeb9f2fSMatt Jacob f->parameter = 0; 455fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "framelength") == 0) { 456fdeb9f2fSMatt Jacob if (param != 512 && param != 1024 && param != 1024) { 457fdeb9f2fSMatt Jacob retval = EINVAL; 458fdeb9f2fSMatt Jacob break; 459fdeb9f2fSMatt Jacob } 460fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_maxfrmlen = param; 461fdeb9f2fSMatt Jacob retval = 0; 462fdeb9f2fSMatt Jacob break; 463fdeb9f2fSMatt Jacob } 464fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "exec_throttle") == 0) { 465fdeb9f2fSMatt Jacob if (param < 16 || param > 255) { 466fdeb9f2fSMatt Jacob retval = EINVAL; 467fdeb9f2fSMatt Jacob break; 468fdeb9f2fSMatt Jacob } 469fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_execthrottle = param; 470fdeb9f2fSMatt Jacob retval = 0; 471fdeb9f2fSMatt Jacob break; 472fdeb9f2fSMatt Jacob } 473fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "fullduplex") == 0) { 474fdeb9f2fSMatt Jacob if (param != 0 && param != 1) { 475fdeb9f2fSMatt Jacob retval = EINVAL; 476fdeb9f2fSMatt Jacob break; 477fdeb9f2fSMatt Jacob } 478fdeb9f2fSMatt Jacob if (param) { 479fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_fwoptions |= 480fdeb9f2fSMatt Jacob ICBOPT_FULL_DUPLEX; 481fdeb9f2fSMatt Jacob } else { 482fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_fwoptions &= 483fdeb9f2fSMatt Jacob ~ICBOPT_FULL_DUPLEX; 484fdeb9f2fSMatt Jacob } 485fdeb9f2fSMatt Jacob retval = 0; 486fdeb9f2fSMatt Jacob break; 487fdeb9f2fSMatt Jacob } 488fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "loopid") == 0) { 489fdeb9f2fSMatt Jacob if (param < 0 || param > 125) { 490fdeb9f2fSMatt Jacob retval = EINVAL; 491fdeb9f2fSMatt Jacob break; 492fdeb9f2fSMatt Jacob } 493fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_loopid = param; 494fdeb9f2fSMatt Jacob retval = 0; 495fdeb9f2fSMatt Jacob break; 496fdeb9f2fSMatt Jacob } 497fdeb9f2fSMatt Jacob retval = EINVAL; 498fdeb9f2fSMatt Jacob break; 499fdeb9f2fSMatt Jacob } 5005d571944SMatt Jacob default: 5015d571944SMatt Jacob break; 5025d571944SMatt Jacob } 5035d571944SMatt Jacob return (retval); 5040470d791SMatt Jacob } 505478f8a96SJustin T. Gibbs 506f6e75de2SMatt Jacob static void 507f6e75de2SMatt Jacob isp_intr_enable(void *arg) 508f6e75de2SMatt Jacob { 509f6e75de2SMatt Jacob struct ispsoftc *isp = arg; 510d6e5500fSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE) { 511f6e75de2SMatt Jacob ENABLE_INTS(isp); 512f6e75de2SMatt Jacob isp->isp_osinfo.intsok = 1; 513d6e5500fSMatt Jacob } 514f6e75de2SMatt Jacob /* Release our hook so that the boot can continue. */ 515f6e75de2SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 516f6e75de2SMatt Jacob } 517d81ba9d5SMatt Jacob 518d81ba9d5SMatt Jacob /* 519d81ba9d5SMatt Jacob * Put the target mode functions here, because some are inlines 520d81ba9d5SMatt Jacob */ 521d81ba9d5SMatt Jacob 522d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 523d81ba9d5SMatt Jacob 524a1bc34c6SMatt Jacob static __inline int is_lun_enabled(struct ispsoftc *, int, lun_id_t); 525a1bc34c6SMatt Jacob static __inline int are_any_luns_enabled(struct ispsoftc *, int); 526a1bc34c6SMatt Jacob static __inline tstate_t *get_lun_statep(struct ispsoftc *, int, lun_id_t); 527d81ba9d5SMatt Jacob static __inline void rls_lun_statep(struct ispsoftc *, tstate_t *); 52864edff94SMatt Jacob static __inline int isp_psema_sig_rqe(struct ispsoftc *, int); 52964edff94SMatt Jacob static __inline int isp_cv_wait_timed_rqe(struct ispsoftc *, int, int); 53064edff94SMatt Jacob static __inline void isp_cv_signal_rqe(struct ispsoftc *, int, int); 53164edff94SMatt Jacob static __inline void isp_vsema_rqe(struct ispsoftc *, int); 53253036e92SMatt Jacob static __inline atio_private_data_t *isp_get_atpd(struct ispsoftc *, int); 533d81ba9d5SMatt Jacob static cam_status 534a1bc34c6SMatt Jacob create_lun_state(struct ispsoftc *, int, struct cam_path *, tstate_t **); 535d81ba9d5SMatt Jacob static void destroy_lun_state(struct ispsoftc *, tstate_t *); 536d81ba9d5SMatt Jacob static void isp_en_lun(struct ispsoftc *, union ccb *); 537d81ba9d5SMatt Jacob static cam_status isp_abort_tgt_ccb(struct ispsoftc *, union ccb *); 538f48ce188SMatt Jacob static timeout_t isp_refire_putback_atio; 539a1bc34c6SMatt Jacob static void isp_complete_ctio(union ccb *); 540a1bc34c6SMatt Jacob static void isp_target_putback_atio(union ccb *); 541a1bc34c6SMatt Jacob static cam_status isp_target_start_ctio(struct ispsoftc *, union ccb *); 542d81ba9d5SMatt Jacob static int isp_handle_platform_atio(struct ispsoftc *, at_entry_t *); 543d81ba9d5SMatt Jacob static int isp_handle_platform_atio2(struct ispsoftc *, at2_entry_t *); 544d81ba9d5SMatt Jacob static int isp_handle_platform_ctio(struct ispsoftc *, void *); 545570c7a3fSMatt Jacob static int isp_handle_platform_notify_scsi(struct ispsoftc *, in_entry_t *); 546570c7a3fSMatt Jacob static int isp_handle_platform_notify_fc(struct ispsoftc *, in_fcentry_t *); 547d81ba9d5SMatt Jacob 548d81ba9d5SMatt Jacob static __inline int 549a1bc34c6SMatt Jacob is_lun_enabled(struct ispsoftc *isp, int bus, lun_id_t lun) 550d81ba9d5SMatt Jacob { 551d81ba9d5SMatt Jacob tstate_t *tptr; 552a1bc34c6SMatt Jacob tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)]; 553a1bc34c6SMatt Jacob if (tptr == NULL) { 554d81ba9d5SMatt Jacob return (0); 555d81ba9d5SMatt Jacob } 556d81ba9d5SMatt Jacob do { 557a1bc34c6SMatt Jacob if (tptr->lun == (lun_id_t) lun && tptr->bus == bus) { 558d81ba9d5SMatt Jacob return (1); 559d81ba9d5SMatt Jacob } 560d81ba9d5SMatt Jacob } while ((tptr = tptr->next) != NULL); 561d81ba9d5SMatt Jacob return (0); 562d81ba9d5SMatt Jacob } 563d81ba9d5SMatt Jacob 564d81ba9d5SMatt Jacob static __inline int 565a1bc34c6SMatt Jacob are_any_luns_enabled(struct ispsoftc *isp, int port) 566d81ba9d5SMatt Jacob { 567a1bc34c6SMatt Jacob int lo, hi; 568a1bc34c6SMatt Jacob if (IS_DUALBUS(isp)) { 569a1bc34c6SMatt Jacob lo = (port * (LUN_HASH_SIZE >> 1)); 570a1bc34c6SMatt Jacob hi = lo + (LUN_HASH_SIZE >> 1); 571a1bc34c6SMatt Jacob } else { 572a1bc34c6SMatt Jacob lo = 0; 573a1bc34c6SMatt Jacob hi = LUN_HASH_SIZE; 574a1bc34c6SMatt Jacob } 575a1bc34c6SMatt Jacob for (lo = 0; lo < hi; lo++) { 576a1bc34c6SMatt Jacob if (isp->isp_osinfo.lun_hash[lo]) { 577d81ba9d5SMatt Jacob return (1); 578d81ba9d5SMatt Jacob } 579d81ba9d5SMatt Jacob } 580d81ba9d5SMatt Jacob return (0); 581d81ba9d5SMatt Jacob } 582d81ba9d5SMatt Jacob 583d81ba9d5SMatt Jacob static __inline tstate_t * 584a1bc34c6SMatt Jacob get_lun_statep(struct ispsoftc *isp, int bus, lun_id_t lun) 585d81ba9d5SMatt Jacob { 58664edff94SMatt Jacob tstate_t *tptr = NULL; 587d81ba9d5SMatt Jacob 588d81ba9d5SMatt Jacob if (lun == CAM_LUN_WILDCARD) { 58964edff94SMatt Jacob if (isp->isp_osinfo.tmflags[bus] & TM_WILDCARD_ENABLED) { 590a1bc34c6SMatt Jacob tptr = &isp->isp_osinfo.tsdflt[bus]; 591d81ba9d5SMatt Jacob tptr->hold++; 592d81ba9d5SMatt Jacob return (tptr); 593d81ba9d5SMatt Jacob } 594126ec864SMatt Jacob } else { 595126ec864SMatt Jacob tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)]; 59664edff94SMatt Jacob if (tptr == NULL) { 59764edff94SMatt Jacob return (NULL); 59864edff94SMatt Jacob } 599126ec864SMatt Jacob } 600d81ba9d5SMatt Jacob 601d81ba9d5SMatt Jacob do { 602a1bc34c6SMatt Jacob if (tptr->lun == lun && tptr->bus == bus) { 603d81ba9d5SMatt Jacob tptr->hold++; 604d81ba9d5SMatt Jacob return (tptr); 605d81ba9d5SMatt Jacob } 606d81ba9d5SMatt Jacob } while ((tptr = tptr->next) != NULL); 607d81ba9d5SMatt Jacob return (tptr); 608d81ba9d5SMatt Jacob } 609d81ba9d5SMatt Jacob 610d81ba9d5SMatt Jacob static __inline void 611d81ba9d5SMatt Jacob rls_lun_statep(struct ispsoftc *isp, tstate_t *tptr) 612d81ba9d5SMatt Jacob { 613d81ba9d5SMatt Jacob if (tptr->hold) 614d81ba9d5SMatt Jacob tptr->hold--; 615d81ba9d5SMatt Jacob } 616d81ba9d5SMatt Jacob 617d81ba9d5SMatt Jacob static __inline int 61864edff94SMatt Jacob isp_psema_sig_rqe(struct ispsoftc *isp, int bus) 619d81ba9d5SMatt Jacob { 62064edff94SMatt Jacob while (isp->isp_osinfo.tmflags[bus] & TM_BUSY) { 62164edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] |= TM_WANTED; 62264edff94SMatt Jacob if (cv_wait_sig(&isp->isp_osinfo.tgtcv0[bus], &isp->isp_lock)) { 623d81ba9d5SMatt Jacob return (-1); 624d81ba9d5SMatt Jacob } 62564edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] |= TM_BUSY; 626d81ba9d5SMatt Jacob } 627d81ba9d5SMatt Jacob return (0); 628d81ba9d5SMatt Jacob } 629d81ba9d5SMatt Jacob 630d81ba9d5SMatt Jacob static __inline int 63164edff94SMatt Jacob isp_cv_wait_timed_rqe(struct ispsoftc *isp, int bus, int timo) 632d81ba9d5SMatt Jacob { 63364edff94SMatt Jacob if (cv_timedwait(&isp->isp_osinfo.tgtcv1[bus], &isp->isp_lock, timo)) { 634d81ba9d5SMatt Jacob return (-1); 635d81ba9d5SMatt Jacob } 636d81ba9d5SMatt Jacob return (0); 637d81ba9d5SMatt Jacob } 638d81ba9d5SMatt Jacob 639d81ba9d5SMatt Jacob static __inline void 64064edff94SMatt Jacob isp_cv_signal_rqe(struct ispsoftc *isp, int bus, int status) 641d81ba9d5SMatt Jacob { 64264edff94SMatt Jacob isp->isp_osinfo.rstatus[bus] = status; 64364edff94SMatt Jacob cv_signal(&isp->isp_osinfo.tgtcv1[bus]); 644d81ba9d5SMatt Jacob } 645d81ba9d5SMatt Jacob 646d81ba9d5SMatt Jacob static __inline void 64764edff94SMatt Jacob isp_vsema_rqe(struct ispsoftc *isp, int bus) 648d81ba9d5SMatt Jacob { 64964edff94SMatt Jacob if (isp->isp_osinfo.tmflags[bus] & TM_WANTED) { 65064edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_WANTED; 65164edff94SMatt Jacob cv_signal(&isp->isp_osinfo.tgtcv0[bus]); 652d81ba9d5SMatt Jacob } 65364edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_BUSY; 654d81ba9d5SMatt Jacob } 655d81ba9d5SMatt Jacob 65653036e92SMatt Jacob static __inline atio_private_data_t * 65753036e92SMatt Jacob isp_get_atpd(struct ispsoftc *isp, int tag) 65853036e92SMatt Jacob { 65953036e92SMatt Jacob atio_private_data_t *atp; 66053036e92SMatt Jacob for (atp = isp->isp_osinfo.atpdp; 66153036e92SMatt Jacob atp < &isp->isp_osinfo.atpdp[ATPDPSIZE]; atp++) { 66253036e92SMatt Jacob if (atp->tag == tag) 66353036e92SMatt Jacob return (atp); 66453036e92SMatt Jacob } 66553036e92SMatt Jacob return (NULL); 66653036e92SMatt Jacob } 66753036e92SMatt Jacob 668d81ba9d5SMatt Jacob static cam_status 669a1bc34c6SMatt Jacob create_lun_state(struct ispsoftc *isp, int bus, 670a1bc34c6SMatt Jacob struct cam_path *path, tstate_t **rslt) 671d81ba9d5SMatt Jacob { 672d81ba9d5SMatt Jacob cam_status status; 673d81ba9d5SMatt Jacob lun_id_t lun; 674a1bc34c6SMatt Jacob int hfx; 675d81ba9d5SMatt Jacob tstate_t *tptr, *new; 676d81ba9d5SMatt Jacob 677d81ba9d5SMatt Jacob lun = xpt_path_lun_id(path); 678d81ba9d5SMatt Jacob if (lun < 0) { 679d81ba9d5SMatt Jacob return (CAM_LUN_INVALID); 680d81ba9d5SMatt Jacob } 681a1bc34c6SMatt Jacob if (is_lun_enabled(isp, bus, lun)) { 682d81ba9d5SMatt Jacob return (CAM_LUN_ALRDY_ENA); 683d81ba9d5SMatt Jacob } 684ea8b5a9aSDavid Malone new = (tstate_t *) malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO); 685d81ba9d5SMatt Jacob if (new == NULL) { 686d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 687d81ba9d5SMatt Jacob } 688d81ba9d5SMatt Jacob 689d81ba9d5SMatt Jacob status = xpt_create_path(&new->owner, NULL, xpt_path_path_id(path), 690d81ba9d5SMatt Jacob xpt_path_target_id(path), xpt_path_lun_id(path)); 691d81ba9d5SMatt Jacob if (status != CAM_REQ_CMP) { 692d81ba9d5SMatt Jacob free(new, M_DEVBUF); 693d81ba9d5SMatt Jacob return (status); 694d81ba9d5SMatt Jacob } 695a1bc34c6SMatt Jacob new->bus = bus; 696d81ba9d5SMatt Jacob new->lun = lun; 697d81ba9d5SMatt Jacob SLIST_INIT(&new->atios); 698d81ba9d5SMatt Jacob SLIST_INIT(&new->inots); 699d81ba9d5SMatt Jacob new->hold = 1; 700d81ba9d5SMatt Jacob 701a1bc34c6SMatt Jacob hfx = LUN_HASH_FUNC(isp, new->bus, new->lun); 702a1bc34c6SMatt Jacob tptr = isp->isp_osinfo.lun_hash[hfx]; 703a1bc34c6SMatt Jacob if (tptr == NULL) { 704a1bc34c6SMatt Jacob isp->isp_osinfo.lun_hash[hfx] = new; 705d81ba9d5SMatt Jacob } else { 706d81ba9d5SMatt Jacob while (tptr->next) 707d81ba9d5SMatt Jacob tptr = tptr->next; 708d81ba9d5SMatt Jacob tptr->next = new; 709d81ba9d5SMatt Jacob } 710d81ba9d5SMatt Jacob *rslt = new; 711d81ba9d5SMatt Jacob return (CAM_REQ_CMP); 712d81ba9d5SMatt Jacob } 713d81ba9d5SMatt Jacob 714d81ba9d5SMatt Jacob static __inline void 715d81ba9d5SMatt Jacob destroy_lun_state(struct ispsoftc *isp, tstate_t *tptr) 716d81ba9d5SMatt Jacob { 717a1bc34c6SMatt Jacob int hfx; 718d81ba9d5SMatt Jacob tstate_t *lw, *pw; 719d81ba9d5SMatt Jacob 720a1bc34c6SMatt Jacob hfx = LUN_HASH_FUNC(isp, tptr->bus, tptr->lun); 721d81ba9d5SMatt Jacob if (tptr->hold) { 722d81ba9d5SMatt Jacob return; 723d81ba9d5SMatt Jacob } 724a1bc34c6SMatt Jacob pw = isp->isp_osinfo.lun_hash[hfx]; 725d81ba9d5SMatt Jacob if (pw == NULL) { 726d81ba9d5SMatt Jacob return; 727a1bc34c6SMatt Jacob } else if (pw->lun == tptr->lun && pw->bus == tptr->bus) { 728a1bc34c6SMatt Jacob isp->isp_osinfo.lun_hash[hfx] = pw->next; 729d81ba9d5SMatt Jacob } else { 730d81ba9d5SMatt Jacob lw = pw; 731d81ba9d5SMatt Jacob pw = lw->next; 732d81ba9d5SMatt Jacob while (pw) { 733a1bc34c6SMatt Jacob if (pw->lun == tptr->lun && pw->bus == tptr->bus) { 734d81ba9d5SMatt Jacob lw->next = pw->next; 735d81ba9d5SMatt Jacob break; 736d81ba9d5SMatt Jacob } 737d81ba9d5SMatt Jacob lw = pw; 738d81ba9d5SMatt Jacob pw = pw->next; 739d81ba9d5SMatt Jacob } 740d81ba9d5SMatt Jacob if (pw == NULL) { 741d81ba9d5SMatt Jacob return; 742d81ba9d5SMatt Jacob } 743d81ba9d5SMatt Jacob } 744d81ba9d5SMatt Jacob free(tptr, M_DEVBUF); 745d81ba9d5SMatt Jacob } 746d81ba9d5SMatt Jacob 7475d571944SMatt Jacob /* 7485d571944SMatt Jacob * we enter with our locks held. 7495d571944SMatt Jacob */ 750d81ba9d5SMatt Jacob static void 751d81ba9d5SMatt Jacob isp_en_lun(struct ispsoftc *isp, union ccb *ccb) 752d81ba9d5SMatt Jacob { 753a1bc34c6SMatt Jacob const char lfmt[] = "Lun now %sabled for target mode on channel %d"; 754d81ba9d5SMatt Jacob struct ccb_en_lun *cel = &ccb->cel; 755d81ba9d5SMatt Jacob tstate_t *tptr; 756d81ba9d5SMatt Jacob u_int16_t rstat; 75764edff94SMatt Jacob int bus, cmd, av, wildcard; 758d81ba9d5SMatt Jacob lun_id_t lun; 759d81ba9d5SMatt Jacob target_id_t tgt; 760d81ba9d5SMatt Jacob 761d81ba9d5SMatt Jacob 762a1bc34c6SMatt Jacob bus = XS_CHANNEL(ccb) & 0x1; 763d81ba9d5SMatt Jacob tgt = ccb->ccb_h.target_id; 764d81ba9d5SMatt Jacob lun = ccb->ccb_h.target_lun; 765d81ba9d5SMatt Jacob 766d81ba9d5SMatt Jacob /* 767d81ba9d5SMatt Jacob * Do some sanity checking first. 768d81ba9d5SMatt Jacob */ 769d81ba9d5SMatt Jacob 770d6e5500fSMatt Jacob if ((lun != CAM_LUN_WILDCARD) && 771d6e5500fSMatt Jacob (lun < 0 || lun >= (lun_id_t) isp->isp_maxluns)) { 772d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 773d81ba9d5SMatt Jacob return; 774d81ba9d5SMatt Jacob } 77564edff94SMatt Jacob 7762ad50ca5SMatt Jacob if (IS_SCSI(isp)) { 777a1bc34c6SMatt Jacob sdparam *sdp = isp->isp_param; 778a1bc34c6SMatt Jacob sdp += bus; 779d81ba9d5SMatt Jacob if (tgt != CAM_TARGET_WILDCARD && 780a1bc34c6SMatt Jacob tgt != sdp->isp_initiator_id) { 781d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_TID_INVALID; 782d81ba9d5SMatt Jacob return; 783d81ba9d5SMatt Jacob } 784d81ba9d5SMatt Jacob } else { 785d81ba9d5SMatt Jacob if (tgt != CAM_TARGET_WILDCARD && 786d6e5500fSMatt Jacob tgt != FCPARAM(isp)->isp_iid) { 787d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_TID_INVALID; 788d81ba9d5SMatt Jacob return; 789d81ba9d5SMatt Jacob } 79064edff94SMatt Jacob /* 79164edff94SMatt Jacob * This is as a good a place as any to check f/w capabilities. 79264edff94SMatt Jacob */ 79364edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_TMODE) == 0) { 79464edff94SMatt Jacob isp_prt(isp, ISP_LOGERR, 79564edff94SMatt Jacob "firmware does not support target mode"); 79664edff94SMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 79764edff94SMatt Jacob return; 79864edff94SMatt Jacob } 79964edff94SMatt Jacob /* 80064edff94SMatt Jacob * XXX: We *could* handle non-SCCLUN f/w, but we'd have to 80164edff94SMatt Jacob * XXX: dorks with our already fragile enable/disable code. 80264edff94SMatt Jacob */ 80364edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) { 80464edff94SMatt Jacob isp_prt(isp, ISP_LOGERR, 80564edff94SMatt Jacob "firmware not SCCLUN capable"); 80664edff94SMatt Jacob } 807d81ba9d5SMatt Jacob } 808d81ba9d5SMatt Jacob 809d6e5500fSMatt Jacob if (tgt == CAM_TARGET_WILDCARD) { 81064edff94SMatt Jacob if (lun == CAM_LUN_WILDCARD) { 81164edff94SMatt Jacob wildcard = 1; 81264edff94SMatt Jacob } else { 813d6e5500fSMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 814d6e5500fSMatt Jacob return; 815d6e5500fSMatt Jacob } 816126ec864SMatt Jacob } else { 817126ec864SMatt Jacob wildcard = 0; 818126ec864SMatt Jacob } 819b6b6ad2fSMatt Jacob 820b6b6ad2fSMatt Jacob /* 821b6b6ad2fSMatt Jacob * Next check to see whether this is a target/lun wildcard action. 82264edff94SMatt Jacob * 82364edff94SMatt Jacob * If so, we know that we can accept commands for luns that haven't 82464edff94SMatt Jacob * been enabled yet and send them upstream. Otherwise, we have to 82564edff94SMatt Jacob * handle them locally (if we see them at all). 826b6b6ad2fSMatt Jacob */ 827126ec864SMatt Jacob 828126ec864SMatt Jacob if (wildcard) { 829a1bc34c6SMatt Jacob tptr = &isp->isp_osinfo.tsdflt[bus]; 830b6b6ad2fSMatt Jacob if (cel->enable) { 83164edff94SMatt Jacob if (isp->isp_osinfo.tmflags[bus] & 83264edff94SMatt Jacob TM_WILDCARD_ENABLED) { 833b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; 834b6b6ad2fSMatt Jacob return; 835b6b6ad2fSMatt Jacob } 836b6b6ad2fSMatt Jacob ccb->ccb_h.status = 837b6b6ad2fSMatt Jacob xpt_create_path(&tptr->owner, NULL, 838b6b6ad2fSMatt Jacob xpt_path_path_id(ccb->ccb_h.path), 839b6b6ad2fSMatt Jacob xpt_path_target_id(ccb->ccb_h.path), 840b6b6ad2fSMatt Jacob xpt_path_lun_id(ccb->ccb_h.path)); 841b6b6ad2fSMatt Jacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 842b6b6ad2fSMatt Jacob return; 843b6b6ad2fSMatt Jacob } 844b6b6ad2fSMatt Jacob SLIST_INIT(&tptr->atios); 845b6b6ad2fSMatt Jacob SLIST_INIT(&tptr->inots); 84664edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] |= TM_WILDCARD_ENABLED; 847126ec864SMatt Jacob } else { 84864edff94SMatt Jacob if ((isp->isp_osinfo.tmflags[bus] & 84964edff94SMatt Jacob TM_WILDCARD_ENABLED) == 0) { 850126ec864SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 851126ec864SMatt Jacob return; 852126ec864SMatt Jacob } 853126ec864SMatt Jacob if (tptr->hold) { 854126ec864SMatt Jacob ccb->ccb_h.status = CAM_SCSI_BUSY; 855126ec864SMatt Jacob return; 856126ec864SMatt Jacob } 857126ec864SMatt Jacob xpt_free_path(tptr->owner); 85864edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_WILDCARD_ENABLED; 859126ec864SMatt Jacob } 860126ec864SMatt Jacob } 861126ec864SMatt Jacob 862126ec864SMatt Jacob /* 863126ec864SMatt Jacob * Now check to see whether this bus needs to be 864126ec864SMatt Jacob * enabled/disabled with respect to target mode. 865126ec864SMatt Jacob */ 866126ec864SMatt Jacob av = bus << 31; 86764edff94SMatt Jacob if (cel->enable && !(isp->isp_osinfo.tmflags[bus] & TM_TMODE_ENABLED)) { 868a1bc34c6SMatt Jacob av |= ENABLE_TARGET_FLAG; 869b6b6ad2fSMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 870b6b6ad2fSMatt Jacob if (av) { 871b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 872126ec864SMatt Jacob if (wildcard) { 87364edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= 87464edff94SMatt Jacob ~TM_WILDCARD_ENABLED; 875b6b6ad2fSMatt Jacob xpt_free_path(tptr->owner); 8765d571944SMatt Jacob } 877b6b6ad2fSMatt Jacob return; 878b6b6ad2fSMatt Jacob } 87964edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] |= TM_TMODE_ENABLED; 880126ec864SMatt Jacob isp_prt(isp, ISP_LOGINFO, 881126ec864SMatt Jacob "Target Mode enabled on channel %d", bus); 88264edff94SMatt Jacob } else if (cel->enable == 0 && 88364edff94SMatt Jacob (isp->isp_osinfo.tmflags[bus] & TM_TMODE_ENABLED) && wildcard) { 884a1bc34c6SMatt Jacob if (are_any_luns_enabled(isp, bus)) { 885b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_SCSI_BUSY; 886b6b6ad2fSMatt Jacob return; 887b6b6ad2fSMatt Jacob } 888b6b6ad2fSMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 889b6b6ad2fSMatt Jacob if (av) { 890b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 891b6b6ad2fSMatt Jacob return; 892b6b6ad2fSMatt Jacob } 89364edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED; 894126ec864SMatt Jacob isp_prt(isp, ISP_LOGINFO, 895126ec864SMatt Jacob "Target Mode disabled on channel %d", bus); 896126ec864SMatt Jacob } 897126ec864SMatt Jacob 898126ec864SMatt Jacob if (wildcard) { 89964edff94SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 900b6b6ad2fSMatt Jacob return; 901b6b6ad2fSMatt Jacob } 902b6b6ad2fSMatt Jacob 903d81ba9d5SMatt Jacob if (cel->enable) { 904d81ba9d5SMatt Jacob ccb->ccb_h.status = 905a1bc34c6SMatt Jacob create_lun_state(isp, bus, ccb->ccb_h.path, &tptr); 906d81ba9d5SMatt Jacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 907d81ba9d5SMatt Jacob return; 908d81ba9d5SMatt Jacob } 909d81ba9d5SMatt Jacob } else { 910a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, lun); 911d81ba9d5SMatt Jacob if (tptr == NULL) { 912d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 913d81ba9d5SMatt Jacob return; 914d81ba9d5SMatt Jacob } 915d81ba9d5SMatt Jacob } 916d81ba9d5SMatt Jacob 91764edff94SMatt Jacob if (isp_psema_sig_rqe(isp, bus)) { 918d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 919d81ba9d5SMatt Jacob if (cel->enable) 920d81ba9d5SMatt Jacob destroy_lun_state(isp, tptr); 921d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 922d81ba9d5SMatt Jacob return; 923d81ba9d5SMatt Jacob } 924d81ba9d5SMatt Jacob 925d81ba9d5SMatt Jacob if (cel->enable) { 926d81ba9d5SMatt Jacob u_int32_t seq = isp->isp_osinfo.rollinfo++; 9275d571944SMatt Jacob int c, n, ulun = lun; 9285d571944SMatt Jacob 9295d571944SMatt Jacob cmd = RQSTYPE_ENABLE_LUN; 9305d571944SMatt Jacob c = DFLT_CMND_CNT; 9315d571944SMatt Jacob n = DFLT_INOT_CNT; 9325d571944SMatt Jacob if (IS_FC(isp) && lun != 0) { 9335d571944SMatt Jacob cmd = RQSTYPE_MODIFY_LUN; 9345d571944SMatt Jacob n = 0; 9355d571944SMatt Jacob /* 9365d571944SMatt Jacob * For SCC firmware, we only deal with setting 9375d571944SMatt Jacob * (enabling or modifying) lun 0. 9385d571944SMatt Jacob */ 9395d571944SMatt Jacob ulun = 0; 9405d571944SMatt Jacob } 941d81ba9d5SMatt Jacob rstat = LUN_ERR; 9425d571944SMatt Jacob if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq)) { 943d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 9443c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, "isp_lun_cmd failed"); 945d81ba9d5SMatt Jacob goto out; 946d81ba9d5SMatt Jacob } 94764edff94SMatt Jacob if (isp_cv_wait_timed_rqe(isp, bus, 30 * hz)) { 948d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 9493c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, 9505d571944SMatt Jacob "wait for ENABLE/MODIFY LUN timed out"); 951d81ba9d5SMatt Jacob goto out; 952d81ba9d5SMatt Jacob } 95364edff94SMatt Jacob rstat = isp->isp_osinfo.rstatus[bus]; 954d81ba9d5SMatt Jacob if (rstat != LUN_OK) { 955d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 9563c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, 9575d571944SMatt Jacob "ENABLE/MODIFY LUN returned 0x%x", rstat); 958d81ba9d5SMatt Jacob goto out; 959d81ba9d5SMatt Jacob } 960d81ba9d5SMatt Jacob } else { 9615d571944SMatt Jacob int c, n, ulun = lun; 962d81ba9d5SMatt Jacob u_int32_t seq; 963d81ba9d5SMatt Jacob 964d81ba9d5SMatt Jacob rstat = LUN_ERR; 9655d571944SMatt Jacob seq = isp->isp_osinfo.rollinfo++; 9665d571944SMatt Jacob cmd = -RQSTYPE_MODIFY_LUN; 967d81ba9d5SMatt Jacob 9685d571944SMatt Jacob c = DFLT_CMND_CNT; 9695d571944SMatt Jacob n = DFLT_INOT_CNT; 9705d571944SMatt Jacob if (IS_FC(isp) && lun != 0) { 9715d571944SMatt Jacob n = 0; 9725d571944SMatt Jacob /* 9735d571944SMatt Jacob * For SCC firmware, we only deal with setting 9745d571944SMatt Jacob * (enabling or modifying) lun 0. 9755d571944SMatt Jacob */ 9765d571944SMatt Jacob ulun = 0; 9775d571944SMatt Jacob } 9785d571944SMatt Jacob if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq)) { 979d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 9803c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, "isp_lun_cmd failed"); 981d81ba9d5SMatt Jacob goto out; 982d81ba9d5SMatt Jacob } 98364edff94SMatt Jacob if (isp_cv_wait_timed_rqe(isp, bus, 30 * hz)) { 984d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 9853c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, 9863c75bb14SMatt Jacob "wait for MODIFY LUN timed out"); 987d81ba9d5SMatt Jacob goto out; 988d81ba9d5SMatt Jacob } 98964edff94SMatt Jacob rstat = isp->isp_osinfo.rstatus[bus]; 990d81ba9d5SMatt Jacob if (rstat != LUN_OK) { 991d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 9923c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, 9933c75bb14SMatt Jacob "MODIFY LUN returned 0x%x", rstat); 994d81ba9d5SMatt Jacob goto out; 995d81ba9d5SMatt Jacob } 9965d571944SMatt Jacob if (IS_FC(isp) && lun) { 9975d571944SMatt Jacob goto out; 9985d571944SMatt Jacob } 9995d571944SMatt Jacob 1000d81ba9d5SMatt Jacob seq = isp->isp_osinfo.rollinfo++; 1001d81ba9d5SMatt Jacob 10025d571944SMatt Jacob rstat = LUN_ERR; 10035d571944SMatt Jacob cmd = -RQSTYPE_ENABLE_LUN; 10045d571944SMatt Jacob if (isp_lun_cmd(isp, cmd, bus, tgt, lun, 0, 0, seq)) { 1005d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 10063c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, "isp_lun_cmd failed"); 1007d81ba9d5SMatt Jacob goto out; 1008d81ba9d5SMatt Jacob } 100964edff94SMatt Jacob if (isp_cv_wait_timed_rqe(isp, bus, 30 * hz)) { 1010d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 10113c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, 10125d571944SMatt Jacob "wait for DISABLE LUN timed out"); 1013d81ba9d5SMatt Jacob goto out; 1014d81ba9d5SMatt Jacob } 101564edff94SMatt Jacob rstat = isp->isp_osinfo.rstatus[bus]; 1016d81ba9d5SMatt Jacob if (rstat != LUN_OK) { 1017d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 10183c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 10195d571944SMatt Jacob "DISABLE LUN returned 0x%x", rstat); 1020d81ba9d5SMatt Jacob goto out; 1021d81ba9d5SMatt Jacob } 1022126ec864SMatt Jacob if (are_any_luns_enabled(isp, bus) == 0) { 1023126ec864SMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 1024126ec864SMatt Jacob if (av) { 1025126ec864SMatt Jacob isp_prt(isp, ISP_LOGWARN, 1026126ec864SMatt Jacob "disable target mode on channel %d failed", 1027126ec864SMatt Jacob bus); 1028126ec864SMatt Jacob goto out; 1029d81ba9d5SMatt Jacob } 103064edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED; 1031126ec864SMatt Jacob xpt_print_path(ccb->ccb_h.path); 1032126ec864SMatt Jacob isp_prt(isp, ISP_LOGINFO, 1033126ec864SMatt Jacob "Target Mode disabled on channel %d", bus); 1034126ec864SMatt Jacob } 1035126ec864SMatt Jacob } 1036126ec864SMatt Jacob 1037d81ba9d5SMatt Jacob out: 103864edff94SMatt Jacob isp_vsema_rqe(isp, bus); 1039d81ba9d5SMatt Jacob 1040d81ba9d5SMatt Jacob if (rstat != LUN_OK) { 1041d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 10423c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 10433c75bb14SMatt Jacob "lun %sable failed", (cel->enable) ? "en" : "dis"); 1044d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 1045d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1046d81ba9d5SMatt Jacob if (cel->enable) 1047d81ba9d5SMatt Jacob destroy_lun_state(isp, tptr); 1048d81ba9d5SMatt Jacob } else { 1049d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 1050a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGINFO, lfmt, 1051a1bc34c6SMatt Jacob (cel->enable) ? "en" : "dis", bus); 1052d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1053d81ba9d5SMatt Jacob if (cel->enable == 0) { 1054d81ba9d5SMatt Jacob destroy_lun_state(isp, tptr); 1055d81ba9d5SMatt Jacob } 1056d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 1057d81ba9d5SMatt Jacob } 1058d81ba9d5SMatt Jacob } 1059d81ba9d5SMatt Jacob 1060d81ba9d5SMatt Jacob static cam_status 1061d81ba9d5SMatt Jacob isp_abort_tgt_ccb(struct ispsoftc *isp, union ccb *ccb) 1062d81ba9d5SMatt Jacob { 1063d81ba9d5SMatt Jacob tstate_t *tptr; 1064d81ba9d5SMatt Jacob struct ccb_hdr_slist *lp; 1065d81ba9d5SMatt Jacob struct ccb_hdr *curelm; 1066d81ba9d5SMatt Jacob int found; 1067d81ba9d5SMatt Jacob union ccb *accb = ccb->cab.abort_ccb; 1068d81ba9d5SMatt Jacob 1069d81ba9d5SMatt Jacob if (accb->ccb_h.target_id != CAM_TARGET_WILDCARD) { 1070d81ba9d5SMatt Jacob if (IS_FC(isp) && (accb->ccb_h.target_id != 1071d81ba9d5SMatt Jacob ((fcparam *) isp->isp_param)->isp_loopid)) { 1072d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 1073d81ba9d5SMatt Jacob } else if (IS_SCSI(isp) && (accb->ccb_h.target_id != 1074d81ba9d5SMatt Jacob ((sdparam *) isp->isp_param)->isp_initiator_id)) { 1075d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 1076d81ba9d5SMatt Jacob } 1077d81ba9d5SMatt Jacob } 1078a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, XS_CHANNEL(ccb), accb->ccb_h.target_lun); 1079d81ba9d5SMatt Jacob if (tptr == NULL) { 1080d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 1081d81ba9d5SMatt Jacob } 1082d81ba9d5SMatt Jacob if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 1083d81ba9d5SMatt Jacob lp = &tptr->atios; 1084d81ba9d5SMatt Jacob } else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY) { 1085d81ba9d5SMatt Jacob lp = &tptr->inots; 1086d81ba9d5SMatt Jacob } else { 1087d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1088d81ba9d5SMatt Jacob return (CAM_UA_ABORT); 1089d81ba9d5SMatt Jacob } 1090d81ba9d5SMatt Jacob curelm = SLIST_FIRST(lp); 1091d81ba9d5SMatt Jacob found = 0; 1092d81ba9d5SMatt Jacob if (curelm == &accb->ccb_h) { 1093d81ba9d5SMatt Jacob found = 1; 1094d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(lp, sim_links.sle); 1095d81ba9d5SMatt Jacob } else { 1096d81ba9d5SMatt Jacob while(curelm != NULL) { 1097d81ba9d5SMatt Jacob struct ccb_hdr *nextelm; 1098d81ba9d5SMatt Jacob 1099d81ba9d5SMatt Jacob nextelm = SLIST_NEXT(curelm, sim_links.sle); 1100d81ba9d5SMatt Jacob if (nextelm == &accb->ccb_h) { 1101d81ba9d5SMatt Jacob found = 1; 1102d81ba9d5SMatt Jacob SLIST_NEXT(curelm, sim_links.sle) = 1103d81ba9d5SMatt Jacob SLIST_NEXT(nextelm, sim_links.sle); 1104d81ba9d5SMatt Jacob break; 1105d81ba9d5SMatt Jacob } 1106d81ba9d5SMatt Jacob curelm = nextelm; 1107d81ba9d5SMatt Jacob } 1108d81ba9d5SMatt Jacob } 1109d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1110d81ba9d5SMatt Jacob if (found) { 1111d81ba9d5SMatt Jacob accb->ccb_h.status = CAM_REQ_ABORTED; 1112d81ba9d5SMatt Jacob return (CAM_REQ_CMP); 1113d81ba9d5SMatt Jacob } 1114d81ba9d5SMatt Jacob return(CAM_PATH_INVALID); 1115d81ba9d5SMatt Jacob } 1116d81ba9d5SMatt Jacob 1117d81ba9d5SMatt Jacob static cam_status 1118d81ba9d5SMatt Jacob isp_target_start_ctio(struct ispsoftc *isp, union ccb *ccb) 1119d81ba9d5SMatt Jacob { 1120d81ba9d5SMatt Jacob void *qe; 112100a8e174SMatt Jacob struct ccb_scsiio *cso = &ccb->csio; 11225f5aafe1SMatt Jacob u_int16_t *hp, save_handle; 11234fd13c1bSMatt Jacob u_int16_t nxti, optr; 11244fd13c1bSMatt Jacob u_int8_t local[QENTRY_LEN]; 1125d81ba9d5SMatt Jacob 1126f48ce188SMatt Jacob 11274fd13c1bSMatt Jacob if (isp_getrqentry(isp, &nxti, &optr, &qe)) { 112892a1e549SMatt Jacob xpt_print_path(ccb->ccb_h.path); 112992a1e549SMatt Jacob printf("Request Queue Overflow in isp_target_start_ctio\n"); 1130d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 1131d81ba9d5SMatt Jacob } 11324fd13c1bSMatt Jacob bzero(local, QENTRY_LEN); 1133d81ba9d5SMatt Jacob 1134d81ba9d5SMatt Jacob /* 1135d81ba9d5SMatt Jacob * We're either moving data or completing a command here. 1136d81ba9d5SMatt Jacob */ 1137d81ba9d5SMatt Jacob 1138d81ba9d5SMatt Jacob if (IS_FC(isp)) { 113953036e92SMatt Jacob atio_private_data_t *atp; 11404fd13c1bSMatt Jacob ct2_entry_t *cto = (ct2_entry_t *) local; 114100a8e174SMatt Jacob 1142d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; 1143d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_count = 1; 114400a8e174SMatt Jacob cto->ct_iid = cso->init_id; 114564edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) { 1146d81ba9d5SMatt Jacob cto->ct_lun = ccb->ccb_h.target_lun; 11472ad50ca5SMatt Jacob } 114853036e92SMatt Jacob 114953036e92SMatt Jacob atp = isp_get_atpd(isp, cso->tag_id); 115053036e92SMatt Jacob if (atp == NULL) { 1151570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGERR, 1152570c7a3fSMatt Jacob "cannot find private data adjunct for tag %x", 115353036e92SMatt Jacob cso->tag_id); 1154570c7a3fSMatt Jacob return (-1); 115553036e92SMatt Jacob } 1156f48ce188SMatt Jacob 115700a8e174SMatt Jacob cto->ct_rxid = cso->tag_id; 115800a8e174SMatt Jacob if (cso->dxfer_len == 0) { 115900a8e174SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA; 1160f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 116100a8e174SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 1162f48ce188SMatt Jacob cto->rsp.m1.ct_scsi_status = cso->scsi_status; 116353036e92SMatt Jacob cto->ct_resid = 116453036e92SMatt Jacob atp->orig_datalen - atp->bytes_xfered; 1165570c7a3fSMatt Jacob if (cto->ct_resid < 0) { 1166570c7a3fSMatt Jacob cto->rsp.m1.ct_scsi_status |= 1167570c7a3fSMatt Jacob CT2_DATA_OVER; 1168570c7a3fSMatt Jacob } else if (cto->ct_resid > 0) { 1169570c7a3fSMatt Jacob cto->rsp.m1.ct_scsi_status |= 1170570c7a3fSMatt Jacob CT2_DATA_UNDER; 1171570c7a3fSMatt Jacob } 1172f48ce188SMatt Jacob } 117300a8e174SMatt Jacob if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) { 117400a8e174SMatt Jacob int m = min(cso->sense_len, MAXRESPLEN); 117500a8e174SMatt Jacob bcopy(&cso->sense_data, cto->rsp.m1.ct_resp, m); 117600a8e174SMatt Jacob cto->rsp.m1.ct_senselen = m; 117700a8e174SMatt Jacob cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID; 117800a8e174SMatt Jacob } 117900a8e174SMatt Jacob } else { 118000a8e174SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE0; 118100a8e174SMatt Jacob if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 118200a8e174SMatt Jacob cto->ct_flags |= CT2_DATA_IN; 118300a8e174SMatt Jacob } else { 118400a8e174SMatt Jacob cto->ct_flags |= CT2_DATA_OUT; 1185d81ba9d5SMatt Jacob } 1186570c7a3fSMatt Jacob cto->ct_reloff = atp->bytes_xfered; 1187d81ba9d5SMatt Jacob if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 1188d81ba9d5SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 118900a8e174SMatt Jacob cto->rsp.m0.ct_scsi_status = cso->scsi_status; 119053036e92SMatt Jacob cto->ct_resid = 119153036e92SMatt Jacob atp->orig_datalen - 119253036e92SMatt Jacob (atp->bytes_xfered + cso->dxfer_len); 1193570c7a3fSMatt Jacob if (cto->ct_resid < 0) { 1194570c7a3fSMatt Jacob cto->rsp.m0.ct_scsi_status |= 1195570c7a3fSMatt Jacob CT2_DATA_OVER; 1196570c7a3fSMatt Jacob } else if (cto->ct_resid > 0) { 1197570c7a3fSMatt Jacob cto->rsp.m0.ct_scsi_status |= 1198570c7a3fSMatt Jacob CT2_DATA_UNDER; 1199570c7a3fSMatt Jacob } 120053036e92SMatt Jacob } else { 120153036e92SMatt Jacob atp->last_xframt = cso->dxfer_len; 1202d81ba9d5SMatt Jacob } 1203f48ce188SMatt Jacob /* 1204f48ce188SMatt Jacob * If we're sending data and status back together, 1205f48ce188SMatt Jacob * we can't also send back sense data as well. 1206f48ce188SMatt Jacob */ 120700a8e174SMatt Jacob ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 120800a8e174SMatt Jacob } 120953036e92SMatt Jacob 1210290dc24bSMatt Jacob if (cto->ct_flags & CT2_SENDSTATUS) { 121164edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 121253036e92SMatt Jacob "CTIO2[%x] STATUS %x origd %u curd %u resid %u", 121353036e92SMatt Jacob cto->ct_rxid, cso->scsi_status, atp->orig_datalen, 121453036e92SMatt Jacob cso->dxfer_len, cto->ct_resid); 1215a1bc34c6SMatt Jacob cto->ct_flags |= CT2_CCINCR; 1216570c7a3fSMatt Jacob atp->state = ATPD_STATE_LAST_CTIO; 1217570c7a3fSMatt Jacob } else 1218570c7a3fSMatt Jacob atp->state = ATPD_STATE_CTIO; 1219a1bc34c6SMatt Jacob cto->ct_timeout = 10; 12205f5aafe1SMatt Jacob hp = &cto->ct_syshandle; 1221d81ba9d5SMatt Jacob } else { 12224fd13c1bSMatt Jacob ct_entry_t *cto = (ct_entry_t *) local; 122300a8e174SMatt Jacob 1224d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 1225d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_count = 1; 122600a8e174SMatt Jacob cto->ct_iid = cso->init_id; 1227a1bc34c6SMatt Jacob cto->ct_iid |= XS_CHANNEL(ccb) << 7; 1228d81ba9d5SMatt Jacob cto->ct_tgt = ccb->ccb_h.target_id; 1229d81ba9d5SMatt Jacob cto->ct_lun = ccb->ccb_h.target_lun; 1230a1bc34c6SMatt Jacob cto->ct_fwhandle = AT_GET_HANDLE(cso->tag_id); 1231a1bc34c6SMatt Jacob if (AT_HAS_TAG(cso->tag_id)) { 1232a1bc34c6SMatt Jacob cto->ct_tag_val = (u_int8_t) AT_GET_TAG(cso->tag_id); 1233f48ce188SMatt Jacob cto->ct_flags |= CT_TQAE; 1234f48ce188SMatt Jacob } 1235f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) { 1236f48ce188SMatt Jacob cto->ct_flags |= CT_NODISC; 1237f48ce188SMatt Jacob } 1238f48ce188SMatt Jacob if (cso->dxfer_len == 0) { 1239d81ba9d5SMatt Jacob cto->ct_flags |= CT_NO_DATA; 124000a8e174SMatt Jacob } else if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 124100a8e174SMatt Jacob cto->ct_flags |= CT_DATA_IN; 124200a8e174SMatt Jacob } else { 124300a8e174SMatt Jacob cto->ct_flags |= CT_DATA_OUT; 1244d81ba9d5SMatt Jacob } 1245f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 124653036e92SMatt Jacob cto->ct_flags |= CT_SENDSTATUS|CT_CCINCR; 124700a8e174SMatt Jacob cto->ct_scsi_status = cso->scsi_status; 124800a8e174SMatt Jacob cto->ct_resid = cso->resid; 124964edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1250a1bc34c6SMatt Jacob "CTIO[%x] SCSI STATUS 0x%x resid %d tag_id %x", 1251a1bc34c6SMatt Jacob cto->ct_fwhandle, cso->scsi_status, cso->resid, 1252a1bc34c6SMatt Jacob cso->tag_id); 125392a1e549SMatt Jacob } 125464edff94SMatt Jacob ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 1255a1bc34c6SMatt Jacob cto->ct_timeout = 10; 12565f5aafe1SMatt Jacob hp = &cto->ct_syshandle; 1257d81ba9d5SMatt Jacob } 1258d81ba9d5SMatt Jacob 1259b09b0095SMatt Jacob if (isp_save_xs(isp, (XS_T *)ccb, hp)) { 126092a1e549SMatt Jacob xpt_print_path(ccb->ccb_h.path); 126192a1e549SMatt Jacob printf("No XFLIST pointers for isp_target_start_ctio\n"); 1262d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 1263d81ba9d5SMatt Jacob } 1264d81ba9d5SMatt Jacob 1265d81ba9d5SMatt Jacob 1266d81ba9d5SMatt Jacob /* 1267d81ba9d5SMatt Jacob * Call the dma setup routines for this entry (and any subsequent 1268d81ba9d5SMatt Jacob * CTIOs) if there's data to move, and then tell the f/w it's got 1269b09b0095SMatt Jacob * new things to play with. As with isp_start's usage of DMA setup, 1270d81ba9d5SMatt Jacob * any swizzling is done in the machine dependent layer. Because 1271d81ba9d5SMatt Jacob * of this, we put the request onto the queue area first in native 1272d81ba9d5SMatt Jacob * format. 1273d81ba9d5SMatt Jacob */ 1274d81ba9d5SMatt Jacob 1275d81ba9d5SMatt Jacob save_handle = *hp; 1276a1bc34c6SMatt Jacob 12774fd13c1bSMatt Jacob switch (ISP_DMASETUP(isp, cso, (ispreq_t *) local, &nxti, optr)) { 1278d81ba9d5SMatt Jacob case CMD_QUEUED: 12794fd13c1bSMatt Jacob ISP_ADD_REQUEST(isp, nxti); 1280d81ba9d5SMatt Jacob return (CAM_REQ_INPROG); 1281d81ba9d5SMatt Jacob 1282d81ba9d5SMatt Jacob case CMD_EAGAIN: 1283d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 1284d81ba9d5SMatt Jacob isp_destroy_handle(isp, save_handle); 1285d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 1286d81ba9d5SMatt Jacob 1287d81ba9d5SMatt Jacob default: 1288d81ba9d5SMatt Jacob isp_destroy_handle(isp, save_handle); 1289b85389e1SMatt Jacob return (XS_ERR(ccb)); 1290d81ba9d5SMatt Jacob } 1291d81ba9d5SMatt Jacob } 1292d81ba9d5SMatt Jacob 1293a1bc34c6SMatt Jacob static void 1294a1bc34c6SMatt Jacob isp_refire_putback_atio(void *arg) 1295f48ce188SMatt Jacob { 1296a1bc34c6SMatt Jacob int s = splcam(); 1297a1bc34c6SMatt Jacob isp_target_putback_atio(arg); 1298a1bc34c6SMatt Jacob splx(s); 1299a1bc34c6SMatt Jacob } 1300a1bc34c6SMatt Jacob 1301a1bc34c6SMatt Jacob static void 1302a1bc34c6SMatt Jacob isp_target_putback_atio(union ccb *ccb) 1303a1bc34c6SMatt Jacob { 1304a1bc34c6SMatt Jacob struct ispsoftc *isp; 1305a1bc34c6SMatt Jacob struct ccb_scsiio *cso; 13064fd13c1bSMatt Jacob u_int16_t nxti, optr; 1307a1bc34c6SMatt Jacob void *qe; 1308a1bc34c6SMatt Jacob 1309a1bc34c6SMatt Jacob isp = XS_ISP(ccb); 1310f48ce188SMatt Jacob 13114fd13c1bSMatt Jacob if (isp_getrqentry(isp, &nxti, &optr, &qe)) { 1312a1bc34c6SMatt Jacob (void) timeout(isp_refire_putback_atio, ccb, 10); 1313a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGWARN, 1314a1bc34c6SMatt Jacob "isp_target_putback_atio: Request Queue Overflow"); 1315a1bc34c6SMatt Jacob return; 1316f48ce188SMatt Jacob } 1317f48ce188SMatt Jacob bzero(qe, QENTRY_LEN); 1318a1bc34c6SMatt Jacob cso = &ccb->csio; 1319f48ce188SMatt Jacob if (IS_FC(isp)) { 13204fd13c1bSMatt Jacob at2_entry_t local, *at = &local; 13214fd13c1bSMatt Jacob MEMZERO(at, sizeof (at2_entry_t)); 1322f48ce188SMatt Jacob at->at_header.rqs_entry_type = RQSTYPE_ATIO2; 1323f48ce188SMatt Jacob at->at_header.rqs_entry_count = 1; 132464edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) != 0) { 1325a1bc34c6SMatt Jacob at->at_scclun = (uint16_t) ccb->ccb_h.target_lun; 1326f48ce188SMatt Jacob } else { 1327a1bc34c6SMatt Jacob at->at_lun = (uint8_t) ccb->ccb_h.target_lun; 1328f48ce188SMatt Jacob } 1329f48ce188SMatt Jacob at->at_status = CT_OK; 1330a1bc34c6SMatt Jacob at->at_rxid = cso->tag_id; 1331570c7a3fSMatt Jacob at->at_iid = cso->ccb_h.target_id; 13324fd13c1bSMatt Jacob isp_put_atio2(isp, at, qe); 1333f48ce188SMatt Jacob } else { 13344fd13c1bSMatt Jacob at_entry_t local, *at = &local; 13354fd13c1bSMatt Jacob MEMZERO(at, sizeof (at_entry_t)); 1336f48ce188SMatt Jacob at->at_header.rqs_entry_type = RQSTYPE_ATIO; 1337f48ce188SMatt Jacob at->at_header.rqs_entry_count = 1; 1338a1bc34c6SMatt Jacob at->at_iid = cso->init_id; 1339a1bc34c6SMatt Jacob at->at_iid |= XS_CHANNEL(ccb) << 7; 1340a1bc34c6SMatt Jacob at->at_tgt = cso->ccb_h.target_id; 1341a1bc34c6SMatt Jacob at->at_lun = cso->ccb_h.target_lun; 1342f48ce188SMatt Jacob at->at_status = CT_OK; 1343a1bc34c6SMatt Jacob at->at_tag_val = AT_GET_TAG(cso->tag_id); 1344a1bc34c6SMatt Jacob at->at_handle = AT_GET_HANDLE(cso->tag_id); 13454fd13c1bSMatt Jacob isp_put_atio(isp, at, qe); 1346f48ce188SMatt Jacob } 1347f48ce188SMatt Jacob ISP_TDQE(isp, "isp_target_putback_atio", (int) optr, qe); 13484fd13c1bSMatt Jacob ISP_ADD_REQUEST(isp, nxti); 1349a1bc34c6SMatt Jacob isp_complete_ctio(ccb); 1350f48ce188SMatt Jacob } 1351f48ce188SMatt Jacob 1352f48ce188SMatt Jacob static void 1353a1bc34c6SMatt Jacob isp_complete_ctio(union ccb *ccb) 1354f48ce188SMatt Jacob { 1355a1bc34c6SMatt Jacob struct ispsoftc *isp = XS_ISP(ccb); 1356a1bc34c6SMatt Jacob if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { 1357a1bc34c6SMatt Jacob ccb->ccb_h.status |= CAM_REQ_CMP; 1358f48ce188SMatt Jacob } 1359a1bc34c6SMatt Jacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1360a1bc34c6SMatt Jacob xpt_done(ccb); 1361f48ce188SMatt Jacob } 1362f48ce188SMatt Jacob 1363d81ba9d5SMatt Jacob /* 1364d81ba9d5SMatt Jacob * Handle ATIO stuff that the generic code can't. 1365d81ba9d5SMatt Jacob * This means handling CDBs. 1366d81ba9d5SMatt Jacob */ 1367d81ba9d5SMatt Jacob 1368d81ba9d5SMatt Jacob static int 1369d81ba9d5SMatt Jacob isp_handle_platform_atio(struct ispsoftc *isp, at_entry_t *aep) 1370d81ba9d5SMatt Jacob { 1371d81ba9d5SMatt Jacob tstate_t *tptr; 137264edff94SMatt Jacob int status, bus, iswildcard; 1373d81ba9d5SMatt Jacob struct ccb_accept_tio *atiop; 1374d81ba9d5SMatt Jacob 1375d81ba9d5SMatt Jacob /* 1376d81ba9d5SMatt Jacob * The firmware status (except for the QLTM_SVALID bit) 1377d81ba9d5SMatt Jacob * indicates why this ATIO was sent to us. 1378d81ba9d5SMatt Jacob * 1379d81ba9d5SMatt Jacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 1380d81ba9d5SMatt Jacob * 1381d81ba9d5SMatt Jacob * If the DISCONNECTS DISABLED bit is set in the flags field, 13825d571944SMatt Jacob * we're still connected on the SCSI bus. 1383d81ba9d5SMatt Jacob */ 1384d81ba9d5SMatt Jacob status = aep->at_status; 1385d81ba9d5SMatt Jacob if ((status & ~QLTM_SVALID) == AT_PHASE_ERROR) { 1386d81ba9d5SMatt Jacob /* 1387d81ba9d5SMatt Jacob * Bus Phase Sequence error. We should have sense data 1388d81ba9d5SMatt Jacob * suggested by the f/w. I'm not sure quite yet what 1389d81ba9d5SMatt Jacob * to do about this for CAM. 1390d81ba9d5SMatt Jacob */ 13913c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, "PHASE ERROR"); 1392d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1393d81ba9d5SMatt Jacob return (0); 1394d81ba9d5SMatt Jacob } 1395d81ba9d5SMatt Jacob if ((status & ~QLTM_SVALID) != AT_CDB) { 13965d571944SMatt Jacob isp_prt(isp, ISP_LOGWARN, "bad atio (0x%x) leaked to platform", 13973c75bb14SMatt Jacob status); 1398d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1399d81ba9d5SMatt Jacob return (0); 1400d81ba9d5SMatt Jacob } 1401d81ba9d5SMatt Jacob 14025d571944SMatt Jacob bus = GET_BUS_VAL(aep->at_iid); 1403a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, aep->at_lun); 1404d81ba9d5SMatt Jacob if (tptr == NULL) { 1405a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD); 140664edff94SMatt Jacob iswildcard = 1; 140764edff94SMatt Jacob } else { 140864edff94SMatt Jacob iswildcard = 0; 1409d81ba9d5SMatt Jacob } 1410d81ba9d5SMatt Jacob 1411d81ba9d5SMatt Jacob if (tptr == NULL) { 1412d81ba9d5SMatt Jacob /* 1413d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1414d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1415d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a BUSY status 1416d81ba9d5SMatt Jacob * instead. This works out okay because the only 1417d81ba9d5SMatt Jacob * time we should, in fact, get this, is in the 1418d81ba9d5SMatt Jacob * case that somebody configured us without the 1419d81ba9d5SMatt Jacob * blackhole driver, so they get what they deserve. 1420d81ba9d5SMatt Jacob */ 1421d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1422d81ba9d5SMatt Jacob return (0); 1423d81ba9d5SMatt Jacob } 1424d81ba9d5SMatt Jacob 1425d81ba9d5SMatt Jacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 1426d81ba9d5SMatt Jacob if (atiop == NULL) { 1427d81ba9d5SMatt Jacob /* 1428d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1429d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1430d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a QUEUE FULL status 1431d81ba9d5SMatt Jacob * instead. This works out okay because the only time we 1432d81ba9d5SMatt Jacob * should, in fact, get this, is in the case that we've 1433d81ba9d5SMatt Jacob * run out of ATIOS. 1434d81ba9d5SMatt Jacob */ 1435d81ba9d5SMatt Jacob xpt_print_path(tptr->owner); 14363c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 1437a1bc34c6SMatt Jacob "no ATIOS for lun %d from initiator %d on channel %d", 14385d571944SMatt Jacob aep->at_lun, GET_IID_VAL(aep->at_iid), bus); 1439d81ba9d5SMatt Jacob if (aep->at_flags & AT_TQAE) 1440d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); 1441d81ba9d5SMatt Jacob else 1442d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 144364edff94SMatt Jacob rls_lun_statep(isp, tptr); 1444d81ba9d5SMatt Jacob return (0); 1445d81ba9d5SMatt Jacob } 1446d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 144764edff94SMatt Jacob if (iswildcard) { 1448d81ba9d5SMatt Jacob atiop->ccb_h.target_id = aep->at_tgt; 1449d81ba9d5SMatt Jacob atiop->ccb_h.target_lun = aep->at_lun; 1450d81ba9d5SMatt Jacob } 1451d81ba9d5SMatt Jacob if (aep->at_flags & AT_NODISC) { 1452f48ce188SMatt Jacob atiop->ccb_h.flags = CAM_DIS_DISCONNECT; 1453f48ce188SMatt Jacob } else { 1454f48ce188SMatt Jacob atiop->ccb_h.flags = 0; 1455d81ba9d5SMatt Jacob } 1456d81ba9d5SMatt Jacob 1457f48ce188SMatt Jacob if (status & QLTM_SVALID) { 1458f48ce188SMatt Jacob size_t amt = imin(QLTM_SENSELEN, sizeof (atiop->sense_data)); 1459f48ce188SMatt Jacob atiop->sense_len = amt; 1460f48ce188SMatt Jacob MEMCPY(&atiop->sense_data, aep->at_sense, amt); 1461f48ce188SMatt Jacob } else { 1462f48ce188SMatt Jacob atiop->sense_len = 0; 1463f48ce188SMatt Jacob } 1464d81ba9d5SMatt Jacob 14655d571944SMatt Jacob atiop->init_id = GET_IID_VAL(aep->at_iid); 1466d81ba9d5SMatt Jacob atiop->cdb_len = aep->at_cdblen; 1467d81ba9d5SMatt Jacob MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen); 1468d81ba9d5SMatt Jacob atiop->ccb_h.status = CAM_CDB_RECVD; 1469a1bc34c6SMatt Jacob /* 1470a1bc34c6SMatt Jacob * Construct a tag 'id' based upon tag value (which may be 0..255) 1471a1bc34c6SMatt Jacob * and the handle (which we have to preserve). 1472a1bc34c6SMatt Jacob */ 1473a1bc34c6SMatt Jacob AT_MAKE_TAGID(atiop->tag_id, aep); 1474a1bc34c6SMatt Jacob if (aep->at_flags & AT_TQAE) { 1475a1bc34c6SMatt Jacob atiop->tag_action = aep->at_tag_type; 1476d81ba9d5SMatt Jacob atiop->ccb_h.status |= CAM_TAG_ACTION_VALID; 1477d81ba9d5SMatt Jacob } 1478d81ba9d5SMatt Jacob xpt_done((union ccb*)atiop); 147964edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 14805d571944SMatt Jacob "ATIO[%x] CDB=0x%x bus %d iid%d->lun%d tag 0x%x ttype 0x%x %s", 14815d571944SMatt Jacob aep->at_handle, aep->at_cdb[0] & 0xff, GET_BUS_VAL(aep->at_iid), 14825d571944SMatt Jacob GET_IID_VAL(aep->at_iid), aep->at_lun, aep->at_tag_val & 0xff, 14835d571944SMatt Jacob aep->at_tag_type, (aep->at_flags & AT_NODISC)? 14845d571944SMatt Jacob "nondisc" : "disconnecting"); 1485d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1486d81ba9d5SMatt Jacob return (0); 1487d81ba9d5SMatt Jacob } 1488d81ba9d5SMatt Jacob 1489d81ba9d5SMatt Jacob static int 1490d81ba9d5SMatt Jacob isp_handle_platform_atio2(struct ispsoftc *isp, at2_entry_t *aep) 1491d81ba9d5SMatt Jacob { 149292a1e549SMatt Jacob lun_id_t lun; 1493d81ba9d5SMatt Jacob tstate_t *tptr; 1494d81ba9d5SMatt Jacob struct ccb_accept_tio *atiop; 149553036e92SMatt Jacob atio_private_data_t *atp; 1496d81ba9d5SMatt Jacob 1497d81ba9d5SMatt Jacob /* 1498d81ba9d5SMatt Jacob * The firmware status (except for the QLTM_SVALID bit) 1499d81ba9d5SMatt Jacob * indicates why this ATIO was sent to us. 1500d81ba9d5SMatt Jacob * 1501d81ba9d5SMatt Jacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 1502d81ba9d5SMatt Jacob */ 1503d81ba9d5SMatt Jacob if ((aep->at_status & ~QLTM_SVALID) != AT_CDB) { 15043c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 15053c75bb14SMatt Jacob "bogus atio (0x%x) leaked to platform", aep->at_status); 1506d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1507d81ba9d5SMatt Jacob return (0); 1508d81ba9d5SMatt Jacob } 1509d81ba9d5SMatt Jacob 151064edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) != 0) { 151192a1e549SMatt Jacob lun = aep->at_scclun; 15122ad50ca5SMatt Jacob } else { 151392a1e549SMatt Jacob lun = aep->at_lun; 15142ad50ca5SMatt Jacob } 1515a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, 0, lun); 1516d81ba9d5SMatt Jacob if (tptr == NULL) { 1517570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, "no state pointer for lun %d", lun); 1518a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD); 1519d81ba9d5SMatt Jacob } 1520d81ba9d5SMatt Jacob 1521d81ba9d5SMatt Jacob if (tptr == NULL) { 152252df5dfdSMatt Jacob /* 152352df5dfdSMatt Jacob * What we'd like to know is whether or not we have a listener 152452df5dfdSMatt Jacob * upstream that really hasn't configured yet. If we do, then 152552df5dfdSMatt Jacob * we can give a more sensible reply here. If not, then we can 152652df5dfdSMatt Jacob * reject this out of hand. 152752df5dfdSMatt Jacob * 152852df5dfdSMatt Jacob * Choices for what to send were 152952df5dfdSMatt Jacob * 153052df5dfdSMatt Jacob * Not Ready, Unit Not Self-Configured Yet 153152df5dfdSMatt Jacob * (0x2,0x3e,0x00) 153252df5dfdSMatt Jacob * 153352df5dfdSMatt Jacob * for the former and 153452df5dfdSMatt Jacob * 153552df5dfdSMatt Jacob * Illegal Request, Logical Unit Not Supported 153652df5dfdSMatt Jacob * (0x5,0x25,0x00) 153752df5dfdSMatt Jacob * 153852df5dfdSMatt Jacob * for the latter. 153952df5dfdSMatt Jacob * 154052df5dfdSMatt Jacob * We used to decide whether there was at least one listener 154152df5dfdSMatt Jacob * based upon whether the black hole driver was configured. 154252df5dfdSMatt Jacob * However, recent config(8) changes have made this hard to do 154352df5dfdSMatt Jacob * at this time. 154452df5dfdSMatt Jacob * 154552df5dfdSMatt Jacob */ 1546570c7a3fSMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1547d81ba9d5SMatt Jacob return (0); 1548d81ba9d5SMatt Jacob } 1549d81ba9d5SMatt Jacob 155053036e92SMatt Jacob atp = isp_get_atpd(isp, 0); 1551d81ba9d5SMatt Jacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 155253036e92SMatt Jacob if (atiop == NULL || atp == NULL) { 1553d81ba9d5SMatt Jacob /* 1554d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1555d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1556d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a QUEUE FULL status 1557d81ba9d5SMatt Jacob * instead. This works out okay because the only time we 1558d81ba9d5SMatt Jacob * should, in fact, get this, is in the case that we've 1559d81ba9d5SMatt Jacob * run out of ATIOS. 1560d81ba9d5SMatt Jacob */ 1561d81ba9d5SMatt Jacob xpt_print_path(tptr->owner); 15623c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 1563570c7a3fSMatt Jacob "no %s for lun %d from initiator %d", 1564570c7a3fSMatt Jacob (atp == NULL && atiop == NULL)? "ATIO2s *or* ATPS" : 1565570c7a3fSMatt Jacob ((atp == NULL)? "ATPs" : "ATIO2s"), lun, aep->at_iid); 1566d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1567d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); 1568d81ba9d5SMatt Jacob return (0); 1569d81ba9d5SMatt Jacob } 1570570c7a3fSMatt Jacob atp->state = ATPD_STATE_ATIO; 1571d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 1572570c7a3fSMatt Jacob tptr->atio_count--; 1573570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO2 lun %d, count now %d", 1574570c7a3fSMatt Jacob lun, tptr->atio_count); 1575f48ce188SMatt Jacob 1576a1bc34c6SMatt Jacob if (tptr == &isp->isp_osinfo.tsdflt[0]) { 1577d81ba9d5SMatt Jacob atiop->ccb_h.target_id = 1578d81ba9d5SMatt Jacob ((fcparam *)isp->isp_param)->isp_loopid; 157992a1e549SMatt Jacob atiop->ccb_h.target_lun = lun; 1580d81ba9d5SMatt Jacob } 1581b0a3ba7eSMatt Jacob /* 1582b0a3ba7eSMatt Jacob * We don't get 'suggested' sense data as we do with SCSI cards. 1583b0a3ba7eSMatt Jacob */ 1584f48ce188SMatt Jacob atiop->sense_len = 0; 1585f48ce188SMatt Jacob 1586d81ba9d5SMatt Jacob atiop->init_id = aep->at_iid; 1587d81ba9d5SMatt Jacob atiop->cdb_len = ATIO2_CDBLEN; 1588d81ba9d5SMatt Jacob MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, ATIO2_CDBLEN); 1589d81ba9d5SMatt Jacob atiop->ccb_h.status = CAM_CDB_RECVD; 1590d81ba9d5SMatt Jacob atiop->tag_id = aep->at_rxid; 1591d81ba9d5SMatt Jacob switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) { 1592d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_SIMPLEQ: 1593d81ba9d5SMatt Jacob atiop->tag_action = MSG_SIMPLE_Q_TAG; 1594d81ba9d5SMatt Jacob break; 1595d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_HEADOFQ: 1596d81ba9d5SMatt Jacob atiop->tag_action = MSG_HEAD_OF_Q_TAG; 1597d81ba9d5SMatt Jacob break; 1598d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_ORDERED: 1599d81ba9d5SMatt Jacob atiop->tag_action = MSG_ORDERED_Q_TAG; 1600d81ba9d5SMatt Jacob break; 1601d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_ACAQ: /* ?? */ 1602d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_UNTAGGED: 1603d81ba9d5SMatt Jacob default: 1604d81ba9d5SMatt Jacob atiop->tag_action = 0; 1605d81ba9d5SMatt Jacob break; 1606d81ba9d5SMatt Jacob } 1607570c7a3fSMatt Jacob atiop->ccb_h.flags = CAM_TAG_ACTION_VALID; 1608f48ce188SMatt Jacob 160953036e92SMatt Jacob atp->tag = atiop->tag_id; 1610570c7a3fSMatt Jacob atp->lun = lun; 161153036e92SMatt Jacob atp->orig_datalen = aep->at_datalen; 161253036e92SMatt Jacob atp->last_xframt = 0; 161353036e92SMatt Jacob atp->bytes_xfered = 0; 1614570c7a3fSMatt Jacob atp->state = ATPD_STATE_CAM; 1615d81ba9d5SMatt Jacob xpt_done((union ccb*)atiop); 1616570c7a3fSMatt Jacob 161764edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 16185f5aafe1SMatt Jacob "ATIO2[%x] CDB=0x%x iid%d->lun%d tattr 0x%x datalen %u", 16195f5aafe1SMatt Jacob aep->at_rxid, aep->at_cdb[0] & 0xff, aep->at_iid, 1620b09b0095SMatt Jacob lun, aep->at_taskflags, aep->at_datalen); 1621d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1622d81ba9d5SMatt Jacob return (0); 1623d81ba9d5SMatt Jacob } 1624d81ba9d5SMatt Jacob 1625d81ba9d5SMatt Jacob static int 1626d81ba9d5SMatt Jacob isp_handle_platform_ctio(struct ispsoftc *isp, void *arg) 1627d81ba9d5SMatt Jacob { 1628d81ba9d5SMatt Jacob union ccb *ccb; 1629a1bc34c6SMatt Jacob int sentstatus, ok, notify_cam, resid = 0; 163064edff94SMatt Jacob u_int16_t tval; 1631d81ba9d5SMatt Jacob 1632d81ba9d5SMatt Jacob /* 1633d81ba9d5SMatt Jacob * CTIO and CTIO2 are close enough.... 1634d81ba9d5SMatt Jacob */ 1635d81ba9d5SMatt Jacob 16365f5aafe1SMatt Jacob ccb = (union ccb *) isp_find_xs(isp, ((ct_entry_t *)arg)->ct_syshandle); 1637d81ba9d5SMatt Jacob KASSERT((ccb != NULL), ("null ccb in isp_handle_platform_ctio")); 16385f5aafe1SMatt Jacob isp_destroy_handle(isp, ((ct_entry_t *)arg)->ct_syshandle); 1639d81ba9d5SMatt Jacob 1640d81ba9d5SMatt Jacob if (IS_FC(isp)) { 1641d81ba9d5SMatt Jacob ct2_entry_t *ct = arg; 1642570c7a3fSMatt Jacob atio_private_data_t *atp = isp_get_atpd(isp, ct->ct_rxid); 1643570c7a3fSMatt Jacob if (atp == NULL) { 1644570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGERR, 1645570c7a3fSMatt Jacob "cannot find adjunct for %x after I/O", 1646570c7a3fSMatt Jacob ct->ct_rxid); 1647570c7a3fSMatt Jacob return (0); 1648570c7a3fSMatt Jacob } 1649d81ba9d5SMatt Jacob sentstatus = ct->ct_flags & CT2_SENDSTATUS; 1650d81ba9d5SMatt Jacob ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; 1651a1bc34c6SMatt Jacob if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) { 165200a8e174SMatt Jacob ccb->ccb_h.status |= CAM_SENT_SENSE; 165300a8e174SMatt Jacob } 1654a1bc34c6SMatt Jacob notify_cam = ct->ct_header.rqs_seqno & 0x1; 16555d571944SMatt Jacob if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) { 1656a1bc34c6SMatt Jacob resid = ct->ct_resid; 165753036e92SMatt Jacob atp->bytes_xfered += (atp->last_xframt - resid); 165853036e92SMatt Jacob atp->last_xframt = 0; 1659570c7a3fSMatt Jacob } 1660570c7a3fSMatt Jacob if (sentstatus || !ok) { 166153036e92SMatt Jacob atp->tag = 0; 166253036e92SMatt Jacob } 1663570c7a3fSMatt Jacob isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, 166464edff94SMatt Jacob "CTIO2[%x] sts 0x%x flg 0x%x sns %d resid %d %s", 166564edff94SMatt Jacob ct->ct_rxid, ct->ct_status, ct->ct_flags, 166664edff94SMatt Jacob (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, 166764edff94SMatt Jacob resid, sentstatus? "FIN" : "MID"); 166864edff94SMatt Jacob tval = ct->ct_rxid; 1669570c7a3fSMatt Jacob 1670570c7a3fSMatt Jacob /* XXX: should really come after isp_complete_ctio */ 1671570c7a3fSMatt Jacob atp->state = ATPD_STATE_PDON; 1672d81ba9d5SMatt Jacob } else { 1673d81ba9d5SMatt Jacob ct_entry_t *ct = arg; 1674d81ba9d5SMatt Jacob sentstatus = ct->ct_flags & CT_SENDSTATUS; 1675d81ba9d5SMatt Jacob ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; 1676d81ba9d5SMatt Jacob /* 1677a1bc34c6SMatt Jacob * We *ought* to be able to get back to the original ATIO 1678a1bc34c6SMatt Jacob * here, but for some reason this gets lost. It's just as 1679a1bc34c6SMatt Jacob * well because it's squirrelled away as part of periph 1680a1bc34c6SMatt Jacob * private data. 1681a1bc34c6SMatt Jacob * 1682a1bc34c6SMatt Jacob * We can live without it as long as we continue to use 1683a1bc34c6SMatt Jacob * the auto-replenish feature for CTIOs. 1684a1bc34c6SMatt Jacob */ 1685a1bc34c6SMatt Jacob notify_cam = ct->ct_header.rqs_seqno & 0x1; 1686a1bc34c6SMatt Jacob if (ct->ct_status & QLTM_SVALID) { 1687a1bc34c6SMatt Jacob char *sp = (char *)ct; 1688a1bc34c6SMatt Jacob sp += CTIO_SENSE_OFFSET; 1689a1bc34c6SMatt Jacob ccb->csio.sense_len = 1690a1bc34c6SMatt Jacob min(sizeof (ccb->csio.sense_data), QLTM_SENSELEN); 1691a1bc34c6SMatt Jacob MEMCPY(&ccb->csio.sense_data, sp, ccb->csio.sense_len); 1692a1bc34c6SMatt Jacob ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 1693a1bc34c6SMatt Jacob } 16945d571944SMatt Jacob if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) { 1695a1bc34c6SMatt Jacob resid = ct->ct_resid; 1696a1bc34c6SMatt Jacob } 169764edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 169864edff94SMatt Jacob "CTIO[%x] tag %x iid %d lun %d sts %x flg %x resid %d %s", 169964edff94SMatt Jacob ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_lun, 170064edff94SMatt Jacob ct->ct_status, ct->ct_flags, resid, 170164edff94SMatt Jacob sentstatus? "FIN" : "MID"); 170264edff94SMatt Jacob tval = ct->ct_fwhandle; 17035d571944SMatt Jacob } 1704a1bc34c6SMatt Jacob ccb->csio.resid += resid; 1705a1bc34c6SMatt Jacob 1706a1bc34c6SMatt Jacob /* 1707a1bc34c6SMatt Jacob * We're here either because intermediate data transfers are done 1708a1bc34c6SMatt Jacob * and/or the final status CTIO (which may have joined with a 1709a1bc34c6SMatt Jacob * Data Transfer) is done. 1710d81ba9d5SMatt Jacob * 1711d81ba9d5SMatt Jacob * In any case, for this platform, the upper layers figure out 1712d81ba9d5SMatt Jacob * what to do next, so all we do here is collect status and 1713a1bc34c6SMatt Jacob * pass information along. Any DMA handles have already been 1714a1bc34c6SMatt Jacob * freed. 1715d81ba9d5SMatt Jacob */ 1716f48ce188SMatt Jacob if (notify_cam == 0) { 171764edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, " INTER CTIO[0x%x] done", tval); 1718f48ce188SMatt Jacob return (0); 1719f48ce188SMatt Jacob } 1720d81ba9d5SMatt Jacob 172153036e92SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO[0x%x] done", 172253036e92SMatt Jacob (sentstatus)? " FINAL " : "MIDTERM ", tval); 1723a1bc34c6SMatt Jacob 1724a1bc34c6SMatt Jacob if (!ok) { 1725a1bc34c6SMatt Jacob isp_target_putback_atio(ccb); 1726d81ba9d5SMatt Jacob } else { 1727a1bc34c6SMatt Jacob isp_complete_ctio(ccb); 1728a1bc34c6SMatt Jacob 1729d81ba9d5SMatt Jacob } 1730a1bc34c6SMatt Jacob return (0); 1731d81ba9d5SMatt Jacob } 1732570c7a3fSMatt Jacob 1733570c7a3fSMatt Jacob static int 1734570c7a3fSMatt Jacob isp_handle_platform_notify_scsi(struct ispsoftc *isp, in_entry_t *inp) 1735570c7a3fSMatt Jacob { 1736570c7a3fSMatt Jacob return (0); /* XXXX */ 1737570c7a3fSMatt Jacob } 1738570c7a3fSMatt Jacob 1739570c7a3fSMatt Jacob static int 1740570c7a3fSMatt Jacob isp_handle_platform_notify_fc(struct ispsoftc *isp, in_fcentry_t *inp) 1741570c7a3fSMatt Jacob { 1742570c7a3fSMatt Jacob 1743570c7a3fSMatt Jacob switch (inp->in_status) { 1744570c7a3fSMatt Jacob case IN_PORT_LOGOUT: 1745570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, "port logout of iid %d", 1746570c7a3fSMatt Jacob inp->in_iid); 1747570c7a3fSMatt Jacob break; 1748570c7a3fSMatt Jacob case IN_PORT_CHANGED: 1749570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, "port changed for iid %d", 1750570c7a3fSMatt Jacob inp->in_iid); 1751570c7a3fSMatt Jacob break; 1752570c7a3fSMatt Jacob case IN_GLOBAL_LOGO: 1753570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGINFO, "all ports logged out"); 1754570c7a3fSMatt Jacob break; 1755570c7a3fSMatt Jacob case IN_ABORT_TASK: 1756570c7a3fSMatt Jacob { 1757570c7a3fSMatt Jacob atio_private_data_t *atp = isp_get_atpd(isp, inp->in_seqid); 1758570c7a3fSMatt Jacob struct ccb_immed_notify *inot = NULL; 1759570c7a3fSMatt Jacob 1760570c7a3fSMatt Jacob if (atp) { 1761570c7a3fSMatt Jacob tstate_t *tptr = get_lun_statep(isp, 0, atp->lun); 1762570c7a3fSMatt Jacob if (tptr) { 1763570c7a3fSMatt Jacob inot = (struct ccb_immed_notify *) 1764570c7a3fSMatt Jacob SLIST_FIRST(&tptr->inots); 1765570c7a3fSMatt Jacob if (inot) { 1766570c7a3fSMatt Jacob SLIST_REMOVE_HEAD(&tptr->inots, 1767570c7a3fSMatt Jacob sim_links.sle); 1768570c7a3fSMatt Jacob } 1769570c7a3fSMatt Jacob } 1770570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, 1771570c7a3fSMatt Jacob "abort task RX_ID %x IID %d state %d", 1772570c7a3fSMatt Jacob inp->in_seqid, inp->in_iid, atp->state); 1773570c7a3fSMatt Jacob } else { 1774570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, 1775570c7a3fSMatt Jacob "abort task RX_ID %x from iid %d, state unknown", 1776570c7a3fSMatt Jacob inp->in_seqid, inp->in_iid); 1777570c7a3fSMatt Jacob } 1778570c7a3fSMatt Jacob if (inot) { 1779570c7a3fSMatt Jacob inot->initiator_id = inp->in_iid; 1780570c7a3fSMatt Jacob inot->sense_len = 0; 1781570c7a3fSMatt Jacob inot->message_args[0] = MSG_ABORT_TAG; 1782570c7a3fSMatt Jacob inot->message_args[1] = inp->in_seqid & 0xff; 1783570c7a3fSMatt Jacob inot->message_args[2] = (inp->in_seqid >> 8) & 0xff; 1784570c7a3fSMatt Jacob inot->ccb_h.status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN; 1785570c7a3fSMatt Jacob xpt_done((union ccb *)inot); 1786570c7a3fSMatt Jacob } 1787570c7a3fSMatt Jacob break; 1788570c7a3fSMatt Jacob } 1789570c7a3fSMatt Jacob default: 1790570c7a3fSMatt Jacob break; 1791570c7a3fSMatt Jacob } 1792570c7a3fSMatt Jacob return (0); 1793570c7a3fSMatt Jacob } 1794d81ba9d5SMatt Jacob #endif 1795d81ba9d5SMatt Jacob 1796478f8a96SJustin T. Gibbs static void 1797cbf57b47SMatt Jacob isp_cam_async(void *cbarg, u_int32_t code, struct cam_path *path, void *arg) 1798478f8a96SJustin T. Gibbs { 1799478f8a96SJustin T. Gibbs struct cam_sim *sim; 1800478f8a96SJustin T. Gibbs struct ispsoftc *isp; 1801478f8a96SJustin T. Gibbs 1802478f8a96SJustin T. Gibbs sim = (struct cam_sim *)cbarg; 1803478f8a96SJustin T. Gibbs isp = (struct ispsoftc *) cam_sim_softc(sim); 1804478f8a96SJustin T. Gibbs switch (code) { 1805478f8a96SJustin T. Gibbs case AC_LOST_DEVICE: 1806ab6c4b31SMatt Jacob if (IS_SCSI(isp)) { 1807478f8a96SJustin T. Gibbs u_int16_t oflags, nflags; 1808478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 1809a1bc34c6SMatt Jacob int tgt; 1810478f8a96SJustin T. Gibbs 1811f9e908dcSMatt Jacob tgt = xpt_path_target_id(path); 1812f6e75de2SMatt Jacob ISP_LOCK(isp); 1813ea6f23cdSMatt Jacob sdp += cam_sim_bus(sim); 18149ce9bdafSMatt Jacob nflags = sdp->isp_devparam[tgt].nvrm_flags; 1815a1bc34c6SMatt Jacob #ifndef ISP_TARGET_MODE 18169ce9bdafSMatt Jacob nflags &= DPARM_SAFE_DFLT; 1817a1bc34c6SMatt Jacob if (isp->isp_loaded_fw) { 1818478f8a96SJustin T. Gibbs nflags |= DPARM_NARROW | DPARM_ASYNC; 1819478f8a96SJustin T. Gibbs } 1820a1bc34c6SMatt Jacob #else 1821a1bc34c6SMatt Jacob nflags = DPARM_DEFAULT; 1822a1bc34c6SMatt Jacob #endif 18239ce9bdafSMatt Jacob oflags = sdp->isp_devparam[tgt].goal_flags; 18249ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_flags = nflags; 1825478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_update = 1; 1826a1bc34c6SMatt Jacob isp->isp_update |= (1 << cam_sim_bus(sim)); 1827478f8a96SJustin T. Gibbs (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL); 18289ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_flags = oflags; 1829f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1830478f8a96SJustin T. Gibbs } 1831478f8a96SJustin T. Gibbs break; 1832478f8a96SJustin T. Gibbs default: 18333c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, "isp_cam_async: Code 0x%x", code); 1834478f8a96SJustin T. Gibbs break; 1835478f8a96SJustin T. Gibbs } 1836478f8a96SJustin T. Gibbs } 1837478f8a96SJustin T. Gibbs 1838478f8a96SJustin T. Gibbs static void 1839c3055363SMatt Jacob isp_poll(struct cam_sim *sim) 1840478f8a96SJustin T. Gibbs { 1841c40e096eSMatt Jacob struct ispsoftc *isp = cam_sim_softc(sim); 1842126ec864SMatt Jacob u_int16_t isr, sema, mbox; 1843126ec864SMatt Jacob 1844c40e096eSMatt Jacob ISP_LOCK(isp); 1845126ec864SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 1846126ec864SMatt Jacob isp_intr(isp, isr, sema, mbox); 1847126ec864SMatt Jacob } 1848c40e096eSMatt Jacob ISP_UNLOCK(isp); 1849478f8a96SJustin T. Gibbs } 1850478f8a96SJustin T. Gibbs 1851ab6c4b31SMatt Jacob 1852478f8a96SJustin T. Gibbs static void 1853b85389e1SMatt Jacob isp_watchdog(void *arg) 1854cc8df88bSMatt Jacob { 1855b09b0095SMatt Jacob XS_T *xs = arg; 1856cc8df88bSMatt Jacob struct ispsoftc *isp = XS_ISP(xs); 1857cc8df88bSMatt Jacob u_int32_t handle; 1858fdeb9f2fSMatt Jacob int iok; 1859b85389e1SMatt Jacob 1860cc8df88bSMatt Jacob /* 1861b85389e1SMatt Jacob * We've decided this command is dead. Make sure we're not trying 1862b85389e1SMatt Jacob * to kill a command that's already dead by getting it's handle and 1863b85389e1SMatt Jacob * and seeing whether it's still alive. 1864cc8df88bSMatt Jacob */ 1865f6e75de2SMatt Jacob ISP_LOCK(isp); 1866fdeb9f2fSMatt Jacob iok = isp->isp_osinfo.intsok; 1867fdeb9f2fSMatt Jacob isp->isp_osinfo.intsok = 0; 1868cc8df88bSMatt Jacob handle = isp_find_handle(isp, xs); 1869cc8df88bSMatt Jacob if (handle) { 1870126ec864SMatt Jacob u_int16_t isr, sema, mbox; 1871126ec864SMatt Jacob 1872b85389e1SMatt Jacob if (XS_CMD_DONE_P(xs)) { 1873b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG1, 1874b09b0095SMatt Jacob "watchdog found done cmd (handle 0x%x)", handle); 1875f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1876b85389e1SMatt Jacob return; 1877b85389e1SMatt Jacob } 1878b85389e1SMatt Jacob 1879b85389e1SMatt Jacob if (XS_CMD_WDOG_P(xs)) { 1880b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1881b09b0095SMatt Jacob "recursive watchdog (handle 0x%x)", handle); 1882f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1883b85389e1SMatt Jacob return; 1884b85389e1SMatt Jacob } 1885b85389e1SMatt Jacob 1886b85389e1SMatt Jacob XS_CMD_S_WDOG(xs); 1887126ec864SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 1888126ec864SMatt Jacob isp_intr(isp, isr, sema, mbox); 1889126ec864SMatt Jacob } 1890126ec864SMatt Jacob if (XS_CMD_DONE_P(xs)) { 1891b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1892126ec864SMatt Jacob "watchdog cleanup for handle 0x%x", handle); 1893b85389e1SMatt Jacob xpt_done((union ccb *) xs); 1894b85389e1SMatt Jacob } else if (XS_CMD_GRACE_P(xs)) { 18951fcf5debSMatt Jacob /* 18961fcf5debSMatt Jacob * Make sure the command is *really* dead before we 18971fcf5debSMatt Jacob * release the handle (and DMA resources) for reuse. 18981fcf5debSMatt Jacob */ 18991fcf5debSMatt Jacob (void) isp_control(isp, ISPCTL_ABORT_CMD, arg); 19001fcf5debSMatt Jacob 19011fcf5debSMatt Jacob /* 19021fcf5debSMatt Jacob * After this point, the comamnd is really dead. 19031fcf5debSMatt Jacob */ 1904f6e75de2SMatt Jacob if (XS_XFRLEN(xs)) { 1905f6e75de2SMatt Jacob ISP_DMAFREE(isp, xs, handle); 1906f6e75de2SMatt Jacob } 1907cc8df88bSMatt Jacob isp_destroy_handle(isp, handle); 1908cc8df88bSMatt Jacob xpt_print_path(xs->ccb_h.path); 19093c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 19102903b272SMatt Jacob "watchdog timeout for handle 0x%x", handle); 1911cc8df88bSMatt Jacob XS_SETERR(xs, CAM_CMD_TIMEOUT); 1912b85389e1SMatt Jacob XS_CMD_C_WDOG(xs); 1913cc8df88bSMatt Jacob isp_done(xs); 1914b85389e1SMatt Jacob } else { 19154fd13c1bSMatt Jacob u_int16_t nxti, optr; 19164fd13c1bSMatt Jacob ispreq_t local, *mp= &local, *qe; 1917b85389e1SMatt Jacob 1918b85389e1SMatt Jacob XS_CMD_C_WDOG(xs); 1919b85389e1SMatt Jacob xs->ccb_h.timeout_ch = timeout(isp_watchdog, xs, hz); 19204fd13c1bSMatt Jacob if (isp_getrqentry(isp, &nxti, &optr, (void **) &qe)) { 1921f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1922b85389e1SMatt Jacob return; 1923b85389e1SMatt Jacob } 1924b85389e1SMatt Jacob XS_CMD_S_GRACE(xs); 1925b85389e1SMatt Jacob MEMZERO((void *) mp, sizeof (*mp)); 1926b85389e1SMatt Jacob mp->req_header.rqs_entry_count = 1; 1927b85389e1SMatt Jacob mp->req_header.rqs_entry_type = RQSTYPE_MARKER; 1928b85389e1SMatt Jacob mp->req_modifier = SYNC_ALL; 1929b85389e1SMatt Jacob mp->req_target = XS_CHANNEL(xs) << 7; 19304fd13c1bSMatt Jacob isp_put_request(isp, mp, qe); 19314fd13c1bSMatt Jacob ISP_ADD_REQUEST(isp, nxti); 1932b85389e1SMatt Jacob } 1933b85389e1SMatt Jacob } else { 1934b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "watchdog with no command"); 1935cc8df88bSMatt Jacob } 1936fdeb9f2fSMatt Jacob isp->isp_osinfo.intsok = iok; 1937f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1938cc8df88bSMatt Jacob } 1939cc8df88bSMatt Jacob 19405d571944SMatt Jacob static void 19415d571944SMatt Jacob isp_kthread(void *arg) 19425d571944SMatt Jacob { 19435d571944SMatt Jacob struct ispsoftc *isp = arg; 19445d571944SMatt Jacob 19455d571944SMatt Jacob mtx_lock(&isp->isp_lock); 1946fdeb9f2fSMatt Jacob /* 1947fdeb9f2fSMatt Jacob * The first loop is for our usage where we have yet to have 1948fdeb9f2fSMatt Jacob * gotten good fibre channel state. 1949fdeb9f2fSMatt Jacob */ 19505d571944SMatt Jacob for (;;) { 1951fdeb9f2fSMatt Jacob int wasfrozen; 1952fdeb9f2fSMatt Jacob 1953fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "kthread: checking FC state"); 19545d571944SMatt Jacob while (isp_fc_runstate(isp, 2 * 1000000) != 0) { 1955fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "kthread: FC state ungood"); 1956f44257c2SMatt Jacob if (FCPARAM(isp)->isp_fwstate != FW_READY || 1957f44257c2SMatt Jacob FCPARAM(isp)->isp_loopstate < LOOP_PDB_RCVD) { 1958f44257c2SMatt Jacob if (FCPARAM(isp)->loop_seen_once == 0 || 1959fdeb9f2fSMatt Jacob isp->isp_osinfo.ktmature == 0) { 1960f44257c2SMatt Jacob break; 1961f44257c2SMatt Jacob } 1962f44257c2SMatt Jacob } 19635d571944SMatt Jacob msleep(isp_kthread, &isp->isp_lock, 19645d571944SMatt Jacob PRIBIO, "isp_fcthrd", hz); 19655d571944SMatt Jacob } 1966fdeb9f2fSMatt Jacob 1967f44257c2SMatt Jacob /* 1968f44257c2SMatt Jacob * Even if we didn't get good loop state we may be 1969f44257c2SMatt Jacob * unfreezing the SIMQ so that we can kill off 1970fdeb9f2fSMatt Jacob * commands (if we've never seen loop before, for example). 1971f44257c2SMatt Jacob */ 1972fdeb9f2fSMatt Jacob isp->isp_osinfo.ktmature = 1; 19735d571944SMatt Jacob wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN; 19745d571944SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN; 19755d571944SMatt Jacob if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) { 1976fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "kthread: releasing simq"); 19775d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 19785d571944SMatt Jacob xpt_release_simq(isp->isp_sim, 1); 19795d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 19805d571944SMatt Jacob } 1981fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "kthread: waiting until called"); 19825d571944SMatt Jacob cv_wait(&isp->isp_osinfo.kthread_cv, &isp->isp_lock); 19835d571944SMatt Jacob } 19845d571944SMatt Jacob } 19855d571944SMatt Jacob 1986cc8df88bSMatt Jacob static void 1987c3055363SMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb) 1988478f8a96SJustin T. Gibbs { 1989f6e75de2SMatt Jacob int bus, tgt, error; 1990478f8a96SJustin T. Gibbs struct ispsoftc *isp; 19914663e367SJustin T. Gibbs struct ccb_trans_settings *cts; 1992478f8a96SJustin T. Gibbs 1993478f8a96SJustin T. Gibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n")); 1994478f8a96SJustin T. Gibbs 1995478f8a96SJustin T. Gibbs isp = (struct ispsoftc *)cam_sim_softc(sim); 1996478f8a96SJustin T. Gibbs ccb->ccb_h.sim_priv.entries[0].field = 0; 1997478f8a96SJustin T. Gibbs ccb->ccb_h.sim_priv.entries[1].ptr = isp; 19980470d791SMatt Jacob if (isp->isp_state != ISP_RUNSTATE && 19990470d791SMatt Jacob ccb->ccb_h.func_code == XPT_SCSI_IO) { 20005d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 200157c801f5SMatt Jacob isp_init(isp); 200257c801f5SMatt Jacob if (isp->isp_state != ISP_INITSTATE) { 2003f6e75de2SMatt Jacob ISP_UNLOCK(isp); 200457c801f5SMatt Jacob /* 200557c801f5SMatt Jacob * Lie. Say it was a selection timeout. 200657c801f5SMatt Jacob */ 2007b85389e1SMatt Jacob ccb->ccb_h.status = CAM_SEL_TIMEOUT | CAM_DEV_QFRZN; 20080470d791SMatt Jacob xpt_freeze_devq(ccb->ccb_h.path, 1); 200957c801f5SMatt Jacob xpt_done(ccb); 201057c801f5SMatt Jacob return; 201157c801f5SMatt Jacob } 201257c801f5SMatt Jacob isp->isp_state = ISP_RUNSTATE; 20135d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 201457c801f5SMatt Jacob } 2015b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "isp_action code %x", ccb->ccb_h.func_code); 2016478f8a96SJustin T. Gibbs 20175d571944SMatt Jacob 2018478f8a96SJustin T. Gibbs switch (ccb->ccb_h.func_code) { 2019478f8a96SJustin T. Gibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 2020478f8a96SJustin T. Gibbs /* 2021478f8a96SJustin T. Gibbs * Do a couple of preliminary checks... 2022478f8a96SJustin T. Gibbs */ 2023478f8a96SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { 2024478f8a96SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) { 2025478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2026478f8a96SJustin T. Gibbs xpt_done(ccb); 2027478f8a96SJustin T. Gibbs break; 2028478f8a96SJustin T. Gibbs } 2029478f8a96SJustin T. Gibbs } 20300470d791SMatt Jacob #ifdef DIAGNOSTIC 20310470d791SMatt Jacob if (ccb->ccb_h.target_id > (ISP_MAX_TARGETS(isp) - 1)) { 2032478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 20330470d791SMatt Jacob } else if (ccb->ccb_h.target_lun > (ISP_MAX_LUNS(isp) - 1)) { 2034478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 2035478f8a96SJustin T. Gibbs } 2036478f8a96SJustin T. Gibbs if (ccb->ccb_h.status == CAM_PATH_INVALID) { 2037bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 2038bfbab170SMatt Jacob "invalid tgt/lun (%d.%d) in XPT_SCSI_IO", 2039bfbab170SMatt Jacob ccb->ccb_h.target_id, ccb->ccb_h.target_lun); 2040478f8a96SJustin T. Gibbs xpt_done(ccb); 2041478f8a96SJustin T. Gibbs break; 2042478f8a96SJustin T. Gibbs } 20430470d791SMatt Jacob #endif 20440470d791SMatt Jacob ((struct ccb_scsiio *) ccb)->scsi_status = SCSI_STATUS_OK; 20455d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2046b09b0095SMatt Jacob error = isp_start((XS_T *) ccb); 20470470d791SMatt Jacob switch (error) { 2048478f8a96SJustin T. Gibbs case CMD_QUEUED: 2049478f8a96SJustin T. Gibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 2050cc8df88bSMatt Jacob if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { 2051d69a5f7dSMatt Jacob u_int64_t ticks = (u_int64_t) hz; 2052cc8df88bSMatt Jacob if (ccb->ccb_h.timeout == CAM_TIME_DEFAULT) 2053d69a5f7dSMatt Jacob ticks = 60 * 1000 * ticks; 2054b85389e1SMatt Jacob else 2055b85389e1SMatt Jacob ticks = ccb->ccb_h.timeout * hz; 2056b85389e1SMatt Jacob ticks = ((ticks + 999) / 1000) + hz + hz; 2057d69a5f7dSMatt Jacob if (ticks >= 0x80000000) { 2058d69a5f7dSMatt Jacob isp_prt(isp, ISP_LOGERR, 2059d69a5f7dSMatt Jacob "timeout overflow"); 2060fdeb9f2fSMatt Jacob ticks = 0x7fffffff; 2061d69a5f7dSMatt Jacob } 2062d69a5f7dSMatt Jacob ccb->ccb_h.timeout_ch = timeout(isp_watchdog, 2063d69a5f7dSMatt Jacob (caddr_t)ccb, (int)ticks); 2064b85389e1SMatt Jacob } else { 2065b85389e1SMatt Jacob callout_handle_init(&ccb->ccb_h.timeout_ch); 2066cc8df88bSMatt Jacob } 20675d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2068478f8a96SJustin T. Gibbs break; 20690470d791SMatt Jacob case CMD_RQLATER: 2070f44257c2SMatt Jacob /* 2071f44257c2SMatt Jacob * This can only happen for Fibre Channel 2072f44257c2SMatt Jacob */ 2073f44257c2SMatt Jacob KASSERT((IS_FC(isp)), ("CMD_RQLATER for FC only")); 2074fdeb9f2fSMatt Jacob if (FCPARAM(isp)->loop_seen_once == 0 && 2075fdeb9f2fSMatt Jacob isp->isp_osinfo.ktmature) { 2076f44257c2SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2077f44257c2SMatt Jacob XS_SETERR(ccb, CAM_SEL_TIMEOUT); 2078f44257c2SMatt Jacob xpt_done(ccb); 2079f44257c2SMatt Jacob break; 2080f44257c2SMatt Jacob } 20815d571944SMatt Jacob cv_signal(&isp->isp_osinfo.kthread_cv); 2082fdeb9f2fSMatt Jacob isp_freeze_loopdown(isp, "isp_action(RQLATER)"); 2083b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 2084fdeb9f2fSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2085478f8a96SJustin T. Gibbs xpt_done(ccb); 2086478f8a96SJustin T. Gibbs break; 20870470d791SMatt Jacob case CMD_EAGAIN: 2088b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 20895d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2090478f8a96SJustin T. Gibbs xpt_done(ccb); 2091478f8a96SJustin T. Gibbs break; 20920470d791SMatt Jacob case CMD_COMPLETE: 20930470d791SMatt Jacob isp_done((struct ccb_scsiio *) ccb); 20945d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 20950470d791SMatt Jacob break; 20960470d791SMatt Jacob default: 2097bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 2098bfbab170SMatt Jacob "What's this? 0x%x at %d in file %s", 209991f1caa2SMatt Jacob error, __LINE__, __FILE__); 2100b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQ_CMP_ERR); 21010470d791SMatt Jacob xpt_done(ccb); 21025d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2103478f8a96SJustin T. Gibbs } 2104478f8a96SJustin T. Gibbs break; 2105478f8a96SJustin T. Gibbs 2106d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2107478f8a96SJustin T. Gibbs case XPT_EN_LUN: /* Enable LUN as a target */ 210864edff94SMatt Jacob { 210964edff94SMatt Jacob int iok; 21105d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 211164edff94SMatt Jacob iok = isp->isp_osinfo.intsok; 211264edff94SMatt Jacob isp->isp_osinfo.intsok = 0; 2113d81ba9d5SMatt Jacob isp_en_lun(isp, ccb); 211464edff94SMatt Jacob isp->isp_osinfo.intsok = iok; 21155d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2116478f8a96SJustin T. Gibbs xpt_done(ccb); 2117478f8a96SJustin T. Gibbs break; 211864edff94SMatt Jacob } 2119d81ba9d5SMatt Jacob case XPT_NOTIFY_ACK: /* recycle notify ack */ 2120d81ba9d5SMatt Jacob case XPT_IMMED_NOTIFY: /* Add Immediate Notify Resource */ 2121d81ba9d5SMatt Jacob case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */ 2122d81ba9d5SMatt Jacob { 2123a1bc34c6SMatt Jacob tstate_t *tptr = 2124a1bc34c6SMatt Jacob get_lun_statep(isp, XS_CHANNEL(ccb), ccb->ccb_h.target_lun); 2125d81ba9d5SMatt Jacob if (tptr == NULL) { 2126d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 2127d81ba9d5SMatt Jacob xpt_done(ccb); 2128d81ba9d5SMatt Jacob break; 2129d81ba9d5SMatt Jacob } 2130f48ce188SMatt Jacob ccb->ccb_h.sim_priv.entries[0].field = 0; 2131f48ce188SMatt Jacob ccb->ccb_h.sim_priv.entries[1].ptr = isp; 2132570c7a3fSMatt Jacob ccb->ccb_h.flags = 0; 2133570c7a3fSMatt Jacob 21345d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2135d81ba9d5SMatt Jacob if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 2136570c7a3fSMatt Jacob /* 2137570c7a3fSMatt Jacob * Note that the command itself may not be done- 2138570c7a3fSMatt Jacob * it may not even have had the first CTIO sent. 2139570c7a3fSMatt Jacob */ 2140570c7a3fSMatt Jacob tptr->atio_count++; 2141570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 2142570c7a3fSMatt Jacob "Put FREE ATIO2, lun %d, count now %d", 2143570c7a3fSMatt Jacob ccb->ccb_h.target_lun, tptr->atio_count); 2144570c7a3fSMatt Jacob SLIST_INSERT_HEAD(&tptr->atios, &ccb->ccb_h, 2145570c7a3fSMatt Jacob sim_links.sle); 2146570c7a3fSMatt Jacob } else if (ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) { 2147d81ba9d5SMatt Jacob SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, 2148d81ba9d5SMatt Jacob sim_links.sle); 2149570c7a3fSMatt Jacob } else { 2150570c7a3fSMatt Jacob ; 2151d81ba9d5SMatt Jacob } 2152d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 2153d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_INPROG; 21545d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2155d81ba9d5SMatt Jacob break; 2156d81ba9d5SMatt Jacob } 2157d81ba9d5SMatt Jacob case XPT_CONT_TARGET_IO: 2158d81ba9d5SMatt Jacob { 21595d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2160d81ba9d5SMatt Jacob ccb->ccb_h.status = isp_target_start_ctio(isp, ccb); 2161d81ba9d5SMatt Jacob if (ccb->ccb_h.status != CAM_REQ_INPROG) { 2162570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, 2163570c7a3fSMatt Jacob "XPT_CONT_TARGET_IO: status 0x%x", 2164570c7a3fSMatt Jacob ccb->ccb_h.status); 2165b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 21665d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2167d81ba9d5SMatt Jacob xpt_done(ccb); 2168d81ba9d5SMatt Jacob } else { 21695d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2170d81ba9d5SMatt Jacob ccb->ccb_h.status |= CAM_SIM_QUEUED; 2171d81ba9d5SMatt Jacob } 2172d81ba9d5SMatt Jacob break; 2173d81ba9d5SMatt Jacob } 2174d81ba9d5SMatt Jacob #endif 2175478f8a96SJustin T. Gibbs case XPT_RESET_DEV: /* BDR the specified SCSI device */ 2176d81ba9d5SMatt Jacob 2177d81ba9d5SMatt Jacob bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path)); 2178d81ba9d5SMatt Jacob tgt = ccb->ccb_h.target_id; 2179d81ba9d5SMatt Jacob tgt |= (bus << 16); 2180d81ba9d5SMatt Jacob 21815d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2182ea6f23cdSMatt Jacob error = isp_control(isp, ISPCTL_RESET_DEV, &tgt); 21835d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2184478f8a96SJustin T. Gibbs if (error) { 2185478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2186478f8a96SJustin T. Gibbs } else { 2187478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2188478f8a96SJustin T. Gibbs } 2189478f8a96SJustin T. Gibbs xpt_done(ccb); 2190478f8a96SJustin T. Gibbs break; 2191478f8a96SJustin T. Gibbs case XPT_ABORT: /* Abort the specified CCB */ 2192d81ba9d5SMatt Jacob { 2193d81ba9d5SMatt Jacob union ccb *accb = ccb->cab.abort_ccb; 21945d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2195d81ba9d5SMatt Jacob switch (accb->ccb_h.func_code) { 2196d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2197d81ba9d5SMatt Jacob case XPT_ACCEPT_TARGET_IO: 2198d81ba9d5SMatt Jacob case XPT_IMMED_NOTIFY: 2199d81ba9d5SMatt Jacob ccb->ccb_h.status = isp_abort_tgt_ccb(isp, ccb); 2200d81ba9d5SMatt Jacob break; 2201d81ba9d5SMatt Jacob case XPT_CONT_TARGET_IO: 2202b09b0095SMatt Jacob isp_prt(isp, ISP_LOGERR, "cannot abort CTIOs yet"); 2203d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_UA_ABORT; 2204d81ba9d5SMatt Jacob break; 2205d81ba9d5SMatt Jacob #endif 2206d81ba9d5SMatt Jacob case XPT_SCSI_IO: 2207478f8a96SJustin T. Gibbs error = isp_control(isp, ISPCTL_ABORT_CMD, ccb); 2208478f8a96SJustin T. Gibbs if (error) { 2209d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_UA_ABORT; 2210478f8a96SJustin T. Gibbs } else { 2211478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2212478f8a96SJustin T. Gibbs } 2213d81ba9d5SMatt Jacob break; 2214d81ba9d5SMatt Jacob default: 2215d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_INVALID; 2216d81ba9d5SMatt Jacob break; 2217d81ba9d5SMatt Jacob } 22185d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2219478f8a96SJustin T. Gibbs xpt_done(ccb); 2220478f8a96SJustin T. Gibbs break; 2221d81ba9d5SMatt Jacob } 2222ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2223ab163f5fSMatt Jacob #define IS_CURRENT_SETTINGS(c) (c->type == CTS_TYPE_CURRENT_SETTINGS) 2224ab163f5fSMatt Jacob #else 2225ab163f5fSMatt Jacob #define IS_CURRENT_SETTINGS(c) (c->flags & CCB_TRANS_CURRENT_SETTINGS) 2226ab163f5fSMatt Jacob #endif 2227478f8a96SJustin T. Gibbs case XPT_SET_TRAN_SETTINGS: /* Nexus Settings */ 2228478f8a96SJustin T. Gibbs cts = &ccb->cts; 22299ce9bdafSMatt Jacob if (!IS_CURRENT_SETTINGS(cts)) { 22309ce9bdafSMatt Jacob ccb->ccb_h.status = CAM_REQ_INVALID; 22319ce9bdafSMatt Jacob xpt_done(ccb); 22329ce9bdafSMatt Jacob break; 22339ce9bdafSMatt Jacob } 2234478f8a96SJustin T. Gibbs tgt = cts->ccb_h.target_id; 22355d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2236ab6c4b31SMatt Jacob if (IS_SCSI(isp)) { 2237ab163f5fSMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2238478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 2239478f8a96SJustin T. Gibbs u_int16_t *dptr; 2240d81ba9d5SMatt Jacob 2241d81ba9d5SMatt Jacob bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 2242478f8a96SJustin T. Gibbs 2243ea6f23cdSMatt Jacob sdp += bus; 2244478f8a96SJustin T. Gibbs /* 22459ce9bdafSMatt Jacob * We always update (internally) from goal_flags 2246478f8a96SJustin T. Gibbs * so any request to change settings just gets 2247478f8a96SJustin T. Gibbs * vectored to that location. 2248478f8a96SJustin T. Gibbs */ 22499ce9bdafSMatt Jacob dptr = &sdp->isp_devparam[tgt].goal_flags; 2250478f8a96SJustin T. Gibbs 2251478f8a96SJustin T. Gibbs /* 2252478f8a96SJustin T. Gibbs * Note that these operations affect the 22539ce9bdafSMatt Jacob * the goal flags (goal_flags)- not 2254478f8a96SJustin T. Gibbs * the current state flags. Then we mark 2255478f8a96SJustin T. Gibbs * things so that the next operation to 2256478f8a96SJustin T. Gibbs * this HBA will cause the update to occur. 2257478f8a96SJustin T. Gibbs */ 2258478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_DISC_VALID) { 2259478f8a96SJustin T. Gibbs if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) { 2260478f8a96SJustin T. Gibbs *dptr |= DPARM_DISC; 2261478f8a96SJustin T. Gibbs } else { 2262478f8a96SJustin T. Gibbs *dptr &= ~DPARM_DISC; 2263478f8a96SJustin T. Gibbs } 2264478f8a96SJustin T. Gibbs } 2265478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_TQ_VALID) { 2266478f8a96SJustin T. Gibbs if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) { 2267478f8a96SJustin T. Gibbs *dptr |= DPARM_TQING; 2268478f8a96SJustin T. Gibbs } else { 2269478f8a96SJustin T. Gibbs *dptr &= ~DPARM_TQING; 2270478f8a96SJustin T. Gibbs } 2271478f8a96SJustin T. Gibbs } 2272478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) { 2273478f8a96SJustin T. Gibbs switch (cts->bus_width) { 2274478f8a96SJustin T. Gibbs case MSG_EXT_WDTR_BUS_16_BIT: 2275478f8a96SJustin T. Gibbs *dptr |= DPARM_WIDE; 2276478f8a96SJustin T. Gibbs break; 2277478f8a96SJustin T. Gibbs default: 2278478f8a96SJustin T. Gibbs *dptr &= ~DPARM_WIDE; 2279478f8a96SJustin T. Gibbs } 2280478f8a96SJustin T. Gibbs } 2281478f8a96SJustin T. Gibbs /* 2282478f8a96SJustin T. Gibbs * Any SYNC RATE of nonzero and SYNC_OFFSET 2283478f8a96SJustin T. Gibbs * of nonzero will cause us to go to the 2284478f8a96SJustin T. Gibbs * selected (from NVRAM) maximum value for 2285478f8a96SJustin T. Gibbs * this device. At a later point, we'll 2286478f8a96SJustin T. Gibbs * allow finer control. 2287478f8a96SJustin T. Gibbs */ 2288478f8a96SJustin T. Gibbs if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) && 2289478f8a96SJustin T. Gibbs (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) && 2290478f8a96SJustin T. Gibbs (cts->sync_offset > 0)) { 2291478f8a96SJustin T. Gibbs *dptr |= DPARM_SYNC; 2292478f8a96SJustin T. Gibbs } else { 2293478f8a96SJustin T. Gibbs *dptr &= ~DPARM_SYNC; 2294478f8a96SJustin T. Gibbs } 2295ab6c4b31SMatt Jacob *dptr |= DPARM_SAFE_DFLT; 2296ab163f5fSMatt Jacob #else 2297ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi = 2298ab163f5fSMatt Jacob &cts->proto_specific.scsi; 2299ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi = 2300ab163f5fSMatt Jacob &cts->xport_specific.spi; 2301ab163f5fSMatt Jacob sdparam *sdp = isp->isp_param; 2302ab163f5fSMatt Jacob u_int16_t *dptr; 2303ab163f5fSMatt Jacob 2304ab163f5fSMatt Jacob bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 2305ab163f5fSMatt Jacob sdp += bus; 2306ab163f5fSMatt Jacob /* 23079ce9bdafSMatt Jacob * We always update (internally) from goal_flags 2308ab163f5fSMatt Jacob * so any request to change settings just gets 2309ab163f5fSMatt Jacob * vectored to that location. 2310ab163f5fSMatt Jacob */ 23119ce9bdafSMatt Jacob dptr = &sdp->isp_devparam[tgt].goal_flags; 2312ab163f5fSMatt Jacob 2313ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_DISC) != 0) { 2314ab163f5fSMatt Jacob if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) 2315ab163f5fSMatt Jacob *dptr |= DPARM_DISC; 2316ab163f5fSMatt Jacob else 2317ab163f5fSMatt Jacob *dptr &= ~DPARM_DISC; 2318ab163f5fSMatt Jacob } 2319ab163f5fSMatt Jacob 2320ab163f5fSMatt Jacob if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 2321ab163f5fSMatt Jacob if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) 2322ab163f5fSMatt Jacob *dptr |= DPARM_TQING; 2323ab163f5fSMatt Jacob else 2324ab163f5fSMatt Jacob *dptr &= ~DPARM_TQING; 2325ab163f5fSMatt Jacob } 2326ab163f5fSMatt Jacob 2327ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 2328ab163f5fSMatt Jacob if (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT) 2329ab163f5fSMatt Jacob *dptr |= DPARM_WIDE; 2330ab163f5fSMatt Jacob else 2331ab163f5fSMatt Jacob *dptr &= ~DPARM_WIDE; 2332ab163f5fSMatt Jacob } 2333ab163f5fSMatt Jacob 2334ab163f5fSMatt Jacob /* 2335ab163f5fSMatt Jacob * XXX: FIX ME 2336ab163f5fSMatt Jacob */ 2337ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) && 23389ce9bdafSMatt Jacob (spi->valid & CTS_SPI_VALID_SYNC_RATE) && 23399ce9bdafSMatt Jacob (spi->sync_period && spi->sync_offset)) { 2340ab163f5fSMatt Jacob *dptr |= DPARM_SYNC; 23419ce9bdafSMatt Jacob /* 23429ce9bdafSMatt Jacob * XXX: CHECK FOR LEGALITY 23439ce9bdafSMatt Jacob */ 23449ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_period = 23459ce9bdafSMatt Jacob spi->sync_period; 23469ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_offset = 23479ce9bdafSMatt Jacob spi->sync_offset; 2348ab163f5fSMatt Jacob } else { 2349ab163f5fSMatt Jacob *dptr &= ~DPARM_SYNC; 2350ab163f5fSMatt Jacob } 2351ab163f5fSMatt Jacob #endif 2352bfbab170SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 23539ce9bdafSMatt Jacob "SET bus %d targ %d to flags %x off %x per %x", 23549ce9bdafSMatt Jacob bus, tgt, sdp->isp_devparam[tgt].goal_flags, 23559ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_offset, 23569ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_period); 2357478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_update = 1; 2358ea6f23cdSMatt Jacob isp->isp_update |= (1 << bus); 2359478f8a96SJustin T. Gibbs } 23605d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2361478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2362478f8a96SJustin T. Gibbs xpt_done(ccb); 2363478f8a96SJustin T. Gibbs break; 2364478f8a96SJustin T. Gibbs case XPT_GET_TRAN_SETTINGS: 2365478f8a96SJustin T. Gibbs cts = &ccb->cts; 2366478f8a96SJustin T. Gibbs tgt = cts->ccb_h.target_id; 2367ab163f5fSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2368ab6c4b31SMatt Jacob if (IS_FC(isp)) { 2369ab163f5fSMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2370478f8a96SJustin T. Gibbs /* 2371478f8a96SJustin T. Gibbs * a lot of normal SCSI things don't make sense. 2372478f8a96SJustin T. Gibbs */ 2373478f8a96SJustin T. Gibbs cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB; 2374478f8a96SJustin T. Gibbs cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2375478f8a96SJustin T. Gibbs /* 2376478f8a96SJustin T. Gibbs * How do you measure the width of a high 2377478f8a96SJustin T. Gibbs * speed serial bus? Well, in bytes. 2378478f8a96SJustin T. Gibbs * 2379478f8a96SJustin T. Gibbs * Offset and period make no sense, though, so we set 2380478f8a96SJustin T. Gibbs * (above) a 'base' transfer speed to be gigabit. 2381478f8a96SJustin T. Gibbs */ 2382478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2383ab163f5fSMatt Jacob #else 2384ab163f5fSMatt Jacob fcparam *fcp = isp->isp_param; 2385ab163f5fSMatt Jacob struct ccb_trans_settings_fc *fc = 2386ab163f5fSMatt Jacob &cts->xport_specific.fc; 2387478f8a96SJustin T. Gibbs 2388ab163f5fSMatt Jacob cts->protocol = PROTO_SCSI; 2389ab163f5fSMatt Jacob cts->protocol_version = SCSI_REV_2; 2390ab163f5fSMatt Jacob cts->transport = XPORT_FC; 2391ab163f5fSMatt Jacob cts->transport_version = 0; 2392ab163f5fSMatt Jacob 2393ab163f5fSMatt Jacob fc->valid = CTS_FC_VALID_SPEED; 239453036e92SMatt Jacob if (fcp->isp_gbspeed == 2) 239553036e92SMatt Jacob fc->bitrate = 200000; 239653036e92SMatt Jacob else 2397ab163f5fSMatt Jacob fc->bitrate = 100000; 2398ab163f5fSMatt Jacob if (tgt > 0 && tgt < MAX_FC_TARG) { 2399ab163f5fSMatt Jacob struct lportdb *lp = &fcp->portdb[tgt]; 2400ab163f5fSMatt Jacob fc->wwnn = lp->node_wwn; 2401ab163f5fSMatt Jacob fc->wwpn = lp->port_wwn; 2402ab163f5fSMatt Jacob fc->port = lp->portid; 2403ab163f5fSMatt Jacob fc->valid |= CTS_FC_VALID_WWNN | 2404ab163f5fSMatt Jacob CTS_FC_VALID_WWPN | CTS_FC_VALID_PORT; 2405ab163f5fSMatt Jacob } 2406ab163f5fSMatt Jacob #endif 2407ab163f5fSMatt Jacob } else { 2408ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2409ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi = 2410ab163f5fSMatt Jacob &cts->proto_specific.scsi; 2411ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi = 2412ab163f5fSMatt Jacob &cts->xport_specific.spi; 2413ab163f5fSMatt Jacob #endif 2414ab163f5fSMatt Jacob sdparam *sdp = isp->isp_param; 2415ab163f5fSMatt Jacob int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 2416ab163f5fSMatt Jacob u_int16_t dval, pval, oval; 2417ab163f5fSMatt Jacob 2418ea6f23cdSMatt Jacob sdp += bus; 2419ab163f5fSMatt Jacob 2420ab163f5fSMatt Jacob if (IS_CURRENT_SETTINGS(cts)) { 242183ae4407SMatt Jacob sdp->isp_devparam[tgt].dev_refresh = 1; 242283ae4407SMatt Jacob isp->isp_update |= (1 << bus); 242383ae4407SMatt Jacob (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, 242483ae4407SMatt Jacob NULL); 24259ce9bdafSMatt Jacob dval = sdp->isp_devparam[tgt].actv_flags; 24269ce9bdafSMatt Jacob oval = sdp->isp_devparam[tgt].actv_offset; 24279ce9bdafSMatt Jacob pval = sdp->isp_devparam[tgt].actv_period; 24284394c92fSMatt Jacob } else { 24299ce9bdafSMatt Jacob dval = sdp->isp_devparam[tgt].nvrm_flags; 24309ce9bdafSMatt Jacob oval = sdp->isp_devparam[tgt].nvrm_offset; 24319ce9bdafSMatt Jacob pval = sdp->isp_devparam[tgt].nvrm_period; 24324394c92fSMatt Jacob } 2433478f8a96SJustin T. Gibbs 2434ab163f5fSMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2435478f8a96SJustin T. Gibbs cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); 2436478f8a96SJustin T. Gibbs 2437478f8a96SJustin T. Gibbs if (dval & DPARM_DISC) { 2438478f8a96SJustin T. Gibbs cts->flags |= CCB_TRANS_DISC_ENB; 2439478f8a96SJustin T. Gibbs } 2440478f8a96SJustin T. Gibbs if (dval & DPARM_TQING) { 2441478f8a96SJustin T. Gibbs cts->flags |= CCB_TRANS_TAG_ENB; 2442478f8a96SJustin T. Gibbs } 2443478f8a96SJustin T. Gibbs if (dval & DPARM_WIDE) { 2444478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2445478f8a96SJustin T. Gibbs } else { 2446478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2447478f8a96SJustin T. Gibbs } 2448478f8a96SJustin T. Gibbs cts->valid = CCB_TRANS_BUS_WIDTH_VALID | 2449478f8a96SJustin T. Gibbs CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2450478f8a96SJustin T. Gibbs 24514394c92fSMatt Jacob if ((dval & DPARM_SYNC) && oval != 0) { 24524394c92fSMatt Jacob cts->sync_period = pval; 24534394c92fSMatt Jacob cts->sync_offset = oval; 2454478f8a96SJustin T. Gibbs cts->valid |= 2455478f8a96SJustin T. Gibbs CCB_TRANS_SYNC_RATE_VALID | 2456478f8a96SJustin T. Gibbs CCB_TRANS_SYNC_OFFSET_VALID; 2457478f8a96SJustin T. Gibbs } 2458ab163f5fSMatt Jacob #else 2459ab163f5fSMatt Jacob cts->protocol = PROTO_SCSI; 2460ab163f5fSMatt Jacob cts->protocol_version = SCSI_REV_2; 2461ab163f5fSMatt Jacob cts->transport = XPORT_SPI; 2462ab163f5fSMatt Jacob cts->transport_version = 2; 2463ab163f5fSMatt Jacob 2464ab163f5fSMatt Jacob scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 2465ab163f5fSMatt Jacob spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 2466ab163f5fSMatt Jacob if (dval & DPARM_DISC) { 2467ab163f5fSMatt Jacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 2468ab163f5fSMatt Jacob } 2469ab163f5fSMatt Jacob if (dval & DPARM_TQING) { 2470ab163f5fSMatt Jacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 2471ab163f5fSMatt Jacob } 24729ce9bdafSMatt Jacob if ((dval & DPARM_SYNC) && oval && pval) { 2473ab163f5fSMatt Jacob spi->sync_offset = oval; 2474ab163f5fSMatt Jacob spi->sync_period = pval; 2475ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 2476ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 2477ab163f5fSMatt Jacob } 2478ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_BUS_WIDTH; 2479ab163f5fSMatt Jacob if (dval & DPARM_WIDE) { 2480ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2481ab163f5fSMatt Jacob } else { 2482ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2483ab163f5fSMatt Jacob } 2484ab163f5fSMatt Jacob if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { 2485ab163f5fSMatt Jacob scsi->valid = CTS_SCSI_VALID_TQ; 2486ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_DISC; 2487ab163f5fSMatt Jacob } else { 2488ab163f5fSMatt Jacob scsi->valid = 0; 2489ab163f5fSMatt Jacob } 2490ab163f5fSMatt Jacob #endif 2491bfbab170SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 24929ce9bdafSMatt Jacob "GET %s bus %d targ %d to flags %x off %x per %x", 24939ce9bdafSMatt Jacob IS_CURRENT_SETTINGS(cts)? "ACTIVE" : "NVRAM", 24949ce9bdafSMatt Jacob bus, tgt, dval, oval, pval); 2495478f8a96SJustin T. Gibbs } 2496ab163f5fSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2497478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2498478f8a96SJustin T. Gibbs xpt_done(ccb); 2499478f8a96SJustin T. Gibbs break; 2500478f8a96SJustin T. Gibbs 2501478f8a96SJustin T. Gibbs case XPT_CALC_GEOMETRY: 2502478f8a96SJustin T. Gibbs { 2503478f8a96SJustin T. Gibbs struct ccb_calc_geometry *ccg; 2504478f8a96SJustin T. Gibbs u_int32_t secs_per_cylinder; 2505478f8a96SJustin T. Gibbs u_int32_t size_mb; 2506478f8a96SJustin T. Gibbs 2507478f8a96SJustin T. Gibbs ccg = &ccb->ccg; 2508478f8a96SJustin T. Gibbs if (ccg->block_size == 0) { 2509bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 2510bfbab170SMatt Jacob "%d.%d XPT_CALC_GEOMETRY block size 0?", 2511bfbab170SMatt Jacob ccg->ccb_h.target_id, ccg->ccb_h.target_lun); 2512478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2513478f8a96SJustin T. Gibbs xpt_done(ccb); 2514478f8a96SJustin T. Gibbs break; 2515478f8a96SJustin T. Gibbs } 2516478f8a96SJustin T. Gibbs size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size); 2517478f8a96SJustin T. Gibbs if (size_mb > 1024) { 2518478f8a96SJustin T. Gibbs ccg->heads = 255; 2519478f8a96SJustin T. Gibbs ccg->secs_per_track = 63; 2520478f8a96SJustin T. Gibbs } else { 2521478f8a96SJustin T. Gibbs ccg->heads = 64; 2522478f8a96SJustin T. Gibbs ccg->secs_per_track = 32; 2523478f8a96SJustin T. Gibbs } 2524478f8a96SJustin T. Gibbs secs_per_cylinder = ccg->heads * ccg->secs_per_track; 2525478f8a96SJustin T. Gibbs ccg->cylinders = ccg->volume_size / secs_per_cylinder; 2526478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2527478f8a96SJustin T. Gibbs xpt_done(ccb); 2528478f8a96SJustin T. Gibbs break; 2529478f8a96SJustin T. Gibbs } 2530478f8a96SJustin T. Gibbs case XPT_RESET_BUS: /* Reset the specified bus */ 2531ab6c4b31SMatt Jacob bus = cam_sim_bus(sim); 25325d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2533ab6c4b31SMatt Jacob error = isp_control(isp, ISPCTL_RESET_BUS, &bus); 25345d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2535478f8a96SJustin T. Gibbs if (error) 2536478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 25372b052931SMatt Jacob else { 2538ea6f23cdSMatt Jacob if (cam_sim_bus(sim) && isp->isp_path2 != NULL) 2539ea6f23cdSMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); 2540ea6f23cdSMatt Jacob else if (isp->isp_path != NULL) 25412b052931SMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path, NULL); 2542478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 25432b052931SMatt Jacob } 2544478f8a96SJustin T. Gibbs xpt_done(ccb); 2545478f8a96SJustin T. Gibbs break; 2546478f8a96SJustin T. Gibbs 2547478f8a96SJustin T. Gibbs case XPT_TERM_IO: /* Terminate the I/O process */ 2548478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2549478f8a96SJustin T. Gibbs xpt_done(ccb); 2550478f8a96SJustin T. Gibbs break; 2551478f8a96SJustin T. Gibbs 2552478f8a96SJustin T. Gibbs case XPT_PATH_INQ: /* Path routing inquiry */ 2553478f8a96SJustin T. Gibbs { 2554478f8a96SJustin T. Gibbs struct ccb_pathinq *cpi = &ccb->cpi; 2555478f8a96SJustin T. Gibbs 2556478f8a96SJustin T. Gibbs cpi->version_num = 1; 2557d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2558a1bc34c6SMatt Jacob cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO; 2559d81ba9d5SMatt Jacob #else 2560478f8a96SJustin T. Gibbs cpi->target_sprt = 0; 2561d81ba9d5SMatt Jacob #endif 2562478f8a96SJustin T. Gibbs cpi->hba_eng_cnt = 0; 25630470d791SMatt Jacob cpi->max_target = ISP_MAX_TARGETS(isp) - 1; 25640470d791SMatt Jacob cpi->max_lun = ISP_MAX_LUNS(isp) - 1; 25650470d791SMatt Jacob cpi->bus_id = cam_sim_bus(sim); 25664394c92fSMatt Jacob if (IS_FC(isp)) { 25674394c92fSMatt Jacob cpi->hba_misc = PIM_NOBUSRESET; 25680470d791SMatt Jacob /* 25690470d791SMatt Jacob * Because our loop ID can shift from time to time, 25700470d791SMatt Jacob * make our initiator ID out of range of our bus. 25710470d791SMatt Jacob */ 25720470d791SMatt Jacob cpi->initiator_id = cpi->max_target + 1; 25730470d791SMatt Jacob 25749deea857SKenneth D. Merry /* 25759deea857SKenneth D. Merry * Set base transfer capabilities for Fibre Channel. 25769deea857SKenneth D. Merry * Technically not correct because we don't know 25779deea857SKenneth D. Merry * what media we're running on top of- but we'll 25789deea857SKenneth D. Merry * look good if we always say 100MB/s. 25799deea857SKenneth D. Merry */ 258053036e92SMatt Jacob if (FCPARAM(isp)->isp_gbspeed == 2) 258153036e92SMatt Jacob cpi->base_transfer_speed = 200000; 258253036e92SMatt Jacob else 25839deea857SKenneth D. Merry cpi->base_transfer_speed = 100000; 25840470d791SMatt Jacob cpi->hba_inquiry = PI_TAG_ABLE; 2585ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2586ab163f5fSMatt Jacob cpi->transport = XPORT_FC; 2587ab163f5fSMatt Jacob cpi->transport_version = 0; /* WHAT'S THIS FOR? */ 2588ab163f5fSMatt Jacob #endif 2589478f8a96SJustin T. Gibbs } else { 2590ea6f23cdSMatt Jacob sdparam *sdp = isp->isp_param; 2591ea6f23cdSMatt Jacob sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path)); 25920470d791SMatt Jacob cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; 25934394c92fSMatt Jacob cpi->hba_misc = 0; 2594ea6f23cdSMatt Jacob cpi->initiator_id = sdp->isp_initiator_id; 25959deea857SKenneth D. Merry cpi->base_transfer_speed = 3300; 2596ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2597ab163f5fSMatt Jacob cpi->transport = XPORT_SPI; 2598ab163f5fSMatt Jacob cpi->transport_version = 2; /* WHAT'S THIS FOR? */ 2599ab163f5fSMatt Jacob #endif 2600478f8a96SJustin T. Gibbs } 2601ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2602ab163f5fSMatt Jacob cpi->protocol = PROTO_SCSI; 2603ab163f5fSMatt Jacob cpi->protocol_version = SCSI_REV_2; 2604ab163f5fSMatt Jacob #endif 2605478f8a96SJustin T. Gibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 2606478f8a96SJustin T. Gibbs strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN); 2607478f8a96SJustin T. Gibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 2608478f8a96SJustin T. Gibbs cpi->unit_number = cam_sim_unit(sim); 2609478f8a96SJustin T. Gibbs cpi->ccb_h.status = CAM_REQ_CMP; 2610478f8a96SJustin T. Gibbs xpt_done(ccb); 2611478f8a96SJustin T. Gibbs break; 2612478f8a96SJustin T. Gibbs } 2613478f8a96SJustin T. Gibbs default: 2614478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2615478f8a96SJustin T. Gibbs xpt_done(ccb); 2616478f8a96SJustin T. Gibbs break; 2617478f8a96SJustin T. Gibbs } 2618478f8a96SJustin T. Gibbs } 2619d3a9eb2eSMatt Jacob 2620d3a9eb2eSMatt Jacob #define ISPDDB (CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB) 2621d3a9eb2eSMatt Jacob void 2622c3055363SMatt Jacob isp_done(struct ccb_scsiio *sccb) 2623d3a9eb2eSMatt Jacob { 2624d3a9eb2eSMatt Jacob struct ispsoftc *isp = XS_ISP(sccb); 2625d3a9eb2eSMatt Jacob 2626d3a9eb2eSMatt Jacob if (XS_NOERR(sccb)) 2627d3a9eb2eSMatt Jacob XS_SETERR(sccb, CAM_REQ_CMP); 2628b85389e1SMatt Jacob 2629d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP && 2630d3a9eb2eSMatt Jacob (sccb->scsi_status != SCSI_STATUS_OK)) { 2631d3a9eb2eSMatt Jacob sccb->ccb_h.status &= ~CAM_STATUS_MASK; 263292a1e549SMatt Jacob if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) && 263392a1e549SMatt Jacob (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) { 263492a1e549SMatt Jacob sccb->ccb_h.status |= CAM_AUTOSENSE_FAIL; 263592a1e549SMatt Jacob } else { 2636d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 2637d3a9eb2eSMatt Jacob } 263892a1e549SMatt Jacob } 2639b85389e1SMatt Jacob 26400470d791SMatt Jacob sccb->ccb_h.status &= ~CAM_SIM_QUEUED; 2641d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2642d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 2643d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_DEV_QFRZN; 26440470d791SMatt Jacob xpt_freeze_devq(sccb->ccb_h.path, 1); 2645fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 2646fdeb9f2fSMatt Jacob "freeze devq %d.%d cam sts %x scsi sts %x", 2647fdeb9f2fSMatt Jacob sccb->ccb_h.target_id, sccb->ccb_h.target_lun, 2648fdeb9f2fSMatt Jacob sccb->ccb_h.status, sccb->scsi_status); 2649d3a9eb2eSMatt Jacob } 2650d3a9eb2eSMatt Jacob } 2651b85389e1SMatt Jacob 2652b85389e1SMatt Jacob if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) && 2653d3a9eb2eSMatt Jacob (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2654d3a9eb2eSMatt Jacob xpt_print_path(sccb->ccb_h.path); 26553c75bb14SMatt Jacob isp_prt(isp, ISP_LOGINFO, 26563c75bb14SMatt Jacob "cam completion status 0x%x", sccb->ccb_h.status); 2657d3a9eb2eSMatt Jacob } 2658b85389e1SMatt Jacob 2659b85389e1SMatt Jacob XS_CMD_S_DONE(sccb); 2660b85389e1SMatt Jacob if (XS_CMD_WDOG_P(sccb) == 0) { 2661b85389e1SMatt Jacob untimeout(isp_watchdog, (caddr_t)sccb, sccb->ccb_h.timeout_ch); 2662b85389e1SMatt Jacob if (XS_CMD_GRACE_P(sccb)) { 2663b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2664b09b0095SMatt Jacob "finished command on borrowed time"); 2665b85389e1SMatt Jacob } 2666b85389e1SMatt Jacob XS_CMD_S_CLEAR(sccb); 26675d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2668d3a9eb2eSMatt Jacob xpt_done((union ccb *) sccb); 26695d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2670d3a9eb2eSMatt Jacob } 2671b85389e1SMatt Jacob } 2672d3a9eb2eSMatt Jacob 2673cbf57b47SMatt Jacob int 26740470d791SMatt Jacob isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg) 2675cbf57b47SMatt Jacob { 2676ea6f23cdSMatt Jacob int bus, rv = 0; 2677cbf57b47SMatt Jacob switch (cmd) { 2678cbf57b47SMatt Jacob case ISPASYNC_NEW_TGT_PARAMS: 26790470d791SMatt Jacob { 2680ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2681ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi; 2682ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi; 2683ab163f5fSMatt Jacob #endif 2684cbf57b47SMatt Jacob int flags, tgt; 2685cbf57b47SMatt Jacob sdparam *sdp = isp->isp_param; 2686ab163f5fSMatt Jacob struct ccb_trans_settings cts; 2687cbf57b47SMatt Jacob struct cam_path *tmppath; 2688cbf57b47SMatt Jacob 2689ab163f5fSMatt Jacob bzero(&cts, sizeof (struct ccb_trans_settings)); 2690ab163f5fSMatt Jacob 2691cbf57b47SMatt Jacob tgt = *((int *)arg); 2692ea6f23cdSMatt Jacob bus = (tgt >> 16) & 0xffff; 2693ea6f23cdSMatt Jacob tgt &= 0xffff; 2694ea6f23cdSMatt Jacob sdp += bus; 269545c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2696cbf57b47SMatt Jacob if (xpt_create_path(&tmppath, NULL, 2697ea6f23cdSMatt Jacob cam_sim_path(bus? isp->isp_sim2 : isp->isp_sim), 2698ea6f23cdSMatt Jacob tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 269945c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2700bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 2701bfbab170SMatt Jacob "isp_async cannot make temp path for %d.%d", 2702bfbab170SMatt Jacob tgt, bus); 2703cbf57b47SMatt Jacob rv = -1; 2704cbf57b47SMatt Jacob break; 2705cbf57b47SMatt Jacob } 270645c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 27079ce9bdafSMatt Jacob flags = sdp->isp_devparam[tgt].actv_flags; 2708ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2709ab163f5fSMatt Jacob cts.type = CTS_TYPE_CURRENT_SETTINGS; 2710ab163f5fSMatt Jacob cts.protocol = PROTO_SCSI; 2711ab163f5fSMatt Jacob cts.transport = XPORT_SPI; 2712ab163f5fSMatt Jacob 2713ab163f5fSMatt Jacob scsi = &cts.proto_specific.scsi; 2714ab163f5fSMatt Jacob spi = &cts.xport_specific.spi; 2715ab163f5fSMatt Jacob 2716ab163f5fSMatt Jacob if (flags & DPARM_TQING) { 2717ab163f5fSMatt Jacob scsi->valid |= CTS_SCSI_VALID_TQ; 2718ab163f5fSMatt Jacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 2719ab163f5fSMatt Jacob spi->flags |= CTS_SPI_FLAGS_TAG_ENB; 2720ab163f5fSMatt Jacob } 2721ab163f5fSMatt Jacob 2722cbf57b47SMatt Jacob if (flags & DPARM_DISC) { 2723ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_DISC; 2724ab163f5fSMatt Jacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 2725ab163f5fSMatt Jacob } 2726ab163f5fSMatt Jacob spi->flags |= CTS_SPI_VALID_BUS_WIDTH; 2727ab163f5fSMatt Jacob if (flags & DPARM_WIDE) { 2728ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2729ab163f5fSMatt Jacob } else { 2730ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2731ab163f5fSMatt Jacob } 2732ab163f5fSMatt Jacob if (flags & DPARM_SYNC) { 2733ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 2734ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 27359ce9bdafSMatt Jacob spi->sync_period = sdp->isp_devparam[tgt].actv_period; 27369ce9bdafSMatt Jacob spi->sync_offset = sdp->isp_devparam[tgt].actv_offset; 2737ab163f5fSMatt Jacob } 2738ab163f5fSMatt Jacob #else 2739ab163f5fSMatt Jacob cts.flags = CCB_TRANS_CURRENT_SETTINGS; 2740ab163f5fSMatt Jacob cts.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2741ab163f5fSMatt Jacob if (flags & DPARM_DISC) { 2742ab163f5fSMatt Jacob cts.flags |= CCB_TRANS_DISC_ENB; 2743cbf57b47SMatt Jacob } 2744cbf57b47SMatt Jacob if (flags & DPARM_TQING) { 2745ab163f5fSMatt Jacob cts.flags |= CCB_TRANS_TAG_ENB; 2746cbf57b47SMatt Jacob } 2747ab163f5fSMatt Jacob cts.valid |= CCB_TRANS_BUS_WIDTH_VALID; 2748ab163f5fSMatt Jacob cts.bus_width = (flags & DPARM_WIDE)? 2749cbf57b47SMatt Jacob MSG_EXT_WDTR_BUS_8_BIT : MSG_EXT_WDTR_BUS_16_BIT; 27509ce9bdafSMatt Jacob cts.sync_period = sdp->isp_devparam[tgt].actv_period; 27519ce9bdafSMatt Jacob cts.sync_offset = sdp->isp_devparam[tgt].actv_offset; 2752cbf57b47SMatt Jacob if (flags & DPARM_SYNC) { 2753ab163f5fSMatt Jacob cts.valid |= 27544394c92fSMatt Jacob CCB_TRANS_SYNC_RATE_VALID | 2755cbf57b47SMatt Jacob CCB_TRANS_SYNC_OFFSET_VALID; 2756cbf57b47SMatt Jacob } 2757ab163f5fSMatt Jacob #endif 2758b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2759b09b0095SMatt Jacob "NEW_TGT_PARAMS bus %d tgt %d period %x offset %x flags %x", 27609ce9bdafSMatt Jacob bus, tgt, sdp->isp_devparam[tgt].actv_period, 27619ce9bdafSMatt Jacob sdp->isp_devparam[tgt].actv_offset, flags); 2762ab163f5fSMatt Jacob xpt_setup_ccb(&cts.ccb_h, tmppath, 1); 27635d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2764ab163f5fSMatt Jacob xpt_async(AC_TRANSFER_NEG, tmppath, &cts); 2765cbf57b47SMatt Jacob xpt_free_path(tmppath); 2766f44257c2SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2767cbf57b47SMatt Jacob break; 27680470d791SMatt Jacob } 276957c801f5SMatt Jacob case ISPASYNC_BUS_RESET: 2770ea6f23cdSMatt Jacob bus = *((int *)arg); 2771b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected", 2772b09b0095SMatt Jacob bus); 2773ea6f23cdSMatt Jacob if (bus > 0 && isp->isp_path2) { 27745d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2775ea6f23cdSMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); 27765d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2777ea6f23cdSMatt Jacob } else if (isp->isp_path) { 27785d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 277957c801f5SMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path, NULL); 27805d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 278157c801f5SMatt Jacob } 278257c801f5SMatt Jacob break; 27835d571944SMatt Jacob case ISPASYNC_LIP: 27845d571944SMatt Jacob if (isp->isp_path) { 2785fdeb9f2fSMatt Jacob isp_freeze_loopdown(isp, "ISPASYNC_LIP"); 27865d571944SMatt Jacob } 27875d571944SMatt Jacob isp_prt(isp, ISP_LOGINFO, "LIP Received"); 27885d571944SMatt Jacob break; 27895d571944SMatt Jacob case ISPASYNC_LOOP_RESET: 27905d571944SMatt Jacob if (isp->isp_path) { 2791fdeb9f2fSMatt Jacob isp_freeze_loopdown(isp, "ISPASYNC_LOOP_RESET"); 27925d571944SMatt Jacob } 27935d571944SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop Reset Received"); 27945d571944SMatt Jacob break; 279557c801f5SMatt Jacob case ISPASYNC_LOOP_DOWN: 279657c801f5SMatt Jacob if (isp->isp_path) { 2797fdeb9f2fSMatt Jacob isp_freeze_loopdown(isp, "ISPASYNC_LOOP_DOWN"); 279857c801f5SMatt Jacob } 2799b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop DOWN"); 280057c801f5SMatt Jacob break; 280157c801f5SMatt Jacob case ISPASYNC_LOOP_UP: 28025d571944SMatt Jacob /* 28035d571944SMatt Jacob * Now we just note that Loop has come up. We don't 28045d571944SMatt Jacob * actually do anything because we're waiting for a 28055d571944SMatt Jacob * Change Notify before activating the FC cleanup 28065d571944SMatt Jacob * thread to look at the state of the loop again. 28075d571944SMatt Jacob */ 2808b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop UP"); 280957c801f5SMatt Jacob break; 2810d6e5500fSMatt Jacob case ISPASYNC_PROMENADE: 28110470d791SMatt Jacob { 2812ab163f5fSMatt Jacob struct cam_path *tmppath; 2813b09b0095SMatt Jacob const char *fmt = "Target %d (Loop 0x%x) Port ID 0x%x " 2814d6e5500fSMatt Jacob "(role %s) %s\n Port WWN 0x%08x%08x\n Node WWN 0x%08x%08x"; 2815d6e5500fSMatt Jacob static const char *roles[4] = { 28160470d791SMatt Jacob "(none)", "Target", "Initiator", "Target/Initiator" 281757c801f5SMatt Jacob }; 281802ab3379SMatt Jacob fcparam *fcp = isp->isp_param; 281902ab3379SMatt Jacob int tgt = *((int *) arg); 2820f44257c2SMatt Jacob int is_tgt_mask = (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT); 282102ab3379SMatt Jacob struct lportdb *lp = &fcp->portdb[tgt]; 282202ab3379SMatt Jacob 2823b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, fmt, tgt, lp->loopid, lp->portid, 2824d6e5500fSMatt Jacob roles[lp->roles & 0x3], 2825d6e5500fSMatt Jacob (lp->valid)? "Arrived" : "Departed", 282602ab3379SMatt Jacob (u_int32_t) (lp->port_wwn >> 32), 282702ab3379SMatt Jacob (u_int32_t) (lp->port_wwn & 0xffffffffLL), 282802ab3379SMatt Jacob (u_int32_t) (lp->node_wwn >> 32), 282902ab3379SMatt Jacob (u_int32_t) (lp->node_wwn & 0xffffffffLL)); 2830ab163f5fSMatt Jacob 283145c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2832ab163f5fSMatt Jacob if (xpt_create_path(&tmppath, NULL, cam_sim_path(isp->isp_sim), 2833ab163f5fSMatt Jacob (target_id_t)tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 283445c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2835ab163f5fSMatt Jacob break; 2836ab163f5fSMatt Jacob } 2837f44257c2SMatt Jacob /* 2838f44257c2SMatt Jacob * Policy: only announce targets. 2839f44257c2SMatt Jacob */ 2840f44257c2SMatt Jacob if (lp->roles & is_tgt_mask) { 2841f44257c2SMatt Jacob if (lp->valid) { 2842ab163f5fSMatt Jacob xpt_async(AC_FOUND_DEVICE, tmppath, NULL); 2843ab163f5fSMatt Jacob } else { 2844ab163f5fSMatt Jacob xpt_async(AC_LOST_DEVICE, tmppath, NULL); 2845ab163f5fSMatt Jacob } 2846f44257c2SMatt Jacob } 2847ab163f5fSMatt Jacob xpt_free_path(tmppath); 2848f44257c2SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 28494394c92fSMatt Jacob break; 28504394c92fSMatt Jacob } 285157c801f5SMatt Jacob case ISPASYNC_CHANGE_NOTIFY: 2852f44257c2SMatt Jacob if (arg == ISPASYNC_CHANGE_PDB) { 28534b9d588eSMatt Jacob isp_prt(isp, ISP_LOGINFO, 2854f44257c2SMatt Jacob "Port Database Changed"); 2855f44257c2SMatt Jacob } else if (arg == ISPASYNC_CHANGE_SNS) { 28564b9d588eSMatt Jacob isp_prt(isp, ISP_LOGINFO, 28574b9d588eSMatt Jacob "Name Server Database Changed"); 28584b9d588eSMatt Jacob } 28595d571944SMatt Jacob cv_signal(&isp->isp_osinfo.kthread_cv); 286057c801f5SMatt Jacob break; 286102ab3379SMatt Jacob case ISPASYNC_FABRIC_DEV: 286202ab3379SMatt Jacob { 2863029f13c6SMatt Jacob int target, base, lim; 286402ab3379SMatt Jacob fcparam *fcp = isp->isp_param; 2865029f13c6SMatt Jacob struct lportdb *lp = NULL; 2866029f13c6SMatt Jacob struct lportdb *clp = (struct lportdb *) arg; 2867029f13c6SMatt Jacob char *pt; 286802ab3379SMatt Jacob 2869029f13c6SMatt Jacob switch (clp->port_type) { 287040cfc8feSMatt Jacob case 1: 287140cfc8feSMatt Jacob pt = " N_Port"; 287240cfc8feSMatt Jacob break; 287340cfc8feSMatt Jacob case 2: 287440cfc8feSMatt Jacob pt = " NL_Port"; 287540cfc8feSMatt Jacob break; 287640cfc8feSMatt Jacob case 3: 287740cfc8feSMatt Jacob pt = "F/NL_Port"; 287840cfc8feSMatt Jacob break; 287940cfc8feSMatt Jacob case 0x7f: 288040cfc8feSMatt Jacob pt = " Nx_Port"; 288140cfc8feSMatt Jacob break; 288240cfc8feSMatt Jacob case 0x81: 288340cfc8feSMatt Jacob pt = " F_port"; 288440cfc8feSMatt Jacob break; 288540cfc8feSMatt Jacob case 0x82: 288640cfc8feSMatt Jacob pt = " FL_Port"; 288740cfc8feSMatt Jacob break; 288840cfc8feSMatt Jacob case 0x84: 288940cfc8feSMatt Jacob pt = " E_port"; 289040cfc8feSMatt Jacob break; 289140cfc8feSMatt Jacob default: 2892029f13c6SMatt Jacob pt = " "; 289340cfc8feSMatt Jacob break; 289440cfc8feSMatt Jacob } 2895029f13c6SMatt Jacob 2896b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, 2897029f13c6SMatt Jacob "%s Fabric Device @ PortID 0x%x", pt, clp->portid); 2898029f13c6SMatt Jacob 289970d2ccceSMatt Jacob /* 2900029f13c6SMatt Jacob * If we don't have an initiator role we bail. 2901029f13c6SMatt Jacob * 2902029f13c6SMatt Jacob * We just use ISPASYNC_FABRIC_DEV for announcement purposes. 290370d2ccceSMatt Jacob */ 2904029f13c6SMatt Jacob 2905029f13c6SMatt Jacob if ((isp->isp_role & ISP_ROLE_INITIATOR) == 0) { 290602ab3379SMatt Jacob break; 290702ab3379SMatt Jacob } 2908029f13c6SMatt Jacob 2909029f13c6SMatt Jacob /* 2910029f13c6SMatt Jacob * Is this entry for us? If so, we bail. 2911029f13c6SMatt Jacob */ 2912029f13c6SMatt Jacob 2913029f13c6SMatt Jacob if (fcp->isp_portid == clp->portid) { 2914029f13c6SMatt Jacob break; 2915029f13c6SMatt Jacob } 2916029f13c6SMatt Jacob 2917029f13c6SMatt Jacob /* 2918029f13c6SMatt Jacob * Else, the default policy is to find room for it in 2919029f13c6SMatt Jacob * our local port database. Later, when we execute 2920029f13c6SMatt Jacob * the call to isp_pdb_sync either this newly arrived 2921029f13c6SMatt Jacob * or already logged in device will be (re)announced. 2922029f13c6SMatt Jacob */ 2923029f13c6SMatt Jacob 2924029f13c6SMatt Jacob if (fcp->isp_topo == TOPO_FL_PORT) 2925029f13c6SMatt Jacob base = FC_SNS_ID+1; 292670d2ccceSMatt Jacob else 2927029f13c6SMatt Jacob base = 0; 2928029f13c6SMatt Jacob 2929029f13c6SMatt Jacob if (fcp->isp_topo == TOPO_N_PORT) 2930029f13c6SMatt Jacob lim = 1; 2931029f13c6SMatt Jacob else 2932029f13c6SMatt Jacob lim = MAX_FC_TARG; 2933029f13c6SMatt Jacob 293470d2ccceSMatt Jacob /* 293570d2ccceSMatt Jacob * Is it already in our list? 293670d2ccceSMatt Jacob */ 2937029f13c6SMatt Jacob for (target = base; target < lim; target++) { 293870d2ccceSMatt Jacob if (target >= FL_PORT_ID && target <= FC_SNS_ID) { 293970d2ccceSMatt Jacob continue; 294070d2ccceSMatt Jacob } 294170d2ccceSMatt Jacob lp = &fcp->portdb[target]; 2942029f13c6SMatt Jacob if (lp->port_wwn == clp->port_wwn && 2943029f13c6SMatt Jacob lp->node_wwn == clp->node_wwn) { 294470d2ccceSMatt Jacob lp->fabric_dev = 1; 294570d2ccceSMatt Jacob break; 294670d2ccceSMatt Jacob } 294770d2ccceSMatt Jacob } 2948029f13c6SMatt Jacob if (target < lim) { 294902ab3379SMatt Jacob break; 295002ab3379SMatt Jacob } 2951029f13c6SMatt Jacob for (target = base; target < lim; target++) { 295270d2ccceSMatt Jacob if (target >= FL_PORT_ID && target <= FC_SNS_ID) { 295370d2ccceSMatt Jacob continue; 295470d2ccceSMatt Jacob } 295502ab3379SMatt Jacob lp = &fcp->portdb[target]; 295670d2ccceSMatt Jacob if (lp->port_wwn == 0) { 295702ab3379SMatt Jacob break; 295802ab3379SMatt Jacob } 295970d2ccceSMatt Jacob } 2960029f13c6SMatt Jacob if (target == lim) { 2961bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 2962029f13c6SMatt Jacob "out of space for fabric devices"); 296302ab3379SMatt Jacob break; 296402ab3379SMatt Jacob } 2965029f13c6SMatt Jacob lp->port_type = clp->port_type; 2966029f13c6SMatt Jacob lp->fc4_type = clp->fc4_type; 2967029f13c6SMatt Jacob lp->node_wwn = clp->node_wwn; 2968029f13c6SMatt Jacob lp->port_wwn = clp->port_wwn; 2969029f13c6SMatt Jacob lp->portid = clp->portid; 297070d2ccceSMatt Jacob lp->fabric_dev = 1; 297102ab3379SMatt Jacob break; 297202ab3379SMatt Jacob } 2973d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2974d81ba9d5SMatt Jacob case ISPASYNC_TARGET_MESSAGE: 2975d81ba9d5SMatt Jacob { 2976d81ba9d5SMatt Jacob tmd_msg_t *mp = arg; 297764edff94SMatt Jacob isp_prt(isp, ISP_LOGALL, 2978b09b0095SMatt Jacob "bus %d iid %d tgt %d lun %d ttype %x tval %x msg[0]=%x", 2979b09b0095SMatt Jacob mp->nt_bus, (int) mp->nt_iid, (int) mp->nt_tgt, 2980b09b0095SMatt Jacob (int) mp->nt_lun, mp->nt_tagtype, mp->nt_tagval, 2981b09b0095SMatt Jacob mp->nt_msg[0]); 2982d81ba9d5SMatt Jacob break; 2983d81ba9d5SMatt Jacob } 2984d81ba9d5SMatt Jacob case ISPASYNC_TARGET_EVENT: 2985d81ba9d5SMatt Jacob { 2986d81ba9d5SMatt Jacob tmd_event_t *ep = arg; 298764edff94SMatt Jacob isp_prt(isp, ISP_LOGALL, 2988b09b0095SMatt Jacob "bus %d event code 0x%x", ep->ev_bus, ep->ev_event); 2989d81ba9d5SMatt Jacob break; 2990d81ba9d5SMatt Jacob } 2991d81ba9d5SMatt Jacob case ISPASYNC_TARGET_ACTION: 2992d81ba9d5SMatt Jacob switch (((isphdr_t *)arg)->rqs_entry_type) { 2993cbf57b47SMatt Jacob default: 2994bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 2995bfbab170SMatt Jacob "event 0x%x for unhandled target action", 2996bfbab170SMatt Jacob ((isphdr_t *)arg)->rqs_entry_type); 2997d81ba9d5SMatt Jacob break; 2998570c7a3fSMatt Jacob case RQSTYPE_NOTIFY: 2999570c7a3fSMatt Jacob if (IS_SCSI(isp)) { 3000570c7a3fSMatt Jacob rv = isp_handle_platform_notify_scsi(isp, 3001570c7a3fSMatt Jacob (in_entry_t *) arg); 3002570c7a3fSMatt Jacob } else { 3003570c7a3fSMatt Jacob rv = isp_handle_platform_notify_fc(isp, 3004570c7a3fSMatt Jacob (in_fcentry_t *) arg); 3005570c7a3fSMatt Jacob } 3006570c7a3fSMatt Jacob break; 3007d81ba9d5SMatt Jacob case RQSTYPE_ATIO: 3008d81ba9d5SMatt Jacob rv = isp_handle_platform_atio(isp, (at_entry_t *) arg); 3009d81ba9d5SMatt Jacob break; 3010d81ba9d5SMatt Jacob case RQSTYPE_ATIO2: 3011d81ba9d5SMatt Jacob rv = isp_handle_platform_atio2(isp, (at2_entry_t *)arg); 3012d81ba9d5SMatt Jacob break; 3013d81ba9d5SMatt Jacob case RQSTYPE_CTIO2: 3014d81ba9d5SMatt Jacob case RQSTYPE_CTIO: 3015d81ba9d5SMatt Jacob rv = isp_handle_platform_ctio(isp, arg); 3016d81ba9d5SMatt Jacob break; 3017d81ba9d5SMatt Jacob case RQSTYPE_ENABLE_LUN: 3018d81ba9d5SMatt Jacob case RQSTYPE_MODIFY_LUN: 301964edff94SMatt Jacob if (IS_DUALBUS(isp)) { 302064edff94SMatt Jacob bus = 302164edff94SMatt Jacob GET_BUS_VAL(((lun_entry_t *)arg)->le_rsvd); 302264edff94SMatt Jacob } else { 302364edff94SMatt Jacob bus = 0; 302464edff94SMatt Jacob } 302564edff94SMatt Jacob isp_cv_signal_rqe(isp, bus, 302664edff94SMatt Jacob ((lun_entry_t *)arg)->le_status); 3027d81ba9d5SMatt Jacob break; 3028d81ba9d5SMatt Jacob } 3029d81ba9d5SMatt Jacob break; 3030d81ba9d5SMatt Jacob #endif 3031ab163f5fSMatt Jacob case ISPASYNC_FW_CRASH: 3032ab163f5fSMatt Jacob { 3033ab163f5fSMatt Jacob u_int16_t mbox1, mbox6; 3034ab163f5fSMatt Jacob mbox1 = ISP_READ(isp, OUTMAILBOX1); 3035ab163f5fSMatt Jacob if (IS_DUALBUS(isp)) { 3036ab163f5fSMatt Jacob mbox6 = ISP_READ(isp, OUTMAILBOX6); 3037ab163f5fSMatt Jacob } else { 3038ab163f5fSMatt Jacob mbox6 = 0; 3039ab163f5fSMatt Jacob } 3040ab163f5fSMatt Jacob isp_prt(isp, ISP_LOGERR, 3041570c7a3fSMatt Jacob "Internal Firmware Error on bus %d @ RISC Address 0x%x", 3042ab163f5fSMatt Jacob mbox6, mbox1); 30438a5f89b9SMatt Jacob #ifdef ISP_FW_CRASH_DUMP 30448a5f89b9SMatt Jacob /* 30458a5f89b9SMatt Jacob * XXX: really need a thread to do this right. 30468a5f89b9SMatt Jacob */ 30478a5f89b9SMatt Jacob if (IS_FC(isp)) { 30488a5f89b9SMatt Jacob FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; 30498a5f89b9SMatt Jacob FCPARAM(isp)->isp_loopstate = LOOP_NIL; 30508a5f89b9SMatt Jacob isp_freeze_loopdown(isp, "f/w crash"); 30518a5f89b9SMatt Jacob isp_fw_dump(isp); 30528a5f89b9SMatt Jacob } 3053ab163f5fSMatt Jacob isp_reinit(isp); 30548a5f89b9SMatt Jacob isp_async(isp, ISPASYNC_FW_RESTARTED, NULL); 30558a5f89b9SMatt Jacob #endif 3056ab163f5fSMatt Jacob break; 3057ab163f5fSMatt Jacob } 3058be534d5fSMatt Jacob case ISPASYNC_UNHANDLED_RESPONSE: 3059be534d5fSMatt Jacob break; 3060d81ba9d5SMatt Jacob default: 3061b09b0095SMatt Jacob isp_prt(isp, ISP_LOGERR, "unknown isp_async event %d", cmd); 3062cbf57b47SMatt Jacob break; 3063cbf57b47SMatt Jacob } 3064cbf57b47SMatt Jacob return (rv); 3065cbf57b47SMatt Jacob } 3066cbf57b47SMatt Jacob 306792718a7fSMatt Jacob 306892718a7fSMatt Jacob /* 306992718a7fSMatt Jacob * Locks are held before coming here. 307092718a7fSMatt Jacob */ 307192718a7fSMatt Jacob void 307292718a7fSMatt Jacob isp_uninit(struct ispsoftc *isp) 307392718a7fSMatt Jacob { 3074ea6f23cdSMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_RESET); 307592718a7fSMatt Jacob DISABLE_INTS(isp); 307692718a7fSMatt Jacob } 3077b09b0095SMatt Jacob 3078b09b0095SMatt Jacob void 3079b09b0095SMatt Jacob isp_prt(struct ispsoftc *isp, int level, const char *fmt, ...) 3080b09b0095SMatt Jacob { 3081b09b0095SMatt Jacob va_list ap; 3082b09b0095SMatt Jacob if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) { 3083b09b0095SMatt Jacob return; 3084b09b0095SMatt Jacob } 30853c75bb14SMatt Jacob printf("%s: ", device_get_nameunit(isp->isp_dev)); 3086b09b0095SMatt Jacob va_start(ap, fmt); 3087b09b0095SMatt Jacob vprintf(fmt, ap); 3088b09b0095SMatt Jacob va_end(ap); 3089b09b0095SMatt Jacob printf("\n"); 3090b09b0095SMatt Jacob } 3091