1098ca2bdSWarner Losh /*- 26054c3f6SMatt Jacob * Platform (FreeBSD) dependent common attachment code for Qlogic adapters. 36054c3f6SMatt Jacob * 4e5265237SMatt Jacob * Copyright (c) 1997-2006 by Matthew Jacob 5e5265237SMatt Jacob * All rights reserved. 66054c3f6SMatt Jacob * 76054c3f6SMatt Jacob * Redistribution and use in source and binary forms, with or without 86054c3f6SMatt Jacob * modification, are permitted provided that the following conditions 96054c3f6SMatt Jacob * are met: 106054c3f6SMatt Jacob * 1. Redistributions of source code must retain the above copyright 116054c3f6SMatt Jacob * notice immediately at the beginning of the file, without modification, 126054c3f6SMatt Jacob * this list of conditions, and the following disclaimer. 13aa57fd6fSMatt Jacob * 2. The name of the author may not be used to endorse or promote products 14aa57fd6fSMatt Jacob * derived from this software without specific prior written permission. 156054c3f6SMatt Jacob * 166054c3f6SMatt Jacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 176054c3f6SMatt Jacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 186054c3f6SMatt Jacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 196054c3f6SMatt Jacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 206054c3f6SMatt Jacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 216054c3f6SMatt Jacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 226054c3f6SMatt Jacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 236054c3f6SMatt Jacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 246054c3f6SMatt Jacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 256054c3f6SMatt Jacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 266054c3f6SMatt Jacob * SUCH DAMAGE. 276054c3f6SMatt Jacob */ 28aad970f1SDavid E. O'Brien 29aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 30aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 31aad970f1SDavid E. O'Brien 326054c3f6SMatt Jacob #include <dev/isp/isp_freebsd.h> 335d571944SMatt Jacob #include <sys/unistd.h> 345d571944SMatt Jacob #include <sys/kthread.h> 353ea883b4SMatt Jacob #include <machine/stdarg.h> /* for use by isp_prt below */ 365d571944SMatt Jacob #include <sys/conf.h> 374eb49427SMatt Jacob #include <sys/module.h> 385d571944SMatt Jacob #include <sys/ioccom.h> 395d571944SMatt Jacob #include <dev/isp/isp_ioctl.h> 406054c3f6SMatt Jacob 41a1bc34c6SMatt Jacob 424eb49427SMatt Jacob MODULE_VERSION(isp, 1); 4356c5b842SMark Murray MODULE_DEPEND(isp, cam, 1, 1, 1); 4473030e03SMatt Jacob int isp_announced = 0; 4573030e03SMatt Jacob ispfwfunc *isp_get_firmware_p = NULL; 4673030e03SMatt Jacob 475d571944SMatt Jacob static d_ioctl_t ispioctl; 48f6e75de2SMatt Jacob static void isp_intr_enable(void *); 491dae40ebSMatt Jacob static void isp_cam_async(void *, uint32_t, struct cam_path *, void *); 500470d791SMatt Jacob static void isp_poll(struct cam_sim *); 51b85389e1SMatt Jacob static timeout_t isp_watchdog; 525d571944SMatt Jacob static void isp_kthread(void *); 53d81ba9d5SMatt Jacob static void isp_action(struct cam_sim *, union ccb *); 540470d791SMatt Jacob 55cc8df88bSMatt Jacob 569cd7268eSMatt Jacob #if __FreeBSD_version < 500000 579cd7268eSMatt Jacob #define ISP_CDEV_MAJOR 248 589cd7268eSMatt Jacob static struct cdevsw isp_cdevsw = { 599cd7268eSMatt Jacob /* open */ nullopen, 609cd7268eSMatt Jacob /* close */ nullclose, 619cd7268eSMatt Jacob /* read */ noread, 629cd7268eSMatt Jacob /* write */ nowrite, 639cd7268eSMatt Jacob /* ioctl */ ispioctl, 649cd7268eSMatt Jacob /* poll */ nopoll, 659cd7268eSMatt Jacob /* mmap */ nommap, 669cd7268eSMatt Jacob /* strategy */ nostrategy, 679cd7268eSMatt Jacob /* name */ "isp", 689cd7268eSMatt Jacob /* maj */ ISP_CDEV_MAJOR, 699cd7268eSMatt Jacob /* dump */ nodump, 709cd7268eSMatt Jacob /* psize */ nopsize, 719cd7268eSMatt Jacob /* flags */ D_TAPE, 729cd7268eSMatt Jacob }; 739cd7268eSMatt Jacob #else 745d571944SMatt Jacob static struct cdevsw isp_cdevsw = { 75dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 76dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, 777ac40f5fSPoul-Henning Kamp .d_ioctl = ispioctl, 787ac40f5fSPoul-Henning Kamp .d_name = "isp", 795d571944SMatt Jacob }; 809cd7268eSMatt Jacob #endif 815d571944SMatt Jacob 829cd7268eSMatt Jacob static ispsoftc_t *isplist = NULL; 83478f8a96SJustin T. Gibbs 84478f8a96SJustin T. Gibbs void 859cd7268eSMatt Jacob isp_attach(ispsoftc_t *isp) 86478f8a96SJustin T. Gibbs { 87ea6f23cdSMatt Jacob int primary, secondary; 88478f8a96SJustin T. Gibbs struct ccb_setasync csa; 89478f8a96SJustin T. Gibbs struct cam_devq *devq; 90ea6f23cdSMatt Jacob struct cam_sim *sim; 91ea6f23cdSMatt Jacob struct cam_path *path; 92478f8a96SJustin T. Gibbs 93478f8a96SJustin T. Gibbs /* 94ea6f23cdSMatt Jacob * Establish (in case of 12X0) which bus is the primary. 95ea6f23cdSMatt Jacob */ 96ea6f23cdSMatt Jacob 97ea6f23cdSMatt Jacob primary = 0; 98ea6f23cdSMatt Jacob secondary = 1; 99ea6f23cdSMatt Jacob 100ea6f23cdSMatt Jacob /* 101ea6f23cdSMatt Jacob * Create the device queue for our SIM(s). 102478f8a96SJustin T. Gibbs */ 103ab6c4b31SMatt Jacob devq = cam_simq_alloc(isp->isp_maxcmds); 104478f8a96SJustin T. Gibbs if (devq == NULL) { 105478f8a96SJustin T. Gibbs return; 106478f8a96SJustin T. Gibbs } 107478f8a96SJustin T. Gibbs 108478f8a96SJustin T. Gibbs /* 109ea6f23cdSMatt Jacob * Construct our SIM entry. 110478f8a96SJustin T. Gibbs */ 11145c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 112ea6f23cdSMatt Jacob sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp, 1133c75bb14SMatt Jacob device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq); 114ea6f23cdSMatt Jacob if (sim == NULL) { 115478f8a96SJustin T. Gibbs cam_simq_free(devq); 11645c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 117478f8a96SJustin T. Gibbs return; 118478f8a96SJustin T. Gibbs } 11945c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 120f6e75de2SMatt Jacob 121f6e75de2SMatt Jacob isp->isp_osinfo.ehook.ich_func = isp_intr_enable; 122f6e75de2SMatt Jacob isp->isp_osinfo.ehook.ich_arg = isp; 12345c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 124f6e75de2SMatt Jacob if (config_intrhook_establish(&isp->isp_osinfo.ehook) != 0) { 12545c9a36aSMatt Jacob cam_sim_free(sim, TRUE); 12645c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 127bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 128bfbab170SMatt Jacob "could not establish interrupt enable hook"); 129f6e75de2SMatt Jacob return; 130f6e75de2SMatt Jacob } 131f6e75de2SMatt Jacob 132ea6f23cdSMatt Jacob if (xpt_bus_register(sim, primary) != CAM_SUCCESS) { 133ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 13445c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 135478f8a96SJustin T. Gibbs return; 136478f8a96SJustin T. Gibbs } 137478f8a96SJustin T. Gibbs 138ea6f23cdSMatt Jacob if (xpt_create_path(&path, NULL, cam_sim_path(sim), 139478f8a96SJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 140ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 141ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 1425d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 14345c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 144478f8a96SJustin T. Gibbs return; 145478f8a96SJustin T. Gibbs } 146478f8a96SJustin T. Gibbs 147ea6f23cdSMatt Jacob xpt_setup_ccb(&csa.ccb_h, path, 5); 148478f8a96SJustin T. Gibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 149478f8a96SJustin T. Gibbs csa.event_enable = AC_LOST_DEVICE; 150cbf57b47SMatt Jacob csa.callback = isp_cam_async; 151ea6f23cdSMatt Jacob csa.callback_arg = sim; 152478f8a96SJustin T. Gibbs xpt_action((union ccb *)&csa); 15345c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 154ea6f23cdSMatt Jacob isp->isp_sim = sim; 155ea6f23cdSMatt Jacob isp->isp_path = path; 1565d571944SMatt Jacob /* 1575d571944SMatt Jacob * Create a kernel thread for fibre channel instances. We 1585d571944SMatt Jacob * don't have dual channel FC cards. 1595d571944SMatt Jacob */ 1605d571944SMatt Jacob if (IS_FC(isp)) { 16145c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1629cd7268eSMatt Jacob #if __FreeBSD_version >= 500000 16345c9a36aSMatt Jacob /* XXX: LOCK VIOLATION */ 1645d571944SMatt Jacob cv_init(&isp->isp_osinfo.kthread_cv, "isp_kthread_cv"); 1655d571944SMatt Jacob if (kthread_create(isp_kthread, isp, &isp->isp_osinfo.kproc, 166316ec49aSScott Long RFHIGHPID, 0, "%s: fc_thrd", 1679cd7268eSMatt Jacob device_get_nameunit(isp->isp_dev))) 1689cd7268eSMatt Jacob #else 1699cd7268eSMatt Jacob if (kthread_create(isp_kthread, isp, &isp->isp_osinfo.kproc, 1709cd7268eSMatt Jacob "%s: fc_thrd", device_get_nameunit(isp->isp_dev))) 1719cd7268eSMatt Jacob #endif 1729cd7268eSMatt Jacob { 1735d571944SMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 1745d571944SMatt Jacob cam_sim_free(sim, TRUE); 1755d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 17645c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 17745c9a36aSMatt Jacob isp_prt(isp, ISP_LOGERR, "could not create kthread"); 1785d571944SMatt Jacob return; 1795d571944SMatt Jacob } 1808e6a12fcSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 1815d571944SMatt Jacob } 1825d571944SMatt Jacob 183478f8a96SJustin T. Gibbs 184ea6f23cdSMatt Jacob /* 185ea6f23cdSMatt Jacob * If we have a second channel, construct SIM entry for that. 186ea6f23cdSMatt Jacob */ 18722e1dc85SMatt Jacob if (IS_DUALBUS(isp)) { 18845c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 189ea6f23cdSMatt Jacob sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp, 1903c75bb14SMatt Jacob device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq); 191ea6f23cdSMatt Jacob if (sim == NULL) { 192ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 193ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 194ea6f23cdSMatt Jacob cam_simq_free(devq); 1955d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 196ea6f23cdSMatt Jacob return; 197ea6f23cdSMatt Jacob } 198ea6f23cdSMatt Jacob if (xpt_bus_register(sim, secondary) != CAM_SUCCESS) { 199ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 200ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 201ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 2025d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 20345c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 204ea6f23cdSMatt Jacob return; 205ea6f23cdSMatt Jacob } 206ea6f23cdSMatt Jacob 207ea6f23cdSMatt Jacob if (xpt_create_path(&path, NULL, cam_sim_path(sim), 208ea6f23cdSMatt Jacob CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 209ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 210ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 211ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 212ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 2135d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 21445c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 215ea6f23cdSMatt Jacob return; 216ea6f23cdSMatt Jacob } 217ea6f23cdSMatt Jacob 218ea6f23cdSMatt Jacob xpt_setup_ccb(&csa.ccb_h, path, 5); 219ea6f23cdSMatt Jacob csa.ccb_h.func_code = XPT_SASYNC_CB; 220ea6f23cdSMatt Jacob csa.event_enable = AC_LOST_DEVICE; 221ea6f23cdSMatt Jacob csa.callback = isp_cam_async; 222ea6f23cdSMatt Jacob csa.callback_arg = sim; 223ea6f23cdSMatt Jacob xpt_action((union ccb *)&csa); 22445c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 225ea6f23cdSMatt Jacob isp->isp_sim2 = sim; 226ea6f23cdSMatt Jacob isp->isp_path2 = path; 227ea6f23cdSMatt Jacob } 2285d571944SMatt Jacob 2295d571944SMatt Jacob /* 2305d571944SMatt Jacob * Create device nodes 2315d571944SMatt Jacob */ 2325d571944SMatt Jacob (void) make_dev(&isp_cdevsw, device_get_unit(isp->isp_dev), UID_ROOT, 2335d571944SMatt Jacob GID_OPERATOR, 0600, "%s", device_get_nameunit(isp->isp_dev)); 2345d571944SMatt Jacob 235d6e5500fSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE) { 236478f8a96SJustin T. Gibbs isp->isp_state = ISP_RUNSTATE; 237b85389e1SMatt Jacob ENABLE_INTS(isp); 238d6e5500fSMatt Jacob } 239d81ba9d5SMatt Jacob if (isplist == NULL) { 240d81ba9d5SMatt Jacob isplist = isp; 241d81ba9d5SMatt Jacob } else { 2429cd7268eSMatt Jacob ispsoftc_t *tmp = isplist; 243d81ba9d5SMatt Jacob while (tmp->isp_osinfo.next) { 244d81ba9d5SMatt Jacob tmp = tmp->isp_osinfo.next; 245d81ba9d5SMatt Jacob } 246d81ba9d5SMatt Jacob tmp->isp_osinfo.next = isp; 247478f8a96SJustin T. Gibbs } 2485d571944SMatt Jacob 2495d571944SMatt Jacob } 2505d571944SMatt Jacob 25153af7d22SMatt Jacob static __inline void 2529cd7268eSMatt Jacob isp_freeze_loopdown(ispsoftc_t *isp, char *msg) 253fdeb9f2fSMatt Jacob { 254fdeb9f2fSMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 255fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "%s: freeze simq (loopdown)", msg); 256fdeb9f2fSMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; 257fdeb9f2fSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 258fdeb9f2fSMatt Jacob xpt_freeze_simq(isp->isp_sim, 1); 259fdeb9f2fSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 260fdeb9f2fSMatt Jacob } else { 261fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "%s: mark frozen (loopdown)", msg); 262fdeb9f2fSMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; 263fdeb9f2fSMatt Jacob } 264fdeb9f2fSMatt Jacob } 265fdeb9f2fSMatt Jacob 2669cd7268eSMatt Jacob 2679cd7268eSMatt Jacob #if __FreeBSD_version < 500000 2689cd7268eSMatt Jacob #define _DEV dev_t 2699cd7268eSMatt Jacob #define _IOP struct proc 2709cd7268eSMatt Jacob #else 2719cd7268eSMatt Jacob #define _IOP struct thread 2729cd7268eSMatt Jacob #define _DEV struct cdev * 2739cd7268eSMatt Jacob #endif 2749cd7268eSMatt Jacob 2755d571944SMatt Jacob static int 2769cd7268eSMatt Jacob ispioctl(_DEV dev, u_long c, caddr_t addr, int flags, _IOP *td) 2775d571944SMatt Jacob { 2789cd7268eSMatt Jacob ispsoftc_t *isp; 279746e9c85SMatt Jacob int nr, retval = ENOTTY; 2805d571944SMatt Jacob 2815d571944SMatt Jacob isp = isplist; 2825d571944SMatt Jacob while (isp) { 2835d571944SMatt Jacob if (minor(dev) == device_get_unit(isp->isp_dev)) { 2845d571944SMatt Jacob break; 2855d571944SMatt Jacob } 2865d571944SMatt Jacob isp = isp->isp_osinfo.next; 2875d571944SMatt Jacob } 2885d571944SMatt Jacob if (isp == NULL) 2895d571944SMatt Jacob return (ENXIO); 2905d571944SMatt Jacob 291c1504bc0SMatt Jacob switch (c) { 292d134aa0bSMatt Jacob #ifdef ISP_FW_CRASH_DUMP 293d134aa0bSMatt Jacob case ISP_GET_FW_CRASH_DUMP: 294d134aa0bSMatt Jacob { 2951dae40ebSMatt Jacob uint16_t *ptr = FCPARAM(isp)->isp_dump_data; 296d134aa0bSMatt Jacob size_t sz; 297d134aa0bSMatt Jacob 298d134aa0bSMatt Jacob retval = 0; 299d134aa0bSMatt Jacob if (IS_2200(isp)) 300d134aa0bSMatt Jacob sz = QLA2200_RISC_IMAGE_DUMP_SIZE; 301d134aa0bSMatt Jacob else 302d134aa0bSMatt Jacob sz = QLA2300_RISC_IMAGE_DUMP_SIZE; 303d134aa0bSMatt Jacob ISP_LOCK(isp); 304d134aa0bSMatt Jacob if (ptr && *ptr) { 305d134aa0bSMatt Jacob void *uaddr = *((void **) addr); 306d134aa0bSMatt Jacob if (copyout(ptr, uaddr, sz)) { 307d134aa0bSMatt Jacob retval = EFAULT; 308d134aa0bSMatt Jacob } else { 309d134aa0bSMatt Jacob *ptr = 0; 310d134aa0bSMatt Jacob } 311d134aa0bSMatt Jacob } else { 312d134aa0bSMatt Jacob retval = ENXIO; 313d134aa0bSMatt Jacob } 314d134aa0bSMatt Jacob ISP_UNLOCK(isp); 315d134aa0bSMatt Jacob break; 316d134aa0bSMatt Jacob } 317d134aa0bSMatt Jacob 318d134aa0bSMatt Jacob case ISP_FORCE_CRASH_DUMP: 319d134aa0bSMatt Jacob ISP_LOCK(isp); 320fdeb9f2fSMatt Jacob isp_freeze_loopdown(isp, "ispioctl(ISP_FORCE_CRASH_DUMP)"); 321d134aa0bSMatt Jacob isp_fw_dump(isp); 322d134aa0bSMatt Jacob isp_reinit(isp); 323d134aa0bSMatt Jacob ISP_UNLOCK(isp); 324d134aa0bSMatt Jacob retval = 0; 325d134aa0bSMatt Jacob break; 326d134aa0bSMatt Jacob #endif 3275d571944SMatt Jacob case ISP_SDBLEV: 3285d571944SMatt Jacob { 3295d571944SMatt Jacob int olddblev = isp->isp_dblev; 3305d571944SMatt Jacob isp->isp_dblev = *(int *)addr; 3315d571944SMatt Jacob *(int *)addr = olddblev; 3325d571944SMatt Jacob retval = 0; 3335d571944SMatt Jacob break; 3345d571944SMatt Jacob } 335746e9c85SMatt Jacob case ISP_GETROLE: 336746e9c85SMatt Jacob *(int *)addr = isp->isp_role; 337746e9c85SMatt Jacob retval = 0; 338746e9c85SMatt Jacob break; 339746e9c85SMatt Jacob case ISP_SETROLE: 340746e9c85SMatt Jacob nr = *(int *)addr; 341746e9c85SMatt Jacob if (nr & ~(ISP_ROLE_INITIATOR|ISP_ROLE_TARGET)) { 342746e9c85SMatt Jacob retval = EINVAL; 343746e9c85SMatt Jacob break; 344746e9c85SMatt Jacob } 345746e9c85SMatt Jacob *(int *)addr = isp->isp_role; 346746e9c85SMatt Jacob isp->isp_role = nr; 347746e9c85SMatt Jacob /* FALLTHROUGH */ 3485d571944SMatt Jacob case ISP_RESETHBA: 3495d571944SMatt Jacob ISP_LOCK(isp); 3505d571944SMatt Jacob isp_reinit(isp); 3515d571944SMatt Jacob ISP_UNLOCK(isp); 3525d571944SMatt Jacob retval = 0; 3535d571944SMatt Jacob break; 354f553351eSMatt Jacob case ISP_RESCAN: 3555d571944SMatt Jacob if (IS_FC(isp)) { 3565d571944SMatt Jacob ISP_LOCK(isp); 3575d571944SMatt Jacob if (isp_fc_runstate(isp, 5 * 1000000)) { 3585d571944SMatt Jacob retval = EIO; 3595d571944SMatt Jacob } else { 3605d571944SMatt Jacob retval = 0; 3615d571944SMatt Jacob } 3625d571944SMatt Jacob ISP_UNLOCK(isp); 3635d571944SMatt Jacob } 3645d571944SMatt Jacob break; 3655d571944SMatt Jacob case ISP_FC_LIP: 3665d571944SMatt Jacob if (IS_FC(isp)) { 3675d571944SMatt Jacob ISP_LOCK(isp); 3685d571944SMatt Jacob if (isp_control(isp, ISPCTL_SEND_LIP, 0)) { 3695d571944SMatt Jacob retval = EIO; 3705d571944SMatt Jacob } else { 3715d571944SMatt Jacob retval = 0; 3725d571944SMatt Jacob } 3735d571944SMatt Jacob ISP_UNLOCK(isp); 3745d571944SMatt Jacob } 3755d571944SMatt Jacob break; 3765d571944SMatt Jacob case ISP_FC_GETDINFO: 3775d571944SMatt Jacob { 3785d571944SMatt Jacob struct isp_fc_device *ifc = (struct isp_fc_device *) addr; 3795d571944SMatt Jacob struct lportdb *lp; 3805d571944SMatt Jacob 3815d571944SMatt Jacob if (ifc->loopid < 0 || ifc->loopid >= MAX_FC_TARG) { 3825d571944SMatt Jacob retval = EINVAL; 3835d571944SMatt Jacob break; 3845d571944SMatt Jacob } 3855d571944SMatt Jacob ISP_LOCK(isp); 3865d571944SMatt Jacob lp = &FCPARAM(isp)->portdb[ifc->loopid]; 3875d571944SMatt Jacob if (lp->valid) { 388c6435ff3SMatt Jacob ifc->role = lp->roles; 3895d571944SMatt Jacob ifc->loopid = lp->loopid; 3905d571944SMatt Jacob ifc->portid = lp->portid; 3915d571944SMatt Jacob ifc->node_wwn = lp->node_wwn; 3925d571944SMatt Jacob ifc->port_wwn = lp->port_wwn; 3935d571944SMatt Jacob retval = 0; 3945d571944SMatt Jacob } else { 3955d571944SMatt Jacob retval = ENODEV; 3965d571944SMatt Jacob } 3975d571944SMatt Jacob ISP_UNLOCK(isp); 3985d571944SMatt Jacob break; 3995d571944SMatt Jacob } 4002903b272SMatt Jacob case ISP_GET_STATS: 4012903b272SMatt Jacob { 4022903b272SMatt Jacob isp_stats_t *sp = (isp_stats_t *) addr; 4032903b272SMatt Jacob 4042903b272SMatt Jacob MEMZERO(sp, sizeof (*sp)); 4052903b272SMatt Jacob sp->isp_stat_version = ISP_STATS_VERSION; 4062903b272SMatt Jacob sp->isp_type = isp->isp_type; 4072903b272SMatt Jacob sp->isp_revision = isp->isp_revision; 4082903b272SMatt Jacob ISP_LOCK(isp); 4092903b272SMatt Jacob sp->isp_stats[ISP_INTCNT] = isp->isp_intcnt; 4102903b272SMatt Jacob sp->isp_stats[ISP_INTBOGUS] = isp->isp_intbogus; 4112903b272SMatt Jacob sp->isp_stats[ISP_INTMBOXC] = isp->isp_intmboxc; 4122903b272SMatt Jacob sp->isp_stats[ISP_INGOASYNC] = isp->isp_intoasync; 4132903b272SMatt Jacob sp->isp_stats[ISP_RSLTCCMPLT] = isp->isp_rsltccmplt; 4142903b272SMatt Jacob sp->isp_stats[ISP_FPHCCMCPLT] = isp->isp_fphccmplt; 4152903b272SMatt Jacob sp->isp_stats[ISP_RSCCHIWAT] = isp->isp_rscchiwater; 4162903b272SMatt Jacob sp->isp_stats[ISP_FPCCHIWAT] = isp->isp_fpcchiwater; 4172903b272SMatt Jacob ISP_UNLOCK(isp); 4182903b272SMatt Jacob retval = 0; 4192903b272SMatt Jacob break; 4202903b272SMatt Jacob } 4212903b272SMatt Jacob case ISP_CLR_STATS: 4222903b272SMatt Jacob ISP_LOCK(isp); 4232903b272SMatt Jacob isp->isp_intcnt = 0; 4242903b272SMatt Jacob isp->isp_intbogus = 0; 4252903b272SMatt Jacob isp->isp_intmboxc = 0; 4262903b272SMatt Jacob isp->isp_intoasync = 0; 4272903b272SMatt Jacob isp->isp_rsltccmplt = 0; 4282903b272SMatt Jacob isp->isp_fphccmplt = 0; 4292903b272SMatt Jacob isp->isp_rscchiwater = 0; 4302903b272SMatt Jacob isp->isp_fpcchiwater = 0; 4312903b272SMatt Jacob ISP_UNLOCK(isp); 4322903b272SMatt Jacob retval = 0; 4332903b272SMatt Jacob break; 434570c7a3fSMatt Jacob case ISP_FC_GETHINFO: 435570c7a3fSMatt Jacob { 436570c7a3fSMatt Jacob struct isp_hba_device *hba = (struct isp_hba_device *) addr; 437570c7a3fSMatt Jacob MEMZERO(hba, sizeof (*hba)); 438570c7a3fSMatt Jacob ISP_LOCK(isp); 439a556b68eSMatt Jacob hba->fc_fw_major = ISP_FW_MAJORX(isp->isp_fwrev); 440a556b68eSMatt Jacob hba->fc_fw_minor = ISP_FW_MINORX(isp->isp_fwrev); 441a556b68eSMatt Jacob hba->fc_fw_micro = ISP_FW_MICROX(isp->isp_fwrev); 442570c7a3fSMatt Jacob hba->fc_speed = FCPARAM(isp)->isp_gbspeed; 443570c7a3fSMatt Jacob hba->fc_scsi_supported = 1; 444570c7a3fSMatt Jacob hba->fc_topology = FCPARAM(isp)->isp_topo + 1; 445570c7a3fSMatt Jacob hba->fc_loopid = FCPARAM(isp)->isp_loopid; 446fd6eb9f7SMatt Jacob hba->nvram_node_wwn = FCPARAM(isp)->isp_nodewwn; 447fd6eb9f7SMatt Jacob hba->nvram_port_wwn = FCPARAM(isp)->isp_portwwn; 448fd6eb9f7SMatt Jacob hba->active_node_wwn = ISP_NODEWWN(isp); 449fd6eb9f7SMatt Jacob hba->active_port_wwn = ISP_PORTWWN(isp); 450570c7a3fSMatt Jacob ISP_UNLOCK(isp); 451570c7a3fSMatt Jacob retval = 0; 452570c7a3fSMatt Jacob break; 453570c7a3fSMatt Jacob } 454fdeb9f2fSMatt Jacob case ISP_GET_FC_PARAM: 455fdeb9f2fSMatt Jacob { 456fdeb9f2fSMatt Jacob struct isp_fc_param *f = (struct isp_fc_param *) addr; 457fdeb9f2fSMatt Jacob 458fdeb9f2fSMatt Jacob if (!IS_FC(isp)) { 459fdeb9f2fSMatt Jacob retval = EINVAL; 460fdeb9f2fSMatt Jacob break; 461fdeb9f2fSMatt Jacob } 462fdeb9f2fSMatt Jacob f->parameter = 0; 463fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "framelength") == 0) { 464fdeb9f2fSMatt Jacob f->parameter = FCPARAM(isp)->isp_maxfrmlen; 465fdeb9f2fSMatt Jacob retval = 0; 466fdeb9f2fSMatt Jacob break; 467fdeb9f2fSMatt Jacob } 468fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "exec_throttle") == 0) { 469fdeb9f2fSMatt Jacob f->parameter = FCPARAM(isp)->isp_execthrottle; 470fdeb9f2fSMatt Jacob retval = 0; 471fdeb9f2fSMatt Jacob break; 472fdeb9f2fSMatt Jacob } 473fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "fullduplex") == 0) { 474fdeb9f2fSMatt Jacob if (FCPARAM(isp)->isp_fwoptions & ICBOPT_FULL_DUPLEX) 475fdeb9f2fSMatt Jacob f->parameter = 1; 476fdeb9f2fSMatt Jacob retval = 0; 477fdeb9f2fSMatt Jacob break; 478fdeb9f2fSMatt Jacob } 479fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "loopid") == 0) { 480fdeb9f2fSMatt Jacob f->parameter = FCPARAM(isp)->isp_loopid; 481fdeb9f2fSMatt Jacob retval = 0; 482fdeb9f2fSMatt Jacob break; 483fdeb9f2fSMatt Jacob } 484fdeb9f2fSMatt Jacob retval = EINVAL; 485fdeb9f2fSMatt Jacob break; 486fdeb9f2fSMatt Jacob } 487fdeb9f2fSMatt Jacob case ISP_SET_FC_PARAM: 488fdeb9f2fSMatt Jacob { 489fdeb9f2fSMatt Jacob struct isp_fc_param *f = (struct isp_fc_param *) addr; 4901dae40ebSMatt Jacob uint32_t param = f->parameter; 491fdeb9f2fSMatt Jacob 492fdeb9f2fSMatt Jacob if (!IS_FC(isp)) { 493fdeb9f2fSMatt Jacob retval = EINVAL; 494fdeb9f2fSMatt Jacob break; 495fdeb9f2fSMatt Jacob } 496fdeb9f2fSMatt Jacob f->parameter = 0; 497fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "framelength") == 0) { 498fdeb9f2fSMatt Jacob if (param != 512 && param != 1024 && param != 1024) { 499fdeb9f2fSMatt Jacob retval = EINVAL; 500fdeb9f2fSMatt Jacob break; 501fdeb9f2fSMatt Jacob } 502fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_maxfrmlen = param; 503fdeb9f2fSMatt Jacob retval = 0; 504fdeb9f2fSMatt Jacob break; 505fdeb9f2fSMatt Jacob } 506fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "exec_throttle") == 0) { 507fdeb9f2fSMatt Jacob if (param < 16 || param > 255) { 508fdeb9f2fSMatt Jacob retval = EINVAL; 509fdeb9f2fSMatt Jacob break; 510fdeb9f2fSMatt Jacob } 511fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_execthrottle = param; 512fdeb9f2fSMatt Jacob retval = 0; 513fdeb9f2fSMatt Jacob break; 514fdeb9f2fSMatt Jacob } 515fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "fullduplex") == 0) { 516fdeb9f2fSMatt Jacob if (param != 0 && param != 1) { 517fdeb9f2fSMatt Jacob retval = EINVAL; 518fdeb9f2fSMatt Jacob break; 519fdeb9f2fSMatt Jacob } 520fdeb9f2fSMatt Jacob if (param) { 521fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_fwoptions |= 522fdeb9f2fSMatt Jacob ICBOPT_FULL_DUPLEX; 523fdeb9f2fSMatt Jacob } else { 524fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_fwoptions &= 525fdeb9f2fSMatt Jacob ~ICBOPT_FULL_DUPLEX; 526fdeb9f2fSMatt Jacob } 527fdeb9f2fSMatt Jacob retval = 0; 528fdeb9f2fSMatt Jacob break; 529fdeb9f2fSMatt Jacob } 530fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "loopid") == 0) { 531fdeb9f2fSMatt Jacob if (param < 0 || param > 125) { 532fdeb9f2fSMatt Jacob retval = EINVAL; 533fdeb9f2fSMatt Jacob break; 534fdeb9f2fSMatt Jacob } 535fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_loopid = param; 536fdeb9f2fSMatt Jacob retval = 0; 537fdeb9f2fSMatt Jacob break; 538fdeb9f2fSMatt Jacob } 539fdeb9f2fSMatt Jacob retval = EINVAL; 540fdeb9f2fSMatt Jacob break; 541fdeb9f2fSMatt Jacob } 5428e62a8acSMatt Jacob case ISP_TSK_MGMT: 5438e62a8acSMatt Jacob { 5448e62a8acSMatt Jacob int needmarker; 5458e62a8acSMatt Jacob struct isp_fc_tsk_mgmt *fct = (struct isp_fc_tsk_mgmt *) addr; 5461dae40ebSMatt Jacob uint16_t loopid; 5478e62a8acSMatt Jacob mbreg_t mbs; 5488e62a8acSMatt Jacob 5498e62a8acSMatt Jacob if (IS_SCSI(isp)) { 5508e62a8acSMatt Jacob retval = EINVAL; 5518e62a8acSMatt Jacob break; 5528e62a8acSMatt Jacob } 5538e62a8acSMatt Jacob 5548e62a8acSMatt Jacob memset(&mbs, 0, sizeof (mbs)); 5558e62a8acSMatt Jacob needmarker = retval = 0; 556e5265237SMatt Jacob loopid = fct->loopid; 557e5265237SMatt Jacob if (IS_2KLOGIN(isp) == 0) { 558e5265237SMatt Jacob loopid <<= 8; 559e5265237SMatt Jacob } 5608e62a8acSMatt Jacob switch (fct->action) { 5618e62a8acSMatt Jacob case CLEAR_ACA: 5628e62a8acSMatt Jacob mbs.param[0] = MBOX_CLEAR_ACA; 563e5265237SMatt Jacob mbs.param[1] = loopid; 5648e62a8acSMatt Jacob mbs.param[2] = fct->lun; 5658e62a8acSMatt Jacob break; 5668e62a8acSMatt Jacob case TARGET_RESET: 5678e62a8acSMatt Jacob mbs.param[0] = MBOX_TARGET_RESET; 568e5265237SMatt Jacob mbs.param[1] = loopid; 5698e62a8acSMatt Jacob needmarker = 1; 5708e62a8acSMatt Jacob break; 5718e62a8acSMatt Jacob case LUN_RESET: 5728e62a8acSMatt Jacob mbs.param[0] = MBOX_LUN_RESET; 573e5265237SMatt Jacob mbs.param[1] = loopid; 5748e62a8acSMatt Jacob mbs.param[2] = fct->lun; 5758e62a8acSMatt Jacob needmarker = 1; 5768e62a8acSMatt Jacob break; 5778e62a8acSMatt Jacob case CLEAR_TASK_SET: 5788e62a8acSMatt Jacob mbs.param[0] = MBOX_CLEAR_TASK_SET; 579e5265237SMatt Jacob mbs.param[1] = loopid; 5808e62a8acSMatt Jacob mbs.param[2] = fct->lun; 5818e62a8acSMatt Jacob needmarker = 1; 5828e62a8acSMatt Jacob break; 5838e62a8acSMatt Jacob case ABORT_TASK_SET: 5848e62a8acSMatt Jacob mbs.param[0] = MBOX_ABORT_TASK_SET; 585e5265237SMatt Jacob mbs.param[1] = loopid; 5868e62a8acSMatt Jacob mbs.param[2] = fct->lun; 5878e62a8acSMatt Jacob needmarker = 1; 5888e62a8acSMatt Jacob break; 5898e62a8acSMatt Jacob default: 5908e62a8acSMatt Jacob retval = EINVAL; 5918e62a8acSMatt Jacob break; 5928e62a8acSMatt Jacob } 5938e62a8acSMatt Jacob if (retval == 0) { 5948e62a8acSMatt Jacob ISP_LOCK(isp); 5958e62a8acSMatt Jacob if (needmarker) { 5968e62a8acSMatt Jacob isp->isp_sendmarker |= 1; 5978e62a8acSMatt Jacob } 5988e62a8acSMatt Jacob retval = isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); 5998e62a8acSMatt Jacob ISP_UNLOCK(isp); 6008e62a8acSMatt Jacob if (retval) 6018e62a8acSMatt Jacob retval = EIO; 6028e62a8acSMatt Jacob } 6038e62a8acSMatt Jacob break; 6048e62a8acSMatt Jacob } 6055d571944SMatt Jacob default: 6065d571944SMatt Jacob break; 6075d571944SMatt Jacob } 6085d571944SMatt Jacob return (retval); 6090470d791SMatt Jacob } 610478f8a96SJustin T. Gibbs 611f6e75de2SMatt Jacob static void 612f6e75de2SMatt Jacob isp_intr_enable(void *arg) 613f6e75de2SMatt Jacob { 6149cd7268eSMatt Jacob ispsoftc_t *isp = arg; 615d6e5500fSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE) { 616f6e75de2SMatt Jacob ENABLE_INTS(isp); 617e3e49f7eSMatt Jacob #if 0 618f6e75de2SMatt Jacob isp->isp_osinfo.intsok = 1; 619e3e49f7eSMatt Jacob #endif 620d6e5500fSMatt Jacob } 621f6e75de2SMatt Jacob /* Release our hook so that the boot can continue. */ 622f6e75de2SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 623f6e75de2SMatt Jacob } 624d81ba9d5SMatt Jacob 625d81ba9d5SMatt Jacob /* 626d81ba9d5SMatt Jacob * Put the target mode functions here, because some are inlines 627d81ba9d5SMatt Jacob */ 628d81ba9d5SMatt Jacob 629d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 630d81ba9d5SMatt Jacob 6319cd7268eSMatt Jacob static __inline int is_lun_enabled(ispsoftc_t *, int, lun_id_t); 6329cd7268eSMatt Jacob static __inline int are_any_luns_enabled(ispsoftc_t *, int); 6339cd7268eSMatt Jacob static __inline tstate_t *get_lun_statep(ispsoftc_t *, int, lun_id_t); 6349cd7268eSMatt Jacob static __inline void rls_lun_statep(ispsoftc_t *, tstate_t *); 6359cd7268eSMatt Jacob static __inline atio_private_data_t *isp_get_atpd(ispsoftc_t *, int); 636d81ba9d5SMatt Jacob static cam_status 6379cd7268eSMatt Jacob create_lun_state(ispsoftc_t *, int, struct cam_path *, tstate_t **); 6389cd7268eSMatt Jacob static void destroy_lun_state(ispsoftc_t *, tstate_t *); 6399cd7268eSMatt Jacob static int isp_en_lun(ispsoftc_t *, union ccb *); 6409cd7268eSMatt Jacob static void isp_ledone(ispsoftc_t *, lun_entry_t *); 6419cd7268eSMatt Jacob static cam_status isp_abort_tgt_ccb(ispsoftc_t *, union ccb *); 642f48ce188SMatt Jacob static timeout_t isp_refire_putback_atio; 643a1bc34c6SMatt Jacob static void isp_complete_ctio(union ccb *); 644a1bc34c6SMatt Jacob static void isp_target_putback_atio(union ccb *); 6459cd7268eSMatt Jacob static void isp_target_start_ctio(ispsoftc_t *, union ccb *); 6469cd7268eSMatt Jacob static int isp_handle_platform_atio(ispsoftc_t *, at_entry_t *); 6479cd7268eSMatt Jacob static int isp_handle_platform_atio2(ispsoftc_t *, at2_entry_t *); 6489cd7268eSMatt Jacob static int isp_handle_platform_ctio(ispsoftc_t *, void *); 6499cd7268eSMatt Jacob static int isp_handle_platform_notify_scsi(ispsoftc_t *, in_entry_t *); 6509cd7268eSMatt Jacob static int isp_handle_platform_notify_fc(ispsoftc_t *, in_fcentry_t *); 651d81ba9d5SMatt Jacob 65253af7d22SMatt Jacob static __inline int 6539cd7268eSMatt Jacob is_lun_enabled(ispsoftc_t *isp, int bus, lun_id_t lun) 654d81ba9d5SMatt Jacob { 655d81ba9d5SMatt Jacob tstate_t *tptr; 656a1bc34c6SMatt Jacob tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)]; 657a1bc34c6SMatt Jacob if (tptr == NULL) { 658d81ba9d5SMatt Jacob return (0); 659d81ba9d5SMatt Jacob } 660d81ba9d5SMatt Jacob do { 661a1bc34c6SMatt Jacob if (tptr->lun == (lun_id_t) lun && tptr->bus == bus) { 662d81ba9d5SMatt Jacob return (1); 663d81ba9d5SMatt Jacob } 664d81ba9d5SMatt Jacob } while ((tptr = tptr->next) != NULL); 665d81ba9d5SMatt Jacob return (0); 666d81ba9d5SMatt Jacob } 667d81ba9d5SMatt Jacob 66853af7d22SMatt Jacob static __inline int 6699cd7268eSMatt Jacob are_any_luns_enabled(ispsoftc_t *isp, int port) 670d81ba9d5SMatt Jacob { 671a1bc34c6SMatt Jacob int lo, hi; 672a1bc34c6SMatt Jacob if (IS_DUALBUS(isp)) { 673a1bc34c6SMatt Jacob lo = (port * (LUN_HASH_SIZE >> 1)); 674a1bc34c6SMatt Jacob hi = lo + (LUN_HASH_SIZE >> 1); 675a1bc34c6SMatt Jacob } else { 676a1bc34c6SMatt Jacob lo = 0; 677a1bc34c6SMatt Jacob hi = LUN_HASH_SIZE; 678a1bc34c6SMatt Jacob } 679a1bc34c6SMatt Jacob for (lo = 0; lo < hi; lo++) { 680a1bc34c6SMatt Jacob if (isp->isp_osinfo.lun_hash[lo]) { 681d81ba9d5SMatt Jacob return (1); 682d81ba9d5SMatt Jacob } 683d81ba9d5SMatt Jacob } 684d81ba9d5SMatt Jacob return (0); 685d81ba9d5SMatt Jacob } 686d81ba9d5SMatt Jacob 68753af7d22SMatt Jacob static __inline tstate_t * 6889cd7268eSMatt Jacob get_lun_statep(ispsoftc_t *isp, int bus, lun_id_t lun) 689d81ba9d5SMatt Jacob { 69064edff94SMatt Jacob tstate_t *tptr = NULL; 691d81ba9d5SMatt Jacob 692d81ba9d5SMatt Jacob if (lun == CAM_LUN_WILDCARD) { 69364edff94SMatt Jacob if (isp->isp_osinfo.tmflags[bus] & TM_WILDCARD_ENABLED) { 694a1bc34c6SMatt Jacob tptr = &isp->isp_osinfo.tsdflt[bus]; 695d81ba9d5SMatt Jacob tptr->hold++; 696d81ba9d5SMatt Jacob return (tptr); 697d81ba9d5SMatt Jacob } 69867ff51f1SMatt Jacob return (NULL); 699126ec864SMatt Jacob } else { 700126ec864SMatt Jacob tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)]; 70164edff94SMatt Jacob if (tptr == NULL) { 70264edff94SMatt Jacob return (NULL); 70364edff94SMatt Jacob } 704126ec864SMatt Jacob } 705d81ba9d5SMatt Jacob 706d81ba9d5SMatt Jacob do { 707a1bc34c6SMatt Jacob if (tptr->lun == lun && tptr->bus == bus) { 708d81ba9d5SMatt Jacob tptr->hold++; 709d81ba9d5SMatt Jacob return (tptr); 710d81ba9d5SMatt Jacob } 711d81ba9d5SMatt Jacob } while ((tptr = tptr->next) != NULL); 712d81ba9d5SMatt Jacob return (tptr); 713d81ba9d5SMatt Jacob } 714d81ba9d5SMatt Jacob 71553af7d22SMatt Jacob static __inline void 7169cd7268eSMatt Jacob rls_lun_statep(ispsoftc_t *isp, tstate_t *tptr) 717d81ba9d5SMatt Jacob { 718d81ba9d5SMatt Jacob if (tptr->hold) 719d81ba9d5SMatt Jacob tptr->hold--; 720d81ba9d5SMatt Jacob } 721d81ba9d5SMatt Jacob 72253af7d22SMatt Jacob static __inline atio_private_data_t * 7239cd7268eSMatt Jacob isp_get_atpd(ispsoftc_t *isp, int tag) 72453036e92SMatt Jacob { 72553036e92SMatt Jacob atio_private_data_t *atp; 72653036e92SMatt Jacob for (atp = isp->isp_osinfo.atpdp; 72753036e92SMatt Jacob atp < &isp->isp_osinfo.atpdp[ATPDPSIZE]; atp++) { 72853036e92SMatt Jacob if (atp->tag == tag) 72953036e92SMatt Jacob return (atp); 73053036e92SMatt Jacob } 73153036e92SMatt Jacob return (NULL); 73253036e92SMatt Jacob } 73353036e92SMatt Jacob 734d81ba9d5SMatt Jacob static cam_status 7359cd7268eSMatt Jacob create_lun_state(ispsoftc_t *isp, int bus, 736a1bc34c6SMatt Jacob struct cam_path *path, tstate_t **rslt) 737d81ba9d5SMatt Jacob { 738d81ba9d5SMatt Jacob cam_status status; 739d81ba9d5SMatt Jacob lun_id_t lun; 740a1bc34c6SMatt Jacob int hfx; 741d81ba9d5SMatt Jacob tstate_t *tptr, *new; 742d81ba9d5SMatt Jacob 743d81ba9d5SMatt Jacob lun = xpt_path_lun_id(path); 744d81ba9d5SMatt Jacob if (lun < 0) { 745d81ba9d5SMatt Jacob return (CAM_LUN_INVALID); 746d81ba9d5SMatt Jacob } 747a1bc34c6SMatt Jacob if (is_lun_enabled(isp, bus, lun)) { 748d81ba9d5SMatt Jacob return (CAM_LUN_ALRDY_ENA); 749d81ba9d5SMatt Jacob } 750ea8b5a9aSDavid Malone new = (tstate_t *) malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO); 751d81ba9d5SMatt Jacob if (new == NULL) { 752d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 753d81ba9d5SMatt Jacob } 754d81ba9d5SMatt Jacob 755d81ba9d5SMatt Jacob status = xpt_create_path(&new->owner, NULL, xpt_path_path_id(path), 756d81ba9d5SMatt Jacob xpt_path_target_id(path), xpt_path_lun_id(path)); 757d81ba9d5SMatt Jacob if (status != CAM_REQ_CMP) { 758d81ba9d5SMatt Jacob free(new, M_DEVBUF); 759d81ba9d5SMatt Jacob return (status); 760d81ba9d5SMatt Jacob } 761a1bc34c6SMatt Jacob new->bus = bus; 762d81ba9d5SMatt Jacob new->lun = lun; 763d81ba9d5SMatt Jacob SLIST_INIT(&new->atios); 764d81ba9d5SMatt Jacob SLIST_INIT(&new->inots); 765d81ba9d5SMatt Jacob new->hold = 1; 766d81ba9d5SMatt Jacob 767a1bc34c6SMatt Jacob hfx = LUN_HASH_FUNC(isp, new->bus, new->lun); 768a1bc34c6SMatt Jacob tptr = isp->isp_osinfo.lun_hash[hfx]; 769a1bc34c6SMatt Jacob if (tptr == NULL) { 770a1bc34c6SMatt Jacob isp->isp_osinfo.lun_hash[hfx] = new; 771d81ba9d5SMatt Jacob } else { 772d81ba9d5SMatt Jacob while (tptr->next) 773d81ba9d5SMatt Jacob tptr = tptr->next; 774d81ba9d5SMatt Jacob tptr->next = new; 775d81ba9d5SMatt Jacob } 776d81ba9d5SMatt Jacob *rslt = new; 777d81ba9d5SMatt Jacob return (CAM_REQ_CMP); 778d81ba9d5SMatt Jacob } 779d81ba9d5SMatt Jacob 78053af7d22SMatt Jacob static __inline void 7819cd7268eSMatt Jacob destroy_lun_state(ispsoftc_t *isp, tstate_t *tptr) 782d81ba9d5SMatt Jacob { 783a1bc34c6SMatt Jacob int hfx; 784d81ba9d5SMatt Jacob tstate_t *lw, *pw; 785d81ba9d5SMatt Jacob 786d81ba9d5SMatt Jacob if (tptr->hold) { 787d81ba9d5SMatt Jacob return; 788d81ba9d5SMatt Jacob } 78967ff51f1SMatt Jacob hfx = LUN_HASH_FUNC(isp, tptr->bus, tptr->lun); 790a1bc34c6SMatt Jacob pw = isp->isp_osinfo.lun_hash[hfx]; 791d81ba9d5SMatt Jacob if (pw == NULL) { 792d81ba9d5SMatt Jacob return; 793a1bc34c6SMatt Jacob } else if (pw->lun == tptr->lun && pw->bus == tptr->bus) { 794a1bc34c6SMatt Jacob isp->isp_osinfo.lun_hash[hfx] = pw->next; 795d81ba9d5SMatt Jacob } else { 796d81ba9d5SMatt Jacob lw = pw; 797d81ba9d5SMatt Jacob pw = lw->next; 798d81ba9d5SMatt Jacob while (pw) { 799a1bc34c6SMatt Jacob if (pw->lun == tptr->lun && pw->bus == tptr->bus) { 800d81ba9d5SMatt Jacob lw->next = pw->next; 801d81ba9d5SMatt Jacob break; 802d81ba9d5SMatt Jacob } 803d81ba9d5SMatt Jacob lw = pw; 804d81ba9d5SMatt Jacob pw = pw->next; 805d81ba9d5SMatt Jacob } 806d81ba9d5SMatt Jacob if (pw == NULL) { 807d81ba9d5SMatt Jacob return; 808d81ba9d5SMatt Jacob } 809d81ba9d5SMatt Jacob } 810d81ba9d5SMatt Jacob free(tptr, M_DEVBUF); 811d81ba9d5SMatt Jacob } 812d81ba9d5SMatt Jacob 8135d571944SMatt Jacob /* 81467ff51f1SMatt Jacob * Enable luns. 8155d571944SMatt Jacob */ 81667ff51f1SMatt Jacob static int 8179cd7268eSMatt Jacob isp_en_lun(ispsoftc_t *isp, union ccb *ccb) 818d81ba9d5SMatt Jacob { 819d81ba9d5SMatt Jacob struct ccb_en_lun *cel = &ccb->cel; 820d81ba9d5SMatt Jacob tstate_t *tptr; 8211dae40ebSMatt Jacob uint32_t seq; 822746e9c85SMatt Jacob int bus, cmd, av, wildcard, tm_on; 823d81ba9d5SMatt Jacob lun_id_t lun; 824d81ba9d5SMatt Jacob target_id_t tgt; 825d81ba9d5SMatt Jacob 82667ff51f1SMatt Jacob bus = XS_CHANNEL(ccb); 82767ff51f1SMatt Jacob if (bus > 1) { 82867ff51f1SMatt Jacob xpt_print_path(ccb->ccb_h.path); 82967ff51f1SMatt Jacob printf("illegal bus %d\n", bus); 83067ff51f1SMatt Jacob ccb->ccb_h.status = CAM_PATH_INVALID; 83167ff51f1SMatt Jacob return (-1); 83267ff51f1SMatt Jacob } 833d81ba9d5SMatt Jacob tgt = ccb->ccb_h.target_id; 834d81ba9d5SMatt Jacob lun = ccb->ccb_h.target_lun; 835d81ba9d5SMatt Jacob 83667ff51f1SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 83767ff51f1SMatt Jacob "isp_en_lun: %sabling lun 0x%x on channel %d", 83867ff51f1SMatt Jacob cel->enable? "en" : "dis", lun, bus); 83967ff51f1SMatt Jacob 840d81ba9d5SMatt Jacob 841d6e5500fSMatt Jacob if ((lun != CAM_LUN_WILDCARD) && 842d6e5500fSMatt Jacob (lun < 0 || lun >= (lun_id_t) isp->isp_maxluns)) { 843d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 84467ff51f1SMatt Jacob return (-1); 845d81ba9d5SMatt Jacob } 84664edff94SMatt Jacob 8472ad50ca5SMatt Jacob if (IS_SCSI(isp)) { 848a1bc34c6SMatt Jacob sdparam *sdp = isp->isp_param; 849a1bc34c6SMatt Jacob sdp += bus; 850d81ba9d5SMatt Jacob if (tgt != CAM_TARGET_WILDCARD && 851a1bc34c6SMatt Jacob tgt != sdp->isp_initiator_id) { 852d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_TID_INVALID; 85367ff51f1SMatt Jacob return (-1); 854d81ba9d5SMatt Jacob } 855d81ba9d5SMatt Jacob } else { 856746e9c85SMatt Jacob /* 857746e9c85SMatt Jacob * There's really no point in doing this yet w/o multi-tid 858746e9c85SMatt Jacob * capability. Even then, it's problematic. 859746e9c85SMatt Jacob */ 860746e9c85SMatt Jacob #if 0 861d81ba9d5SMatt Jacob if (tgt != CAM_TARGET_WILDCARD && 862d6e5500fSMatt Jacob tgt != FCPARAM(isp)->isp_iid) { 863d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_TID_INVALID; 86467ff51f1SMatt Jacob return (-1); 865d81ba9d5SMatt Jacob } 866746e9c85SMatt Jacob #endif 86764edff94SMatt Jacob /* 86864edff94SMatt Jacob * This is as a good a place as any to check f/w capabilities. 86964edff94SMatt Jacob */ 87064edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_TMODE) == 0) { 87164edff94SMatt Jacob isp_prt(isp, ISP_LOGERR, 87264edff94SMatt Jacob "firmware does not support target mode"); 87364edff94SMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 87467ff51f1SMatt Jacob return (-1); 87564edff94SMatt Jacob } 87664edff94SMatt Jacob /* 87764edff94SMatt Jacob * XXX: We *could* handle non-SCCLUN f/w, but we'd have to 87864edff94SMatt Jacob * XXX: dorks with our already fragile enable/disable code. 87964edff94SMatt Jacob */ 88064edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) { 88164edff94SMatt Jacob isp_prt(isp, ISP_LOGERR, 88264edff94SMatt Jacob "firmware not SCCLUN capable"); 883746e9c85SMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 88467ff51f1SMatt Jacob return (-1); 88564edff94SMatt Jacob } 886d81ba9d5SMatt Jacob } 887d81ba9d5SMatt Jacob 888d6e5500fSMatt Jacob if (tgt == CAM_TARGET_WILDCARD) { 88964edff94SMatt Jacob if (lun == CAM_LUN_WILDCARD) { 89064edff94SMatt Jacob wildcard = 1; 89164edff94SMatt Jacob } else { 892d6e5500fSMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 89367ff51f1SMatt Jacob return (-1); 894d6e5500fSMatt Jacob } 895126ec864SMatt Jacob } else { 896126ec864SMatt Jacob wildcard = 0; 897126ec864SMatt Jacob } 898b6b6ad2fSMatt Jacob 899746e9c85SMatt Jacob tm_on = (isp->isp_osinfo.tmflags[bus] & TM_TMODE_ENABLED) != 0; 900746e9c85SMatt Jacob 901b6b6ad2fSMatt Jacob /* 902b6b6ad2fSMatt Jacob * Next check to see whether this is a target/lun wildcard action. 90364edff94SMatt Jacob * 90464edff94SMatt Jacob * If so, we know that we can accept commands for luns that haven't 90564edff94SMatt Jacob * been enabled yet and send them upstream. Otherwise, we have to 90664edff94SMatt Jacob * handle them locally (if we see them at all). 907b6b6ad2fSMatt Jacob */ 908126ec864SMatt Jacob 909126ec864SMatt Jacob if (wildcard) { 910a1bc34c6SMatt Jacob tptr = &isp->isp_osinfo.tsdflt[bus]; 911b6b6ad2fSMatt Jacob if (cel->enable) { 91267ff51f1SMatt Jacob if (tm_on) { 913b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; 91467ff51f1SMatt Jacob return (-1); 915b6b6ad2fSMatt Jacob } 916b6b6ad2fSMatt Jacob ccb->ccb_h.status = 917b6b6ad2fSMatt Jacob xpt_create_path(&tptr->owner, NULL, 918b6b6ad2fSMatt Jacob xpt_path_path_id(ccb->ccb_h.path), 919b6b6ad2fSMatt Jacob xpt_path_target_id(ccb->ccb_h.path), 920b6b6ad2fSMatt Jacob xpt_path_lun_id(ccb->ccb_h.path)); 921b6b6ad2fSMatt Jacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 92267ff51f1SMatt Jacob return (-1); 923b6b6ad2fSMatt Jacob } 924b6b6ad2fSMatt Jacob SLIST_INIT(&tptr->atios); 925b6b6ad2fSMatt Jacob SLIST_INIT(&tptr->inots); 92664edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] |= TM_WILDCARD_ENABLED; 927126ec864SMatt Jacob } else { 92867ff51f1SMatt Jacob if (tm_on == 0) { 929126ec864SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 93067ff51f1SMatt Jacob return (-1); 931126ec864SMatt Jacob } 932126ec864SMatt Jacob if (tptr->hold) { 933126ec864SMatt Jacob ccb->ccb_h.status = CAM_SCSI_BUSY; 93467ff51f1SMatt Jacob return (-1); 935126ec864SMatt Jacob } 936126ec864SMatt Jacob xpt_free_path(tptr->owner); 93764edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_WILDCARD_ENABLED; 938126ec864SMatt Jacob } 939126ec864SMatt Jacob } 940126ec864SMatt Jacob 941126ec864SMatt Jacob /* 942126ec864SMatt Jacob * Now check to see whether this bus needs to be 943126ec864SMatt Jacob * enabled/disabled with respect to target mode. 944126ec864SMatt Jacob */ 945126ec864SMatt Jacob av = bus << 31; 946746e9c85SMatt Jacob if (cel->enable && tm_on == 0) { 947a1bc34c6SMatt Jacob av |= ENABLE_TARGET_FLAG; 948b6b6ad2fSMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 949b6b6ad2fSMatt Jacob if (av) { 950b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 951126ec864SMatt Jacob if (wildcard) { 95264edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= 95364edff94SMatt Jacob ~TM_WILDCARD_ENABLED; 954b6b6ad2fSMatt Jacob xpt_free_path(tptr->owner); 9555d571944SMatt Jacob } 95667ff51f1SMatt Jacob return (-1); 957b6b6ad2fSMatt Jacob } 95864edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] |= TM_TMODE_ENABLED; 959126ec864SMatt Jacob isp_prt(isp, ISP_LOGINFO, 960126ec864SMatt Jacob "Target Mode enabled on channel %d", bus); 961746e9c85SMatt Jacob } else if (cel->enable == 0 && tm_on && wildcard) { 962a1bc34c6SMatt Jacob if (are_any_luns_enabled(isp, bus)) { 963b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_SCSI_BUSY; 96467ff51f1SMatt Jacob return (-1); 965b6b6ad2fSMatt Jacob } 966b6b6ad2fSMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 967b6b6ad2fSMatt Jacob if (av) { 968b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 96967ff51f1SMatt Jacob return (-1); 970b6b6ad2fSMatt Jacob } 97164edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED; 972126ec864SMatt Jacob isp_prt(isp, ISP_LOGINFO, 973126ec864SMatt Jacob "Target Mode disabled on channel %d", bus); 974126ec864SMatt Jacob } 975126ec864SMatt Jacob 976126ec864SMatt Jacob if (wildcard) { 97764edff94SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 97867ff51f1SMatt Jacob return (-1); 979b6b6ad2fSMatt Jacob } 980b6b6ad2fSMatt Jacob 98167ff51f1SMatt Jacob /* 98267ff51f1SMatt Jacob * Find an empty slot 98367ff51f1SMatt Jacob */ 98467ff51f1SMatt Jacob for (seq = 0; seq < NLEACT; seq++) { 98567ff51f1SMatt Jacob if (isp->isp_osinfo.leact[seq] == 0) { 98667ff51f1SMatt Jacob break; 98767ff51f1SMatt Jacob } 98867ff51f1SMatt Jacob } 98967ff51f1SMatt Jacob if (seq >= NLEACT) { 99067ff51f1SMatt Jacob ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 99167ff51f1SMatt Jacob return (-1); 99267ff51f1SMatt Jacob 99367ff51f1SMatt Jacob } 99467ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = ccb; 99567ff51f1SMatt Jacob 996d81ba9d5SMatt Jacob if (cel->enable) { 997d81ba9d5SMatt Jacob ccb->ccb_h.status = 998a1bc34c6SMatt Jacob create_lun_state(isp, bus, ccb->ccb_h.path, &tptr); 999d81ba9d5SMatt Jacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 100067ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 100167ff51f1SMatt Jacob return (-1); 1002d81ba9d5SMatt Jacob } 1003d81ba9d5SMatt Jacob } else { 1004a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, lun); 1005d81ba9d5SMatt Jacob if (tptr == NULL) { 1006d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 100767ff51f1SMatt Jacob return (-1); 1008d81ba9d5SMatt Jacob } 1009d81ba9d5SMatt Jacob } 1010d81ba9d5SMatt Jacob 1011d81ba9d5SMatt Jacob if (cel->enable) { 10125d571944SMatt Jacob int c, n, ulun = lun; 10135d571944SMatt Jacob 10145d571944SMatt Jacob cmd = RQSTYPE_ENABLE_LUN; 10155d571944SMatt Jacob c = DFLT_CMND_CNT; 10165d571944SMatt Jacob n = DFLT_INOT_CNT; 10175d571944SMatt Jacob if (IS_FC(isp) && lun != 0) { 10185d571944SMatt Jacob cmd = RQSTYPE_MODIFY_LUN; 10195d571944SMatt Jacob n = 0; 10205d571944SMatt Jacob /* 10215d571944SMatt Jacob * For SCC firmware, we only deal with setting 10225d571944SMatt Jacob * (enabling or modifying) lun 0. 10235d571944SMatt Jacob */ 10245d571944SMatt Jacob ulun = 0; 10255d571944SMatt Jacob } 102667ff51f1SMatt Jacob if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq+1) == 0) { 102767ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 102867ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_INPROG; 102967ff51f1SMatt Jacob return (seq); 1030d81ba9d5SMatt Jacob } 1031d81ba9d5SMatt Jacob } else { 10325d571944SMatt Jacob int c, n, ulun = lun; 1033d81ba9d5SMatt Jacob 10345d571944SMatt Jacob cmd = -RQSTYPE_MODIFY_LUN; 10355d571944SMatt Jacob c = DFLT_CMND_CNT; 10365d571944SMatt Jacob n = DFLT_INOT_CNT; 10375d571944SMatt Jacob if (IS_FC(isp) && lun != 0) { 10385d571944SMatt Jacob n = 0; 10395d571944SMatt Jacob /* 10405d571944SMatt Jacob * For SCC firmware, we only deal with setting 10415d571944SMatt Jacob * (enabling or modifying) lun 0. 10425d571944SMatt Jacob */ 10435d571944SMatt Jacob ulun = 0; 10445d571944SMatt Jacob } 104567ff51f1SMatt Jacob if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq+1) == 0) { 104667ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 104767ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_INPROG; 104867ff51f1SMatt Jacob return (seq); 1049d81ba9d5SMatt Jacob } 1050d81ba9d5SMatt Jacob } 105167ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 1052d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 105367ff51f1SMatt Jacob printf("isp_lun_cmd failed\n"); 105467ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 105567ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 105667ff51f1SMatt Jacob return (-1); 10575d571944SMatt Jacob } 10585d571944SMatt Jacob 105967ff51f1SMatt Jacob static void 10609cd7268eSMatt Jacob isp_ledone(ispsoftc_t *isp, lun_entry_t *lep) 106167ff51f1SMatt Jacob { 106267ff51f1SMatt Jacob const char lfmt[] = "lun %d now %sabled for target mode on channel %d"; 106367ff51f1SMatt Jacob union ccb *ccb; 10641dae40ebSMatt Jacob uint32_t seq; 106567ff51f1SMatt Jacob tstate_t *tptr; 106667ff51f1SMatt Jacob int av; 106767ff51f1SMatt Jacob struct ccb_en_lun *cel; 1068d81ba9d5SMatt Jacob 106967ff51f1SMatt Jacob seq = lep->le_reserved - 1; 107067ff51f1SMatt Jacob if (seq >= NLEACT) { 10713c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, 107267ff51f1SMatt Jacob "seq out of range (%u) in isp_ledone", seq); 107367ff51f1SMatt Jacob return; 1074d81ba9d5SMatt Jacob } 107567ff51f1SMatt Jacob ccb = isp->isp_osinfo.leact[seq]; 107667ff51f1SMatt Jacob if (ccb == 0) { 107767ff51f1SMatt Jacob isp_prt(isp, ISP_LOGERR, 107867ff51f1SMatt Jacob "no ccb for seq %u in isp_ledone", seq); 107967ff51f1SMatt Jacob return; 108067ff51f1SMatt Jacob } 108167ff51f1SMatt Jacob cel = &ccb->cel; 108267ff51f1SMatt Jacob tptr = get_lun_statep(isp, XS_CHANNEL(ccb), XS_LUN(ccb)); 108367ff51f1SMatt Jacob if (tptr == NULL) { 1084d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 108567ff51f1SMatt Jacob printf("null tptr in isp_ledone\n"); 108667ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 108767ff51f1SMatt Jacob return; 1088d81ba9d5SMatt Jacob } 108967ff51f1SMatt Jacob 109067ff51f1SMatt Jacob if (lep->le_status != LUN_OK) { 109167ff51f1SMatt Jacob xpt_print_path(ccb->ccb_h.path); 109267ff51f1SMatt Jacob printf("ENABLE/MODIFY LUN returned 0x%x\n", lep->le_status); 109367ff51f1SMatt Jacob err: 109467ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 109567ff51f1SMatt Jacob xpt_print_path(ccb->ccb_h.path); 109667ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 109767ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 109867ff51f1SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 109967ff51f1SMatt Jacob xpt_done(ccb); 110067ff51f1SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 110167ff51f1SMatt Jacob return; 110267ff51f1SMatt Jacob } else { 110367ff51f1SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 110467ff51f1SMatt Jacob "isp_ledone: ENABLE/MODIFY done okay"); 110567ff51f1SMatt Jacob } 110667ff51f1SMatt Jacob 110767ff51f1SMatt Jacob 110867ff51f1SMatt Jacob if (cel->enable) { 110967ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 11109cd7268eSMatt Jacob isp_prt(isp, ISP_LOGINFO, lfmt, 111167ff51f1SMatt Jacob XS_LUN(ccb), "en", XS_CHANNEL(ccb)); 111267ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 111367ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 111467ff51f1SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 111567ff51f1SMatt Jacob xpt_done(ccb); 111667ff51f1SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 111767ff51f1SMatt Jacob return; 111867ff51f1SMatt Jacob } 111967ff51f1SMatt Jacob 112067ff51f1SMatt Jacob if (lep->le_header.rqs_entry_type == RQSTYPE_MODIFY_LUN) { 112167ff51f1SMatt Jacob if (isp_lun_cmd(isp, -RQSTYPE_ENABLE_LUN, XS_CHANNEL(ccb), 112267ff51f1SMatt Jacob XS_TGT(ccb), XS_LUN(ccb), 0, 0, seq+1)) { 112367ff51f1SMatt Jacob xpt_print_path(ccb->ccb_h.path); 112467ff51f1SMatt Jacob printf("isp_ledone: isp_lun_cmd failed\n"); 112567ff51f1SMatt Jacob goto err; 112667ff51f1SMatt Jacob } 112767ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 112867ff51f1SMatt Jacob return; 112967ff51f1SMatt Jacob } 113067ff51f1SMatt Jacob 113167ff51f1SMatt Jacob isp_prt(isp, ISP_LOGINFO, lfmt, XS_LUN(ccb), "dis", XS_CHANNEL(ccb)); 113267ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 113367ff51f1SMatt Jacob destroy_lun_state(isp, tptr); 113467ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 113567ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 113667ff51f1SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 113767ff51f1SMatt Jacob xpt_done(ccb); 113867ff51f1SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 113967ff51f1SMatt Jacob if (are_any_luns_enabled(isp, XS_CHANNEL(ccb)) == 0) { 114067ff51f1SMatt Jacob int bus = XS_CHANNEL(ccb); 114167ff51f1SMatt Jacob av = bus << 31; 1142126ec864SMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 1143126ec864SMatt Jacob if (av) { 1144126ec864SMatt Jacob isp_prt(isp, ISP_LOGWARN, 114567ff51f1SMatt Jacob "disable target mode on channel %d failed", bus); 114667ff51f1SMatt Jacob } else { 1147126ec864SMatt Jacob isp_prt(isp, ISP_LOGINFO, 1148126ec864SMatt Jacob "Target Mode disabled on channel %d", bus); 1149126ec864SMatt Jacob } 115067ff51f1SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED; 115167ff51f1SMatt Jacob } 1152126ec864SMatt Jacob } 1153126ec864SMatt Jacob 1154d81ba9d5SMatt Jacob 1155d81ba9d5SMatt Jacob static cam_status 11569cd7268eSMatt Jacob isp_abort_tgt_ccb(ispsoftc_t *isp, union ccb *ccb) 1157d81ba9d5SMatt Jacob { 1158d81ba9d5SMatt Jacob tstate_t *tptr; 1159d81ba9d5SMatt Jacob struct ccb_hdr_slist *lp; 1160d81ba9d5SMatt Jacob struct ccb_hdr *curelm; 1161746e9c85SMatt Jacob int found, *ctr; 1162d81ba9d5SMatt Jacob union ccb *accb = ccb->cab.abort_ccb; 1163d81ba9d5SMatt Jacob 1164746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "aborting ccb %p", accb); 1165d81ba9d5SMatt Jacob if (accb->ccb_h.target_id != CAM_TARGET_WILDCARD) { 1166746e9c85SMatt Jacob int badpath = 0; 1167d81ba9d5SMatt Jacob if (IS_FC(isp) && (accb->ccb_h.target_id != 1168d81ba9d5SMatt Jacob ((fcparam *) isp->isp_param)->isp_loopid)) { 1169746e9c85SMatt Jacob badpath = 1; 1170d81ba9d5SMatt Jacob } else if (IS_SCSI(isp) && (accb->ccb_h.target_id != 1171d81ba9d5SMatt Jacob ((sdparam *) isp->isp_param)->isp_initiator_id)) { 1172746e9c85SMatt Jacob badpath = 1; 1173746e9c85SMatt Jacob } 1174746e9c85SMatt Jacob if (badpath) { 1175746e9c85SMatt Jacob /* 1176746e9c85SMatt Jacob * Being restrictive about target ids is really about 1177746e9c85SMatt Jacob * making sure we're aborting for the right multi-tid 1178746e9c85SMatt Jacob * path. This doesn't really make much sense at present. 1179746e9c85SMatt Jacob */ 1180746e9c85SMatt Jacob #if 0 1181d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 1182746e9c85SMatt Jacob #endif 1183d81ba9d5SMatt Jacob } 1184d81ba9d5SMatt Jacob } 1185a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, XS_CHANNEL(ccb), accb->ccb_h.target_lun); 1186d81ba9d5SMatt Jacob if (tptr == NULL) { 1187746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1188746e9c85SMatt Jacob "isp_abort_tgt_ccb: can't get statep"); 1189d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 1190d81ba9d5SMatt Jacob } 1191d81ba9d5SMatt Jacob if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 1192d81ba9d5SMatt Jacob lp = &tptr->atios; 1193746e9c85SMatt Jacob ctr = &tptr->atio_count; 1194d81ba9d5SMatt Jacob } else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY) { 1195d81ba9d5SMatt Jacob lp = &tptr->inots; 1196746e9c85SMatt Jacob ctr = &tptr->inot_count; 1197d81ba9d5SMatt Jacob } else { 1198d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1199746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1200746e9c85SMatt Jacob "isp_abort_tgt_ccb: bad func %d\n", accb->ccb_h.func_code); 1201d81ba9d5SMatt Jacob return (CAM_UA_ABORT); 1202d81ba9d5SMatt Jacob } 1203d81ba9d5SMatt Jacob curelm = SLIST_FIRST(lp); 1204d81ba9d5SMatt Jacob found = 0; 1205d81ba9d5SMatt Jacob if (curelm == &accb->ccb_h) { 1206d81ba9d5SMatt Jacob found = 1; 1207d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(lp, sim_links.sle); 1208d81ba9d5SMatt Jacob } else { 1209d81ba9d5SMatt Jacob while(curelm != NULL) { 1210d81ba9d5SMatt Jacob struct ccb_hdr *nextelm; 1211d81ba9d5SMatt Jacob 1212d81ba9d5SMatt Jacob nextelm = SLIST_NEXT(curelm, sim_links.sle); 1213d81ba9d5SMatt Jacob if (nextelm == &accb->ccb_h) { 1214d81ba9d5SMatt Jacob found = 1; 1215d81ba9d5SMatt Jacob SLIST_NEXT(curelm, sim_links.sle) = 1216d81ba9d5SMatt Jacob SLIST_NEXT(nextelm, sim_links.sle); 1217d81ba9d5SMatt Jacob break; 1218d81ba9d5SMatt Jacob } 1219d81ba9d5SMatt Jacob curelm = nextelm; 1220d81ba9d5SMatt Jacob } 1221d81ba9d5SMatt Jacob } 1222d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1223d81ba9d5SMatt Jacob if (found) { 1224c1504bc0SMatt Jacob (*ctr)--; 1225d81ba9d5SMatt Jacob accb->ccb_h.status = CAM_REQ_ABORTED; 1226746e9c85SMatt Jacob xpt_done(accb); 1227d81ba9d5SMatt Jacob return (CAM_REQ_CMP); 1228d81ba9d5SMatt Jacob } 1229746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1230746e9c85SMatt Jacob "isp_abort_tgt_ccb: CCB %p not found\n", ccb); 1231d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 1232d81ba9d5SMatt Jacob } 1233d81ba9d5SMatt Jacob 12349cd7268eSMatt Jacob static void 12359cd7268eSMatt Jacob isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb) 1236d81ba9d5SMatt Jacob { 1237d81ba9d5SMatt Jacob void *qe; 123800a8e174SMatt Jacob struct ccb_scsiio *cso = &ccb->csio; 12391dae40ebSMatt Jacob uint16_t *hp, save_handle; 12401dae40ebSMatt Jacob uint16_t nxti, optr; 12411dae40ebSMatt Jacob uint8_t local[QENTRY_LEN]; 1242d81ba9d5SMatt Jacob 1243f48ce188SMatt Jacob 12444fd13c1bSMatt Jacob if (isp_getrqentry(isp, &nxti, &optr, &qe)) { 124592a1e549SMatt Jacob xpt_print_path(ccb->ccb_h.path); 124692a1e549SMatt Jacob printf("Request Queue Overflow in isp_target_start_ctio\n"); 12479cd7268eSMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 12489cd7268eSMatt Jacob goto out; 1249d81ba9d5SMatt Jacob } 12504fd13c1bSMatt Jacob bzero(local, QENTRY_LEN); 1251d81ba9d5SMatt Jacob 1252d81ba9d5SMatt Jacob /* 1253d81ba9d5SMatt Jacob * We're either moving data or completing a command here. 1254d81ba9d5SMatt Jacob */ 1255d81ba9d5SMatt Jacob 1256d81ba9d5SMatt Jacob if (IS_FC(isp)) { 125753036e92SMatt Jacob atio_private_data_t *atp; 12584fd13c1bSMatt Jacob ct2_entry_t *cto = (ct2_entry_t *) local; 125900a8e174SMatt Jacob 1260d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; 1261d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_count = 1; 126200a8e174SMatt Jacob cto->ct_iid = cso->init_id; 126364edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) { 1264d81ba9d5SMatt Jacob cto->ct_lun = ccb->ccb_h.target_lun; 12652ad50ca5SMatt Jacob } 126653036e92SMatt Jacob 126753036e92SMatt Jacob atp = isp_get_atpd(isp, cso->tag_id); 126853036e92SMatt Jacob if (atp == NULL) { 1269570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGERR, 1270570c7a3fSMatt Jacob "cannot find private data adjunct for tag %x", 127153036e92SMatt Jacob cso->tag_id); 12729cd7268eSMatt Jacob XS_SETERR(ccb, CAM_REQ_CMP_ERR); 12739cd7268eSMatt Jacob goto out; 127453036e92SMatt Jacob } 1275f48ce188SMatt Jacob 127600a8e174SMatt Jacob cto->ct_rxid = cso->tag_id; 127700a8e174SMatt Jacob if (cso->dxfer_len == 0) { 127800a8e174SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA; 1279f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 128000a8e174SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 1281f48ce188SMatt Jacob cto->rsp.m1.ct_scsi_status = cso->scsi_status; 128253036e92SMatt Jacob cto->ct_resid = 128353036e92SMatt Jacob atp->orig_datalen - atp->bytes_xfered; 1284570c7a3fSMatt Jacob if (cto->ct_resid < 0) { 1285570c7a3fSMatt Jacob cto->rsp.m1.ct_scsi_status |= 1286570c7a3fSMatt Jacob CT2_DATA_OVER; 1287570c7a3fSMatt Jacob } else if (cto->ct_resid > 0) { 1288570c7a3fSMatt Jacob cto->rsp.m1.ct_scsi_status |= 1289570c7a3fSMatt Jacob CT2_DATA_UNDER; 1290570c7a3fSMatt Jacob } 1291f48ce188SMatt Jacob } 129200a8e174SMatt Jacob if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) { 129300a8e174SMatt Jacob int m = min(cso->sense_len, MAXRESPLEN); 129400a8e174SMatt Jacob bcopy(&cso->sense_data, cto->rsp.m1.ct_resp, m); 129500a8e174SMatt Jacob cto->rsp.m1.ct_senselen = m; 129600a8e174SMatt Jacob cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID; 129700a8e174SMatt Jacob } 129800a8e174SMatt Jacob } else { 129900a8e174SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE0; 130000a8e174SMatt Jacob if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 130100a8e174SMatt Jacob cto->ct_flags |= CT2_DATA_IN; 130200a8e174SMatt Jacob } else { 130300a8e174SMatt Jacob cto->ct_flags |= CT2_DATA_OUT; 1304d81ba9d5SMatt Jacob } 1305570c7a3fSMatt Jacob cto->ct_reloff = atp->bytes_xfered; 1306d81ba9d5SMatt Jacob if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 1307d81ba9d5SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 130800a8e174SMatt Jacob cto->rsp.m0.ct_scsi_status = cso->scsi_status; 130953036e92SMatt Jacob cto->ct_resid = 131053036e92SMatt Jacob atp->orig_datalen - 131153036e92SMatt Jacob (atp->bytes_xfered + cso->dxfer_len); 1312570c7a3fSMatt Jacob if (cto->ct_resid < 0) { 1313570c7a3fSMatt Jacob cto->rsp.m0.ct_scsi_status |= 1314570c7a3fSMatt Jacob CT2_DATA_OVER; 1315570c7a3fSMatt Jacob } else if (cto->ct_resid > 0) { 1316570c7a3fSMatt Jacob cto->rsp.m0.ct_scsi_status |= 1317570c7a3fSMatt Jacob CT2_DATA_UNDER; 1318570c7a3fSMatt Jacob } 131953036e92SMatt Jacob } else { 132053036e92SMatt Jacob atp->last_xframt = cso->dxfer_len; 1321d81ba9d5SMatt Jacob } 1322f48ce188SMatt Jacob /* 1323f48ce188SMatt Jacob * If we're sending data and status back together, 1324f48ce188SMatt Jacob * we can't also send back sense data as well. 1325f48ce188SMatt Jacob */ 132600a8e174SMatt Jacob ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 132700a8e174SMatt Jacob } 132853036e92SMatt Jacob 1329290dc24bSMatt Jacob if (cto->ct_flags & CT2_SENDSTATUS) { 133064edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 133153036e92SMatt Jacob "CTIO2[%x] STATUS %x origd %u curd %u resid %u", 133253036e92SMatt Jacob cto->ct_rxid, cso->scsi_status, atp->orig_datalen, 133353036e92SMatt Jacob cso->dxfer_len, cto->ct_resid); 1334a1bc34c6SMatt Jacob cto->ct_flags |= CT2_CCINCR; 1335570c7a3fSMatt Jacob atp->state = ATPD_STATE_LAST_CTIO; 13369cd7268eSMatt Jacob } else { 1337570c7a3fSMatt Jacob atp->state = ATPD_STATE_CTIO; 13389cd7268eSMatt Jacob } 1339a1bc34c6SMatt Jacob cto->ct_timeout = 10; 13405f5aafe1SMatt Jacob hp = &cto->ct_syshandle; 1341d81ba9d5SMatt Jacob } else { 13424fd13c1bSMatt Jacob ct_entry_t *cto = (ct_entry_t *) local; 134300a8e174SMatt Jacob 1344d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 1345d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_count = 1; 134600a8e174SMatt Jacob cto->ct_iid = cso->init_id; 1347a1bc34c6SMatt Jacob cto->ct_iid |= XS_CHANNEL(ccb) << 7; 1348d81ba9d5SMatt Jacob cto->ct_tgt = ccb->ccb_h.target_id; 1349d81ba9d5SMatt Jacob cto->ct_lun = ccb->ccb_h.target_lun; 1350a1bc34c6SMatt Jacob cto->ct_fwhandle = AT_GET_HANDLE(cso->tag_id); 1351a1bc34c6SMatt Jacob if (AT_HAS_TAG(cso->tag_id)) { 13521dae40ebSMatt Jacob cto->ct_tag_val = (uint8_t) AT_GET_TAG(cso->tag_id); 1353f48ce188SMatt Jacob cto->ct_flags |= CT_TQAE; 1354f48ce188SMatt Jacob } 1355f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) { 1356f48ce188SMatt Jacob cto->ct_flags |= CT_NODISC; 1357f48ce188SMatt Jacob } 1358f48ce188SMatt Jacob if (cso->dxfer_len == 0) { 1359d81ba9d5SMatt Jacob cto->ct_flags |= CT_NO_DATA; 136000a8e174SMatt Jacob } else if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 136100a8e174SMatt Jacob cto->ct_flags |= CT_DATA_IN; 136200a8e174SMatt Jacob } else { 136300a8e174SMatt Jacob cto->ct_flags |= CT_DATA_OUT; 1364d81ba9d5SMatt Jacob } 1365f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 136653036e92SMatt Jacob cto->ct_flags |= CT_SENDSTATUS|CT_CCINCR; 136700a8e174SMatt Jacob cto->ct_scsi_status = cso->scsi_status; 136800a8e174SMatt Jacob cto->ct_resid = cso->resid; 136964edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1370a1bc34c6SMatt Jacob "CTIO[%x] SCSI STATUS 0x%x resid %d tag_id %x", 1371a1bc34c6SMatt Jacob cto->ct_fwhandle, cso->scsi_status, cso->resid, 1372a1bc34c6SMatt Jacob cso->tag_id); 137392a1e549SMatt Jacob } 137464edff94SMatt Jacob ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 1375a1bc34c6SMatt Jacob cto->ct_timeout = 10; 13765f5aafe1SMatt Jacob hp = &cto->ct_syshandle; 1377d81ba9d5SMatt Jacob } 1378d81ba9d5SMatt Jacob 137951e23558SNate Lawson if (isp_save_xs_tgt(isp, ccb, hp)) { 138092a1e549SMatt Jacob xpt_print_path(ccb->ccb_h.path); 138192a1e549SMatt Jacob printf("No XFLIST pointers for isp_target_start_ctio\n"); 13829cd7268eSMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 13839cd7268eSMatt Jacob goto out; 1384d81ba9d5SMatt Jacob } 1385d81ba9d5SMatt Jacob 1386d81ba9d5SMatt Jacob 1387d81ba9d5SMatt Jacob /* 1388d81ba9d5SMatt Jacob * Call the dma setup routines for this entry (and any subsequent 1389d81ba9d5SMatt Jacob * CTIOs) if there's data to move, and then tell the f/w it's got 1390b09b0095SMatt Jacob * new things to play with. As with isp_start's usage of DMA setup, 1391d81ba9d5SMatt Jacob * any swizzling is done in the machine dependent layer. Because 1392d81ba9d5SMatt Jacob * of this, we put the request onto the queue area first in native 1393d81ba9d5SMatt Jacob * format. 1394d81ba9d5SMatt Jacob */ 1395d81ba9d5SMatt Jacob 1396d81ba9d5SMatt Jacob save_handle = *hp; 1397a1bc34c6SMatt Jacob 13984fd13c1bSMatt Jacob switch (ISP_DMASETUP(isp, cso, (ispreq_t *) local, &nxti, optr)) { 1399d81ba9d5SMatt Jacob case CMD_QUEUED: 14004fd13c1bSMatt Jacob ISP_ADD_REQUEST(isp, nxti); 14019cd7268eSMatt Jacob ccb->ccb_h.status |= CAM_SIM_QUEUED; 14029cd7268eSMatt Jacob return; 1403d81ba9d5SMatt Jacob 1404d81ba9d5SMatt Jacob case CMD_EAGAIN: 14059cd7268eSMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 14069cd7268eSMatt Jacob break; 1407d81ba9d5SMatt Jacob 1408d81ba9d5SMatt Jacob default: 14099cd7268eSMatt Jacob break; 1410d81ba9d5SMatt Jacob } 14119cd7268eSMatt Jacob isp_destroy_tgt_handle(isp, save_handle); 14129cd7268eSMatt Jacob 14139cd7268eSMatt Jacob out: 14149cd7268eSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 14159cd7268eSMatt Jacob xpt_done(ccb); 14169cd7268eSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 1417d81ba9d5SMatt Jacob } 1418d81ba9d5SMatt Jacob 1419a1bc34c6SMatt Jacob static void 1420a1bc34c6SMatt Jacob isp_refire_putback_atio(void *arg) 1421f48ce188SMatt Jacob { 1422a1bc34c6SMatt Jacob int s = splcam(); 1423a1bc34c6SMatt Jacob isp_target_putback_atio(arg); 1424a1bc34c6SMatt Jacob splx(s); 1425a1bc34c6SMatt Jacob } 1426a1bc34c6SMatt Jacob 1427a1bc34c6SMatt Jacob static void 1428a1bc34c6SMatt Jacob isp_target_putback_atio(union ccb *ccb) 1429a1bc34c6SMatt Jacob { 14309cd7268eSMatt Jacob ispsoftc_t *isp; 1431a1bc34c6SMatt Jacob struct ccb_scsiio *cso; 14321dae40ebSMatt Jacob uint16_t nxti, optr; 1433a1bc34c6SMatt Jacob void *qe; 1434a1bc34c6SMatt Jacob 1435a1bc34c6SMatt Jacob isp = XS_ISP(ccb); 1436f48ce188SMatt Jacob 14374fd13c1bSMatt Jacob if (isp_getrqentry(isp, &nxti, &optr, &qe)) { 1438a1bc34c6SMatt Jacob (void) timeout(isp_refire_putback_atio, ccb, 10); 1439a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGWARN, 1440a1bc34c6SMatt Jacob "isp_target_putback_atio: Request Queue Overflow"); 1441a1bc34c6SMatt Jacob return; 1442f48ce188SMatt Jacob } 1443f48ce188SMatt Jacob bzero(qe, QENTRY_LEN); 1444a1bc34c6SMatt Jacob cso = &ccb->csio; 1445f48ce188SMatt Jacob if (IS_FC(isp)) { 14464fd13c1bSMatt Jacob at2_entry_t local, *at = &local; 14474fd13c1bSMatt Jacob MEMZERO(at, sizeof (at2_entry_t)); 1448f48ce188SMatt Jacob at->at_header.rqs_entry_type = RQSTYPE_ATIO2; 1449f48ce188SMatt Jacob at->at_header.rqs_entry_count = 1; 145064edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) != 0) { 1451a1bc34c6SMatt Jacob at->at_scclun = (uint16_t) ccb->ccb_h.target_lun; 1452f48ce188SMatt Jacob } else { 1453a1bc34c6SMatt Jacob at->at_lun = (uint8_t) ccb->ccb_h.target_lun; 1454f48ce188SMatt Jacob } 1455f48ce188SMatt Jacob at->at_status = CT_OK; 1456a1bc34c6SMatt Jacob at->at_rxid = cso->tag_id; 1457570c7a3fSMatt Jacob at->at_iid = cso->ccb_h.target_id; 14584fd13c1bSMatt Jacob isp_put_atio2(isp, at, qe); 1459f48ce188SMatt Jacob } else { 14604fd13c1bSMatt Jacob at_entry_t local, *at = &local; 14614fd13c1bSMatt Jacob MEMZERO(at, sizeof (at_entry_t)); 1462f48ce188SMatt Jacob at->at_header.rqs_entry_type = RQSTYPE_ATIO; 1463f48ce188SMatt Jacob at->at_header.rqs_entry_count = 1; 1464a1bc34c6SMatt Jacob at->at_iid = cso->init_id; 1465a1bc34c6SMatt Jacob at->at_iid |= XS_CHANNEL(ccb) << 7; 1466a1bc34c6SMatt Jacob at->at_tgt = cso->ccb_h.target_id; 1467a1bc34c6SMatt Jacob at->at_lun = cso->ccb_h.target_lun; 1468f48ce188SMatt Jacob at->at_status = CT_OK; 1469a1bc34c6SMatt Jacob at->at_tag_val = AT_GET_TAG(cso->tag_id); 1470a1bc34c6SMatt Jacob at->at_handle = AT_GET_HANDLE(cso->tag_id); 14714fd13c1bSMatt Jacob isp_put_atio(isp, at, qe); 1472f48ce188SMatt Jacob } 1473f48ce188SMatt Jacob ISP_TDQE(isp, "isp_target_putback_atio", (int) optr, qe); 14744fd13c1bSMatt Jacob ISP_ADD_REQUEST(isp, nxti); 1475a1bc34c6SMatt Jacob isp_complete_ctio(ccb); 1476f48ce188SMatt Jacob } 1477f48ce188SMatt Jacob 1478f48ce188SMatt Jacob static void 1479a1bc34c6SMatt Jacob isp_complete_ctio(union ccb *ccb) 1480f48ce188SMatt Jacob { 14819cd7268eSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1482a1bc34c6SMatt Jacob if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { 1483a1bc34c6SMatt Jacob ccb->ccb_h.status |= CAM_REQ_CMP; 1484f48ce188SMatt Jacob } 1485a1bc34c6SMatt Jacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1486a1bc34c6SMatt Jacob xpt_done(ccb); 14879cd7268eSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 1488f48ce188SMatt Jacob } 1489f48ce188SMatt Jacob 1490d81ba9d5SMatt Jacob /* 1491d81ba9d5SMatt Jacob * Handle ATIO stuff that the generic code can't. 1492d81ba9d5SMatt Jacob * This means handling CDBs. 1493d81ba9d5SMatt Jacob */ 1494d81ba9d5SMatt Jacob 1495d81ba9d5SMatt Jacob static int 14969cd7268eSMatt Jacob isp_handle_platform_atio(ispsoftc_t *isp, at_entry_t *aep) 1497d81ba9d5SMatt Jacob { 1498d81ba9d5SMatt Jacob tstate_t *tptr; 149964edff94SMatt Jacob int status, bus, iswildcard; 1500d81ba9d5SMatt Jacob struct ccb_accept_tio *atiop; 1501d81ba9d5SMatt Jacob 1502d81ba9d5SMatt Jacob /* 1503d81ba9d5SMatt Jacob * The firmware status (except for the QLTM_SVALID bit) 1504d81ba9d5SMatt Jacob * indicates why this ATIO was sent to us. 1505d81ba9d5SMatt Jacob * 1506d81ba9d5SMatt Jacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 1507d81ba9d5SMatt Jacob * 1508d81ba9d5SMatt Jacob * If the DISCONNECTS DISABLED bit is set in the flags field, 15095d571944SMatt Jacob * we're still connected on the SCSI bus. 1510d81ba9d5SMatt Jacob */ 1511d81ba9d5SMatt Jacob status = aep->at_status; 1512d81ba9d5SMatt Jacob if ((status & ~QLTM_SVALID) == AT_PHASE_ERROR) { 1513d81ba9d5SMatt Jacob /* 1514d81ba9d5SMatt Jacob * Bus Phase Sequence error. We should have sense data 1515d81ba9d5SMatt Jacob * suggested by the f/w. I'm not sure quite yet what 1516d81ba9d5SMatt Jacob * to do about this for CAM. 1517d81ba9d5SMatt Jacob */ 15183c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, "PHASE ERROR"); 1519d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1520d81ba9d5SMatt Jacob return (0); 1521d81ba9d5SMatt Jacob } 1522d81ba9d5SMatt Jacob if ((status & ~QLTM_SVALID) != AT_CDB) { 15235d571944SMatt Jacob isp_prt(isp, ISP_LOGWARN, "bad atio (0x%x) leaked to platform", 15243c75bb14SMatt Jacob status); 1525d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1526d81ba9d5SMatt Jacob return (0); 1527d81ba9d5SMatt Jacob } 1528d81ba9d5SMatt Jacob 15295d571944SMatt Jacob bus = GET_BUS_VAL(aep->at_iid); 1530a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, aep->at_lun); 1531d81ba9d5SMatt Jacob if (tptr == NULL) { 1532a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD); 1533746e9c85SMatt Jacob if (tptr == NULL) { 1534746e9c85SMatt Jacob isp_endcmd(isp, aep, 1535746e9c85SMatt Jacob SCSI_STATUS_CHECK_COND | ECMD_SVALID | 1536746e9c85SMatt Jacob (0x5 << 12) | (0x25 << 16), 0); 1537746e9c85SMatt Jacob return (0); 1538746e9c85SMatt Jacob } 153964edff94SMatt Jacob iswildcard = 1; 154064edff94SMatt Jacob } else { 154164edff94SMatt Jacob iswildcard = 0; 1542d81ba9d5SMatt Jacob } 1543d81ba9d5SMatt Jacob 1544d81ba9d5SMatt Jacob if (tptr == NULL) { 1545d81ba9d5SMatt Jacob /* 1546d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1547d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1548d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a BUSY status 1549d81ba9d5SMatt Jacob * instead. This works out okay because the only 1550d81ba9d5SMatt Jacob * time we should, in fact, get this, is in the 1551d81ba9d5SMatt Jacob * case that somebody configured us without the 1552d81ba9d5SMatt Jacob * blackhole driver, so they get what they deserve. 1553d81ba9d5SMatt Jacob */ 1554d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1555d81ba9d5SMatt Jacob return (0); 1556d81ba9d5SMatt Jacob } 1557d81ba9d5SMatt Jacob 1558d81ba9d5SMatt Jacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 1559d81ba9d5SMatt Jacob if (atiop == NULL) { 1560d81ba9d5SMatt Jacob /* 1561d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1562d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1563d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a QUEUE FULL status 1564d81ba9d5SMatt Jacob * instead. This works out okay because the only time we 1565d81ba9d5SMatt Jacob * should, in fact, get this, is in the case that we've 1566d81ba9d5SMatt Jacob * run out of ATIOS. 1567d81ba9d5SMatt Jacob */ 1568d81ba9d5SMatt Jacob xpt_print_path(tptr->owner); 15693c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 1570a1bc34c6SMatt Jacob "no ATIOS for lun %d from initiator %d on channel %d", 15715d571944SMatt Jacob aep->at_lun, GET_IID_VAL(aep->at_iid), bus); 1572d81ba9d5SMatt Jacob if (aep->at_flags & AT_TQAE) 1573d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); 1574d81ba9d5SMatt Jacob else 1575d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 157664edff94SMatt Jacob rls_lun_statep(isp, tptr); 1577d81ba9d5SMatt Jacob return (0); 1578d81ba9d5SMatt Jacob } 1579d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 1580746e9c85SMatt Jacob tptr->atio_count--; 1581746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO lun %d, count now %d", 1582746e9c85SMatt Jacob aep->at_lun, tptr->atio_count); 158364edff94SMatt Jacob if (iswildcard) { 1584d81ba9d5SMatt Jacob atiop->ccb_h.target_id = aep->at_tgt; 1585d81ba9d5SMatt Jacob atiop->ccb_h.target_lun = aep->at_lun; 1586d81ba9d5SMatt Jacob } 1587d81ba9d5SMatt Jacob if (aep->at_flags & AT_NODISC) { 1588f48ce188SMatt Jacob atiop->ccb_h.flags = CAM_DIS_DISCONNECT; 1589f48ce188SMatt Jacob } else { 1590f48ce188SMatt Jacob atiop->ccb_h.flags = 0; 1591d81ba9d5SMatt Jacob } 1592d81ba9d5SMatt Jacob 1593f48ce188SMatt Jacob if (status & QLTM_SVALID) { 1594f48ce188SMatt Jacob size_t amt = imin(QLTM_SENSELEN, sizeof (atiop->sense_data)); 1595f48ce188SMatt Jacob atiop->sense_len = amt; 1596f48ce188SMatt Jacob MEMCPY(&atiop->sense_data, aep->at_sense, amt); 1597f48ce188SMatt Jacob } else { 1598f48ce188SMatt Jacob atiop->sense_len = 0; 1599f48ce188SMatt Jacob } 1600d81ba9d5SMatt Jacob 16015d571944SMatt Jacob atiop->init_id = GET_IID_VAL(aep->at_iid); 1602d81ba9d5SMatt Jacob atiop->cdb_len = aep->at_cdblen; 1603d81ba9d5SMatt Jacob MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen); 1604d81ba9d5SMatt Jacob atiop->ccb_h.status = CAM_CDB_RECVD; 1605a1bc34c6SMatt Jacob /* 1606a1bc34c6SMatt Jacob * Construct a tag 'id' based upon tag value (which may be 0..255) 1607a1bc34c6SMatt Jacob * and the handle (which we have to preserve). 1608a1bc34c6SMatt Jacob */ 16099f242f78SMatt Jacob AT_MAKE_TAGID(atiop->tag_id, device_get_unit(isp->isp_dev), aep); 1610a1bc34c6SMatt Jacob if (aep->at_flags & AT_TQAE) { 1611a1bc34c6SMatt Jacob atiop->tag_action = aep->at_tag_type; 1612d81ba9d5SMatt Jacob atiop->ccb_h.status |= CAM_TAG_ACTION_VALID; 1613d81ba9d5SMatt Jacob } 1614d81ba9d5SMatt Jacob xpt_done((union ccb*)atiop); 161564edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 16165d571944SMatt Jacob "ATIO[%x] CDB=0x%x bus %d iid%d->lun%d tag 0x%x ttype 0x%x %s", 16175d571944SMatt Jacob aep->at_handle, aep->at_cdb[0] & 0xff, GET_BUS_VAL(aep->at_iid), 16185d571944SMatt Jacob GET_IID_VAL(aep->at_iid), aep->at_lun, aep->at_tag_val & 0xff, 16195d571944SMatt Jacob aep->at_tag_type, (aep->at_flags & AT_NODISC)? 16205d571944SMatt Jacob "nondisc" : "disconnecting"); 1621d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1622d81ba9d5SMatt Jacob return (0); 1623d81ba9d5SMatt Jacob } 1624d81ba9d5SMatt Jacob 1625d81ba9d5SMatt Jacob static int 16269cd7268eSMatt Jacob isp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep) 1627d81ba9d5SMatt Jacob { 162892a1e549SMatt Jacob lun_id_t lun; 1629d81ba9d5SMatt Jacob tstate_t *tptr; 1630d81ba9d5SMatt Jacob struct ccb_accept_tio *atiop; 163153036e92SMatt Jacob atio_private_data_t *atp; 1632d81ba9d5SMatt Jacob 1633d81ba9d5SMatt Jacob /* 1634d81ba9d5SMatt Jacob * The firmware status (except for the QLTM_SVALID bit) 1635d81ba9d5SMatt Jacob * indicates why this ATIO was sent to us. 1636d81ba9d5SMatt Jacob * 1637d81ba9d5SMatt Jacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 1638d81ba9d5SMatt Jacob */ 1639d81ba9d5SMatt Jacob if ((aep->at_status & ~QLTM_SVALID) != AT_CDB) { 16403c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 16413c75bb14SMatt Jacob "bogus atio (0x%x) leaked to platform", aep->at_status); 1642d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1643d81ba9d5SMatt Jacob return (0); 1644d81ba9d5SMatt Jacob } 1645d81ba9d5SMatt Jacob 164664edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) != 0) { 164792a1e549SMatt Jacob lun = aep->at_scclun; 16482ad50ca5SMatt Jacob } else { 164992a1e549SMatt Jacob lun = aep->at_lun; 16502ad50ca5SMatt Jacob } 1651a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, 0, lun); 1652d81ba9d5SMatt Jacob if (tptr == NULL) { 1653746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1654746e9c85SMatt Jacob "[0x%x] no state pointer for lun %d", aep->at_rxid, lun); 1655a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD); 1656746e9c85SMatt Jacob if (tptr == NULL) { 1657746e9c85SMatt Jacob isp_endcmd(isp, aep, 1658746e9c85SMatt Jacob SCSI_STATUS_CHECK_COND | ECMD_SVALID | 1659746e9c85SMatt Jacob (0x5 << 12) | (0x25 << 16), 0); 1660746e9c85SMatt Jacob return (0); 1661746e9c85SMatt Jacob } 1662d81ba9d5SMatt Jacob } 1663d81ba9d5SMatt Jacob 166453036e92SMatt Jacob atp = isp_get_atpd(isp, 0); 1665d81ba9d5SMatt Jacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 166653036e92SMatt Jacob if (atiop == NULL || atp == NULL) { 1667746e9c85SMatt Jacob 1668d81ba9d5SMatt Jacob /* 1669d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1670d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1671d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a QUEUE FULL status 1672d81ba9d5SMatt Jacob * instead. This works out okay because the only time we 1673d81ba9d5SMatt Jacob * should, in fact, get this, is in the case that we've 1674d81ba9d5SMatt Jacob * run out of ATIOS. 1675d81ba9d5SMatt Jacob */ 1676d81ba9d5SMatt Jacob xpt_print_path(tptr->owner); 16773c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 1678570c7a3fSMatt Jacob "no %s for lun %d from initiator %d", 1679570c7a3fSMatt Jacob (atp == NULL && atiop == NULL)? "ATIO2s *or* ATPS" : 1680570c7a3fSMatt Jacob ((atp == NULL)? "ATPs" : "ATIO2s"), lun, aep->at_iid); 1681d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1682d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); 1683d81ba9d5SMatt Jacob return (0); 1684d81ba9d5SMatt Jacob } 1685570c7a3fSMatt Jacob atp->state = ATPD_STATE_ATIO; 1686d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 1687570c7a3fSMatt Jacob tptr->atio_count--; 1688746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO lun %d, count now %d", 1689570c7a3fSMatt Jacob lun, tptr->atio_count); 1690f48ce188SMatt Jacob 1691a1bc34c6SMatt Jacob if (tptr == &isp->isp_osinfo.tsdflt[0]) { 1692d81ba9d5SMatt Jacob atiop->ccb_h.target_id = 1693d81ba9d5SMatt Jacob ((fcparam *)isp->isp_param)->isp_loopid; 169492a1e549SMatt Jacob atiop->ccb_h.target_lun = lun; 1695d81ba9d5SMatt Jacob } 1696b0a3ba7eSMatt Jacob /* 1697b0a3ba7eSMatt Jacob * We don't get 'suggested' sense data as we do with SCSI cards. 1698b0a3ba7eSMatt Jacob */ 1699f48ce188SMatt Jacob atiop->sense_len = 0; 1700f48ce188SMatt Jacob 1701d81ba9d5SMatt Jacob atiop->init_id = aep->at_iid; 1702d81ba9d5SMatt Jacob atiop->cdb_len = ATIO2_CDBLEN; 1703d81ba9d5SMatt Jacob MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, ATIO2_CDBLEN); 1704d81ba9d5SMatt Jacob atiop->ccb_h.status = CAM_CDB_RECVD; 1705d81ba9d5SMatt Jacob atiop->tag_id = aep->at_rxid; 1706d81ba9d5SMatt Jacob switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) { 1707d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_SIMPLEQ: 1708d81ba9d5SMatt Jacob atiop->tag_action = MSG_SIMPLE_Q_TAG; 1709d81ba9d5SMatt Jacob break; 1710d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_HEADOFQ: 1711d81ba9d5SMatt Jacob atiop->tag_action = MSG_HEAD_OF_Q_TAG; 1712d81ba9d5SMatt Jacob break; 1713d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_ORDERED: 1714d81ba9d5SMatt Jacob atiop->tag_action = MSG_ORDERED_Q_TAG; 1715d81ba9d5SMatt Jacob break; 1716d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_ACAQ: /* ?? */ 1717d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_UNTAGGED: 1718d81ba9d5SMatt Jacob default: 1719d81ba9d5SMatt Jacob atiop->tag_action = 0; 1720d81ba9d5SMatt Jacob break; 1721d81ba9d5SMatt Jacob } 1722570c7a3fSMatt Jacob atiop->ccb_h.flags = CAM_TAG_ACTION_VALID; 1723f48ce188SMatt Jacob 172453036e92SMatt Jacob atp->tag = atiop->tag_id; 1725570c7a3fSMatt Jacob atp->lun = lun; 172653036e92SMatt Jacob atp->orig_datalen = aep->at_datalen; 172753036e92SMatt Jacob atp->last_xframt = 0; 172853036e92SMatt Jacob atp->bytes_xfered = 0; 1729570c7a3fSMatt Jacob atp->state = ATPD_STATE_CAM; 173067ff51f1SMatt Jacob ISPLOCK_2_CAMLOCK(siP); 1731d81ba9d5SMatt Jacob xpt_done((union ccb*)atiop); 1732570c7a3fSMatt Jacob 173364edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 17345f5aafe1SMatt Jacob "ATIO2[%x] CDB=0x%x iid%d->lun%d tattr 0x%x datalen %u", 17355f5aafe1SMatt Jacob aep->at_rxid, aep->at_cdb[0] & 0xff, aep->at_iid, 1736b09b0095SMatt Jacob lun, aep->at_taskflags, aep->at_datalen); 1737d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1738d81ba9d5SMatt Jacob return (0); 1739d81ba9d5SMatt Jacob } 1740d81ba9d5SMatt Jacob 1741d81ba9d5SMatt Jacob static int 17429cd7268eSMatt Jacob isp_handle_platform_ctio(ispsoftc_t *isp, void *arg) 1743d81ba9d5SMatt Jacob { 1744d81ba9d5SMatt Jacob union ccb *ccb; 1745a1bc34c6SMatt Jacob int sentstatus, ok, notify_cam, resid = 0; 17461dae40ebSMatt Jacob uint16_t tval; 1747d81ba9d5SMatt Jacob 1748d81ba9d5SMatt Jacob /* 1749d81ba9d5SMatt Jacob * CTIO and CTIO2 are close enough.... 1750d81ba9d5SMatt Jacob */ 1751d81ba9d5SMatt Jacob 175251e23558SNate Lawson ccb = isp_find_xs_tgt(isp, ((ct_entry_t *)arg)->ct_syshandle); 1753d81ba9d5SMatt Jacob KASSERT((ccb != NULL), ("null ccb in isp_handle_platform_ctio")); 175451e23558SNate Lawson isp_destroy_tgt_handle(isp, ((ct_entry_t *)arg)->ct_syshandle); 1755d81ba9d5SMatt Jacob 1756d81ba9d5SMatt Jacob if (IS_FC(isp)) { 1757d81ba9d5SMatt Jacob ct2_entry_t *ct = arg; 1758570c7a3fSMatt Jacob atio_private_data_t *atp = isp_get_atpd(isp, ct->ct_rxid); 1759570c7a3fSMatt Jacob if (atp == NULL) { 1760570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGERR, 1761570c7a3fSMatt Jacob "cannot find adjunct for %x after I/O", 1762570c7a3fSMatt Jacob ct->ct_rxid); 1763570c7a3fSMatt Jacob return (0); 1764570c7a3fSMatt Jacob } 1765d81ba9d5SMatt Jacob sentstatus = ct->ct_flags & CT2_SENDSTATUS; 1766d81ba9d5SMatt Jacob ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; 1767a1bc34c6SMatt Jacob if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) { 176800a8e174SMatt Jacob ccb->ccb_h.status |= CAM_SENT_SENSE; 176900a8e174SMatt Jacob } 1770a1bc34c6SMatt Jacob notify_cam = ct->ct_header.rqs_seqno & 0x1; 17715d571944SMatt Jacob if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) { 1772a1bc34c6SMatt Jacob resid = ct->ct_resid; 177353036e92SMatt Jacob atp->bytes_xfered += (atp->last_xframt - resid); 177453036e92SMatt Jacob atp->last_xframt = 0; 1775570c7a3fSMatt Jacob } 1776570c7a3fSMatt Jacob if (sentstatus || !ok) { 177753036e92SMatt Jacob atp->tag = 0; 177853036e92SMatt Jacob } 1779570c7a3fSMatt Jacob isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, 178064edff94SMatt Jacob "CTIO2[%x] sts 0x%x flg 0x%x sns %d resid %d %s", 178164edff94SMatt Jacob ct->ct_rxid, ct->ct_status, ct->ct_flags, 178264edff94SMatt Jacob (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, 178364edff94SMatt Jacob resid, sentstatus? "FIN" : "MID"); 178464edff94SMatt Jacob tval = ct->ct_rxid; 1785570c7a3fSMatt Jacob 1786570c7a3fSMatt Jacob /* XXX: should really come after isp_complete_ctio */ 1787570c7a3fSMatt Jacob atp->state = ATPD_STATE_PDON; 1788d81ba9d5SMatt Jacob } else { 1789d81ba9d5SMatt Jacob ct_entry_t *ct = arg; 1790d81ba9d5SMatt Jacob sentstatus = ct->ct_flags & CT_SENDSTATUS; 1791d81ba9d5SMatt Jacob ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; 1792d81ba9d5SMatt Jacob /* 1793a1bc34c6SMatt Jacob * We *ought* to be able to get back to the original ATIO 1794a1bc34c6SMatt Jacob * here, but for some reason this gets lost. It's just as 1795a1bc34c6SMatt Jacob * well because it's squirrelled away as part of periph 1796a1bc34c6SMatt Jacob * private data. 1797a1bc34c6SMatt Jacob * 1798a1bc34c6SMatt Jacob * We can live without it as long as we continue to use 1799a1bc34c6SMatt Jacob * the auto-replenish feature for CTIOs. 1800a1bc34c6SMatt Jacob */ 1801a1bc34c6SMatt Jacob notify_cam = ct->ct_header.rqs_seqno & 0x1; 1802a1bc34c6SMatt Jacob if (ct->ct_status & QLTM_SVALID) { 1803a1bc34c6SMatt Jacob char *sp = (char *)ct; 1804a1bc34c6SMatt Jacob sp += CTIO_SENSE_OFFSET; 1805a1bc34c6SMatt Jacob ccb->csio.sense_len = 1806a1bc34c6SMatt Jacob min(sizeof (ccb->csio.sense_data), QLTM_SENSELEN); 1807a1bc34c6SMatt Jacob MEMCPY(&ccb->csio.sense_data, sp, ccb->csio.sense_len); 1808a1bc34c6SMatt Jacob ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 1809a1bc34c6SMatt Jacob } 18105d571944SMatt Jacob if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) { 1811a1bc34c6SMatt Jacob resid = ct->ct_resid; 1812a1bc34c6SMatt Jacob } 181364edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 181464edff94SMatt Jacob "CTIO[%x] tag %x iid %d lun %d sts %x flg %x resid %d %s", 181564edff94SMatt Jacob ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_lun, 181664edff94SMatt Jacob ct->ct_status, ct->ct_flags, resid, 181764edff94SMatt Jacob sentstatus? "FIN" : "MID"); 181864edff94SMatt Jacob tval = ct->ct_fwhandle; 18195d571944SMatt Jacob } 1820a1bc34c6SMatt Jacob ccb->csio.resid += resid; 1821a1bc34c6SMatt Jacob 1822a1bc34c6SMatt Jacob /* 1823a1bc34c6SMatt Jacob * We're here either because intermediate data transfers are done 1824a1bc34c6SMatt Jacob * and/or the final status CTIO (which may have joined with a 1825a1bc34c6SMatt Jacob * Data Transfer) is done. 1826d81ba9d5SMatt Jacob * 1827d81ba9d5SMatt Jacob * In any case, for this platform, the upper layers figure out 1828d81ba9d5SMatt Jacob * what to do next, so all we do here is collect status and 1829a1bc34c6SMatt Jacob * pass information along. Any DMA handles have already been 1830a1bc34c6SMatt Jacob * freed. 1831d81ba9d5SMatt Jacob */ 1832f48ce188SMatt Jacob if (notify_cam == 0) { 183364edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, " INTER CTIO[0x%x] done", tval); 1834f48ce188SMatt Jacob return (0); 1835f48ce188SMatt Jacob } 1836d81ba9d5SMatt Jacob 183753036e92SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO[0x%x] done", 183853036e92SMatt Jacob (sentstatus)? " FINAL " : "MIDTERM ", tval); 1839a1bc34c6SMatt Jacob 1840a1bc34c6SMatt Jacob if (!ok) { 1841a1bc34c6SMatt Jacob isp_target_putback_atio(ccb); 1842d81ba9d5SMatt Jacob } else { 1843a1bc34c6SMatt Jacob isp_complete_ctio(ccb); 1844a1bc34c6SMatt Jacob 1845d81ba9d5SMatt Jacob } 1846a1bc34c6SMatt Jacob return (0); 1847d81ba9d5SMatt Jacob } 1848570c7a3fSMatt Jacob 1849570c7a3fSMatt Jacob static int 18509cd7268eSMatt Jacob isp_handle_platform_notify_scsi(ispsoftc_t *isp, in_entry_t *inp) 1851570c7a3fSMatt Jacob { 1852570c7a3fSMatt Jacob return (0); /* XXXX */ 1853570c7a3fSMatt Jacob } 1854570c7a3fSMatt Jacob 1855570c7a3fSMatt Jacob static int 18569cd7268eSMatt Jacob isp_handle_platform_notify_fc(ispsoftc_t *isp, in_fcentry_t *inp) 1857570c7a3fSMatt Jacob { 1858570c7a3fSMatt Jacob 1859570c7a3fSMatt Jacob switch (inp->in_status) { 1860570c7a3fSMatt Jacob case IN_PORT_LOGOUT: 1861570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, "port logout of iid %d", 1862570c7a3fSMatt Jacob inp->in_iid); 1863570c7a3fSMatt Jacob break; 1864570c7a3fSMatt Jacob case IN_PORT_CHANGED: 1865570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, "port changed for iid %d", 1866570c7a3fSMatt Jacob inp->in_iid); 1867570c7a3fSMatt Jacob break; 1868570c7a3fSMatt Jacob case IN_GLOBAL_LOGO: 1869570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGINFO, "all ports logged out"); 1870570c7a3fSMatt Jacob break; 1871570c7a3fSMatt Jacob case IN_ABORT_TASK: 1872570c7a3fSMatt Jacob { 1873570c7a3fSMatt Jacob atio_private_data_t *atp = isp_get_atpd(isp, inp->in_seqid); 1874570c7a3fSMatt Jacob struct ccb_immed_notify *inot = NULL; 1875570c7a3fSMatt Jacob 1876570c7a3fSMatt Jacob if (atp) { 1877570c7a3fSMatt Jacob tstate_t *tptr = get_lun_statep(isp, 0, atp->lun); 1878570c7a3fSMatt Jacob if (tptr) { 1879570c7a3fSMatt Jacob inot = (struct ccb_immed_notify *) 1880570c7a3fSMatt Jacob SLIST_FIRST(&tptr->inots); 1881570c7a3fSMatt Jacob if (inot) { 1882746e9c85SMatt Jacob tptr->inot_count--; 1883570c7a3fSMatt Jacob SLIST_REMOVE_HEAD(&tptr->inots, 1884570c7a3fSMatt Jacob sim_links.sle); 1885746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1886746e9c85SMatt Jacob "Take FREE INOT count now %d", 1887746e9c85SMatt Jacob tptr->inot_count); 1888570c7a3fSMatt Jacob } 1889570c7a3fSMatt Jacob } 1890570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, 1891570c7a3fSMatt Jacob "abort task RX_ID %x IID %d state %d", 1892570c7a3fSMatt Jacob inp->in_seqid, inp->in_iid, atp->state); 1893570c7a3fSMatt Jacob } else { 1894570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, 1895570c7a3fSMatt Jacob "abort task RX_ID %x from iid %d, state unknown", 1896570c7a3fSMatt Jacob inp->in_seqid, inp->in_iid); 1897570c7a3fSMatt Jacob } 1898570c7a3fSMatt Jacob if (inot) { 1899570c7a3fSMatt Jacob inot->initiator_id = inp->in_iid; 1900570c7a3fSMatt Jacob inot->sense_len = 0; 1901570c7a3fSMatt Jacob inot->message_args[0] = MSG_ABORT_TAG; 1902570c7a3fSMatt Jacob inot->message_args[1] = inp->in_seqid & 0xff; 1903570c7a3fSMatt Jacob inot->message_args[2] = (inp->in_seqid >> 8) & 0xff; 1904570c7a3fSMatt Jacob inot->ccb_h.status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN; 1905570c7a3fSMatt Jacob xpt_done((union ccb *)inot); 1906570c7a3fSMatt Jacob } 1907570c7a3fSMatt Jacob break; 1908570c7a3fSMatt Jacob } 1909570c7a3fSMatt Jacob default: 1910570c7a3fSMatt Jacob break; 1911570c7a3fSMatt Jacob } 1912570c7a3fSMatt Jacob return (0); 1913570c7a3fSMatt Jacob } 1914d81ba9d5SMatt Jacob #endif 1915d81ba9d5SMatt Jacob 1916478f8a96SJustin T. Gibbs static void 19171dae40ebSMatt Jacob isp_cam_async(void *cbarg, uint32_t code, struct cam_path *path, void *arg) 1918478f8a96SJustin T. Gibbs { 1919478f8a96SJustin T. Gibbs struct cam_sim *sim; 19209cd7268eSMatt Jacob ispsoftc_t *isp; 1921478f8a96SJustin T. Gibbs 1922478f8a96SJustin T. Gibbs sim = (struct cam_sim *)cbarg; 19239cd7268eSMatt Jacob isp = (ispsoftc_t *) cam_sim_softc(sim); 1924478f8a96SJustin T. Gibbs switch (code) { 1925478f8a96SJustin T. Gibbs case AC_LOST_DEVICE: 1926ab6c4b31SMatt Jacob if (IS_SCSI(isp)) { 19271dae40ebSMatt Jacob uint16_t oflags, nflags; 1928478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 1929a1bc34c6SMatt Jacob int tgt; 1930478f8a96SJustin T. Gibbs 1931f9e908dcSMatt Jacob tgt = xpt_path_target_id(path); 193241ed683eSMatt Jacob if (tgt >= 0) { 1933ea6f23cdSMatt Jacob sdp += cam_sim_bus(sim); 193441ed683eSMatt Jacob ISP_LOCK(isp); 19359ce9bdafSMatt Jacob nflags = sdp->isp_devparam[tgt].nvrm_flags; 1936a1bc34c6SMatt Jacob #ifndef ISP_TARGET_MODE 19379ce9bdafSMatt Jacob nflags &= DPARM_SAFE_DFLT; 1938a1bc34c6SMatt Jacob if (isp->isp_loaded_fw) { 1939478f8a96SJustin T. Gibbs nflags |= DPARM_NARROW | DPARM_ASYNC; 1940478f8a96SJustin T. Gibbs } 1941a1bc34c6SMatt Jacob #else 1942a1bc34c6SMatt Jacob nflags = DPARM_DEFAULT; 1943a1bc34c6SMatt Jacob #endif 19449ce9bdafSMatt Jacob oflags = sdp->isp_devparam[tgt].goal_flags; 19459ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_flags = nflags; 1946478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_update = 1; 1947a1bc34c6SMatt Jacob isp->isp_update |= (1 << cam_sim_bus(sim)); 194841ed683eSMatt Jacob (void) isp_control(isp, 194941ed683eSMatt Jacob ISPCTL_UPDATE_PARAMS, NULL); 19509ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_flags = oflags; 1951f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1952478f8a96SJustin T. Gibbs } 195341ed683eSMatt Jacob } 1954478f8a96SJustin T. Gibbs break; 1955478f8a96SJustin T. Gibbs default: 19563c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, "isp_cam_async: Code 0x%x", code); 1957478f8a96SJustin T. Gibbs break; 1958478f8a96SJustin T. Gibbs } 1959478f8a96SJustin T. Gibbs } 1960478f8a96SJustin T. Gibbs 1961478f8a96SJustin T. Gibbs static void 1962c3055363SMatt Jacob isp_poll(struct cam_sim *sim) 1963478f8a96SJustin T. Gibbs { 19649cd7268eSMatt Jacob ispsoftc_t *isp = cam_sim_softc(sim); 19651dae40ebSMatt Jacob uint16_t isr, sema, mbox; 1966126ec864SMatt Jacob 1967c40e096eSMatt Jacob ISP_LOCK(isp); 1968126ec864SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 1969126ec864SMatt Jacob isp_intr(isp, isr, sema, mbox); 1970126ec864SMatt Jacob } 1971c40e096eSMatt Jacob ISP_UNLOCK(isp); 1972478f8a96SJustin T. Gibbs } 1973478f8a96SJustin T. Gibbs 1974ab6c4b31SMatt Jacob 1975478f8a96SJustin T. Gibbs static void 1976b85389e1SMatt Jacob isp_watchdog(void *arg) 1977cc8df88bSMatt Jacob { 1978b09b0095SMatt Jacob XS_T *xs = arg; 19799cd7268eSMatt Jacob ispsoftc_t *isp = XS_ISP(xs); 19801dae40ebSMatt Jacob uint32_t handle; 1981fdeb9f2fSMatt Jacob int iok; 1982b85389e1SMatt Jacob 1983cc8df88bSMatt Jacob /* 1984b85389e1SMatt Jacob * We've decided this command is dead. Make sure we're not trying 1985b85389e1SMatt Jacob * to kill a command that's already dead by getting it's handle and 1986b85389e1SMatt Jacob * and seeing whether it's still alive. 1987cc8df88bSMatt Jacob */ 1988f6e75de2SMatt Jacob ISP_LOCK(isp); 1989fdeb9f2fSMatt Jacob iok = isp->isp_osinfo.intsok; 1990fdeb9f2fSMatt Jacob isp->isp_osinfo.intsok = 0; 1991cc8df88bSMatt Jacob handle = isp_find_handle(isp, xs); 1992cc8df88bSMatt Jacob if (handle) { 19931dae40ebSMatt Jacob uint16_t isr, sema, mbox; 1994126ec864SMatt Jacob 1995b85389e1SMatt Jacob if (XS_CMD_DONE_P(xs)) { 1996b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG1, 1997b09b0095SMatt Jacob "watchdog found done cmd (handle 0x%x)", handle); 1998f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1999b85389e1SMatt Jacob return; 2000b85389e1SMatt Jacob } 2001b85389e1SMatt Jacob 2002b85389e1SMatt Jacob if (XS_CMD_WDOG_P(xs)) { 2003b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2004b09b0095SMatt Jacob "recursive watchdog (handle 0x%x)", handle); 2005f6e75de2SMatt Jacob ISP_UNLOCK(isp); 2006b85389e1SMatt Jacob return; 2007b85389e1SMatt Jacob } 2008b85389e1SMatt Jacob 2009b85389e1SMatt Jacob XS_CMD_S_WDOG(xs); 2010126ec864SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 2011126ec864SMatt Jacob isp_intr(isp, isr, sema, mbox); 2012126ec864SMatt Jacob } 2013126ec864SMatt Jacob if (XS_CMD_DONE_P(xs)) { 2014b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2015126ec864SMatt Jacob "watchdog cleanup for handle 0x%x", handle); 2016b85389e1SMatt Jacob xpt_done((union ccb *) xs); 2017b85389e1SMatt Jacob } else if (XS_CMD_GRACE_P(xs)) { 20181fcf5debSMatt Jacob /* 20191fcf5debSMatt Jacob * Make sure the command is *really* dead before we 20201fcf5debSMatt Jacob * release the handle (and DMA resources) for reuse. 20211fcf5debSMatt Jacob */ 20221fcf5debSMatt Jacob (void) isp_control(isp, ISPCTL_ABORT_CMD, arg); 20231fcf5debSMatt Jacob 20241fcf5debSMatt Jacob /* 20251fcf5debSMatt Jacob * After this point, the comamnd is really dead. 20261fcf5debSMatt Jacob */ 2027f6e75de2SMatt Jacob if (XS_XFRLEN(xs)) { 2028f6e75de2SMatt Jacob ISP_DMAFREE(isp, xs, handle); 2029f6e75de2SMatt Jacob } 2030cc8df88bSMatt Jacob isp_destroy_handle(isp, handle); 2031cc8df88bSMatt Jacob xpt_print_path(xs->ccb_h.path); 20323c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 20332903b272SMatt Jacob "watchdog timeout for handle 0x%x", handle); 2034cc8df88bSMatt Jacob XS_SETERR(xs, CAM_CMD_TIMEOUT); 2035b85389e1SMatt Jacob XS_CMD_C_WDOG(xs); 2036cc8df88bSMatt Jacob isp_done(xs); 2037b85389e1SMatt Jacob } else { 20381dae40ebSMatt Jacob uint16_t nxti, optr; 20394fd13c1bSMatt Jacob ispreq_t local, *mp= &local, *qe; 2040b85389e1SMatt Jacob 2041b85389e1SMatt Jacob XS_CMD_C_WDOG(xs); 2042b85389e1SMatt Jacob xs->ccb_h.timeout_ch = timeout(isp_watchdog, xs, hz); 20434fd13c1bSMatt Jacob if (isp_getrqentry(isp, &nxti, &optr, (void **) &qe)) { 2044f6e75de2SMatt Jacob ISP_UNLOCK(isp); 2045b85389e1SMatt Jacob return; 2046b85389e1SMatt Jacob } 2047b85389e1SMatt Jacob XS_CMD_S_GRACE(xs); 2048b85389e1SMatt Jacob MEMZERO((void *) mp, sizeof (*mp)); 2049b85389e1SMatt Jacob mp->req_header.rqs_entry_count = 1; 2050b85389e1SMatt Jacob mp->req_header.rqs_entry_type = RQSTYPE_MARKER; 2051b85389e1SMatt Jacob mp->req_modifier = SYNC_ALL; 2052b85389e1SMatt Jacob mp->req_target = XS_CHANNEL(xs) << 7; 20534fd13c1bSMatt Jacob isp_put_request(isp, mp, qe); 20544fd13c1bSMatt Jacob ISP_ADD_REQUEST(isp, nxti); 2055b85389e1SMatt Jacob } 2056b85389e1SMatt Jacob } else { 2057b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "watchdog with no command"); 2058cc8df88bSMatt Jacob } 2059fdeb9f2fSMatt Jacob isp->isp_osinfo.intsok = iok; 2060f6e75de2SMatt Jacob ISP_UNLOCK(isp); 2061cc8df88bSMatt Jacob } 2062cc8df88bSMatt Jacob 20635d571944SMatt Jacob static void 20645d571944SMatt Jacob isp_kthread(void *arg) 20655d571944SMatt Jacob { 20669cd7268eSMatt Jacob ispsoftc_t *isp = arg; 20675d571944SMatt Jacob 20689cd7268eSMatt Jacob 20699cd7268eSMatt Jacob #if __FreeBSD_version < 500000 20709cd7268eSMatt Jacob int s; 20719cd7268eSMatt Jacob 20729cd7268eSMatt Jacob s = splcam(); 20739cd7268eSMatt Jacob isp->isp_osinfo.intsok = 1; 20749cd7268eSMatt Jacob #else 2075162e9893SMatt Jacob #ifdef ISP_SMPLOCK 20765d571944SMatt Jacob mtx_lock(&isp->isp_lock); 2077ee76282eSMatt Jacob #else 2078ee76282eSMatt Jacob mtx_lock(&Giant); 2079162e9893SMatt Jacob #endif 20809cd7268eSMatt Jacob #endif 2081fdeb9f2fSMatt Jacob /* 2082fdeb9f2fSMatt Jacob * The first loop is for our usage where we have yet to have 2083fdeb9f2fSMatt Jacob * gotten good fibre channel state. 2084fdeb9f2fSMatt Jacob */ 20855d571944SMatt Jacob for (;;) { 2086fdeb9f2fSMatt Jacob int wasfrozen; 2087fdeb9f2fSMatt Jacob 2088fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "kthread: checking FC state"); 20895d571944SMatt Jacob while (isp_fc_runstate(isp, 2 * 1000000) != 0) { 2090fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "kthread: FC state ungood"); 2091f44257c2SMatt Jacob if (FCPARAM(isp)->isp_fwstate != FW_READY || 2092f44257c2SMatt Jacob FCPARAM(isp)->isp_loopstate < LOOP_PDB_RCVD) { 2093f44257c2SMatt Jacob if (FCPARAM(isp)->loop_seen_once == 0 || 2094fdeb9f2fSMatt Jacob isp->isp_osinfo.ktmature == 0) { 2095f44257c2SMatt Jacob break; 2096f44257c2SMatt Jacob } 2097f44257c2SMatt Jacob } 2098162e9893SMatt Jacob #ifdef ISP_SMPLOCK 20995d571944SMatt Jacob msleep(isp_kthread, &isp->isp_lock, 21005d571944SMatt Jacob PRIBIO, "isp_fcthrd", hz); 2101162e9893SMatt Jacob #else 2102162e9893SMatt Jacob (void) tsleep(isp_kthread, PRIBIO, "isp_fcthrd", hz); 2103162e9893SMatt Jacob #endif 21045d571944SMatt Jacob } 2105fdeb9f2fSMatt Jacob 2106f44257c2SMatt Jacob /* 2107f44257c2SMatt Jacob * Even if we didn't get good loop state we may be 2108f44257c2SMatt Jacob * unfreezing the SIMQ so that we can kill off 2109fdeb9f2fSMatt Jacob * commands (if we've never seen loop before, for example). 2110f44257c2SMatt Jacob */ 2111fdeb9f2fSMatt Jacob isp->isp_osinfo.ktmature = 1; 21125d571944SMatt Jacob wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN; 21135d571944SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN; 21145d571944SMatt Jacob if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) { 2115fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "kthread: releasing simq"); 21165d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 21175d571944SMatt Jacob xpt_release_simq(isp->isp_sim, 1); 21185d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 21195d571944SMatt Jacob } 2120fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "kthread: waiting until called"); 21219cd7268eSMatt Jacob #if __FreeBSD_version < 500000 21229cd7268eSMatt Jacob tsleep(&isp->isp_osinfo.kproc, PRIBIO, "isp_fc_worker", 0); 21239cd7268eSMatt Jacob #else 2124162e9893SMatt Jacob #ifdef ISP_SMPLOCK 21255d571944SMatt Jacob cv_wait(&isp->isp_osinfo.kthread_cv, &isp->isp_lock); 2126162e9893SMatt Jacob #else 2127162e9893SMatt Jacob (void) tsleep(&isp->isp_osinfo.kthread_cv, PRIBIO, "fc_cv", 0); 2128162e9893SMatt Jacob #endif 21299cd7268eSMatt Jacob #endif 21305d571944SMatt Jacob } 21315d571944SMatt Jacob } 21325d571944SMatt Jacob 2133cc8df88bSMatt Jacob static void 2134c3055363SMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb) 2135478f8a96SJustin T. Gibbs { 2136f6e75de2SMatt Jacob int bus, tgt, error; 21379cd7268eSMatt Jacob ispsoftc_t *isp; 21384663e367SJustin T. Gibbs struct ccb_trans_settings *cts; 2139478f8a96SJustin T. Gibbs 2140478f8a96SJustin T. Gibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n")); 2141478f8a96SJustin T. Gibbs 21429cd7268eSMatt Jacob isp = (ispsoftc_t *)cam_sim_softc(sim); 2143478f8a96SJustin T. Gibbs ccb->ccb_h.sim_priv.entries[0].field = 0; 2144478f8a96SJustin T. Gibbs ccb->ccb_h.sim_priv.entries[1].ptr = isp; 21450470d791SMatt Jacob if (isp->isp_state != ISP_RUNSTATE && 21460470d791SMatt Jacob ccb->ccb_h.func_code == XPT_SCSI_IO) { 21475d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 214857c801f5SMatt Jacob isp_init(isp); 214957c801f5SMatt Jacob if (isp->isp_state != ISP_INITSTATE) { 2150f6e75de2SMatt Jacob ISP_UNLOCK(isp); 215157c801f5SMatt Jacob /* 215257c801f5SMatt Jacob * Lie. Say it was a selection timeout. 215357c801f5SMatt Jacob */ 2154b85389e1SMatt Jacob ccb->ccb_h.status = CAM_SEL_TIMEOUT | CAM_DEV_QFRZN; 21550470d791SMatt Jacob xpt_freeze_devq(ccb->ccb_h.path, 1); 215657c801f5SMatt Jacob xpt_done(ccb); 215757c801f5SMatt Jacob return; 215857c801f5SMatt Jacob } 215957c801f5SMatt Jacob isp->isp_state = ISP_RUNSTATE; 21605d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 216157c801f5SMatt Jacob } 2162b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "isp_action code %x", ccb->ccb_h.func_code); 2163478f8a96SJustin T. Gibbs 21645d571944SMatt Jacob 2165478f8a96SJustin T. Gibbs switch (ccb->ccb_h.func_code) { 2166478f8a96SJustin T. Gibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 2167478f8a96SJustin T. Gibbs /* 2168478f8a96SJustin T. Gibbs * Do a couple of preliminary checks... 2169478f8a96SJustin T. Gibbs */ 2170478f8a96SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { 2171478f8a96SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) { 2172478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2173478f8a96SJustin T. Gibbs xpt_done(ccb); 2174478f8a96SJustin T. Gibbs break; 2175478f8a96SJustin T. Gibbs } 2176478f8a96SJustin T. Gibbs } 21770470d791SMatt Jacob #ifdef DIAGNOSTIC 21780470d791SMatt Jacob if (ccb->ccb_h.target_id > (ISP_MAX_TARGETS(isp) - 1)) { 2179478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 21800470d791SMatt Jacob } else if (ccb->ccb_h.target_lun > (ISP_MAX_LUNS(isp) - 1)) { 2181478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 2182478f8a96SJustin T. Gibbs } 2183478f8a96SJustin T. Gibbs if (ccb->ccb_h.status == CAM_PATH_INVALID) { 2184bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 2185bfbab170SMatt Jacob "invalid tgt/lun (%d.%d) in XPT_SCSI_IO", 2186bfbab170SMatt Jacob ccb->ccb_h.target_id, ccb->ccb_h.target_lun); 2187478f8a96SJustin T. Gibbs xpt_done(ccb); 2188478f8a96SJustin T. Gibbs break; 2189478f8a96SJustin T. Gibbs } 21900470d791SMatt Jacob #endif 21910470d791SMatt Jacob ((struct ccb_scsiio *) ccb)->scsi_status = SCSI_STATUS_OK; 21925d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2193b09b0095SMatt Jacob error = isp_start((XS_T *) ccb); 21940470d791SMatt Jacob switch (error) { 2195478f8a96SJustin T. Gibbs case CMD_QUEUED: 2196478f8a96SJustin T. Gibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 2197cc8df88bSMatt Jacob if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { 21981dae40ebSMatt Jacob uint64_t ticks = (uint64_t) hz; 2199cc8df88bSMatt Jacob if (ccb->ccb_h.timeout == CAM_TIME_DEFAULT) 2200d69a5f7dSMatt Jacob ticks = 60 * 1000 * ticks; 2201b85389e1SMatt Jacob else 2202b85389e1SMatt Jacob ticks = ccb->ccb_h.timeout * hz; 2203b85389e1SMatt Jacob ticks = ((ticks + 999) / 1000) + hz + hz; 2204d69a5f7dSMatt Jacob if (ticks >= 0x80000000) { 2205d69a5f7dSMatt Jacob isp_prt(isp, ISP_LOGERR, 2206d69a5f7dSMatt Jacob "timeout overflow"); 2207fdeb9f2fSMatt Jacob ticks = 0x7fffffff; 2208d69a5f7dSMatt Jacob } 2209d69a5f7dSMatt Jacob ccb->ccb_h.timeout_ch = timeout(isp_watchdog, 2210d69a5f7dSMatt Jacob (caddr_t)ccb, (int)ticks); 2211b85389e1SMatt Jacob } else { 2212b85389e1SMatt Jacob callout_handle_init(&ccb->ccb_h.timeout_ch); 2213cc8df88bSMatt Jacob } 22145d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2215478f8a96SJustin T. Gibbs break; 22160470d791SMatt Jacob case CMD_RQLATER: 2217f44257c2SMatt Jacob /* 2218f44257c2SMatt Jacob * This can only happen for Fibre Channel 2219f44257c2SMatt Jacob */ 2220f44257c2SMatt Jacob KASSERT((IS_FC(isp)), ("CMD_RQLATER for FC only")); 2221fdeb9f2fSMatt Jacob if (FCPARAM(isp)->loop_seen_once == 0 && 2222fdeb9f2fSMatt Jacob isp->isp_osinfo.ktmature) { 2223f44257c2SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2224f44257c2SMatt Jacob XS_SETERR(ccb, CAM_SEL_TIMEOUT); 2225f44257c2SMatt Jacob xpt_done(ccb); 2226f44257c2SMatt Jacob break; 2227f44257c2SMatt Jacob } 22289cd7268eSMatt Jacob #if __FreeBSD_version < 500000 22299cd7268eSMatt Jacob wakeup(&isp->isp_osinfo.kproc); 22309cd7268eSMatt Jacob #else 2231162e9893SMatt Jacob #ifdef ISP_SMPLOCK 22325d571944SMatt Jacob cv_signal(&isp->isp_osinfo.kthread_cv); 2233162e9893SMatt Jacob #else 2234162e9893SMatt Jacob wakeup(&isp->isp_osinfo.kthread_cv); 2235162e9893SMatt Jacob #endif 22369cd7268eSMatt Jacob #endif 2237fdeb9f2fSMatt Jacob isp_freeze_loopdown(isp, "isp_action(RQLATER)"); 2238b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 2239fdeb9f2fSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2240478f8a96SJustin T. Gibbs xpt_done(ccb); 2241478f8a96SJustin T. Gibbs break; 22420470d791SMatt Jacob case CMD_EAGAIN: 2243b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 22445d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2245478f8a96SJustin T. Gibbs xpt_done(ccb); 2246478f8a96SJustin T. Gibbs break; 22470470d791SMatt Jacob case CMD_COMPLETE: 22480470d791SMatt Jacob isp_done((struct ccb_scsiio *) ccb); 22495d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 22500470d791SMatt Jacob break; 22510470d791SMatt Jacob default: 2252bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 2253bfbab170SMatt Jacob "What's this? 0x%x at %d in file %s", 225491f1caa2SMatt Jacob error, __LINE__, __FILE__); 2255b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQ_CMP_ERR); 22560470d791SMatt Jacob xpt_done(ccb); 22575d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2258478f8a96SJustin T. Gibbs } 2259478f8a96SJustin T. Gibbs break; 2260478f8a96SJustin T. Gibbs 2261d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2262478f8a96SJustin T. Gibbs case XPT_EN_LUN: /* Enable LUN as a target */ 226364edff94SMatt Jacob { 226467ff51f1SMatt Jacob int seq, iok, i; 22655d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 226664edff94SMatt Jacob iok = isp->isp_osinfo.intsok; 226764edff94SMatt Jacob isp->isp_osinfo.intsok = 0; 226867ff51f1SMatt Jacob seq = isp_en_lun(isp, ccb); 226967ff51f1SMatt Jacob if (seq < 0) { 227064edff94SMatt Jacob isp->isp_osinfo.intsok = iok; 22715d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2272478f8a96SJustin T. Gibbs xpt_done(ccb); 2273478f8a96SJustin T. Gibbs break; 227464edff94SMatt Jacob } 227567ff51f1SMatt Jacob for (i = 0; isp->isp_osinfo.leact[seq] && i < 30 * 1000; i++) { 22761dae40ebSMatt Jacob uint16_t isr, sema, mbox; 227767ff51f1SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 227867ff51f1SMatt Jacob isp_intr(isp, isr, sema, mbox); 227967ff51f1SMatt Jacob } 228067ff51f1SMatt Jacob DELAY(1000); 228167ff51f1SMatt Jacob } 228267ff51f1SMatt Jacob isp->isp_osinfo.intsok = iok; 228367ff51f1SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 228467ff51f1SMatt Jacob break; 228567ff51f1SMatt Jacob } 2286d81ba9d5SMatt Jacob case XPT_NOTIFY_ACK: /* recycle notify ack */ 2287d81ba9d5SMatt Jacob case XPT_IMMED_NOTIFY: /* Add Immediate Notify Resource */ 2288d81ba9d5SMatt Jacob case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */ 2289d81ba9d5SMatt Jacob { 2290a1bc34c6SMatt Jacob tstate_t *tptr = 2291a1bc34c6SMatt Jacob get_lun_statep(isp, XS_CHANNEL(ccb), ccb->ccb_h.target_lun); 2292d81ba9d5SMatt Jacob if (tptr == NULL) { 2293d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 2294d81ba9d5SMatt Jacob xpt_done(ccb); 2295d81ba9d5SMatt Jacob break; 2296d81ba9d5SMatt Jacob } 2297f48ce188SMatt Jacob ccb->ccb_h.sim_priv.entries[0].field = 0; 2298f48ce188SMatt Jacob ccb->ccb_h.sim_priv.entries[1].ptr = isp; 2299570c7a3fSMatt Jacob ccb->ccb_h.flags = 0; 2300570c7a3fSMatt Jacob 23015d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2302d81ba9d5SMatt Jacob if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 2303570c7a3fSMatt Jacob /* 2304570c7a3fSMatt Jacob * Note that the command itself may not be done- 2305570c7a3fSMatt Jacob * it may not even have had the first CTIO sent. 2306570c7a3fSMatt Jacob */ 2307570c7a3fSMatt Jacob tptr->atio_count++; 2308570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 2309746e9c85SMatt Jacob "Put FREE ATIO, lun %d, count now %d", 2310570c7a3fSMatt Jacob ccb->ccb_h.target_lun, tptr->atio_count); 2311570c7a3fSMatt Jacob SLIST_INSERT_HEAD(&tptr->atios, &ccb->ccb_h, 2312570c7a3fSMatt Jacob sim_links.sle); 2313570c7a3fSMatt Jacob } else if (ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) { 2314746e9c85SMatt Jacob tptr->inot_count++; 2315746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 2316746e9c85SMatt Jacob "Put FREE INOT, lun %d, count now %d", 2317746e9c85SMatt Jacob ccb->ccb_h.target_lun, tptr->inot_count); 2318d81ba9d5SMatt Jacob SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, 2319d81ba9d5SMatt Jacob sim_links.sle); 2320570c7a3fSMatt Jacob } else { 2321746e9c85SMatt Jacob isp_prt(isp, ISP_LOGWARN, "Got Notify ACK");; 2322d81ba9d5SMatt Jacob } 2323d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 2324d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_INPROG; 23255d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2326d81ba9d5SMatt Jacob break; 2327d81ba9d5SMatt Jacob } 2328d81ba9d5SMatt Jacob case XPT_CONT_TARGET_IO: 2329d81ba9d5SMatt Jacob { 23305d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 23319cd7268eSMatt Jacob isp_target_start_ctio(isp, ccb); 23325d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2333d81ba9d5SMatt Jacob break; 2334d81ba9d5SMatt Jacob } 2335d81ba9d5SMatt Jacob #endif 2336478f8a96SJustin T. Gibbs case XPT_RESET_DEV: /* BDR the specified SCSI device */ 2337d81ba9d5SMatt Jacob 2338d81ba9d5SMatt Jacob bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path)); 2339d81ba9d5SMatt Jacob tgt = ccb->ccb_h.target_id; 2340d81ba9d5SMatt Jacob tgt |= (bus << 16); 2341d81ba9d5SMatt Jacob 23425d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2343ea6f23cdSMatt Jacob error = isp_control(isp, ISPCTL_RESET_DEV, &tgt); 23445d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2345478f8a96SJustin T. Gibbs if (error) { 2346478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2347478f8a96SJustin T. Gibbs } else { 2348478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2349478f8a96SJustin T. Gibbs } 2350478f8a96SJustin T. Gibbs xpt_done(ccb); 2351478f8a96SJustin T. Gibbs break; 2352478f8a96SJustin T. Gibbs case XPT_ABORT: /* Abort the specified CCB */ 2353d81ba9d5SMatt Jacob { 2354d81ba9d5SMatt Jacob union ccb *accb = ccb->cab.abort_ccb; 23555d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2356d81ba9d5SMatt Jacob switch (accb->ccb_h.func_code) { 2357d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2358d81ba9d5SMatt Jacob case XPT_ACCEPT_TARGET_IO: 2359d81ba9d5SMatt Jacob case XPT_IMMED_NOTIFY: 2360d81ba9d5SMatt Jacob ccb->ccb_h.status = isp_abort_tgt_ccb(isp, ccb); 2361d81ba9d5SMatt Jacob break; 2362d81ba9d5SMatt Jacob case XPT_CONT_TARGET_IO: 2363b09b0095SMatt Jacob isp_prt(isp, ISP_LOGERR, "cannot abort CTIOs yet"); 2364d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_UA_ABORT; 2365d81ba9d5SMatt Jacob break; 2366d81ba9d5SMatt Jacob #endif 2367d81ba9d5SMatt Jacob case XPT_SCSI_IO: 2368478f8a96SJustin T. Gibbs error = isp_control(isp, ISPCTL_ABORT_CMD, ccb); 2369478f8a96SJustin T. Gibbs if (error) { 2370d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_UA_ABORT; 2371478f8a96SJustin T. Gibbs } else { 2372478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2373478f8a96SJustin T. Gibbs } 2374d81ba9d5SMatt Jacob break; 2375d81ba9d5SMatt Jacob default: 2376d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_INVALID; 2377d81ba9d5SMatt Jacob break; 2378d81ba9d5SMatt Jacob } 23795d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2380478f8a96SJustin T. Gibbs xpt_done(ccb); 2381478f8a96SJustin T. Gibbs break; 2382d81ba9d5SMatt Jacob } 2383ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2384ab163f5fSMatt Jacob #define IS_CURRENT_SETTINGS(c) (c->type == CTS_TYPE_CURRENT_SETTINGS) 2385ab163f5fSMatt Jacob #else 2386ab163f5fSMatt Jacob #define IS_CURRENT_SETTINGS(c) (c->flags & CCB_TRANS_CURRENT_SETTINGS) 2387ab163f5fSMatt Jacob #endif 2388478f8a96SJustin T. Gibbs case XPT_SET_TRAN_SETTINGS: /* Nexus Settings */ 2389478f8a96SJustin T. Gibbs cts = &ccb->cts; 23909ce9bdafSMatt Jacob if (!IS_CURRENT_SETTINGS(cts)) { 23919ce9bdafSMatt Jacob ccb->ccb_h.status = CAM_REQ_INVALID; 23929ce9bdafSMatt Jacob xpt_done(ccb); 23939ce9bdafSMatt Jacob break; 23949ce9bdafSMatt Jacob } 2395478f8a96SJustin T. Gibbs tgt = cts->ccb_h.target_id; 23965d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2397ab6c4b31SMatt Jacob if (IS_SCSI(isp)) { 2398ab163f5fSMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2399478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 24001dae40ebSMatt Jacob uint16_t *dptr; 2401d81ba9d5SMatt Jacob 2402d81ba9d5SMatt Jacob bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 2403478f8a96SJustin T. Gibbs 2404ea6f23cdSMatt Jacob sdp += bus; 2405478f8a96SJustin T. Gibbs /* 24069ce9bdafSMatt Jacob * We always update (internally) from goal_flags 2407478f8a96SJustin T. Gibbs * so any request to change settings just gets 2408478f8a96SJustin T. Gibbs * vectored to that location. 2409478f8a96SJustin T. Gibbs */ 24109ce9bdafSMatt Jacob dptr = &sdp->isp_devparam[tgt].goal_flags; 2411478f8a96SJustin T. Gibbs 2412478f8a96SJustin T. Gibbs /* 2413478f8a96SJustin T. Gibbs * Note that these operations affect the 24149ce9bdafSMatt Jacob * the goal flags (goal_flags)- not 2415478f8a96SJustin T. Gibbs * the current state flags. Then we mark 2416478f8a96SJustin T. Gibbs * things so that the next operation to 2417478f8a96SJustin T. Gibbs * this HBA will cause the update to occur. 2418478f8a96SJustin T. Gibbs */ 2419478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_DISC_VALID) { 2420478f8a96SJustin T. Gibbs if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) { 2421478f8a96SJustin T. Gibbs *dptr |= DPARM_DISC; 2422478f8a96SJustin T. Gibbs } else { 2423478f8a96SJustin T. Gibbs *dptr &= ~DPARM_DISC; 2424478f8a96SJustin T. Gibbs } 2425478f8a96SJustin T. Gibbs } 2426478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_TQ_VALID) { 2427478f8a96SJustin T. Gibbs if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) { 2428478f8a96SJustin T. Gibbs *dptr |= DPARM_TQING; 2429478f8a96SJustin T. Gibbs } else { 2430478f8a96SJustin T. Gibbs *dptr &= ~DPARM_TQING; 2431478f8a96SJustin T. Gibbs } 2432478f8a96SJustin T. Gibbs } 2433478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) { 2434478f8a96SJustin T. Gibbs switch (cts->bus_width) { 2435478f8a96SJustin T. Gibbs case MSG_EXT_WDTR_BUS_16_BIT: 2436478f8a96SJustin T. Gibbs *dptr |= DPARM_WIDE; 2437478f8a96SJustin T. Gibbs break; 2438478f8a96SJustin T. Gibbs default: 2439478f8a96SJustin T. Gibbs *dptr &= ~DPARM_WIDE; 2440478f8a96SJustin T. Gibbs } 2441478f8a96SJustin T. Gibbs } 2442478f8a96SJustin T. Gibbs /* 2443478f8a96SJustin T. Gibbs * Any SYNC RATE of nonzero and SYNC_OFFSET 2444478f8a96SJustin T. Gibbs * of nonzero will cause us to go to the 2445478f8a96SJustin T. Gibbs * selected (from NVRAM) maximum value for 2446478f8a96SJustin T. Gibbs * this device. At a later point, we'll 2447478f8a96SJustin T. Gibbs * allow finer control. 2448478f8a96SJustin T. Gibbs */ 2449478f8a96SJustin T. Gibbs if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) && 2450478f8a96SJustin T. Gibbs (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) && 2451478f8a96SJustin T. Gibbs (cts->sync_offset > 0)) { 2452478f8a96SJustin T. Gibbs *dptr |= DPARM_SYNC; 2453478f8a96SJustin T. Gibbs } else { 2454478f8a96SJustin T. Gibbs *dptr &= ~DPARM_SYNC; 2455478f8a96SJustin T. Gibbs } 2456ab6c4b31SMatt Jacob *dptr |= DPARM_SAFE_DFLT; 2457ab163f5fSMatt Jacob #else 2458ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi = 2459ab163f5fSMatt Jacob &cts->proto_specific.scsi; 2460ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi = 2461ab163f5fSMatt Jacob &cts->xport_specific.spi; 2462ab163f5fSMatt Jacob sdparam *sdp = isp->isp_param; 24631dae40ebSMatt Jacob uint16_t *dptr; 2464ab163f5fSMatt Jacob 2465ab163f5fSMatt Jacob bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 2466ab163f5fSMatt Jacob sdp += bus; 2467ab163f5fSMatt Jacob /* 24689ce9bdafSMatt Jacob * We always update (internally) from goal_flags 2469ab163f5fSMatt Jacob * so any request to change settings just gets 2470ab163f5fSMatt Jacob * vectored to that location. 2471ab163f5fSMatt Jacob */ 24729ce9bdafSMatt Jacob dptr = &sdp->isp_devparam[tgt].goal_flags; 2473ab163f5fSMatt Jacob 2474ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_DISC) != 0) { 2475ab163f5fSMatt Jacob if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) 2476ab163f5fSMatt Jacob *dptr |= DPARM_DISC; 2477ab163f5fSMatt Jacob else 2478ab163f5fSMatt Jacob *dptr &= ~DPARM_DISC; 2479ab163f5fSMatt Jacob } 2480ab163f5fSMatt Jacob 2481ab163f5fSMatt Jacob if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 2482ab163f5fSMatt Jacob if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) 2483ab163f5fSMatt Jacob *dptr |= DPARM_TQING; 2484ab163f5fSMatt Jacob else 2485ab163f5fSMatt Jacob *dptr &= ~DPARM_TQING; 2486ab163f5fSMatt Jacob } 2487ab163f5fSMatt Jacob 2488ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 2489ab163f5fSMatt Jacob if (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT) 2490ab163f5fSMatt Jacob *dptr |= DPARM_WIDE; 2491ab163f5fSMatt Jacob else 2492ab163f5fSMatt Jacob *dptr &= ~DPARM_WIDE; 2493ab163f5fSMatt Jacob } 2494ab163f5fSMatt Jacob 2495ab163f5fSMatt Jacob /* 2496ab163f5fSMatt Jacob * XXX: FIX ME 2497ab163f5fSMatt Jacob */ 2498ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) && 24999ce9bdafSMatt Jacob (spi->valid & CTS_SPI_VALID_SYNC_RATE) && 25009ce9bdafSMatt Jacob (spi->sync_period && spi->sync_offset)) { 2501ab163f5fSMatt Jacob *dptr |= DPARM_SYNC; 25029ce9bdafSMatt Jacob /* 25039ce9bdafSMatt Jacob * XXX: CHECK FOR LEGALITY 25049ce9bdafSMatt Jacob */ 25059ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_period = 25069ce9bdafSMatt Jacob spi->sync_period; 25079ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_offset = 25089ce9bdafSMatt Jacob spi->sync_offset; 2509ab163f5fSMatt Jacob } else { 2510ab163f5fSMatt Jacob *dptr &= ~DPARM_SYNC; 2511ab163f5fSMatt Jacob } 2512ab163f5fSMatt Jacob #endif 2513bfbab170SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 25149ce9bdafSMatt Jacob "SET bus %d targ %d to flags %x off %x per %x", 25159ce9bdafSMatt Jacob bus, tgt, sdp->isp_devparam[tgt].goal_flags, 25169ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_offset, 25179ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_period); 2518478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_update = 1; 2519ea6f23cdSMatt Jacob isp->isp_update |= (1 << bus); 2520478f8a96SJustin T. Gibbs } 25215d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2522478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2523478f8a96SJustin T. Gibbs xpt_done(ccb); 2524478f8a96SJustin T. Gibbs break; 2525478f8a96SJustin T. Gibbs case XPT_GET_TRAN_SETTINGS: 2526478f8a96SJustin T. Gibbs cts = &ccb->cts; 2527478f8a96SJustin T. Gibbs tgt = cts->ccb_h.target_id; 2528ab163f5fSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2529ab6c4b31SMatt Jacob if (IS_FC(isp)) { 2530ab163f5fSMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2531478f8a96SJustin T. Gibbs /* 2532478f8a96SJustin T. Gibbs * a lot of normal SCSI things don't make sense. 2533478f8a96SJustin T. Gibbs */ 2534478f8a96SJustin T. Gibbs cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB; 2535478f8a96SJustin T. Gibbs cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2536478f8a96SJustin T. Gibbs /* 2537478f8a96SJustin T. Gibbs * How do you measure the width of a high 2538478f8a96SJustin T. Gibbs * speed serial bus? Well, in bytes. 2539478f8a96SJustin T. Gibbs * 2540478f8a96SJustin T. Gibbs * Offset and period make no sense, though, so we set 2541478f8a96SJustin T. Gibbs * (above) a 'base' transfer speed to be gigabit. 2542478f8a96SJustin T. Gibbs */ 2543478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2544ab163f5fSMatt Jacob #else 2545ab163f5fSMatt Jacob fcparam *fcp = isp->isp_param; 2546ab163f5fSMatt Jacob struct ccb_trans_settings_fc *fc = 2547ab163f5fSMatt Jacob &cts->xport_specific.fc; 2548478f8a96SJustin T. Gibbs 2549ab163f5fSMatt Jacob cts->protocol = PROTO_SCSI; 2550ab163f5fSMatt Jacob cts->protocol_version = SCSI_REV_2; 2551ab163f5fSMatt Jacob cts->transport = XPORT_FC; 2552ab163f5fSMatt Jacob cts->transport_version = 0; 2553ab163f5fSMatt Jacob 2554ab163f5fSMatt Jacob fc->valid = CTS_FC_VALID_SPEED; 255553036e92SMatt Jacob if (fcp->isp_gbspeed == 2) 255653036e92SMatt Jacob fc->bitrate = 200000; 255753036e92SMatt Jacob else 2558ab163f5fSMatt Jacob fc->bitrate = 100000; 2559ab163f5fSMatt Jacob if (tgt > 0 && tgt < MAX_FC_TARG) { 2560ab163f5fSMatt Jacob struct lportdb *lp = &fcp->portdb[tgt]; 2561ab163f5fSMatt Jacob fc->wwnn = lp->node_wwn; 2562ab163f5fSMatt Jacob fc->wwpn = lp->port_wwn; 2563ab163f5fSMatt Jacob fc->port = lp->portid; 2564ab163f5fSMatt Jacob fc->valid |= CTS_FC_VALID_WWNN | 2565ab163f5fSMatt Jacob CTS_FC_VALID_WWPN | CTS_FC_VALID_PORT; 2566ab163f5fSMatt Jacob } 2567ab163f5fSMatt Jacob #endif 2568ab163f5fSMatt Jacob } else { 2569ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2570ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi = 2571ab163f5fSMatt Jacob &cts->proto_specific.scsi; 2572ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi = 2573ab163f5fSMatt Jacob &cts->xport_specific.spi; 2574ab163f5fSMatt Jacob #endif 2575ab163f5fSMatt Jacob sdparam *sdp = isp->isp_param; 2576ab163f5fSMatt Jacob int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 25771dae40ebSMatt Jacob uint16_t dval, pval, oval; 2578ab163f5fSMatt Jacob 2579ea6f23cdSMatt Jacob sdp += bus; 2580ab163f5fSMatt Jacob 2581ab163f5fSMatt Jacob if (IS_CURRENT_SETTINGS(cts)) { 258283ae4407SMatt Jacob sdp->isp_devparam[tgt].dev_refresh = 1; 258383ae4407SMatt Jacob isp->isp_update |= (1 << bus); 258483ae4407SMatt Jacob (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, 258583ae4407SMatt Jacob NULL); 25869ce9bdafSMatt Jacob dval = sdp->isp_devparam[tgt].actv_flags; 25879ce9bdafSMatt Jacob oval = sdp->isp_devparam[tgt].actv_offset; 25889ce9bdafSMatt Jacob pval = sdp->isp_devparam[tgt].actv_period; 25894394c92fSMatt Jacob } else { 25909ce9bdafSMatt Jacob dval = sdp->isp_devparam[tgt].nvrm_flags; 25919ce9bdafSMatt Jacob oval = sdp->isp_devparam[tgt].nvrm_offset; 25929ce9bdafSMatt Jacob pval = sdp->isp_devparam[tgt].nvrm_period; 25934394c92fSMatt Jacob } 2594478f8a96SJustin T. Gibbs 2595ab163f5fSMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2596478f8a96SJustin T. Gibbs cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); 2597478f8a96SJustin T. Gibbs 2598478f8a96SJustin T. Gibbs if (dval & DPARM_DISC) { 2599478f8a96SJustin T. Gibbs cts->flags |= CCB_TRANS_DISC_ENB; 2600478f8a96SJustin T. Gibbs } 2601478f8a96SJustin T. Gibbs if (dval & DPARM_TQING) { 2602478f8a96SJustin T. Gibbs cts->flags |= CCB_TRANS_TAG_ENB; 2603478f8a96SJustin T. Gibbs } 2604478f8a96SJustin T. Gibbs if (dval & DPARM_WIDE) { 2605478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2606478f8a96SJustin T. Gibbs } else { 2607478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2608478f8a96SJustin T. Gibbs } 2609478f8a96SJustin T. Gibbs cts->valid = CCB_TRANS_BUS_WIDTH_VALID | 2610478f8a96SJustin T. Gibbs CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2611478f8a96SJustin T. Gibbs 26124394c92fSMatt Jacob if ((dval & DPARM_SYNC) && oval != 0) { 26134394c92fSMatt Jacob cts->sync_period = pval; 26144394c92fSMatt Jacob cts->sync_offset = oval; 2615478f8a96SJustin T. Gibbs cts->valid |= 2616478f8a96SJustin T. Gibbs CCB_TRANS_SYNC_RATE_VALID | 2617478f8a96SJustin T. Gibbs CCB_TRANS_SYNC_OFFSET_VALID; 2618478f8a96SJustin T. Gibbs } 2619ab163f5fSMatt Jacob #else 2620ab163f5fSMatt Jacob cts->protocol = PROTO_SCSI; 2621ab163f5fSMatt Jacob cts->protocol_version = SCSI_REV_2; 2622ab163f5fSMatt Jacob cts->transport = XPORT_SPI; 2623ab163f5fSMatt Jacob cts->transport_version = 2; 2624ab163f5fSMatt Jacob 2625ab163f5fSMatt Jacob scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 2626ab163f5fSMatt Jacob spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 2627ab163f5fSMatt Jacob if (dval & DPARM_DISC) { 2628ab163f5fSMatt Jacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 2629ab163f5fSMatt Jacob } 2630ab163f5fSMatt Jacob if (dval & DPARM_TQING) { 2631ab163f5fSMatt Jacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 2632ab163f5fSMatt Jacob } 26339ce9bdafSMatt Jacob if ((dval & DPARM_SYNC) && oval && pval) { 2634ab163f5fSMatt Jacob spi->sync_offset = oval; 2635ab163f5fSMatt Jacob spi->sync_period = pval; 2636ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 2637ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 2638ab163f5fSMatt Jacob } 2639ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_BUS_WIDTH; 2640ab163f5fSMatt Jacob if (dval & DPARM_WIDE) { 2641ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2642ab163f5fSMatt Jacob } else { 2643ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2644ab163f5fSMatt Jacob } 2645ab163f5fSMatt Jacob if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { 2646ab163f5fSMatt Jacob scsi->valid = CTS_SCSI_VALID_TQ; 2647ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_DISC; 2648ab163f5fSMatt Jacob } else { 2649ab163f5fSMatt Jacob scsi->valid = 0; 2650ab163f5fSMatt Jacob } 2651ab163f5fSMatt Jacob #endif 2652bfbab170SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 26539ce9bdafSMatt Jacob "GET %s bus %d targ %d to flags %x off %x per %x", 26549ce9bdafSMatt Jacob IS_CURRENT_SETTINGS(cts)? "ACTIVE" : "NVRAM", 26559ce9bdafSMatt Jacob bus, tgt, dval, oval, pval); 2656478f8a96SJustin T. Gibbs } 2657ab163f5fSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2658478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2659478f8a96SJustin T. Gibbs xpt_done(ccb); 2660478f8a96SJustin T. Gibbs break; 2661478f8a96SJustin T. Gibbs 2662478f8a96SJustin T. Gibbs case XPT_CALC_GEOMETRY: 26639cd7268eSMatt Jacob #if __FreeBSD_version < 500000 2664478f8a96SJustin T. Gibbs { 2665478f8a96SJustin T. Gibbs struct ccb_calc_geometry *ccg; 26669cd7268eSMatt Jacob u_int32_t secs_per_cylinder; 26679cd7268eSMatt Jacob u_int32_t size_mb; 2668478f8a96SJustin T. Gibbs 2669478f8a96SJustin T. Gibbs ccg = &ccb->ccg; 2670478f8a96SJustin T. Gibbs if (ccg->block_size == 0) { 2671478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2672478f8a96SJustin T. Gibbs xpt_done(ccb); 2673478f8a96SJustin T. Gibbs break; 2674478f8a96SJustin T. Gibbs } 26759cd7268eSMatt Jacob size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size); 26769cd7268eSMatt Jacob if (size_mb > 1024) { 26779cd7268eSMatt Jacob ccg->heads = 255; 26789cd7268eSMatt Jacob ccg->secs_per_track = 63; 26799cd7268eSMatt Jacob } else { 26809cd7268eSMatt Jacob ccg->heads = 64; 26819cd7268eSMatt Jacob ccg->secs_per_track = 32; 26829cd7268eSMatt Jacob } 26839cd7268eSMatt Jacob secs_per_cylinder = ccg->heads * ccg->secs_per_track; 26849cd7268eSMatt Jacob ccg->cylinders = ccg->volume_size / secs_per_cylinder; 26859cd7268eSMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 2686478f8a96SJustin T. Gibbs xpt_done(ccb); 2687478f8a96SJustin T. Gibbs break; 2688478f8a96SJustin T. Gibbs } 26899cd7268eSMatt Jacob #else 26909cd7268eSMatt Jacob { 26919cd7268eSMatt Jacob cam_calc_geometry(&ccb->ccg, /*extended*/1); 26929cd7268eSMatt Jacob xpt_done(ccb); 26939cd7268eSMatt Jacob break; 26949cd7268eSMatt Jacob } 26959cd7268eSMatt Jacob #endif 2696478f8a96SJustin T. Gibbs case XPT_RESET_BUS: /* Reset the specified bus */ 2697ab6c4b31SMatt Jacob bus = cam_sim_bus(sim); 26985d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2699ab6c4b31SMatt Jacob error = isp_control(isp, ISPCTL_RESET_BUS, &bus); 27005d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2701478f8a96SJustin T. Gibbs if (error) 2702478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 27032b052931SMatt Jacob else { 2704ea6f23cdSMatt Jacob if (cam_sim_bus(sim) && isp->isp_path2 != NULL) 2705ea6f23cdSMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); 2706ea6f23cdSMatt Jacob else if (isp->isp_path != NULL) 27072b052931SMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path, NULL); 2708478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 27092b052931SMatt Jacob } 2710478f8a96SJustin T. Gibbs xpt_done(ccb); 2711478f8a96SJustin T. Gibbs break; 2712478f8a96SJustin T. Gibbs 2713478f8a96SJustin T. Gibbs case XPT_TERM_IO: /* Terminate the I/O process */ 2714478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2715478f8a96SJustin T. Gibbs xpt_done(ccb); 2716478f8a96SJustin T. Gibbs break; 2717478f8a96SJustin T. Gibbs 2718478f8a96SJustin T. Gibbs case XPT_PATH_INQ: /* Path routing inquiry */ 2719478f8a96SJustin T. Gibbs { 2720478f8a96SJustin T. Gibbs struct ccb_pathinq *cpi = &ccb->cpi; 2721478f8a96SJustin T. Gibbs 2722478f8a96SJustin T. Gibbs cpi->version_num = 1; 2723d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2724a1bc34c6SMatt Jacob cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO; 2725d81ba9d5SMatt Jacob #else 2726478f8a96SJustin T. Gibbs cpi->target_sprt = 0; 2727d81ba9d5SMatt Jacob #endif 2728478f8a96SJustin T. Gibbs cpi->hba_eng_cnt = 0; 27290470d791SMatt Jacob cpi->max_target = ISP_MAX_TARGETS(isp) - 1; 27300470d791SMatt Jacob cpi->max_lun = ISP_MAX_LUNS(isp) - 1; 27310470d791SMatt Jacob cpi->bus_id = cam_sim_bus(sim); 27324394c92fSMatt Jacob if (IS_FC(isp)) { 27334394c92fSMatt Jacob cpi->hba_misc = PIM_NOBUSRESET; 27340470d791SMatt Jacob /* 27350470d791SMatt Jacob * Because our loop ID can shift from time to time, 27360470d791SMatt Jacob * make our initiator ID out of range of our bus. 27370470d791SMatt Jacob */ 27380470d791SMatt Jacob cpi->initiator_id = cpi->max_target + 1; 27390470d791SMatt Jacob 27409deea857SKenneth D. Merry /* 27419deea857SKenneth D. Merry * Set base transfer capabilities for Fibre Channel. 27429deea857SKenneth D. Merry * Technically not correct because we don't know 27439deea857SKenneth D. Merry * what media we're running on top of- but we'll 27449deea857SKenneth D. Merry * look good if we always say 100MB/s. 27459deea857SKenneth D. Merry */ 274653036e92SMatt Jacob if (FCPARAM(isp)->isp_gbspeed == 2) 274753036e92SMatt Jacob cpi->base_transfer_speed = 200000; 274853036e92SMatt Jacob else 27499deea857SKenneth D. Merry cpi->base_transfer_speed = 100000; 27500470d791SMatt Jacob cpi->hba_inquiry = PI_TAG_ABLE; 2751ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2752ab163f5fSMatt Jacob cpi->transport = XPORT_FC; 2753ab163f5fSMatt Jacob cpi->transport_version = 0; /* WHAT'S THIS FOR? */ 2754ab163f5fSMatt Jacob #endif 2755478f8a96SJustin T. Gibbs } else { 2756ea6f23cdSMatt Jacob sdparam *sdp = isp->isp_param; 2757ea6f23cdSMatt Jacob sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path)); 27580470d791SMatt Jacob cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; 27594394c92fSMatt Jacob cpi->hba_misc = 0; 2760ea6f23cdSMatt Jacob cpi->initiator_id = sdp->isp_initiator_id; 27619deea857SKenneth D. Merry cpi->base_transfer_speed = 3300; 2762ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2763ab163f5fSMatt Jacob cpi->transport = XPORT_SPI; 2764ab163f5fSMatt Jacob cpi->transport_version = 2; /* WHAT'S THIS FOR? */ 2765ab163f5fSMatt Jacob #endif 2766478f8a96SJustin T. Gibbs } 2767ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2768ab163f5fSMatt Jacob cpi->protocol = PROTO_SCSI; 2769ab163f5fSMatt Jacob cpi->protocol_version = SCSI_REV_2; 2770ab163f5fSMatt Jacob #endif 2771478f8a96SJustin T. Gibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 2772478f8a96SJustin T. Gibbs strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN); 2773478f8a96SJustin T. Gibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 2774478f8a96SJustin T. Gibbs cpi->unit_number = cam_sim_unit(sim); 2775478f8a96SJustin T. Gibbs cpi->ccb_h.status = CAM_REQ_CMP; 2776478f8a96SJustin T. Gibbs xpt_done(ccb); 2777478f8a96SJustin T. Gibbs break; 2778478f8a96SJustin T. Gibbs } 2779478f8a96SJustin T. Gibbs default: 2780478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2781478f8a96SJustin T. Gibbs xpt_done(ccb); 2782478f8a96SJustin T. Gibbs break; 2783478f8a96SJustin T. Gibbs } 2784478f8a96SJustin T. Gibbs } 2785d3a9eb2eSMatt Jacob 2786d3a9eb2eSMatt Jacob #define ISPDDB (CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB) 2787d3a9eb2eSMatt Jacob void 2788c3055363SMatt Jacob isp_done(struct ccb_scsiio *sccb) 2789d3a9eb2eSMatt Jacob { 27909cd7268eSMatt Jacob ispsoftc_t *isp = XS_ISP(sccb); 2791d3a9eb2eSMatt Jacob 2792d3a9eb2eSMatt Jacob if (XS_NOERR(sccb)) 2793d3a9eb2eSMatt Jacob XS_SETERR(sccb, CAM_REQ_CMP); 2794b85389e1SMatt Jacob 2795d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP && 2796d3a9eb2eSMatt Jacob (sccb->scsi_status != SCSI_STATUS_OK)) { 2797d3a9eb2eSMatt Jacob sccb->ccb_h.status &= ~CAM_STATUS_MASK; 279892a1e549SMatt Jacob if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) && 279992a1e549SMatt Jacob (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) { 280092a1e549SMatt Jacob sccb->ccb_h.status |= CAM_AUTOSENSE_FAIL; 280192a1e549SMatt Jacob } else { 2802d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 2803d3a9eb2eSMatt Jacob } 280492a1e549SMatt Jacob } 2805b85389e1SMatt Jacob 28060470d791SMatt Jacob sccb->ccb_h.status &= ~CAM_SIM_QUEUED; 2807d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2808d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 2809d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_DEV_QFRZN; 28100470d791SMatt Jacob xpt_freeze_devq(sccb->ccb_h.path, 1); 2811fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 2812fdeb9f2fSMatt Jacob "freeze devq %d.%d cam sts %x scsi sts %x", 2813fdeb9f2fSMatt Jacob sccb->ccb_h.target_id, sccb->ccb_h.target_lun, 2814fdeb9f2fSMatt Jacob sccb->ccb_h.status, sccb->scsi_status); 2815d3a9eb2eSMatt Jacob } 2816d3a9eb2eSMatt Jacob } 2817b85389e1SMatt Jacob 2818b85389e1SMatt Jacob if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) && 2819d3a9eb2eSMatt Jacob (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2820d3a9eb2eSMatt Jacob xpt_print_path(sccb->ccb_h.path); 28213c75bb14SMatt Jacob isp_prt(isp, ISP_LOGINFO, 28223c75bb14SMatt Jacob "cam completion status 0x%x", sccb->ccb_h.status); 2823d3a9eb2eSMatt Jacob } 2824b85389e1SMatt Jacob 2825b85389e1SMatt Jacob XS_CMD_S_DONE(sccb); 2826b85389e1SMatt Jacob if (XS_CMD_WDOG_P(sccb) == 0) { 2827b85389e1SMatt Jacob untimeout(isp_watchdog, (caddr_t)sccb, sccb->ccb_h.timeout_ch); 2828b85389e1SMatt Jacob if (XS_CMD_GRACE_P(sccb)) { 2829b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2830b09b0095SMatt Jacob "finished command on borrowed time"); 2831b85389e1SMatt Jacob } 2832b85389e1SMatt Jacob XS_CMD_S_CLEAR(sccb); 28335d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2834d3a9eb2eSMatt Jacob xpt_done((union ccb *) sccb); 28355d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2836d3a9eb2eSMatt Jacob } 2837b85389e1SMatt Jacob } 2838d3a9eb2eSMatt Jacob 2839cbf57b47SMatt Jacob int 28409cd7268eSMatt Jacob isp_async(ispsoftc_t *isp, ispasync_t cmd, void *arg) 2841cbf57b47SMatt Jacob { 2842ea6f23cdSMatt Jacob int bus, rv = 0; 2843cbf57b47SMatt Jacob switch (cmd) { 2844cbf57b47SMatt Jacob case ISPASYNC_NEW_TGT_PARAMS: 28450470d791SMatt Jacob { 2846ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2847ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi; 2848ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi; 2849ab163f5fSMatt Jacob #endif 2850cbf57b47SMatt Jacob int flags, tgt; 2851cbf57b47SMatt Jacob sdparam *sdp = isp->isp_param; 2852ab163f5fSMatt Jacob struct ccb_trans_settings cts; 2853cbf57b47SMatt Jacob struct cam_path *tmppath; 2854cbf57b47SMatt Jacob 2855ab163f5fSMatt Jacob bzero(&cts, sizeof (struct ccb_trans_settings)); 2856ab163f5fSMatt Jacob 2857cbf57b47SMatt Jacob tgt = *((int *)arg); 2858ea6f23cdSMatt Jacob bus = (tgt >> 16) & 0xffff; 2859ea6f23cdSMatt Jacob tgt &= 0xffff; 2860ea6f23cdSMatt Jacob sdp += bus; 286145c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2862cbf57b47SMatt Jacob if (xpt_create_path(&tmppath, NULL, 2863ea6f23cdSMatt Jacob cam_sim_path(bus? isp->isp_sim2 : isp->isp_sim), 2864ea6f23cdSMatt Jacob tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 286545c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2866bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 2867bfbab170SMatt Jacob "isp_async cannot make temp path for %d.%d", 2868bfbab170SMatt Jacob tgt, bus); 2869cbf57b47SMatt Jacob rv = -1; 2870cbf57b47SMatt Jacob break; 2871cbf57b47SMatt Jacob } 287245c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 28739ce9bdafSMatt Jacob flags = sdp->isp_devparam[tgt].actv_flags; 2874ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2875ab163f5fSMatt Jacob cts.type = CTS_TYPE_CURRENT_SETTINGS; 2876ab163f5fSMatt Jacob cts.protocol = PROTO_SCSI; 2877ab163f5fSMatt Jacob cts.transport = XPORT_SPI; 2878ab163f5fSMatt Jacob 2879ab163f5fSMatt Jacob scsi = &cts.proto_specific.scsi; 2880ab163f5fSMatt Jacob spi = &cts.xport_specific.spi; 2881ab163f5fSMatt Jacob 2882ab163f5fSMatt Jacob if (flags & DPARM_TQING) { 2883ab163f5fSMatt Jacob scsi->valid |= CTS_SCSI_VALID_TQ; 2884ab163f5fSMatt Jacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 2885ab163f5fSMatt Jacob spi->flags |= CTS_SPI_FLAGS_TAG_ENB; 2886ab163f5fSMatt Jacob } 2887ab163f5fSMatt Jacob 2888cbf57b47SMatt Jacob if (flags & DPARM_DISC) { 2889ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_DISC; 2890ab163f5fSMatt Jacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 2891ab163f5fSMatt Jacob } 2892ab163f5fSMatt Jacob spi->flags |= CTS_SPI_VALID_BUS_WIDTH; 2893ab163f5fSMatt Jacob if (flags & DPARM_WIDE) { 2894ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2895ab163f5fSMatt Jacob } else { 2896ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2897ab163f5fSMatt Jacob } 2898ab163f5fSMatt Jacob if (flags & DPARM_SYNC) { 2899ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 2900ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 29019ce9bdafSMatt Jacob spi->sync_period = sdp->isp_devparam[tgt].actv_period; 29029ce9bdafSMatt Jacob spi->sync_offset = sdp->isp_devparam[tgt].actv_offset; 2903ab163f5fSMatt Jacob } 2904ab163f5fSMatt Jacob #else 2905ab163f5fSMatt Jacob cts.flags = CCB_TRANS_CURRENT_SETTINGS; 2906ab163f5fSMatt Jacob cts.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2907ab163f5fSMatt Jacob if (flags & DPARM_DISC) { 2908ab163f5fSMatt Jacob cts.flags |= CCB_TRANS_DISC_ENB; 2909cbf57b47SMatt Jacob } 2910cbf57b47SMatt Jacob if (flags & DPARM_TQING) { 2911ab163f5fSMatt Jacob cts.flags |= CCB_TRANS_TAG_ENB; 2912cbf57b47SMatt Jacob } 2913ab163f5fSMatt Jacob cts.valid |= CCB_TRANS_BUS_WIDTH_VALID; 2914ab163f5fSMatt Jacob cts.bus_width = (flags & DPARM_WIDE)? 2915cbf57b47SMatt Jacob MSG_EXT_WDTR_BUS_8_BIT : MSG_EXT_WDTR_BUS_16_BIT; 29169ce9bdafSMatt Jacob cts.sync_period = sdp->isp_devparam[tgt].actv_period; 29179ce9bdafSMatt Jacob cts.sync_offset = sdp->isp_devparam[tgt].actv_offset; 2918cbf57b47SMatt Jacob if (flags & DPARM_SYNC) { 2919ab163f5fSMatt Jacob cts.valid |= 29204394c92fSMatt Jacob CCB_TRANS_SYNC_RATE_VALID | 2921cbf57b47SMatt Jacob CCB_TRANS_SYNC_OFFSET_VALID; 2922cbf57b47SMatt Jacob } 2923ab163f5fSMatt Jacob #endif 2924b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2925b09b0095SMatt Jacob "NEW_TGT_PARAMS bus %d tgt %d period %x offset %x flags %x", 29269ce9bdafSMatt Jacob bus, tgt, sdp->isp_devparam[tgt].actv_period, 29279ce9bdafSMatt Jacob sdp->isp_devparam[tgt].actv_offset, flags); 2928ab163f5fSMatt Jacob xpt_setup_ccb(&cts.ccb_h, tmppath, 1); 29295d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2930ab163f5fSMatt Jacob xpt_async(AC_TRANSFER_NEG, tmppath, &cts); 2931cbf57b47SMatt Jacob xpt_free_path(tmppath); 2932f44257c2SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2933cbf57b47SMatt Jacob break; 29340470d791SMatt Jacob } 293557c801f5SMatt Jacob case ISPASYNC_BUS_RESET: 2936ea6f23cdSMatt Jacob bus = *((int *)arg); 2937b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected", 2938b09b0095SMatt Jacob bus); 2939ea6f23cdSMatt Jacob if (bus > 0 && isp->isp_path2) { 29405d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2941ea6f23cdSMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); 29425d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2943ea6f23cdSMatt Jacob } else if (isp->isp_path) { 29445d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 294557c801f5SMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path, NULL); 29465d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 294757c801f5SMatt Jacob } 294857c801f5SMatt Jacob break; 29495d571944SMatt Jacob case ISPASYNC_LIP: 29505d571944SMatt Jacob if (isp->isp_path) { 2951fdeb9f2fSMatt Jacob isp_freeze_loopdown(isp, "ISPASYNC_LIP"); 29525d571944SMatt Jacob } 29535d571944SMatt Jacob isp_prt(isp, ISP_LOGINFO, "LIP Received"); 29545d571944SMatt Jacob break; 29555d571944SMatt Jacob case ISPASYNC_LOOP_RESET: 29565d571944SMatt Jacob if (isp->isp_path) { 2957fdeb9f2fSMatt Jacob isp_freeze_loopdown(isp, "ISPASYNC_LOOP_RESET"); 29585d571944SMatt Jacob } 29595d571944SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop Reset Received"); 29605d571944SMatt Jacob break; 296157c801f5SMatt Jacob case ISPASYNC_LOOP_DOWN: 296257c801f5SMatt Jacob if (isp->isp_path) { 2963fdeb9f2fSMatt Jacob isp_freeze_loopdown(isp, "ISPASYNC_LOOP_DOWN"); 296457c801f5SMatt Jacob } 2965b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop DOWN"); 296657c801f5SMatt Jacob break; 296757c801f5SMatt Jacob case ISPASYNC_LOOP_UP: 29685d571944SMatt Jacob /* 29695d571944SMatt Jacob * Now we just note that Loop has come up. We don't 29705d571944SMatt Jacob * actually do anything because we're waiting for a 29715d571944SMatt Jacob * Change Notify before activating the FC cleanup 29725d571944SMatt Jacob * thread to look at the state of the loop again. 29735d571944SMatt Jacob */ 2974b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop UP"); 297557c801f5SMatt Jacob break; 2976d6e5500fSMatt Jacob case ISPASYNC_PROMENADE: 29770470d791SMatt Jacob { 2978b09b0095SMatt Jacob const char *fmt = "Target %d (Loop 0x%x) Port ID 0x%x " 2979d6e5500fSMatt Jacob "(role %s) %s\n Port WWN 0x%08x%08x\n Node WWN 0x%08x%08x"; 2980d6e5500fSMatt Jacob static const char *roles[4] = { 29810470d791SMatt Jacob "(none)", "Target", "Initiator", "Target/Initiator" 298257c801f5SMatt Jacob }; 298302ab3379SMatt Jacob fcparam *fcp = isp->isp_param; 298402ab3379SMatt Jacob int tgt = *((int *) arg); 29859cd7268eSMatt Jacob #if __FreeBSD_version >= 500000 2986f44257c2SMatt Jacob int is_tgt_mask = (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT); 29879cd7268eSMatt Jacob struct cam_path *tmppath; 29889cd7268eSMatt Jacob #endif 298902ab3379SMatt Jacob struct lportdb *lp = &fcp->portdb[tgt]; 299002ab3379SMatt Jacob 2991b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, fmt, tgt, lp->loopid, lp->portid, 2992d6e5500fSMatt Jacob roles[lp->roles & 0x3], 2993d6e5500fSMatt Jacob (lp->valid)? "Arrived" : "Departed", 29941dae40ebSMatt Jacob (uint32_t) (lp->port_wwn >> 32), 29951dae40ebSMatt Jacob (uint32_t) (lp->port_wwn & 0xffffffffLL), 29961dae40ebSMatt Jacob (uint32_t) (lp->node_wwn >> 32), 29971dae40ebSMatt Jacob (uint32_t) (lp->node_wwn & 0xffffffffLL)); 2998ab163f5fSMatt Jacob 299945c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 30009cd7268eSMatt Jacob #if __FreeBSD_version >= 500000 3001ab163f5fSMatt Jacob if (xpt_create_path(&tmppath, NULL, cam_sim_path(isp->isp_sim), 3002ab163f5fSMatt Jacob (target_id_t)tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 300345c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 3004ab163f5fSMatt Jacob break; 3005ab163f5fSMatt Jacob } 3006f44257c2SMatt Jacob /* 3007f44257c2SMatt Jacob * Policy: only announce targets. 3008f44257c2SMatt Jacob */ 3009f44257c2SMatt Jacob if (lp->roles & is_tgt_mask) { 3010f44257c2SMatt Jacob if (lp->valid) { 3011ab163f5fSMatt Jacob xpt_async(AC_FOUND_DEVICE, tmppath, NULL); 3012ab163f5fSMatt Jacob } else { 3013ab163f5fSMatt Jacob xpt_async(AC_LOST_DEVICE, tmppath, NULL); 3014ab163f5fSMatt Jacob } 3015f44257c2SMatt Jacob } 3016ab163f5fSMatt Jacob xpt_free_path(tmppath); 30179cd7268eSMatt Jacob #endif 3018f44257c2SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 30194394c92fSMatt Jacob break; 30204394c92fSMatt Jacob } 302157c801f5SMatt Jacob case ISPASYNC_CHANGE_NOTIFY: 3022f44257c2SMatt Jacob if (arg == ISPASYNC_CHANGE_PDB) { 30234b9d588eSMatt Jacob isp_prt(isp, ISP_LOGINFO, 3024f44257c2SMatt Jacob "Port Database Changed"); 3025f44257c2SMatt Jacob } else if (arg == ISPASYNC_CHANGE_SNS) { 30264b9d588eSMatt Jacob isp_prt(isp, ISP_LOGINFO, 30274b9d588eSMatt Jacob "Name Server Database Changed"); 30284b9d588eSMatt Jacob } 30299cd7268eSMatt Jacob #if __FreeBSD_version < 500000 30309cd7268eSMatt Jacob wakeup(&isp->isp_osinfo.kproc); 30319cd7268eSMatt Jacob #else 3032162e9893SMatt Jacob #ifdef ISP_SMPLOCK 30335d571944SMatt Jacob cv_signal(&isp->isp_osinfo.kthread_cv); 3034162e9893SMatt Jacob #else 3035162e9893SMatt Jacob wakeup(&isp->isp_osinfo.kthread_cv); 3036162e9893SMatt Jacob #endif 30379cd7268eSMatt Jacob #endif 303857c801f5SMatt Jacob break; 303902ab3379SMatt Jacob case ISPASYNC_FABRIC_DEV: 304002ab3379SMatt Jacob { 3041029f13c6SMatt Jacob int target, base, lim; 304202ab3379SMatt Jacob fcparam *fcp = isp->isp_param; 3043029f13c6SMatt Jacob struct lportdb *lp = NULL; 3044029f13c6SMatt Jacob struct lportdb *clp = (struct lportdb *) arg; 3045029f13c6SMatt Jacob char *pt; 304602ab3379SMatt Jacob 3047029f13c6SMatt Jacob switch (clp->port_type) { 304840cfc8feSMatt Jacob case 1: 304940cfc8feSMatt Jacob pt = " N_Port"; 305040cfc8feSMatt Jacob break; 305140cfc8feSMatt Jacob case 2: 305240cfc8feSMatt Jacob pt = " NL_Port"; 305340cfc8feSMatt Jacob break; 305440cfc8feSMatt Jacob case 3: 305540cfc8feSMatt Jacob pt = "F/NL_Port"; 305640cfc8feSMatt Jacob break; 305740cfc8feSMatt Jacob case 0x7f: 305840cfc8feSMatt Jacob pt = " Nx_Port"; 305940cfc8feSMatt Jacob break; 306040cfc8feSMatt Jacob case 0x81: 306140cfc8feSMatt Jacob pt = " F_port"; 306240cfc8feSMatt Jacob break; 306340cfc8feSMatt Jacob case 0x82: 306440cfc8feSMatt Jacob pt = " FL_Port"; 306540cfc8feSMatt Jacob break; 306640cfc8feSMatt Jacob case 0x84: 306740cfc8feSMatt Jacob pt = " E_port"; 306840cfc8feSMatt Jacob break; 306940cfc8feSMatt Jacob default: 3070029f13c6SMatt Jacob pt = " "; 307140cfc8feSMatt Jacob break; 307240cfc8feSMatt Jacob } 3073029f13c6SMatt Jacob 3074b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, 3075029f13c6SMatt Jacob "%s Fabric Device @ PortID 0x%x", pt, clp->portid); 3076029f13c6SMatt Jacob 307770d2ccceSMatt Jacob /* 3078029f13c6SMatt Jacob * If we don't have an initiator role we bail. 3079029f13c6SMatt Jacob * 3080029f13c6SMatt Jacob * We just use ISPASYNC_FABRIC_DEV for announcement purposes. 308170d2ccceSMatt Jacob */ 3082029f13c6SMatt Jacob 3083029f13c6SMatt Jacob if ((isp->isp_role & ISP_ROLE_INITIATOR) == 0) { 308402ab3379SMatt Jacob break; 308502ab3379SMatt Jacob } 3086029f13c6SMatt Jacob 3087029f13c6SMatt Jacob /* 3088029f13c6SMatt Jacob * Is this entry for us? If so, we bail. 3089029f13c6SMatt Jacob */ 3090029f13c6SMatt Jacob 3091029f13c6SMatt Jacob if (fcp->isp_portid == clp->portid) { 3092029f13c6SMatt Jacob break; 3093029f13c6SMatt Jacob } 3094029f13c6SMatt Jacob 3095029f13c6SMatt Jacob /* 3096029f13c6SMatt Jacob * Else, the default policy is to find room for it in 3097029f13c6SMatt Jacob * our local port database. Later, when we execute 3098029f13c6SMatt Jacob * the call to isp_pdb_sync either this newly arrived 3099029f13c6SMatt Jacob * or already logged in device will be (re)announced. 3100029f13c6SMatt Jacob */ 3101029f13c6SMatt Jacob 3102029f13c6SMatt Jacob if (fcp->isp_topo == TOPO_FL_PORT) 3103029f13c6SMatt Jacob base = FC_SNS_ID+1; 310470d2ccceSMatt Jacob else 3105029f13c6SMatt Jacob base = 0; 3106029f13c6SMatt Jacob 3107029f13c6SMatt Jacob if (fcp->isp_topo == TOPO_N_PORT) 3108029f13c6SMatt Jacob lim = 1; 3109029f13c6SMatt Jacob else 3110029f13c6SMatt Jacob lim = MAX_FC_TARG; 3111029f13c6SMatt Jacob 311270d2ccceSMatt Jacob /* 311370d2ccceSMatt Jacob * Is it already in our list? 311470d2ccceSMatt Jacob */ 3115029f13c6SMatt Jacob for (target = base; target < lim; target++) { 311670d2ccceSMatt Jacob if (target >= FL_PORT_ID && target <= FC_SNS_ID) { 311770d2ccceSMatt Jacob continue; 311870d2ccceSMatt Jacob } 311970d2ccceSMatt Jacob lp = &fcp->portdb[target]; 3120029f13c6SMatt Jacob if (lp->port_wwn == clp->port_wwn && 3121029f13c6SMatt Jacob lp->node_wwn == clp->node_wwn) { 312270d2ccceSMatt Jacob lp->fabric_dev = 1; 312370d2ccceSMatt Jacob break; 312470d2ccceSMatt Jacob } 312570d2ccceSMatt Jacob } 3126029f13c6SMatt Jacob if (target < lim) { 312702ab3379SMatt Jacob break; 312802ab3379SMatt Jacob } 3129029f13c6SMatt Jacob for (target = base; target < lim; target++) { 313070d2ccceSMatt Jacob if (target >= FL_PORT_ID && target <= FC_SNS_ID) { 313170d2ccceSMatt Jacob continue; 313270d2ccceSMatt Jacob } 313302ab3379SMatt Jacob lp = &fcp->portdb[target]; 313470d2ccceSMatt Jacob if (lp->port_wwn == 0) { 313502ab3379SMatt Jacob break; 313602ab3379SMatt Jacob } 313770d2ccceSMatt Jacob } 3138029f13c6SMatt Jacob if (target == lim) { 3139bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 3140029f13c6SMatt Jacob "out of space for fabric devices"); 314102ab3379SMatt Jacob break; 314202ab3379SMatt Jacob } 3143029f13c6SMatt Jacob lp->port_type = clp->port_type; 3144029f13c6SMatt Jacob lp->fc4_type = clp->fc4_type; 3145029f13c6SMatt Jacob lp->node_wwn = clp->node_wwn; 3146029f13c6SMatt Jacob lp->port_wwn = clp->port_wwn; 3147029f13c6SMatt Jacob lp->portid = clp->portid; 314870d2ccceSMatt Jacob lp->fabric_dev = 1; 314902ab3379SMatt Jacob break; 315002ab3379SMatt Jacob } 3151d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 3152e5265237SMatt Jacob case ISPASYNC_TARGET_NOTIFY: 3153d81ba9d5SMatt Jacob { 3154e5265237SMatt Jacob tmd_notify_t *nt = arg; 315564edff94SMatt Jacob isp_prt(isp, ISP_LOGALL, 3156e5265237SMatt Jacob "target notify code 0x%x", nt->nt_ncode); 3157d81ba9d5SMatt Jacob break; 3158d81ba9d5SMatt Jacob } 3159d81ba9d5SMatt Jacob case ISPASYNC_TARGET_ACTION: 3160d81ba9d5SMatt Jacob switch (((isphdr_t *)arg)->rqs_entry_type) { 3161cbf57b47SMatt Jacob default: 3162bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 3163bfbab170SMatt Jacob "event 0x%x for unhandled target action", 3164bfbab170SMatt Jacob ((isphdr_t *)arg)->rqs_entry_type); 3165d81ba9d5SMatt Jacob break; 3166570c7a3fSMatt Jacob case RQSTYPE_NOTIFY: 3167570c7a3fSMatt Jacob if (IS_SCSI(isp)) { 3168570c7a3fSMatt Jacob rv = isp_handle_platform_notify_scsi(isp, 3169570c7a3fSMatt Jacob (in_entry_t *) arg); 3170570c7a3fSMatt Jacob } else { 3171570c7a3fSMatt Jacob rv = isp_handle_platform_notify_fc(isp, 3172570c7a3fSMatt Jacob (in_fcentry_t *) arg); 3173570c7a3fSMatt Jacob } 3174570c7a3fSMatt Jacob break; 3175d81ba9d5SMatt Jacob case RQSTYPE_ATIO: 3176d81ba9d5SMatt Jacob rv = isp_handle_platform_atio(isp, (at_entry_t *) arg); 3177d81ba9d5SMatt Jacob break; 3178d81ba9d5SMatt Jacob case RQSTYPE_ATIO2: 3179d81ba9d5SMatt Jacob rv = isp_handle_platform_atio2(isp, (at2_entry_t *)arg); 3180d81ba9d5SMatt Jacob break; 3181d81ba9d5SMatt Jacob case RQSTYPE_CTIO2: 3182d81ba9d5SMatt Jacob case RQSTYPE_CTIO: 3183d81ba9d5SMatt Jacob rv = isp_handle_platform_ctio(isp, arg); 3184d81ba9d5SMatt Jacob break; 3185d81ba9d5SMatt Jacob case RQSTYPE_ENABLE_LUN: 3186d81ba9d5SMatt Jacob case RQSTYPE_MODIFY_LUN: 318767ff51f1SMatt Jacob isp_ledone(isp, (lun_entry_t *) arg); 3188d81ba9d5SMatt Jacob break; 3189d81ba9d5SMatt Jacob } 3190d81ba9d5SMatt Jacob break; 3191d81ba9d5SMatt Jacob #endif 3192ab163f5fSMatt Jacob case ISPASYNC_FW_CRASH: 3193ab163f5fSMatt Jacob { 31941dae40ebSMatt Jacob uint16_t mbox1, mbox6; 3195ab163f5fSMatt Jacob mbox1 = ISP_READ(isp, OUTMAILBOX1); 3196ab163f5fSMatt Jacob if (IS_DUALBUS(isp)) { 3197ab163f5fSMatt Jacob mbox6 = ISP_READ(isp, OUTMAILBOX6); 3198ab163f5fSMatt Jacob } else { 3199ab163f5fSMatt Jacob mbox6 = 0; 3200ab163f5fSMatt Jacob } 3201ab163f5fSMatt Jacob isp_prt(isp, ISP_LOGERR, 3202570c7a3fSMatt Jacob "Internal Firmware Error on bus %d @ RISC Address 0x%x", 3203ab163f5fSMatt Jacob mbox6, mbox1); 32048a5f89b9SMatt Jacob #ifdef ISP_FW_CRASH_DUMP 32058a5f89b9SMatt Jacob /* 32068a5f89b9SMatt Jacob * XXX: really need a thread to do this right. 32078a5f89b9SMatt Jacob */ 32088a5f89b9SMatt Jacob if (IS_FC(isp)) { 32098a5f89b9SMatt Jacob FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; 32108a5f89b9SMatt Jacob FCPARAM(isp)->isp_loopstate = LOOP_NIL; 32118a5f89b9SMatt Jacob isp_freeze_loopdown(isp, "f/w crash"); 32128a5f89b9SMatt Jacob isp_fw_dump(isp); 32138a5f89b9SMatt Jacob } 3214ab163f5fSMatt Jacob isp_reinit(isp); 32158a5f89b9SMatt Jacob isp_async(isp, ISPASYNC_FW_RESTARTED, NULL); 32168a5f89b9SMatt Jacob #endif 3217ab163f5fSMatt Jacob break; 3218ab163f5fSMatt Jacob } 3219be534d5fSMatt Jacob case ISPASYNC_UNHANDLED_RESPONSE: 3220be534d5fSMatt Jacob break; 3221d81ba9d5SMatt Jacob default: 3222b09b0095SMatt Jacob isp_prt(isp, ISP_LOGERR, "unknown isp_async event %d", cmd); 3223cbf57b47SMatt Jacob break; 3224cbf57b47SMatt Jacob } 3225cbf57b47SMatt Jacob return (rv); 3226cbf57b47SMatt Jacob } 3227cbf57b47SMatt Jacob 322892718a7fSMatt Jacob 322992718a7fSMatt Jacob /* 323092718a7fSMatt Jacob * Locks are held before coming here. 323192718a7fSMatt Jacob */ 323292718a7fSMatt Jacob void 32339cd7268eSMatt Jacob isp_uninit(ispsoftc_t *isp) 323492718a7fSMatt Jacob { 3235ea6f23cdSMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_RESET); 323692718a7fSMatt Jacob DISABLE_INTS(isp); 323792718a7fSMatt Jacob } 3238b09b0095SMatt Jacob 3239b09b0095SMatt Jacob void 32409cd7268eSMatt Jacob isp_prt(ispsoftc_t *isp, int level, const char *fmt, ...) 3241b09b0095SMatt Jacob { 3242b09b0095SMatt Jacob va_list ap; 3243b09b0095SMatt Jacob if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) { 3244b09b0095SMatt Jacob return; 3245b09b0095SMatt Jacob } 32463c75bb14SMatt Jacob printf("%s: ", device_get_nameunit(isp->isp_dev)); 3247b09b0095SMatt Jacob va_start(ap, fmt); 3248b09b0095SMatt Jacob vprintf(fmt, ap); 3249b09b0095SMatt Jacob va_end(ap); 3250b09b0095SMatt Jacob printf("\n"); 3251b09b0095SMatt Jacob } 3252