1c3aac50fSPeter Wemm /* $FreeBSD$ */ 26054c3f6SMatt Jacob /* 36054c3f6SMatt Jacob * Platform (FreeBSD) dependent common attachment code for Qlogic adapters. 46054c3f6SMatt Jacob * 55f5aafe1SMatt Jacob * Copyright (c) 1997, 1998, 1999, 2000, 2001 by Matthew Jacob 66054c3f6SMatt Jacob * 76054c3f6SMatt Jacob * Redistribution and use in source and binary forms, with or without 86054c3f6SMatt Jacob * modification, are permitted provided that the following conditions 96054c3f6SMatt Jacob * are met: 106054c3f6SMatt Jacob * 1. Redistributions of source code must retain the above copyright 116054c3f6SMatt Jacob * notice immediately at the beginning of the file, without modification, 126054c3f6SMatt Jacob * this list of conditions, and the following disclaimer. 13aa57fd6fSMatt Jacob * 2. The name of the author may not be used to endorse or promote products 14aa57fd6fSMatt Jacob * derived from this software without specific prior written permission. 156054c3f6SMatt Jacob * 166054c3f6SMatt Jacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 176054c3f6SMatt Jacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 186054c3f6SMatt Jacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 196054c3f6SMatt Jacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 206054c3f6SMatt Jacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 216054c3f6SMatt Jacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 226054c3f6SMatt Jacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 236054c3f6SMatt Jacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 246054c3f6SMatt Jacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 256054c3f6SMatt Jacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 266054c3f6SMatt Jacob * SUCH DAMAGE. 276054c3f6SMatt Jacob */ 286054c3f6SMatt Jacob #include <dev/isp/isp_freebsd.h> 295d571944SMatt Jacob #include <sys/unistd.h> 305d571944SMatt Jacob #include <sys/kthread.h> 313ea883b4SMatt Jacob #include <machine/stdarg.h> /* for use by isp_prt below */ 325d571944SMatt Jacob #include <sys/conf.h> 335d571944SMatt Jacob #include <sys/ioccom.h> 345d571944SMatt Jacob #include <dev/isp/isp_ioctl.h> 356054c3f6SMatt Jacob 36a1bc34c6SMatt Jacob 375d571944SMatt Jacob static d_ioctl_t ispioctl; 38f6e75de2SMatt Jacob static void isp_intr_enable(void *); 390470d791SMatt Jacob static void isp_cam_async(void *, u_int32_t, struct cam_path *, void *); 400470d791SMatt Jacob static void isp_poll(struct cam_sim *); 415d571944SMatt Jacob #if 0 420470d791SMatt Jacob static void isp_relsim(void *); 435d571944SMatt Jacob #endif 44b85389e1SMatt Jacob static timeout_t isp_watchdog; 455d571944SMatt Jacob static void isp_kthread(void *); 46d81ba9d5SMatt Jacob static void isp_action(struct cam_sim *, union ccb *); 470470d791SMatt Jacob 48cc8df88bSMatt Jacob 495d571944SMatt Jacob #define ISP_CDEV_MAJOR 248 505d571944SMatt Jacob static struct cdevsw isp_cdevsw = { 515d571944SMatt Jacob /* open */ nullopen, 525d571944SMatt Jacob /* close */ nullclose, 535d571944SMatt Jacob /* read */ noread, 545d571944SMatt Jacob /* write */ nowrite, 555d571944SMatt Jacob /* ioctl */ ispioctl, 565d571944SMatt Jacob /* poll */ nopoll, 575d571944SMatt Jacob /* mmap */ nommap, 585d571944SMatt Jacob /* strategy */ nostrategy, 595d571944SMatt Jacob /* name */ "isp", 605d571944SMatt Jacob /* maj */ ISP_CDEV_MAJOR, 615d571944SMatt Jacob /* dump */ nodump, 625d571944SMatt Jacob /* psize */ nopsize, 635d571944SMatt Jacob /* flags */ D_TAPE, 645d571944SMatt Jacob }; 655d571944SMatt Jacob 66d81ba9d5SMatt Jacob static struct ispsoftc *isplist = NULL; 67478f8a96SJustin T. Gibbs 68478f8a96SJustin T. Gibbs void 69c3055363SMatt Jacob isp_attach(struct ispsoftc *isp) 70478f8a96SJustin T. Gibbs { 71ea6f23cdSMatt Jacob int primary, secondary; 72478f8a96SJustin T. Gibbs struct ccb_setasync csa; 73478f8a96SJustin T. Gibbs struct cam_devq *devq; 74ea6f23cdSMatt Jacob struct cam_sim *sim; 75ea6f23cdSMatt Jacob struct cam_path *path; 76478f8a96SJustin T. Gibbs 77478f8a96SJustin T. Gibbs /* 78ea6f23cdSMatt Jacob * Establish (in case of 12X0) which bus is the primary. 79ea6f23cdSMatt Jacob */ 80ea6f23cdSMatt Jacob 81ea6f23cdSMatt Jacob primary = 0; 82ea6f23cdSMatt Jacob secondary = 1; 83ea6f23cdSMatt Jacob 84ea6f23cdSMatt Jacob /* 85ea6f23cdSMatt Jacob * Create the device queue for our SIM(s). 86478f8a96SJustin T. Gibbs */ 87ab6c4b31SMatt Jacob devq = cam_simq_alloc(isp->isp_maxcmds); 88478f8a96SJustin T. Gibbs if (devq == NULL) { 89478f8a96SJustin T. Gibbs return; 90478f8a96SJustin T. Gibbs } 91478f8a96SJustin T. Gibbs 92478f8a96SJustin T. Gibbs /* 93ea6f23cdSMatt Jacob * Construct our SIM entry. 94478f8a96SJustin T. Gibbs */ 9545c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 96ea6f23cdSMatt Jacob sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp, 973c75bb14SMatt Jacob device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq); 98ea6f23cdSMatt Jacob if (sim == NULL) { 99478f8a96SJustin T. Gibbs cam_simq_free(devq); 10045c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 101478f8a96SJustin T. Gibbs return; 102478f8a96SJustin T. Gibbs } 10345c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 104f6e75de2SMatt Jacob 105f6e75de2SMatt Jacob isp->isp_osinfo.ehook.ich_func = isp_intr_enable; 106f6e75de2SMatt Jacob isp->isp_osinfo.ehook.ich_arg = isp; 10745c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 108f6e75de2SMatt Jacob if (config_intrhook_establish(&isp->isp_osinfo.ehook) != 0) { 10945c9a36aSMatt Jacob cam_sim_free(sim, TRUE); 11045c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 111bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 112bfbab170SMatt Jacob "could not establish interrupt enable hook"); 113f6e75de2SMatt Jacob return; 114f6e75de2SMatt Jacob } 115f6e75de2SMatt Jacob 116ea6f23cdSMatt Jacob if (xpt_bus_register(sim, primary) != CAM_SUCCESS) { 117ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 11845c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 119478f8a96SJustin T. Gibbs return; 120478f8a96SJustin T. Gibbs } 121478f8a96SJustin T. Gibbs 122ea6f23cdSMatt Jacob if (xpt_create_path(&path, NULL, cam_sim_path(sim), 123478f8a96SJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 124ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 125ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 1265d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 12745c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 128478f8a96SJustin T. Gibbs return; 129478f8a96SJustin T. Gibbs } 130478f8a96SJustin T. Gibbs 131ea6f23cdSMatt Jacob xpt_setup_ccb(&csa.ccb_h, path, 5); 132478f8a96SJustin T. Gibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 133478f8a96SJustin T. Gibbs csa.event_enable = AC_LOST_DEVICE; 134cbf57b47SMatt Jacob csa.callback = isp_cam_async; 135ea6f23cdSMatt Jacob csa.callback_arg = sim; 136478f8a96SJustin T. Gibbs xpt_action((union ccb *)&csa); 13745c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 138ea6f23cdSMatt Jacob isp->isp_sim = sim; 139ea6f23cdSMatt Jacob isp->isp_path = path; 1405d571944SMatt Jacob /* 1415d571944SMatt Jacob * Create a kernel thread for fibre channel instances. We 1425d571944SMatt Jacob * don't have dual channel FC cards. 1435d571944SMatt Jacob */ 1445d571944SMatt Jacob if (IS_FC(isp)) { 14545c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 14645c9a36aSMatt Jacob /* XXX: LOCK VIOLATION */ 1475d571944SMatt Jacob cv_init(&isp->isp_osinfo.kthread_cv, "isp_kthread_cv"); 1485d571944SMatt Jacob if (kthread_create(isp_kthread, isp, &isp->isp_osinfo.kproc, 1495d571944SMatt Jacob RFHIGHPID, "%s: fc_thrd", 1505d571944SMatt Jacob device_get_nameunit(isp->isp_dev))) { 1515d571944SMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 1525d571944SMatt Jacob cam_sim_free(sim, TRUE); 1535d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 15445c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 15545c9a36aSMatt Jacob isp_prt(isp, ISP_LOGERR, "could not create kthread"); 1565d571944SMatt Jacob return; 1575d571944SMatt Jacob } 1588e6a12fcSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 1595d571944SMatt Jacob } 1605d571944SMatt Jacob 161478f8a96SJustin T. Gibbs 162ea6f23cdSMatt Jacob /* 163ea6f23cdSMatt Jacob * If we have a second channel, construct SIM entry for that. 164ea6f23cdSMatt Jacob */ 16522e1dc85SMatt Jacob if (IS_DUALBUS(isp)) { 16645c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 167ea6f23cdSMatt Jacob sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp, 1683c75bb14SMatt Jacob device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq); 169ea6f23cdSMatt Jacob if (sim == NULL) { 170ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 171ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 172ea6f23cdSMatt Jacob cam_simq_free(devq); 1735d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 174ea6f23cdSMatt Jacob return; 175ea6f23cdSMatt Jacob } 176ea6f23cdSMatt Jacob if (xpt_bus_register(sim, secondary) != CAM_SUCCESS) { 177ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 178ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 179ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 1805d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 18145c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 182ea6f23cdSMatt Jacob return; 183ea6f23cdSMatt Jacob } 184ea6f23cdSMatt Jacob 185ea6f23cdSMatt Jacob if (xpt_create_path(&path, NULL, cam_sim_path(sim), 186ea6f23cdSMatt Jacob CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 187ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 188ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 189ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 190ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 1915d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 19245c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 193ea6f23cdSMatt Jacob return; 194ea6f23cdSMatt Jacob } 195ea6f23cdSMatt Jacob 196ea6f23cdSMatt Jacob xpt_setup_ccb(&csa.ccb_h, path, 5); 197ea6f23cdSMatt Jacob csa.ccb_h.func_code = XPT_SASYNC_CB; 198ea6f23cdSMatt Jacob csa.event_enable = AC_LOST_DEVICE; 199ea6f23cdSMatt Jacob csa.callback = isp_cam_async; 200ea6f23cdSMatt Jacob csa.callback_arg = sim; 201ea6f23cdSMatt Jacob xpt_action((union ccb *)&csa); 20245c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 203ea6f23cdSMatt Jacob isp->isp_sim2 = sim; 204ea6f23cdSMatt Jacob isp->isp_path2 = path; 205ea6f23cdSMatt Jacob } 2065d571944SMatt Jacob 20764edff94SMatt Jacob #ifdef ISP_TARGET_MODE 20864edff94SMatt Jacob cv_init(&isp->isp_osinfo.tgtcv0[0], "isp_tgcv0a"); 20964edff94SMatt Jacob cv_init(&isp->isp_osinfo.tgtcv0[1], "isp_tgcv0b"); 21064edff94SMatt Jacob cv_init(&isp->isp_osinfo.tgtcv1[0], "isp_tgcv1a"); 21164edff94SMatt Jacob cv_init(&isp->isp_osinfo.tgtcv1[1], "isp_tgcv1b"); 21264edff94SMatt Jacob #endif 2135d571944SMatt Jacob /* 2145d571944SMatt Jacob * Create device nodes 2155d571944SMatt Jacob */ 2165d571944SMatt Jacob (void) make_dev(&isp_cdevsw, device_get_unit(isp->isp_dev), UID_ROOT, 2175d571944SMatt Jacob GID_OPERATOR, 0600, "%s", device_get_nameunit(isp->isp_dev)); 2185d571944SMatt Jacob 219d6e5500fSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE) { 220478f8a96SJustin T. Gibbs isp->isp_state = ISP_RUNSTATE; 221b85389e1SMatt Jacob ENABLE_INTS(isp); 222d6e5500fSMatt Jacob } 223d81ba9d5SMatt Jacob if (isplist == NULL) { 224d81ba9d5SMatt Jacob isplist = isp; 225d81ba9d5SMatt Jacob } else { 226d81ba9d5SMatt Jacob struct ispsoftc *tmp = isplist; 227d81ba9d5SMatt Jacob while (tmp->isp_osinfo.next) { 228d81ba9d5SMatt Jacob tmp = tmp->isp_osinfo.next; 229d81ba9d5SMatt Jacob } 230d81ba9d5SMatt Jacob tmp->isp_osinfo.next = isp; 231478f8a96SJustin T. Gibbs } 2325d571944SMatt Jacob 2335d571944SMatt Jacob } 2345d571944SMatt Jacob 2355d571944SMatt Jacob static int 236b40ce416SJulian Elischer ispioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 2375d571944SMatt Jacob { 2385d571944SMatt Jacob struct ispsoftc *isp; 2395d571944SMatt Jacob int retval = ENOTTY; 2405d571944SMatt Jacob 2415d571944SMatt Jacob isp = isplist; 2425d571944SMatt Jacob while (isp) { 2435d571944SMatt Jacob if (minor(dev) == device_get_unit(isp->isp_dev)) { 2445d571944SMatt Jacob break; 2455d571944SMatt Jacob } 2465d571944SMatt Jacob isp = isp->isp_osinfo.next; 2475d571944SMatt Jacob } 2485d571944SMatt Jacob if (isp == NULL) 2495d571944SMatt Jacob return (ENXIO); 2505d571944SMatt Jacob 2515d571944SMatt Jacob switch (cmd) { 252d134aa0bSMatt Jacob #ifdef ISP_FW_CRASH_DUMP 253d134aa0bSMatt Jacob case ISP_GET_FW_CRASH_DUMP: 254d134aa0bSMatt Jacob { 255d134aa0bSMatt Jacob u_int16_t *ptr = FCPARAM(isp)->isp_dump_data; 256d134aa0bSMatt Jacob size_t sz; 257d134aa0bSMatt Jacob 258d134aa0bSMatt Jacob retval = 0; 259d134aa0bSMatt Jacob if (IS_2200(isp)) 260d134aa0bSMatt Jacob sz = QLA2200_RISC_IMAGE_DUMP_SIZE; 261d134aa0bSMatt Jacob else 262d134aa0bSMatt Jacob sz = QLA2300_RISC_IMAGE_DUMP_SIZE; 263d134aa0bSMatt Jacob ISP_LOCK(isp); 264d134aa0bSMatt Jacob if (ptr && *ptr) { 265d134aa0bSMatt Jacob void *uaddr = *((void **) addr); 266d134aa0bSMatt Jacob if (copyout(ptr, uaddr, sz)) { 267d134aa0bSMatt Jacob retval = EFAULT; 268d134aa0bSMatt Jacob } else { 269d134aa0bSMatt Jacob *ptr = 0; 270d134aa0bSMatt Jacob } 271d134aa0bSMatt Jacob } else { 272d134aa0bSMatt Jacob retval = ENXIO; 273d134aa0bSMatt Jacob } 274d134aa0bSMatt Jacob ISP_UNLOCK(isp); 275d134aa0bSMatt Jacob break; 276d134aa0bSMatt Jacob } 277d134aa0bSMatt Jacob 278d134aa0bSMatt Jacob case ISP_FORCE_CRASH_DUMP: 279d134aa0bSMatt Jacob ISP_LOCK(isp); 280d134aa0bSMatt Jacob if ((isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN) == 0) { 281d134aa0bSMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; 282d134aa0bSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 283d134aa0bSMatt Jacob xpt_freeze_simq(isp->isp_sim, 1); 284d134aa0bSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 285d134aa0bSMatt Jacob } 286d134aa0bSMatt Jacob isp_fw_dump(isp); 287d134aa0bSMatt Jacob isp_reinit(isp); 288d134aa0bSMatt Jacob ISP_UNLOCK(isp); 289d134aa0bSMatt Jacob retval = 0; 290d134aa0bSMatt Jacob break; 291d134aa0bSMatt Jacob #endif 2925d571944SMatt Jacob case ISP_SDBLEV: 2935d571944SMatt Jacob { 2945d571944SMatt Jacob int olddblev = isp->isp_dblev; 2955d571944SMatt Jacob isp->isp_dblev = *(int *)addr; 2965d571944SMatt Jacob *(int *)addr = olddblev; 2975d571944SMatt Jacob retval = 0; 2985d571944SMatt Jacob break; 2995d571944SMatt Jacob } 3005d571944SMatt Jacob case ISP_RESETHBA: 3015d571944SMatt Jacob ISP_LOCK(isp); 3025d571944SMatt Jacob isp_reinit(isp); 3035d571944SMatt Jacob ISP_UNLOCK(isp); 3045d571944SMatt Jacob retval = 0; 3055d571944SMatt Jacob break; 3065d571944SMatt Jacob case ISP_FC_RESCAN: 3075d571944SMatt Jacob if (IS_FC(isp)) { 3085d571944SMatt Jacob ISP_LOCK(isp); 3095d571944SMatt Jacob if (isp_fc_runstate(isp, 5 * 1000000)) { 3105d571944SMatt Jacob retval = EIO; 3115d571944SMatt Jacob } else { 3125d571944SMatt Jacob retval = 0; 3135d571944SMatt Jacob } 3145d571944SMatt Jacob ISP_UNLOCK(isp); 3155d571944SMatt Jacob } 3165d571944SMatt Jacob break; 3175d571944SMatt Jacob case ISP_FC_LIP: 3185d571944SMatt Jacob if (IS_FC(isp)) { 3195d571944SMatt Jacob ISP_LOCK(isp); 3205d571944SMatt Jacob if (isp_control(isp, ISPCTL_SEND_LIP, 0)) { 3215d571944SMatt Jacob retval = EIO; 3225d571944SMatt Jacob } else { 3235d571944SMatt Jacob retval = 0; 3245d571944SMatt Jacob } 3255d571944SMatt Jacob ISP_UNLOCK(isp); 3265d571944SMatt Jacob } 3275d571944SMatt Jacob break; 3285d571944SMatt Jacob case ISP_FC_GETDINFO: 3295d571944SMatt Jacob { 3305d571944SMatt Jacob struct isp_fc_device *ifc = (struct isp_fc_device *) addr; 3315d571944SMatt Jacob struct lportdb *lp; 3325d571944SMatt Jacob 3335d571944SMatt Jacob if (ifc->loopid < 0 || ifc->loopid >= MAX_FC_TARG) { 3345d571944SMatt Jacob retval = EINVAL; 3355d571944SMatt Jacob break; 3365d571944SMatt Jacob } 3375d571944SMatt Jacob ISP_LOCK(isp); 3385d571944SMatt Jacob lp = &FCPARAM(isp)->portdb[ifc->loopid]; 3395d571944SMatt Jacob if (lp->valid) { 3405d571944SMatt Jacob ifc->loopid = lp->loopid; 3415d571944SMatt Jacob ifc->portid = lp->portid; 3425d571944SMatt Jacob ifc->node_wwn = lp->node_wwn; 3435d571944SMatt Jacob ifc->port_wwn = lp->port_wwn; 3445d571944SMatt Jacob retval = 0; 3455d571944SMatt Jacob } else { 3465d571944SMatt Jacob retval = ENODEV; 3475d571944SMatt Jacob } 3485d571944SMatt Jacob ISP_UNLOCK(isp); 3495d571944SMatt Jacob break; 3505d571944SMatt Jacob } 3512903b272SMatt Jacob case ISP_GET_STATS: 3522903b272SMatt Jacob { 3532903b272SMatt Jacob isp_stats_t *sp = (isp_stats_t *) addr; 3542903b272SMatt Jacob 3552903b272SMatt Jacob MEMZERO(sp, sizeof (*sp)); 3562903b272SMatt Jacob sp->isp_stat_version = ISP_STATS_VERSION; 3572903b272SMatt Jacob sp->isp_type = isp->isp_type; 3582903b272SMatt Jacob sp->isp_revision = isp->isp_revision; 3592903b272SMatt Jacob ISP_LOCK(isp); 3602903b272SMatt Jacob sp->isp_stats[ISP_INTCNT] = isp->isp_intcnt; 3612903b272SMatt Jacob sp->isp_stats[ISP_INTBOGUS] = isp->isp_intbogus; 3622903b272SMatt Jacob sp->isp_stats[ISP_INTMBOXC] = isp->isp_intmboxc; 3632903b272SMatt Jacob sp->isp_stats[ISP_INGOASYNC] = isp->isp_intoasync; 3642903b272SMatt Jacob sp->isp_stats[ISP_RSLTCCMPLT] = isp->isp_rsltccmplt; 3652903b272SMatt Jacob sp->isp_stats[ISP_FPHCCMCPLT] = isp->isp_fphccmplt; 3662903b272SMatt Jacob sp->isp_stats[ISP_RSCCHIWAT] = isp->isp_rscchiwater; 3672903b272SMatt Jacob sp->isp_stats[ISP_FPCCHIWAT] = isp->isp_fpcchiwater; 3682903b272SMatt Jacob ISP_UNLOCK(isp); 3692903b272SMatt Jacob retval = 0; 3702903b272SMatt Jacob break; 3712903b272SMatt Jacob } 3722903b272SMatt Jacob case ISP_CLR_STATS: 3732903b272SMatt Jacob ISP_LOCK(isp); 3742903b272SMatt Jacob isp->isp_intcnt = 0; 3752903b272SMatt Jacob isp->isp_intbogus = 0; 3762903b272SMatt Jacob isp->isp_intmboxc = 0; 3772903b272SMatt Jacob isp->isp_intoasync = 0; 3782903b272SMatt Jacob isp->isp_rsltccmplt = 0; 3792903b272SMatt Jacob isp->isp_fphccmplt = 0; 3802903b272SMatt Jacob isp->isp_rscchiwater = 0; 3812903b272SMatt Jacob isp->isp_fpcchiwater = 0; 3822903b272SMatt Jacob ISP_UNLOCK(isp); 3832903b272SMatt Jacob retval = 0; 3842903b272SMatt Jacob break; 3852903b272SMatt Jacob 3865d571944SMatt Jacob default: 3875d571944SMatt Jacob break; 3885d571944SMatt Jacob } 3895d571944SMatt Jacob return (retval); 3900470d791SMatt Jacob } 391478f8a96SJustin T. Gibbs 392f6e75de2SMatt Jacob static void 393f6e75de2SMatt Jacob isp_intr_enable(void *arg) 394f6e75de2SMatt Jacob { 395f6e75de2SMatt Jacob struct ispsoftc *isp = arg; 396d6e5500fSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE) { 397f6e75de2SMatt Jacob ENABLE_INTS(isp); 398f6e75de2SMatt Jacob isp->isp_osinfo.intsok = 1; 399d6e5500fSMatt Jacob } 400f6e75de2SMatt Jacob /* Release our hook so that the boot can continue. */ 401f6e75de2SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 402f6e75de2SMatt Jacob } 403d81ba9d5SMatt Jacob 404d81ba9d5SMatt Jacob /* 405d81ba9d5SMatt Jacob * Put the target mode functions here, because some are inlines 406d81ba9d5SMatt Jacob */ 407d81ba9d5SMatt Jacob 408d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 409d81ba9d5SMatt Jacob 410a1bc34c6SMatt Jacob static __inline int is_lun_enabled(struct ispsoftc *, int, lun_id_t); 411a1bc34c6SMatt Jacob static __inline int are_any_luns_enabled(struct ispsoftc *, int); 412a1bc34c6SMatt Jacob static __inline tstate_t *get_lun_statep(struct ispsoftc *, int, lun_id_t); 413d81ba9d5SMatt Jacob static __inline void rls_lun_statep(struct ispsoftc *, tstate_t *); 41464edff94SMatt Jacob static __inline int isp_psema_sig_rqe(struct ispsoftc *, int); 41564edff94SMatt Jacob static __inline int isp_cv_wait_timed_rqe(struct ispsoftc *, int, int); 41664edff94SMatt Jacob static __inline void isp_cv_signal_rqe(struct ispsoftc *, int, int); 41764edff94SMatt Jacob static __inline void isp_vsema_rqe(struct ispsoftc *, int); 41853036e92SMatt Jacob static __inline atio_private_data_t *isp_get_atpd(struct ispsoftc *, int); 419d81ba9d5SMatt Jacob static cam_status 420a1bc34c6SMatt Jacob create_lun_state(struct ispsoftc *, int, struct cam_path *, tstate_t **); 421d81ba9d5SMatt Jacob static void destroy_lun_state(struct ispsoftc *, tstate_t *); 422d81ba9d5SMatt Jacob static void isp_en_lun(struct ispsoftc *, union ccb *); 423d81ba9d5SMatt Jacob static cam_status isp_abort_tgt_ccb(struct ispsoftc *, union ccb *); 424f48ce188SMatt Jacob static timeout_t isp_refire_putback_atio; 425a1bc34c6SMatt Jacob static void isp_complete_ctio(union ccb *); 426a1bc34c6SMatt Jacob static void isp_target_putback_atio(union ccb *); 427a1bc34c6SMatt Jacob static cam_status isp_target_start_ctio(struct ispsoftc *, union ccb *); 428d81ba9d5SMatt Jacob static int isp_handle_platform_atio(struct ispsoftc *, at_entry_t *); 429d81ba9d5SMatt Jacob static int isp_handle_platform_atio2(struct ispsoftc *, at2_entry_t *); 430d81ba9d5SMatt Jacob static int isp_handle_platform_ctio(struct ispsoftc *, void *); 431d81ba9d5SMatt Jacob 432d81ba9d5SMatt Jacob static __inline int 433a1bc34c6SMatt Jacob is_lun_enabled(struct ispsoftc *isp, int bus, lun_id_t lun) 434d81ba9d5SMatt Jacob { 435d81ba9d5SMatt Jacob tstate_t *tptr; 436a1bc34c6SMatt Jacob tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)]; 437a1bc34c6SMatt Jacob if (tptr == NULL) { 438d81ba9d5SMatt Jacob return (0); 439d81ba9d5SMatt Jacob } 440d81ba9d5SMatt Jacob do { 441a1bc34c6SMatt Jacob if (tptr->lun == (lun_id_t) lun && tptr->bus == bus) { 442d81ba9d5SMatt Jacob return (1); 443d81ba9d5SMatt Jacob } 444d81ba9d5SMatt Jacob } while ((tptr = tptr->next) != NULL); 445d81ba9d5SMatt Jacob return (0); 446d81ba9d5SMatt Jacob } 447d81ba9d5SMatt Jacob 448d81ba9d5SMatt Jacob static __inline int 449a1bc34c6SMatt Jacob are_any_luns_enabled(struct ispsoftc *isp, int port) 450d81ba9d5SMatt Jacob { 451a1bc34c6SMatt Jacob int lo, hi; 452a1bc34c6SMatt Jacob if (IS_DUALBUS(isp)) { 453a1bc34c6SMatt Jacob lo = (port * (LUN_HASH_SIZE >> 1)); 454a1bc34c6SMatt Jacob hi = lo + (LUN_HASH_SIZE >> 1); 455a1bc34c6SMatt Jacob } else { 456a1bc34c6SMatt Jacob lo = 0; 457a1bc34c6SMatt Jacob hi = LUN_HASH_SIZE; 458a1bc34c6SMatt Jacob } 459a1bc34c6SMatt Jacob for (lo = 0; lo < hi; lo++) { 460a1bc34c6SMatt Jacob if (isp->isp_osinfo.lun_hash[lo]) { 461d81ba9d5SMatt Jacob return (1); 462d81ba9d5SMatt Jacob } 463d81ba9d5SMatt Jacob } 464d81ba9d5SMatt Jacob return (0); 465d81ba9d5SMatt Jacob } 466d81ba9d5SMatt Jacob 467d81ba9d5SMatt Jacob static __inline tstate_t * 468a1bc34c6SMatt Jacob get_lun_statep(struct ispsoftc *isp, int bus, lun_id_t lun) 469d81ba9d5SMatt Jacob { 47064edff94SMatt Jacob tstate_t *tptr = NULL; 471d81ba9d5SMatt Jacob 472d81ba9d5SMatt Jacob if (lun == CAM_LUN_WILDCARD) { 47364edff94SMatt Jacob if (isp->isp_osinfo.tmflags[bus] & TM_WILDCARD_ENABLED) { 474a1bc34c6SMatt Jacob tptr = &isp->isp_osinfo.tsdflt[bus]; 475d81ba9d5SMatt Jacob tptr->hold++; 476d81ba9d5SMatt Jacob return (tptr); 477d81ba9d5SMatt Jacob } 478126ec864SMatt Jacob } else { 479126ec864SMatt Jacob tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)]; 48064edff94SMatt Jacob if (tptr == NULL) { 48164edff94SMatt Jacob return (NULL); 48264edff94SMatt Jacob } 483126ec864SMatt Jacob } 484d81ba9d5SMatt Jacob 485d81ba9d5SMatt Jacob do { 486a1bc34c6SMatt Jacob if (tptr->lun == lun && tptr->bus == bus) { 487d81ba9d5SMatt Jacob tptr->hold++; 488d81ba9d5SMatt Jacob return (tptr); 489d81ba9d5SMatt Jacob } 490d81ba9d5SMatt Jacob } while ((tptr = tptr->next) != NULL); 491d81ba9d5SMatt Jacob return (tptr); 492d81ba9d5SMatt Jacob } 493d81ba9d5SMatt Jacob 494d81ba9d5SMatt Jacob static __inline void 495d81ba9d5SMatt Jacob rls_lun_statep(struct ispsoftc *isp, tstate_t *tptr) 496d81ba9d5SMatt Jacob { 497d81ba9d5SMatt Jacob if (tptr->hold) 498d81ba9d5SMatt Jacob tptr->hold--; 499d81ba9d5SMatt Jacob } 500d81ba9d5SMatt Jacob 501d81ba9d5SMatt Jacob static __inline int 50264edff94SMatt Jacob isp_psema_sig_rqe(struct ispsoftc *isp, int bus) 503d81ba9d5SMatt Jacob { 50464edff94SMatt Jacob while (isp->isp_osinfo.tmflags[bus] & TM_BUSY) { 50564edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] |= TM_WANTED; 50664edff94SMatt Jacob if (cv_wait_sig(&isp->isp_osinfo.tgtcv0[bus], &isp->isp_lock)) { 507d81ba9d5SMatt Jacob return (-1); 508d81ba9d5SMatt Jacob } 50964edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] |= TM_BUSY; 510d81ba9d5SMatt Jacob } 511d81ba9d5SMatt Jacob return (0); 512d81ba9d5SMatt Jacob } 513d81ba9d5SMatt Jacob 514d81ba9d5SMatt Jacob static __inline int 51564edff94SMatt Jacob isp_cv_wait_timed_rqe(struct ispsoftc *isp, int bus, int timo) 516d81ba9d5SMatt Jacob { 51764edff94SMatt Jacob if (cv_timedwait(&isp->isp_osinfo.tgtcv1[bus], &isp->isp_lock, timo)) { 518d81ba9d5SMatt Jacob return (-1); 519d81ba9d5SMatt Jacob } 520d81ba9d5SMatt Jacob return (0); 521d81ba9d5SMatt Jacob } 522d81ba9d5SMatt Jacob 523d81ba9d5SMatt Jacob static __inline void 52464edff94SMatt Jacob isp_cv_signal_rqe(struct ispsoftc *isp, int bus, int status) 525d81ba9d5SMatt Jacob { 52664edff94SMatt Jacob isp->isp_osinfo.rstatus[bus] = status; 52764edff94SMatt Jacob cv_signal(&isp->isp_osinfo.tgtcv1[bus]); 528d81ba9d5SMatt Jacob } 529d81ba9d5SMatt Jacob 530d81ba9d5SMatt Jacob static __inline void 53164edff94SMatt Jacob isp_vsema_rqe(struct ispsoftc *isp, int bus) 532d81ba9d5SMatt Jacob { 53364edff94SMatt Jacob if (isp->isp_osinfo.tmflags[bus] & TM_WANTED) { 53464edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_WANTED; 53564edff94SMatt Jacob cv_signal(&isp->isp_osinfo.tgtcv0[bus]); 536d81ba9d5SMatt Jacob } 53764edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_BUSY; 538d81ba9d5SMatt Jacob } 539d81ba9d5SMatt Jacob 54053036e92SMatt Jacob static __inline atio_private_data_t * 54153036e92SMatt Jacob isp_get_atpd(struct ispsoftc *isp, int tag) 54253036e92SMatt Jacob { 54353036e92SMatt Jacob atio_private_data_t *atp; 54453036e92SMatt Jacob for (atp = isp->isp_osinfo.atpdp; 54553036e92SMatt Jacob atp < &isp->isp_osinfo.atpdp[ATPDPSIZE]; atp++) { 54653036e92SMatt Jacob if (atp->tag == tag) 54753036e92SMatt Jacob return (atp); 54853036e92SMatt Jacob } 54953036e92SMatt Jacob return (NULL); 55053036e92SMatt Jacob } 55153036e92SMatt Jacob 552d81ba9d5SMatt Jacob static cam_status 553a1bc34c6SMatt Jacob create_lun_state(struct ispsoftc *isp, int bus, 554a1bc34c6SMatt Jacob struct cam_path *path, tstate_t **rslt) 555d81ba9d5SMatt Jacob { 556d81ba9d5SMatt Jacob cam_status status; 557d81ba9d5SMatt Jacob lun_id_t lun; 558a1bc34c6SMatt Jacob int hfx; 559d81ba9d5SMatt Jacob tstate_t *tptr, *new; 560d81ba9d5SMatt Jacob 561d81ba9d5SMatt Jacob lun = xpt_path_lun_id(path); 562d81ba9d5SMatt Jacob if (lun < 0) { 563d81ba9d5SMatt Jacob return (CAM_LUN_INVALID); 564d81ba9d5SMatt Jacob } 565a1bc34c6SMatt Jacob if (is_lun_enabled(isp, bus, lun)) { 566d81ba9d5SMatt Jacob return (CAM_LUN_ALRDY_ENA); 567d81ba9d5SMatt Jacob } 568ea8b5a9aSDavid Malone new = (tstate_t *) malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO); 569d81ba9d5SMatt Jacob if (new == NULL) { 570d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 571d81ba9d5SMatt Jacob } 572d81ba9d5SMatt Jacob 573d81ba9d5SMatt Jacob status = xpt_create_path(&new->owner, NULL, xpt_path_path_id(path), 574d81ba9d5SMatt Jacob xpt_path_target_id(path), xpt_path_lun_id(path)); 575d81ba9d5SMatt Jacob if (status != CAM_REQ_CMP) { 576d81ba9d5SMatt Jacob free(new, M_DEVBUF); 577d81ba9d5SMatt Jacob return (status); 578d81ba9d5SMatt Jacob } 579a1bc34c6SMatt Jacob new->bus = bus; 580d81ba9d5SMatt Jacob new->lun = lun; 581d81ba9d5SMatt Jacob SLIST_INIT(&new->atios); 582d81ba9d5SMatt Jacob SLIST_INIT(&new->inots); 583d81ba9d5SMatt Jacob new->hold = 1; 584d81ba9d5SMatt Jacob 585a1bc34c6SMatt Jacob hfx = LUN_HASH_FUNC(isp, new->bus, new->lun); 586a1bc34c6SMatt Jacob tptr = isp->isp_osinfo.lun_hash[hfx]; 587a1bc34c6SMatt Jacob if (tptr == NULL) { 588a1bc34c6SMatt Jacob isp->isp_osinfo.lun_hash[hfx] = new; 589d81ba9d5SMatt Jacob } else { 590d81ba9d5SMatt Jacob while (tptr->next) 591d81ba9d5SMatt Jacob tptr = tptr->next; 592d81ba9d5SMatt Jacob tptr->next = new; 593d81ba9d5SMatt Jacob } 594d81ba9d5SMatt Jacob *rslt = new; 595d81ba9d5SMatt Jacob return (CAM_REQ_CMP); 596d81ba9d5SMatt Jacob } 597d81ba9d5SMatt Jacob 598d81ba9d5SMatt Jacob static __inline void 599d81ba9d5SMatt Jacob destroy_lun_state(struct ispsoftc *isp, tstate_t *tptr) 600d81ba9d5SMatt Jacob { 601a1bc34c6SMatt Jacob int hfx; 602d81ba9d5SMatt Jacob tstate_t *lw, *pw; 603d81ba9d5SMatt Jacob 604a1bc34c6SMatt Jacob hfx = LUN_HASH_FUNC(isp, tptr->bus, tptr->lun); 605d81ba9d5SMatt Jacob if (tptr->hold) { 606d81ba9d5SMatt Jacob return; 607d81ba9d5SMatt Jacob } 608a1bc34c6SMatt Jacob pw = isp->isp_osinfo.lun_hash[hfx]; 609d81ba9d5SMatt Jacob if (pw == NULL) { 610d81ba9d5SMatt Jacob return; 611a1bc34c6SMatt Jacob } else if (pw->lun == tptr->lun && pw->bus == tptr->bus) { 612a1bc34c6SMatt Jacob isp->isp_osinfo.lun_hash[hfx] = pw->next; 613d81ba9d5SMatt Jacob } else { 614d81ba9d5SMatt Jacob lw = pw; 615d81ba9d5SMatt Jacob pw = lw->next; 616d81ba9d5SMatt Jacob while (pw) { 617a1bc34c6SMatt Jacob if (pw->lun == tptr->lun && pw->bus == tptr->bus) { 618d81ba9d5SMatt Jacob lw->next = pw->next; 619d81ba9d5SMatt Jacob break; 620d81ba9d5SMatt Jacob } 621d81ba9d5SMatt Jacob lw = pw; 622d81ba9d5SMatt Jacob pw = pw->next; 623d81ba9d5SMatt Jacob } 624d81ba9d5SMatt Jacob if (pw == NULL) { 625d81ba9d5SMatt Jacob return; 626d81ba9d5SMatt Jacob } 627d81ba9d5SMatt Jacob } 628d81ba9d5SMatt Jacob free(tptr, M_DEVBUF); 629d81ba9d5SMatt Jacob } 630d81ba9d5SMatt Jacob 6315d571944SMatt Jacob /* 6325d571944SMatt Jacob * we enter with our locks held. 6335d571944SMatt Jacob */ 634d81ba9d5SMatt Jacob static void 635d81ba9d5SMatt Jacob isp_en_lun(struct ispsoftc *isp, union ccb *ccb) 636d81ba9d5SMatt Jacob { 637a1bc34c6SMatt Jacob const char lfmt[] = "Lun now %sabled for target mode on channel %d"; 638d81ba9d5SMatt Jacob struct ccb_en_lun *cel = &ccb->cel; 639d81ba9d5SMatt Jacob tstate_t *tptr; 640d81ba9d5SMatt Jacob u_int16_t rstat; 64164edff94SMatt Jacob int bus, cmd, av, wildcard; 642d81ba9d5SMatt Jacob lun_id_t lun; 643d81ba9d5SMatt Jacob target_id_t tgt; 644d81ba9d5SMatt Jacob 645d81ba9d5SMatt Jacob 646a1bc34c6SMatt Jacob bus = XS_CHANNEL(ccb) & 0x1; 647d81ba9d5SMatt Jacob tgt = ccb->ccb_h.target_id; 648d81ba9d5SMatt Jacob lun = ccb->ccb_h.target_lun; 649d81ba9d5SMatt Jacob 650d81ba9d5SMatt Jacob /* 651d81ba9d5SMatt Jacob * Do some sanity checking first. 652d81ba9d5SMatt Jacob */ 653d81ba9d5SMatt Jacob 654d6e5500fSMatt Jacob if ((lun != CAM_LUN_WILDCARD) && 655d6e5500fSMatt Jacob (lun < 0 || lun >= (lun_id_t) isp->isp_maxluns)) { 656d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 657d81ba9d5SMatt Jacob return; 658d81ba9d5SMatt Jacob } 65964edff94SMatt Jacob 6602ad50ca5SMatt Jacob if (IS_SCSI(isp)) { 661a1bc34c6SMatt Jacob sdparam *sdp = isp->isp_param; 662a1bc34c6SMatt Jacob sdp += bus; 663d81ba9d5SMatt Jacob if (tgt != CAM_TARGET_WILDCARD && 664a1bc34c6SMatt Jacob tgt != sdp->isp_initiator_id) { 665d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_TID_INVALID; 666d81ba9d5SMatt Jacob return; 667d81ba9d5SMatt Jacob } 668d81ba9d5SMatt Jacob } else { 669d81ba9d5SMatt Jacob if (tgt != CAM_TARGET_WILDCARD && 670d6e5500fSMatt Jacob tgt != FCPARAM(isp)->isp_iid) { 671d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_TID_INVALID; 672d81ba9d5SMatt Jacob return; 673d81ba9d5SMatt Jacob } 67464edff94SMatt Jacob /* 67564edff94SMatt Jacob * This is as a good a place as any to check f/w capabilities. 67664edff94SMatt Jacob */ 67764edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_TMODE) == 0) { 67864edff94SMatt Jacob isp_prt(isp, ISP_LOGERR, 67964edff94SMatt Jacob "firmware does not support target mode"); 68064edff94SMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 68164edff94SMatt Jacob return; 68264edff94SMatt Jacob } 68364edff94SMatt Jacob /* 68464edff94SMatt Jacob * XXX: We *could* handle non-SCCLUN f/w, but we'd have to 68564edff94SMatt Jacob * XXX: dorks with our already fragile enable/disable code. 68664edff94SMatt Jacob */ 68764edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) { 68864edff94SMatt Jacob isp_prt(isp, ISP_LOGERR, 68964edff94SMatt Jacob "firmware not SCCLUN capable"); 69064edff94SMatt Jacob } 691d81ba9d5SMatt Jacob } 692d81ba9d5SMatt Jacob 693d6e5500fSMatt Jacob if (tgt == CAM_TARGET_WILDCARD) { 69464edff94SMatt Jacob if (lun == CAM_LUN_WILDCARD) { 69564edff94SMatt Jacob wildcard = 1; 69664edff94SMatt Jacob } else { 697d6e5500fSMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 698d6e5500fSMatt Jacob return; 699d6e5500fSMatt Jacob } 700126ec864SMatt Jacob } else { 701126ec864SMatt Jacob wildcard = 0; 702126ec864SMatt Jacob } 703b6b6ad2fSMatt Jacob 704b6b6ad2fSMatt Jacob /* 705b6b6ad2fSMatt Jacob * Next check to see whether this is a target/lun wildcard action. 70664edff94SMatt Jacob * 70764edff94SMatt Jacob * If so, we know that we can accept commands for luns that haven't 70864edff94SMatt Jacob * been enabled yet and send them upstream. Otherwise, we have to 70964edff94SMatt Jacob * handle them locally (if we see them at all). 710b6b6ad2fSMatt Jacob */ 711126ec864SMatt Jacob 712126ec864SMatt Jacob if (wildcard) { 713a1bc34c6SMatt Jacob tptr = &isp->isp_osinfo.tsdflt[bus]; 714b6b6ad2fSMatt Jacob if (cel->enable) { 71564edff94SMatt Jacob if (isp->isp_osinfo.tmflags[bus] & 71664edff94SMatt Jacob TM_WILDCARD_ENABLED) { 717b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; 718b6b6ad2fSMatt Jacob return; 719b6b6ad2fSMatt Jacob } 720b6b6ad2fSMatt Jacob ccb->ccb_h.status = 721b6b6ad2fSMatt Jacob xpt_create_path(&tptr->owner, NULL, 722b6b6ad2fSMatt Jacob xpt_path_path_id(ccb->ccb_h.path), 723b6b6ad2fSMatt Jacob xpt_path_target_id(ccb->ccb_h.path), 724b6b6ad2fSMatt Jacob xpt_path_lun_id(ccb->ccb_h.path)); 725b6b6ad2fSMatt Jacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 726b6b6ad2fSMatt Jacob return; 727b6b6ad2fSMatt Jacob } 728b6b6ad2fSMatt Jacob SLIST_INIT(&tptr->atios); 729b6b6ad2fSMatt Jacob SLIST_INIT(&tptr->inots); 73064edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] |= TM_WILDCARD_ENABLED; 731126ec864SMatt Jacob } else { 73264edff94SMatt Jacob if ((isp->isp_osinfo.tmflags[bus] & 73364edff94SMatt Jacob TM_WILDCARD_ENABLED) == 0) { 734126ec864SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 735126ec864SMatt Jacob return; 736126ec864SMatt Jacob } 737126ec864SMatt Jacob if (tptr->hold) { 738126ec864SMatt Jacob ccb->ccb_h.status = CAM_SCSI_BUSY; 739126ec864SMatt Jacob return; 740126ec864SMatt Jacob } 741126ec864SMatt Jacob xpt_free_path(tptr->owner); 74264edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_WILDCARD_ENABLED; 743126ec864SMatt Jacob } 744126ec864SMatt Jacob } 745126ec864SMatt Jacob 746126ec864SMatt Jacob /* 747126ec864SMatt Jacob * Now check to see whether this bus needs to be 748126ec864SMatt Jacob * enabled/disabled with respect to target mode. 749126ec864SMatt Jacob */ 750126ec864SMatt Jacob av = bus << 31; 75164edff94SMatt Jacob if (cel->enable && !(isp->isp_osinfo.tmflags[bus] & TM_TMODE_ENABLED)) { 752a1bc34c6SMatt Jacob av |= ENABLE_TARGET_FLAG; 753b6b6ad2fSMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 754b6b6ad2fSMatt Jacob if (av) { 755b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 756126ec864SMatt Jacob if (wildcard) { 75764edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= 75864edff94SMatt Jacob ~TM_WILDCARD_ENABLED; 759b6b6ad2fSMatt Jacob xpt_free_path(tptr->owner); 7605d571944SMatt Jacob } 761b6b6ad2fSMatt Jacob return; 762b6b6ad2fSMatt Jacob } 76364edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] |= TM_TMODE_ENABLED; 764126ec864SMatt Jacob isp_prt(isp, ISP_LOGINFO, 765126ec864SMatt Jacob "Target Mode enabled on channel %d", bus); 76664edff94SMatt Jacob } else if (cel->enable == 0 && 76764edff94SMatt Jacob (isp->isp_osinfo.tmflags[bus] & TM_TMODE_ENABLED) && wildcard) { 768a1bc34c6SMatt Jacob if (are_any_luns_enabled(isp, bus)) { 769b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_SCSI_BUSY; 770b6b6ad2fSMatt Jacob return; 771b6b6ad2fSMatt Jacob } 772b6b6ad2fSMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 773b6b6ad2fSMatt Jacob if (av) { 774b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 775b6b6ad2fSMatt Jacob return; 776b6b6ad2fSMatt Jacob } 77764edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED; 778126ec864SMatt Jacob isp_prt(isp, ISP_LOGINFO, 779126ec864SMatt Jacob "Target Mode disabled on channel %d", bus); 780126ec864SMatt Jacob } 781126ec864SMatt Jacob 782126ec864SMatt Jacob if (wildcard) { 78364edff94SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 784b6b6ad2fSMatt Jacob return; 785b6b6ad2fSMatt Jacob } 786b6b6ad2fSMatt Jacob 787d81ba9d5SMatt Jacob if (cel->enable) { 788d81ba9d5SMatt Jacob ccb->ccb_h.status = 789a1bc34c6SMatt Jacob create_lun_state(isp, bus, ccb->ccb_h.path, &tptr); 790d81ba9d5SMatt Jacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 791d81ba9d5SMatt Jacob return; 792d81ba9d5SMatt Jacob } 793d81ba9d5SMatt Jacob } else { 794a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, lun); 795d81ba9d5SMatt Jacob if (tptr == NULL) { 796d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 797d81ba9d5SMatt Jacob return; 798d81ba9d5SMatt Jacob } 799d81ba9d5SMatt Jacob } 800d81ba9d5SMatt Jacob 80164edff94SMatt Jacob if (isp_psema_sig_rqe(isp, bus)) { 802d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 803d81ba9d5SMatt Jacob if (cel->enable) 804d81ba9d5SMatt Jacob destroy_lun_state(isp, tptr); 805d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 806d81ba9d5SMatt Jacob return; 807d81ba9d5SMatt Jacob } 808d81ba9d5SMatt Jacob 809d81ba9d5SMatt Jacob if (cel->enable) { 810d81ba9d5SMatt Jacob u_int32_t seq = isp->isp_osinfo.rollinfo++; 8115d571944SMatt Jacob int c, n, ulun = lun; 8125d571944SMatt Jacob 8135d571944SMatt Jacob cmd = RQSTYPE_ENABLE_LUN; 8145d571944SMatt Jacob c = DFLT_CMND_CNT; 8155d571944SMatt Jacob n = DFLT_INOT_CNT; 8165d571944SMatt Jacob if (IS_FC(isp) && lun != 0) { 8175d571944SMatt Jacob cmd = RQSTYPE_MODIFY_LUN; 8185d571944SMatt Jacob n = 0; 8195d571944SMatt Jacob /* 8205d571944SMatt Jacob * For SCC firmware, we only deal with setting 8215d571944SMatt Jacob * (enabling or modifying) lun 0. 8225d571944SMatt Jacob */ 8235d571944SMatt Jacob ulun = 0; 8245d571944SMatt Jacob } 825d81ba9d5SMatt Jacob rstat = LUN_ERR; 8265d571944SMatt Jacob if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq)) { 827d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 8283c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, "isp_lun_cmd failed"); 829d81ba9d5SMatt Jacob goto out; 830d81ba9d5SMatt Jacob } 83164edff94SMatt Jacob if (isp_cv_wait_timed_rqe(isp, bus, 30 * hz)) { 832d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 8333c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, 8345d571944SMatt Jacob "wait for ENABLE/MODIFY LUN timed out"); 835d81ba9d5SMatt Jacob goto out; 836d81ba9d5SMatt Jacob } 83764edff94SMatt Jacob rstat = isp->isp_osinfo.rstatus[bus]; 838d81ba9d5SMatt Jacob if (rstat != LUN_OK) { 839d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 8403c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, 8415d571944SMatt Jacob "ENABLE/MODIFY LUN returned 0x%x", rstat); 842d81ba9d5SMatt Jacob goto out; 843d81ba9d5SMatt Jacob } 844d81ba9d5SMatt Jacob } else { 8455d571944SMatt Jacob int c, n, ulun = lun; 846d81ba9d5SMatt Jacob u_int32_t seq; 847d81ba9d5SMatt Jacob 848d81ba9d5SMatt Jacob rstat = LUN_ERR; 8495d571944SMatt Jacob seq = isp->isp_osinfo.rollinfo++; 8505d571944SMatt Jacob cmd = -RQSTYPE_MODIFY_LUN; 851d81ba9d5SMatt Jacob 8525d571944SMatt Jacob c = DFLT_CMND_CNT; 8535d571944SMatt Jacob n = DFLT_INOT_CNT; 8545d571944SMatt Jacob if (IS_FC(isp) && lun != 0) { 8555d571944SMatt Jacob n = 0; 8565d571944SMatt Jacob /* 8575d571944SMatt Jacob * For SCC firmware, we only deal with setting 8585d571944SMatt Jacob * (enabling or modifying) lun 0. 8595d571944SMatt Jacob */ 8605d571944SMatt Jacob ulun = 0; 8615d571944SMatt Jacob } 8625d571944SMatt Jacob if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq)) { 863d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 8643c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, "isp_lun_cmd failed"); 865d81ba9d5SMatt Jacob goto out; 866d81ba9d5SMatt Jacob } 86764edff94SMatt Jacob if (isp_cv_wait_timed_rqe(isp, bus, 30 * hz)) { 868d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 8693c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, 8703c75bb14SMatt Jacob "wait for MODIFY LUN timed out"); 871d81ba9d5SMatt Jacob goto out; 872d81ba9d5SMatt Jacob } 87364edff94SMatt Jacob rstat = isp->isp_osinfo.rstatus[bus]; 874d81ba9d5SMatt Jacob if (rstat != LUN_OK) { 875d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 8763c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, 8773c75bb14SMatt Jacob "MODIFY LUN returned 0x%x", rstat); 878d81ba9d5SMatt Jacob goto out; 879d81ba9d5SMatt Jacob } 8805d571944SMatt Jacob if (IS_FC(isp) && lun) { 8815d571944SMatt Jacob goto out; 8825d571944SMatt Jacob } 8835d571944SMatt Jacob 884d81ba9d5SMatt Jacob seq = isp->isp_osinfo.rollinfo++; 885d81ba9d5SMatt Jacob 8865d571944SMatt Jacob rstat = LUN_ERR; 8875d571944SMatt Jacob cmd = -RQSTYPE_ENABLE_LUN; 8885d571944SMatt Jacob if (isp_lun_cmd(isp, cmd, bus, tgt, lun, 0, 0, seq)) { 889d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 8903c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, "isp_lun_cmd failed"); 891d81ba9d5SMatt Jacob goto out; 892d81ba9d5SMatt Jacob } 89364edff94SMatt Jacob if (isp_cv_wait_timed_rqe(isp, bus, 30 * hz)) { 894d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 8953c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, 8965d571944SMatt Jacob "wait for DISABLE LUN timed out"); 897d81ba9d5SMatt Jacob goto out; 898d81ba9d5SMatt Jacob } 89964edff94SMatt Jacob rstat = isp->isp_osinfo.rstatus[bus]; 900d81ba9d5SMatt Jacob if (rstat != LUN_OK) { 901d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 9023c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 9035d571944SMatt Jacob "DISABLE LUN returned 0x%x", rstat); 904d81ba9d5SMatt Jacob goto out; 905d81ba9d5SMatt Jacob } 906126ec864SMatt Jacob if (are_any_luns_enabled(isp, bus) == 0) { 907126ec864SMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 908126ec864SMatt Jacob if (av) { 909126ec864SMatt Jacob isp_prt(isp, ISP_LOGWARN, 910126ec864SMatt Jacob "disable target mode on channel %d failed", 911126ec864SMatt Jacob bus); 912126ec864SMatt Jacob goto out; 913d81ba9d5SMatt Jacob } 91464edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED; 915126ec864SMatt Jacob xpt_print_path(ccb->ccb_h.path); 916126ec864SMatt Jacob isp_prt(isp, ISP_LOGINFO, 917126ec864SMatt Jacob "Target Mode disabled on channel %d", bus); 918126ec864SMatt Jacob } 919126ec864SMatt Jacob } 920126ec864SMatt Jacob 921d81ba9d5SMatt Jacob out: 92264edff94SMatt Jacob isp_vsema_rqe(isp, bus); 923d81ba9d5SMatt Jacob 924d81ba9d5SMatt Jacob if (rstat != LUN_OK) { 925d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 9263c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 9273c75bb14SMatt Jacob "lun %sable failed", (cel->enable) ? "en" : "dis"); 928d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 929d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 930d81ba9d5SMatt Jacob if (cel->enable) 931d81ba9d5SMatt Jacob destroy_lun_state(isp, tptr); 932d81ba9d5SMatt Jacob } else { 933d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 934a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGINFO, lfmt, 935a1bc34c6SMatt Jacob (cel->enable) ? "en" : "dis", bus); 936d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 937d81ba9d5SMatt Jacob if (cel->enable == 0) { 938d81ba9d5SMatt Jacob destroy_lun_state(isp, tptr); 939d81ba9d5SMatt Jacob } 940d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 941d81ba9d5SMatt Jacob } 942d81ba9d5SMatt Jacob } 943d81ba9d5SMatt Jacob 944d81ba9d5SMatt Jacob static cam_status 945d81ba9d5SMatt Jacob isp_abort_tgt_ccb(struct ispsoftc *isp, union ccb *ccb) 946d81ba9d5SMatt Jacob { 947d81ba9d5SMatt Jacob tstate_t *tptr; 948d81ba9d5SMatt Jacob struct ccb_hdr_slist *lp; 949d81ba9d5SMatt Jacob struct ccb_hdr *curelm; 950d81ba9d5SMatt Jacob int found; 951d81ba9d5SMatt Jacob union ccb *accb = ccb->cab.abort_ccb; 952d81ba9d5SMatt Jacob 953d81ba9d5SMatt Jacob if (accb->ccb_h.target_id != CAM_TARGET_WILDCARD) { 954d81ba9d5SMatt Jacob if (IS_FC(isp) && (accb->ccb_h.target_id != 955d81ba9d5SMatt Jacob ((fcparam *) isp->isp_param)->isp_loopid)) { 956d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 957d81ba9d5SMatt Jacob } else if (IS_SCSI(isp) && (accb->ccb_h.target_id != 958d81ba9d5SMatt Jacob ((sdparam *) isp->isp_param)->isp_initiator_id)) { 959d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 960d81ba9d5SMatt Jacob } 961d81ba9d5SMatt Jacob } 962a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, XS_CHANNEL(ccb), accb->ccb_h.target_lun); 963d81ba9d5SMatt Jacob if (tptr == NULL) { 964d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 965d81ba9d5SMatt Jacob } 966d81ba9d5SMatt Jacob if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 967d81ba9d5SMatt Jacob lp = &tptr->atios; 968d81ba9d5SMatt Jacob } else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY) { 969d81ba9d5SMatt Jacob lp = &tptr->inots; 970d81ba9d5SMatt Jacob } else { 971d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 972d81ba9d5SMatt Jacob return (CAM_UA_ABORT); 973d81ba9d5SMatt Jacob } 974d81ba9d5SMatt Jacob curelm = SLIST_FIRST(lp); 975d81ba9d5SMatt Jacob found = 0; 976d81ba9d5SMatt Jacob if (curelm == &accb->ccb_h) { 977d81ba9d5SMatt Jacob found = 1; 978d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(lp, sim_links.sle); 979d81ba9d5SMatt Jacob } else { 980d81ba9d5SMatt Jacob while(curelm != NULL) { 981d81ba9d5SMatt Jacob struct ccb_hdr *nextelm; 982d81ba9d5SMatt Jacob 983d81ba9d5SMatt Jacob nextelm = SLIST_NEXT(curelm, sim_links.sle); 984d81ba9d5SMatt Jacob if (nextelm == &accb->ccb_h) { 985d81ba9d5SMatt Jacob found = 1; 986d81ba9d5SMatt Jacob SLIST_NEXT(curelm, sim_links.sle) = 987d81ba9d5SMatt Jacob SLIST_NEXT(nextelm, sim_links.sle); 988d81ba9d5SMatt Jacob break; 989d81ba9d5SMatt Jacob } 990d81ba9d5SMatt Jacob curelm = nextelm; 991d81ba9d5SMatt Jacob } 992d81ba9d5SMatt Jacob } 993d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 994d81ba9d5SMatt Jacob if (found) { 995d81ba9d5SMatt Jacob accb->ccb_h.status = CAM_REQ_ABORTED; 996d81ba9d5SMatt Jacob return (CAM_REQ_CMP); 997d81ba9d5SMatt Jacob } 998d81ba9d5SMatt Jacob return(CAM_PATH_INVALID); 999d81ba9d5SMatt Jacob } 1000d81ba9d5SMatt Jacob 1001d81ba9d5SMatt Jacob static cam_status 1002d81ba9d5SMatt Jacob isp_target_start_ctio(struct ispsoftc *isp, union ccb *ccb) 1003d81ba9d5SMatt Jacob { 1004d81ba9d5SMatt Jacob void *qe; 100500a8e174SMatt Jacob struct ccb_scsiio *cso = &ccb->csio; 10065f5aafe1SMatt Jacob u_int16_t *hp, save_handle; 10074fd13c1bSMatt Jacob u_int16_t nxti, optr; 10084fd13c1bSMatt Jacob u_int8_t local[QENTRY_LEN]; 1009d81ba9d5SMatt Jacob 1010f48ce188SMatt Jacob 10114fd13c1bSMatt Jacob if (isp_getrqentry(isp, &nxti, &optr, &qe)) { 101292a1e549SMatt Jacob xpt_print_path(ccb->ccb_h.path); 101392a1e549SMatt Jacob printf("Request Queue Overflow in isp_target_start_ctio\n"); 1014d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 1015d81ba9d5SMatt Jacob } 10164fd13c1bSMatt Jacob bzero(local, QENTRY_LEN); 1017d81ba9d5SMatt Jacob 1018d81ba9d5SMatt Jacob /* 1019d81ba9d5SMatt Jacob * We're either moving data or completing a command here. 1020d81ba9d5SMatt Jacob */ 1021d81ba9d5SMatt Jacob 1022d81ba9d5SMatt Jacob if (IS_FC(isp)) { 102353036e92SMatt Jacob atio_private_data_t *atp; 10244fd13c1bSMatt Jacob ct2_entry_t *cto = (ct2_entry_t *) local; 102500a8e174SMatt Jacob 1026d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; 1027d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_count = 1; 102800a8e174SMatt Jacob cto->ct_iid = cso->init_id; 102964edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) { 1030d81ba9d5SMatt Jacob cto->ct_lun = ccb->ccb_h.target_lun; 10312ad50ca5SMatt Jacob } 103253036e92SMatt Jacob 103353036e92SMatt Jacob atp = isp_get_atpd(isp, cso->tag_id); 103453036e92SMatt Jacob if (atp == NULL) { 103553036e92SMatt Jacob panic("cannot find private data adjunct for tag %x", 103653036e92SMatt Jacob cso->tag_id); 103753036e92SMatt Jacob } 1038f48ce188SMatt Jacob 103900a8e174SMatt Jacob cto->ct_rxid = cso->tag_id; 104000a8e174SMatt Jacob if (cso->dxfer_len == 0) { 104100a8e174SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA; 1042f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 104300a8e174SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 1044f48ce188SMatt Jacob cto->rsp.m1.ct_scsi_status = cso->scsi_status; 104553036e92SMatt Jacob cto->ct_resid = 104653036e92SMatt Jacob atp->orig_datalen - atp->bytes_xfered; 1047f48ce188SMatt Jacob } 104800a8e174SMatt Jacob if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) { 104900a8e174SMatt Jacob int m = min(cso->sense_len, MAXRESPLEN); 105000a8e174SMatt Jacob bcopy(&cso->sense_data, cto->rsp.m1.ct_resp, m); 105100a8e174SMatt Jacob cto->rsp.m1.ct_senselen = m; 105200a8e174SMatt Jacob cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID; 105300a8e174SMatt Jacob } 105400a8e174SMatt Jacob } else { 105500a8e174SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE0; 105600a8e174SMatt Jacob if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 105700a8e174SMatt Jacob cto->ct_flags |= CT2_DATA_IN; 105800a8e174SMatt Jacob } else { 105900a8e174SMatt Jacob cto->ct_flags |= CT2_DATA_OUT; 1060d81ba9d5SMatt Jacob } 1061d81ba9d5SMatt Jacob if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 1062d81ba9d5SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 106300a8e174SMatt Jacob cto->rsp.m0.ct_scsi_status = cso->scsi_status; 106453036e92SMatt Jacob cto->ct_resid = 106553036e92SMatt Jacob atp->orig_datalen - 106653036e92SMatt Jacob (atp->bytes_xfered + cso->dxfer_len); 106753036e92SMatt Jacob } else { 106853036e92SMatt Jacob atp->last_xframt = cso->dxfer_len; 1069d81ba9d5SMatt Jacob } 1070f48ce188SMatt Jacob /* 1071f48ce188SMatt Jacob * If we're sending data and status back together, 1072f48ce188SMatt Jacob * we can't also send back sense data as well. 1073f48ce188SMatt Jacob */ 107400a8e174SMatt Jacob ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 107500a8e174SMatt Jacob } 107653036e92SMatt Jacob 1077290dc24bSMatt Jacob if (cto->ct_flags & CT2_SENDSTATUS) { 107864edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 107953036e92SMatt Jacob "CTIO2[%x] STATUS %x origd %u curd %u resid %u", 108053036e92SMatt Jacob cto->ct_rxid, cso->scsi_status, atp->orig_datalen, 108153036e92SMatt Jacob cso->dxfer_len, cto->ct_resid); 1082a1bc34c6SMatt Jacob cto->ct_flags |= CT2_CCINCR; 108364edff94SMatt Jacob } 1084a1bc34c6SMatt Jacob cto->ct_timeout = 10; 10855f5aafe1SMatt Jacob hp = &cto->ct_syshandle; 1086d81ba9d5SMatt Jacob } else { 10874fd13c1bSMatt Jacob ct_entry_t *cto = (ct_entry_t *) local; 108800a8e174SMatt Jacob 1089d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 1090d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_count = 1; 109100a8e174SMatt Jacob cto->ct_iid = cso->init_id; 1092a1bc34c6SMatt Jacob cto->ct_iid |= XS_CHANNEL(ccb) << 7; 1093d81ba9d5SMatt Jacob cto->ct_tgt = ccb->ccb_h.target_id; 1094d81ba9d5SMatt Jacob cto->ct_lun = ccb->ccb_h.target_lun; 1095a1bc34c6SMatt Jacob cto->ct_fwhandle = AT_GET_HANDLE(cso->tag_id); 1096a1bc34c6SMatt Jacob if (AT_HAS_TAG(cso->tag_id)) { 1097a1bc34c6SMatt Jacob cto->ct_tag_val = (u_int8_t) AT_GET_TAG(cso->tag_id); 1098f48ce188SMatt Jacob cto->ct_flags |= CT_TQAE; 1099f48ce188SMatt Jacob } 1100f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) { 1101f48ce188SMatt Jacob cto->ct_flags |= CT_NODISC; 1102f48ce188SMatt Jacob } 1103f48ce188SMatt Jacob if (cso->dxfer_len == 0) { 1104d81ba9d5SMatt Jacob cto->ct_flags |= CT_NO_DATA; 110500a8e174SMatt Jacob } else if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 110600a8e174SMatt Jacob cto->ct_flags |= CT_DATA_IN; 110700a8e174SMatt Jacob } else { 110800a8e174SMatt Jacob cto->ct_flags |= CT_DATA_OUT; 1109d81ba9d5SMatt Jacob } 1110f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 111153036e92SMatt Jacob cto->ct_flags |= CT_SENDSTATUS|CT_CCINCR; 111200a8e174SMatt Jacob cto->ct_scsi_status = cso->scsi_status; 111300a8e174SMatt Jacob cto->ct_resid = cso->resid; 111464edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1115a1bc34c6SMatt Jacob "CTIO[%x] SCSI STATUS 0x%x resid %d tag_id %x", 1116a1bc34c6SMatt Jacob cto->ct_fwhandle, cso->scsi_status, cso->resid, 1117a1bc34c6SMatt Jacob cso->tag_id); 111892a1e549SMatt Jacob } 111964edff94SMatt Jacob ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 1120a1bc34c6SMatt Jacob cto->ct_timeout = 10; 11215f5aafe1SMatt Jacob hp = &cto->ct_syshandle; 1122d81ba9d5SMatt Jacob } 1123d81ba9d5SMatt Jacob 1124b09b0095SMatt Jacob if (isp_save_xs(isp, (XS_T *)ccb, hp)) { 112592a1e549SMatt Jacob xpt_print_path(ccb->ccb_h.path); 112692a1e549SMatt Jacob printf("No XFLIST pointers for isp_target_start_ctio\n"); 1127d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 1128d81ba9d5SMatt Jacob } 1129d81ba9d5SMatt Jacob 1130d81ba9d5SMatt Jacob 1131d81ba9d5SMatt Jacob /* 1132d81ba9d5SMatt Jacob * Call the dma setup routines for this entry (and any subsequent 1133d81ba9d5SMatt Jacob * CTIOs) if there's data to move, and then tell the f/w it's got 1134b09b0095SMatt Jacob * new things to play with. As with isp_start's usage of DMA setup, 1135d81ba9d5SMatt Jacob * any swizzling is done in the machine dependent layer. Because 1136d81ba9d5SMatt Jacob * of this, we put the request onto the queue area first in native 1137d81ba9d5SMatt Jacob * format. 1138d81ba9d5SMatt Jacob */ 1139d81ba9d5SMatt Jacob 1140d81ba9d5SMatt Jacob save_handle = *hp; 1141a1bc34c6SMatt Jacob 11424fd13c1bSMatt Jacob switch (ISP_DMASETUP(isp, cso, (ispreq_t *) local, &nxti, optr)) { 1143d81ba9d5SMatt Jacob case CMD_QUEUED: 11444fd13c1bSMatt Jacob ISP_ADD_REQUEST(isp, nxti); 1145d81ba9d5SMatt Jacob return (CAM_REQ_INPROG); 1146d81ba9d5SMatt Jacob 1147d81ba9d5SMatt Jacob case CMD_EAGAIN: 1148d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 1149d81ba9d5SMatt Jacob isp_destroy_handle(isp, save_handle); 1150d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 1151d81ba9d5SMatt Jacob 1152d81ba9d5SMatt Jacob default: 1153d81ba9d5SMatt Jacob isp_destroy_handle(isp, save_handle); 1154b85389e1SMatt Jacob return (XS_ERR(ccb)); 1155d81ba9d5SMatt Jacob } 1156d81ba9d5SMatt Jacob } 1157d81ba9d5SMatt Jacob 1158a1bc34c6SMatt Jacob static void 1159a1bc34c6SMatt Jacob isp_refire_putback_atio(void *arg) 1160f48ce188SMatt Jacob { 1161a1bc34c6SMatt Jacob int s = splcam(); 1162a1bc34c6SMatt Jacob isp_target_putback_atio(arg); 1163a1bc34c6SMatt Jacob splx(s); 1164a1bc34c6SMatt Jacob } 1165a1bc34c6SMatt Jacob 1166a1bc34c6SMatt Jacob static void 1167a1bc34c6SMatt Jacob isp_target_putback_atio(union ccb *ccb) 1168a1bc34c6SMatt Jacob { 1169a1bc34c6SMatt Jacob struct ispsoftc *isp; 1170a1bc34c6SMatt Jacob struct ccb_scsiio *cso; 11714fd13c1bSMatt Jacob u_int16_t nxti, optr; 1172a1bc34c6SMatt Jacob void *qe; 1173a1bc34c6SMatt Jacob 1174a1bc34c6SMatt Jacob isp = XS_ISP(ccb); 1175f48ce188SMatt Jacob 11764fd13c1bSMatt Jacob if (isp_getrqentry(isp, &nxti, &optr, &qe)) { 1177a1bc34c6SMatt Jacob (void) timeout(isp_refire_putback_atio, ccb, 10); 1178a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGWARN, 1179a1bc34c6SMatt Jacob "isp_target_putback_atio: Request Queue Overflow"); 1180a1bc34c6SMatt Jacob return; 1181f48ce188SMatt Jacob } 1182f48ce188SMatt Jacob bzero(qe, QENTRY_LEN); 1183a1bc34c6SMatt Jacob cso = &ccb->csio; 1184f48ce188SMatt Jacob if (IS_FC(isp)) { 11854fd13c1bSMatt Jacob at2_entry_t local, *at = &local; 11864fd13c1bSMatt Jacob MEMZERO(at, sizeof (at2_entry_t)); 1187f48ce188SMatt Jacob at->at_header.rqs_entry_type = RQSTYPE_ATIO2; 1188f48ce188SMatt Jacob at->at_header.rqs_entry_count = 1; 118964edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) != 0) { 1190a1bc34c6SMatt Jacob at->at_scclun = (uint16_t) ccb->ccb_h.target_lun; 1191f48ce188SMatt Jacob } else { 1192a1bc34c6SMatt Jacob at->at_lun = (uint8_t) ccb->ccb_h.target_lun; 1193f48ce188SMatt Jacob } 1194f48ce188SMatt Jacob at->at_status = CT_OK; 1195a1bc34c6SMatt Jacob at->at_rxid = cso->tag_id; 11964fd13c1bSMatt Jacob isp_put_atio2(isp, at, qe); 1197f48ce188SMatt Jacob } else { 11984fd13c1bSMatt Jacob at_entry_t local, *at = &local; 11994fd13c1bSMatt Jacob MEMZERO(at, sizeof (at_entry_t)); 1200f48ce188SMatt Jacob at->at_header.rqs_entry_type = RQSTYPE_ATIO; 1201f48ce188SMatt Jacob at->at_header.rqs_entry_count = 1; 1202a1bc34c6SMatt Jacob at->at_iid = cso->init_id; 1203a1bc34c6SMatt Jacob at->at_iid |= XS_CHANNEL(ccb) << 7; 1204a1bc34c6SMatt Jacob at->at_tgt = cso->ccb_h.target_id; 1205a1bc34c6SMatt Jacob at->at_lun = cso->ccb_h.target_lun; 1206f48ce188SMatt Jacob at->at_status = CT_OK; 1207a1bc34c6SMatt Jacob at->at_tag_val = AT_GET_TAG(cso->tag_id); 1208a1bc34c6SMatt Jacob at->at_handle = AT_GET_HANDLE(cso->tag_id); 12094fd13c1bSMatt Jacob isp_put_atio(isp, at, qe); 1210f48ce188SMatt Jacob } 1211f48ce188SMatt Jacob ISP_TDQE(isp, "isp_target_putback_atio", (int) optr, qe); 12124fd13c1bSMatt Jacob ISP_ADD_REQUEST(isp, nxti); 1213a1bc34c6SMatt Jacob isp_complete_ctio(ccb); 1214f48ce188SMatt Jacob } 1215f48ce188SMatt Jacob 1216f48ce188SMatt Jacob static void 1217a1bc34c6SMatt Jacob isp_complete_ctio(union ccb *ccb) 1218f48ce188SMatt Jacob { 1219a1bc34c6SMatt Jacob struct ispsoftc *isp = XS_ISP(ccb); 1220a1bc34c6SMatt Jacob if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { 1221a1bc34c6SMatt Jacob ccb->ccb_h.status |= CAM_REQ_CMP; 1222f48ce188SMatt Jacob } 1223a1bc34c6SMatt Jacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1224a1bc34c6SMatt Jacob if (isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE) { 1225a1bc34c6SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_RESOURCE; 1226a1bc34c6SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 1227a1bc34c6SMatt Jacob if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 1228a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "ctio->relsimq"); 1229a1bc34c6SMatt Jacob ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 1230a1bc34c6SMatt Jacob } else { 1231a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGWARN, "ctio->devqfrozen"); 1232a1bc34c6SMatt Jacob } 1233a1bc34c6SMatt Jacob } else { 1234a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGWARN, 1235a1bc34c6SMatt Jacob "ctio->simqfrozen(%x)", isp->isp_osinfo.simqfrozen); 1236a1bc34c6SMatt Jacob } 1237a1bc34c6SMatt Jacob } 1238a1bc34c6SMatt Jacob xpt_done(ccb); 1239f48ce188SMatt Jacob } 1240f48ce188SMatt Jacob 1241d81ba9d5SMatt Jacob /* 1242d81ba9d5SMatt Jacob * Handle ATIO stuff that the generic code can't. 1243d81ba9d5SMatt Jacob * This means handling CDBs. 1244d81ba9d5SMatt Jacob */ 1245d81ba9d5SMatt Jacob 1246d81ba9d5SMatt Jacob static int 1247d81ba9d5SMatt Jacob isp_handle_platform_atio(struct ispsoftc *isp, at_entry_t *aep) 1248d81ba9d5SMatt Jacob { 1249d81ba9d5SMatt Jacob tstate_t *tptr; 125064edff94SMatt Jacob int status, bus, iswildcard; 1251d81ba9d5SMatt Jacob struct ccb_accept_tio *atiop; 1252d81ba9d5SMatt Jacob 1253d81ba9d5SMatt Jacob /* 1254d81ba9d5SMatt Jacob * The firmware status (except for the QLTM_SVALID bit) 1255d81ba9d5SMatt Jacob * indicates why this ATIO was sent to us. 1256d81ba9d5SMatt Jacob * 1257d81ba9d5SMatt Jacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 1258d81ba9d5SMatt Jacob * 1259d81ba9d5SMatt Jacob * If the DISCONNECTS DISABLED bit is set in the flags field, 12605d571944SMatt Jacob * we're still connected on the SCSI bus. 1261d81ba9d5SMatt Jacob */ 1262d81ba9d5SMatt Jacob status = aep->at_status; 1263d81ba9d5SMatt Jacob if ((status & ~QLTM_SVALID) == AT_PHASE_ERROR) { 1264d81ba9d5SMatt Jacob /* 1265d81ba9d5SMatt Jacob * Bus Phase Sequence error. We should have sense data 1266d81ba9d5SMatt Jacob * suggested by the f/w. I'm not sure quite yet what 1267d81ba9d5SMatt Jacob * to do about this for CAM. 1268d81ba9d5SMatt Jacob */ 12693c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, "PHASE ERROR"); 1270d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1271d81ba9d5SMatt Jacob return (0); 1272d81ba9d5SMatt Jacob } 1273d81ba9d5SMatt Jacob if ((status & ~QLTM_SVALID) != AT_CDB) { 12745d571944SMatt Jacob isp_prt(isp, ISP_LOGWARN, "bad atio (0x%x) leaked to platform", 12753c75bb14SMatt Jacob status); 1276d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1277d81ba9d5SMatt Jacob return (0); 1278d81ba9d5SMatt Jacob } 1279d81ba9d5SMatt Jacob 12805d571944SMatt Jacob bus = GET_BUS_VAL(aep->at_iid); 1281a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, aep->at_lun); 1282d81ba9d5SMatt Jacob if (tptr == NULL) { 1283a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD); 128464edff94SMatt Jacob iswildcard = 1; 128564edff94SMatt Jacob } else { 128664edff94SMatt Jacob iswildcard = 0; 1287d81ba9d5SMatt Jacob } 1288d81ba9d5SMatt Jacob 1289d81ba9d5SMatt Jacob if (tptr == NULL) { 1290d81ba9d5SMatt Jacob /* 1291d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1292d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1293d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a BUSY status 1294d81ba9d5SMatt Jacob * instead. This works out okay because the only 1295d81ba9d5SMatt Jacob * time we should, in fact, get this, is in the 1296d81ba9d5SMatt Jacob * case that somebody configured us without the 1297d81ba9d5SMatt Jacob * blackhole driver, so they get what they deserve. 1298d81ba9d5SMatt Jacob */ 1299d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1300d81ba9d5SMatt Jacob return (0); 1301d81ba9d5SMatt Jacob } 1302d81ba9d5SMatt Jacob 1303d81ba9d5SMatt Jacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 1304d81ba9d5SMatt Jacob if (atiop == NULL) { 1305d81ba9d5SMatt Jacob /* 1306d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1307d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1308d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a QUEUE FULL status 1309d81ba9d5SMatt Jacob * instead. This works out okay because the only time we 1310d81ba9d5SMatt Jacob * should, in fact, get this, is in the case that we've 1311d81ba9d5SMatt Jacob * run out of ATIOS. 1312d81ba9d5SMatt Jacob */ 1313d81ba9d5SMatt Jacob xpt_print_path(tptr->owner); 13143c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 1315a1bc34c6SMatt Jacob "no ATIOS for lun %d from initiator %d on channel %d", 13165d571944SMatt Jacob aep->at_lun, GET_IID_VAL(aep->at_iid), bus); 1317d81ba9d5SMatt Jacob if (aep->at_flags & AT_TQAE) 1318d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); 1319d81ba9d5SMatt Jacob else 1320d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 132164edff94SMatt Jacob rls_lun_statep(isp, tptr); 1322d81ba9d5SMatt Jacob return (0); 1323d81ba9d5SMatt Jacob } 1324d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 132564edff94SMatt Jacob if (iswildcard) { 1326d81ba9d5SMatt Jacob atiop->ccb_h.target_id = aep->at_tgt; 1327d81ba9d5SMatt Jacob atiop->ccb_h.target_lun = aep->at_lun; 1328d81ba9d5SMatt Jacob } 1329d81ba9d5SMatt Jacob if (aep->at_flags & AT_NODISC) { 1330f48ce188SMatt Jacob atiop->ccb_h.flags = CAM_DIS_DISCONNECT; 1331f48ce188SMatt Jacob } else { 1332f48ce188SMatt Jacob atiop->ccb_h.flags = 0; 1333d81ba9d5SMatt Jacob } 1334d81ba9d5SMatt Jacob 1335f48ce188SMatt Jacob if (status & QLTM_SVALID) { 1336f48ce188SMatt Jacob size_t amt = imin(QLTM_SENSELEN, sizeof (atiop->sense_data)); 1337f48ce188SMatt Jacob atiop->sense_len = amt; 1338f48ce188SMatt Jacob MEMCPY(&atiop->sense_data, aep->at_sense, amt); 1339f48ce188SMatt Jacob } else { 1340f48ce188SMatt Jacob atiop->sense_len = 0; 1341f48ce188SMatt Jacob } 1342d81ba9d5SMatt Jacob 13435d571944SMatt Jacob atiop->init_id = GET_IID_VAL(aep->at_iid); 1344d81ba9d5SMatt Jacob atiop->cdb_len = aep->at_cdblen; 1345d81ba9d5SMatt Jacob MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen); 1346d81ba9d5SMatt Jacob atiop->ccb_h.status = CAM_CDB_RECVD; 1347a1bc34c6SMatt Jacob /* 1348a1bc34c6SMatt Jacob * Construct a tag 'id' based upon tag value (which may be 0..255) 1349a1bc34c6SMatt Jacob * and the handle (which we have to preserve). 1350a1bc34c6SMatt Jacob */ 1351a1bc34c6SMatt Jacob AT_MAKE_TAGID(atiop->tag_id, aep); 1352a1bc34c6SMatt Jacob if (aep->at_flags & AT_TQAE) { 1353a1bc34c6SMatt Jacob atiop->tag_action = aep->at_tag_type; 1354d81ba9d5SMatt Jacob atiop->ccb_h.status |= CAM_TAG_ACTION_VALID; 1355d81ba9d5SMatt Jacob } 1356d81ba9d5SMatt Jacob xpt_done((union ccb*)atiop); 135764edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 13585d571944SMatt Jacob "ATIO[%x] CDB=0x%x bus %d iid%d->lun%d tag 0x%x ttype 0x%x %s", 13595d571944SMatt Jacob aep->at_handle, aep->at_cdb[0] & 0xff, GET_BUS_VAL(aep->at_iid), 13605d571944SMatt Jacob GET_IID_VAL(aep->at_iid), aep->at_lun, aep->at_tag_val & 0xff, 13615d571944SMatt Jacob aep->at_tag_type, (aep->at_flags & AT_NODISC)? 13625d571944SMatt Jacob "nondisc" : "disconnecting"); 1363d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1364d81ba9d5SMatt Jacob return (0); 1365d81ba9d5SMatt Jacob } 1366d81ba9d5SMatt Jacob 1367d81ba9d5SMatt Jacob static int 1368d81ba9d5SMatt Jacob isp_handle_platform_atio2(struct ispsoftc *isp, at2_entry_t *aep) 1369d81ba9d5SMatt Jacob { 137092a1e549SMatt Jacob lun_id_t lun; 1371d81ba9d5SMatt Jacob tstate_t *tptr; 1372d81ba9d5SMatt Jacob struct ccb_accept_tio *atiop; 137353036e92SMatt Jacob atio_private_data_t *atp; 1374d81ba9d5SMatt Jacob 1375d81ba9d5SMatt Jacob /* 1376d81ba9d5SMatt Jacob * The firmware status (except for the QLTM_SVALID bit) 1377d81ba9d5SMatt Jacob * indicates why this ATIO was sent to us. 1378d81ba9d5SMatt Jacob * 1379d81ba9d5SMatt Jacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 1380d81ba9d5SMatt Jacob */ 1381d81ba9d5SMatt Jacob if ((aep->at_status & ~QLTM_SVALID) != AT_CDB) { 13823c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 13833c75bb14SMatt Jacob "bogus atio (0x%x) leaked to platform", aep->at_status); 1384d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1385d81ba9d5SMatt Jacob return (0); 1386d81ba9d5SMatt Jacob } 1387d81ba9d5SMatt Jacob 138864edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) != 0) { 138992a1e549SMatt Jacob lun = aep->at_scclun; 13902ad50ca5SMatt Jacob } else { 139192a1e549SMatt Jacob lun = aep->at_lun; 13922ad50ca5SMatt Jacob } 1393a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, 0, lun); 1394d81ba9d5SMatt Jacob if (tptr == NULL) { 1395a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD); 1396d81ba9d5SMatt Jacob } 1397d81ba9d5SMatt Jacob 1398d81ba9d5SMatt Jacob if (tptr == NULL) { 139952df5dfdSMatt Jacob /* 140052df5dfdSMatt Jacob * What we'd like to know is whether or not we have a listener 140152df5dfdSMatt Jacob * upstream that really hasn't configured yet. If we do, then 140252df5dfdSMatt Jacob * we can give a more sensible reply here. If not, then we can 140352df5dfdSMatt Jacob * reject this out of hand. 140452df5dfdSMatt Jacob * 140552df5dfdSMatt Jacob * Choices for what to send were 140652df5dfdSMatt Jacob * 140752df5dfdSMatt Jacob * Not Ready, Unit Not Self-Configured Yet 140852df5dfdSMatt Jacob * (0x2,0x3e,0x00) 140952df5dfdSMatt Jacob * 141052df5dfdSMatt Jacob * for the former and 141152df5dfdSMatt Jacob * 141252df5dfdSMatt Jacob * Illegal Request, Logical Unit Not Supported 141352df5dfdSMatt Jacob * (0x5,0x25,0x00) 141452df5dfdSMatt Jacob * 141552df5dfdSMatt Jacob * for the latter. 141652df5dfdSMatt Jacob * 141752df5dfdSMatt Jacob * We used to decide whether there was at least one listener 141852df5dfdSMatt Jacob * based upon whether the black hole driver was configured. 141952df5dfdSMatt Jacob * However, recent config(8) changes have made this hard to do 142052df5dfdSMatt Jacob * at this time. 142152df5dfdSMatt Jacob * 142252df5dfdSMatt Jacob */ 1423d81ba9d5SMatt Jacob u_int32_t ccode = SCSI_STATUS_BUSY; 1424d81ba9d5SMatt Jacob 1425d81ba9d5SMatt Jacob /* 1426d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1427d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1428d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a BUSY status 1429d81ba9d5SMatt Jacob * instead. This works out okay because the only 1430d81ba9d5SMatt Jacob * time we should, in fact, get this, is in the 1431d81ba9d5SMatt Jacob * case that somebody configured us without the 1432d81ba9d5SMatt Jacob * blackhole driver, so they get what they deserve. 1433d81ba9d5SMatt Jacob */ 1434d81ba9d5SMatt Jacob isp_endcmd(isp, aep, ccode, 0); 1435d81ba9d5SMatt Jacob return (0); 1436d81ba9d5SMatt Jacob } 1437d81ba9d5SMatt Jacob 143853036e92SMatt Jacob atp = isp_get_atpd(isp, 0); 1439d81ba9d5SMatt Jacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 144053036e92SMatt Jacob if (atiop == NULL || atp == NULL) { 1441d81ba9d5SMatt Jacob /* 1442d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1443d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1444d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a QUEUE FULL status 1445d81ba9d5SMatt Jacob * instead. This works out okay because the only time we 1446d81ba9d5SMatt Jacob * should, in fact, get this, is in the case that we've 1447d81ba9d5SMatt Jacob * run out of ATIOS. 1448d81ba9d5SMatt Jacob */ 1449d81ba9d5SMatt Jacob xpt_print_path(tptr->owner); 14503c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 14513c75bb14SMatt Jacob "no ATIOS for lun %d from initiator %d", lun, aep->at_iid); 1452d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1453d81ba9d5SMatt Jacob if (aep->at_flags & AT_TQAE) 1454d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); 1455d81ba9d5SMatt Jacob else 1456d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1457d81ba9d5SMatt Jacob return (0); 1458d81ba9d5SMatt Jacob } 1459d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 1460f48ce188SMatt Jacob 1461a1bc34c6SMatt Jacob if (tptr == &isp->isp_osinfo.tsdflt[0]) { 1462d81ba9d5SMatt Jacob atiop->ccb_h.target_id = 1463d81ba9d5SMatt Jacob ((fcparam *)isp->isp_param)->isp_loopid; 146492a1e549SMatt Jacob atiop->ccb_h.target_lun = lun; 1465d81ba9d5SMatt Jacob } 1466b0a3ba7eSMatt Jacob /* 1467b0a3ba7eSMatt Jacob * We don't get 'suggested' sense data as we do with SCSI cards. 1468b0a3ba7eSMatt Jacob */ 1469f48ce188SMatt Jacob atiop->sense_len = 0; 1470f48ce188SMatt Jacob 1471d81ba9d5SMatt Jacob atiop->init_id = aep->at_iid; 1472d81ba9d5SMatt Jacob atiop->cdb_len = ATIO2_CDBLEN; 1473d81ba9d5SMatt Jacob MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, ATIO2_CDBLEN); 1474d81ba9d5SMatt Jacob atiop->ccb_h.status = CAM_CDB_RECVD; 1475d81ba9d5SMatt Jacob atiop->tag_id = aep->at_rxid; 1476d81ba9d5SMatt Jacob switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) { 1477d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_SIMPLEQ: 1478d81ba9d5SMatt Jacob atiop->tag_action = MSG_SIMPLE_Q_TAG; 1479d81ba9d5SMatt Jacob break; 1480d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_HEADOFQ: 1481d81ba9d5SMatt Jacob atiop->tag_action = MSG_HEAD_OF_Q_TAG; 1482d81ba9d5SMatt Jacob break; 1483d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_ORDERED: 1484d81ba9d5SMatt Jacob atiop->tag_action = MSG_ORDERED_Q_TAG; 1485d81ba9d5SMatt Jacob break; 1486d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_ACAQ: /* ?? */ 1487d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_UNTAGGED: 1488d81ba9d5SMatt Jacob default: 1489d81ba9d5SMatt Jacob atiop->tag_action = 0; 1490d81ba9d5SMatt Jacob break; 1491d81ba9d5SMatt Jacob } 1492d81ba9d5SMatt Jacob if (atiop->tag_action != 0) { 1493d81ba9d5SMatt Jacob atiop->ccb_h.status |= CAM_TAG_ACTION_VALID; 1494d81ba9d5SMatt Jacob } 1495f48ce188SMatt Jacob 149653036e92SMatt Jacob atp->tag = atiop->tag_id; 149753036e92SMatt Jacob atp->orig_datalen = aep->at_datalen; 149853036e92SMatt Jacob atp->last_xframt = 0; 149953036e92SMatt Jacob atp->bytes_xfered = 0; 1500f48ce188SMatt Jacob 1501d81ba9d5SMatt Jacob xpt_done((union ccb*)atiop); 150264edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 15035f5aafe1SMatt Jacob "ATIO2[%x] CDB=0x%x iid%d->lun%d tattr 0x%x datalen %u", 15045f5aafe1SMatt Jacob aep->at_rxid, aep->at_cdb[0] & 0xff, aep->at_iid, 1505b09b0095SMatt Jacob lun, aep->at_taskflags, aep->at_datalen); 1506d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1507d81ba9d5SMatt Jacob return (0); 1508d81ba9d5SMatt Jacob } 1509d81ba9d5SMatt Jacob 1510d81ba9d5SMatt Jacob static int 1511d81ba9d5SMatt Jacob isp_handle_platform_ctio(struct ispsoftc *isp, void *arg) 1512d81ba9d5SMatt Jacob { 1513d81ba9d5SMatt Jacob union ccb *ccb; 1514a1bc34c6SMatt Jacob int sentstatus, ok, notify_cam, resid = 0; 151564edff94SMatt Jacob u_int16_t tval; 1516d81ba9d5SMatt Jacob 1517d81ba9d5SMatt Jacob /* 1518d81ba9d5SMatt Jacob * CTIO and CTIO2 are close enough.... 1519d81ba9d5SMatt Jacob */ 1520d81ba9d5SMatt Jacob 15215f5aafe1SMatt Jacob ccb = (union ccb *) isp_find_xs(isp, ((ct_entry_t *)arg)->ct_syshandle); 1522d81ba9d5SMatt Jacob KASSERT((ccb != NULL), ("null ccb in isp_handle_platform_ctio")); 15235f5aafe1SMatt Jacob isp_destroy_handle(isp, ((ct_entry_t *)arg)->ct_syshandle); 1524d81ba9d5SMatt Jacob 1525d81ba9d5SMatt Jacob if (IS_FC(isp)) { 1526d81ba9d5SMatt Jacob ct2_entry_t *ct = arg; 1527d81ba9d5SMatt Jacob sentstatus = ct->ct_flags & CT2_SENDSTATUS; 1528d81ba9d5SMatt Jacob ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; 1529a1bc34c6SMatt Jacob if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) { 153000a8e174SMatt Jacob ccb->ccb_h.status |= CAM_SENT_SENSE; 153100a8e174SMatt Jacob } 1532a1bc34c6SMatt Jacob notify_cam = ct->ct_header.rqs_seqno & 0x1; 15335d571944SMatt Jacob if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) { 153453036e92SMatt Jacob atio_private_data_t *atp = 153553036e92SMatt Jacob isp_get_atpd(isp, ct->ct_rxid); 153653036e92SMatt Jacob if (atp == NULL) { 153753036e92SMatt Jacob panic("cannot find adjunct after I/O"); 153853036e92SMatt Jacob } 1539a1bc34c6SMatt Jacob resid = ct->ct_resid; 154053036e92SMatt Jacob atp->bytes_xfered += (atp->last_xframt - resid); 154153036e92SMatt Jacob atp->last_xframt = 0; 154253036e92SMatt Jacob if (sentstatus) { 154353036e92SMatt Jacob atp->tag = 0; 154453036e92SMatt Jacob } 15455d571944SMatt Jacob } 154664edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 154764edff94SMatt Jacob "CTIO2[%x] sts 0x%x flg 0x%x sns %d resid %d %s", 154864edff94SMatt Jacob ct->ct_rxid, ct->ct_status, ct->ct_flags, 154964edff94SMatt Jacob (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, 155064edff94SMatt Jacob resid, sentstatus? "FIN" : "MID"); 155164edff94SMatt Jacob tval = ct->ct_rxid; 1552d81ba9d5SMatt Jacob } else { 1553d81ba9d5SMatt Jacob ct_entry_t *ct = arg; 1554d81ba9d5SMatt Jacob sentstatus = ct->ct_flags & CT_SENDSTATUS; 1555d81ba9d5SMatt Jacob ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; 1556d81ba9d5SMatt Jacob /* 1557a1bc34c6SMatt Jacob * We *ought* to be able to get back to the original ATIO 1558a1bc34c6SMatt Jacob * here, but for some reason this gets lost. It's just as 1559a1bc34c6SMatt Jacob * well because it's squirrelled away as part of periph 1560a1bc34c6SMatt Jacob * private data. 1561a1bc34c6SMatt Jacob * 1562a1bc34c6SMatt Jacob * We can live without it as long as we continue to use 1563a1bc34c6SMatt Jacob * the auto-replenish feature for CTIOs. 1564a1bc34c6SMatt Jacob */ 1565a1bc34c6SMatt Jacob notify_cam = ct->ct_header.rqs_seqno & 0x1; 1566a1bc34c6SMatt Jacob if (ct->ct_status & QLTM_SVALID) { 1567a1bc34c6SMatt Jacob char *sp = (char *)ct; 1568a1bc34c6SMatt Jacob sp += CTIO_SENSE_OFFSET; 1569a1bc34c6SMatt Jacob ccb->csio.sense_len = 1570a1bc34c6SMatt Jacob min(sizeof (ccb->csio.sense_data), QLTM_SENSELEN); 1571a1bc34c6SMatt Jacob MEMCPY(&ccb->csio.sense_data, sp, ccb->csio.sense_len); 1572a1bc34c6SMatt Jacob ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 1573a1bc34c6SMatt Jacob } 15745d571944SMatt Jacob if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) { 1575a1bc34c6SMatt Jacob resid = ct->ct_resid; 1576a1bc34c6SMatt Jacob } 157764edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 157864edff94SMatt Jacob "CTIO[%x] tag %x iid %d lun %d sts %x flg %x resid %d %s", 157964edff94SMatt Jacob ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_lun, 158064edff94SMatt Jacob ct->ct_status, ct->ct_flags, resid, 158164edff94SMatt Jacob sentstatus? "FIN" : "MID"); 158264edff94SMatt Jacob tval = ct->ct_fwhandle; 15835d571944SMatt Jacob } 1584a1bc34c6SMatt Jacob ccb->csio.resid += resid; 1585a1bc34c6SMatt Jacob 1586a1bc34c6SMatt Jacob /* 1587a1bc34c6SMatt Jacob * We're here either because intermediate data transfers are done 1588a1bc34c6SMatt Jacob * and/or the final status CTIO (which may have joined with a 1589a1bc34c6SMatt Jacob * Data Transfer) is done. 1590d81ba9d5SMatt Jacob * 1591d81ba9d5SMatt Jacob * In any case, for this platform, the upper layers figure out 1592d81ba9d5SMatt Jacob * what to do next, so all we do here is collect status and 1593a1bc34c6SMatt Jacob * pass information along. Any DMA handles have already been 1594a1bc34c6SMatt Jacob * freed. 1595d81ba9d5SMatt Jacob */ 1596f48ce188SMatt Jacob if (notify_cam == 0) { 159764edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, " INTER CTIO[0x%x] done", tval); 1598f48ce188SMatt Jacob return (0); 1599f48ce188SMatt Jacob } 1600d81ba9d5SMatt Jacob 160153036e92SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO[0x%x] done", 160253036e92SMatt Jacob (sentstatus)? " FINAL " : "MIDTERM ", tval); 1603a1bc34c6SMatt Jacob 1604a1bc34c6SMatt Jacob if (!ok) { 1605a1bc34c6SMatt Jacob isp_target_putback_atio(ccb); 1606d81ba9d5SMatt Jacob } else { 1607a1bc34c6SMatt Jacob isp_complete_ctio(ccb); 1608a1bc34c6SMatt Jacob 1609d81ba9d5SMatt Jacob } 1610a1bc34c6SMatt Jacob return (0); 1611d81ba9d5SMatt Jacob } 1612d81ba9d5SMatt Jacob #endif 1613d81ba9d5SMatt Jacob 1614478f8a96SJustin T. Gibbs static void 1615cbf57b47SMatt Jacob isp_cam_async(void *cbarg, u_int32_t code, struct cam_path *path, void *arg) 1616478f8a96SJustin T. Gibbs { 1617478f8a96SJustin T. Gibbs struct cam_sim *sim; 1618478f8a96SJustin T. Gibbs struct ispsoftc *isp; 1619478f8a96SJustin T. Gibbs 1620478f8a96SJustin T. Gibbs sim = (struct cam_sim *)cbarg; 1621478f8a96SJustin T. Gibbs isp = (struct ispsoftc *) cam_sim_softc(sim); 1622478f8a96SJustin T. Gibbs switch (code) { 1623478f8a96SJustin T. Gibbs case AC_LOST_DEVICE: 1624ab6c4b31SMatt Jacob if (IS_SCSI(isp)) { 1625478f8a96SJustin T. Gibbs u_int16_t oflags, nflags; 1626478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 1627a1bc34c6SMatt Jacob int tgt; 1628478f8a96SJustin T. Gibbs 1629f9e908dcSMatt Jacob tgt = xpt_path_target_id(path); 1630f6e75de2SMatt Jacob ISP_LOCK(isp); 1631ea6f23cdSMatt Jacob sdp += cam_sim_bus(sim); 16329ce9bdafSMatt Jacob nflags = sdp->isp_devparam[tgt].nvrm_flags; 1633a1bc34c6SMatt Jacob #ifndef ISP_TARGET_MODE 16349ce9bdafSMatt Jacob nflags &= DPARM_SAFE_DFLT; 1635a1bc34c6SMatt Jacob if (isp->isp_loaded_fw) { 1636478f8a96SJustin T. Gibbs nflags |= DPARM_NARROW | DPARM_ASYNC; 1637478f8a96SJustin T. Gibbs } 1638a1bc34c6SMatt Jacob #else 1639a1bc34c6SMatt Jacob nflags = DPARM_DEFAULT; 1640a1bc34c6SMatt Jacob #endif 16419ce9bdafSMatt Jacob oflags = sdp->isp_devparam[tgt].goal_flags; 16429ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_flags = nflags; 1643478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_update = 1; 1644a1bc34c6SMatt Jacob isp->isp_update |= (1 << cam_sim_bus(sim)); 1645478f8a96SJustin T. Gibbs (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL); 16469ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_flags = oflags; 1647f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1648478f8a96SJustin T. Gibbs } 1649478f8a96SJustin T. Gibbs break; 1650478f8a96SJustin T. Gibbs default: 16513c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, "isp_cam_async: Code 0x%x", code); 1652478f8a96SJustin T. Gibbs break; 1653478f8a96SJustin T. Gibbs } 1654478f8a96SJustin T. Gibbs } 1655478f8a96SJustin T. Gibbs 1656478f8a96SJustin T. Gibbs static void 1657c3055363SMatt Jacob isp_poll(struct cam_sim *sim) 1658478f8a96SJustin T. Gibbs { 1659c40e096eSMatt Jacob struct ispsoftc *isp = cam_sim_softc(sim); 1660126ec864SMatt Jacob u_int16_t isr, sema, mbox; 1661126ec864SMatt Jacob 1662c40e096eSMatt Jacob ISP_LOCK(isp); 1663126ec864SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 1664126ec864SMatt Jacob isp_intr(isp, isr, sema, mbox); 1665126ec864SMatt Jacob } 1666c40e096eSMatt Jacob ISP_UNLOCK(isp); 1667478f8a96SJustin T. Gibbs } 1668478f8a96SJustin T. Gibbs 16695d571944SMatt Jacob #if 0 16700470d791SMatt Jacob static void 16710470d791SMatt Jacob isp_relsim(void *arg) 16720470d791SMatt Jacob { 16730470d791SMatt Jacob struct ispsoftc *isp = arg; 1674f6e75de2SMatt Jacob ISP_LOCK(isp); 16750470d791SMatt Jacob if (isp->isp_osinfo.simqfrozen & SIMQFRZ_TIMED) { 16760470d791SMatt Jacob int wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_TIMED; 16770470d791SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_TIMED; 16780470d791SMatt Jacob if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) { 16790470d791SMatt Jacob xpt_release_simq(isp->isp_sim, 1); 1680b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "timed relsimq"); 16810470d791SMatt Jacob } 16820470d791SMatt Jacob } 1683f6e75de2SMatt Jacob ISP_UNLOCK(isp); 16840470d791SMatt Jacob } 16855d571944SMatt Jacob #endif 1686ab6c4b31SMatt Jacob 1687478f8a96SJustin T. Gibbs static void 1688b85389e1SMatt Jacob isp_watchdog(void *arg) 1689cc8df88bSMatt Jacob { 1690b09b0095SMatt Jacob XS_T *xs = arg; 1691cc8df88bSMatt Jacob struct ispsoftc *isp = XS_ISP(xs); 1692cc8df88bSMatt Jacob u_int32_t handle; 1693b85389e1SMatt Jacob 1694cc8df88bSMatt Jacob /* 1695b85389e1SMatt Jacob * We've decided this command is dead. Make sure we're not trying 1696b85389e1SMatt Jacob * to kill a command that's already dead by getting it's handle and 1697b85389e1SMatt Jacob * and seeing whether it's still alive. 1698cc8df88bSMatt Jacob */ 1699f6e75de2SMatt Jacob ISP_LOCK(isp); 1700cc8df88bSMatt Jacob handle = isp_find_handle(isp, xs); 1701cc8df88bSMatt Jacob if (handle) { 1702126ec864SMatt Jacob u_int16_t isr, sema, mbox; 1703126ec864SMatt Jacob 1704b85389e1SMatt Jacob if (XS_CMD_DONE_P(xs)) { 1705b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG1, 1706b09b0095SMatt Jacob "watchdog found done cmd (handle 0x%x)", handle); 1707f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1708b85389e1SMatt Jacob return; 1709b85389e1SMatt Jacob } 1710b85389e1SMatt Jacob 1711b85389e1SMatt Jacob if (XS_CMD_WDOG_P(xs)) { 1712b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1713b09b0095SMatt Jacob "recursive watchdog (handle 0x%x)", handle); 1714f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1715b85389e1SMatt Jacob return; 1716b85389e1SMatt Jacob } 1717b85389e1SMatt Jacob 1718b85389e1SMatt Jacob XS_CMD_S_WDOG(xs); 1719126ec864SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 1720126ec864SMatt Jacob isp_intr(isp, isr, sema, mbox); 1721126ec864SMatt Jacob } 1722126ec864SMatt Jacob if (XS_CMD_DONE_P(xs)) { 1723b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1724126ec864SMatt Jacob "watchdog cleanup for handle 0x%x", handle); 1725b85389e1SMatt Jacob xpt_done((union ccb *) xs); 1726b85389e1SMatt Jacob } else if (XS_CMD_GRACE_P(xs)) { 17271fcf5debSMatt Jacob /* 17281fcf5debSMatt Jacob * Make sure the command is *really* dead before we 17291fcf5debSMatt Jacob * release the handle (and DMA resources) for reuse. 17301fcf5debSMatt Jacob */ 17311fcf5debSMatt Jacob (void) isp_control(isp, ISPCTL_ABORT_CMD, arg); 17321fcf5debSMatt Jacob 17331fcf5debSMatt Jacob /* 17341fcf5debSMatt Jacob * After this point, the comamnd is really dead. 17351fcf5debSMatt Jacob */ 1736f6e75de2SMatt Jacob if (XS_XFRLEN(xs)) { 1737f6e75de2SMatt Jacob ISP_DMAFREE(isp, xs, handle); 1738f6e75de2SMatt Jacob } 1739cc8df88bSMatt Jacob isp_destroy_handle(isp, handle); 1740cc8df88bSMatt Jacob xpt_print_path(xs->ccb_h.path); 17413c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 17422903b272SMatt Jacob "watchdog timeout for handle 0x%x", handle); 1743cc8df88bSMatt Jacob XS_SETERR(xs, CAM_CMD_TIMEOUT); 1744b85389e1SMatt Jacob XS_CMD_C_WDOG(xs); 1745cc8df88bSMatt Jacob isp_done(xs); 1746b85389e1SMatt Jacob } else { 17474fd13c1bSMatt Jacob u_int16_t nxti, optr; 17484fd13c1bSMatt Jacob ispreq_t local, *mp= &local, *qe; 1749b85389e1SMatt Jacob 1750b85389e1SMatt Jacob XS_CMD_C_WDOG(xs); 1751b85389e1SMatt Jacob xs->ccb_h.timeout_ch = timeout(isp_watchdog, xs, hz); 17524fd13c1bSMatt Jacob if (isp_getrqentry(isp, &nxti, &optr, (void **) &qe)) { 1753f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1754b85389e1SMatt Jacob return; 1755b85389e1SMatt Jacob } 1756b85389e1SMatt Jacob XS_CMD_S_GRACE(xs); 1757b85389e1SMatt Jacob MEMZERO((void *) mp, sizeof (*mp)); 1758b85389e1SMatt Jacob mp->req_header.rqs_entry_count = 1; 1759b85389e1SMatt Jacob mp->req_header.rqs_entry_type = RQSTYPE_MARKER; 1760b85389e1SMatt Jacob mp->req_modifier = SYNC_ALL; 1761b85389e1SMatt Jacob mp->req_target = XS_CHANNEL(xs) << 7; 17624fd13c1bSMatt Jacob isp_put_request(isp, mp, qe); 17634fd13c1bSMatt Jacob ISP_ADD_REQUEST(isp, nxti); 1764b85389e1SMatt Jacob } 1765b85389e1SMatt Jacob } else { 1766b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "watchdog with no command"); 1767cc8df88bSMatt Jacob } 1768f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1769cc8df88bSMatt Jacob } 1770cc8df88bSMatt Jacob 1771f44257c2SMatt Jacob static int isp_ktmature = 0; 1772f44257c2SMatt Jacob 17735d571944SMatt Jacob static void 17745d571944SMatt Jacob isp_kthread(void *arg) 17755d571944SMatt Jacob { 17765d571944SMatt Jacob int wasfrozen; 17775d571944SMatt Jacob struct ispsoftc *isp = arg; 17785d571944SMatt Jacob 17795d571944SMatt Jacob mtx_lock(&isp->isp_lock); 17805d571944SMatt Jacob for (;;) { 17815d571944SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "kthread checking FC state"); 17825d571944SMatt Jacob while (isp_fc_runstate(isp, 2 * 1000000) != 0) { 1783f44257c2SMatt Jacob if (FCPARAM(isp)->isp_fwstate != FW_READY || 1784f44257c2SMatt Jacob FCPARAM(isp)->isp_loopstate < LOOP_PDB_RCVD) { 1785f44257c2SMatt Jacob if (FCPARAM(isp)->loop_seen_once == 0 || 1786f44257c2SMatt Jacob isp_ktmature == 0) { 1787f44257c2SMatt Jacob break; 1788f44257c2SMatt Jacob } 1789f44257c2SMatt Jacob } 17905d571944SMatt Jacob msleep(isp_kthread, &isp->isp_lock, 17915d571944SMatt Jacob PRIBIO, "isp_fcthrd", hz); 17925d571944SMatt Jacob } 1793f44257c2SMatt Jacob /* 1794f44257c2SMatt Jacob * Even if we didn't get good loop state we may be 1795f44257c2SMatt Jacob * unfreezing the SIMQ so that we can kill off 1796f44257c2SMatt Jacob * commands (if we've never seen loop before, e.g.) 1797f44257c2SMatt Jacob */ 1798f44257c2SMatt Jacob isp_ktmature = 1; 17995d571944SMatt Jacob wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN; 18005d571944SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN; 18015d571944SMatt Jacob if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) { 18025d571944SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "kthread up release simq"); 18035d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 18045d571944SMatt Jacob xpt_release_simq(isp->isp_sim, 1); 18055d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 18065d571944SMatt Jacob } 18075d571944SMatt Jacob cv_wait(&isp->isp_osinfo.kthread_cv, &isp->isp_lock); 18085d571944SMatt Jacob } 18095d571944SMatt Jacob } 18105d571944SMatt Jacob 1811cc8df88bSMatt Jacob static void 1812c3055363SMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb) 1813478f8a96SJustin T. Gibbs { 1814f6e75de2SMatt Jacob int bus, tgt, error; 1815478f8a96SJustin T. Gibbs struct ispsoftc *isp; 18164663e367SJustin T. Gibbs struct ccb_trans_settings *cts; 1817478f8a96SJustin T. Gibbs 1818478f8a96SJustin T. Gibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n")); 1819478f8a96SJustin T. Gibbs 1820478f8a96SJustin T. Gibbs isp = (struct ispsoftc *)cam_sim_softc(sim); 1821478f8a96SJustin T. Gibbs ccb->ccb_h.sim_priv.entries[0].field = 0; 1822478f8a96SJustin T. Gibbs ccb->ccb_h.sim_priv.entries[1].ptr = isp; 18230470d791SMatt Jacob if (isp->isp_state != ISP_RUNSTATE && 18240470d791SMatt Jacob ccb->ccb_h.func_code == XPT_SCSI_IO) { 18255d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 182657c801f5SMatt Jacob isp_init(isp); 182757c801f5SMatt Jacob if (isp->isp_state != ISP_INITSTATE) { 1828f6e75de2SMatt Jacob ISP_UNLOCK(isp); 182957c801f5SMatt Jacob /* 183057c801f5SMatt Jacob * Lie. Say it was a selection timeout. 183157c801f5SMatt Jacob */ 1832b85389e1SMatt Jacob ccb->ccb_h.status = CAM_SEL_TIMEOUT | CAM_DEV_QFRZN; 18330470d791SMatt Jacob xpt_freeze_devq(ccb->ccb_h.path, 1); 183457c801f5SMatt Jacob xpt_done(ccb); 183557c801f5SMatt Jacob return; 183657c801f5SMatt Jacob } 183757c801f5SMatt Jacob isp->isp_state = ISP_RUNSTATE; 18385d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 183957c801f5SMatt Jacob } 1840b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "isp_action code %x", ccb->ccb_h.func_code); 1841478f8a96SJustin T. Gibbs 18425d571944SMatt Jacob 1843478f8a96SJustin T. Gibbs switch (ccb->ccb_h.func_code) { 1844478f8a96SJustin T. Gibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 1845478f8a96SJustin T. Gibbs /* 1846478f8a96SJustin T. Gibbs * Do a couple of preliminary checks... 1847478f8a96SJustin T. Gibbs */ 1848478f8a96SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { 1849478f8a96SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) { 1850478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 1851478f8a96SJustin T. Gibbs xpt_done(ccb); 1852478f8a96SJustin T. Gibbs break; 1853478f8a96SJustin T. Gibbs } 1854478f8a96SJustin T. Gibbs } 18550470d791SMatt Jacob #ifdef DIAGNOSTIC 18560470d791SMatt Jacob if (ccb->ccb_h.target_id > (ISP_MAX_TARGETS(isp) - 1)) { 1857478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 18580470d791SMatt Jacob } else if (ccb->ccb_h.target_lun > (ISP_MAX_LUNS(isp) - 1)) { 1859478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 1860478f8a96SJustin T. Gibbs } 1861478f8a96SJustin T. Gibbs if (ccb->ccb_h.status == CAM_PATH_INVALID) { 1862bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 1863bfbab170SMatt Jacob "invalid tgt/lun (%d.%d) in XPT_SCSI_IO", 1864bfbab170SMatt Jacob ccb->ccb_h.target_id, ccb->ccb_h.target_lun); 1865478f8a96SJustin T. Gibbs xpt_done(ccb); 1866478f8a96SJustin T. Gibbs break; 1867478f8a96SJustin T. Gibbs } 18680470d791SMatt Jacob #endif 18690470d791SMatt Jacob ((struct ccb_scsiio *) ccb)->scsi_status = SCSI_STATUS_OK; 18705d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 1871b09b0095SMatt Jacob error = isp_start((XS_T *) ccb); 18720470d791SMatt Jacob switch (error) { 1873478f8a96SJustin T. Gibbs case CMD_QUEUED: 1874478f8a96SJustin T. Gibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 1875cc8df88bSMatt Jacob if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { 1876d69a5f7dSMatt Jacob u_int64_t ticks = (u_int64_t) hz; 1877cc8df88bSMatt Jacob if (ccb->ccb_h.timeout == CAM_TIME_DEFAULT) 1878d69a5f7dSMatt Jacob ticks = 60 * 1000 * ticks; 1879b85389e1SMatt Jacob else 1880b85389e1SMatt Jacob ticks = ccb->ccb_h.timeout * hz; 1881b85389e1SMatt Jacob ticks = ((ticks + 999) / 1000) + hz + hz; 1882d69a5f7dSMatt Jacob if (ticks >= 0x80000000) { 1883d69a5f7dSMatt Jacob isp_prt(isp, ISP_LOGERR, 1884d69a5f7dSMatt Jacob "timeout overflow"); 1885d69a5f7dSMatt Jacob ticks = 0x80000000; 1886d69a5f7dSMatt Jacob } 1887d69a5f7dSMatt Jacob ccb->ccb_h.timeout_ch = timeout(isp_watchdog, 1888d69a5f7dSMatt Jacob (caddr_t)ccb, (int)ticks); 1889b85389e1SMatt Jacob } else { 1890b85389e1SMatt Jacob callout_handle_init(&ccb->ccb_h.timeout_ch); 1891cc8df88bSMatt Jacob } 18925d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1893478f8a96SJustin T. Gibbs break; 18940470d791SMatt Jacob case CMD_RQLATER: 1895f44257c2SMatt Jacob /* 1896f44257c2SMatt Jacob * This can only happen for Fibre Channel 1897f44257c2SMatt Jacob */ 1898f44257c2SMatt Jacob KASSERT((IS_FC(isp)), ("CMD_RQLATER for FC only")); 1899f44257c2SMatt Jacob if (FCPARAM(isp)->loop_seen_once == 0 && isp_ktmature) { 1900f44257c2SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1901f44257c2SMatt Jacob XS_SETERR(ccb, CAM_SEL_TIMEOUT); 1902f44257c2SMatt Jacob xpt_done(ccb); 1903f44257c2SMatt Jacob break; 1904f44257c2SMatt Jacob } 19055d571944SMatt Jacob cv_signal(&isp->isp_osinfo.kthread_cv); 19060470d791SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 1907b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1908b09b0095SMatt Jacob "RQLATER freeze simq"); 19095d571944SMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; 19105d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1911478f8a96SJustin T. Gibbs xpt_freeze_simq(sim, 1); 19125d571944SMatt Jacob } else { 19135d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 191400f50ce8SMatt Jacob } 1915b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 1916478f8a96SJustin T. Gibbs xpt_done(ccb); 1917478f8a96SJustin T. Gibbs break; 19180470d791SMatt Jacob case CMD_EAGAIN: 19190470d791SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 19200470d791SMatt Jacob xpt_freeze_simq(sim, 1); 1921b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1922b09b0095SMatt Jacob "EAGAIN freeze simq"); 1923478f8a96SJustin T. Gibbs } 19240470d791SMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_RESOURCE; 1925b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 19265d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1927478f8a96SJustin T. Gibbs xpt_done(ccb); 1928478f8a96SJustin T. Gibbs break; 19290470d791SMatt Jacob case CMD_COMPLETE: 19300470d791SMatt Jacob isp_done((struct ccb_scsiio *) ccb); 19315d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 19320470d791SMatt Jacob break; 19330470d791SMatt Jacob default: 1934bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 1935bfbab170SMatt Jacob "What's this? 0x%x at %d in file %s", 193691f1caa2SMatt Jacob error, __LINE__, __FILE__); 1937b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQ_CMP_ERR); 19380470d791SMatt Jacob xpt_done(ccb); 19395d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1940478f8a96SJustin T. Gibbs } 1941478f8a96SJustin T. Gibbs break; 1942478f8a96SJustin T. Gibbs 1943d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 1944478f8a96SJustin T. Gibbs case XPT_EN_LUN: /* Enable LUN as a target */ 194564edff94SMatt Jacob { 194664edff94SMatt Jacob int iok; 19475d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 194864edff94SMatt Jacob iok = isp->isp_osinfo.intsok; 194964edff94SMatt Jacob isp->isp_osinfo.intsok = 0; 1950d81ba9d5SMatt Jacob isp_en_lun(isp, ccb); 195164edff94SMatt Jacob isp->isp_osinfo.intsok = iok; 19525d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1953478f8a96SJustin T. Gibbs xpt_done(ccb); 1954478f8a96SJustin T. Gibbs break; 195564edff94SMatt Jacob } 1956d81ba9d5SMatt Jacob case XPT_NOTIFY_ACK: /* recycle notify ack */ 1957d81ba9d5SMatt Jacob case XPT_IMMED_NOTIFY: /* Add Immediate Notify Resource */ 1958d81ba9d5SMatt Jacob case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */ 1959d81ba9d5SMatt Jacob { 1960a1bc34c6SMatt Jacob tstate_t *tptr = 1961a1bc34c6SMatt Jacob get_lun_statep(isp, XS_CHANNEL(ccb), ccb->ccb_h.target_lun); 1962d81ba9d5SMatt Jacob if (tptr == NULL) { 1963d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 1964d81ba9d5SMatt Jacob xpt_done(ccb); 1965d81ba9d5SMatt Jacob break; 1966d81ba9d5SMatt Jacob } 1967f48ce188SMatt Jacob ccb->ccb_h.sim_priv.entries[0].field = 0; 1968f48ce188SMatt Jacob ccb->ccb_h.sim_priv.entries[1].ptr = isp; 19695d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 1970d81ba9d5SMatt Jacob if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 1971d81ba9d5SMatt Jacob SLIST_INSERT_HEAD(&tptr->atios, 1972d81ba9d5SMatt Jacob &ccb->ccb_h, sim_links.sle); 1973d81ba9d5SMatt Jacob } else { 1974d81ba9d5SMatt Jacob SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, 1975d81ba9d5SMatt Jacob sim_links.sle); 1976d81ba9d5SMatt Jacob } 1977d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1978d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_INPROG; 19795d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1980d81ba9d5SMatt Jacob break; 1981d81ba9d5SMatt Jacob } 1982d81ba9d5SMatt Jacob case XPT_CONT_TARGET_IO: 1983d81ba9d5SMatt Jacob { 19845d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 1985d81ba9d5SMatt Jacob ccb->ccb_h.status = isp_target_start_ctio(isp, ccb); 1986d81ba9d5SMatt Jacob if (ccb->ccb_h.status != CAM_REQ_INPROG) { 1987d81ba9d5SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 1988d81ba9d5SMatt Jacob xpt_freeze_simq(sim, 1); 1989d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 19903c75bb14SMatt Jacob isp_prt(isp, ISP_LOGINFO, 19913c75bb14SMatt Jacob "XPT_CONT_TARGET_IO freeze simq"); 1992d81ba9d5SMatt Jacob } 1993d81ba9d5SMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_RESOURCE; 1994b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 19955d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1996d81ba9d5SMatt Jacob xpt_done(ccb); 1997d81ba9d5SMatt Jacob } else { 19985d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1999d81ba9d5SMatt Jacob ccb->ccb_h.status |= CAM_SIM_QUEUED; 2000d81ba9d5SMatt Jacob } 2001d81ba9d5SMatt Jacob break; 2002d81ba9d5SMatt Jacob } 2003d81ba9d5SMatt Jacob #endif 2004478f8a96SJustin T. Gibbs case XPT_RESET_DEV: /* BDR the specified SCSI device */ 2005d81ba9d5SMatt Jacob 2006d81ba9d5SMatt Jacob bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path)); 2007d81ba9d5SMatt Jacob tgt = ccb->ccb_h.target_id; 2008d81ba9d5SMatt Jacob tgt |= (bus << 16); 2009d81ba9d5SMatt Jacob 20105d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2011ea6f23cdSMatt Jacob error = isp_control(isp, ISPCTL_RESET_DEV, &tgt); 20125d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2013478f8a96SJustin T. Gibbs if (error) { 2014478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2015478f8a96SJustin T. Gibbs } else { 2016478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2017478f8a96SJustin T. Gibbs } 2018478f8a96SJustin T. Gibbs xpt_done(ccb); 2019478f8a96SJustin T. Gibbs break; 2020478f8a96SJustin T. Gibbs case XPT_ABORT: /* Abort the specified CCB */ 2021d81ba9d5SMatt Jacob { 2022d81ba9d5SMatt Jacob union ccb *accb = ccb->cab.abort_ccb; 20235d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2024d81ba9d5SMatt Jacob switch (accb->ccb_h.func_code) { 2025d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2026d81ba9d5SMatt Jacob case XPT_ACCEPT_TARGET_IO: 2027d81ba9d5SMatt Jacob case XPT_IMMED_NOTIFY: 2028d81ba9d5SMatt Jacob ccb->ccb_h.status = isp_abort_tgt_ccb(isp, ccb); 2029d81ba9d5SMatt Jacob break; 2030d81ba9d5SMatt Jacob case XPT_CONT_TARGET_IO: 2031b09b0095SMatt Jacob isp_prt(isp, ISP_LOGERR, "cannot abort CTIOs yet"); 2032d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_UA_ABORT; 2033d81ba9d5SMatt Jacob break; 2034d81ba9d5SMatt Jacob #endif 2035d81ba9d5SMatt Jacob case XPT_SCSI_IO: 2036478f8a96SJustin T. Gibbs error = isp_control(isp, ISPCTL_ABORT_CMD, ccb); 2037478f8a96SJustin T. Gibbs if (error) { 2038d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_UA_ABORT; 2039478f8a96SJustin T. Gibbs } else { 2040478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2041478f8a96SJustin T. Gibbs } 2042d81ba9d5SMatt Jacob break; 2043d81ba9d5SMatt Jacob default: 2044d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_INVALID; 2045d81ba9d5SMatt Jacob break; 2046d81ba9d5SMatt Jacob } 20475d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2048478f8a96SJustin T. Gibbs xpt_done(ccb); 2049478f8a96SJustin T. Gibbs break; 2050d81ba9d5SMatt Jacob } 2051ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2052ab163f5fSMatt Jacob #define IS_CURRENT_SETTINGS(c) (c->type == CTS_TYPE_CURRENT_SETTINGS) 2053ab163f5fSMatt Jacob #else 2054ab163f5fSMatt Jacob #define IS_CURRENT_SETTINGS(c) (c->flags & CCB_TRANS_CURRENT_SETTINGS) 2055ab163f5fSMatt Jacob #endif 2056478f8a96SJustin T. Gibbs case XPT_SET_TRAN_SETTINGS: /* Nexus Settings */ 2057478f8a96SJustin T. Gibbs cts = &ccb->cts; 20589ce9bdafSMatt Jacob if (!IS_CURRENT_SETTINGS(cts)) { 20599ce9bdafSMatt Jacob ccb->ccb_h.status = CAM_REQ_INVALID; 20609ce9bdafSMatt Jacob xpt_done(ccb); 20619ce9bdafSMatt Jacob break; 20629ce9bdafSMatt Jacob } 2063478f8a96SJustin T. Gibbs tgt = cts->ccb_h.target_id; 20645d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2065ab6c4b31SMatt Jacob if (IS_SCSI(isp)) { 2066ab163f5fSMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2067478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 2068478f8a96SJustin T. Gibbs u_int16_t *dptr; 2069d81ba9d5SMatt Jacob 2070d81ba9d5SMatt Jacob bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 2071478f8a96SJustin T. Gibbs 2072ea6f23cdSMatt Jacob sdp += bus; 2073478f8a96SJustin T. Gibbs /* 20749ce9bdafSMatt Jacob * We always update (internally) from goal_flags 2075478f8a96SJustin T. Gibbs * so any request to change settings just gets 2076478f8a96SJustin T. Gibbs * vectored to that location. 2077478f8a96SJustin T. Gibbs */ 20789ce9bdafSMatt Jacob dptr = &sdp->isp_devparam[tgt].goal_flags; 2079478f8a96SJustin T. Gibbs 2080478f8a96SJustin T. Gibbs /* 2081478f8a96SJustin T. Gibbs * Note that these operations affect the 20829ce9bdafSMatt Jacob * the goal flags (goal_flags)- not 2083478f8a96SJustin T. Gibbs * the current state flags. Then we mark 2084478f8a96SJustin T. Gibbs * things so that the next operation to 2085478f8a96SJustin T. Gibbs * this HBA will cause the update to occur. 2086478f8a96SJustin T. Gibbs */ 2087478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_DISC_VALID) { 2088478f8a96SJustin T. Gibbs if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) { 2089478f8a96SJustin T. Gibbs *dptr |= DPARM_DISC; 2090478f8a96SJustin T. Gibbs } else { 2091478f8a96SJustin T. Gibbs *dptr &= ~DPARM_DISC; 2092478f8a96SJustin T. Gibbs } 2093478f8a96SJustin T. Gibbs } 2094478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_TQ_VALID) { 2095478f8a96SJustin T. Gibbs if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) { 2096478f8a96SJustin T. Gibbs *dptr |= DPARM_TQING; 2097478f8a96SJustin T. Gibbs } else { 2098478f8a96SJustin T. Gibbs *dptr &= ~DPARM_TQING; 2099478f8a96SJustin T. Gibbs } 2100478f8a96SJustin T. Gibbs } 2101478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) { 2102478f8a96SJustin T. Gibbs switch (cts->bus_width) { 2103478f8a96SJustin T. Gibbs case MSG_EXT_WDTR_BUS_16_BIT: 2104478f8a96SJustin T. Gibbs *dptr |= DPARM_WIDE; 2105478f8a96SJustin T. Gibbs break; 2106478f8a96SJustin T. Gibbs default: 2107478f8a96SJustin T. Gibbs *dptr &= ~DPARM_WIDE; 2108478f8a96SJustin T. Gibbs } 2109478f8a96SJustin T. Gibbs } 2110478f8a96SJustin T. Gibbs /* 2111478f8a96SJustin T. Gibbs * Any SYNC RATE of nonzero and SYNC_OFFSET 2112478f8a96SJustin T. Gibbs * of nonzero will cause us to go to the 2113478f8a96SJustin T. Gibbs * selected (from NVRAM) maximum value for 2114478f8a96SJustin T. Gibbs * this device. At a later point, we'll 2115478f8a96SJustin T. Gibbs * allow finer control. 2116478f8a96SJustin T. Gibbs */ 2117478f8a96SJustin T. Gibbs if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) && 2118478f8a96SJustin T. Gibbs (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) && 2119478f8a96SJustin T. Gibbs (cts->sync_offset > 0)) { 2120478f8a96SJustin T. Gibbs *dptr |= DPARM_SYNC; 2121478f8a96SJustin T. Gibbs } else { 2122478f8a96SJustin T. Gibbs *dptr &= ~DPARM_SYNC; 2123478f8a96SJustin T. Gibbs } 2124ab6c4b31SMatt Jacob *dptr |= DPARM_SAFE_DFLT; 2125ab163f5fSMatt Jacob #else 2126ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi = 2127ab163f5fSMatt Jacob &cts->proto_specific.scsi; 2128ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi = 2129ab163f5fSMatt Jacob &cts->xport_specific.spi; 2130ab163f5fSMatt Jacob sdparam *sdp = isp->isp_param; 2131ab163f5fSMatt Jacob u_int16_t *dptr; 2132ab163f5fSMatt Jacob 2133ab163f5fSMatt Jacob bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 2134ab163f5fSMatt Jacob sdp += bus; 2135ab163f5fSMatt Jacob /* 21369ce9bdafSMatt Jacob * We always update (internally) from goal_flags 2137ab163f5fSMatt Jacob * so any request to change settings just gets 2138ab163f5fSMatt Jacob * vectored to that location. 2139ab163f5fSMatt Jacob */ 21409ce9bdafSMatt Jacob dptr = &sdp->isp_devparam[tgt].goal_flags; 2141ab163f5fSMatt Jacob 2142ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_DISC) != 0) { 2143ab163f5fSMatt Jacob if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) 2144ab163f5fSMatt Jacob *dptr |= DPARM_DISC; 2145ab163f5fSMatt Jacob else 2146ab163f5fSMatt Jacob *dptr &= ~DPARM_DISC; 2147ab163f5fSMatt Jacob } 2148ab163f5fSMatt Jacob 2149ab163f5fSMatt Jacob if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 2150ab163f5fSMatt Jacob if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) 2151ab163f5fSMatt Jacob *dptr |= DPARM_TQING; 2152ab163f5fSMatt Jacob else 2153ab163f5fSMatt Jacob *dptr &= ~DPARM_TQING; 2154ab163f5fSMatt Jacob } 2155ab163f5fSMatt Jacob 2156ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 2157ab163f5fSMatt Jacob if (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT) 2158ab163f5fSMatt Jacob *dptr |= DPARM_WIDE; 2159ab163f5fSMatt Jacob else 2160ab163f5fSMatt Jacob *dptr &= ~DPARM_WIDE; 2161ab163f5fSMatt Jacob } 2162ab163f5fSMatt Jacob 2163ab163f5fSMatt Jacob /* 2164ab163f5fSMatt Jacob * XXX: FIX ME 2165ab163f5fSMatt Jacob */ 2166ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) && 21679ce9bdafSMatt Jacob (spi->valid & CTS_SPI_VALID_SYNC_RATE) && 21689ce9bdafSMatt Jacob (spi->sync_period && spi->sync_offset)) { 2169ab163f5fSMatt Jacob *dptr |= DPARM_SYNC; 21709ce9bdafSMatt Jacob /* 21719ce9bdafSMatt Jacob * XXX: CHECK FOR LEGALITY 21729ce9bdafSMatt Jacob */ 21739ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_period = 21749ce9bdafSMatt Jacob spi->sync_period; 21759ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_offset = 21769ce9bdafSMatt Jacob spi->sync_offset; 2177ab163f5fSMatt Jacob } else { 2178ab163f5fSMatt Jacob *dptr &= ~DPARM_SYNC; 2179ab163f5fSMatt Jacob } 2180ab163f5fSMatt Jacob #endif 2181bfbab170SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 21829ce9bdafSMatt Jacob "SET bus %d targ %d to flags %x off %x per %x", 21839ce9bdafSMatt Jacob bus, tgt, sdp->isp_devparam[tgt].goal_flags, 21849ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_offset, 21859ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_period); 2186478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_update = 1; 2187ea6f23cdSMatt Jacob isp->isp_update |= (1 << bus); 2188478f8a96SJustin T. Gibbs } 21895d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2190478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2191478f8a96SJustin T. Gibbs xpt_done(ccb); 2192478f8a96SJustin T. Gibbs break; 2193478f8a96SJustin T. Gibbs case XPT_GET_TRAN_SETTINGS: 2194478f8a96SJustin T. Gibbs cts = &ccb->cts; 2195478f8a96SJustin T. Gibbs tgt = cts->ccb_h.target_id; 2196ab163f5fSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2197ab6c4b31SMatt Jacob if (IS_FC(isp)) { 2198ab163f5fSMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2199478f8a96SJustin T. Gibbs /* 2200478f8a96SJustin T. Gibbs * a lot of normal SCSI things don't make sense. 2201478f8a96SJustin T. Gibbs */ 2202478f8a96SJustin T. Gibbs cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB; 2203478f8a96SJustin T. Gibbs cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2204478f8a96SJustin T. Gibbs /* 2205478f8a96SJustin T. Gibbs * How do you measure the width of a high 2206478f8a96SJustin T. Gibbs * speed serial bus? Well, in bytes. 2207478f8a96SJustin T. Gibbs * 2208478f8a96SJustin T. Gibbs * Offset and period make no sense, though, so we set 2209478f8a96SJustin T. Gibbs * (above) a 'base' transfer speed to be gigabit. 2210478f8a96SJustin T. Gibbs */ 2211478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2212ab163f5fSMatt Jacob #else 2213ab163f5fSMatt Jacob fcparam *fcp = isp->isp_param; 2214ab163f5fSMatt Jacob struct ccb_trans_settings_fc *fc = 2215ab163f5fSMatt Jacob &cts->xport_specific.fc; 2216478f8a96SJustin T. Gibbs 2217ab163f5fSMatt Jacob cts->protocol = PROTO_SCSI; 2218ab163f5fSMatt Jacob cts->protocol_version = SCSI_REV_2; 2219ab163f5fSMatt Jacob cts->transport = XPORT_FC; 2220ab163f5fSMatt Jacob cts->transport_version = 0; 2221ab163f5fSMatt Jacob 2222ab163f5fSMatt Jacob fc->valid = CTS_FC_VALID_SPEED; 222353036e92SMatt Jacob if (fcp->isp_gbspeed == 2) 222453036e92SMatt Jacob fc->bitrate = 200000; 222553036e92SMatt Jacob else 2226ab163f5fSMatt Jacob fc->bitrate = 100000; 2227ab163f5fSMatt Jacob if (tgt > 0 && tgt < MAX_FC_TARG) { 2228ab163f5fSMatt Jacob struct lportdb *lp = &fcp->portdb[tgt]; 2229ab163f5fSMatt Jacob fc->wwnn = lp->node_wwn; 2230ab163f5fSMatt Jacob fc->wwpn = lp->port_wwn; 2231ab163f5fSMatt Jacob fc->port = lp->portid; 2232ab163f5fSMatt Jacob fc->valid |= CTS_FC_VALID_WWNN | 2233ab163f5fSMatt Jacob CTS_FC_VALID_WWPN | CTS_FC_VALID_PORT; 2234ab163f5fSMatt Jacob } 2235ab163f5fSMatt Jacob #endif 2236ab163f5fSMatt Jacob } else { 2237ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2238ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi = 2239ab163f5fSMatt Jacob &cts->proto_specific.scsi; 2240ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi = 2241ab163f5fSMatt Jacob &cts->xport_specific.spi; 2242ab163f5fSMatt Jacob #endif 2243ab163f5fSMatt Jacob sdparam *sdp = isp->isp_param; 2244ab163f5fSMatt Jacob int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 2245ab163f5fSMatt Jacob u_int16_t dval, pval, oval; 2246ab163f5fSMatt Jacob 2247ea6f23cdSMatt Jacob sdp += bus; 2248ab163f5fSMatt Jacob 2249ab163f5fSMatt Jacob if (IS_CURRENT_SETTINGS(cts)) { 225083ae4407SMatt Jacob sdp->isp_devparam[tgt].dev_refresh = 1; 225183ae4407SMatt Jacob isp->isp_update |= (1 << bus); 225283ae4407SMatt Jacob (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, 225383ae4407SMatt Jacob NULL); 22549ce9bdafSMatt Jacob dval = sdp->isp_devparam[tgt].actv_flags; 22559ce9bdafSMatt Jacob oval = sdp->isp_devparam[tgt].actv_offset; 22569ce9bdafSMatt Jacob pval = sdp->isp_devparam[tgt].actv_period; 22574394c92fSMatt Jacob } else { 22589ce9bdafSMatt Jacob dval = sdp->isp_devparam[tgt].nvrm_flags; 22599ce9bdafSMatt Jacob oval = sdp->isp_devparam[tgt].nvrm_offset; 22609ce9bdafSMatt Jacob pval = sdp->isp_devparam[tgt].nvrm_period; 22614394c92fSMatt Jacob } 2262478f8a96SJustin T. Gibbs 2263ab163f5fSMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2264478f8a96SJustin T. Gibbs cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); 2265478f8a96SJustin T. Gibbs 2266478f8a96SJustin T. Gibbs if (dval & DPARM_DISC) { 2267478f8a96SJustin T. Gibbs cts->flags |= CCB_TRANS_DISC_ENB; 2268478f8a96SJustin T. Gibbs } 2269478f8a96SJustin T. Gibbs if (dval & DPARM_TQING) { 2270478f8a96SJustin T. Gibbs cts->flags |= CCB_TRANS_TAG_ENB; 2271478f8a96SJustin T. Gibbs } 2272478f8a96SJustin T. Gibbs if (dval & DPARM_WIDE) { 2273478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2274478f8a96SJustin T. Gibbs } else { 2275478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2276478f8a96SJustin T. Gibbs } 2277478f8a96SJustin T. Gibbs cts->valid = CCB_TRANS_BUS_WIDTH_VALID | 2278478f8a96SJustin T. Gibbs CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2279478f8a96SJustin T. Gibbs 22804394c92fSMatt Jacob if ((dval & DPARM_SYNC) && oval != 0) { 22814394c92fSMatt Jacob cts->sync_period = pval; 22824394c92fSMatt Jacob cts->sync_offset = oval; 2283478f8a96SJustin T. Gibbs cts->valid |= 2284478f8a96SJustin T. Gibbs CCB_TRANS_SYNC_RATE_VALID | 2285478f8a96SJustin T. Gibbs CCB_TRANS_SYNC_OFFSET_VALID; 2286478f8a96SJustin T. Gibbs } 2287ab163f5fSMatt Jacob #else 2288ab163f5fSMatt Jacob cts->protocol = PROTO_SCSI; 2289ab163f5fSMatt Jacob cts->protocol_version = SCSI_REV_2; 2290ab163f5fSMatt Jacob cts->transport = XPORT_SPI; 2291ab163f5fSMatt Jacob cts->transport_version = 2; 2292ab163f5fSMatt Jacob 2293ab163f5fSMatt Jacob scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 2294ab163f5fSMatt Jacob spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 2295ab163f5fSMatt Jacob if (dval & DPARM_DISC) { 2296ab163f5fSMatt Jacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 2297ab163f5fSMatt Jacob } 2298ab163f5fSMatt Jacob if (dval & DPARM_TQING) { 2299ab163f5fSMatt Jacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 2300ab163f5fSMatt Jacob } 23019ce9bdafSMatt Jacob if ((dval & DPARM_SYNC) && oval && pval) { 2302ab163f5fSMatt Jacob spi->sync_offset = oval; 2303ab163f5fSMatt Jacob spi->sync_period = pval; 2304ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 2305ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 2306ab163f5fSMatt Jacob } 2307ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_BUS_WIDTH; 2308ab163f5fSMatt Jacob if (dval & DPARM_WIDE) { 2309ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2310ab163f5fSMatt Jacob } else { 2311ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2312ab163f5fSMatt Jacob } 2313ab163f5fSMatt Jacob if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { 2314ab163f5fSMatt Jacob scsi->valid = CTS_SCSI_VALID_TQ; 2315ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_DISC; 2316ab163f5fSMatt Jacob } else { 2317ab163f5fSMatt Jacob scsi->valid = 0; 2318ab163f5fSMatt Jacob } 2319ab163f5fSMatt Jacob #endif 2320bfbab170SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 23219ce9bdafSMatt Jacob "GET %s bus %d targ %d to flags %x off %x per %x", 23229ce9bdafSMatt Jacob IS_CURRENT_SETTINGS(cts)? "ACTIVE" : "NVRAM", 23239ce9bdafSMatt Jacob bus, tgt, dval, oval, pval); 2324478f8a96SJustin T. Gibbs } 2325ab163f5fSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2326478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2327478f8a96SJustin T. Gibbs xpt_done(ccb); 2328478f8a96SJustin T. Gibbs break; 2329478f8a96SJustin T. Gibbs 2330478f8a96SJustin T. Gibbs case XPT_CALC_GEOMETRY: 2331478f8a96SJustin T. Gibbs { 2332478f8a96SJustin T. Gibbs struct ccb_calc_geometry *ccg; 2333478f8a96SJustin T. Gibbs u_int32_t secs_per_cylinder; 2334478f8a96SJustin T. Gibbs u_int32_t size_mb; 2335478f8a96SJustin T. Gibbs 2336478f8a96SJustin T. Gibbs ccg = &ccb->ccg; 2337478f8a96SJustin T. Gibbs if (ccg->block_size == 0) { 2338bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 2339bfbab170SMatt Jacob "%d.%d XPT_CALC_GEOMETRY block size 0?", 2340bfbab170SMatt Jacob ccg->ccb_h.target_id, ccg->ccb_h.target_lun); 2341478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2342478f8a96SJustin T. Gibbs xpt_done(ccb); 2343478f8a96SJustin T. Gibbs break; 2344478f8a96SJustin T. Gibbs } 2345478f8a96SJustin T. Gibbs size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size); 2346478f8a96SJustin T. Gibbs if (size_mb > 1024) { 2347478f8a96SJustin T. Gibbs ccg->heads = 255; 2348478f8a96SJustin T. Gibbs ccg->secs_per_track = 63; 2349478f8a96SJustin T. Gibbs } else { 2350478f8a96SJustin T. Gibbs ccg->heads = 64; 2351478f8a96SJustin T. Gibbs ccg->secs_per_track = 32; 2352478f8a96SJustin T. Gibbs } 2353478f8a96SJustin T. Gibbs secs_per_cylinder = ccg->heads * ccg->secs_per_track; 2354478f8a96SJustin T. Gibbs ccg->cylinders = ccg->volume_size / secs_per_cylinder; 2355478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2356478f8a96SJustin T. Gibbs xpt_done(ccb); 2357478f8a96SJustin T. Gibbs break; 2358478f8a96SJustin T. Gibbs } 2359478f8a96SJustin T. Gibbs case XPT_RESET_BUS: /* Reset the specified bus */ 2360ab6c4b31SMatt Jacob bus = cam_sim_bus(sim); 23615d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2362ab6c4b31SMatt Jacob error = isp_control(isp, ISPCTL_RESET_BUS, &bus); 23635d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2364478f8a96SJustin T. Gibbs if (error) 2365478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 23662b052931SMatt Jacob else { 2367ea6f23cdSMatt Jacob if (cam_sim_bus(sim) && isp->isp_path2 != NULL) 2368ea6f23cdSMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); 2369ea6f23cdSMatt Jacob else if (isp->isp_path != NULL) 23702b052931SMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path, NULL); 2371478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 23722b052931SMatt Jacob } 2373478f8a96SJustin T. Gibbs xpt_done(ccb); 2374478f8a96SJustin T. Gibbs break; 2375478f8a96SJustin T. Gibbs 2376478f8a96SJustin T. Gibbs case XPT_TERM_IO: /* Terminate the I/O process */ 2377478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2378478f8a96SJustin T. Gibbs xpt_done(ccb); 2379478f8a96SJustin T. Gibbs break; 2380478f8a96SJustin T. Gibbs 2381478f8a96SJustin T. Gibbs case XPT_PATH_INQ: /* Path routing inquiry */ 2382478f8a96SJustin T. Gibbs { 2383478f8a96SJustin T. Gibbs struct ccb_pathinq *cpi = &ccb->cpi; 2384478f8a96SJustin T. Gibbs 2385478f8a96SJustin T. Gibbs cpi->version_num = 1; 2386d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2387a1bc34c6SMatt Jacob cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO; 2388d81ba9d5SMatt Jacob #else 2389478f8a96SJustin T. Gibbs cpi->target_sprt = 0; 2390d81ba9d5SMatt Jacob #endif 2391478f8a96SJustin T. Gibbs cpi->hba_eng_cnt = 0; 23920470d791SMatt Jacob cpi->max_target = ISP_MAX_TARGETS(isp) - 1; 23930470d791SMatt Jacob cpi->max_lun = ISP_MAX_LUNS(isp) - 1; 23940470d791SMatt Jacob cpi->bus_id = cam_sim_bus(sim); 23954394c92fSMatt Jacob if (IS_FC(isp)) { 23964394c92fSMatt Jacob cpi->hba_misc = PIM_NOBUSRESET; 23970470d791SMatt Jacob /* 23980470d791SMatt Jacob * Because our loop ID can shift from time to time, 23990470d791SMatt Jacob * make our initiator ID out of range of our bus. 24000470d791SMatt Jacob */ 24010470d791SMatt Jacob cpi->initiator_id = cpi->max_target + 1; 24020470d791SMatt Jacob 24039deea857SKenneth D. Merry /* 24049deea857SKenneth D. Merry * Set base transfer capabilities for Fibre Channel. 24059deea857SKenneth D. Merry * Technically not correct because we don't know 24069deea857SKenneth D. Merry * what media we're running on top of- but we'll 24079deea857SKenneth D. Merry * look good if we always say 100MB/s. 24089deea857SKenneth D. Merry */ 240953036e92SMatt Jacob if (FCPARAM(isp)->isp_gbspeed == 2) 241053036e92SMatt Jacob cpi->base_transfer_speed = 200000; 241153036e92SMatt Jacob else 24129deea857SKenneth D. Merry cpi->base_transfer_speed = 100000; 24130470d791SMatt Jacob cpi->hba_inquiry = PI_TAG_ABLE; 2414ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2415ab163f5fSMatt Jacob cpi->transport = XPORT_FC; 2416ab163f5fSMatt Jacob cpi->transport_version = 0; /* WHAT'S THIS FOR? */ 2417ab163f5fSMatt Jacob #endif 2418478f8a96SJustin T. Gibbs } else { 2419ea6f23cdSMatt Jacob sdparam *sdp = isp->isp_param; 2420ea6f23cdSMatt Jacob sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path)); 24210470d791SMatt Jacob cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; 24224394c92fSMatt Jacob cpi->hba_misc = 0; 2423ea6f23cdSMatt Jacob cpi->initiator_id = sdp->isp_initiator_id; 24249deea857SKenneth D. Merry cpi->base_transfer_speed = 3300; 2425ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2426ab163f5fSMatt Jacob cpi->transport = XPORT_SPI; 2427ab163f5fSMatt Jacob cpi->transport_version = 2; /* WHAT'S THIS FOR? */ 2428ab163f5fSMatt Jacob #endif 2429478f8a96SJustin T. Gibbs } 2430ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2431ab163f5fSMatt Jacob cpi->protocol = PROTO_SCSI; 2432ab163f5fSMatt Jacob cpi->protocol_version = SCSI_REV_2; 2433ab163f5fSMatt Jacob #endif 2434478f8a96SJustin T. Gibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 2435478f8a96SJustin T. Gibbs strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN); 2436478f8a96SJustin T. Gibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 2437478f8a96SJustin T. Gibbs cpi->unit_number = cam_sim_unit(sim); 2438478f8a96SJustin T. Gibbs cpi->ccb_h.status = CAM_REQ_CMP; 2439478f8a96SJustin T. Gibbs xpt_done(ccb); 2440478f8a96SJustin T. Gibbs break; 2441478f8a96SJustin T. Gibbs } 2442478f8a96SJustin T. Gibbs default: 2443478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2444478f8a96SJustin T. Gibbs xpt_done(ccb); 2445478f8a96SJustin T. Gibbs break; 2446478f8a96SJustin T. Gibbs } 2447478f8a96SJustin T. Gibbs } 2448d3a9eb2eSMatt Jacob 2449d3a9eb2eSMatt Jacob #define ISPDDB (CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB) 2450d3a9eb2eSMatt Jacob void 2451c3055363SMatt Jacob isp_done(struct ccb_scsiio *sccb) 2452d3a9eb2eSMatt Jacob { 2453d3a9eb2eSMatt Jacob struct ispsoftc *isp = XS_ISP(sccb); 2454d3a9eb2eSMatt Jacob 2455d3a9eb2eSMatt Jacob if (XS_NOERR(sccb)) 2456d3a9eb2eSMatt Jacob XS_SETERR(sccb, CAM_REQ_CMP); 2457b85389e1SMatt Jacob 2458d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP && 2459d3a9eb2eSMatt Jacob (sccb->scsi_status != SCSI_STATUS_OK)) { 2460d3a9eb2eSMatt Jacob sccb->ccb_h.status &= ~CAM_STATUS_MASK; 246192a1e549SMatt Jacob if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) && 246292a1e549SMatt Jacob (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) { 246392a1e549SMatt Jacob sccb->ccb_h.status |= CAM_AUTOSENSE_FAIL; 246492a1e549SMatt Jacob } else { 2465d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 2466d3a9eb2eSMatt Jacob } 246792a1e549SMatt Jacob } 2468b85389e1SMatt Jacob 24690470d791SMatt Jacob sccb->ccb_h.status &= ~CAM_SIM_QUEUED; 2470d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2471d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 2472d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_DEV_QFRZN; 24730470d791SMatt Jacob xpt_freeze_devq(sccb->ccb_h.path, 1); 24740470d791SMatt Jacob if (sccb->scsi_status != SCSI_STATUS_OK) 2475b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2476b09b0095SMatt Jacob "freeze devq %d.%d %x %x", 2477b09b0095SMatt Jacob sccb->ccb_h.target_id, 24780470d791SMatt Jacob sccb->ccb_h.target_lun, sccb->ccb_h.status, 2479b09b0095SMatt Jacob sccb->scsi_status); 2480d3a9eb2eSMatt Jacob } 2481d3a9eb2eSMatt Jacob } 2482b85389e1SMatt Jacob 24830470d791SMatt Jacob /* 24840470d791SMatt Jacob * If we were frozen waiting resources, clear that we were frozen 24850470d791SMatt Jacob * waiting for resources. If we are no longer frozen, and the devq 24860470d791SMatt Jacob * isn't frozen, mark the completing CCB to have the XPT layer 24870470d791SMatt Jacob * release the simq. 24880470d791SMatt Jacob */ 248957c801f5SMatt Jacob if (isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE) { 249057c801f5SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_RESOURCE; 24910470d791SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 24920470d791SMatt Jacob if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 2493b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2494b09b0095SMatt Jacob "isp_done->relsimq"); 2495d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_RELEASE_SIMQ; 24960470d791SMatt Jacob } else { 2497b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2498b09b0095SMatt Jacob "isp_done->devq frozen"); 2499d3a9eb2eSMatt Jacob } 25000470d791SMatt Jacob } else { 2501b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2502b09b0095SMatt Jacob "isp_done -> simqfrozen = %x", 2503b09b0095SMatt Jacob isp->isp_osinfo.simqfrozen); 25040470d791SMatt Jacob } 25050470d791SMatt Jacob } 2506b85389e1SMatt Jacob if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) && 2507d3a9eb2eSMatt Jacob (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2508d3a9eb2eSMatt Jacob xpt_print_path(sccb->ccb_h.path); 25093c75bb14SMatt Jacob isp_prt(isp, ISP_LOGINFO, 25103c75bb14SMatt Jacob "cam completion status 0x%x", sccb->ccb_h.status); 2511d3a9eb2eSMatt Jacob } 2512b85389e1SMatt Jacob 2513b85389e1SMatt Jacob XS_CMD_S_DONE(sccb); 2514b85389e1SMatt Jacob if (XS_CMD_WDOG_P(sccb) == 0) { 2515b85389e1SMatt Jacob untimeout(isp_watchdog, (caddr_t)sccb, sccb->ccb_h.timeout_ch); 2516b85389e1SMatt Jacob if (XS_CMD_GRACE_P(sccb)) { 2517b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2518b09b0095SMatt Jacob "finished command on borrowed time"); 2519b85389e1SMatt Jacob } 2520b85389e1SMatt Jacob XS_CMD_S_CLEAR(sccb); 25215d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2522d3a9eb2eSMatt Jacob xpt_done((union ccb *) sccb); 25235d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2524d3a9eb2eSMatt Jacob } 2525b85389e1SMatt Jacob } 2526d3a9eb2eSMatt Jacob 2527cbf57b47SMatt Jacob int 25280470d791SMatt Jacob isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg) 2529cbf57b47SMatt Jacob { 2530ea6f23cdSMatt Jacob int bus, rv = 0; 2531cbf57b47SMatt Jacob switch (cmd) { 2532cbf57b47SMatt Jacob case ISPASYNC_NEW_TGT_PARAMS: 25330470d791SMatt Jacob { 2534ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2535ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi; 2536ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi; 2537ab163f5fSMatt Jacob #endif 2538cbf57b47SMatt Jacob int flags, tgt; 2539cbf57b47SMatt Jacob sdparam *sdp = isp->isp_param; 2540ab163f5fSMatt Jacob struct ccb_trans_settings cts; 2541cbf57b47SMatt Jacob struct cam_path *tmppath; 2542cbf57b47SMatt Jacob 2543ab163f5fSMatt Jacob bzero(&cts, sizeof (struct ccb_trans_settings)); 2544ab163f5fSMatt Jacob 2545cbf57b47SMatt Jacob tgt = *((int *)arg); 2546ea6f23cdSMatt Jacob bus = (tgt >> 16) & 0xffff; 2547ea6f23cdSMatt Jacob tgt &= 0xffff; 2548ea6f23cdSMatt Jacob sdp += bus; 254945c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2550cbf57b47SMatt Jacob if (xpt_create_path(&tmppath, NULL, 2551ea6f23cdSMatt Jacob cam_sim_path(bus? isp->isp_sim2 : isp->isp_sim), 2552ea6f23cdSMatt Jacob tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 255345c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2554bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 2555bfbab170SMatt Jacob "isp_async cannot make temp path for %d.%d", 2556bfbab170SMatt Jacob tgt, bus); 2557cbf57b47SMatt Jacob rv = -1; 2558cbf57b47SMatt Jacob break; 2559cbf57b47SMatt Jacob } 256045c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 25619ce9bdafSMatt Jacob flags = sdp->isp_devparam[tgt].actv_flags; 2562ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2563ab163f5fSMatt Jacob cts.type = CTS_TYPE_CURRENT_SETTINGS; 2564ab163f5fSMatt Jacob cts.protocol = PROTO_SCSI; 2565ab163f5fSMatt Jacob cts.transport = XPORT_SPI; 2566ab163f5fSMatt Jacob 2567ab163f5fSMatt Jacob scsi = &cts.proto_specific.scsi; 2568ab163f5fSMatt Jacob spi = &cts.xport_specific.spi; 2569ab163f5fSMatt Jacob 2570ab163f5fSMatt Jacob if (flags & DPARM_TQING) { 2571ab163f5fSMatt Jacob scsi->valid |= CTS_SCSI_VALID_TQ; 2572ab163f5fSMatt Jacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 2573ab163f5fSMatt Jacob spi->flags |= CTS_SPI_FLAGS_TAG_ENB; 2574ab163f5fSMatt Jacob } 2575ab163f5fSMatt Jacob 2576cbf57b47SMatt Jacob if (flags & DPARM_DISC) { 2577ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_DISC; 2578ab163f5fSMatt Jacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 2579ab163f5fSMatt Jacob } 2580ab163f5fSMatt Jacob spi->flags |= CTS_SPI_VALID_BUS_WIDTH; 2581ab163f5fSMatt Jacob if (flags & DPARM_WIDE) { 2582ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2583ab163f5fSMatt Jacob } else { 2584ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2585ab163f5fSMatt Jacob } 2586ab163f5fSMatt Jacob if (flags & DPARM_SYNC) { 2587ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 2588ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 25899ce9bdafSMatt Jacob spi->sync_period = sdp->isp_devparam[tgt].actv_period; 25909ce9bdafSMatt Jacob spi->sync_offset = sdp->isp_devparam[tgt].actv_offset; 2591ab163f5fSMatt Jacob } 2592ab163f5fSMatt Jacob #else 2593ab163f5fSMatt Jacob cts.flags = CCB_TRANS_CURRENT_SETTINGS; 2594ab163f5fSMatt Jacob cts.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2595ab163f5fSMatt Jacob if (flags & DPARM_DISC) { 2596ab163f5fSMatt Jacob cts.flags |= CCB_TRANS_DISC_ENB; 2597cbf57b47SMatt Jacob } 2598cbf57b47SMatt Jacob if (flags & DPARM_TQING) { 2599ab163f5fSMatt Jacob cts.flags |= CCB_TRANS_TAG_ENB; 2600cbf57b47SMatt Jacob } 2601ab163f5fSMatt Jacob cts.valid |= CCB_TRANS_BUS_WIDTH_VALID; 2602ab163f5fSMatt Jacob cts.bus_width = (flags & DPARM_WIDE)? 2603cbf57b47SMatt Jacob MSG_EXT_WDTR_BUS_8_BIT : MSG_EXT_WDTR_BUS_16_BIT; 26049ce9bdafSMatt Jacob cts.sync_period = sdp->isp_devparam[tgt].actv_period; 26059ce9bdafSMatt Jacob cts.sync_offset = sdp->isp_devparam[tgt].actv_offset; 2606cbf57b47SMatt Jacob if (flags & DPARM_SYNC) { 2607ab163f5fSMatt Jacob cts.valid |= 26084394c92fSMatt Jacob CCB_TRANS_SYNC_RATE_VALID | 2609cbf57b47SMatt Jacob CCB_TRANS_SYNC_OFFSET_VALID; 2610cbf57b47SMatt Jacob } 2611ab163f5fSMatt Jacob #endif 2612b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2613b09b0095SMatt Jacob "NEW_TGT_PARAMS bus %d tgt %d period %x offset %x flags %x", 26149ce9bdafSMatt Jacob bus, tgt, sdp->isp_devparam[tgt].actv_period, 26159ce9bdafSMatt Jacob sdp->isp_devparam[tgt].actv_offset, flags); 2616ab163f5fSMatt Jacob xpt_setup_ccb(&cts.ccb_h, tmppath, 1); 26175d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2618ab163f5fSMatt Jacob xpt_async(AC_TRANSFER_NEG, tmppath, &cts); 2619cbf57b47SMatt Jacob xpt_free_path(tmppath); 2620f44257c2SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2621cbf57b47SMatt Jacob break; 26220470d791SMatt Jacob } 262357c801f5SMatt Jacob case ISPASYNC_BUS_RESET: 2624ea6f23cdSMatt Jacob bus = *((int *)arg); 2625b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected", 2626b09b0095SMatt Jacob bus); 2627ea6f23cdSMatt Jacob if (bus > 0 && isp->isp_path2) { 26285d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2629ea6f23cdSMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); 26305d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2631ea6f23cdSMatt Jacob } else if (isp->isp_path) { 26325d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 263357c801f5SMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path, NULL); 26345d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 263557c801f5SMatt Jacob } 263657c801f5SMatt Jacob break; 26375d571944SMatt Jacob case ISPASYNC_LIP: 26385d571944SMatt Jacob if (isp->isp_path) { 26395d571944SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 26405d571944SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "LIP freeze simq"); 26415d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 26425d571944SMatt Jacob xpt_freeze_simq(isp->isp_sim, 1); 26435d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 26445d571944SMatt Jacob } 26455d571944SMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; 26465d571944SMatt Jacob } 26475d571944SMatt Jacob isp_prt(isp, ISP_LOGINFO, "LIP Received"); 26485d571944SMatt Jacob break; 26495d571944SMatt Jacob case ISPASYNC_LOOP_RESET: 26505d571944SMatt Jacob if (isp->isp_path) { 26515d571944SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 26525d571944SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 26535d571944SMatt Jacob "Loop Reset freeze simq"); 26545d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 26555d571944SMatt Jacob xpt_freeze_simq(isp->isp_sim, 1); 26565d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 26575d571944SMatt Jacob } 26585d571944SMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; 26595d571944SMatt Jacob } 26605d571944SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop Reset Received"); 26615d571944SMatt Jacob break; 266257c801f5SMatt Jacob case ISPASYNC_LOOP_DOWN: 266357c801f5SMatt Jacob if (isp->isp_path) { 26640470d791SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 26655d571944SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 2666b09b0095SMatt Jacob "loop down freeze simq"); 26675d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 266857c801f5SMatt Jacob xpt_freeze_simq(isp->isp_sim, 1); 26695d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 26700470d791SMatt Jacob } 267157c801f5SMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; 267257c801f5SMatt Jacob } 2673b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop DOWN"); 267457c801f5SMatt Jacob break; 267557c801f5SMatt Jacob case ISPASYNC_LOOP_UP: 26765d571944SMatt Jacob /* 26775d571944SMatt Jacob * Now we just note that Loop has come up. We don't 26785d571944SMatt Jacob * actually do anything because we're waiting for a 26795d571944SMatt Jacob * Change Notify before activating the FC cleanup 26805d571944SMatt Jacob * thread to look at the state of the loop again. 26815d571944SMatt Jacob */ 2682b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop UP"); 268357c801f5SMatt Jacob break; 2684d6e5500fSMatt Jacob case ISPASYNC_PROMENADE: 26850470d791SMatt Jacob { 2686ab163f5fSMatt Jacob struct cam_path *tmppath; 2687b09b0095SMatt Jacob const char *fmt = "Target %d (Loop 0x%x) Port ID 0x%x " 2688d6e5500fSMatt Jacob "(role %s) %s\n Port WWN 0x%08x%08x\n Node WWN 0x%08x%08x"; 2689d6e5500fSMatt Jacob static const char *roles[4] = { 26900470d791SMatt Jacob "(none)", "Target", "Initiator", "Target/Initiator" 269157c801f5SMatt Jacob }; 269202ab3379SMatt Jacob fcparam *fcp = isp->isp_param; 269302ab3379SMatt Jacob int tgt = *((int *) arg); 2694f44257c2SMatt Jacob int is_tgt_mask = (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT); 269502ab3379SMatt Jacob struct lportdb *lp = &fcp->portdb[tgt]; 269602ab3379SMatt Jacob 2697b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, fmt, tgt, lp->loopid, lp->portid, 2698d6e5500fSMatt Jacob roles[lp->roles & 0x3], 2699d6e5500fSMatt Jacob (lp->valid)? "Arrived" : "Departed", 270002ab3379SMatt Jacob (u_int32_t) (lp->port_wwn >> 32), 270102ab3379SMatt Jacob (u_int32_t) (lp->port_wwn & 0xffffffffLL), 270202ab3379SMatt Jacob (u_int32_t) (lp->node_wwn >> 32), 270302ab3379SMatt Jacob (u_int32_t) (lp->node_wwn & 0xffffffffLL)); 2704ab163f5fSMatt Jacob 270545c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2706ab163f5fSMatt Jacob if (xpt_create_path(&tmppath, NULL, cam_sim_path(isp->isp_sim), 2707ab163f5fSMatt Jacob (target_id_t)tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 270845c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2709ab163f5fSMatt Jacob break; 2710ab163f5fSMatt Jacob } 2711f44257c2SMatt Jacob /* 2712f44257c2SMatt Jacob * Policy: only announce targets. 2713f44257c2SMatt Jacob */ 2714f44257c2SMatt Jacob if (lp->roles & is_tgt_mask) { 2715f44257c2SMatt Jacob if (lp->valid) { 2716ab163f5fSMatt Jacob xpt_async(AC_FOUND_DEVICE, tmppath, NULL); 2717ab163f5fSMatt Jacob } else { 2718ab163f5fSMatt Jacob xpt_async(AC_LOST_DEVICE, tmppath, NULL); 2719ab163f5fSMatt Jacob } 2720f44257c2SMatt Jacob } 2721ab163f5fSMatt Jacob xpt_free_path(tmppath); 2722f44257c2SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 27234394c92fSMatt Jacob break; 27244394c92fSMatt Jacob } 272557c801f5SMatt Jacob case ISPASYNC_CHANGE_NOTIFY: 2726f44257c2SMatt Jacob if (arg == ISPASYNC_CHANGE_PDB) { 27274b9d588eSMatt Jacob isp_prt(isp, ISP_LOGINFO, 2728f44257c2SMatt Jacob "Port Database Changed"); 2729f44257c2SMatt Jacob } else if (arg == ISPASYNC_CHANGE_SNS) { 27304b9d588eSMatt Jacob isp_prt(isp, ISP_LOGINFO, 27314b9d588eSMatt Jacob "Name Server Database Changed"); 27324b9d588eSMatt Jacob } 27335d571944SMatt Jacob cv_signal(&isp->isp_osinfo.kthread_cv); 273457c801f5SMatt Jacob break; 273502ab3379SMatt Jacob case ISPASYNC_FABRIC_DEV: 273602ab3379SMatt Jacob { 273770d2ccceSMatt Jacob int target, lrange; 273870d2ccceSMatt Jacob struct lportdb *lp = NULL; 273940cfc8feSMatt Jacob char *pt; 274040cfc8feSMatt Jacob sns_ganrsp_t *resp = (sns_ganrsp_t *) arg; 274102ab3379SMatt Jacob u_int32_t portid; 274240cfc8feSMatt Jacob u_int64_t wwpn, wwnn; 274302ab3379SMatt Jacob fcparam *fcp = isp->isp_param; 274402ab3379SMatt Jacob 274502ab3379SMatt Jacob portid = 274602ab3379SMatt Jacob (((u_int32_t) resp->snscb_port_id[0]) << 16) | 274702ab3379SMatt Jacob (((u_int32_t) resp->snscb_port_id[1]) << 8) | 274802ab3379SMatt Jacob (((u_int32_t) resp->snscb_port_id[2])); 274940cfc8feSMatt Jacob 275040cfc8feSMatt Jacob wwpn = 275102ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[0]) << 56) | 275202ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[1]) << 48) | 275302ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[2]) << 40) | 275402ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[3]) << 32) | 275502ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[4]) << 24) | 275602ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[5]) << 16) | 275702ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[6]) << 8) | 275802ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[7])); 275940cfc8feSMatt Jacob 276040cfc8feSMatt Jacob wwnn = 276140cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[0]) << 56) | 276240cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[1]) << 48) | 276340cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[2]) << 40) | 276440cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[3]) << 32) | 276540cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[4]) << 24) | 276640cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[5]) << 16) | 276740cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[6]) << 8) | 276840cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[7])); 276940cfc8feSMatt Jacob if (portid == 0 || wwpn == 0) { 277002ab3379SMatt Jacob break; 277102ab3379SMatt Jacob } 277240cfc8feSMatt Jacob 277340cfc8feSMatt Jacob switch (resp->snscb_port_type) { 277440cfc8feSMatt Jacob case 1: 277540cfc8feSMatt Jacob pt = " N_Port"; 277640cfc8feSMatt Jacob break; 277740cfc8feSMatt Jacob case 2: 277840cfc8feSMatt Jacob pt = " NL_Port"; 277940cfc8feSMatt Jacob break; 278040cfc8feSMatt Jacob case 3: 278140cfc8feSMatt Jacob pt = "F/NL_Port"; 278240cfc8feSMatt Jacob break; 278340cfc8feSMatt Jacob case 0x7f: 278440cfc8feSMatt Jacob pt = " Nx_Port"; 278540cfc8feSMatt Jacob break; 278640cfc8feSMatt Jacob case 0x81: 278740cfc8feSMatt Jacob pt = " F_port"; 278840cfc8feSMatt Jacob break; 278940cfc8feSMatt Jacob case 0x82: 279040cfc8feSMatt Jacob pt = " FL_Port"; 279140cfc8feSMatt Jacob break; 279240cfc8feSMatt Jacob case 0x84: 279340cfc8feSMatt Jacob pt = " E_port"; 279440cfc8feSMatt Jacob break; 279540cfc8feSMatt Jacob default: 279640cfc8feSMatt Jacob pt = "?"; 279740cfc8feSMatt Jacob break; 279840cfc8feSMatt Jacob } 2799b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, 2800b09b0095SMatt Jacob "%s @ 0x%x, Node 0x%08x%08x Port %08x%08x", 2801b09b0095SMatt Jacob pt, portid, ((u_int32_t) (wwnn >> 32)), ((u_int32_t) wwnn), 280240cfc8feSMatt Jacob ((u_int32_t) (wwpn >> 32)), ((u_int32_t) wwpn)); 280370d2ccceSMatt Jacob /* 280470d2ccceSMatt Jacob * We're only interested in SCSI_FCP types (for now) 280570d2ccceSMatt Jacob */ 280670d2ccceSMatt Jacob if ((resp->snscb_fc4_types[2] & 1) == 0) { 280702ab3379SMatt Jacob break; 280802ab3379SMatt Jacob } 280970d2ccceSMatt Jacob if (fcp->isp_topo != TOPO_F_PORT) 281070d2ccceSMatt Jacob lrange = FC_SNS_ID+1; 281170d2ccceSMatt Jacob else 281270d2ccceSMatt Jacob lrange = 0; 281370d2ccceSMatt Jacob /* 281470d2ccceSMatt Jacob * Is it already in our list? 281570d2ccceSMatt Jacob */ 281670d2ccceSMatt Jacob for (target = lrange; target < MAX_FC_TARG; target++) { 281770d2ccceSMatt Jacob if (target >= FL_PORT_ID && target <= FC_SNS_ID) { 281870d2ccceSMatt Jacob continue; 281970d2ccceSMatt Jacob } 282070d2ccceSMatt Jacob lp = &fcp->portdb[target]; 282170d2ccceSMatt Jacob if (lp->port_wwn == wwpn && lp->node_wwn == wwnn) { 282270d2ccceSMatt Jacob lp->fabric_dev = 1; 282370d2ccceSMatt Jacob break; 282470d2ccceSMatt Jacob } 282570d2ccceSMatt Jacob } 282602ab3379SMatt Jacob if (target < MAX_FC_TARG) { 282702ab3379SMatt Jacob break; 282802ab3379SMatt Jacob } 282970d2ccceSMatt Jacob for (target = lrange; target < MAX_FC_TARG; target++) { 283070d2ccceSMatt Jacob if (target >= FL_PORT_ID && target <= FC_SNS_ID) { 283170d2ccceSMatt Jacob continue; 283270d2ccceSMatt Jacob } 283302ab3379SMatt Jacob lp = &fcp->portdb[target]; 283470d2ccceSMatt Jacob if (lp->port_wwn == 0) { 283502ab3379SMatt Jacob break; 283602ab3379SMatt Jacob } 283770d2ccceSMatt Jacob } 283802ab3379SMatt Jacob if (target == MAX_FC_TARG) { 2839bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 2840bfbab170SMatt Jacob "no more space for fabric devices"); 284102ab3379SMatt Jacob break; 284202ab3379SMatt Jacob } 284340cfc8feSMatt Jacob lp->node_wwn = wwnn; 284440cfc8feSMatt Jacob lp->port_wwn = wwpn; 284502ab3379SMatt Jacob lp->portid = portid; 284670d2ccceSMatt Jacob lp->fabric_dev = 1; 284702ab3379SMatt Jacob break; 284802ab3379SMatt Jacob } 2849d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2850d81ba9d5SMatt Jacob case ISPASYNC_TARGET_MESSAGE: 2851d81ba9d5SMatt Jacob { 2852d81ba9d5SMatt Jacob tmd_msg_t *mp = arg; 285364edff94SMatt Jacob isp_prt(isp, ISP_LOGALL, 2854b09b0095SMatt Jacob "bus %d iid %d tgt %d lun %d ttype %x tval %x msg[0]=%x", 2855b09b0095SMatt Jacob mp->nt_bus, (int) mp->nt_iid, (int) mp->nt_tgt, 2856b09b0095SMatt Jacob (int) mp->nt_lun, mp->nt_tagtype, mp->nt_tagval, 2857b09b0095SMatt Jacob mp->nt_msg[0]); 2858d81ba9d5SMatt Jacob break; 2859d81ba9d5SMatt Jacob } 2860d81ba9d5SMatt Jacob case ISPASYNC_TARGET_EVENT: 2861d81ba9d5SMatt Jacob { 2862d81ba9d5SMatt Jacob tmd_event_t *ep = arg; 286364edff94SMatt Jacob isp_prt(isp, ISP_LOGALL, 2864b09b0095SMatt Jacob "bus %d event code 0x%x", ep->ev_bus, ep->ev_event); 2865d81ba9d5SMatt Jacob break; 2866d81ba9d5SMatt Jacob } 2867d81ba9d5SMatt Jacob case ISPASYNC_TARGET_ACTION: 2868d81ba9d5SMatt Jacob switch (((isphdr_t *)arg)->rqs_entry_type) { 2869cbf57b47SMatt Jacob default: 2870bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 2871bfbab170SMatt Jacob "event 0x%x for unhandled target action", 2872bfbab170SMatt Jacob ((isphdr_t *)arg)->rqs_entry_type); 2873d81ba9d5SMatt Jacob break; 2874d81ba9d5SMatt Jacob case RQSTYPE_ATIO: 2875d81ba9d5SMatt Jacob rv = isp_handle_platform_atio(isp, (at_entry_t *) arg); 2876d81ba9d5SMatt Jacob break; 2877d81ba9d5SMatt Jacob case RQSTYPE_ATIO2: 2878d81ba9d5SMatt Jacob rv = isp_handle_platform_atio2(isp, (at2_entry_t *)arg); 2879d81ba9d5SMatt Jacob break; 2880d81ba9d5SMatt Jacob case RQSTYPE_CTIO2: 2881d81ba9d5SMatt Jacob case RQSTYPE_CTIO: 2882d81ba9d5SMatt Jacob rv = isp_handle_platform_ctio(isp, arg); 2883d81ba9d5SMatt Jacob break; 2884d81ba9d5SMatt Jacob case RQSTYPE_ENABLE_LUN: 2885d81ba9d5SMatt Jacob case RQSTYPE_MODIFY_LUN: 288664edff94SMatt Jacob if (IS_DUALBUS(isp)) { 288764edff94SMatt Jacob bus = 288864edff94SMatt Jacob GET_BUS_VAL(((lun_entry_t *)arg)->le_rsvd); 288964edff94SMatt Jacob } else { 289064edff94SMatt Jacob bus = 0; 289164edff94SMatt Jacob } 289264edff94SMatt Jacob isp_cv_signal_rqe(isp, bus, 289364edff94SMatt Jacob ((lun_entry_t *)arg)->le_status); 2894d81ba9d5SMatt Jacob break; 2895d81ba9d5SMatt Jacob } 2896d81ba9d5SMatt Jacob break; 2897d81ba9d5SMatt Jacob #endif 2898ab163f5fSMatt Jacob case ISPASYNC_FW_CRASH: 2899ab163f5fSMatt Jacob { 2900ab163f5fSMatt Jacob u_int16_t mbox1, mbox6; 2901ab163f5fSMatt Jacob mbox1 = ISP_READ(isp, OUTMAILBOX1); 2902ab163f5fSMatt Jacob if (IS_DUALBUS(isp)) { 2903ab163f5fSMatt Jacob mbox6 = ISP_READ(isp, OUTMAILBOX6); 2904ab163f5fSMatt Jacob } else { 2905ab163f5fSMatt Jacob mbox6 = 0; 2906ab163f5fSMatt Jacob } 2907ab163f5fSMatt Jacob isp_prt(isp, ISP_LOGERR, 2908ab163f5fSMatt Jacob "Internal Firmware on bus %d Error @ RISC Address 0x%x", 2909ab163f5fSMatt Jacob mbox6, mbox1); 2910ab163f5fSMatt Jacob isp_reinit(isp); 2911ab163f5fSMatt Jacob break; 2912ab163f5fSMatt Jacob } 2913be534d5fSMatt Jacob case ISPASYNC_UNHANDLED_RESPONSE: 2914be534d5fSMatt Jacob break; 2915d81ba9d5SMatt Jacob default: 2916b09b0095SMatt Jacob isp_prt(isp, ISP_LOGERR, "unknown isp_async event %d", cmd); 2917cbf57b47SMatt Jacob break; 2918cbf57b47SMatt Jacob } 2919cbf57b47SMatt Jacob return (rv); 2920cbf57b47SMatt Jacob } 2921cbf57b47SMatt Jacob 292292718a7fSMatt Jacob 292392718a7fSMatt Jacob /* 292492718a7fSMatt Jacob * Locks are held before coming here. 292592718a7fSMatt Jacob */ 292692718a7fSMatt Jacob void 292792718a7fSMatt Jacob isp_uninit(struct ispsoftc *isp) 292892718a7fSMatt Jacob { 2929ea6f23cdSMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_RESET); 293092718a7fSMatt Jacob DISABLE_INTS(isp); 293192718a7fSMatt Jacob } 2932b09b0095SMatt Jacob 2933b09b0095SMatt Jacob void 2934b09b0095SMatt Jacob isp_prt(struct ispsoftc *isp, int level, const char *fmt, ...) 2935b09b0095SMatt Jacob { 2936b09b0095SMatt Jacob va_list ap; 2937b09b0095SMatt Jacob if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) { 2938b09b0095SMatt Jacob return; 2939b09b0095SMatt Jacob } 29403c75bb14SMatt Jacob printf("%s: ", device_get_nameunit(isp->isp_dev)); 2941b09b0095SMatt Jacob va_start(ap, fmt); 2942b09b0095SMatt Jacob vprintf(fmt, ap); 2943b09b0095SMatt Jacob va_end(ap); 2944b09b0095SMatt Jacob printf("\n"); 2945b09b0095SMatt Jacob } 2946