1098ca2bdSWarner Losh /*- 26054c3f6SMatt Jacob * Platform (FreeBSD) dependent common attachment code for Qlogic adapters. 36054c3f6SMatt Jacob * 4e5265237SMatt Jacob * Copyright (c) 1997-2006 by Matthew Jacob 5e5265237SMatt Jacob * All rights reserved. 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 */ 28aad970f1SDavid E. O'Brien 29aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 30aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 31aad970f1SDavid E. O'Brien 326054c3f6SMatt Jacob #include <dev/isp/isp_freebsd.h> 335d571944SMatt Jacob #include <sys/unistd.h> 345d571944SMatt Jacob #include <sys/kthread.h> 353ea883b4SMatt Jacob #include <machine/stdarg.h> /* for use by isp_prt below */ 365d571944SMatt Jacob #include <sys/conf.h> 374eb49427SMatt Jacob #include <sys/module.h> 385d571944SMatt Jacob #include <sys/ioccom.h> 395d571944SMatt Jacob #include <dev/isp/isp_ioctl.h> 406054c3f6SMatt Jacob 41a1bc34c6SMatt Jacob 424eb49427SMatt Jacob MODULE_VERSION(isp, 1); 4356c5b842SMark Murray MODULE_DEPEND(isp, cam, 1, 1, 1); 4473030e03SMatt Jacob int isp_announced = 0; 4573030e03SMatt Jacob ispfwfunc *isp_get_firmware_p = NULL; 4673030e03SMatt Jacob 475d571944SMatt Jacob static d_ioctl_t ispioctl; 48f6e75de2SMatt Jacob static void isp_intr_enable(void *); 490470d791SMatt Jacob static void isp_cam_async(void *, u_int32_t, struct cam_path *, void *); 500470d791SMatt Jacob static void isp_poll(struct cam_sim *); 51b85389e1SMatt Jacob static timeout_t isp_watchdog; 525d571944SMatt Jacob static void isp_kthread(void *); 53d81ba9d5SMatt Jacob static void isp_action(struct cam_sim *, union ccb *); 540470d791SMatt Jacob 55cc8df88bSMatt Jacob 565d571944SMatt Jacob static struct cdevsw isp_cdevsw = { 57dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 58dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, 597ac40f5fSPoul-Henning Kamp .d_ioctl = ispioctl, 607ac40f5fSPoul-Henning Kamp .d_name = "isp", 615d571944SMatt Jacob }; 625d571944SMatt Jacob 63d81ba9d5SMatt Jacob static struct ispsoftc *isplist = NULL; 64478f8a96SJustin T. Gibbs 65478f8a96SJustin T. Gibbs void 66c3055363SMatt Jacob isp_attach(struct ispsoftc *isp) 67478f8a96SJustin T. Gibbs { 68ea6f23cdSMatt Jacob int primary, secondary; 69478f8a96SJustin T. Gibbs struct ccb_setasync csa; 70478f8a96SJustin T. Gibbs struct cam_devq *devq; 71ea6f23cdSMatt Jacob struct cam_sim *sim; 72ea6f23cdSMatt Jacob struct cam_path *path; 73478f8a96SJustin T. Gibbs 74478f8a96SJustin T. Gibbs /* 75ea6f23cdSMatt Jacob * Establish (in case of 12X0) which bus is the primary. 76ea6f23cdSMatt Jacob */ 77ea6f23cdSMatt Jacob 78ea6f23cdSMatt Jacob primary = 0; 79ea6f23cdSMatt Jacob secondary = 1; 80ea6f23cdSMatt Jacob 81ea6f23cdSMatt Jacob /* 82ea6f23cdSMatt Jacob * Create the device queue for our SIM(s). 83478f8a96SJustin T. Gibbs */ 84ab6c4b31SMatt Jacob devq = cam_simq_alloc(isp->isp_maxcmds); 85478f8a96SJustin T. Gibbs if (devq == NULL) { 86478f8a96SJustin T. Gibbs return; 87478f8a96SJustin T. Gibbs } 88478f8a96SJustin T. Gibbs 89478f8a96SJustin T. Gibbs /* 90ea6f23cdSMatt Jacob * Construct our SIM entry. 91478f8a96SJustin T. Gibbs */ 9245c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 93ea6f23cdSMatt Jacob sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp, 943c75bb14SMatt Jacob device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq); 95ea6f23cdSMatt Jacob if (sim == NULL) { 96478f8a96SJustin T. Gibbs cam_simq_free(devq); 9745c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 98478f8a96SJustin T. Gibbs return; 99478f8a96SJustin T. Gibbs } 10045c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 101f6e75de2SMatt Jacob 102f6e75de2SMatt Jacob isp->isp_osinfo.ehook.ich_func = isp_intr_enable; 103f6e75de2SMatt Jacob isp->isp_osinfo.ehook.ich_arg = isp; 10445c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 105f6e75de2SMatt Jacob if (config_intrhook_establish(&isp->isp_osinfo.ehook) != 0) { 10645c9a36aSMatt Jacob cam_sim_free(sim, TRUE); 10745c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 108bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 109bfbab170SMatt Jacob "could not establish interrupt enable hook"); 110f6e75de2SMatt Jacob return; 111f6e75de2SMatt Jacob } 112f6e75de2SMatt Jacob 113ea6f23cdSMatt Jacob if (xpt_bus_register(sim, primary) != CAM_SUCCESS) { 114ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 11545c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 116478f8a96SJustin T. Gibbs return; 117478f8a96SJustin T. Gibbs } 118478f8a96SJustin T. Gibbs 119ea6f23cdSMatt Jacob if (xpt_create_path(&path, NULL, cam_sim_path(sim), 120478f8a96SJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 121ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 122ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 1235d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 12445c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 125478f8a96SJustin T. Gibbs return; 126478f8a96SJustin T. Gibbs } 127478f8a96SJustin T. Gibbs 128ea6f23cdSMatt Jacob xpt_setup_ccb(&csa.ccb_h, path, 5); 129478f8a96SJustin T. Gibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 130478f8a96SJustin T. Gibbs csa.event_enable = AC_LOST_DEVICE; 131cbf57b47SMatt Jacob csa.callback = isp_cam_async; 132ea6f23cdSMatt Jacob csa.callback_arg = sim; 133478f8a96SJustin T. Gibbs xpt_action((union ccb *)&csa); 13445c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 135ea6f23cdSMatt Jacob isp->isp_sim = sim; 136ea6f23cdSMatt Jacob isp->isp_path = path; 1375d571944SMatt Jacob /* 1385d571944SMatt Jacob * Create a kernel thread for fibre channel instances. We 1395d571944SMatt Jacob * don't have dual channel FC cards. 1405d571944SMatt Jacob */ 1415d571944SMatt Jacob if (IS_FC(isp)) { 14245c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 14345c9a36aSMatt Jacob /* XXX: LOCK VIOLATION */ 1445d571944SMatt Jacob cv_init(&isp->isp_osinfo.kthread_cv, "isp_kthread_cv"); 1455d571944SMatt Jacob if (kthread_create(isp_kthread, isp, &isp->isp_osinfo.kproc, 146316ec49aSScott Long RFHIGHPID, 0, "%s: fc_thrd", 1475d571944SMatt Jacob device_get_nameunit(isp->isp_dev))) { 1485d571944SMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 1495d571944SMatt Jacob cam_sim_free(sim, TRUE); 1505d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 15145c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 15245c9a36aSMatt Jacob isp_prt(isp, ISP_LOGERR, "could not create kthread"); 1535d571944SMatt Jacob return; 1545d571944SMatt Jacob } 1558e6a12fcSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 1565d571944SMatt Jacob } 1575d571944SMatt Jacob 158478f8a96SJustin T. Gibbs 159ea6f23cdSMatt Jacob /* 160ea6f23cdSMatt Jacob * If we have a second channel, construct SIM entry for that. 161ea6f23cdSMatt Jacob */ 16222e1dc85SMatt Jacob if (IS_DUALBUS(isp)) { 16345c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 164ea6f23cdSMatt Jacob sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp, 1653c75bb14SMatt Jacob device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq); 166ea6f23cdSMatt Jacob if (sim == NULL) { 167ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 168ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 169ea6f23cdSMatt Jacob cam_simq_free(devq); 1705d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 171ea6f23cdSMatt Jacob return; 172ea6f23cdSMatt Jacob } 173ea6f23cdSMatt Jacob if (xpt_bus_register(sim, secondary) != CAM_SUCCESS) { 174ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 175ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 176ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 1775d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 17845c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 179ea6f23cdSMatt Jacob return; 180ea6f23cdSMatt Jacob } 181ea6f23cdSMatt Jacob 182ea6f23cdSMatt Jacob if (xpt_create_path(&path, NULL, cam_sim_path(sim), 183ea6f23cdSMatt Jacob CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 184ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 185ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 186ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 187ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 1885d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 18945c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 190ea6f23cdSMatt Jacob return; 191ea6f23cdSMatt Jacob } 192ea6f23cdSMatt Jacob 193ea6f23cdSMatt Jacob xpt_setup_ccb(&csa.ccb_h, path, 5); 194ea6f23cdSMatt Jacob csa.ccb_h.func_code = XPT_SASYNC_CB; 195ea6f23cdSMatt Jacob csa.event_enable = AC_LOST_DEVICE; 196ea6f23cdSMatt Jacob csa.callback = isp_cam_async; 197ea6f23cdSMatt Jacob csa.callback_arg = sim; 198ea6f23cdSMatt Jacob xpt_action((union ccb *)&csa); 19945c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 200ea6f23cdSMatt Jacob isp->isp_sim2 = sim; 201ea6f23cdSMatt Jacob isp->isp_path2 = path; 202ea6f23cdSMatt Jacob } 2035d571944SMatt Jacob 2045d571944SMatt Jacob /* 2055d571944SMatt Jacob * Create device nodes 2065d571944SMatt Jacob */ 2075d571944SMatt Jacob (void) make_dev(&isp_cdevsw, device_get_unit(isp->isp_dev), UID_ROOT, 2085d571944SMatt Jacob GID_OPERATOR, 0600, "%s", device_get_nameunit(isp->isp_dev)); 2095d571944SMatt Jacob 210d6e5500fSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE) { 211478f8a96SJustin T. Gibbs isp->isp_state = ISP_RUNSTATE; 212b85389e1SMatt Jacob ENABLE_INTS(isp); 213d6e5500fSMatt Jacob } 214d81ba9d5SMatt Jacob if (isplist == NULL) { 215d81ba9d5SMatt Jacob isplist = isp; 216d81ba9d5SMatt Jacob } else { 217d81ba9d5SMatt Jacob struct ispsoftc *tmp = isplist; 218d81ba9d5SMatt Jacob while (tmp->isp_osinfo.next) { 219d81ba9d5SMatt Jacob tmp = tmp->isp_osinfo.next; 220d81ba9d5SMatt Jacob } 221d81ba9d5SMatt Jacob tmp->isp_osinfo.next = isp; 222478f8a96SJustin T. Gibbs } 2235d571944SMatt Jacob 2245d571944SMatt Jacob } 2255d571944SMatt Jacob 22653af7d22SMatt Jacob static __inline void 227fdeb9f2fSMatt Jacob isp_freeze_loopdown(struct ispsoftc *isp, char *msg) 228fdeb9f2fSMatt Jacob { 229fdeb9f2fSMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 230fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "%s: freeze simq (loopdown)", msg); 231fdeb9f2fSMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; 232fdeb9f2fSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 233fdeb9f2fSMatt Jacob xpt_freeze_simq(isp->isp_sim, 1); 234fdeb9f2fSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 235fdeb9f2fSMatt Jacob } else { 236fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "%s: mark frozen (loopdown)", msg); 237fdeb9f2fSMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; 238fdeb9f2fSMatt Jacob } 239fdeb9f2fSMatt Jacob } 240fdeb9f2fSMatt Jacob 2415d571944SMatt Jacob static int 24289c9c53dSPoul-Henning Kamp ispioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 2435d571944SMatt Jacob { 2445d571944SMatt Jacob struct ispsoftc *isp; 245746e9c85SMatt Jacob int nr, retval = ENOTTY; 2465d571944SMatt Jacob 2475d571944SMatt Jacob isp = isplist; 2485d571944SMatt Jacob while (isp) { 2495d571944SMatt Jacob if (minor(dev) == device_get_unit(isp->isp_dev)) { 2505d571944SMatt Jacob break; 2515d571944SMatt Jacob } 2525d571944SMatt Jacob isp = isp->isp_osinfo.next; 2535d571944SMatt Jacob } 2545d571944SMatt Jacob if (isp == NULL) 2555d571944SMatt Jacob return (ENXIO); 2565d571944SMatt Jacob 2575d571944SMatt Jacob switch (cmd) { 258d134aa0bSMatt Jacob #ifdef ISP_FW_CRASH_DUMP 259d134aa0bSMatt Jacob case ISP_GET_FW_CRASH_DUMP: 260d134aa0bSMatt Jacob { 261d134aa0bSMatt Jacob u_int16_t *ptr = FCPARAM(isp)->isp_dump_data; 262d134aa0bSMatt Jacob size_t sz; 263d134aa0bSMatt Jacob 264d134aa0bSMatt Jacob retval = 0; 265d134aa0bSMatt Jacob if (IS_2200(isp)) 266d134aa0bSMatt Jacob sz = QLA2200_RISC_IMAGE_DUMP_SIZE; 267d134aa0bSMatt Jacob else 268d134aa0bSMatt Jacob sz = QLA2300_RISC_IMAGE_DUMP_SIZE; 269d134aa0bSMatt Jacob ISP_LOCK(isp); 270d134aa0bSMatt Jacob if (ptr && *ptr) { 271d134aa0bSMatt Jacob void *uaddr = *((void **) addr); 272d134aa0bSMatt Jacob if (copyout(ptr, uaddr, sz)) { 273d134aa0bSMatt Jacob retval = EFAULT; 274d134aa0bSMatt Jacob } else { 275d134aa0bSMatt Jacob *ptr = 0; 276d134aa0bSMatt Jacob } 277d134aa0bSMatt Jacob } else { 278d134aa0bSMatt Jacob retval = ENXIO; 279d134aa0bSMatt Jacob } 280d134aa0bSMatt Jacob ISP_UNLOCK(isp); 281d134aa0bSMatt Jacob break; 282d134aa0bSMatt Jacob } 283d134aa0bSMatt Jacob 284d134aa0bSMatt Jacob case ISP_FORCE_CRASH_DUMP: 285d134aa0bSMatt Jacob ISP_LOCK(isp); 286fdeb9f2fSMatt Jacob isp_freeze_loopdown(isp, "ispioctl(ISP_FORCE_CRASH_DUMP)"); 287d134aa0bSMatt Jacob isp_fw_dump(isp); 288d134aa0bSMatt Jacob isp_reinit(isp); 289d134aa0bSMatt Jacob ISP_UNLOCK(isp); 290d134aa0bSMatt Jacob retval = 0; 291d134aa0bSMatt Jacob break; 292d134aa0bSMatt Jacob #endif 2935d571944SMatt Jacob case ISP_SDBLEV: 2945d571944SMatt Jacob { 2955d571944SMatt Jacob int olddblev = isp->isp_dblev; 2965d571944SMatt Jacob isp->isp_dblev = *(int *)addr; 2975d571944SMatt Jacob *(int *)addr = olddblev; 2985d571944SMatt Jacob retval = 0; 2995d571944SMatt Jacob break; 3005d571944SMatt Jacob } 301746e9c85SMatt Jacob case ISP_GETROLE: 302746e9c85SMatt Jacob *(int *)addr = isp->isp_role; 303746e9c85SMatt Jacob retval = 0; 304746e9c85SMatt Jacob break; 305746e9c85SMatt Jacob case ISP_SETROLE: 306746e9c85SMatt Jacob nr = *(int *)addr; 307746e9c85SMatt Jacob if (nr & ~(ISP_ROLE_INITIATOR|ISP_ROLE_TARGET)) { 308746e9c85SMatt Jacob retval = EINVAL; 309746e9c85SMatt Jacob break; 310746e9c85SMatt Jacob } 311746e9c85SMatt Jacob *(int *)addr = isp->isp_role; 312746e9c85SMatt Jacob isp->isp_role = nr; 313746e9c85SMatt Jacob /* FALLTHROUGH */ 3145d571944SMatt Jacob case ISP_RESETHBA: 3155d571944SMatt Jacob ISP_LOCK(isp); 3165d571944SMatt Jacob isp_reinit(isp); 3175d571944SMatt Jacob ISP_UNLOCK(isp); 3185d571944SMatt Jacob retval = 0; 3195d571944SMatt Jacob break; 320f553351eSMatt Jacob case ISP_RESCAN: 3215d571944SMatt Jacob if (IS_FC(isp)) { 3225d571944SMatt Jacob ISP_LOCK(isp); 3235d571944SMatt Jacob if (isp_fc_runstate(isp, 5 * 1000000)) { 3245d571944SMatt Jacob retval = EIO; 3255d571944SMatt Jacob } else { 3265d571944SMatt Jacob retval = 0; 3275d571944SMatt Jacob } 3285d571944SMatt Jacob ISP_UNLOCK(isp); 3295d571944SMatt Jacob } 3305d571944SMatt Jacob break; 3315d571944SMatt Jacob case ISP_FC_LIP: 3325d571944SMatt Jacob if (IS_FC(isp)) { 3335d571944SMatt Jacob ISP_LOCK(isp); 3345d571944SMatt Jacob if (isp_control(isp, ISPCTL_SEND_LIP, 0)) { 3355d571944SMatt Jacob retval = EIO; 3365d571944SMatt Jacob } else { 3375d571944SMatt Jacob retval = 0; 3385d571944SMatt Jacob } 3395d571944SMatt Jacob ISP_UNLOCK(isp); 3405d571944SMatt Jacob } 3415d571944SMatt Jacob break; 3425d571944SMatt Jacob case ISP_FC_GETDINFO: 3435d571944SMatt Jacob { 3445d571944SMatt Jacob struct isp_fc_device *ifc = (struct isp_fc_device *) addr; 3455d571944SMatt Jacob struct lportdb *lp; 3465d571944SMatt Jacob 3475d571944SMatt Jacob if (ifc->loopid < 0 || ifc->loopid >= MAX_FC_TARG) { 3485d571944SMatt Jacob retval = EINVAL; 3495d571944SMatt Jacob break; 3505d571944SMatt Jacob } 3515d571944SMatt Jacob ISP_LOCK(isp); 3525d571944SMatt Jacob lp = &FCPARAM(isp)->portdb[ifc->loopid]; 3535d571944SMatt Jacob if (lp->valid) { 3545d571944SMatt Jacob ifc->loopid = lp->loopid; 3555d571944SMatt Jacob ifc->portid = lp->portid; 3565d571944SMatt Jacob ifc->node_wwn = lp->node_wwn; 3575d571944SMatt Jacob ifc->port_wwn = lp->port_wwn; 3585d571944SMatt Jacob retval = 0; 3595d571944SMatt Jacob } else { 3605d571944SMatt Jacob retval = ENODEV; 3615d571944SMatt Jacob } 3625d571944SMatt Jacob ISP_UNLOCK(isp); 3635d571944SMatt Jacob break; 3645d571944SMatt Jacob } 3652903b272SMatt Jacob case ISP_GET_STATS: 3662903b272SMatt Jacob { 3672903b272SMatt Jacob isp_stats_t *sp = (isp_stats_t *) addr; 3682903b272SMatt Jacob 3692903b272SMatt Jacob MEMZERO(sp, sizeof (*sp)); 3702903b272SMatt Jacob sp->isp_stat_version = ISP_STATS_VERSION; 3712903b272SMatt Jacob sp->isp_type = isp->isp_type; 3722903b272SMatt Jacob sp->isp_revision = isp->isp_revision; 3732903b272SMatt Jacob ISP_LOCK(isp); 3742903b272SMatt Jacob sp->isp_stats[ISP_INTCNT] = isp->isp_intcnt; 3752903b272SMatt Jacob sp->isp_stats[ISP_INTBOGUS] = isp->isp_intbogus; 3762903b272SMatt Jacob sp->isp_stats[ISP_INTMBOXC] = isp->isp_intmboxc; 3772903b272SMatt Jacob sp->isp_stats[ISP_INGOASYNC] = isp->isp_intoasync; 3782903b272SMatt Jacob sp->isp_stats[ISP_RSLTCCMPLT] = isp->isp_rsltccmplt; 3792903b272SMatt Jacob sp->isp_stats[ISP_FPHCCMCPLT] = isp->isp_fphccmplt; 3802903b272SMatt Jacob sp->isp_stats[ISP_RSCCHIWAT] = isp->isp_rscchiwater; 3812903b272SMatt Jacob sp->isp_stats[ISP_FPCCHIWAT] = isp->isp_fpcchiwater; 3822903b272SMatt Jacob ISP_UNLOCK(isp); 3832903b272SMatt Jacob retval = 0; 3842903b272SMatt Jacob break; 3852903b272SMatt Jacob } 3862903b272SMatt Jacob case ISP_CLR_STATS: 3872903b272SMatt Jacob ISP_LOCK(isp); 3882903b272SMatt Jacob isp->isp_intcnt = 0; 3892903b272SMatt Jacob isp->isp_intbogus = 0; 3902903b272SMatt Jacob isp->isp_intmboxc = 0; 3912903b272SMatt Jacob isp->isp_intoasync = 0; 3922903b272SMatt Jacob isp->isp_rsltccmplt = 0; 3932903b272SMatt Jacob isp->isp_fphccmplt = 0; 3942903b272SMatt Jacob isp->isp_rscchiwater = 0; 3952903b272SMatt Jacob isp->isp_fpcchiwater = 0; 3962903b272SMatt Jacob ISP_UNLOCK(isp); 3972903b272SMatt Jacob retval = 0; 3982903b272SMatt Jacob break; 399570c7a3fSMatt Jacob case ISP_FC_GETHINFO: 400570c7a3fSMatt Jacob { 401570c7a3fSMatt Jacob struct isp_hba_device *hba = (struct isp_hba_device *) addr; 402570c7a3fSMatt Jacob MEMZERO(hba, sizeof (*hba)); 403570c7a3fSMatt Jacob ISP_LOCK(isp); 404a556b68eSMatt Jacob hba->fc_fw_major = ISP_FW_MAJORX(isp->isp_fwrev); 405a556b68eSMatt Jacob hba->fc_fw_minor = ISP_FW_MINORX(isp->isp_fwrev); 406a556b68eSMatt Jacob hba->fc_fw_micro = ISP_FW_MICROX(isp->isp_fwrev); 407570c7a3fSMatt Jacob hba->fc_speed = FCPARAM(isp)->isp_gbspeed; 408570c7a3fSMatt Jacob hba->fc_scsi_supported = 1; 409570c7a3fSMatt Jacob hba->fc_topology = FCPARAM(isp)->isp_topo + 1; 410570c7a3fSMatt Jacob hba->fc_loopid = FCPARAM(isp)->isp_loopid; 411fd6eb9f7SMatt Jacob hba->nvram_node_wwn = FCPARAM(isp)->isp_nodewwn; 412fd6eb9f7SMatt Jacob hba->nvram_port_wwn = FCPARAM(isp)->isp_portwwn; 413fd6eb9f7SMatt Jacob hba->active_node_wwn = ISP_NODEWWN(isp); 414fd6eb9f7SMatt Jacob hba->active_port_wwn = ISP_PORTWWN(isp); 415570c7a3fSMatt Jacob ISP_UNLOCK(isp); 416570c7a3fSMatt Jacob retval = 0; 417570c7a3fSMatt Jacob break; 418570c7a3fSMatt Jacob } 419fdeb9f2fSMatt Jacob case ISP_GET_FC_PARAM: 420fdeb9f2fSMatt Jacob { 421fdeb9f2fSMatt Jacob struct isp_fc_param *f = (struct isp_fc_param *) addr; 422fdeb9f2fSMatt Jacob 423fdeb9f2fSMatt Jacob if (!IS_FC(isp)) { 424fdeb9f2fSMatt Jacob retval = EINVAL; 425fdeb9f2fSMatt Jacob break; 426fdeb9f2fSMatt Jacob } 427fdeb9f2fSMatt Jacob f->parameter = 0; 428fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "framelength") == 0) { 429fdeb9f2fSMatt Jacob f->parameter = FCPARAM(isp)->isp_maxfrmlen; 430fdeb9f2fSMatt Jacob retval = 0; 431fdeb9f2fSMatt Jacob break; 432fdeb9f2fSMatt Jacob } 433fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "exec_throttle") == 0) { 434fdeb9f2fSMatt Jacob f->parameter = FCPARAM(isp)->isp_execthrottle; 435fdeb9f2fSMatt Jacob retval = 0; 436fdeb9f2fSMatt Jacob break; 437fdeb9f2fSMatt Jacob } 438fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "fullduplex") == 0) { 439fdeb9f2fSMatt Jacob if (FCPARAM(isp)->isp_fwoptions & ICBOPT_FULL_DUPLEX) 440fdeb9f2fSMatt Jacob f->parameter = 1; 441fdeb9f2fSMatt Jacob retval = 0; 442fdeb9f2fSMatt Jacob break; 443fdeb9f2fSMatt Jacob } 444fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "loopid") == 0) { 445fdeb9f2fSMatt Jacob f->parameter = FCPARAM(isp)->isp_loopid; 446fdeb9f2fSMatt Jacob retval = 0; 447fdeb9f2fSMatt Jacob break; 448fdeb9f2fSMatt Jacob } 449fdeb9f2fSMatt Jacob retval = EINVAL; 450fdeb9f2fSMatt Jacob break; 451fdeb9f2fSMatt Jacob } 452fdeb9f2fSMatt Jacob case ISP_SET_FC_PARAM: 453fdeb9f2fSMatt Jacob { 454fdeb9f2fSMatt Jacob struct isp_fc_param *f = (struct isp_fc_param *) addr; 455fdeb9f2fSMatt Jacob u_int32_t param = f->parameter; 456fdeb9f2fSMatt Jacob 457fdeb9f2fSMatt Jacob if (!IS_FC(isp)) { 458fdeb9f2fSMatt Jacob retval = EINVAL; 459fdeb9f2fSMatt Jacob break; 460fdeb9f2fSMatt Jacob } 461fdeb9f2fSMatt Jacob f->parameter = 0; 462fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "framelength") == 0) { 463fdeb9f2fSMatt Jacob if (param != 512 && param != 1024 && param != 1024) { 464fdeb9f2fSMatt Jacob retval = EINVAL; 465fdeb9f2fSMatt Jacob break; 466fdeb9f2fSMatt Jacob } 467fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_maxfrmlen = param; 468fdeb9f2fSMatt Jacob retval = 0; 469fdeb9f2fSMatt Jacob break; 470fdeb9f2fSMatt Jacob } 471fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "exec_throttle") == 0) { 472fdeb9f2fSMatt Jacob if (param < 16 || param > 255) { 473fdeb9f2fSMatt Jacob retval = EINVAL; 474fdeb9f2fSMatt Jacob break; 475fdeb9f2fSMatt Jacob } 476fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_execthrottle = param; 477fdeb9f2fSMatt Jacob retval = 0; 478fdeb9f2fSMatt Jacob break; 479fdeb9f2fSMatt Jacob } 480fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "fullduplex") == 0) { 481fdeb9f2fSMatt Jacob if (param != 0 && param != 1) { 482fdeb9f2fSMatt Jacob retval = EINVAL; 483fdeb9f2fSMatt Jacob break; 484fdeb9f2fSMatt Jacob } 485fdeb9f2fSMatt Jacob if (param) { 486fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_fwoptions |= 487fdeb9f2fSMatt Jacob ICBOPT_FULL_DUPLEX; 488fdeb9f2fSMatt Jacob } else { 489fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_fwoptions &= 490fdeb9f2fSMatt Jacob ~ICBOPT_FULL_DUPLEX; 491fdeb9f2fSMatt Jacob } 492fdeb9f2fSMatt Jacob retval = 0; 493fdeb9f2fSMatt Jacob break; 494fdeb9f2fSMatt Jacob } 495fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "loopid") == 0) { 496fdeb9f2fSMatt Jacob if (param < 0 || param > 125) { 497fdeb9f2fSMatt Jacob retval = EINVAL; 498fdeb9f2fSMatt Jacob break; 499fdeb9f2fSMatt Jacob } 500fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_loopid = param; 501fdeb9f2fSMatt Jacob retval = 0; 502fdeb9f2fSMatt Jacob break; 503fdeb9f2fSMatt Jacob } 504fdeb9f2fSMatt Jacob retval = EINVAL; 505fdeb9f2fSMatt Jacob break; 506fdeb9f2fSMatt Jacob } 5078e62a8acSMatt Jacob case ISP_TSK_MGMT: 5088e62a8acSMatt Jacob { 5098e62a8acSMatt Jacob int needmarker; 5108e62a8acSMatt Jacob struct isp_fc_tsk_mgmt *fct = (struct isp_fc_tsk_mgmt *) addr; 511e5265237SMatt Jacob u_int16_t loopid; 5128e62a8acSMatt Jacob mbreg_t mbs; 5138e62a8acSMatt Jacob 5148e62a8acSMatt Jacob if (IS_SCSI(isp)) { 5158e62a8acSMatt Jacob retval = EINVAL; 5168e62a8acSMatt Jacob break; 5178e62a8acSMatt Jacob } 5188e62a8acSMatt Jacob 5198e62a8acSMatt Jacob memset(&mbs, 0, sizeof (mbs)); 5208e62a8acSMatt Jacob needmarker = retval = 0; 521e5265237SMatt Jacob loopid = fct->loopid; 522e5265237SMatt Jacob if (IS_2KLOGIN(isp) == 0) { 523e5265237SMatt Jacob loopid <<= 8; 524e5265237SMatt Jacob } 5258e62a8acSMatt Jacob switch (fct->action) { 5268e62a8acSMatt Jacob case CLEAR_ACA: 5278e62a8acSMatt Jacob mbs.param[0] = MBOX_CLEAR_ACA; 528e5265237SMatt Jacob mbs.param[1] = loopid; 5298e62a8acSMatt Jacob mbs.param[2] = fct->lun; 5308e62a8acSMatt Jacob break; 5318e62a8acSMatt Jacob case TARGET_RESET: 5328e62a8acSMatt Jacob mbs.param[0] = MBOX_TARGET_RESET; 533e5265237SMatt Jacob mbs.param[1] = loopid; 5348e62a8acSMatt Jacob needmarker = 1; 5358e62a8acSMatt Jacob break; 5368e62a8acSMatt Jacob case LUN_RESET: 5378e62a8acSMatt Jacob mbs.param[0] = MBOX_LUN_RESET; 538e5265237SMatt Jacob mbs.param[1] = loopid; 5398e62a8acSMatt Jacob mbs.param[2] = fct->lun; 5408e62a8acSMatt Jacob needmarker = 1; 5418e62a8acSMatt Jacob break; 5428e62a8acSMatt Jacob case CLEAR_TASK_SET: 5438e62a8acSMatt Jacob mbs.param[0] = MBOX_CLEAR_TASK_SET; 544e5265237SMatt Jacob mbs.param[1] = loopid; 5458e62a8acSMatt Jacob mbs.param[2] = fct->lun; 5468e62a8acSMatt Jacob needmarker = 1; 5478e62a8acSMatt Jacob break; 5488e62a8acSMatt Jacob case ABORT_TASK_SET: 5498e62a8acSMatt Jacob mbs.param[0] = MBOX_ABORT_TASK_SET; 550e5265237SMatt Jacob mbs.param[1] = loopid; 5518e62a8acSMatt Jacob mbs.param[2] = fct->lun; 5528e62a8acSMatt Jacob needmarker = 1; 5538e62a8acSMatt Jacob break; 5548e62a8acSMatt Jacob default: 5558e62a8acSMatt Jacob retval = EINVAL; 5568e62a8acSMatt Jacob break; 5578e62a8acSMatt Jacob } 5588e62a8acSMatt Jacob if (retval == 0) { 5598e62a8acSMatt Jacob ISP_LOCK(isp); 5608e62a8acSMatt Jacob if (needmarker) { 5618e62a8acSMatt Jacob isp->isp_sendmarker |= 1; 5628e62a8acSMatt Jacob } 5638e62a8acSMatt Jacob retval = isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); 5648e62a8acSMatt Jacob ISP_UNLOCK(isp); 5658e62a8acSMatt Jacob if (retval) 5668e62a8acSMatt Jacob retval = EIO; 5678e62a8acSMatt Jacob } 5688e62a8acSMatt Jacob break; 5698e62a8acSMatt Jacob } 5705d571944SMatt Jacob default: 5715d571944SMatt Jacob break; 5725d571944SMatt Jacob } 5735d571944SMatt Jacob return (retval); 5740470d791SMatt Jacob } 575478f8a96SJustin T. Gibbs 576f6e75de2SMatt Jacob static void 577f6e75de2SMatt Jacob isp_intr_enable(void *arg) 578f6e75de2SMatt Jacob { 579f6e75de2SMatt Jacob struct ispsoftc *isp = arg; 580d6e5500fSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE) { 581f6e75de2SMatt Jacob ENABLE_INTS(isp); 582e3e49f7eSMatt Jacob #if 0 583f6e75de2SMatt Jacob isp->isp_osinfo.intsok = 1; 584e3e49f7eSMatt Jacob #endif 585d6e5500fSMatt Jacob } 586f6e75de2SMatt Jacob /* Release our hook so that the boot can continue. */ 587f6e75de2SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 588f6e75de2SMatt Jacob } 589d81ba9d5SMatt Jacob 590d81ba9d5SMatt Jacob /* 591d81ba9d5SMatt Jacob * Put the target mode functions here, because some are inlines 592d81ba9d5SMatt Jacob */ 593d81ba9d5SMatt Jacob 594d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 595d81ba9d5SMatt Jacob 59653af7d22SMatt Jacob static __inline int is_lun_enabled(struct ispsoftc *, int, lun_id_t); 59753af7d22SMatt Jacob static __inline int are_any_luns_enabled(struct ispsoftc *, int); 59853af7d22SMatt Jacob static __inline tstate_t *get_lun_statep(struct ispsoftc *, int, lun_id_t); 59953af7d22SMatt Jacob static __inline void rls_lun_statep(struct ispsoftc *, tstate_t *); 60053af7d22SMatt Jacob static __inline atio_private_data_t *isp_get_atpd(struct ispsoftc *, int); 601d81ba9d5SMatt Jacob static cam_status 602a1bc34c6SMatt Jacob create_lun_state(struct ispsoftc *, int, struct cam_path *, tstate_t **); 603d81ba9d5SMatt Jacob static void destroy_lun_state(struct ispsoftc *, tstate_t *); 60467ff51f1SMatt Jacob static int isp_en_lun(struct ispsoftc *, union ccb *); 60567ff51f1SMatt Jacob static void isp_ledone(struct ispsoftc *, lun_entry_t *); 606d81ba9d5SMatt Jacob static cam_status isp_abort_tgt_ccb(struct ispsoftc *, union ccb *); 607f48ce188SMatt Jacob static timeout_t isp_refire_putback_atio; 608a1bc34c6SMatt Jacob static void isp_complete_ctio(union ccb *); 609a1bc34c6SMatt Jacob static void isp_target_putback_atio(union ccb *); 610a1bc34c6SMatt Jacob static cam_status isp_target_start_ctio(struct ispsoftc *, union ccb *); 611d81ba9d5SMatt Jacob static int isp_handle_platform_atio(struct ispsoftc *, at_entry_t *); 612d81ba9d5SMatt Jacob static int isp_handle_platform_atio2(struct ispsoftc *, at2_entry_t *); 613d81ba9d5SMatt Jacob static int isp_handle_platform_ctio(struct ispsoftc *, void *); 614570c7a3fSMatt Jacob static int isp_handle_platform_notify_scsi(struct ispsoftc *, in_entry_t *); 615570c7a3fSMatt Jacob static int isp_handle_platform_notify_fc(struct ispsoftc *, in_fcentry_t *); 616d81ba9d5SMatt Jacob 61753af7d22SMatt Jacob static __inline int 618a1bc34c6SMatt Jacob is_lun_enabled(struct ispsoftc *isp, int bus, lun_id_t lun) 619d81ba9d5SMatt Jacob { 620d81ba9d5SMatt Jacob tstate_t *tptr; 621a1bc34c6SMatt Jacob tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)]; 622a1bc34c6SMatt Jacob if (tptr == NULL) { 623d81ba9d5SMatt Jacob return (0); 624d81ba9d5SMatt Jacob } 625d81ba9d5SMatt Jacob do { 626a1bc34c6SMatt Jacob if (tptr->lun == (lun_id_t) lun && tptr->bus == bus) { 627d81ba9d5SMatt Jacob return (1); 628d81ba9d5SMatt Jacob } 629d81ba9d5SMatt Jacob } while ((tptr = tptr->next) != NULL); 630d81ba9d5SMatt Jacob return (0); 631d81ba9d5SMatt Jacob } 632d81ba9d5SMatt Jacob 63353af7d22SMatt Jacob static __inline int 634a1bc34c6SMatt Jacob are_any_luns_enabled(struct ispsoftc *isp, int port) 635d81ba9d5SMatt Jacob { 636a1bc34c6SMatt Jacob int lo, hi; 637a1bc34c6SMatt Jacob if (IS_DUALBUS(isp)) { 638a1bc34c6SMatt Jacob lo = (port * (LUN_HASH_SIZE >> 1)); 639a1bc34c6SMatt Jacob hi = lo + (LUN_HASH_SIZE >> 1); 640a1bc34c6SMatt Jacob } else { 641a1bc34c6SMatt Jacob lo = 0; 642a1bc34c6SMatt Jacob hi = LUN_HASH_SIZE; 643a1bc34c6SMatt Jacob } 644a1bc34c6SMatt Jacob for (lo = 0; lo < hi; lo++) { 645a1bc34c6SMatt Jacob if (isp->isp_osinfo.lun_hash[lo]) { 646d81ba9d5SMatt Jacob return (1); 647d81ba9d5SMatt Jacob } 648d81ba9d5SMatt Jacob } 649d81ba9d5SMatt Jacob return (0); 650d81ba9d5SMatt Jacob } 651d81ba9d5SMatt Jacob 65253af7d22SMatt Jacob static __inline tstate_t * 653a1bc34c6SMatt Jacob get_lun_statep(struct ispsoftc *isp, int bus, lun_id_t lun) 654d81ba9d5SMatt Jacob { 65564edff94SMatt Jacob tstate_t *tptr = NULL; 656d81ba9d5SMatt Jacob 657d81ba9d5SMatt Jacob if (lun == CAM_LUN_WILDCARD) { 65864edff94SMatt Jacob if (isp->isp_osinfo.tmflags[bus] & TM_WILDCARD_ENABLED) { 659a1bc34c6SMatt Jacob tptr = &isp->isp_osinfo.tsdflt[bus]; 660d81ba9d5SMatt Jacob tptr->hold++; 661d81ba9d5SMatt Jacob return (tptr); 662d81ba9d5SMatt Jacob } 66367ff51f1SMatt Jacob return (NULL); 664126ec864SMatt Jacob } else { 665126ec864SMatt Jacob tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)]; 66664edff94SMatt Jacob if (tptr == NULL) { 66764edff94SMatt Jacob return (NULL); 66864edff94SMatt Jacob } 669126ec864SMatt Jacob } 670d81ba9d5SMatt Jacob 671d81ba9d5SMatt Jacob do { 672a1bc34c6SMatt Jacob if (tptr->lun == lun && tptr->bus == bus) { 673d81ba9d5SMatt Jacob tptr->hold++; 674d81ba9d5SMatt Jacob return (tptr); 675d81ba9d5SMatt Jacob } 676d81ba9d5SMatt Jacob } while ((tptr = tptr->next) != NULL); 677d81ba9d5SMatt Jacob return (tptr); 678d81ba9d5SMatt Jacob } 679d81ba9d5SMatt Jacob 68053af7d22SMatt Jacob static __inline void 681d81ba9d5SMatt Jacob rls_lun_statep(struct ispsoftc *isp, tstate_t *tptr) 682d81ba9d5SMatt Jacob { 683d81ba9d5SMatt Jacob if (tptr->hold) 684d81ba9d5SMatt Jacob tptr->hold--; 685d81ba9d5SMatt Jacob } 686d81ba9d5SMatt Jacob 68753af7d22SMatt Jacob static __inline atio_private_data_t * 68853036e92SMatt Jacob isp_get_atpd(struct ispsoftc *isp, int tag) 68953036e92SMatt Jacob { 69053036e92SMatt Jacob atio_private_data_t *atp; 69153036e92SMatt Jacob for (atp = isp->isp_osinfo.atpdp; 69253036e92SMatt Jacob atp < &isp->isp_osinfo.atpdp[ATPDPSIZE]; atp++) { 69353036e92SMatt Jacob if (atp->tag == tag) 69453036e92SMatt Jacob return (atp); 69553036e92SMatt Jacob } 69653036e92SMatt Jacob return (NULL); 69753036e92SMatt Jacob } 69853036e92SMatt Jacob 699d81ba9d5SMatt Jacob static cam_status 700a1bc34c6SMatt Jacob create_lun_state(struct ispsoftc *isp, int bus, 701a1bc34c6SMatt Jacob struct cam_path *path, tstate_t **rslt) 702d81ba9d5SMatt Jacob { 703d81ba9d5SMatt Jacob cam_status status; 704d81ba9d5SMatt Jacob lun_id_t lun; 705a1bc34c6SMatt Jacob int hfx; 706d81ba9d5SMatt Jacob tstate_t *tptr, *new; 707d81ba9d5SMatt Jacob 708d81ba9d5SMatt Jacob lun = xpt_path_lun_id(path); 709d81ba9d5SMatt Jacob if (lun < 0) { 710d81ba9d5SMatt Jacob return (CAM_LUN_INVALID); 711d81ba9d5SMatt Jacob } 712a1bc34c6SMatt Jacob if (is_lun_enabled(isp, bus, lun)) { 713d81ba9d5SMatt Jacob return (CAM_LUN_ALRDY_ENA); 714d81ba9d5SMatt Jacob } 715ea8b5a9aSDavid Malone new = (tstate_t *) malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO); 716d81ba9d5SMatt Jacob if (new == NULL) { 717d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 718d81ba9d5SMatt Jacob } 719d81ba9d5SMatt Jacob 720d81ba9d5SMatt Jacob status = xpt_create_path(&new->owner, NULL, xpt_path_path_id(path), 721d81ba9d5SMatt Jacob xpt_path_target_id(path), xpt_path_lun_id(path)); 722d81ba9d5SMatt Jacob if (status != CAM_REQ_CMP) { 723d81ba9d5SMatt Jacob free(new, M_DEVBUF); 724d81ba9d5SMatt Jacob return (status); 725d81ba9d5SMatt Jacob } 726a1bc34c6SMatt Jacob new->bus = bus; 727d81ba9d5SMatt Jacob new->lun = lun; 728d81ba9d5SMatt Jacob SLIST_INIT(&new->atios); 729d81ba9d5SMatt Jacob SLIST_INIT(&new->inots); 730d81ba9d5SMatt Jacob new->hold = 1; 731d81ba9d5SMatt Jacob 732a1bc34c6SMatt Jacob hfx = LUN_HASH_FUNC(isp, new->bus, new->lun); 733a1bc34c6SMatt Jacob tptr = isp->isp_osinfo.lun_hash[hfx]; 734a1bc34c6SMatt Jacob if (tptr == NULL) { 735a1bc34c6SMatt Jacob isp->isp_osinfo.lun_hash[hfx] = new; 736d81ba9d5SMatt Jacob } else { 737d81ba9d5SMatt Jacob while (tptr->next) 738d81ba9d5SMatt Jacob tptr = tptr->next; 739d81ba9d5SMatt Jacob tptr->next = new; 740d81ba9d5SMatt Jacob } 741d81ba9d5SMatt Jacob *rslt = new; 742d81ba9d5SMatt Jacob return (CAM_REQ_CMP); 743d81ba9d5SMatt Jacob } 744d81ba9d5SMatt Jacob 74553af7d22SMatt Jacob static __inline void 746d81ba9d5SMatt Jacob destroy_lun_state(struct ispsoftc *isp, tstate_t *tptr) 747d81ba9d5SMatt Jacob { 748a1bc34c6SMatt Jacob int hfx; 749d81ba9d5SMatt Jacob tstate_t *lw, *pw; 750d81ba9d5SMatt Jacob 751d81ba9d5SMatt Jacob if (tptr->hold) { 752d81ba9d5SMatt Jacob return; 753d81ba9d5SMatt Jacob } 75467ff51f1SMatt Jacob hfx = LUN_HASH_FUNC(isp, tptr->bus, tptr->lun); 755a1bc34c6SMatt Jacob pw = isp->isp_osinfo.lun_hash[hfx]; 756d81ba9d5SMatt Jacob if (pw == NULL) { 757d81ba9d5SMatt Jacob return; 758a1bc34c6SMatt Jacob } else if (pw->lun == tptr->lun && pw->bus == tptr->bus) { 759a1bc34c6SMatt Jacob isp->isp_osinfo.lun_hash[hfx] = pw->next; 760d81ba9d5SMatt Jacob } else { 761d81ba9d5SMatt Jacob lw = pw; 762d81ba9d5SMatt Jacob pw = lw->next; 763d81ba9d5SMatt Jacob while (pw) { 764a1bc34c6SMatt Jacob if (pw->lun == tptr->lun && pw->bus == tptr->bus) { 765d81ba9d5SMatt Jacob lw->next = pw->next; 766d81ba9d5SMatt Jacob break; 767d81ba9d5SMatt Jacob } 768d81ba9d5SMatt Jacob lw = pw; 769d81ba9d5SMatt Jacob pw = pw->next; 770d81ba9d5SMatt Jacob } 771d81ba9d5SMatt Jacob if (pw == NULL) { 772d81ba9d5SMatt Jacob return; 773d81ba9d5SMatt Jacob } 774d81ba9d5SMatt Jacob } 775d81ba9d5SMatt Jacob free(tptr, M_DEVBUF); 776d81ba9d5SMatt Jacob } 777d81ba9d5SMatt Jacob 7785d571944SMatt Jacob /* 77967ff51f1SMatt Jacob * Enable luns. 7805d571944SMatt Jacob */ 78167ff51f1SMatt Jacob static int 782d81ba9d5SMatt Jacob isp_en_lun(struct ispsoftc *isp, union ccb *ccb) 783d81ba9d5SMatt Jacob { 784d81ba9d5SMatt Jacob struct ccb_en_lun *cel = &ccb->cel; 785d81ba9d5SMatt Jacob tstate_t *tptr; 78667ff51f1SMatt Jacob u_int32_t seq; 787746e9c85SMatt Jacob int bus, cmd, av, wildcard, tm_on; 788d81ba9d5SMatt Jacob lun_id_t lun; 789d81ba9d5SMatt Jacob target_id_t tgt; 790d81ba9d5SMatt Jacob 79167ff51f1SMatt Jacob bus = XS_CHANNEL(ccb); 79267ff51f1SMatt Jacob if (bus > 1) { 79367ff51f1SMatt Jacob xpt_print_path(ccb->ccb_h.path); 79467ff51f1SMatt Jacob printf("illegal bus %d\n", bus); 79567ff51f1SMatt Jacob ccb->ccb_h.status = CAM_PATH_INVALID; 79667ff51f1SMatt Jacob return (-1); 79767ff51f1SMatt Jacob } 798d81ba9d5SMatt Jacob tgt = ccb->ccb_h.target_id; 799d81ba9d5SMatt Jacob lun = ccb->ccb_h.target_lun; 800d81ba9d5SMatt Jacob 80167ff51f1SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 80267ff51f1SMatt Jacob "isp_en_lun: %sabling lun 0x%x on channel %d", 80367ff51f1SMatt Jacob cel->enable? "en" : "dis", lun, bus); 80467ff51f1SMatt Jacob 805d81ba9d5SMatt Jacob 806d6e5500fSMatt Jacob if ((lun != CAM_LUN_WILDCARD) && 807d6e5500fSMatt Jacob (lun < 0 || lun >= (lun_id_t) isp->isp_maxluns)) { 808d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 80967ff51f1SMatt Jacob return (-1); 810d81ba9d5SMatt Jacob } 81164edff94SMatt Jacob 8122ad50ca5SMatt Jacob if (IS_SCSI(isp)) { 813a1bc34c6SMatt Jacob sdparam *sdp = isp->isp_param; 814a1bc34c6SMatt Jacob sdp += bus; 815d81ba9d5SMatt Jacob if (tgt != CAM_TARGET_WILDCARD && 816a1bc34c6SMatt Jacob tgt != sdp->isp_initiator_id) { 817d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_TID_INVALID; 81867ff51f1SMatt Jacob return (-1); 819d81ba9d5SMatt Jacob } 820d81ba9d5SMatt Jacob } else { 821746e9c85SMatt Jacob /* 822746e9c85SMatt Jacob * There's really no point in doing this yet w/o multi-tid 823746e9c85SMatt Jacob * capability. Even then, it's problematic. 824746e9c85SMatt Jacob */ 825746e9c85SMatt Jacob #if 0 826d81ba9d5SMatt Jacob if (tgt != CAM_TARGET_WILDCARD && 827d6e5500fSMatt Jacob tgt != FCPARAM(isp)->isp_iid) { 828d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_TID_INVALID; 82967ff51f1SMatt Jacob return (-1); 830d81ba9d5SMatt Jacob } 831746e9c85SMatt Jacob #endif 83264edff94SMatt Jacob /* 83364edff94SMatt Jacob * This is as a good a place as any to check f/w capabilities. 83464edff94SMatt Jacob */ 83564edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_TMODE) == 0) { 83664edff94SMatt Jacob isp_prt(isp, ISP_LOGERR, 83764edff94SMatt Jacob "firmware does not support target mode"); 83864edff94SMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 83967ff51f1SMatt Jacob return (-1); 84064edff94SMatt Jacob } 84164edff94SMatt Jacob /* 84264edff94SMatt Jacob * XXX: We *could* handle non-SCCLUN f/w, but we'd have to 84364edff94SMatt Jacob * XXX: dorks with our already fragile enable/disable code. 84464edff94SMatt Jacob */ 84564edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) { 84664edff94SMatt Jacob isp_prt(isp, ISP_LOGERR, 84764edff94SMatt Jacob "firmware not SCCLUN capable"); 848746e9c85SMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 84967ff51f1SMatt Jacob return (-1); 85064edff94SMatt Jacob } 851d81ba9d5SMatt Jacob } 852d81ba9d5SMatt Jacob 853d6e5500fSMatt Jacob if (tgt == CAM_TARGET_WILDCARD) { 85464edff94SMatt Jacob if (lun == CAM_LUN_WILDCARD) { 85564edff94SMatt Jacob wildcard = 1; 85664edff94SMatt Jacob } else { 857d6e5500fSMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 85867ff51f1SMatt Jacob return (-1); 859d6e5500fSMatt Jacob } 860126ec864SMatt Jacob } else { 861126ec864SMatt Jacob wildcard = 0; 862126ec864SMatt Jacob } 863b6b6ad2fSMatt Jacob 864746e9c85SMatt Jacob tm_on = (isp->isp_osinfo.tmflags[bus] & TM_TMODE_ENABLED) != 0; 865746e9c85SMatt Jacob 866b6b6ad2fSMatt Jacob /* 867b6b6ad2fSMatt Jacob * Next check to see whether this is a target/lun wildcard action. 86864edff94SMatt Jacob * 86964edff94SMatt Jacob * If so, we know that we can accept commands for luns that haven't 87064edff94SMatt Jacob * been enabled yet and send them upstream. Otherwise, we have to 87164edff94SMatt Jacob * handle them locally (if we see them at all). 872b6b6ad2fSMatt Jacob */ 873126ec864SMatt Jacob 874126ec864SMatt Jacob if (wildcard) { 875a1bc34c6SMatt Jacob tptr = &isp->isp_osinfo.tsdflt[bus]; 876b6b6ad2fSMatt Jacob if (cel->enable) { 87767ff51f1SMatt Jacob if (tm_on) { 878b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; 87967ff51f1SMatt Jacob return (-1); 880b6b6ad2fSMatt Jacob } 881b6b6ad2fSMatt Jacob ccb->ccb_h.status = 882b6b6ad2fSMatt Jacob xpt_create_path(&tptr->owner, NULL, 883b6b6ad2fSMatt Jacob xpt_path_path_id(ccb->ccb_h.path), 884b6b6ad2fSMatt Jacob xpt_path_target_id(ccb->ccb_h.path), 885b6b6ad2fSMatt Jacob xpt_path_lun_id(ccb->ccb_h.path)); 886b6b6ad2fSMatt Jacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 88767ff51f1SMatt Jacob return (-1); 888b6b6ad2fSMatt Jacob } 889b6b6ad2fSMatt Jacob SLIST_INIT(&tptr->atios); 890b6b6ad2fSMatt Jacob SLIST_INIT(&tptr->inots); 89164edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] |= TM_WILDCARD_ENABLED; 892126ec864SMatt Jacob } else { 89367ff51f1SMatt Jacob if (tm_on == 0) { 894126ec864SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 89567ff51f1SMatt Jacob return (-1); 896126ec864SMatt Jacob } 897126ec864SMatt Jacob if (tptr->hold) { 898126ec864SMatt Jacob ccb->ccb_h.status = CAM_SCSI_BUSY; 89967ff51f1SMatt Jacob return (-1); 900126ec864SMatt Jacob } 901126ec864SMatt Jacob xpt_free_path(tptr->owner); 90264edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_WILDCARD_ENABLED; 903126ec864SMatt Jacob } 904126ec864SMatt Jacob } 905126ec864SMatt Jacob 906126ec864SMatt Jacob /* 907126ec864SMatt Jacob * Now check to see whether this bus needs to be 908126ec864SMatt Jacob * enabled/disabled with respect to target mode. 909126ec864SMatt Jacob */ 910126ec864SMatt Jacob av = bus << 31; 911746e9c85SMatt Jacob if (cel->enable && tm_on == 0) { 912a1bc34c6SMatt Jacob av |= ENABLE_TARGET_FLAG; 913b6b6ad2fSMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 914b6b6ad2fSMatt Jacob if (av) { 915b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 916126ec864SMatt Jacob if (wildcard) { 91764edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= 91864edff94SMatt Jacob ~TM_WILDCARD_ENABLED; 919b6b6ad2fSMatt Jacob xpt_free_path(tptr->owner); 9205d571944SMatt Jacob } 92167ff51f1SMatt Jacob return (-1); 922b6b6ad2fSMatt Jacob } 92364edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] |= TM_TMODE_ENABLED; 924126ec864SMatt Jacob isp_prt(isp, ISP_LOGINFO, 925126ec864SMatt Jacob "Target Mode enabled on channel %d", bus); 926746e9c85SMatt Jacob } else if (cel->enable == 0 && tm_on && wildcard) { 927a1bc34c6SMatt Jacob if (are_any_luns_enabled(isp, bus)) { 928b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_SCSI_BUSY; 92967ff51f1SMatt Jacob return (-1); 930b6b6ad2fSMatt Jacob } 931b6b6ad2fSMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 932b6b6ad2fSMatt Jacob if (av) { 933b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 93467ff51f1SMatt Jacob return (-1); 935b6b6ad2fSMatt Jacob } 93664edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED; 937126ec864SMatt Jacob isp_prt(isp, ISP_LOGINFO, 938126ec864SMatt Jacob "Target Mode disabled on channel %d", bus); 939126ec864SMatt Jacob } 940126ec864SMatt Jacob 941126ec864SMatt Jacob if (wildcard) { 94264edff94SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 94367ff51f1SMatt Jacob return (-1); 944b6b6ad2fSMatt Jacob } 945b6b6ad2fSMatt Jacob 94667ff51f1SMatt Jacob /* 94767ff51f1SMatt Jacob * Find an empty slot 94867ff51f1SMatt Jacob */ 94967ff51f1SMatt Jacob for (seq = 0; seq < NLEACT; seq++) { 95067ff51f1SMatt Jacob if (isp->isp_osinfo.leact[seq] == 0) { 95167ff51f1SMatt Jacob break; 95267ff51f1SMatt Jacob } 95367ff51f1SMatt Jacob } 95467ff51f1SMatt Jacob if (seq >= NLEACT) { 95567ff51f1SMatt Jacob ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 95667ff51f1SMatt Jacob return (-1); 95767ff51f1SMatt Jacob 95867ff51f1SMatt Jacob } 95967ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = ccb; 96067ff51f1SMatt Jacob 961d81ba9d5SMatt Jacob if (cel->enable) { 962d81ba9d5SMatt Jacob ccb->ccb_h.status = 963a1bc34c6SMatt Jacob create_lun_state(isp, bus, ccb->ccb_h.path, &tptr); 964d81ba9d5SMatt Jacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 96567ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 96667ff51f1SMatt Jacob return (-1); 967d81ba9d5SMatt Jacob } 968d81ba9d5SMatt Jacob } else { 969a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, lun); 970d81ba9d5SMatt Jacob if (tptr == NULL) { 971d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 97267ff51f1SMatt Jacob return (-1); 973d81ba9d5SMatt Jacob } 974d81ba9d5SMatt Jacob } 975d81ba9d5SMatt Jacob 976d81ba9d5SMatt Jacob if (cel->enable) { 9775d571944SMatt Jacob int c, n, ulun = lun; 9785d571944SMatt Jacob 9795d571944SMatt Jacob cmd = RQSTYPE_ENABLE_LUN; 9805d571944SMatt Jacob c = DFLT_CMND_CNT; 9815d571944SMatt Jacob n = DFLT_INOT_CNT; 9825d571944SMatt Jacob if (IS_FC(isp) && lun != 0) { 9835d571944SMatt Jacob cmd = RQSTYPE_MODIFY_LUN; 9845d571944SMatt Jacob n = 0; 9855d571944SMatt Jacob /* 9865d571944SMatt Jacob * For SCC firmware, we only deal with setting 9875d571944SMatt Jacob * (enabling or modifying) lun 0. 9885d571944SMatt Jacob */ 9895d571944SMatt Jacob ulun = 0; 9905d571944SMatt Jacob } 99167ff51f1SMatt Jacob if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq+1) == 0) { 99267ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 99367ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_INPROG; 99467ff51f1SMatt Jacob return (seq); 995d81ba9d5SMatt Jacob } 996d81ba9d5SMatt Jacob } else { 9975d571944SMatt Jacob int c, n, ulun = lun; 998d81ba9d5SMatt Jacob 9995d571944SMatt Jacob cmd = -RQSTYPE_MODIFY_LUN; 10005d571944SMatt Jacob c = DFLT_CMND_CNT; 10015d571944SMatt Jacob n = DFLT_INOT_CNT; 10025d571944SMatt Jacob if (IS_FC(isp) && lun != 0) { 10035d571944SMatt Jacob n = 0; 10045d571944SMatt Jacob /* 10055d571944SMatt Jacob * For SCC firmware, we only deal with setting 10065d571944SMatt Jacob * (enabling or modifying) lun 0. 10075d571944SMatt Jacob */ 10085d571944SMatt Jacob ulun = 0; 10095d571944SMatt Jacob } 101067ff51f1SMatt Jacob if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq+1) == 0) { 101167ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 101267ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_INPROG; 101367ff51f1SMatt Jacob return (seq); 1014d81ba9d5SMatt Jacob } 1015d81ba9d5SMatt Jacob } 101667ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 1017d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 101867ff51f1SMatt Jacob printf("isp_lun_cmd failed\n"); 101967ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 102067ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 102167ff51f1SMatt Jacob return (-1); 10225d571944SMatt Jacob } 10235d571944SMatt Jacob 102467ff51f1SMatt Jacob static void 102567ff51f1SMatt Jacob isp_ledone(struct ispsoftc *isp, lun_entry_t *lep) 102667ff51f1SMatt Jacob { 102767ff51f1SMatt Jacob const char lfmt[] = "lun %d now %sabled for target mode on channel %d"; 102867ff51f1SMatt Jacob union ccb *ccb; 102967ff51f1SMatt Jacob u_int32_t seq; 103067ff51f1SMatt Jacob tstate_t *tptr; 103167ff51f1SMatt Jacob int av; 103267ff51f1SMatt Jacob struct ccb_en_lun *cel; 1033d81ba9d5SMatt Jacob 103467ff51f1SMatt Jacob seq = lep->le_reserved - 1; 103567ff51f1SMatt Jacob if (seq >= NLEACT) { 10363c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, 103767ff51f1SMatt Jacob "seq out of range (%u) in isp_ledone", seq); 103867ff51f1SMatt Jacob return; 1039d81ba9d5SMatt Jacob } 104067ff51f1SMatt Jacob ccb = isp->isp_osinfo.leact[seq]; 104167ff51f1SMatt Jacob if (ccb == 0) { 104267ff51f1SMatt Jacob isp_prt(isp, ISP_LOGERR, 104367ff51f1SMatt Jacob "no ccb for seq %u in isp_ledone", seq); 104467ff51f1SMatt Jacob return; 104567ff51f1SMatt Jacob } 104667ff51f1SMatt Jacob cel = &ccb->cel; 104767ff51f1SMatt Jacob tptr = get_lun_statep(isp, XS_CHANNEL(ccb), XS_LUN(ccb)); 104867ff51f1SMatt Jacob if (tptr == NULL) { 1049d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 105067ff51f1SMatt Jacob printf("null tptr in isp_ledone\n"); 105167ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 105267ff51f1SMatt Jacob return; 1053d81ba9d5SMatt Jacob } 105467ff51f1SMatt Jacob 105567ff51f1SMatt Jacob if (lep->le_status != LUN_OK) { 105667ff51f1SMatt Jacob xpt_print_path(ccb->ccb_h.path); 105767ff51f1SMatt Jacob printf("ENABLE/MODIFY LUN returned 0x%x\n", lep->le_status); 105867ff51f1SMatt Jacob err: 105967ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 106067ff51f1SMatt Jacob xpt_print_path(ccb->ccb_h.path); 106167ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 106267ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 106367ff51f1SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 106467ff51f1SMatt Jacob xpt_done(ccb); 106567ff51f1SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 106667ff51f1SMatt Jacob return; 106767ff51f1SMatt Jacob } else { 106867ff51f1SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 106967ff51f1SMatt Jacob "isp_ledone: ENABLE/MODIFY done okay"); 107067ff51f1SMatt Jacob } 107167ff51f1SMatt Jacob 107267ff51f1SMatt Jacob 107367ff51f1SMatt Jacob if (cel->enable) { 107467ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 107567ff51f1SMatt Jacob isp_prt(isp, /* ISP_LOGINFO */ ISP_LOGALL, lfmt, 107667ff51f1SMatt Jacob XS_LUN(ccb), "en", XS_CHANNEL(ccb)); 107767ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 107867ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 107967ff51f1SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 108067ff51f1SMatt Jacob xpt_done(ccb); 108167ff51f1SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 108267ff51f1SMatt Jacob return; 108367ff51f1SMatt Jacob } 108467ff51f1SMatt Jacob 108567ff51f1SMatt Jacob if (lep->le_header.rqs_entry_type == RQSTYPE_MODIFY_LUN) { 108667ff51f1SMatt Jacob if (isp_lun_cmd(isp, -RQSTYPE_ENABLE_LUN, XS_CHANNEL(ccb), 108767ff51f1SMatt Jacob XS_TGT(ccb), XS_LUN(ccb), 0, 0, seq+1)) { 108867ff51f1SMatt Jacob xpt_print_path(ccb->ccb_h.path); 108967ff51f1SMatt Jacob printf("isp_ledone: isp_lun_cmd failed\n"); 109067ff51f1SMatt Jacob goto err; 109167ff51f1SMatt Jacob } 109267ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 109367ff51f1SMatt Jacob return; 109467ff51f1SMatt Jacob } 109567ff51f1SMatt Jacob 109667ff51f1SMatt Jacob isp_prt(isp, ISP_LOGINFO, lfmt, XS_LUN(ccb), "dis", XS_CHANNEL(ccb)); 109767ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 109867ff51f1SMatt Jacob destroy_lun_state(isp, tptr); 109967ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 110067ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 110167ff51f1SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 110267ff51f1SMatt Jacob xpt_done(ccb); 110367ff51f1SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 110467ff51f1SMatt Jacob if (are_any_luns_enabled(isp, XS_CHANNEL(ccb)) == 0) { 110567ff51f1SMatt Jacob int bus = XS_CHANNEL(ccb); 110667ff51f1SMatt Jacob av = bus << 31; 1107126ec864SMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 1108126ec864SMatt Jacob if (av) { 1109126ec864SMatt Jacob isp_prt(isp, ISP_LOGWARN, 111067ff51f1SMatt Jacob "disable target mode on channel %d failed", bus); 111167ff51f1SMatt Jacob } else { 1112126ec864SMatt Jacob isp_prt(isp, ISP_LOGINFO, 1113126ec864SMatt Jacob "Target Mode disabled on channel %d", bus); 1114126ec864SMatt Jacob } 111567ff51f1SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED; 111667ff51f1SMatt Jacob } 1117126ec864SMatt Jacob } 1118126ec864SMatt Jacob 1119d81ba9d5SMatt Jacob 1120d81ba9d5SMatt Jacob static cam_status 1121d81ba9d5SMatt Jacob isp_abort_tgt_ccb(struct ispsoftc *isp, union ccb *ccb) 1122d81ba9d5SMatt Jacob { 1123d81ba9d5SMatt Jacob tstate_t *tptr; 1124d81ba9d5SMatt Jacob struct ccb_hdr_slist *lp; 1125d81ba9d5SMatt Jacob struct ccb_hdr *curelm; 1126746e9c85SMatt Jacob int found, *ctr; 1127d81ba9d5SMatt Jacob union ccb *accb = ccb->cab.abort_ccb; 1128d81ba9d5SMatt Jacob 1129746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "aborting ccb %p", accb); 1130d81ba9d5SMatt Jacob if (accb->ccb_h.target_id != CAM_TARGET_WILDCARD) { 1131746e9c85SMatt Jacob int badpath = 0; 1132d81ba9d5SMatt Jacob if (IS_FC(isp) && (accb->ccb_h.target_id != 1133d81ba9d5SMatt Jacob ((fcparam *) isp->isp_param)->isp_loopid)) { 1134746e9c85SMatt Jacob badpath = 1; 1135d81ba9d5SMatt Jacob } else if (IS_SCSI(isp) && (accb->ccb_h.target_id != 1136d81ba9d5SMatt Jacob ((sdparam *) isp->isp_param)->isp_initiator_id)) { 1137746e9c85SMatt Jacob badpath = 1; 1138746e9c85SMatt Jacob } 1139746e9c85SMatt Jacob if (badpath) { 1140746e9c85SMatt Jacob /* 1141746e9c85SMatt Jacob * Being restrictive about target ids is really about 1142746e9c85SMatt Jacob * making sure we're aborting for the right multi-tid 1143746e9c85SMatt Jacob * path. This doesn't really make much sense at present. 1144746e9c85SMatt Jacob */ 1145746e9c85SMatt Jacob #if 0 1146d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 1147746e9c85SMatt Jacob #endif 1148d81ba9d5SMatt Jacob } 1149d81ba9d5SMatt Jacob } 1150a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, XS_CHANNEL(ccb), accb->ccb_h.target_lun); 1151d81ba9d5SMatt Jacob if (tptr == NULL) { 1152746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1153746e9c85SMatt Jacob "isp_abort_tgt_ccb: can't get statep"); 1154d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 1155d81ba9d5SMatt Jacob } 1156d81ba9d5SMatt Jacob if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 1157d81ba9d5SMatt Jacob lp = &tptr->atios; 1158746e9c85SMatt Jacob ctr = &tptr->atio_count; 1159d81ba9d5SMatt Jacob } else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY) { 1160d81ba9d5SMatt Jacob lp = &tptr->inots; 1161746e9c85SMatt Jacob ctr = &tptr->inot_count; 1162d81ba9d5SMatt Jacob } else { 1163d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1164746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1165746e9c85SMatt Jacob "isp_abort_tgt_ccb: bad func %d\n", accb->ccb_h.func_code); 1166d81ba9d5SMatt Jacob return (CAM_UA_ABORT); 1167d81ba9d5SMatt Jacob } 1168d81ba9d5SMatt Jacob curelm = SLIST_FIRST(lp); 1169d81ba9d5SMatt Jacob found = 0; 1170d81ba9d5SMatt Jacob if (curelm == &accb->ccb_h) { 1171d81ba9d5SMatt Jacob found = 1; 1172d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(lp, sim_links.sle); 1173d81ba9d5SMatt Jacob } else { 1174d81ba9d5SMatt Jacob while(curelm != NULL) { 1175d81ba9d5SMatt Jacob struct ccb_hdr *nextelm; 1176d81ba9d5SMatt Jacob 1177d81ba9d5SMatt Jacob nextelm = SLIST_NEXT(curelm, sim_links.sle); 1178d81ba9d5SMatt Jacob if (nextelm == &accb->ccb_h) { 1179d81ba9d5SMatt Jacob found = 1; 1180d81ba9d5SMatt Jacob SLIST_NEXT(curelm, sim_links.sle) = 1181d81ba9d5SMatt Jacob SLIST_NEXT(nextelm, sim_links.sle); 1182d81ba9d5SMatt Jacob break; 1183d81ba9d5SMatt Jacob } 1184d81ba9d5SMatt Jacob curelm = nextelm; 1185d81ba9d5SMatt Jacob } 1186d81ba9d5SMatt Jacob } 1187d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1188d81ba9d5SMatt Jacob if (found) { 1189746e9c85SMatt Jacob *ctr--; 1190d81ba9d5SMatt Jacob accb->ccb_h.status = CAM_REQ_ABORTED; 1191746e9c85SMatt Jacob xpt_done(accb); 1192d81ba9d5SMatt Jacob return (CAM_REQ_CMP); 1193d81ba9d5SMatt Jacob } 1194746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1195746e9c85SMatt Jacob "isp_abort_tgt_ccb: CCB %p not found\n", ccb); 1196d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 1197d81ba9d5SMatt Jacob } 1198d81ba9d5SMatt Jacob 1199d81ba9d5SMatt Jacob static cam_status 1200d81ba9d5SMatt Jacob isp_target_start_ctio(struct ispsoftc *isp, union ccb *ccb) 1201d81ba9d5SMatt Jacob { 1202d81ba9d5SMatt Jacob void *qe; 120300a8e174SMatt Jacob struct ccb_scsiio *cso = &ccb->csio; 12045f5aafe1SMatt Jacob u_int16_t *hp, save_handle; 12054fd13c1bSMatt Jacob u_int16_t nxti, optr; 12064fd13c1bSMatt Jacob u_int8_t local[QENTRY_LEN]; 1207d81ba9d5SMatt Jacob 1208f48ce188SMatt Jacob 12094fd13c1bSMatt Jacob if (isp_getrqentry(isp, &nxti, &optr, &qe)) { 121092a1e549SMatt Jacob xpt_print_path(ccb->ccb_h.path); 121192a1e549SMatt Jacob printf("Request Queue Overflow in isp_target_start_ctio\n"); 1212d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 1213d81ba9d5SMatt Jacob } 12144fd13c1bSMatt Jacob bzero(local, QENTRY_LEN); 1215d81ba9d5SMatt Jacob 1216d81ba9d5SMatt Jacob /* 1217d81ba9d5SMatt Jacob * We're either moving data or completing a command here. 1218d81ba9d5SMatt Jacob */ 1219d81ba9d5SMatt Jacob 1220d81ba9d5SMatt Jacob if (IS_FC(isp)) { 122153036e92SMatt Jacob atio_private_data_t *atp; 12224fd13c1bSMatt Jacob ct2_entry_t *cto = (ct2_entry_t *) local; 122300a8e174SMatt Jacob 1224d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; 1225d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_count = 1; 122600a8e174SMatt Jacob cto->ct_iid = cso->init_id; 122764edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) { 1228d81ba9d5SMatt Jacob cto->ct_lun = ccb->ccb_h.target_lun; 12292ad50ca5SMatt Jacob } 123053036e92SMatt Jacob 123153036e92SMatt Jacob atp = isp_get_atpd(isp, cso->tag_id); 123253036e92SMatt Jacob if (atp == NULL) { 1233570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGERR, 1234570c7a3fSMatt Jacob "cannot find private data adjunct for tag %x", 123553036e92SMatt Jacob cso->tag_id); 1236570c7a3fSMatt Jacob return (-1); 123753036e92SMatt Jacob } 1238f48ce188SMatt Jacob 123900a8e174SMatt Jacob cto->ct_rxid = cso->tag_id; 124000a8e174SMatt Jacob if (cso->dxfer_len == 0) { 124100a8e174SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA; 1242f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 124300a8e174SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 1244f48ce188SMatt Jacob cto->rsp.m1.ct_scsi_status = cso->scsi_status; 124553036e92SMatt Jacob cto->ct_resid = 124653036e92SMatt Jacob atp->orig_datalen - atp->bytes_xfered; 1247570c7a3fSMatt Jacob if (cto->ct_resid < 0) { 1248570c7a3fSMatt Jacob cto->rsp.m1.ct_scsi_status |= 1249570c7a3fSMatt Jacob CT2_DATA_OVER; 1250570c7a3fSMatt Jacob } else if (cto->ct_resid > 0) { 1251570c7a3fSMatt Jacob cto->rsp.m1.ct_scsi_status |= 1252570c7a3fSMatt Jacob CT2_DATA_UNDER; 1253570c7a3fSMatt Jacob } 1254f48ce188SMatt Jacob } 125500a8e174SMatt Jacob if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) { 125600a8e174SMatt Jacob int m = min(cso->sense_len, MAXRESPLEN); 125700a8e174SMatt Jacob bcopy(&cso->sense_data, cto->rsp.m1.ct_resp, m); 125800a8e174SMatt Jacob cto->rsp.m1.ct_senselen = m; 125900a8e174SMatt Jacob cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID; 126000a8e174SMatt Jacob } 126100a8e174SMatt Jacob } else { 126200a8e174SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE0; 126300a8e174SMatt Jacob if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 126400a8e174SMatt Jacob cto->ct_flags |= CT2_DATA_IN; 126500a8e174SMatt Jacob } else { 126600a8e174SMatt Jacob cto->ct_flags |= CT2_DATA_OUT; 1267d81ba9d5SMatt Jacob } 1268570c7a3fSMatt Jacob cto->ct_reloff = atp->bytes_xfered; 1269d81ba9d5SMatt Jacob if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 1270d81ba9d5SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 127100a8e174SMatt Jacob cto->rsp.m0.ct_scsi_status = cso->scsi_status; 127253036e92SMatt Jacob cto->ct_resid = 127353036e92SMatt Jacob atp->orig_datalen - 127453036e92SMatt Jacob (atp->bytes_xfered + cso->dxfer_len); 1275570c7a3fSMatt Jacob if (cto->ct_resid < 0) { 1276570c7a3fSMatt Jacob cto->rsp.m0.ct_scsi_status |= 1277570c7a3fSMatt Jacob CT2_DATA_OVER; 1278570c7a3fSMatt Jacob } else if (cto->ct_resid > 0) { 1279570c7a3fSMatt Jacob cto->rsp.m0.ct_scsi_status |= 1280570c7a3fSMatt Jacob CT2_DATA_UNDER; 1281570c7a3fSMatt Jacob } 128253036e92SMatt Jacob } else { 128353036e92SMatt Jacob atp->last_xframt = cso->dxfer_len; 1284d81ba9d5SMatt Jacob } 1285f48ce188SMatt Jacob /* 1286f48ce188SMatt Jacob * If we're sending data and status back together, 1287f48ce188SMatt Jacob * we can't also send back sense data as well. 1288f48ce188SMatt Jacob */ 128900a8e174SMatt Jacob ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 129000a8e174SMatt Jacob } 129153036e92SMatt Jacob 1292290dc24bSMatt Jacob if (cto->ct_flags & CT2_SENDSTATUS) { 129364edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 129453036e92SMatt Jacob "CTIO2[%x] STATUS %x origd %u curd %u resid %u", 129553036e92SMatt Jacob cto->ct_rxid, cso->scsi_status, atp->orig_datalen, 129653036e92SMatt Jacob cso->dxfer_len, cto->ct_resid); 1297a1bc34c6SMatt Jacob cto->ct_flags |= CT2_CCINCR; 1298570c7a3fSMatt Jacob atp->state = ATPD_STATE_LAST_CTIO; 1299570c7a3fSMatt Jacob } else 1300570c7a3fSMatt Jacob atp->state = ATPD_STATE_CTIO; 1301a1bc34c6SMatt Jacob cto->ct_timeout = 10; 13025f5aafe1SMatt Jacob hp = &cto->ct_syshandle; 1303d81ba9d5SMatt Jacob } else { 13044fd13c1bSMatt Jacob ct_entry_t *cto = (ct_entry_t *) local; 130500a8e174SMatt Jacob 1306d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 1307d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_count = 1; 130800a8e174SMatt Jacob cto->ct_iid = cso->init_id; 1309a1bc34c6SMatt Jacob cto->ct_iid |= XS_CHANNEL(ccb) << 7; 1310d81ba9d5SMatt Jacob cto->ct_tgt = ccb->ccb_h.target_id; 1311d81ba9d5SMatt Jacob cto->ct_lun = ccb->ccb_h.target_lun; 1312a1bc34c6SMatt Jacob cto->ct_fwhandle = AT_GET_HANDLE(cso->tag_id); 1313a1bc34c6SMatt Jacob if (AT_HAS_TAG(cso->tag_id)) { 1314a1bc34c6SMatt Jacob cto->ct_tag_val = (u_int8_t) AT_GET_TAG(cso->tag_id); 1315f48ce188SMatt Jacob cto->ct_flags |= CT_TQAE; 1316f48ce188SMatt Jacob } 1317f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) { 1318f48ce188SMatt Jacob cto->ct_flags |= CT_NODISC; 1319f48ce188SMatt Jacob } 1320f48ce188SMatt Jacob if (cso->dxfer_len == 0) { 1321d81ba9d5SMatt Jacob cto->ct_flags |= CT_NO_DATA; 132200a8e174SMatt Jacob } else if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 132300a8e174SMatt Jacob cto->ct_flags |= CT_DATA_IN; 132400a8e174SMatt Jacob } else { 132500a8e174SMatt Jacob cto->ct_flags |= CT_DATA_OUT; 1326d81ba9d5SMatt Jacob } 1327f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 132853036e92SMatt Jacob cto->ct_flags |= CT_SENDSTATUS|CT_CCINCR; 132900a8e174SMatt Jacob cto->ct_scsi_status = cso->scsi_status; 133000a8e174SMatt Jacob cto->ct_resid = cso->resid; 133164edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1332a1bc34c6SMatt Jacob "CTIO[%x] SCSI STATUS 0x%x resid %d tag_id %x", 1333a1bc34c6SMatt Jacob cto->ct_fwhandle, cso->scsi_status, cso->resid, 1334a1bc34c6SMatt Jacob cso->tag_id); 133592a1e549SMatt Jacob } 133664edff94SMatt Jacob ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 1337a1bc34c6SMatt Jacob cto->ct_timeout = 10; 13385f5aafe1SMatt Jacob hp = &cto->ct_syshandle; 1339d81ba9d5SMatt Jacob } 1340d81ba9d5SMatt Jacob 134151e23558SNate Lawson if (isp_save_xs_tgt(isp, ccb, hp)) { 134292a1e549SMatt Jacob xpt_print_path(ccb->ccb_h.path); 134392a1e549SMatt Jacob printf("No XFLIST pointers for isp_target_start_ctio\n"); 1344d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 1345d81ba9d5SMatt Jacob } 1346d81ba9d5SMatt Jacob 1347d81ba9d5SMatt Jacob 1348d81ba9d5SMatt Jacob /* 1349d81ba9d5SMatt Jacob * Call the dma setup routines for this entry (and any subsequent 1350d81ba9d5SMatt Jacob * CTIOs) if there's data to move, and then tell the f/w it's got 1351b09b0095SMatt Jacob * new things to play with. As with isp_start's usage of DMA setup, 1352d81ba9d5SMatt Jacob * any swizzling is done in the machine dependent layer. Because 1353d81ba9d5SMatt Jacob * of this, we put the request onto the queue area first in native 1354d81ba9d5SMatt Jacob * format. 1355d81ba9d5SMatt Jacob */ 1356d81ba9d5SMatt Jacob 1357d81ba9d5SMatt Jacob save_handle = *hp; 1358a1bc34c6SMatt Jacob 13594fd13c1bSMatt Jacob switch (ISP_DMASETUP(isp, cso, (ispreq_t *) local, &nxti, optr)) { 1360d81ba9d5SMatt Jacob case CMD_QUEUED: 13614fd13c1bSMatt Jacob ISP_ADD_REQUEST(isp, nxti); 1362d81ba9d5SMatt Jacob return (CAM_REQ_INPROG); 1363d81ba9d5SMatt Jacob 1364d81ba9d5SMatt Jacob case CMD_EAGAIN: 1365d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 136651e23558SNate Lawson isp_destroy_tgt_handle(isp, save_handle); 1367d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 1368d81ba9d5SMatt Jacob 1369d81ba9d5SMatt Jacob default: 137051e23558SNate Lawson isp_destroy_tgt_handle(isp, save_handle); 1371b85389e1SMatt Jacob return (XS_ERR(ccb)); 1372d81ba9d5SMatt Jacob } 1373d81ba9d5SMatt Jacob } 1374d81ba9d5SMatt Jacob 1375a1bc34c6SMatt Jacob static void 1376a1bc34c6SMatt Jacob isp_refire_putback_atio(void *arg) 1377f48ce188SMatt Jacob { 1378a1bc34c6SMatt Jacob int s = splcam(); 1379a1bc34c6SMatt Jacob isp_target_putback_atio(arg); 1380a1bc34c6SMatt Jacob splx(s); 1381a1bc34c6SMatt Jacob } 1382a1bc34c6SMatt Jacob 1383a1bc34c6SMatt Jacob static void 1384a1bc34c6SMatt Jacob isp_target_putback_atio(union ccb *ccb) 1385a1bc34c6SMatt Jacob { 1386a1bc34c6SMatt Jacob struct ispsoftc *isp; 1387a1bc34c6SMatt Jacob struct ccb_scsiio *cso; 13884fd13c1bSMatt Jacob u_int16_t nxti, optr; 1389a1bc34c6SMatt Jacob void *qe; 1390a1bc34c6SMatt Jacob 1391a1bc34c6SMatt Jacob isp = XS_ISP(ccb); 1392f48ce188SMatt Jacob 13934fd13c1bSMatt Jacob if (isp_getrqentry(isp, &nxti, &optr, &qe)) { 1394a1bc34c6SMatt Jacob (void) timeout(isp_refire_putback_atio, ccb, 10); 1395a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGWARN, 1396a1bc34c6SMatt Jacob "isp_target_putback_atio: Request Queue Overflow"); 1397a1bc34c6SMatt Jacob return; 1398f48ce188SMatt Jacob } 1399f48ce188SMatt Jacob bzero(qe, QENTRY_LEN); 1400a1bc34c6SMatt Jacob cso = &ccb->csio; 1401f48ce188SMatt Jacob if (IS_FC(isp)) { 14024fd13c1bSMatt Jacob at2_entry_t local, *at = &local; 14034fd13c1bSMatt Jacob MEMZERO(at, sizeof (at2_entry_t)); 1404f48ce188SMatt Jacob at->at_header.rqs_entry_type = RQSTYPE_ATIO2; 1405f48ce188SMatt Jacob at->at_header.rqs_entry_count = 1; 140664edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) != 0) { 1407a1bc34c6SMatt Jacob at->at_scclun = (uint16_t) ccb->ccb_h.target_lun; 1408f48ce188SMatt Jacob } else { 1409a1bc34c6SMatt Jacob at->at_lun = (uint8_t) ccb->ccb_h.target_lun; 1410f48ce188SMatt Jacob } 1411f48ce188SMatt Jacob at->at_status = CT_OK; 1412a1bc34c6SMatt Jacob at->at_rxid = cso->tag_id; 1413570c7a3fSMatt Jacob at->at_iid = cso->ccb_h.target_id; 14144fd13c1bSMatt Jacob isp_put_atio2(isp, at, qe); 1415f48ce188SMatt Jacob } else { 14164fd13c1bSMatt Jacob at_entry_t local, *at = &local; 14174fd13c1bSMatt Jacob MEMZERO(at, sizeof (at_entry_t)); 1418f48ce188SMatt Jacob at->at_header.rqs_entry_type = RQSTYPE_ATIO; 1419f48ce188SMatt Jacob at->at_header.rqs_entry_count = 1; 1420a1bc34c6SMatt Jacob at->at_iid = cso->init_id; 1421a1bc34c6SMatt Jacob at->at_iid |= XS_CHANNEL(ccb) << 7; 1422a1bc34c6SMatt Jacob at->at_tgt = cso->ccb_h.target_id; 1423a1bc34c6SMatt Jacob at->at_lun = cso->ccb_h.target_lun; 1424f48ce188SMatt Jacob at->at_status = CT_OK; 1425a1bc34c6SMatt Jacob at->at_tag_val = AT_GET_TAG(cso->tag_id); 1426a1bc34c6SMatt Jacob at->at_handle = AT_GET_HANDLE(cso->tag_id); 14274fd13c1bSMatt Jacob isp_put_atio(isp, at, qe); 1428f48ce188SMatt Jacob } 1429f48ce188SMatt Jacob ISP_TDQE(isp, "isp_target_putback_atio", (int) optr, qe); 14304fd13c1bSMatt Jacob ISP_ADD_REQUEST(isp, nxti); 1431a1bc34c6SMatt Jacob isp_complete_ctio(ccb); 1432f48ce188SMatt Jacob } 1433f48ce188SMatt Jacob 1434f48ce188SMatt Jacob static void 1435a1bc34c6SMatt Jacob isp_complete_ctio(union ccb *ccb) 1436f48ce188SMatt Jacob { 1437a1bc34c6SMatt Jacob if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { 1438a1bc34c6SMatt Jacob ccb->ccb_h.status |= CAM_REQ_CMP; 1439f48ce188SMatt Jacob } 1440a1bc34c6SMatt Jacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1441a1bc34c6SMatt Jacob xpt_done(ccb); 1442f48ce188SMatt Jacob } 1443f48ce188SMatt Jacob 1444d81ba9d5SMatt Jacob /* 1445d81ba9d5SMatt Jacob * Handle ATIO stuff that the generic code can't. 1446d81ba9d5SMatt Jacob * This means handling CDBs. 1447d81ba9d5SMatt Jacob */ 1448d81ba9d5SMatt Jacob 1449d81ba9d5SMatt Jacob static int 1450d81ba9d5SMatt Jacob isp_handle_platform_atio(struct ispsoftc *isp, at_entry_t *aep) 1451d81ba9d5SMatt Jacob { 1452d81ba9d5SMatt Jacob tstate_t *tptr; 145364edff94SMatt Jacob int status, bus, iswildcard; 1454d81ba9d5SMatt Jacob struct ccb_accept_tio *atiop; 1455d81ba9d5SMatt Jacob 1456d81ba9d5SMatt Jacob /* 1457d81ba9d5SMatt Jacob * The firmware status (except for the QLTM_SVALID bit) 1458d81ba9d5SMatt Jacob * indicates why this ATIO was sent to us. 1459d81ba9d5SMatt Jacob * 1460d81ba9d5SMatt Jacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 1461d81ba9d5SMatt Jacob * 1462d81ba9d5SMatt Jacob * If the DISCONNECTS DISABLED bit is set in the flags field, 14635d571944SMatt Jacob * we're still connected on the SCSI bus. 1464d81ba9d5SMatt Jacob */ 1465d81ba9d5SMatt Jacob status = aep->at_status; 1466d81ba9d5SMatt Jacob if ((status & ~QLTM_SVALID) == AT_PHASE_ERROR) { 1467d81ba9d5SMatt Jacob /* 1468d81ba9d5SMatt Jacob * Bus Phase Sequence error. We should have sense data 1469d81ba9d5SMatt Jacob * suggested by the f/w. I'm not sure quite yet what 1470d81ba9d5SMatt Jacob * to do about this for CAM. 1471d81ba9d5SMatt Jacob */ 14723c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, "PHASE ERROR"); 1473d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1474d81ba9d5SMatt Jacob return (0); 1475d81ba9d5SMatt Jacob } 1476d81ba9d5SMatt Jacob if ((status & ~QLTM_SVALID) != AT_CDB) { 14775d571944SMatt Jacob isp_prt(isp, ISP_LOGWARN, "bad atio (0x%x) leaked to platform", 14783c75bb14SMatt Jacob status); 1479d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1480d81ba9d5SMatt Jacob return (0); 1481d81ba9d5SMatt Jacob } 1482d81ba9d5SMatt Jacob 14835d571944SMatt Jacob bus = GET_BUS_VAL(aep->at_iid); 1484a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, aep->at_lun); 1485d81ba9d5SMatt Jacob if (tptr == NULL) { 1486a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD); 1487746e9c85SMatt Jacob if (tptr == NULL) { 1488746e9c85SMatt Jacob isp_endcmd(isp, aep, 1489746e9c85SMatt Jacob SCSI_STATUS_CHECK_COND | ECMD_SVALID | 1490746e9c85SMatt Jacob (0x5 << 12) | (0x25 << 16), 0); 1491746e9c85SMatt Jacob return (0); 1492746e9c85SMatt Jacob } 149364edff94SMatt Jacob iswildcard = 1; 149464edff94SMatt Jacob } else { 149564edff94SMatt Jacob iswildcard = 0; 1496d81ba9d5SMatt Jacob } 1497d81ba9d5SMatt Jacob 1498d81ba9d5SMatt Jacob if (tptr == NULL) { 1499d81ba9d5SMatt Jacob /* 1500d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1501d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1502d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a BUSY status 1503d81ba9d5SMatt Jacob * instead. This works out okay because the only 1504d81ba9d5SMatt Jacob * time we should, in fact, get this, is in the 1505d81ba9d5SMatt Jacob * case that somebody configured us without the 1506d81ba9d5SMatt Jacob * blackhole driver, so they get what they deserve. 1507d81ba9d5SMatt Jacob */ 1508d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1509d81ba9d5SMatt Jacob return (0); 1510d81ba9d5SMatt Jacob } 1511d81ba9d5SMatt Jacob 1512d81ba9d5SMatt Jacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 1513d81ba9d5SMatt Jacob if (atiop == NULL) { 1514d81ba9d5SMatt Jacob /* 1515d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1516d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1517d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a QUEUE FULL status 1518d81ba9d5SMatt Jacob * instead. This works out okay because the only time we 1519d81ba9d5SMatt Jacob * should, in fact, get this, is in the case that we've 1520d81ba9d5SMatt Jacob * run out of ATIOS. 1521d81ba9d5SMatt Jacob */ 1522d81ba9d5SMatt Jacob xpt_print_path(tptr->owner); 15233c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 1524a1bc34c6SMatt Jacob "no ATIOS for lun %d from initiator %d on channel %d", 15255d571944SMatt Jacob aep->at_lun, GET_IID_VAL(aep->at_iid), bus); 1526d81ba9d5SMatt Jacob if (aep->at_flags & AT_TQAE) 1527d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); 1528d81ba9d5SMatt Jacob else 1529d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 153064edff94SMatt Jacob rls_lun_statep(isp, tptr); 1531d81ba9d5SMatt Jacob return (0); 1532d81ba9d5SMatt Jacob } 1533d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 1534746e9c85SMatt Jacob tptr->atio_count--; 1535746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO lun %d, count now %d", 1536746e9c85SMatt Jacob aep->at_lun, tptr->atio_count); 153764edff94SMatt Jacob if (iswildcard) { 1538d81ba9d5SMatt Jacob atiop->ccb_h.target_id = aep->at_tgt; 1539d81ba9d5SMatt Jacob atiop->ccb_h.target_lun = aep->at_lun; 1540d81ba9d5SMatt Jacob } 1541d81ba9d5SMatt Jacob if (aep->at_flags & AT_NODISC) { 1542f48ce188SMatt Jacob atiop->ccb_h.flags = CAM_DIS_DISCONNECT; 1543f48ce188SMatt Jacob } else { 1544f48ce188SMatt Jacob atiop->ccb_h.flags = 0; 1545d81ba9d5SMatt Jacob } 1546d81ba9d5SMatt Jacob 1547f48ce188SMatt Jacob if (status & QLTM_SVALID) { 1548f48ce188SMatt Jacob size_t amt = imin(QLTM_SENSELEN, sizeof (atiop->sense_data)); 1549f48ce188SMatt Jacob atiop->sense_len = amt; 1550f48ce188SMatt Jacob MEMCPY(&atiop->sense_data, aep->at_sense, amt); 1551f48ce188SMatt Jacob } else { 1552f48ce188SMatt Jacob atiop->sense_len = 0; 1553f48ce188SMatt Jacob } 1554d81ba9d5SMatt Jacob 15555d571944SMatt Jacob atiop->init_id = GET_IID_VAL(aep->at_iid); 1556d81ba9d5SMatt Jacob atiop->cdb_len = aep->at_cdblen; 1557d81ba9d5SMatt Jacob MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen); 1558d81ba9d5SMatt Jacob atiop->ccb_h.status = CAM_CDB_RECVD; 1559a1bc34c6SMatt Jacob /* 1560a1bc34c6SMatt Jacob * Construct a tag 'id' based upon tag value (which may be 0..255) 1561a1bc34c6SMatt Jacob * and the handle (which we have to preserve). 1562a1bc34c6SMatt Jacob */ 15639f242f78SMatt Jacob AT_MAKE_TAGID(atiop->tag_id, device_get_unit(isp->isp_dev), aep); 1564a1bc34c6SMatt Jacob if (aep->at_flags & AT_TQAE) { 1565a1bc34c6SMatt Jacob atiop->tag_action = aep->at_tag_type; 1566d81ba9d5SMatt Jacob atiop->ccb_h.status |= CAM_TAG_ACTION_VALID; 1567d81ba9d5SMatt Jacob } 1568d81ba9d5SMatt Jacob xpt_done((union ccb*)atiop); 156964edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 15705d571944SMatt Jacob "ATIO[%x] CDB=0x%x bus %d iid%d->lun%d tag 0x%x ttype 0x%x %s", 15715d571944SMatt Jacob aep->at_handle, aep->at_cdb[0] & 0xff, GET_BUS_VAL(aep->at_iid), 15725d571944SMatt Jacob GET_IID_VAL(aep->at_iid), aep->at_lun, aep->at_tag_val & 0xff, 15735d571944SMatt Jacob aep->at_tag_type, (aep->at_flags & AT_NODISC)? 15745d571944SMatt Jacob "nondisc" : "disconnecting"); 1575d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1576d81ba9d5SMatt Jacob return (0); 1577d81ba9d5SMatt Jacob } 1578d81ba9d5SMatt Jacob 1579d81ba9d5SMatt Jacob static int 1580d81ba9d5SMatt Jacob isp_handle_platform_atio2(struct ispsoftc *isp, at2_entry_t *aep) 1581d81ba9d5SMatt Jacob { 158292a1e549SMatt Jacob lun_id_t lun; 1583d81ba9d5SMatt Jacob tstate_t *tptr; 1584d81ba9d5SMatt Jacob struct ccb_accept_tio *atiop; 158553036e92SMatt Jacob atio_private_data_t *atp; 1586d81ba9d5SMatt Jacob 1587d81ba9d5SMatt Jacob /* 1588d81ba9d5SMatt Jacob * The firmware status (except for the QLTM_SVALID bit) 1589d81ba9d5SMatt Jacob * indicates why this ATIO was sent to us. 1590d81ba9d5SMatt Jacob * 1591d81ba9d5SMatt Jacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 1592d81ba9d5SMatt Jacob */ 1593d81ba9d5SMatt Jacob if ((aep->at_status & ~QLTM_SVALID) != AT_CDB) { 15943c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 15953c75bb14SMatt Jacob "bogus atio (0x%x) leaked to platform", aep->at_status); 1596d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1597d81ba9d5SMatt Jacob return (0); 1598d81ba9d5SMatt Jacob } 1599d81ba9d5SMatt Jacob 160064edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) != 0) { 160192a1e549SMatt Jacob lun = aep->at_scclun; 16022ad50ca5SMatt Jacob } else { 160392a1e549SMatt Jacob lun = aep->at_lun; 16042ad50ca5SMatt Jacob } 1605a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, 0, lun); 1606d81ba9d5SMatt Jacob if (tptr == NULL) { 1607746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1608746e9c85SMatt Jacob "[0x%x] no state pointer for lun %d", aep->at_rxid, lun); 1609a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD); 1610746e9c85SMatt Jacob if (tptr == NULL) { 1611746e9c85SMatt Jacob isp_endcmd(isp, aep, 1612746e9c85SMatt Jacob SCSI_STATUS_CHECK_COND | ECMD_SVALID | 1613746e9c85SMatt Jacob (0x5 << 12) | (0x25 << 16), 0); 1614746e9c85SMatt Jacob return (0); 1615746e9c85SMatt Jacob } 1616d81ba9d5SMatt Jacob } 1617d81ba9d5SMatt Jacob 161853036e92SMatt Jacob atp = isp_get_atpd(isp, 0); 1619d81ba9d5SMatt Jacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 162053036e92SMatt Jacob if (atiop == NULL || atp == NULL) { 1621746e9c85SMatt Jacob 1622d81ba9d5SMatt Jacob /* 1623d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1624d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1625d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a QUEUE FULL status 1626d81ba9d5SMatt Jacob * instead. This works out okay because the only time we 1627d81ba9d5SMatt Jacob * should, in fact, get this, is in the case that we've 1628d81ba9d5SMatt Jacob * run out of ATIOS. 1629d81ba9d5SMatt Jacob */ 1630d81ba9d5SMatt Jacob xpt_print_path(tptr->owner); 16313c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 1632570c7a3fSMatt Jacob "no %s for lun %d from initiator %d", 1633570c7a3fSMatt Jacob (atp == NULL && atiop == NULL)? "ATIO2s *or* ATPS" : 1634570c7a3fSMatt Jacob ((atp == NULL)? "ATPs" : "ATIO2s"), lun, aep->at_iid); 1635d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1636d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); 1637d81ba9d5SMatt Jacob return (0); 1638d81ba9d5SMatt Jacob } 1639570c7a3fSMatt Jacob atp->state = ATPD_STATE_ATIO; 1640d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 1641570c7a3fSMatt Jacob tptr->atio_count--; 1642746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO lun %d, count now %d", 1643570c7a3fSMatt Jacob lun, tptr->atio_count); 1644f48ce188SMatt Jacob 1645a1bc34c6SMatt Jacob if (tptr == &isp->isp_osinfo.tsdflt[0]) { 1646d81ba9d5SMatt Jacob atiop->ccb_h.target_id = 1647d81ba9d5SMatt Jacob ((fcparam *)isp->isp_param)->isp_loopid; 164892a1e549SMatt Jacob atiop->ccb_h.target_lun = lun; 1649d81ba9d5SMatt Jacob } 1650b0a3ba7eSMatt Jacob /* 1651b0a3ba7eSMatt Jacob * We don't get 'suggested' sense data as we do with SCSI cards. 1652b0a3ba7eSMatt Jacob */ 1653f48ce188SMatt Jacob atiop->sense_len = 0; 1654f48ce188SMatt Jacob 1655d81ba9d5SMatt Jacob atiop->init_id = aep->at_iid; 1656d81ba9d5SMatt Jacob atiop->cdb_len = ATIO2_CDBLEN; 1657d81ba9d5SMatt Jacob MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, ATIO2_CDBLEN); 1658d81ba9d5SMatt Jacob atiop->ccb_h.status = CAM_CDB_RECVD; 1659d81ba9d5SMatt Jacob atiop->tag_id = aep->at_rxid; 1660d81ba9d5SMatt Jacob switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) { 1661d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_SIMPLEQ: 1662d81ba9d5SMatt Jacob atiop->tag_action = MSG_SIMPLE_Q_TAG; 1663d81ba9d5SMatt Jacob break; 1664d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_HEADOFQ: 1665d81ba9d5SMatt Jacob atiop->tag_action = MSG_HEAD_OF_Q_TAG; 1666d81ba9d5SMatt Jacob break; 1667d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_ORDERED: 1668d81ba9d5SMatt Jacob atiop->tag_action = MSG_ORDERED_Q_TAG; 1669d81ba9d5SMatt Jacob break; 1670d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_ACAQ: /* ?? */ 1671d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_UNTAGGED: 1672d81ba9d5SMatt Jacob default: 1673d81ba9d5SMatt Jacob atiop->tag_action = 0; 1674d81ba9d5SMatt Jacob break; 1675d81ba9d5SMatt Jacob } 1676570c7a3fSMatt Jacob atiop->ccb_h.flags = CAM_TAG_ACTION_VALID; 1677f48ce188SMatt Jacob 167853036e92SMatt Jacob atp->tag = atiop->tag_id; 1679570c7a3fSMatt Jacob atp->lun = lun; 168053036e92SMatt Jacob atp->orig_datalen = aep->at_datalen; 168153036e92SMatt Jacob atp->last_xframt = 0; 168253036e92SMatt Jacob atp->bytes_xfered = 0; 1683570c7a3fSMatt Jacob atp->state = ATPD_STATE_CAM; 168467ff51f1SMatt Jacob ISPLOCK_2_CAMLOCK(siP); 1685d81ba9d5SMatt Jacob xpt_done((union ccb*)atiop); 1686570c7a3fSMatt Jacob 168764edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 16885f5aafe1SMatt Jacob "ATIO2[%x] CDB=0x%x iid%d->lun%d tattr 0x%x datalen %u", 16895f5aafe1SMatt Jacob aep->at_rxid, aep->at_cdb[0] & 0xff, aep->at_iid, 1690b09b0095SMatt Jacob lun, aep->at_taskflags, aep->at_datalen); 1691d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1692d81ba9d5SMatt Jacob return (0); 1693d81ba9d5SMatt Jacob } 1694d81ba9d5SMatt Jacob 1695d81ba9d5SMatt Jacob static int 1696d81ba9d5SMatt Jacob isp_handle_platform_ctio(struct ispsoftc *isp, void *arg) 1697d81ba9d5SMatt Jacob { 1698d81ba9d5SMatt Jacob union ccb *ccb; 1699a1bc34c6SMatt Jacob int sentstatus, ok, notify_cam, resid = 0; 170064edff94SMatt Jacob u_int16_t tval; 1701d81ba9d5SMatt Jacob 1702d81ba9d5SMatt Jacob /* 1703d81ba9d5SMatt Jacob * CTIO and CTIO2 are close enough.... 1704d81ba9d5SMatt Jacob */ 1705d81ba9d5SMatt Jacob 170651e23558SNate Lawson ccb = isp_find_xs_tgt(isp, ((ct_entry_t *)arg)->ct_syshandle); 1707d81ba9d5SMatt Jacob KASSERT((ccb != NULL), ("null ccb in isp_handle_platform_ctio")); 170851e23558SNate Lawson isp_destroy_tgt_handle(isp, ((ct_entry_t *)arg)->ct_syshandle); 1709d81ba9d5SMatt Jacob 1710d81ba9d5SMatt Jacob if (IS_FC(isp)) { 1711d81ba9d5SMatt Jacob ct2_entry_t *ct = arg; 1712570c7a3fSMatt Jacob atio_private_data_t *atp = isp_get_atpd(isp, ct->ct_rxid); 1713570c7a3fSMatt Jacob if (atp == NULL) { 1714570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGERR, 1715570c7a3fSMatt Jacob "cannot find adjunct for %x after I/O", 1716570c7a3fSMatt Jacob ct->ct_rxid); 1717570c7a3fSMatt Jacob return (0); 1718570c7a3fSMatt Jacob } 1719d81ba9d5SMatt Jacob sentstatus = ct->ct_flags & CT2_SENDSTATUS; 1720d81ba9d5SMatt Jacob ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; 1721a1bc34c6SMatt Jacob if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) { 172200a8e174SMatt Jacob ccb->ccb_h.status |= CAM_SENT_SENSE; 172300a8e174SMatt Jacob } 1724a1bc34c6SMatt Jacob notify_cam = ct->ct_header.rqs_seqno & 0x1; 17255d571944SMatt Jacob if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) { 1726a1bc34c6SMatt Jacob resid = ct->ct_resid; 172753036e92SMatt Jacob atp->bytes_xfered += (atp->last_xframt - resid); 172853036e92SMatt Jacob atp->last_xframt = 0; 1729570c7a3fSMatt Jacob } 1730570c7a3fSMatt Jacob if (sentstatus || !ok) { 173153036e92SMatt Jacob atp->tag = 0; 173253036e92SMatt Jacob } 1733570c7a3fSMatt Jacob isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, 173464edff94SMatt Jacob "CTIO2[%x] sts 0x%x flg 0x%x sns %d resid %d %s", 173564edff94SMatt Jacob ct->ct_rxid, ct->ct_status, ct->ct_flags, 173664edff94SMatt Jacob (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, 173764edff94SMatt Jacob resid, sentstatus? "FIN" : "MID"); 173864edff94SMatt Jacob tval = ct->ct_rxid; 1739570c7a3fSMatt Jacob 1740570c7a3fSMatt Jacob /* XXX: should really come after isp_complete_ctio */ 1741570c7a3fSMatt Jacob atp->state = ATPD_STATE_PDON; 1742d81ba9d5SMatt Jacob } else { 1743d81ba9d5SMatt Jacob ct_entry_t *ct = arg; 1744d81ba9d5SMatt Jacob sentstatus = ct->ct_flags & CT_SENDSTATUS; 1745d81ba9d5SMatt Jacob ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; 1746d81ba9d5SMatt Jacob /* 1747a1bc34c6SMatt Jacob * We *ought* to be able to get back to the original ATIO 1748a1bc34c6SMatt Jacob * here, but for some reason this gets lost. It's just as 1749a1bc34c6SMatt Jacob * well because it's squirrelled away as part of periph 1750a1bc34c6SMatt Jacob * private data. 1751a1bc34c6SMatt Jacob * 1752a1bc34c6SMatt Jacob * We can live without it as long as we continue to use 1753a1bc34c6SMatt Jacob * the auto-replenish feature for CTIOs. 1754a1bc34c6SMatt Jacob */ 1755a1bc34c6SMatt Jacob notify_cam = ct->ct_header.rqs_seqno & 0x1; 1756a1bc34c6SMatt Jacob if (ct->ct_status & QLTM_SVALID) { 1757a1bc34c6SMatt Jacob char *sp = (char *)ct; 1758a1bc34c6SMatt Jacob sp += CTIO_SENSE_OFFSET; 1759a1bc34c6SMatt Jacob ccb->csio.sense_len = 1760a1bc34c6SMatt Jacob min(sizeof (ccb->csio.sense_data), QLTM_SENSELEN); 1761a1bc34c6SMatt Jacob MEMCPY(&ccb->csio.sense_data, sp, ccb->csio.sense_len); 1762a1bc34c6SMatt Jacob ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 1763a1bc34c6SMatt Jacob } 17645d571944SMatt Jacob if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) { 1765a1bc34c6SMatt Jacob resid = ct->ct_resid; 1766a1bc34c6SMatt Jacob } 176764edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 176864edff94SMatt Jacob "CTIO[%x] tag %x iid %d lun %d sts %x flg %x resid %d %s", 176964edff94SMatt Jacob ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_lun, 177064edff94SMatt Jacob ct->ct_status, ct->ct_flags, resid, 177164edff94SMatt Jacob sentstatus? "FIN" : "MID"); 177264edff94SMatt Jacob tval = ct->ct_fwhandle; 17735d571944SMatt Jacob } 1774a1bc34c6SMatt Jacob ccb->csio.resid += resid; 1775a1bc34c6SMatt Jacob 1776a1bc34c6SMatt Jacob /* 1777a1bc34c6SMatt Jacob * We're here either because intermediate data transfers are done 1778a1bc34c6SMatt Jacob * and/or the final status CTIO (which may have joined with a 1779a1bc34c6SMatt Jacob * Data Transfer) is done. 1780d81ba9d5SMatt Jacob * 1781d81ba9d5SMatt Jacob * In any case, for this platform, the upper layers figure out 1782d81ba9d5SMatt Jacob * what to do next, so all we do here is collect status and 1783a1bc34c6SMatt Jacob * pass information along. Any DMA handles have already been 1784a1bc34c6SMatt Jacob * freed. 1785d81ba9d5SMatt Jacob */ 1786f48ce188SMatt Jacob if (notify_cam == 0) { 178764edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, " INTER CTIO[0x%x] done", tval); 1788f48ce188SMatt Jacob return (0); 1789f48ce188SMatt Jacob } 1790d81ba9d5SMatt Jacob 179153036e92SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO[0x%x] done", 179253036e92SMatt Jacob (sentstatus)? " FINAL " : "MIDTERM ", tval); 1793a1bc34c6SMatt Jacob 1794a1bc34c6SMatt Jacob if (!ok) { 1795a1bc34c6SMatt Jacob isp_target_putback_atio(ccb); 1796d81ba9d5SMatt Jacob } else { 1797a1bc34c6SMatt Jacob isp_complete_ctio(ccb); 1798a1bc34c6SMatt Jacob 1799d81ba9d5SMatt Jacob } 1800a1bc34c6SMatt Jacob return (0); 1801d81ba9d5SMatt Jacob } 1802570c7a3fSMatt Jacob 1803570c7a3fSMatt Jacob static int 1804570c7a3fSMatt Jacob isp_handle_platform_notify_scsi(struct ispsoftc *isp, in_entry_t *inp) 1805570c7a3fSMatt Jacob { 1806570c7a3fSMatt Jacob return (0); /* XXXX */ 1807570c7a3fSMatt Jacob } 1808570c7a3fSMatt Jacob 1809570c7a3fSMatt Jacob static int 1810570c7a3fSMatt Jacob isp_handle_platform_notify_fc(struct ispsoftc *isp, in_fcentry_t *inp) 1811570c7a3fSMatt Jacob { 1812570c7a3fSMatt Jacob 1813570c7a3fSMatt Jacob switch (inp->in_status) { 1814570c7a3fSMatt Jacob case IN_PORT_LOGOUT: 1815570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, "port logout of iid %d", 1816570c7a3fSMatt Jacob inp->in_iid); 1817570c7a3fSMatt Jacob break; 1818570c7a3fSMatt Jacob case IN_PORT_CHANGED: 1819570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, "port changed for iid %d", 1820570c7a3fSMatt Jacob inp->in_iid); 1821570c7a3fSMatt Jacob break; 1822570c7a3fSMatt Jacob case IN_GLOBAL_LOGO: 1823570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGINFO, "all ports logged out"); 1824570c7a3fSMatt Jacob break; 1825570c7a3fSMatt Jacob case IN_ABORT_TASK: 1826570c7a3fSMatt Jacob { 1827570c7a3fSMatt Jacob atio_private_data_t *atp = isp_get_atpd(isp, inp->in_seqid); 1828570c7a3fSMatt Jacob struct ccb_immed_notify *inot = NULL; 1829570c7a3fSMatt Jacob 1830570c7a3fSMatt Jacob if (atp) { 1831570c7a3fSMatt Jacob tstate_t *tptr = get_lun_statep(isp, 0, atp->lun); 1832570c7a3fSMatt Jacob if (tptr) { 1833570c7a3fSMatt Jacob inot = (struct ccb_immed_notify *) 1834570c7a3fSMatt Jacob SLIST_FIRST(&tptr->inots); 1835570c7a3fSMatt Jacob if (inot) { 1836746e9c85SMatt Jacob tptr->inot_count--; 1837570c7a3fSMatt Jacob SLIST_REMOVE_HEAD(&tptr->inots, 1838570c7a3fSMatt Jacob sim_links.sle); 1839746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1840746e9c85SMatt Jacob "Take FREE INOT count now %d", 1841746e9c85SMatt Jacob tptr->inot_count); 1842570c7a3fSMatt Jacob } 1843570c7a3fSMatt Jacob } 1844570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, 1845570c7a3fSMatt Jacob "abort task RX_ID %x IID %d state %d", 1846570c7a3fSMatt Jacob inp->in_seqid, inp->in_iid, atp->state); 1847570c7a3fSMatt Jacob } else { 1848570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, 1849570c7a3fSMatt Jacob "abort task RX_ID %x from iid %d, state unknown", 1850570c7a3fSMatt Jacob inp->in_seqid, inp->in_iid); 1851570c7a3fSMatt Jacob } 1852570c7a3fSMatt Jacob if (inot) { 1853570c7a3fSMatt Jacob inot->initiator_id = inp->in_iid; 1854570c7a3fSMatt Jacob inot->sense_len = 0; 1855570c7a3fSMatt Jacob inot->message_args[0] = MSG_ABORT_TAG; 1856570c7a3fSMatt Jacob inot->message_args[1] = inp->in_seqid & 0xff; 1857570c7a3fSMatt Jacob inot->message_args[2] = (inp->in_seqid >> 8) & 0xff; 1858570c7a3fSMatt Jacob inot->ccb_h.status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN; 1859570c7a3fSMatt Jacob xpt_done((union ccb *)inot); 1860570c7a3fSMatt Jacob } 1861570c7a3fSMatt Jacob break; 1862570c7a3fSMatt Jacob } 1863570c7a3fSMatt Jacob default: 1864570c7a3fSMatt Jacob break; 1865570c7a3fSMatt Jacob } 1866570c7a3fSMatt Jacob return (0); 1867570c7a3fSMatt Jacob } 1868d81ba9d5SMatt Jacob #endif 1869d81ba9d5SMatt Jacob 1870478f8a96SJustin T. Gibbs static void 1871cbf57b47SMatt Jacob isp_cam_async(void *cbarg, u_int32_t code, struct cam_path *path, void *arg) 1872478f8a96SJustin T. Gibbs { 1873478f8a96SJustin T. Gibbs struct cam_sim *sim; 1874478f8a96SJustin T. Gibbs struct ispsoftc *isp; 1875478f8a96SJustin T. Gibbs 1876478f8a96SJustin T. Gibbs sim = (struct cam_sim *)cbarg; 1877478f8a96SJustin T. Gibbs isp = (struct ispsoftc *) cam_sim_softc(sim); 1878478f8a96SJustin T. Gibbs switch (code) { 1879478f8a96SJustin T. Gibbs case AC_LOST_DEVICE: 1880ab6c4b31SMatt Jacob if (IS_SCSI(isp)) { 1881478f8a96SJustin T. Gibbs u_int16_t oflags, nflags; 1882478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 1883a1bc34c6SMatt Jacob int tgt; 1884478f8a96SJustin T. Gibbs 1885f9e908dcSMatt Jacob tgt = xpt_path_target_id(path); 188641ed683eSMatt Jacob if (tgt >= 0) { 1887ea6f23cdSMatt Jacob sdp += cam_sim_bus(sim); 188841ed683eSMatt Jacob ISP_LOCK(isp); 18899ce9bdafSMatt Jacob nflags = sdp->isp_devparam[tgt].nvrm_flags; 1890a1bc34c6SMatt Jacob #ifndef ISP_TARGET_MODE 18919ce9bdafSMatt Jacob nflags &= DPARM_SAFE_DFLT; 1892a1bc34c6SMatt Jacob if (isp->isp_loaded_fw) { 1893478f8a96SJustin T. Gibbs nflags |= DPARM_NARROW | DPARM_ASYNC; 1894478f8a96SJustin T. Gibbs } 1895a1bc34c6SMatt Jacob #else 1896a1bc34c6SMatt Jacob nflags = DPARM_DEFAULT; 1897a1bc34c6SMatt Jacob #endif 18989ce9bdafSMatt Jacob oflags = sdp->isp_devparam[tgt].goal_flags; 18999ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_flags = nflags; 1900478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_update = 1; 1901a1bc34c6SMatt Jacob isp->isp_update |= (1 << cam_sim_bus(sim)); 190241ed683eSMatt Jacob (void) isp_control(isp, 190341ed683eSMatt Jacob ISPCTL_UPDATE_PARAMS, NULL); 19049ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_flags = oflags; 1905f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1906478f8a96SJustin T. Gibbs } 190741ed683eSMatt Jacob } 1908478f8a96SJustin T. Gibbs break; 1909478f8a96SJustin T. Gibbs default: 19103c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, "isp_cam_async: Code 0x%x", code); 1911478f8a96SJustin T. Gibbs break; 1912478f8a96SJustin T. Gibbs } 1913478f8a96SJustin T. Gibbs } 1914478f8a96SJustin T. Gibbs 1915478f8a96SJustin T. Gibbs static void 1916c3055363SMatt Jacob isp_poll(struct cam_sim *sim) 1917478f8a96SJustin T. Gibbs { 1918c40e096eSMatt Jacob struct ispsoftc *isp = cam_sim_softc(sim); 1919126ec864SMatt Jacob u_int16_t isr, sema, mbox; 1920126ec864SMatt Jacob 1921c40e096eSMatt Jacob ISP_LOCK(isp); 1922126ec864SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 1923126ec864SMatt Jacob isp_intr(isp, isr, sema, mbox); 1924126ec864SMatt Jacob } 1925c40e096eSMatt Jacob ISP_UNLOCK(isp); 1926478f8a96SJustin T. Gibbs } 1927478f8a96SJustin T. Gibbs 1928ab6c4b31SMatt Jacob 1929478f8a96SJustin T. Gibbs static void 1930b85389e1SMatt Jacob isp_watchdog(void *arg) 1931cc8df88bSMatt Jacob { 1932b09b0095SMatt Jacob XS_T *xs = arg; 1933cc8df88bSMatt Jacob struct ispsoftc *isp = XS_ISP(xs); 1934cc8df88bSMatt Jacob u_int32_t handle; 1935fdeb9f2fSMatt Jacob int iok; 1936b85389e1SMatt Jacob 1937cc8df88bSMatt Jacob /* 1938b85389e1SMatt Jacob * We've decided this command is dead. Make sure we're not trying 1939b85389e1SMatt Jacob * to kill a command that's already dead by getting it's handle and 1940b85389e1SMatt Jacob * and seeing whether it's still alive. 1941cc8df88bSMatt Jacob */ 1942f6e75de2SMatt Jacob ISP_LOCK(isp); 1943fdeb9f2fSMatt Jacob iok = isp->isp_osinfo.intsok; 1944fdeb9f2fSMatt Jacob isp->isp_osinfo.intsok = 0; 1945cc8df88bSMatt Jacob handle = isp_find_handle(isp, xs); 1946cc8df88bSMatt Jacob if (handle) { 1947126ec864SMatt Jacob u_int16_t isr, sema, mbox; 1948126ec864SMatt Jacob 1949b85389e1SMatt Jacob if (XS_CMD_DONE_P(xs)) { 1950b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG1, 1951b09b0095SMatt Jacob "watchdog found done cmd (handle 0x%x)", handle); 1952f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1953b85389e1SMatt Jacob return; 1954b85389e1SMatt Jacob } 1955b85389e1SMatt Jacob 1956b85389e1SMatt Jacob if (XS_CMD_WDOG_P(xs)) { 1957b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1958b09b0095SMatt Jacob "recursive watchdog (handle 0x%x)", handle); 1959f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1960b85389e1SMatt Jacob return; 1961b85389e1SMatt Jacob } 1962b85389e1SMatt Jacob 1963b85389e1SMatt Jacob XS_CMD_S_WDOG(xs); 1964126ec864SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 1965126ec864SMatt Jacob isp_intr(isp, isr, sema, mbox); 1966126ec864SMatt Jacob } 1967126ec864SMatt Jacob if (XS_CMD_DONE_P(xs)) { 1968b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1969126ec864SMatt Jacob "watchdog cleanup for handle 0x%x", handle); 1970b85389e1SMatt Jacob xpt_done((union ccb *) xs); 1971b85389e1SMatt Jacob } else if (XS_CMD_GRACE_P(xs)) { 19721fcf5debSMatt Jacob /* 19731fcf5debSMatt Jacob * Make sure the command is *really* dead before we 19741fcf5debSMatt Jacob * release the handle (and DMA resources) for reuse. 19751fcf5debSMatt Jacob */ 19761fcf5debSMatt Jacob (void) isp_control(isp, ISPCTL_ABORT_CMD, arg); 19771fcf5debSMatt Jacob 19781fcf5debSMatt Jacob /* 19791fcf5debSMatt Jacob * After this point, the comamnd is really dead. 19801fcf5debSMatt Jacob */ 1981f6e75de2SMatt Jacob if (XS_XFRLEN(xs)) { 1982f6e75de2SMatt Jacob ISP_DMAFREE(isp, xs, handle); 1983f6e75de2SMatt Jacob } 1984cc8df88bSMatt Jacob isp_destroy_handle(isp, handle); 1985cc8df88bSMatt Jacob xpt_print_path(xs->ccb_h.path); 19863c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 19872903b272SMatt Jacob "watchdog timeout for handle 0x%x", handle); 1988cc8df88bSMatt Jacob XS_SETERR(xs, CAM_CMD_TIMEOUT); 1989b85389e1SMatt Jacob XS_CMD_C_WDOG(xs); 1990cc8df88bSMatt Jacob isp_done(xs); 1991b85389e1SMatt Jacob } else { 19924fd13c1bSMatt Jacob u_int16_t nxti, optr; 19934fd13c1bSMatt Jacob ispreq_t local, *mp= &local, *qe; 1994b85389e1SMatt Jacob 1995b85389e1SMatt Jacob XS_CMD_C_WDOG(xs); 1996b85389e1SMatt Jacob xs->ccb_h.timeout_ch = timeout(isp_watchdog, xs, hz); 19974fd13c1bSMatt Jacob if (isp_getrqentry(isp, &nxti, &optr, (void **) &qe)) { 1998f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1999b85389e1SMatt Jacob return; 2000b85389e1SMatt Jacob } 2001b85389e1SMatt Jacob XS_CMD_S_GRACE(xs); 2002b85389e1SMatt Jacob MEMZERO((void *) mp, sizeof (*mp)); 2003b85389e1SMatt Jacob mp->req_header.rqs_entry_count = 1; 2004b85389e1SMatt Jacob mp->req_header.rqs_entry_type = RQSTYPE_MARKER; 2005b85389e1SMatt Jacob mp->req_modifier = SYNC_ALL; 2006b85389e1SMatt Jacob mp->req_target = XS_CHANNEL(xs) << 7; 20074fd13c1bSMatt Jacob isp_put_request(isp, mp, qe); 20084fd13c1bSMatt Jacob ISP_ADD_REQUEST(isp, nxti); 2009b85389e1SMatt Jacob } 2010b85389e1SMatt Jacob } else { 2011b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "watchdog with no command"); 2012cc8df88bSMatt Jacob } 2013fdeb9f2fSMatt Jacob isp->isp_osinfo.intsok = iok; 2014f6e75de2SMatt Jacob ISP_UNLOCK(isp); 2015cc8df88bSMatt Jacob } 2016cc8df88bSMatt Jacob 20175d571944SMatt Jacob static void 20185d571944SMatt Jacob isp_kthread(void *arg) 20195d571944SMatt Jacob { 20205d571944SMatt Jacob struct ispsoftc *isp = arg; 20215d571944SMatt Jacob 2022162e9893SMatt Jacob #ifdef ISP_SMPLOCK 20235d571944SMatt Jacob mtx_lock(&isp->isp_lock); 2024ee76282eSMatt Jacob #else 2025ee76282eSMatt Jacob mtx_lock(&Giant); 2026162e9893SMatt Jacob #endif 2027fdeb9f2fSMatt Jacob /* 2028fdeb9f2fSMatt Jacob * The first loop is for our usage where we have yet to have 2029fdeb9f2fSMatt Jacob * gotten good fibre channel state. 2030fdeb9f2fSMatt Jacob */ 20315d571944SMatt Jacob for (;;) { 2032fdeb9f2fSMatt Jacob int wasfrozen; 2033fdeb9f2fSMatt Jacob 2034fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "kthread: checking FC state"); 20355d571944SMatt Jacob while (isp_fc_runstate(isp, 2 * 1000000) != 0) { 2036fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "kthread: FC state ungood"); 2037f44257c2SMatt Jacob if (FCPARAM(isp)->isp_fwstate != FW_READY || 2038f44257c2SMatt Jacob FCPARAM(isp)->isp_loopstate < LOOP_PDB_RCVD) { 2039f44257c2SMatt Jacob if (FCPARAM(isp)->loop_seen_once == 0 || 2040fdeb9f2fSMatt Jacob isp->isp_osinfo.ktmature == 0) { 2041f44257c2SMatt Jacob break; 2042f44257c2SMatt Jacob } 2043f44257c2SMatt Jacob } 2044162e9893SMatt Jacob #ifdef ISP_SMPLOCK 20455d571944SMatt Jacob msleep(isp_kthread, &isp->isp_lock, 20465d571944SMatt Jacob PRIBIO, "isp_fcthrd", hz); 2047162e9893SMatt Jacob #else 2048162e9893SMatt Jacob (void) tsleep(isp_kthread, PRIBIO, "isp_fcthrd", hz); 2049162e9893SMatt Jacob #endif 20505d571944SMatt Jacob } 2051fdeb9f2fSMatt Jacob 2052f44257c2SMatt Jacob /* 2053f44257c2SMatt Jacob * Even if we didn't get good loop state we may be 2054f44257c2SMatt Jacob * unfreezing the SIMQ so that we can kill off 2055fdeb9f2fSMatt Jacob * commands (if we've never seen loop before, for example). 2056f44257c2SMatt Jacob */ 2057fdeb9f2fSMatt Jacob isp->isp_osinfo.ktmature = 1; 20585d571944SMatt Jacob wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN; 20595d571944SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN; 20605d571944SMatt Jacob if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) { 2061fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "kthread: releasing simq"); 20625d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 20635d571944SMatt Jacob xpt_release_simq(isp->isp_sim, 1); 20645d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 20655d571944SMatt Jacob } 2066fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "kthread: waiting until called"); 2067162e9893SMatt Jacob #ifdef ISP_SMPLOCK 20685d571944SMatt Jacob cv_wait(&isp->isp_osinfo.kthread_cv, &isp->isp_lock); 2069162e9893SMatt Jacob #else 2070162e9893SMatt Jacob (void) tsleep(&isp->isp_osinfo.kthread_cv, PRIBIO, "fc_cv", 0); 2071162e9893SMatt Jacob #endif 20725d571944SMatt Jacob } 20735d571944SMatt Jacob } 20745d571944SMatt Jacob 2075cc8df88bSMatt Jacob static void 2076c3055363SMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb) 2077478f8a96SJustin T. Gibbs { 2078f6e75de2SMatt Jacob int bus, tgt, error; 2079478f8a96SJustin T. Gibbs struct ispsoftc *isp; 20804663e367SJustin T. Gibbs struct ccb_trans_settings *cts; 2081478f8a96SJustin T. Gibbs 2082478f8a96SJustin T. Gibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n")); 2083478f8a96SJustin T. Gibbs 2084478f8a96SJustin T. Gibbs isp = (struct ispsoftc *)cam_sim_softc(sim); 2085478f8a96SJustin T. Gibbs ccb->ccb_h.sim_priv.entries[0].field = 0; 2086478f8a96SJustin T. Gibbs ccb->ccb_h.sim_priv.entries[1].ptr = isp; 20870470d791SMatt Jacob if (isp->isp_state != ISP_RUNSTATE && 20880470d791SMatt Jacob ccb->ccb_h.func_code == XPT_SCSI_IO) { 20895d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 209057c801f5SMatt Jacob isp_init(isp); 209157c801f5SMatt Jacob if (isp->isp_state != ISP_INITSTATE) { 2092f6e75de2SMatt Jacob ISP_UNLOCK(isp); 209357c801f5SMatt Jacob /* 209457c801f5SMatt Jacob * Lie. Say it was a selection timeout. 209557c801f5SMatt Jacob */ 2096b85389e1SMatt Jacob ccb->ccb_h.status = CAM_SEL_TIMEOUT | CAM_DEV_QFRZN; 20970470d791SMatt Jacob xpt_freeze_devq(ccb->ccb_h.path, 1); 209857c801f5SMatt Jacob xpt_done(ccb); 209957c801f5SMatt Jacob return; 210057c801f5SMatt Jacob } 210157c801f5SMatt Jacob isp->isp_state = ISP_RUNSTATE; 21025d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 210357c801f5SMatt Jacob } 2104b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "isp_action code %x", ccb->ccb_h.func_code); 2105478f8a96SJustin T. Gibbs 21065d571944SMatt Jacob 2107478f8a96SJustin T. Gibbs switch (ccb->ccb_h.func_code) { 2108478f8a96SJustin T. Gibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 2109478f8a96SJustin T. Gibbs /* 2110478f8a96SJustin T. Gibbs * Do a couple of preliminary checks... 2111478f8a96SJustin T. Gibbs */ 2112478f8a96SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { 2113478f8a96SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) { 2114478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2115478f8a96SJustin T. Gibbs xpt_done(ccb); 2116478f8a96SJustin T. Gibbs break; 2117478f8a96SJustin T. Gibbs } 2118478f8a96SJustin T. Gibbs } 21190470d791SMatt Jacob #ifdef DIAGNOSTIC 21200470d791SMatt Jacob if (ccb->ccb_h.target_id > (ISP_MAX_TARGETS(isp) - 1)) { 2121478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 21220470d791SMatt Jacob } else if (ccb->ccb_h.target_lun > (ISP_MAX_LUNS(isp) - 1)) { 2123478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 2124478f8a96SJustin T. Gibbs } 2125478f8a96SJustin T. Gibbs if (ccb->ccb_h.status == CAM_PATH_INVALID) { 2126bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 2127bfbab170SMatt Jacob "invalid tgt/lun (%d.%d) in XPT_SCSI_IO", 2128bfbab170SMatt Jacob ccb->ccb_h.target_id, ccb->ccb_h.target_lun); 2129478f8a96SJustin T. Gibbs xpt_done(ccb); 2130478f8a96SJustin T. Gibbs break; 2131478f8a96SJustin T. Gibbs } 21320470d791SMatt Jacob #endif 21330470d791SMatt Jacob ((struct ccb_scsiio *) ccb)->scsi_status = SCSI_STATUS_OK; 21345d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2135b09b0095SMatt Jacob error = isp_start((XS_T *) ccb); 21360470d791SMatt Jacob switch (error) { 2137478f8a96SJustin T. Gibbs case CMD_QUEUED: 2138478f8a96SJustin T. Gibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 2139cc8df88bSMatt Jacob if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { 2140d69a5f7dSMatt Jacob u_int64_t ticks = (u_int64_t) hz; 2141cc8df88bSMatt Jacob if (ccb->ccb_h.timeout == CAM_TIME_DEFAULT) 2142d69a5f7dSMatt Jacob ticks = 60 * 1000 * ticks; 2143b85389e1SMatt Jacob else 2144b85389e1SMatt Jacob ticks = ccb->ccb_h.timeout * hz; 2145b85389e1SMatt Jacob ticks = ((ticks + 999) / 1000) + hz + hz; 2146d69a5f7dSMatt Jacob if (ticks >= 0x80000000) { 2147d69a5f7dSMatt Jacob isp_prt(isp, ISP_LOGERR, 2148d69a5f7dSMatt Jacob "timeout overflow"); 2149fdeb9f2fSMatt Jacob ticks = 0x7fffffff; 2150d69a5f7dSMatt Jacob } 2151d69a5f7dSMatt Jacob ccb->ccb_h.timeout_ch = timeout(isp_watchdog, 2152d69a5f7dSMatt Jacob (caddr_t)ccb, (int)ticks); 2153b85389e1SMatt Jacob } else { 2154b85389e1SMatt Jacob callout_handle_init(&ccb->ccb_h.timeout_ch); 2155cc8df88bSMatt Jacob } 21565d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2157478f8a96SJustin T. Gibbs break; 21580470d791SMatt Jacob case CMD_RQLATER: 2159f44257c2SMatt Jacob /* 2160f44257c2SMatt Jacob * This can only happen for Fibre Channel 2161f44257c2SMatt Jacob */ 2162f44257c2SMatt Jacob KASSERT((IS_FC(isp)), ("CMD_RQLATER for FC only")); 2163fdeb9f2fSMatt Jacob if (FCPARAM(isp)->loop_seen_once == 0 && 2164fdeb9f2fSMatt Jacob isp->isp_osinfo.ktmature) { 2165f44257c2SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2166f44257c2SMatt Jacob XS_SETERR(ccb, CAM_SEL_TIMEOUT); 2167f44257c2SMatt Jacob xpt_done(ccb); 2168f44257c2SMatt Jacob break; 2169f44257c2SMatt Jacob } 2170162e9893SMatt Jacob #ifdef ISP_SMPLOCK 21715d571944SMatt Jacob cv_signal(&isp->isp_osinfo.kthread_cv); 2172162e9893SMatt Jacob #else 2173162e9893SMatt Jacob wakeup(&isp->isp_osinfo.kthread_cv); 2174162e9893SMatt Jacob #endif 2175fdeb9f2fSMatt Jacob isp_freeze_loopdown(isp, "isp_action(RQLATER)"); 2176b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 2177fdeb9f2fSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2178478f8a96SJustin T. Gibbs xpt_done(ccb); 2179478f8a96SJustin T. Gibbs break; 21800470d791SMatt Jacob case CMD_EAGAIN: 2181b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 21825d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2183478f8a96SJustin T. Gibbs xpt_done(ccb); 2184478f8a96SJustin T. Gibbs break; 21850470d791SMatt Jacob case CMD_COMPLETE: 21860470d791SMatt Jacob isp_done((struct ccb_scsiio *) ccb); 21875d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 21880470d791SMatt Jacob break; 21890470d791SMatt Jacob default: 2190bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 2191bfbab170SMatt Jacob "What's this? 0x%x at %d in file %s", 219291f1caa2SMatt Jacob error, __LINE__, __FILE__); 2193b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQ_CMP_ERR); 21940470d791SMatt Jacob xpt_done(ccb); 21955d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2196478f8a96SJustin T. Gibbs } 2197478f8a96SJustin T. Gibbs break; 2198478f8a96SJustin T. Gibbs 2199d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2200478f8a96SJustin T. Gibbs case XPT_EN_LUN: /* Enable LUN as a target */ 220164edff94SMatt Jacob { 220267ff51f1SMatt Jacob int seq, iok, i; 22035d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 220464edff94SMatt Jacob iok = isp->isp_osinfo.intsok; 220564edff94SMatt Jacob isp->isp_osinfo.intsok = 0; 220667ff51f1SMatt Jacob seq = isp_en_lun(isp, ccb); 220767ff51f1SMatt Jacob if (seq < 0) { 220864edff94SMatt Jacob isp->isp_osinfo.intsok = iok; 22095d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2210478f8a96SJustin T. Gibbs xpt_done(ccb); 2211478f8a96SJustin T. Gibbs break; 221264edff94SMatt Jacob } 221367ff51f1SMatt Jacob for (i = 0; isp->isp_osinfo.leact[seq] && i < 30 * 1000; i++) { 221467ff51f1SMatt Jacob u_int16_t isr, sema, mbox; 221567ff51f1SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 221667ff51f1SMatt Jacob isp_intr(isp, isr, sema, mbox); 221767ff51f1SMatt Jacob } 221867ff51f1SMatt Jacob DELAY(1000); 221967ff51f1SMatt Jacob } 222067ff51f1SMatt Jacob isp->isp_osinfo.intsok = iok; 222167ff51f1SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 222267ff51f1SMatt Jacob break; 222367ff51f1SMatt Jacob } 2224d81ba9d5SMatt Jacob case XPT_NOTIFY_ACK: /* recycle notify ack */ 2225d81ba9d5SMatt Jacob case XPT_IMMED_NOTIFY: /* Add Immediate Notify Resource */ 2226d81ba9d5SMatt Jacob case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */ 2227d81ba9d5SMatt Jacob { 2228a1bc34c6SMatt Jacob tstate_t *tptr = 2229a1bc34c6SMatt Jacob get_lun_statep(isp, XS_CHANNEL(ccb), ccb->ccb_h.target_lun); 2230d81ba9d5SMatt Jacob if (tptr == NULL) { 2231d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 2232d81ba9d5SMatt Jacob xpt_done(ccb); 2233d81ba9d5SMatt Jacob break; 2234d81ba9d5SMatt Jacob } 2235f48ce188SMatt Jacob ccb->ccb_h.sim_priv.entries[0].field = 0; 2236f48ce188SMatt Jacob ccb->ccb_h.sim_priv.entries[1].ptr = isp; 2237570c7a3fSMatt Jacob ccb->ccb_h.flags = 0; 2238570c7a3fSMatt Jacob 22395d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2240d81ba9d5SMatt Jacob if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 2241570c7a3fSMatt Jacob /* 2242570c7a3fSMatt Jacob * Note that the command itself may not be done- 2243570c7a3fSMatt Jacob * it may not even have had the first CTIO sent. 2244570c7a3fSMatt Jacob */ 2245570c7a3fSMatt Jacob tptr->atio_count++; 2246570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 2247746e9c85SMatt Jacob "Put FREE ATIO, lun %d, count now %d", 2248570c7a3fSMatt Jacob ccb->ccb_h.target_lun, tptr->atio_count); 2249570c7a3fSMatt Jacob SLIST_INSERT_HEAD(&tptr->atios, &ccb->ccb_h, 2250570c7a3fSMatt Jacob sim_links.sle); 2251570c7a3fSMatt Jacob } else if (ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) { 2252746e9c85SMatt Jacob tptr->inot_count++; 2253746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 2254746e9c85SMatt Jacob "Put FREE INOT, lun %d, count now %d", 2255746e9c85SMatt Jacob ccb->ccb_h.target_lun, tptr->inot_count); 2256d81ba9d5SMatt Jacob SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, 2257d81ba9d5SMatt Jacob sim_links.sle); 2258570c7a3fSMatt Jacob } else { 2259746e9c85SMatt Jacob isp_prt(isp, ISP_LOGWARN, "Got Notify ACK");; 2260d81ba9d5SMatt Jacob } 2261d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 2262d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_INPROG; 22635d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2264d81ba9d5SMatt Jacob break; 2265d81ba9d5SMatt Jacob } 2266d81ba9d5SMatt Jacob case XPT_CONT_TARGET_IO: 2267d81ba9d5SMatt Jacob { 22685d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2269d81ba9d5SMatt Jacob ccb->ccb_h.status = isp_target_start_ctio(isp, ccb); 2270d81ba9d5SMatt Jacob if (ccb->ccb_h.status != CAM_REQ_INPROG) { 2271570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, 2272570c7a3fSMatt Jacob "XPT_CONT_TARGET_IO: status 0x%x", 2273570c7a3fSMatt Jacob ccb->ccb_h.status); 2274b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 22755d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2276d81ba9d5SMatt Jacob xpt_done(ccb); 2277d81ba9d5SMatt Jacob } else { 22785d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2279d81ba9d5SMatt Jacob ccb->ccb_h.status |= CAM_SIM_QUEUED; 2280d81ba9d5SMatt Jacob } 2281d81ba9d5SMatt Jacob break; 2282d81ba9d5SMatt Jacob } 2283d81ba9d5SMatt Jacob #endif 2284478f8a96SJustin T. Gibbs case XPT_RESET_DEV: /* BDR the specified SCSI device */ 2285d81ba9d5SMatt Jacob 2286d81ba9d5SMatt Jacob bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path)); 2287d81ba9d5SMatt Jacob tgt = ccb->ccb_h.target_id; 2288d81ba9d5SMatt Jacob tgt |= (bus << 16); 2289d81ba9d5SMatt Jacob 22905d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2291ea6f23cdSMatt Jacob error = isp_control(isp, ISPCTL_RESET_DEV, &tgt); 22925d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2293478f8a96SJustin T. Gibbs if (error) { 2294478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2295478f8a96SJustin T. Gibbs } else { 2296478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2297478f8a96SJustin T. Gibbs } 2298478f8a96SJustin T. Gibbs xpt_done(ccb); 2299478f8a96SJustin T. Gibbs break; 2300478f8a96SJustin T. Gibbs case XPT_ABORT: /* Abort the specified CCB */ 2301d81ba9d5SMatt Jacob { 2302d81ba9d5SMatt Jacob union ccb *accb = ccb->cab.abort_ccb; 23035d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2304d81ba9d5SMatt Jacob switch (accb->ccb_h.func_code) { 2305d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2306d81ba9d5SMatt Jacob case XPT_ACCEPT_TARGET_IO: 2307d81ba9d5SMatt Jacob case XPT_IMMED_NOTIFY: 2308d81ba9d5SMatt Jacob ccb->ccb_h.status = isp_abort_tgt_ccb(isp, ccb); 2309d81ba9d5SMatt Jacob break; 2310d81ba9d5SMatt Jacob case XPT_CONT_TARGET_IO: 2311b09b0095SMatt Jacob isp_prt(isp, ISP_LOGERR, "cannot abort CTIOs yet"); 2312d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_UA_ABORT; 2313d81ba9d5SMatt Jacob break; 2314d81ba9d5SMatt Jacob #endif 2315d81ba9d5SMatt Jacob case XPT_SCSI_IO: 2316478f8a96SJustin T. Gibbs error = isp_control(isp, ISPCTL_ABORT_CMD, ccb); 2317478f8a96SJustin T. Gibbs if (error) { 2318d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_UA_ABORT; 2319478f8a96SJustin T. Gibbs } else { 2320478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2321478f8a96SJustin T. Gibbs } 2322d81ba9d5SMatt Jacob break; 2323d81ba9d5SMatt Jacob default: 2324d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_INVALID; 2325d81ba9d5SMatt Jacob break; 2326d81ba9d5SMatt Jacob } 23275d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2328478f8a96SJustin T. Gibbs xpt_done(ccb); 2329478f8a96SJustin T. Gibbs break; 2330d81ba9d5SMatt Jacob } 2331ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2332ab163f5fSMatt Jacob #define IS_CURRENT_SETTINGS(c) (c->type == CTS_TYPE_CURRENT_SETTINGS) 2333ab163f5fSMatt Jacob #else 2334ab163f5fSMatt Jacob #define IS_CURRENT_SETTINGS(c) (c->flags & CCB_TRANS_CURRENT_SETTINGS) 2335ab163f5fSMatt Jacob #endif 2336478f8a96SJustin T. Gibbs case XPT_SET_TRAN_SETTINGS: /* Nexus Settings */ 2337478f8a96SJustin T. Gibbs cts = &ccb->cts; 23389ce9bdafSMatt Jacob if (!IS_CURRENT_SETTINGS(cts)) { 23399ce9bdafSMatt Jacob ccb->ccb_h.status = CAM_REQ_INVALID; 23409ce9bdafSMatt Jacob xpt_done(ccb); 23419ce9bdafSMatt Jacob break; 23429ce9bdafSMatt Jacob } 2343478f8a96SJustin T. Gibbs tgt = cts->ccb_h.target_id; 23445d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2345ab6c4b31SMatt Jacob if (IS_SCSI(isp)) { 2346ab163f5fSMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2347478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 2348478f8a96SJustin T. Gibbs u_int16_t *dptr; 2349d81ba9d5SMatt Jacob 2350d81ba9d5SMatt Jacob bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 2351478f8a96SJustin T. Gibbs 2352ea6f23cdSMatt Jacob sdp += bus; 2353478f8a96SJustin T. Gibbs /* 23549ce9bdafSMatt Jacob * We always update (internally) from goal_flags 2355478f8a96SJustin T. Gibbs * so any request to change settings just gets 2356478f8a96SJustin T. Gibbs * vectored to that location. 2357478f8a96SJustin T. Gibbs */ 23589ce9bdafSMatt Jacob dptr = &sdp->isp_devparam[tgt].goal_flags; 2359478f8a96SJustin T. Gibbs 2360478f8a96SJustin T. Gibbs /* 2361478f8a96SJustin T. Gibbs * Note that these operations affect the 23629ce9bdafSMatt Jacob * the goal flags (goal_flags)- not 2363478f8a96SJustin T. Gibbs * the current state flags. Then we mark 2364478f8a96SJustin T. Gibbs * things so that the next operation to 2365478f8a96SJustin T. Gibbs * this HBA will cause the update to occur. 2366478f8a96SJustin T. Gibbs */ 2367478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_DISC_VALID) { 2368478f8a96SJustin T. Gibbs if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) { 2369478f8a96SJustin T. Gibbs *dptr |= DPARM_DISC; 2370478f8a96SJustin T. Gibbs } else { 2371478f8a96SJustin T. Gibbs *dptr &= ~DPARM_DISC; 2372478f8a96SJustin T. Gibbs } 2373478f8a96SJustin T. Gibbs } 2374478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_TQ_VALID) { 2375478f8a96SJustin T. Gibbs if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) { 2376478f8a96SJustin T. Gibbs *dptr |= DPARM_TQING; 2377478f8a96SJustin T. Gibbs } else { 2378478f8a96SJustin T. Gibbs *dptr &= ~DPARM_TQING; 2379478f8a96SJustin T. Gibbs } 2380478f8a96SJustin T. Gibbs } 2381478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) { 2382478f8a96SJustin T. Gibbs switch (cts->bus_width) { 2383478f8a96SJustin T. Gibbs case MSG_EXT_WDTR_BUS_16_BIT: 2384478f8a96SJustin T. Gibbs *dptr |= DPARM_WIDE; 2385478f8a96SJustin T. Gibbs break; 2386478f8a96SJustin T. Gibbs default: 2387478f8a96SJustin T. Gibbs *dptr &= ~DPARM_WIDE; 2388478f8a96SJustin T. Gibbs } 2389478f8a96SJustin T. Gibbs } 2390478f8a96SJustin T. Gibbs /* 2391478f8a96SJustin T. Gibbs * Any SYNC RATE of nonzero and SYNC_OFFSET 2392478f8a96SJustin T. Gibbs * of nonzero will cause us to go to the 2393478f8a96SJustin T. Gibbs * selected (from NVRAM) maximum value for 2394478f8a96SJustin T. Gibbs * this device. At a later point, we'll 2395478f8a96SJustin T. Gibbs * allow finer control. 2396478f8a96SJustin T. Gibbs */ 2397478f8a96SJustin T. Gibbs if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) && 2398478f8a96SJustin T. Gibbs (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) && 2399478f8a96SJustin T. Gibbs (cts->sync_offset > 0)) { 2400478f8a96SJustin T. Gibbs *dptr |= DPARM_SYNC; 2401478f8a96SJustin T. Gibbs } else { 2402478f8a96SJustin T. Gibbs *dptr &= ~DPARM_SYNC; 2403478f8a96SJustin T. Gibbs } 2404ab6c4b31SMatt Jacob *dptr |= DPARM_SAFE_DFLT; 2405ab163f5fSMatt Jacob #else 2406ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi = 2407ab163f5fSMatt Jacob &cts->proto_specific.scsi; 2408ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi = 2409ab163f5fSMatt Jacob &cts->xport_specific.spi; 2410ab163f5fSMatt Jacob sdparam *sdp = isp->isp_param; 2411ab163f5fSMatt Jacob u_int16_t *dptr; 2412ab163f5fSMatt Jacob 2413ab163f5fSMatt Jacob bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 2414ab163f5fSMatt Jacob sdp += bus; 2415ab163f5fSMatt Jacob /* 24169ce9bdafSMatt Jacob * We always update (internally) from goal_flags 2417ab163f5fSMatt Jacob * so any request to change settings just gets 2418ab163f5fSMatt Jacob * vectored to that location. 2419ab163f5fSMatt Jacob */ 24209ce9bdafSMatt Jacob dptr = &sdp->isp_devparam[tgt].goal_flags; 2421ab163f5fSMatt Jacob 2422ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_DISC) != 0) { 2423ab163f5fSMatt Jacob if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) 2424ab163f5fSMatt Jacob *dptr |= DPARM_DISC; 2425ab163f5fSMatt Jacob else 2426ab163f5fSMatt Jacob *dptr &= ~DPARM_DISC; 2427ab163f5fSMatt Jacob } 2428ab163f5fSMatt Jacob 2429ab163f5fSMatt Jacob if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 2430ab163f5fSMatt Jacob if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) 2431ab163f5fSMatt Jacob *dptr |= DPARM_TQING; 2432ab163f5fSMatt Jacob else 2433ab163f5fSMatt Jacob *dptr &= ~DPARM_TQING; 2434ab163f5fSMatt Jacob } 2435ab163f5fSMatt Jacob 2436ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 2437ab163f5fSMatt Jacob if (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT) 2438ab163f5fSMatt Jacob *dptr |= DPARM_WIDE; 2439ab163f5fSMatt Jacob else 2440ab163f5fSMatt Jacob *dptr &= ~DPARM_WIDE; 2441ab163f5fSMatt Jacob } 2442ab163f5fSMatt Jacob 2443ab163f5fSMatt Jacob /* 2444ab163f5fSMatt Jacob * XXX: FIX ME 2445ab163f5fSMatt Jacob */ 2446ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) && 24479ce9bdafSMatt Jacob (spi->valid & CTS_SPI_VALID_SYNC_RATE) && 24489ce9bdafSMatt Jacob (spi->sync_period && spi->sync_offset)) { 2449ab163f5fSMatt Jacob *dptr |= DPARM_SYNC; 24509ce9bdafSMatt Jacob /* 24519ce9bdafSMatt Jacob * XXX: CHECK FOR LEGALITY 24529ce9bdafSMatt Jacob */ 24539ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_period = 24549ce9bdafSMatt Jacob spi->sync_period; 24559ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_offset = 24569ce9bdafSMatt Jacob spi->sync_offset; 2457ab163f5fSMatt Jacob } else { 2458ab163f5fSMatt Jacob *dptr &= ~DPARM_SYNC; 2459ab163f5fSMatt Jacob } 2460ab163f5fSMatt Jacob #endif 2461bfbab170SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 24629ce9bdafSMatt Jacob "SET bus %d targ %d to flags %x off %x per %x", 24639ce9bdafSMatt Jacob bus, tgt, sdp->isp_devparam[tgt].goal_flags, 24649ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_offset, 24659ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_period); 2466478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_update = 1; 2467ea6f23cdSMatt Jacob isp->isp_update |= (1 << bus); 2468478f8a96SJustin T. Gibbs } 24695d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2470478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2471478f8a96SJustin T. Gibbs xpt_done(ccb); 2472478f8a96SJustin T. Gibbs break; 2473478f8a96SJustin T. Gibbs case XPT_GET_TRAN_SETTINGS: 2474478f8a96SJustin T. Gibbs cts = &ccb->cts; 2475478f8a96SJustin T. Gibbs tgt = cts->ccb_h.target_id; 2476ab163f5fSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2477ab6c4b31SMatt Jacob if (IS_FC(isp)) { 2478ab163f5fSMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2479478f8a96SJustin T. Gibbs /* 2480478f8a96SJustin T. Gibbs * a lot of normal SCSI things don't make sense. 2481478f8a96SJustin T. Gibbs */ 2482478f8a96SJustin T. Gibbs cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB; 2483478f8a96SJustin T. Gibbs cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2484478f8a96SJustin T. Gibbs /* 2485478f8a96SJustin T. Gibbs * How do you measure the width of a high 2486478f8a96SJustin T. Gibbs * speed serial bus? Well, in bytes. 2487478f8a96SJustin T. Gibbs * 2488478f8a96SJustin T. Gibbs * Offset and period make no sense, though, so we set 2489478f8a96SJustin T. Gibbs * (above) a 'base' transfer speed to be gigabit. 2490478f8a96SJustin T. Gibbs */ 2491478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2492ab163f5fSMatt Jacob #else 2493ab163f5fSMatt Jacob fcparam *fcp = isp->isp_param; 2494ab163f5fSMatt Jacob struct ccb_trans_settings_fc *fc = 2495ab163f5fSMatt Jacob &cts->xport_specific.fc; 2496478f8a96SJustin T. Gibbs 2497ab163f5fSMatt Jacob cts->protocol = PROTO_SCSI; 2498ab163f5fSMatt Jacob cts->protocol_version = SCSI_REV_2; 2499ab163f5fSMatt Jacob cts->transport = XPORT_FC; 2500ab163f5fSMatt Jacob cts->transport_version = 0; 2501ab163f5fSMatt Jacob 2502ab163f5fSMatt Jacob fc->valid = CTS_FC_VALID_SPEED; 250353036e92SMatt Jacob if (fcp->isp_gbspeed == 2) 250453036e92SMatt Jacob fc->bitrate = 200000; 250553036e92SMatt Jacob else 2506ab163f5fSMatt Jacob fc->bitrate = 100000; 2507ab163f5fSMatt Jacob if (tgt > 0 && tgt < MAX_FC_TARG) { 2508ab163f5fSMatt Jacob struct lportdb *lp = &fcp->portdb[tgt]; 2509ab163f5fSMatt Jacob fc->wwnn = lp->node_wwn; 2510ab163f5fSMatt Jacob fc->wwpn = lp->port_wwn; 2511ab163f5fSMatt Jacob fc->port = lp->portid; 2512ab163f5fSMatt Jacob fc->valid |= CTS_FC_VALID_WWNN | 2513ab163f5fSMatt Jacob CTS_FC_VALID_WWPN | CTS_FC_VALID_PORT; 2514ab163f5fSMatt Jacob } 2515ab163f5fSMatt Jacob #endif 2516ab163f5fSMatt Jacob } else { 2517ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2518ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi = 2519ab163f5fSMatt Jacob &cts->proto_specific.scsi; 2520ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi = 2521ab163f5fSMatt Jacob &cts->xport_specific.spi; 2522ab163f5fSMatt Jacob #endif 2523ab163f5fSMatt Jacob sdparam *sdp = isp->isp_param; 2524ab163f5fSMatt Jacob int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 2525ab163f5fSMatt Jacob u_int16_t dval, pval, oval; 2526ab163f5fSMatt Jacob 2527ea6f23cdSMatt Jacob sdp += bus; 2528ab163f5fSMatt Jacob 2529ab163f5fSMatt Jacob if (IS_CURRENT_SETTINGS(cts)) { 253083ae4407SMatt Jacob sdp->isp_devparam[tgt].dev_refresh = 1; 253183ae4407SMatt Jacob isp->isp_update |= (1 << bus); 253283ae4407SMatt Jacob (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, 253383ae4407SMatt Jacob NULL); 25349ce9bdafSMatt Jacob dval = sdp->isp_devparam[tgt].actv_flags; 25359ce9bdafSMatt Jacob oval = sdp->isp_devparam[tgt].actv_offset; 25369ce9bdafSMatt Jacob pval = sdp->isp_devparam[tgt].actv_period; 25374394c92fSMatt Jacob } else { 25389ce9bdafSMatt Jacob dval = sdp->isp_devparam[tgt].nvrm_flags; 25399ce9bdafSMatt Jacob oval = sdp->isp_devparam[tgt].nvrm_offset; 25409ce9bdafSMatt Jacob pval = sdp->isp_devparam[tgt].nvrm_period; 25414394c92fSMatt Jacob } 2542478f8a96SJustin T. Gibbs 2543ab163f5fSMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2544478f8a96SJustin T. Gibbs cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); 2545478f8a96SJustin T. Gibbs 2546478f8a96SJustin T. Gibbs if (dval & DPARM_DISC) { 2547478f8a96SJustin T. Gibbs cts->flags |= CCB_TRANS_DISC_ENB; 2548478f8a96SJustin T. Gibbs } 2549478f8a96SJustin T. Gibbs if (dval & DPARM_TQING) { 2550478f8a96SJustin T. Gibbs cts->flags |= CCB_TRANS_TAG_ENB; 2551478f8a96SJustin T. Gibbs } 2552478f8a96SJustin T. Gibbs if (dval & DPARM_WIDE) { 2553478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2554478f8a96SJustin T. Gibbs } else { 2555478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2556478f8a96SJustin T. Gibbs } 2557478f8a96SJustin T. Gibbs cts->valid = CCB_TRANS_BUS_WIDTH_VALID | 2558478f8a96SJustin T. Gibbs CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2559478f8a96SJustin T. Gibbs 25604394c92fSMatt Jacob if ((dval & DPARM_SYNC) && oval != 0) { 25614394c92fSMatt Jacob cts->sync_period = pval; 25624394c92fSMatt Jacob cts->sync_offset = oval; 2563478f8a96SJustin T. Gibbs cts->valid |= 2564478f8a96SJustin T. Gibbs CCB_TRANS_SYNC_RATE_VALID | 2565478f8a96SJustin T. Gibbs CCB_TRANS_SYNC_OFFSET_VALID; 2566478f8a96SJustin T. Gibbs } 2567ab163f5fSMatt Jacob #else 2568ab163f5fSMatt Jacob cts->protocol = PROTO_SCSI; 2569ab163f5fSMatt Jacob cts->protocol_version = SCSI_REV_2; 2570ab163f5fSMatt Jacob cts->transport = XPORT_SPI; 2571ab163f5fSMatt Jacob cts->transport_version = 2; 2572ab163f5fSMatt Jacob 2573ab163f5fSMatt Jacob scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 2574ab163f5fSMatt Jacob spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 2575ab163f5fSMatt Jacob if (dval & DPARM_DISC) { 2576ab163f5fSMatt Jacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 2577ab163f5fSMatt Jacob } 2578ab163f5fSMatt Jacob if (dval & DPARM_TQING) { 2579ab163f5fSMatt Jacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 2580ab163f5fSMatt Jacob } 25819ce9bdafSMatt Jacob if ((dval & DPARM_SYNC) && oval && pval) { 2582ab163f5fSMatt Jacob spi->sync_offset = oval; 2583ab163f5fSMatt Jacob spi->sync_period = pval; 2584ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 2585ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 2586ab163f5fSMatt Jacob } 2587ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_BUS_WIDTH; 2588ab163f5fSMatt Jacob if (dval & DPARM_WIDE) { 2589ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2590ab163f5fSMatt Jacob } else { 2591ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2592ab163f5fSMatt Jacob } 2593ab163f5fSMatt Jacob if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { 2594ab163f5fSMatt Jacob scsi->valid = CTS_SCSI_VALID_TQ; 2595ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_DISC; 2596ab163f5fSMatt Jacob } else { 2597ab163f5fSMatt Jacob scsi->valid = 0; 2598ab163f5fSMatt Jacob } 2599ab163f5fSMatt Jacob #endif 2600bfbab170SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 26019ce9bdafSMatt Jacob "GET %s bus %d targ %d to flags %x off %x per %x", 26029ce9bdafSMatt Jacob IS_CURRENT_SETTINGS(cts)? "ACTIVE" : "NVRAM", 26039ce9bdafSMatt Jacob bus, tgt, dval, oval, pval); 2604478f8a96SJustin T. Gibbs } 2605ab163f5fSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2606478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2607478f8a96SJustin T. Gibbs xpt_done(ccb); 2608478f8a96SJustin T. Gibbs break; 2609478f8a96SJustin T. Gibbs 2610478f8a96SJustin T. Gibbs case XPT_CALC_GEOMETRY: 2611478f8a96SJustin T. Gibbs { 2612478f8a96SJustin T. Gibbs struct ccb_calc_geometry *ccg; 2613478f8a96SJustin T. Gibbs 2614478f8a96SJustin T. Gibbs ccg = &ccb->ccg; 2615478f8a96SJustin T. Gibbs if (ccg->block_size == 0) { 2616bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 2617bfbab170SMatt Jacob "%d.%d XPT_CALC_GEOMETRY block size 0?", 2618bfbab170SMatt Jacob ccg->ccb_h.target_id, ccg->ccb_h.target_lun); 2619478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2620478f8a96SJustin T. Gibbs xpt_done(ccb); 2621478f8a96SJustin T. Gibbs break; 2622478f8a96SJustin T. Gibbs } 26232813692cSNate Lawson cam_calc_geometry(ccg, /*extended*/1); 2624478f8a96SJustin T. Gibbs xpt_done(ccb); 2625478f8a96SJustin T. Gibbs break; 2626478f8a96SJustin T. Gibbs } 2627478f8a96SJustin T. Gibbs case XPT_RESET_BUS: /* Reset the specified bus */ 2628ab6c4b31SMatt Jacob bus = cam_sim_bus(sim); 26295d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2630ab6c4b31SMatt Jacob error = isp_control(isp, ISPCTL_RESET_BUS, &bus); 26315d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2632478f8a96SJustin T. Gibbs if (error) 2633478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 26342b052931SMatt Jacob else { 2635ea6f23cdSMatt Jacob if (cam_sim_bus(sim) && isp->isp_path2 != NULL) 2636ea6f23cdSMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); 2637ea6f23cdSMatt Jacob else if (isp->isp_path != NULL) 26382b052931SMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path, NULL); 2639478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 26402b052931SMatt Jacob } 2641478f8a96SJustin T. Gibbs xpt_done(ccb); 2642478f8a96SJustin T. Gibbs break; 2643478f8a96SJustin T. Gibbs 2644478f8a96SJustin T. Gibbs case XPT_TERM_IO: /* Terminate the I/O process */ 2645478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2646478f8a96SJustin T. Gibbs xpt_done(ccb); 2647478f8a96SJustin T. Gibbs break; 2648478f8a96SJustin T. Gibbs 2649478f8a96SJustin T. Gibbs case XPT_PATH_INQ: /* Path routing inquiry */ 2650478f8a96SJustin T. Gibbs { 2651478f8a96SJustin T. Gibbs struct ccb_pathinq *cpi = &ccb->cpi; 2652478f8a96SJustin T. Gibbs 2653478f8a96SJustin T. Gibbs cpi->version_num = 1; 2654d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2655a1bc34c6SMatt Jacob cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO; 2656d81ba9d5SMatt Jacob #else 2657478f8a96SJustin T. Gibbs cpi->target_sprt = 0; 2658d81ba9d5SMatt Jacob #endif 2659478f8a96SJustin T. Gibbs cpi->hba_eng_cnt = 0; 26600470d791SMatt Jacob cpi->max_target = ISP_MAX_TARGETS(isp) - 1; 26610470d791SMatt Jacob cpi->max_lun = ISP_MAX_LUNS(isp) - 1; 26620470d791SMatt Jacob cpi->bus_id = cam_sim_bus(sim); 26634394c92fSMatt Jacob if (IS_FC(isp)) { 26644394c92fSMatt Jacob cpi->hba_misc = PIM_NOBUSRESET; 26650470d791SMatt Jacob /* 26660470d791SMatt Jacob * Because our loop ID can shift from time to time, 26670470d791SMatt Jacob * make our initiator ID out of range of our bus. 26680470d791SMatt Jacob */ 26690470d791SMatt Jacob cpi->initiator_id = cpi->max_target + 1; 26700470d791SMatt Jacob 26719deea857SKenneth D. Merry /* 26729deea857SKenneth D. Merry * Set base transfer capabilities for Fibre Channel. 26739deea857SKenneth D. Merry * Technically not correct because we don't know 26749deea857SKenneth D. Merry * what media we're running on top of- but we'll 26759deea857SKenneth D. Merry * look good if we always say 100MB/s. 26769deea857SKenneth D. Merry */ 267753036e92SMatt Jacob if (FCPARAM(isp)->isp_gbspeed == 2) 267853036e92SMatt Jacob cpi->base_transfer_speed = 200000; 267953036e92SMatt Jacob else 26809deea857SKenneth D. Merry cpi->base_transfer_speed = 100000; 26810470d791SMatt Jacob cpi->hba_inquiry = PI_TAG_ABLE; 2682ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2683ab163f5fSMatt Jacob cpi->transport = XPORT_FC; 2684ab163f5fSMatt Jacob cpi->transport_version = 0; /* WHAT'S THIS FOR? */ 2685ab163f5fSMatt Jacob #endif 2686478f8a96SJustin T. Gibbs } else { 2687ea6f23cdSMatt Jacob sdparam *sdp = isp->isp_param; 2688ea6f23cdSMatt Jacob sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path)); 26890470d791SMatt Jacob cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; 26904394c92fSMatt Jacob cpi->hba_misc = 0; 2691ea6f23cdSMatt Jacob cpi->initiator_id = sdp->isp_initiator_id; 26929deea857SKenneth D. Merry cpi->base_transfer_speed = 3300; 2693ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2694ab163f5fSMatt Jacob cpi->transport = XPORT_SPI; 2695ab163f5fSMatt Jacob cpi->transport_version = 2; /* WHAT'S THIS FOR? */ 2696ab163f5fSMatt Jacob #endif 2697478f8a96SJustin T. Gibbs } 2698ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2699ab163f5fSMatt Jacob cpi->protocol = PROTO_SCSI; 2700ab163f5fSMatt Jacob cpi->protocol_version = SCSI_REV_2; 2701ab163f5fSMatt Jacob #endif 2702478f8a96SJustin T. Gibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 2703478f8a96SJustin T. Gibbs strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN); 2704478f8a96SJustin T. Gibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 2705478f8a96SJustin T. Gibbs cpi->unit_number = cam_sim_unit(sim); 2706478f8a96SJustin T. Gibbs cpi->ccb_h.status = CAM_REQ_CMP; 2707478f8a96SJustin T. Gibbs xpt_done(ccb); 2708478f8a96SJustin T. Gibbs break; 2709478f8a96SJustin T. Gibbs } 2710478f8a96SJustin T. Gibbs default: 2711478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2712478f8a96SJustin T. Gibbs xpt_done(ccb); 2713478f8a96SJustin T. Gibbs break; 2714478f8a96SJustin T. Gibbs } 2715478f8a96SJustin T. Gibbs } 2716d3a9eb2eSMatt Jacob 2717d3a9eb2eSMatt Jacob #define ISPDDB (CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB) 2718d3a9eb2eSMatt Jacob void 2719c3055363SMatt Jacob isp_done(struct ccb_scsiio *sccb) 2720d3a9eb2eSMatt Jacob { 2721d3a9eb2eSMatt Jacob struct ispsoftc *isp = XS_ISP(sccb); 2722d3a9eb2eSMatt Jacob 2723d3a9eb2eSMatt Jacob if (XS_NOERR(sccb)) 2724d3a9eb2eSMatt Jacob XS_SETERR(sccb, CAM_REQ_CMP); 2725b85389e1SMatt Jacob 2726d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP && 2727d3a9eb2eSMatt Jacob (sccb->scsi_status != SCSI_STATUS_OK)) { 2728d3a9eb2eSMatt Jacob sccb->ccb_h.status &= ~CAM_STATUS_MASK; 272992a1e549SMatt Jacob if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) && 273092a1e549SMatt Jacob (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) { 273192a1e549SMatt Jacob sccb->ccb_h.status |= CAM_AUTOSENSE_FAIL; 273292a1e549SMatt Jacob } else { 2733d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 2734d3a9eb2eSMatt Jacob } 273592a1e549SMatt Jacob } 2736b85389e1SMatt Jacob 27370470d791SMatt Jacob sccb->ccb_h.status &= ~CAM_SIM_QUEUED; 2738d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2739d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 2740d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_DEV_QFRZN; 27410470d791SMatt Jacob xpt_freeze_devq(sccb->ccb_h.path, 1); 2742fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 2743fdeb9f2fSMatt Jacob "freeze devq %d.%d cam sts %x scsi sts %x", 2744fdeb9f2fSMatt Jacob sccb->ccb_h.target_id, sccb->ccb_h.target_lun, 2745fdeb9f2fSMatt Jacob sccb->ccb_h.status, sccb->scsi_status); 2746d3a9eb2eSMatt Jacob } 2747d3a9eb2eSMatt Jacob } 2748b85389e1SMatt Jacob 2749b85389e1SMatt Jacob if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) && 2750d3a9eb2eSMatt Jacob (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2751d3a9eb2eSMatt Jacob xpt_print_path(sccb->ccb_h.path); 27523c75bb14SMatt Jacob isp_prt(isp, ISP_LOGINFO, 27533c75bb14SMatt Jacob "cam completion status 0x%x", sccb->ccb_h.status); 2754d3a9eb2eSMatt Jacob } 2755b85389e1SMatt Jacob 2756b85389e1SMatt Jacob XS_CMD_S_DONE(sccb); 2757b85389e1SMatt Jacob if (XS_CMD_WDOG_P(sccb) == 0) { 2758b85389e1SMatt Jacob untimeout(isp_watchdog, (caddr_t)sccb, sccb->ccb_h.timeout_ch); 2759b85389e1SMatt Jacob if (XS_CMD_GRACE_P(sccb)) { 2760b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2761b09b0095SMatt Jacob "finished command on borrowed time"); 2762b85389e1SMatt Jacob } 2763b85389e1SMatt Jacob XS_CMD_S_CLEAR(sccb); 27645d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2765d3a9eb2eSMatt Jacob xpt_done((union ccb *) sccb); 27665d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2767d3a9eb2eSMatt Jacob } 2768b85389e1SMatt Jacob } 2769d3a9eb2eSMatt Jacob 2770cbf57b47SMatt Jacob int 27710470d791SMatt Jacob isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg) 2772cbf57b47SMatt Jacob { 2773ea6f23cdSMatt Jacob int bus, rv = 0; 2774cbf57b47SMatt Jacob switch (cmd) { 2775cbf57b47SMatt Jacob case ISPASYNC_NEW_TGT_PARAMS: 27760470d791SMatt Jacob { 2777ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2778ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi; 2779ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi; 2780ab163f5fSMatt Jacob #endif 2781cbf57b47SMatt Jacob int flags, tgt; 2782cbf57b47SMatt Jacob sdparam *sdp = isp->isp_param; 2783ab163f5fSMatt Jacob struct ccb_trans_settings cts; 2784cbf57b47SMatt Jacob struct cam_path *tmppath; 2785cbf57b47SMatt Jacob 2786ab163f5fSMatt Jacob bzero(&cts, sizeof (struct ccb_trans_settings)); 2787ab163f5fSMatt Jacob 2788cbf57b47SMatt Jacob tgt = *((int *)arg); 2789ea6f23cdSMatt Jacob bus = (tgt >> 16) & 0xffff; 2790ea6f23cdSMatt Jacob tgt &= 0xffff; 2791ea6f23cdSMatt Jacob sdp += bus; 279245c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2793cbf57b47SMatt Jacob if (xpt_create_path(&tmppath, NULL, 2794ea6f23cdSMatt Jacob cam_sim_path(bus? isp->isp_sim2 : isp->isp_sim), 2795ea6f23cdSMatt Jacob tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 279645c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2797bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 2798bfbab170SMatt Jacob "isp_async cannot make temp path for %d.%d", 2799bfbab170SMatt Jacob tgt, bus); 2800cbf57b47SMatt Jacob rv = -1; 2801cbf57b47SMatt Jacob break; 2802cbf57b47SMatt Jacob } 280345c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 28049ce9bdafSMatt Jacob flags = sdp->isp_devparam[tgt].actv_flags; 2805ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2806ab163f5fSMatt Jacob cts.type = CTS_TYPE_CURRENT_SETTINGS; 2807ab163f5fSMatt Jacob cts.protocol = PROTO_SCSI; 2808ab163f5fSMatt Jacob cts.transport = XPORT_SPI; 2809ab163f5fSMatt Jacob 2810ab163f5fSMatt Jacob scsi = &cts.proto_specific.scsi; 2811ab163f5fSMatt Jacob spi = &cts.xport_specific.spi; 2812ab163f5fSMatt Jacob 2813ab163f5fSMatt Jacob if (flags & DPARM_TQING) { 2814ab163f5fSMatt Jacob scsi->valid |= CTS_SCSI_VALID_TQ; 2815ab163f5fSMatt Jacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 2816ab163f5fSMatt Jacob spi->flags |= CTS_SPI_FLAGS_TAG_ENB; 2817ab163f5fSMatt Jacob } 2818ab163f5fSMatt Jacob 2819cbf57b47SMatt Jacob if (flags & DPARM_DISC) { 2820ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_DISC; 2821ab163f5fSMatt Jacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 2822ab163f5fSMatt Jacob } 2823ab163f5fSMatt Jacob spi->flags |= CTS_SPI_VALID_BUS_WIDTH; 2824ab163f5fSMatt Jacob if (flags & DPARM_WIDE) { 2825ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2826ab163f5fSMatt Jacob } else { 2827ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2828ab163f5fSMatt Jacob } 2829ab163f5fSMatt Jacob if (flags & DPARM_SYNC) { 2830ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 2831ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 28329ce9bdafSMatt Jacob spi->sync_period = sdp->isp_devparam[tgt].actv_period; 28339ce9bdafSMatt Jacob spi->sync_offset = sdp->isp_devparam[tgt].actv_offset; 2834ab163f5fSMatt Jacob } 2835ab163f5fSMatt Jacob #else 2836ab163f5fSMatt Jacob cts.flags = CCB_TRANS_CURRENT_SETTINGS; 2837ab163f5fSMatt Jacob cts.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2838ab163f5fSMatt Jacob if (flags & DPARM_DISC) { 2839ab163f5fSMatt Jacob cts.flags |= CCB_TRANS_DISC_ENB; 2840cbf57b47SMatt Jacob } 2841cbf57b47SMatt Jacob if (flags & DPARM_TQING) { 2842ab163f5fSMatt Jacob cts.flags |= CCB_TRANS_TAG_ENB; 2843cbf57b47SMatt Jacob } 2844ab163f5fSMatt Jacob cts.valid |= CCB_TRANS_BUS_WIDTH_VALID; 2845ab163f5fSMatt Jacob cts.bus_width = (flags & DPARM_WIDE)? 2846cbf57b47SMatt Jacob MSG_EXT_WDTR_BUS_8_BIT : MSG_EXT_WDTR_BUS_16_BIT; 28479ce9bdafSMatt Jacob cts.sync_period = sdp->isp_devparam[tgt].actv_period; 28489ce9bdafSMatt Jacob cts.sync_offset = sdp->isp_devparam[tgt].actv_offset; 2849cbf57b47SMatt Jacob if (flags & DPARM_SYNC) { 2850ab163f5fSMatt Jacob cts.valid |= 28514394c92fSMatt Jacob CCB_TRANS_SYNC_RATE_VALID | 2852cbf57b47SMatt Jacob CCB_TRANS_SYNC_OFFSET_VALID; 2853cbf57b47SMatt Jacob } 2854ab163f5fSMatt Jacob #endif 2855b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2856b09b0095SMatt Jacob "NEW_TGT_PARAMS bus %d tgt %d period %x offset %x flags %x", 28579ce9bdafSMatt Jacob bus, tgt, sdp->isp_devparam[tgt].actv_period, 28589ce9bdafSMatt Jacob sdp->isp_devparam[tgt].actv_offset, flags); 2859ab163f5fSMatt Jacob xpt_setup_ccb(&cts.ccb_h, tmppath, 1); 28605d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2861ab163f5fSMatt Jacob xpt_async(AC_TRANSFER_NEG, tmppath, &cts); 2862cbf57b47SMatt Jacob xpt_free_path(tmppath); 2863f44257c2SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2864cbf57b47SMatt Jacob break; 28650470d791SMatt Jacob } 286657c801f5SMatt Jacob case ISPASYNC_BUS_RESET: 2867ea6f23cdSMatt Jacob bus = *((int *)arg); 2868b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected", 2869b09b0095SMatt Jacob bus); 2870ea6f23cdSMatt Jacob if (bus > 0 && isp->isp_path2) { 28715d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2872ea6f23cdSMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); 28735d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2874ea6f23cdSMatt Jacob } else if (isp->isp_path) { 28755d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 287657c801f5SMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path, NULL); 28775d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 287857c801f5SMatt Jacob } 287957c801f5SMatt Jacob break; 28805d571944SMatt Jacob case ISPASYNC_LIP: 28815d571944SMatt Jacob if (isp->isp_path) { 2882fdeb9f2fSMatt Jacob isp_freeze_loopdown(isp, "ISPASYNC_LIP"); 28835d571944SMatt Jacob } 28845d571944SMatt Jacob isp_prt(isp, ISP_LOGINFO, "LIP Received"); 28855d571944SMatt Jacob break; 28865d571944SMatt Jacob case ISPASYNC_LOOP_RESET: 28875d571944SMatt Jacob if (isp->isp_path) { 2888fdeb9f2fSMatt Jacob isp_freeze_loopdown(isp, "ISPASYNC_LOOP_RESET"); 28895d571944SMatt Jacob } 28905d571944SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop Reset Received"); 28915d571944SMatt Jacob break; 289257c801f5SMatt Jacob case ISPASYNC_LOOP_DOWN: 289357c801f5SMatt Jacob if (isp->isp_path) { 2894fdeb9f2fSMatt Jacob isp_freeze_loopdown(isp, "ISPASYNC_LOOP_DOWN"); 289557c801f5SMatt Jacob } 2896b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop DOWN"); 289757c801f5SMatt Jacob break; 289857c801f5SMatt Jacob case ISPASYNC_LOOP_UP: 28995d571944SMatt Jacob /* 29005d571944SMatt Jacob * Now we just note that Loop has come up. We don't 29015d571944SMatt Jacob * actually do anything because we're waiting for a 29025d571944SMatt Jacob * Change Notify before activating the FC cleanup 29035d571944SMatt Jacob * thread to look at the state of the loop again. 29045d571944SMatt Jacob */ 2905b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop UP"); 290657c801f5SMatt Jacob break; 2907d6e5500fSMatt Jacob case ISPASYNC_PROMENADE: 29080470d791SMatt Jacob { 2909ab163f5fSMatt Jacob struct cam_path *tmppath; 2910b09b0095SMatt Jacob const char *fmt = "Target %d (Loop 0x%x) Port ID 0x%x " 2911d6e5500fSMatt Jacob "(role %s) %s\n Port WWN 0x%08x%08x\n Node WWN 0x%08x%08x"; 2912d6e5500fSMatt Jacob static const char *roles[4] = { 29130470d791SMatt Jacob "(none)", "Target", "Initiator", "Target/Initiator" 291457c801f5SMatt Jacob }; 291502ab3379SMatt Jacob fcparam *fcp = isp->isp_param; 291602ab3379SMatt Jacob int tgt = *((int *) arg); 2917f44257c2SMatt Jacob int is_tgt_mask = (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT); 291802ab3379SMatt Jacob struct lportdb *lp = &fcp->portdb[tgt]; 291902ab3379SMatt Jacob 2920b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, fmt, tgt, lp->loopid, lp->portid, 2921d6e5500fSMatt Jacob roles[lp->roles & 0x3], 2922d6e5500fSMatt Jacob (lp->valid)? "Arrived" : "Departed", 292302ab3379SMatt Jacob (u_int32_t) (lp->port_wwn >> 32), 292402ab3379SMatt Jacob (u_int32_t) (lp->port_wwn & 0xffffffffLL), 292502ab3379SMatt Jacob (u_int32_t) (lp->node_wwn >> 32), 292602ab3379SMatt Jacob (u_int32_t) (lp->node_wwn & 0xffffffffLL)); 2927ab163f5fSMatt Jacob 292845c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2929ab163f5fSMatt Jacob if (xpt_create_path(&tmppath, NULL, cam_sim_path(isp->isp_sim), 2930ab163f5fSMatt Jacob (target_id_t)tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 293145c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2932ab163f5fSMatt Jacob break; 2933ab163f5fSMatt Jacob } 2934f44257c2SMatt Jacob /* 2935f44257c2SMatt Jacob * Policy: only announce targets. 2936f44257c2SMatt Jacob */ 2937f44257c2SMatt Jacob if (lp->roles & is_tgt_mask) { 2938f44257c2SMatt Jacob if (lp->valid) { 2939ab163f5fSMatt Jacob xpt_async(AC_FOUND_DEVICE, tmppath, NULL); 2940ab163f5fSMatt Jacob } else { 2941ab163f5fSMatt Jacob xpt_async(AC_LOST_DEVICE, tmppath, NULL); 2942ab163f5fSMatt Jacob } 2943f44257c2SMatt Jacob } 2944ab163f5fSMatt Jacob xpt_free_path(tmppath); 2945f44257c2SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 29464394c92fSMatt Jacob break; 29474394c92fSMatt Jacob } 294857c801f5SMatt Jacob case ISPASYNC_CHANGE_NOTIFY: 2949f44257c2SMatt Jacob if (arg == ISPASYNC_CHANGE_PDB) { 29504b9d588eSMatt Jacob isp_prt(isp, ISP_LOGINFO, 2951f44257c2SMatt Jacob "Port Database Changed"); 2952f44257c2SMatt Jacob } else if (arg == ISPASYNC_CHANGE_SNS) { 29534b9d588eSMatt Jacob isp_prt(isp, ISP_LOGINFO, 29544b9d588eSMatt Jacob "Name Server Database Changed"); 29554b9d588eSMatt Jacob } 2956162e9893SMatt Jacob #ifdef ISP_SMPLOCK 29575d571944SMatt Jacob cv_signal(&isp->isp_osinfo.kthread_cv); 2958162e9893SMatt Jacob #else 2959162e9893SMatt Jacob wakeup(&isp->isp_osinfo.kthread_cv); 2960162e9893SMatt Jacob #endif 296157c801f5SMatt Jacob break; 296202ab3379SMatt Jacob case ISPASYNC_FABRIC_DEV: 296302ab3379SMatt Jacob { 2964029f13c6SMatt Jacob int target, base, lim; 296502ab3379SMatt Jacob fcparam *fcp = isp->isp_param; 2966029f13c6SMatt Jacob struct lportdb *lp = NULL; 2967029f13c6SMatt Jacob struct lportdb *clp = (struct lportdb *) arg; 2968029f13c6SMatt Jacob char *pt; 296902ab3379SMatt Jacob 2970029f13c6SMatt Jacob switch (clp->port_type) { 297140cfc8feSMatt Jacob case 1: 297240cfc8feSMatt Jacob pt = " N_Port"; 297340cfc8feSMatt Jacob break; 297440cfc8feSMatt Jacob case 2: 297540cfc8feSMatt Jacob pt = " NL_Port"; 297640cfc8feSMatt Jacob break; 297740cfc8feSMatt Jacob case 3: 297840cfc8feSMatt Jacob pt = "F/NL_Port"; 297940cfc8feSMatt Jacob break; 298040cfc8feSMatt Jacob case 0x7f: 298140cfc8feSMatt Jacob pt = " Nx_Port"; 298240cfc8feSMatt Jacob break; 298340cfc8feSMatt Jacob case 0x81: 298440cfc8feSMatt Jacob pt = " F_port"; 298540cfc8feSMatt Jacob break; 298640cfc8feSMatt Jacob case 0x82: 298740cfc8feSMatt Jacob pt = " FL_Port"; 298840cfc8feSMatt Jacob break; 298940cfc8feSMatt Jacob case 0x84: 299040cfc8feSMatt Jacob pt = " E_port"; 299140cfc8feSMatt Jacob break; 299240cfc8feSMatt Jacob default: 2993029f13c6SMatt Jacob pt = " "; 299440cfc8feSMatt Jacob break; 299540cfc8feSMatt Jacob } 2996029f13c6SMatt Jacob 2997b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, 2998029f13c6SMatt Jacob "%s Fabric Device @ PortID 0x%x", pt, clp->portid); 2999029f13c6SMatt Jacob 300070d2ccceSMatt Jacob /* 3001029f13c6SMatt Jacob * If we don't have an initiator role we bail. 3002029f13c6SMatt Jacob * 3003029f13c6SMatt Jacob * We just use ISPASYNC_FABRIC_DEV for announcement purposes. 300470d2ccceSMatt Jacob */ 3005029f13c6SMatt Jacob 3006029f13c6SMatt Jacob if ((isp->isp_role & ISP_ROLE_INITIATOR) == 0) { 300702ab3379SMatt Jacob break; 300802ab3379SMatt Jacob } 3009029f13c6SMatt Jacob 3010029f13c6SMatt Jacob /* 3011029f13c6SMatt Jacob * Is this entry for us? If so, we bail. 3012029f13c6SMatt Jacob */ 3013029f13c6SMatt Jacob 3014029f13c6SMatt Jacob if (fcp->isp_portid == clp->portid) { 3015029f13c6SMatt Jacob break; 3016029f13c6SMatt Jacob } 3017029f13c6SMatt Jacob 3018029f13c6SMatt Jacob /* 3019029f13c6SMatt Jacob * Else, the default policy is to find room for it in 3020029f13c6SMatt Jacob * our local port database. Later, when we execute 3021029f13c6SMatt Jacob * the call to isp_pdb_sync either this newly arrived 3022029f13c6SMatt Jacob * or already logged in device will be (re)announced. 3023029f13c6SMatt Jacob */ 3024029f13c6SMatt Jacob 3025029f13c6SMatt Jacob if (fcp->isp_topo == TOPO_FL_PORT) 3026029f13c6SMatt Jacob base = FC_SNS_ID+1; 302770d2ccceSMatt Jacob else 3028029f13c6SMatt Jacob base = 0; 3029029f13c6SMatt Jacob 3030029f13c6SMatt Jacob if (fcp->isp_topo == TOPO_N_PORT) 3031029f13c6SMatt Jacob lim = 1; 3032029f13c6SMatt Jacob else 3033029f13c6SMatt Jacob lim = MAX_FC_TARG; 3034029f13c6SMatt Jacob 303570d2ccceSMatt Jacob /* 303670d2ccceSMatt Jacob * Is it already in our list? 303770d2ccceSMatt Jacob */ 3038029f13c6SMatt Jacob for (target = base; target < lim; target++) { 303970d2ccceSMatt Jacob if (target >= FL_PORT_ID && target <= FC_SNS_ID) { 304070d2ccceSMatt Jacob continue; 304170d2ccceSMatt Jacob } 304270d2ccceSMatt Jacob lp = &fcp->portdb[target]; 3043029f13c6SMatt Jacob if (lp->port_wwn == clp->port_wwn && 3044029f13c6SMatt Jacob lp->node_wwn == clp->node_wwn) { 304570d2ccceSMatt Jacob lp->fabric_dev = 1; 304670d2ccceSMatt Jacob break; 304770d2ccceSMatt Jacob } 304870d2ccceSMatt Jacob } 3049029f13c6SMatt Jacob if (target < lim) { 305002ab3379SMatt Jacob break; 305102ab3379SMatt Jacob } 3052029f13c6SMatt Jacob for (target = base; target < lim; target++) { 305370d2ccceSMatt Jacob if (target >= FL_PORT_ID && target <= FC_SNS_ID) { 305470d2ccceSMatt Jacob continue; 305570d2ccceSMatt Jacob } 305602ab3379SMatt Jacob lp = &fcp->portdb[target]; 305770d2ccceSMatt Jacob if (lp->port_wwn == 0) { 305802ab3379SMatt Jacob break; 305902ab3379SMatt Jacob } 306070d2ccceSMatt Jacob } 3061029f13c6SMatt Jacob if (target == lim) { 3062bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 3063029f13c6SMatt Jacob "out of space for fabric devices"); 306402ab3379SMatt Jacob break; 306502ab3379SMatt Jacob } 3066029f13c6SMatt Jacob lp->port_type = clp->port_type; 3067029f13c6SMatt Jacob lp->fc4_type = clp->fc4_type; 3068029f13c6SMatt Jacob lp->node_wwn = clp->node_wwn; 3069029f13c6SMatt Jacob lp->port_wwn = clp->port_wwn; 3070029f13c6SMatt Jacob lp->portid = clp->portid; 307170d2ccceSMatt Jacob lp->fabric_dev = 1; 307202ab3379SMatt Jacob break; 307302ab3379SMatt Jacob } 3074d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 3075e5265237SMatt Jacob case ISPASYNC_TARGET_NOTIFY: 3076d81ba9d5SMatt Jacob { 3077e5265237SMatt Jacob tmd_notify_t *nt = arg; 307864edff94SMatt Jacob isp_prt(isp, ISP_LOGALL, 3079e5265237SMatt Jacob "target notify code 0x%x", nt->nt_ncode); 3080d81ba9d5SMatt Jacob break; 3081d81ba9d5SMatt Jacob } 3082d81ba9d5SMatt Jacob case ISPASYNC_TARGET_ACTION: 3083d81ba9d5SMatt Jacob switch (((isphdr_t *)arg)->rqs_entry_type) { 3084cbf57b47SMatt Jacob default: 3085bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 3086bfbab170SMatt Jacob "event 0x%x for unhandled target action", 3087bfbab170SMatt Jacob ((isphdr_t *)arg)->rqs_entry_type); 3088d81ba9d5SMatt Jacob break; 3089570c7a3fSMatt Jacob case RQSTYPE_NOTIFY: 3090570c7a3fSMatt Jacob if (IS_SCSI(isp)) { 3091570c7a3fSMatt Jacob rv = isp_handle_platform_notify_scsi(isp, 3092570c7a3fSMatt Jacob (in_entry_t *) arg); 3093570c7a3fSMatt Jacob } else { 3094570c7a3fSMatt Jacob rv = isp_handle_platform_notify_fc(isp, 3095570c7a3fSMatt Jacob (in_fcentry_t *) arg); 3096570c7a3fSMatt Jacob } 3097570c7a3fSMatt Jacob break; 3098d81ba9d5SMatt Jacob case RQSTYPE_ATIO: 3099d81ba9d5SMatt Jacob rv = isp_handle_platform_atio(isp, (at_entry_t *) arg); 3100d81ba9d5SMatt Jacob break; 3101d81ba9d5SMatt Jacob case RQSTYPE_ATIO2: 3102d81ba9d5SMatt Jacob rv = isp_handle_platform_atio2(isp, (at2_entry_t *)arg); 3103d81ba9d5SMatt Jacob break; 3104d81ba9d5SMatt Jacob case RQSTYPE_CTIO2: 3105d81ba9d5SMatt Jacob case RQSTYPE_CTIO: 3106d81ba9d5SMatt Jacob rv = isp_handle_platform_ctio(isp, arg); 3107d81ba9d5SMatt Jacob break; 3108d81ba9d5SMatt Jacob case RQSTYPE_ENABLE_LUN: 3109d81ba9d5SMatt Jacob case RQSTYPE_MODIFY_LUN: 311067ff51f1SMatt Jacob isp_ledone(isp, (lun_entry_t *) arg); 3111d81ba9d5SMatt Jacob break; 3112d81ba9d5SMatt Jacob } 3113d81ba9d5SMatt Jacob break; 3114d81ba9d5SMatt Jacob #endif 3115ab163f5fSMatt Jacob case ISPASYNC_FW_CRASH: 3116ab163f5fSMatt Jacob { 3117ab163f5fSMatt Jacob u_int16_t mbox1, mbox6; 3118ab163f5fSMatt Jacob mbox1 = ISP_READ(isp, OUTMAILBOX1); 3119ab163f5fSMatt Jacob if (IS_DUALBUS(isp)) { 3120ab163f5fSMatt Jacob mbox6 = ISP_READ(isp, OUTMAILBOX6); 3121ab163f5fSMatt Jacob } else { 3122ab163f5fSMatt Jacob mbox6 = 0; 3123ab163f5fSMatt Jacob } 3124ab163f5fSMatt Jacob isp_prt(isp, ISP_LOGERR, 3125570c7a3fSMatt Jacob "Internal Firmware Error on bus %d @ RISC Address 0x%x", 3126ab163f5fSMatt Jacob mbox6, mbox1); 31278a5f89b9SMatt Jacob #ifdef ISP_FW_CRASH_DUMP 31288a5f89b9SMatt Jacob /* 31298a5f89b9SMatt Jacob * XXX: really need a thread to do this right. 31308a5f89b9SMatt Jacob */ 31318a5f89b9SMatt Jacob if (IS_FC(isp)) { 31328a5f89b9SMatt Jacob FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; 31338a5f89b9SMatt Jacob FCPARAM(isp)->isp_loopstate = LOOP_NIL; 31348a5f89b9SMatt Jacob isp_freeze_loopdown(isp, "f/w crash"); 31358a5f89b9SMatt Jacob isp_fw_dump(isp); 31368a5f89b9SMatt Jacob } 3137ab163f5fSMatt Jacob isp_reinit(isp); 31388a5f89b9SMatt Jacob isp_async(isp, ISPASYNC_FW_RESTARTED, NULL); 31398a5f89b9SMatt Jacob #endif 3140ab163f5fSMatt Jacob break; 3141ab163f5fSMatt Jacob } 3142be534d5fSMatt Jacob case ISPASYNC_UNHANDLED_RESPONSE: 3143be534d5fSMatt Jacob break; 3144d81ba9d5SMatt Jacob default: 3145b09b0095SMatt Jacob isp_prt(isp, ISP_LOGERR, "unknown isp_async event %d", cmd); 3146cbf57b47SMatt Jacob break; 3147cbf57b47SMatt Jacob } 3148cbf57b47SMatt Jacob return (rv); 3149cbf57b47SMatt Jacob } 3150cbf57b47SMatt Jacob 315192718a7fSMatt Jacob 315292718a7fSMatt Jacob /* 315392718a7fSMatt Jacob * Locks are held before coming here. 315492718a7fSMatt Jacob */ 315592718a7fSMatt Jacob void 315692718a7fSMatt Jacob isp_uninit(struct ispsoftc *isp) 315792718a7fSMatt Jacob { 3158ea6f23cdSMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_RESET); 315992718a7fSMatt Jacob DISABLE_INTS(isp); 316092718a7fSMatt Jacob } 3161b09b0095SMatt Jacob 3162b09b0095SMatt Jacob void 3163b09b0095SMatt Jacob isp_prt(struct ispsoftc *isp, int level, const char *fmt, ...) 3164b09b0095SMatt Jacob { 3165b09b0095SMatt Jacob va_list ap; 3166b09b0095SMatt Jacob if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) { 3167b09b0095SMatt Jacob return; 3168b09b0095SMatt Jacob } 31693c75bb14SMatt Jacob printf("%s: ", device_get_nameunit(isp->isp_dev)); 3170b09b0095SMatt Jacob va_start(ap, fmt); 3171b09b0095SMatt Jacob vprintf(fmt, ap); 3172b09b0095SMatt Jacob va_end(ap); 3173b09b0095SMatt Jacob printf("\n"); 3174b09b0095SMatt Jacob } 3175