1098ca2bdSWarner Losh /*- 26054c3f6SMatt Jacob * 3e5265237SMatt Jacob * Copyright (c) 1997-2006 by Matthew Jacob 4e5265237SMatt Jacob * All rights reserved. 56054c3f6SMatt Jacob * 66054c3f6SMatt Jacob * Redistribution and use in source and binary forms, with or without 76054c3f6SMatt Jacob * modification, are permitted provided that the following conditions 86054c3f6SMatt Jacob * are met: 96054c3f6SMatt Jacob * 1. Redistributions of source code must retain the above copyright 106054c3f6SMatt Jacob * notice immediately at the beginning of the file, without modification, 116054c3f6SMatt Jacob * this list of conditions, and the following disclaimer. 12aa57fd6fSMatt Jacob * 2. The name of the author may not be used to endorse or promote products 13aa57fd6fSMatt Jacob * derived from this software without specific prior written permission. 146054c3f6SMatt Jacob * 156054c3f6SMatt Jacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 166054c3f6SMatt Jacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 176054c3f6SMatt Jacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 186054c3f6SMatt Jacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 196054c3f6SMatt Jacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 206054c3f6SMatt Jacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 216054c3f6SMatt Jacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 226054c3f6SMatt Jacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 236054c3f6SMatt Jacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 246054c3f6SMatt Jacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 256054c3f6SMatt Jacob * SUCH DAMAGE. 266054c3f6SMatt Jacob */ 27aad970f1SDavid E. O'Brien 28799881e0SMatt Jacob /* 29799881e0SMatt Jacob * Platform (FreeBSD) dependent common attachment code for Qlogic adapters. 30799881e0SMatt Jacob */ 31aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 32aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 336054c3f6SMatt Jacob #include <dev/isp/isp_freebsd.h> 345d571944SMatt Jacob #include <sys/unistd.h> 355d571944SMatt Jacob #include <sys/kthread.h> 363ea883b4SMatt Jacob #include <machine/stdarg.h> /* for use by isp_prt below */ 375d571944SMatt Jacob #include <sys/conf.h> 384eb49427SMatt Jacob #include <sys/module.h> 395d571944SMatt Jacob #include <sys/ioccom.h> 405d571944SMatt Jacob #include <dev/isp/isp_ioctl.h> 416054c3f6SMatt Jacob 42a1bc34c6SMatt Jacob 434eb49427SMatt Jacob MODULE_VERSION(isp, 1); 4456c5b842SMark Murray MODULE_DEPEND(isp, cam, 1, 1, 1); 4573030e03SMatt Jacob int isp_announced = 0; 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: 29402e2b2d9SMatt Jacob if (IS_FC(isp)) { 2951dae40ebSMatt Jacob uint16_t *ptr = FCPARAM(isp)->isp_dump_data; 296d134aa0bSMatt Jacob size_t sz; 297d134aa0bSMatt Jacob 298d134aa0bSMatt Jacob retval = 0; 29902e2b2d9SMatt Jacob if (IS_2200(isp)) { 300d134aa0bSMatt Jacob sz = QLA2200_RISC_IMAGE_DUMP_SIZE; 30102e2b2d9SMatt Jacob } else { 302d134aa0bSMatt Jacob sz = QLA2300_RISC_IMAGE_DUMP_SIZE; 30302e2b2d9SMatt Jacob } 304d134aa0bSMatt Jacob ISP_LOCK(isp); 305d134aa0bSMatt Jacob if (ptr && *ptr) { 306d134aa0bSMatt Jacob void *uaddr = *((void **) addr); 307d134aa0bSMatt Jacob if (copyout(ptr, uaddr, sz)) { 308d134aa0bSMatt Jacob retval = EFAULT; 309d134aa0bSMatt Jacob } else { 310d134aa0bSMatt Jacob *ptr = 0; 311d134aa0bSMatt Jacob } 312d134aa0bSMatt Jacob } else { 313d134aa0bSMatt Jacob retval = ENXIO; 314d134aa0bSMatt Jacob } 315d134aa0bSMatt Jacob ISP_UNLOCK(isp); 316d134aa0bSMatt Jacob } 31702e2b2d9SMatt Jacob break; 318d134aa0bSMatt Jacob case ISP_FORCE_CRASH_DUMP: 31902e2b2d9SMatt Jacob if (IS_FC(isp)) { 320d134aa0bSMatt Jacob ISP_LOCK(isp); 32102e2b2d9SMatt Jacob isp_freeze_loopdown(isp, 32202e2b2d9SMatt Jacob "ispioctl(ISP_FORCE_CRASH_DUMP)"); 323d134aa0bSMatt Jacob isp_fw_dump(isp); 324d134aa0bSMatt Jacob isp_reinit(isp); 325d134aa0bSMatt Jacob ISP_UNLOCK(isp); 326d134aa0bSMatt Jacob retval = 0; 32702e2b2d9SMatt Jacob } 328d134aa0bSMatt Jacob break; 329d134aa0bSMatt Jacob #endif 3305d571944SMatt Jacob case ISP_SDBLEV: 3315d571944SMatt Jacob { 3325d571944SMatt Jacob int olddblev = isp->isp_dblev; 3335d571944SMatt Jacob isp->isp_dblev = *(int *)addr; 3345d571944SMatt Jacob *(int *)addr = olddblev; 3355d571944SMatt Jacob retval = 0; 3365d571944SMatt Jacob break; 3375d571944SMatt Jacob } 338746e9c85SMatt Jacob case ISP_GETROLE: 339746e9c85SMatt Jacob *(int *)addr = isp->isp_role; 340746e9c85SMatt Jacob retval = 0; 341746e9c85SMatt Jacob break; 342746e9c85SMatt Jacob case ISP_SETROLE: 343746e9c85SMatt Jacob nr = *(int *)addr; 344746e9c85SMatt Jacob if (nr & ~(ISP_ROLE_INITIATOR|ISP_ROLE_TARGET)) { 345746e9c85SMatt Jacob retval = EINVAL; 346746e9c85SMatt Jacob break; 347746e9c85SMatt Jacob } 348746e9c85SMatt Jacob *(int *)addr = isp->isp_role; 349746e9c85SMatt Jacob isp->isp_role = nr; 350746e9c85SMatt Jacob /* FALLTHROUGH */ 3515d571944SMatt Jacob case ISP_RESETHBA: 3525d571944SMatt Jacob ISP_LOCK(isp); 3535d571944SMatt Jacob isp_reinit(isp); 3545d571944SMatt Jacob ISP_UNLOCK(isp); 3555d571944SMatt Jacob retval = 0; 3565d571944SMatt Jacob break; 357f553351eSMatt Jacob case ISP_RESCAN: 3585d571944SMatt Jacob if (IS_FC(isp)) { 3595d571944SMatt Jacob ISP_LOCK(isp); 3605d571944SMatt Jacob if (isp_fc_runstate(isp, 5 * 1000000)) { 3615d571944SMatt Jacob retval = EIO; 3625d571944SMatt Jacob } else { 3635d571944SMatt Jacob retval = 0; 3645d571944SMatt Jacob } 3655d571944SMatt Jacob ISP_UNLOCK(isp); 3665d571944SMatt Jacob } 3675d571944SMatt Jacob break; 3685d571944SMatt Jacob case ISP_FC_LIP: 3695d571944SMatt Jacob if (IS_FC(isp)) { 3705d571944SMatt Jacob ISP_LOCK(isp); 3715d571944SMatt Jacob if (isp_control(isp, ISPCTL_SEND_LIP, 0)) { 3725d571944SMatt Jacob retval = EIO; 3735d571944SMatt Jacob } else { 3745d571944SMatt Jacob retval = 0; 3755d571944SMatt Jacob } 3765d571944SMatt Jacob ISP_UNLOCK(isp); 3775d571944SMatt Jacob } 3785d571944SMatt Jacob break; 3795d571944SMatt Jacob case ISP_FC_GETDINFO: 3805d571944SMatt Jacob { 3815d571944SMatt Jacob struct isp_fc_device *ifc = (struct isp_fc_device *) addr; 3825d571944SMatt Jacob struct lportdb *lp; 3835d571944SMatt Jacob 38402e2b2d9SMatt Jacob if (IS_SCSI(isp)) { 38502e2b2d9SMatt Jacob break; 38602e2b2d9SMatt Jacob } 3875d571944SMatt Jacob if (ifc->loopid < 0 || ifc->loopid >= MAX_FC_TARG) { 3885d571944SMatt Jacob retval = EINVAL; 3895d571944SMatt Jacob break; 3905d571944SMatt Jacob } 3915d571944SMatt Jacob ISP_LOCK(isp); 3925d571944SMatt Jacob lp = &FCPARAM(isp)->portdb[ifc->loopid]; 3935d571944SMatt Jacob if (lp->valid) { 394c6435ff3SMatt Jacob ifc->role = lp->roles; 3955d571944SMatt Jacob ifc->loopid = lp->loopid; 3965d571944SMatt Jacob ifc->portid = lp->portid; 3975d571944SMatt Jacob ifc->node_wwn = lp->node_wwn; 3985d571944SMatt Jacob ifc->port_wwn = lp->port_wwn; 3995d571944SMatt Jacob retval = 0; 4005d571944SMatt Jacob } else { 4015d571944SMatt Jacob retval = ENODEV; 4025d571944SMatt Jacob } 4035d571944SMatt Jacob ISP_UNLOCK(isp); 4045d571944SMatt Jacob break; 4055d571944SMatt Jacob } 4062903b272SMatt Jacob case ISP_GET_STATS: 4072903b272SMatt Jacob { 4082903b272SMatt Jacob isp_stats_t *sp = (isp_stats_t *) addr; 4092903b272SMatt Jacob 4102903b272SMatt Jacob MEMZERO(sp, sizeof (*sp)); 4112903b272SMatt Jacob sp->isp_stat_version = ISP_STATS_VERSION; 4122903b272SMatt Jacob sp->isp_type = isp->isp_type; 4132903b272SMatt Jacob sp->isp_revision = isp->isp_revision; 4142903b272SMatt Jacob ISP_LOCK(isp); 4152903b272SMatt Jacob sp->isp_stats[ISP_INTCNT] = isp->isp_intcnt; 4162903b272SMatt Jacob sp->isp_stats[ISP_INTBOGUS] = isp->isp_intbogus; 4172903b272SMatt Jacob sp->isp_stats[ISP_INTMBOXC] = isp->isp_intmboxc; 4182903b272SMatt Jacob sp->isp_stats[ISP_INGOASYNC] = isp->isp_intoasync; 4192903b272SMatt Jacob sp->isp_stats[ISP_RSLTCCMPLT] = isp->isp_rsltccmplt; 4202903b272SMatt Jacob sp->isp_stats[ISP_FPHCCMCPLT] = isp->isp_fphccmplt; 4212903b272SMatt Jacob sp->isp_stats[ISP_RSCCHIWAT] = isp->isp_rscchiwater; 4222903b272SMatt Jacob sp->isp_stats[ISP_FPCCHIWAT] = isp->isp_fpcchiwater; 4232903b272SMatt Jacob ISP_UNLOCK(isp); 4242903b272SMatt Jacob retval = 0; 4252903b272SMatt Jacob break; 4262903b272SMatt Jacob } 4272903b272SMatt Jacob case ISP_CLR_STATS: 4282903b272SMatt Jacob ISP_LOCK(isp); 4292903b272SMatt Jacob isp->isp_intcnt = 0; 4302903b272SMatt Jacob isp->isp_intbogus = 0; 4312903b272SMatt Jacob isp->isp_intmboxc = 0; 4322903b272SMatt Jacob isp->isp_intoasync = 0; 4332903b272SMatt Jacob isp->isp_rsltccmplt = 0; 4342903b272SMatt Jacob isp->isp_fphccmplt = 0; 4352903b272SMatt Jacob isp->isp_rscchiwater = 0; 4362903b272SMatt Jacob isp->isp_fpcchiwater = 0; 4372903b272SMatt Jacob ISP_UNLOCK(isp); 4382903b272SMatt Jacob retval = 0; 4392903b272SMatt Jacob break; 440570c7a3fSMatt Jacob case ISP_FC_GETHINFO: 441570c7a3fSMatt Jacob { 442570c7a3fSMatt Jacob struct isp_hba_device *hba = (struct isp_hba_device *) addr; 443570c7a3fSMatt Jacob MEMZERO(hba, sizeof (*hba)); 44402e2b2d9SMatt Jacob 445a556b68eSMatt Jacob hba->fc_fw_major = ISP_FW_MAJORX(isp->isp_fwrev); 446a556b68eSMatt Jacob hba->fc_fw_minor = ISP_FW_MINORX(isp->isp_fwrev); 447a556b68eSMatt Jacob hba->fc_fw_micro = ISP_FW_MICROX(isp->isp_fwrev); 44802e2b2d9SMatt Jacob if (IS_FC(isp)) { 449570c7a3fSMatt Jacob hba->fc_speed = FCPARAM(isp)->isp_gbspeed; 450570c7a3fSMatt Jacob hba->fc_scsi_supported = 1; 451570c7a3fSMatt Jacob hba->fc_topology = FCPARAM(isp)->isp_topo + 1; 452570c7a3fSMatt Jacob hba->fc_loopid = FCPARAM(isp)->isp_loopid; 453fd6eb9f7SMatt Jacob hba->nvram_node_wwn = FCPARAM(isp)->isp_nodewwn; 454fd6eb9f7SMatt Jacob hba->nvram_port_wwn = FCPARAM(isp)->isp_portwwn; 455fd6eb9f7SMatt Jacob hba->active_node_wwn = ISP_NODEWWN(isp); 456fd6eb9f7SMatt Jacob hba->active_port_wwn = ISP_PORTWWN(isp); 45702e2b2d9SMatt Jacob } 458570c7a3fSMatt Jacob retval = 0; 459570c7a3fSMatt Jacob break; 460570c7a3fSMatt Jacob } 461fdeb9f2fSMatt Jacob case ISP_GET_FC_PARAM: 462fdeb9f2fSMatt Jacob { 463fdeb9f2fSMatt Jacob struct isp_fc_param *f = (struct isp_fc_param *) addr; 464fdeb9f2fSMatt Jacob 46502e2b2d9SMatt Jacob if (IS_SCSI(isp)) { 466fdeb9f2fSMatt Jacob break; 467fdeb9f2fSMatt Jacob } 468fdeb9f2fSMatt Jacob f->parameter = 0; 469fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "framelength") == 0) { 470fdeb9f2fSMatt Jacob f->parameter = FCPARAM(isp)->isp_maxfrmlen; 471fdeb9f2fSMatt Jacob retval = 0; 472fdeb9f2fSMatt Jacob break; 473fdeb9f2fSMatt Jacob } 474fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "exec_throttle") == 0) { 475fdeb9f2fSMatt Jacob f->parameter = FCPARAM(isp)->isp_execthrottle; 476fdeb9f2fSMatt Jacob retval = 0; 477fdeb9f2fSMatt Jacob break; 478fdeb9f2fSMatt Jacob } 479fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "fullduplex") == 0) { 480fdeb9f2fSMatt Jacob if (FCPARAM(isp)->isp_fwoptions & ICBOPT_FULL_DUPLEX) 481fdeb9f2fSMatt Jacob f->parameter = 1; 482fdeb9f2fSMatt Jacob retval = 0; 483fdeb9f2fSMatt Jacob break; 484fdeb9f2fSMatt Jacob } 485fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "loopid") == 0) { 486fdeb9f2fSMatt Jacob f->parameter = FCPARAM(isp)->isp_loopid; 487fdeb9f2fSMatt Jacob retval = 0; 488fdeb9f2fSMatt Jacob break; 489fdeb9f2fSMatt Jacob } 490fdeb9f2fSMatt Jacob retval = EINVAL; 491fdeb9f2fSMatt Jacob break; 492fdeb9f2fSMatt Jacob } 493fdeb9f2fSMatt Jacob case ISP_SET_FC_PARAM: 494fdeb9f2fSMatt Jacob { 495fdeb9f2fSMatt Jacob struct isp_fc_param *f = (struct isp_fc_param *) addr; 4961dae40ebSMatt Jacob uint32_t param = f->parameter; 497fdeb9f2fSMatt Jacob 49802e2b2d9SMatt Jacob if (IS_SCSI(isp)) { 499fdeb9f2fSMatt Jacob break; 500fdeb9f2fSMatt Jacob } 501fdeb9f2fSMatt Jacob f->parameter = 0; 502fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "framelength") == 0) { 503fdeb9f2fSMatt Jacob if (param != 512 && param != 1024 && param != 1024) { 504fdeb9f2fSMatt Jacob retval = EINVAL; 505fdeb9f2fSMatt Jacob break; 506fdeb9f2fSMatt Jacob } 507fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_maxfrmlen = param; 508fdeb9f2fSMatt Jacob retval = 0; 509fdeb9f2fSMatt Jacob break; 510fdeb9f2fSMatt Jacob } 511fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "exec_throttle") == 0) { 512fdeb9f2fSMatt Jacob if (param < 16 || param > 255) { 513fdeb9f2fSMatt Jacob retval = EINVAL; 514fdeb9f2fSMatt Jacob break; 515fdeb9f2fSMatt Jacob } 516fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_execthrottle = param; 517fdeb9f2fSMatt Jacob retval = 0; 518fdeb9f2fSMatt Jacob break; 519fdeb9f2fSMatt Jacob } 520fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "fullduplex") == 0) { 521fdeb9f2fSMatt Jacob if (param != 0 && param != 1) { 522fdeb9f2fSMatt Jacob retval = EINVAL; 523fdeb9f2fSMatt Jacob break; 524fdeb9f2fSMatt Jacob } 525fdeb9f2fSMatt Jacob if (param) { 526fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_fwoptions |= 527fdeb9f2fSMatt Jacob ICBOPT_FULL_DUPLEX; 528fdeb9f2fSMatt Jacob } else { 529fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_fwoptions &= 530fdeb9f2fSMatt Jacob ~ICBOPT_FULL_DUPLEX; 531fdeb9f2fSMatt Jacob } 532fdeb9f2fSMatt Jacob retval = 0; 533fdeb9f2fSMatt Jacob break; 534fdeb9f2fSMatt Jacob } 535fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "loopid") == 0) { 536fdeb9f2fSMatt Jacob if (param < 0 || param > 125) { 537fdeb9f2fSMatt Jacob retval = EINVAL; 538fdeb9f2fSMatt Jacob break; 539fdeb9f2fSMatt Jacob } 540fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_loopid = param; 541fdeb9f2fSMatt Jacob retval = 0; 542fdeb9f2fSMatt Jacob break; 543fdeb9f2fSMatt Jacob } 544fdeb9f2fSMatt Jacob retval = EINVAL; 545fdeb9f2fSMatt Jacob break; 546fdeb9f2fSMatt Jacob } 5478e62a8acSMatt Jacob case ISP_TSK_MGMT: 5488e62a8acSMatt Jacob { 5498e62a8acSMatt Jacob int needmarker; 5508e62a8acSMatt Jacob struct isp_fc_tsk_mgmt *fct = (struct isp_fc_tsk_mgmt *) addr; 5511dae40ebSMatt Jacob uint16_t loopid; 5528e62a8acSMatt Jacob mbreg_t mbs; 5538e62a8acSMatt Jacob 5548e62a8acSMatt Jacob if (IS_SCSI(isp)) { 5558e62a8acSMatt Jacob break; 5568e62a8acSMatt Jacob } 5578e62a8acSMatt Jacob 5588e62a8acSMatt Jacob memset(&mbs, 0, sizeof (mbs)); 5598e62a8acSMatt Jacob needmarker = retval = 0; 560e5265237SMatt Jacob loopid = fct->loopid; 561e5265237SMatt Jacob if (IS_2KLOGIN(isp) == 0) { 562e5265237SMatt Jacob loopid <<= 8; 563e5265237SMatt Jacob } 5648e62a8acSMatt Jacob switch (fct->action) { 565f0f536d1SMatt Jacob case IPT_CLEAR_ACA: 5668e62a8acSMatt Jacob mbs.param[0] = MBOX_CLEAR_ACA; 567e5265237SMatt Jacob mbs.param[1] = loopid; 5688e62a8acSMatt Jacob mbs.param[2] = fct->lun; 5698e62a8acSMatt Jacob break; 570f0f536d1SMatt Jacob case IPT_TARGET_RESET: 5718e62a8acSMatt Jacob mbs.param[0] = MBOX_TARGET_RESET; 572e5265237SMatt Jacob mbs.param[1] = loopid; 5738e62a8acSMatt Jacob needmarker = 1; 5748e62a8acSMatt Jacob break; 575f0f536d1SMatt Jacob case IPT_LUN_RESET: 5768e62a8acSMatt Jacob mbs.param[0] = MBOX_LUN_RESET; 577e5265237SMatt Jacob mbs.param[1] = loopid; 5788e62a8acSMatt Jacob mbs.param[2] = fct->lun; 5798e62a8acSMatt Jacob needmarker = 1; 5808e62a8acSMatt Jacob break; 581f0f536d1SMatt Jacob case IPT_CLEAR_TASK_SET: 5828e62a8acSMatt Jacob mbs.param[0] = MBOX_CLEAR_TASK_SET; 583e5265237SMatt Jacob mbs.param[1] = loopid; 5848e62a8acSMatt Jacob mbs.param[2] = fct->lun; 5858e62a8acSMatt Jacob needmarker = 1; 5868e62a8acSMatt Jacob break; 587f0f536d1SMatt Jacob case IPT_ABORT_TASK_SET: 5888e62a8acSMatt Jacob mbs.param[0] = MBOX_ABORT_TASK_SET; 589e5265237SMatt Jacob mbs.param[1] = loopid; 5908e62a8acSMatt Jacob mbs.param[2] = fct->lun; 5918e62a8acSMatt Jacob needmarker = 1; 5928e62a8acSMatt Jacob break; 5938e62a8acSMatt Jacob default: 5948e62a8acSMatt Jacob retval = EINVAL; 5958e62a8acSMatt Jacob break; 5968e62a8acSMatt Jacob } 5978e62a8acSMatt Jacob if (retval == 0) { 5988e62a8acSMatt Jacob ISP_LOCK(isp); 5998e62a8acSMatt Jacob if (needmarker) { 6008e62a8acSMatt Jacob isp->isp_sendmarker |= 1; 6018e62a8acSMatt Jacob } 6028e62a8acSMatt Jacob retval = isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); 6038e62a8acSMatt Jacob ISP_UNLOCK(isp); 6048e62a8acSMatt Jacob if (retval) 6058e62a8acSMatt Jacob retval = EIO; 6068e62a8acSMatt Jacob } 6078e62a8acSMatt Jacob break; 6088e62a8acSMatt Jacob } 6095d571944SMatt Jacob default: 6105d571944SMatt Jacob break; 6115d571944SMatt Jacob } 6125d571944SMatt Jacob return (retval); 6130470d791SMatt Jacob } 614478f8a96SJustin T. Gibbs 615f6e75de2SMatt Jacob static void 616f6e75de2SMatt Jacob isp_intr_enable(void *arg) 617f6e75de2SMatt Jacob { 6189cd7268eSMatt Jacob ispsoftc_t *isp = arg; 619d6e5500fSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE) { 620f6e75de2SMatt Jacob ENABLE_INTS(isp); 621e3e49f7eSMatt Jacob #if 0 622f6e75de2SMatt Jacob isp->isp_osinfo.intsok = 1; 623e3e49f7eSMatt Jacob #endif 624d6e5500fSMatt Jacob } 625f6e75de2SMatt Jacob /* Release our hook so that the boot can continue. */ 626f6e75de2SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 627f6e75de2SMatt Jacob } 628d81ba9d5SMatt Jacob 629d81ba9d5SMatt Jacob /* 630d81ba9d5SMatt Jacob * Put the target mode functions here, because some are inlines 631d81ba9d5SMatt Jacob */ 632d81ba9d5SMatt Jacob 633d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 634d81ba9d5SMatt Jacob 6359cd7268eSMatt Jacob static __inline int is_lun_enabled(ispsoftc_t *, int, lun_id_t); 6369cd7268eSMatt Jacob static __inline int are_any_luns_enabled(ispsoftc_t *, int); 6379cd7268eSMatt Jacob static __inline tstate_t *get_lun_statep(ispsoftc_t *, int, lun_id_t); 6389cd7268eSMatt Jacob static __inline void rls_lun_statep(ispsoftc_t *, tstate_t *); 6399cd7268eSMatt Jacob static __inline atio_private_data_t *isp_get_atpd(ispsoftc_t *, int); 640d81ba9d5SMatt Jacob static cam_status 6419cd7268eSMatt Jacob create_lun_state(ispsoftc_t *, int, struct cam_path *, tstate_t **); 6429cd7268eSMatt Jacob static void destroy_lun_state(ispsoftc_t *, tstate_t *); 6439cd7268eSMatt Jacob static int isp_en_lun(ispsoftc_t *, union ccb *); 6449cd7268eSMatt Jacob static void isp_ledone(ispsoftc_t *, lun_entry_t *); 6459cd7268eSMatt Jacob static cam_status isp_abort_tgt_ccb(ispsoftc_t *, union ccb *); 646f48ce188SMatt Jacob static timeout_t isp_refire_putback_atio; 647a1bc34c6SMatt Jacob static void isp_complete_ctio(union ccb *); 648a1bc34c6SMatt Jacob static void isp_target_putback_atio(union ccb *); 6499cd7268eSMatt Jacob static void isp_target_start_ctio(ispsoftc_t *, union ccb *); 6509cd7268eSMatt Jacob static int isp_handle_platform_atio(ispsoftc_t *, at_entry_t *); 6519cd7268eSMatt Jacob static int isp_handle_platform_atio2(ispsoftc_t *, at2_entry_t *); 6529cd7268eSMatt Jacob static int isp_handle_platform_ctio(ispsoftc_t *, void *); 6539cd7268eSMatt Jacob static int isp_handle_platform_notify_scsi(ispsoftc_t *, in_entry_t *); 6549cd7268eSMatt Jacob static int isp_handle_platform_notify_fc(ispsoftc_t *, in_fcentry_t *); 655d81ba9d5SMatt Jacob 65653af7d22SMatt Jacob static __inline int 6579cd7268eSMatt Jacob is_lun_enabled(ispsoftc_t *isp, int bus, lun_id_t lun) 658d81ba9d5SMatt Jacob { 659d81ba9d5SMatt Jacob tstate_t *tptr; 660a1bc34c6SMatt Jacob tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)]; 661a1bc34c6SMatt Jacob if (tptr == NULL) { 662d81ba9d5SMatt Jacob return (0); 663d81ba9d5SMatt Jacob } 664d81ba9d5SMatt Jacob do { 665a1bc34c6SMatt Jacob if (tptr->lun == (lun_id_t) lun && tptr->bus == bus) { 666d81ba9d5SMatt Jacob return (1); 667d81ba9d5SMatt Jacob } 668d81ba9d5SMatt Jacob } while ((tptr = tptr->next) != NULL); 669d81ba9d5SMatt Jacob return (0); 670d81ba9d5SMatt Jacob } 671d81ba9d5SMatt Jacob 67253af7d22SMatt Jacob static __inline int 6739cd7268eSMatt Jacob are_any_luns_enabled(ispsoftc_t *isp, int port) 674d81ba9d5SMatt Jacob { 675a1bc34c6SMatt Jacob int lo, hi; 676a1bc34c6SMatt Jacob if (IS_DUALBUS(isp)) { 677a1bc34c6SMatt Jacob lo = (port * (LUN_HASH_SIZE >> 1)); 678a1bc34c6SMatt Jacob hi = lo + (LUN_HASH_SIZE >> 1); 679a1bc34c6SMatt Jacob } else { 680a1bc34c6SMatt Jacob lo = 0; 681a1bc34c6SMatt Jacob hi = LUN_HASH_SIZE; 682a1bc34c6SMatt Jacob } 683a1bc34c6SMatt Jacob for (lo = 0; lo < hi; lo++) { 684a1bc34c6SMatt Jacob if (isp->isp_osinfo.lun_hash[lo]) { 685d81ba9d5SMatt Jacob return (1); 686d81ba9d5SMatt Jacob } 687d81ba9d5SMatt Jacob } 688d81ba9d5SMatt Jacob return (0); 689d81ba9d5SMatt Jacob } 690d81ba9d5SMatt Jacob 69153af7d22SMatt Jacob static __inline tstate_t * 6929cd7268eSMatt Jacob get_lun_statep(ispsoftc_t *isp, int bus, lun_id_t lun) 693d81ba9d5SMatt Jacob { 69464edff94SMatt Jacob tstate_t *tptr = NULL; 695d81ba9d5SMatt Jacob 696d81ba9d5SMatt Jacob if (lun == CAM_LUN_WILDCARD) { 69764edff94SMatt Jacob if (isp->isp_osinfo.tmflags[bus] & TM_WILDCARD_ENABLED) { 698a1bc34c6SMatt Jacob tptr = &isp->isp_osinfo.tsdflt[bus]; 699d81ba9d5SMatt Jacob tptr->hold++; 700d81ba9d5SMatt Jacob return (tptr); 701d81ba9d5SMatt Jacob } 70267ff51f1SMatt Jacob return (NULL); 703126ec864SMatt Jacob } else { 704126ec864SMatt Jacob tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)]; 70564edff94SMatt Jacob if (tptr == NULL) { 70664edff94SMatt Jacob return (NULL); 70764edff94SMatt Jacob } 708126ec864SMatt Jacob } 709d81ba9d5SMatt Jacob 710d81ba9d5SMatt Jacob do { 711a1bc34c6SMatt Jacob if (tptr->lun == lun && tptr->bus == bus) { 712d81ba9d5SMatt Jacob tptr->hold++; 713d81ba9d5SMatt Jacob return (tptr); 714d81ba9d5SMatt Jacob } 715d81ba9d5SMatt Jacob } while ((tptr = tptr->next) != NULL); 716d81ba9d5SMatt Jacob return (tptr); 717d81ba9d5SMatt Jacob } 718d81ba9d5SMatt Jacob 71953af7d22SMatt Jacob static __inline void 7209cd7268eSMatt Jacob rls_lun_statep(ispsoftc_t *isp, tstate_t *tptr) 721d81ba9d5SMatt Jacob { 722d81ba9d5SMatt Jacob if (tptr->hold) 723d81ba9d5SMatt Jacob tptr->hold--; 724d81ba9d5SMatt Jacob } 725d81ba9d5SMatt Jacob 72653af7d22SMatt Jacob static __inline atio_private_data_t * 7279cd7268eSMatt Jacob isp_get_atpd(ispsoftc_t *isp, int tag) 72853036e92SMatt Jacob { 72953036e92SMatt Jacob atio_private_data_t *atp; 73053036e92SMatt Jacob for (atp = isp->isp_osinfo.atpdp; 73153036e92SMatt Jacob atp < &isp->isp_osinfo.atpdp[ATPDPSIZE]; atp++) { 73253036e92SMatt Jacob if (atp->tag == tag) 73353036e92SMatt Jacob return (atp); 73453036e92SMatt Jacob } 73553036e92SMatt Jacob return (NULL); 73653036e92SMatt Jacob } 73753036e92SMatt Jacob 738d81ba9d5SMatt Jacob static cam_status 7399cd7268eSMatt Jacob create_lun_state(ispsoftc_t *isp, int bus, 740a1bc34c6SMatt Jacob struct cam_path *path, tstate_t **rslt) 741d81ba9d5SMatt Jacob { 742d81ba9d5SMatt Jacob cam_status status; 743d81ba9d5SMatt Jacob lun_id_t lun; 744a1bc34c6SMatt Jacob int hfx; 745d81ba9d5SMatt Jacob tstate_t *tptr, *new; 746d81ba9d5SMatt Jacob 747d81ba9d5SMatt Jacob lun = xpt_path_lun_id(path); 748d81ba9d5SMatt Jacob if (lun < 0) { 749d81ba9d5SMatt Jacob return (CAM_LUN_INVALID); 750d81ba9d5SMatt Jacob } 751a1bc34c6SMatt Jacob if (is_lun_enabled(isp, bus, lun)) { 752d81ba9d5SMatt Jacob return (CAM_LUN_ALRDY_ENA); 753d81ba9d5SMatt Jacob } 754ea8b5a9aSDavid Malone new = (tstate_t *) malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO); 755d81ba9d5SMatt Jacob if (new == NULL) { 756d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 757d81ba9d5SMatt Jacob } 758d81ba9d5SMatt Jacob 759d81ba9d5SMatt Jacob status = xpt_create_path(&new->owner, NULL, xpt_path_path_id(path), 760d81ba9d5SMatt Jacob xpt_path_target_id(path), xpt_path_lun_id(path)); 761d81ba9d5SMatt Jacob if (status != CAM_REQ_CMP) { 762d81ba9d5SMatt Jacob free(new, M_DEVBUF); 763d81ba9d5SMatt Jacob return (status); 764d81ba9d5SMatt Jacob } 765a1bc34c6SMatt Jacob new->bus = bus; 766d81ba9d5SMatt Jacob new->lun = lun; 767d81ba9d5SMatt Jacob SLIST_INIT(&new->atios); 768d81ba9d5SMatt Jacob SLIST_INIT(&new->inots); 769d81ba9d5SMatt Jacob new->hold = 1; 770d81ba9d5SMatt Jacob 771a1bc34c6SMatt Jacob hfx = LUN_HASH_FUNC(isp, new->bus, new->lun); 772a1bc34c6SMatt Jacob tptr = isp->isp_osinfo.lun_hash[hfx]; 773a1bc34c6SMatt Jacob if (tptr == NULL) { 774a1bc34c6SMatt Jacob isp->isp_osinfo.lun_hash[hfx] = new; 775d81ba9d5SMatt Jacob } else { 776d81ba9d5SMatt Jacob while (tptr->next) 777d81ba9d5SMatt Jacob tptr = tptr->next; 778d81ba9d5SMatt Jacob tptr->next = new; 779d81ba9d5SMatt Jacob } 780d81ba9d5SMatt Jacob *rslt = new; 781d81ba9d5SMatt Jacob return (CAM_REQ_CMP); 782d81ba9d5SMatt Jacob } 783d81ba9d5SMatt Jacob 78453af7d22SMatt Jacob static __inline void 7859cd7268eSMatt Jacob destroy_lun_state(ispsoftc_t *isp, tstate_t *tptr) 786d81ba9d5SMatt Jacob { 787a1bc34c6SMatt Jacob int hfx; 788d81ba9d5SMatt Jacob tstate_t *lw, *pw; 789d81ba9d5SMatt Jacob 790d81ba9d5SMatt Jacob if (tptr->hold) { 791d81ba9d5SMatt Jacob return; 792d81ba9d5SMatt Jacob } 79367ff51f1SMatt Jacob hfx = LUN_HASH_FUNC(isp, tptr->bus, tptr->lun); 794a1bc34c6SMatt Jacob pw = isp->isp_osinfo.lun_hash[hfx]; 795d81ba9d5SMatt Jacob if (pw == NULL) { 796d81ba9d5SMatt Jacob return; 797a1bc34c6SMatt Jacob } else if (pw->lun == tptr->lun && pw->bus == tptr->bus) { 798a1bc34c6SMatt Jacob isp->isp_osinfo.lun_hash[hfx] = pw->next; 799d81ba9d5SMatt Jacob } else { 800d81ba9d5SMatt Jacob lw = pw; 801d81ba9d5SMatt Jacob pw = lw->next; 802d81ba9d5SMatt Jacob while (pw) { 803a1bc34c6SMatt Jacob if (pw->lun == tptr->lun && pw->bus == tptr->bus) { 804d81ba9d5SMatt Jacob lw->next = pw->next; 805d81ba9d5SMatt Jacob break; 806d81ba9d5SMatt Jacob } 807d81ba9d5SMatt Jacob lw = pw; 808d81ba9d5SMatt Jacob pw = pw->next; 809d81ba9d5SMatt Jacob } 810d81ba9d5SMatt Jacob if (pw == NULL) { 811d81ba9d5SMatt Jacob return; 812d81ba9d5SMatt Jacob } 813d81ba9d5SMatt Jacob } 814d81ba9d5SMatt Jacob free(tptr, M_DEVBUF); 815d81ba9d5SMatt Jacob } 816d81ba9d5SMatt Jacob 8175d571944SMatt Jacob /* 81867ff51f1SMatt Jacob * Enable luns. 8195d571944SMatt Jacob */ 82067ff51f1SMatt Jacob static int 8219cd7268eSMatt Jacob isp_en_lun(ispsoftc_t *isp, union ccb *ccb) 822d81ba9d5SMatt Jacob { 823d81ba9d5SMatt Jacob struct ccb_en_lun *cel = &ccb->cel; 824d81ba9d5SMatt Jacob tstate_t *tptr; 8251dae40ebSMatt Jacob uint32_t seq; 826746e9c85SMatt Jacob int bus, cmd, av, wildcard, tm_on; 827d81ba9d5SMatt Jacob lun_id_t lun; 828d81ba9d5SMatt Jacob target_id_t tgt; 829d81ba9d5SMatt Jacob 83067ff51f1SMatt Jacob bus = XS_CHANNEL(ccb); 83167ff51f1SMatt Jacob if (bus > 1) { 83267ff51f1SMatt Jacob xpt_print_path(ccb->ccb_h.path); 83367ff51f1SMatt Jacob printf("illegal bus %d\n", bus); 83467ff51f1SMatt Jacob ccb->ccb_h.status = CAM_PATH_INVALID; 83567ff51f1SMatt Jacob return (-1); 83667ff51f1SMatt Jacob } 837d81ba9d5SMatt Jacob tgt = ccb->ccb_h.target_id; 838d81ba9d5SMatt Jacob lun = ccb->ccb_h.target_lun; 839d81ba9d5SMatt Jacob 84067ff51f1SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 84167ff51f1SMatt Jacob "isp_en_lun: %sabling lun 0x%x on channel %d", 84267ff51f1SMatt Jacob cel->enable? "en" : "dis", lun, bus); 84367ff51f1SMatt Jacob 844d81ba9d5SMatt Jacob 845d6e5500fSMatt Jacob if ((lun != CAM_LUN_WILDCARD) && 846d6e5500fSMatt Jacob (lun < 0 || lun >= (lun_id_t) isp->isp_maxluns)) { 847d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 84867ff51f1SMatt Jacob return (-1); 849d81ba9d5SMatt Jacob } 85064edff94SMatt Jacob 8512ad50ca5SMatt Jacob if (IS_SCSI(isp)) { 852a1bc34c6SMatt Jacob sdparam *sdp = isp->isp_param; 853a1bc34c6SMatt Jacob sdp += bus; 854d81ba9d5SMatt Jacob if (tgt != CAM_TARGET_WILDCARD && 855a1bc34c6SMatt Jacob tgt != sdp->isp_initiator_id) { 856d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_TID_INVALID; 85767ff51f1SMatt Jacob return (-1); 858d81ba9d5SMatt Jacob } 859d81ba9d5SMatt Jacob } else { 860746e9c85SMatt Jacob /* 861746e9c85SMatt Jacob * There's really no point in doing this yet w/o multi-tid 862746e9c85SMatt Jacob * capability. Even then, it's problematic. 863746e9c85SMatt Jacob */ 864746e9c85SMatt Jacob #if 0 865d81ba9d5SMatt Jacob if (tgt != CAM_TARGET_WILDCARD && 866d6e5500fSMatt Jacob tgt != FCPARAM(isp)->isp_iid) { 867d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_TID_INVALID; 86867ff51f1SMatt Jacob return (-1); 869d81ba9d5SMatt Jacob } 870746e9c85SMatt Jacob #endif 87164edff94SMatt Jacob /* 87264edff94SMatt Jacob * This is as a good a place as any to check f/w capabilities. 87364edff94SMatt Jacob */ 87464edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_TMODE) == 0) { 87564edff94SMatt Jacob isp_prt(isp, ISP_LOGERR, 87664edff94SMatt Jacob "firmware does not support target mode"); 87764edff94SMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 87867ff51f1SMatt Jacob return (-1); 87964edff94SMatt Jacob } 88064edff94SMatt Jacob /* 88164edff94SMatt Jacob * XXX: We *could* handle non-SCCLUN f/w, but we'd have to 88264edff94SMatt Jacob * XXX: dorks with our already fragile enable/disable code. 88364edff94SMatt Jacob */ 88464edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) { 88564edff94SMatt Jacob isp_prt(isp, ISP_LOGERR, 88664edff94SMatt Jacob "firmware not SCCLUN capable"); 887746e9c85SMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 88867ff51f1SMatt Jacob return (-1); 88964edff94SMatt Jacob } 890d81ba9d5SMatt Jacob } 891d81ba9d5SMatt Jacob 892d6e5500fSMatt Jacob if (tgt == CAM_TARGET_WILDCARD) { 89364edff94SMatt Jacob if (lun == CAM_LUN_WILDCARD) { 89464edff94SMatt Jacob wildcard = 1; 89564edff94SMatt Jacob } else { 896d6e5500fSMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 89767ff51f1SMatt Jacob return (-1); 898d6e5500fSMatt Jacob } 899126ec864SMatt Jacob } else { 900126ec864SMatt Jacob wildcard = 0; 901126ec864SMatt Jacob } 902b6b6ad2fSMatt Jacob 903746e9c85SMatt Jacob tm_on = (isp->isp_osinfo.tmflags[bus] & TM_TMODE_ENABLED) != 0; 904746e9c85SMatt Jacob 905b6b6ad2fSMatt Jacob /* 906b6b6ad2fSMatt Jacob * Next check to see whether this is a target/lun wildcard action. 90764edff94SMatt Jacob * 90864edff94SMatt Jacob * If so, we know that we can accept commands for luns that haven't 90964edff94SMatt Jacob * been enabled yet and send them upstream. Otherwise, we have to 91064edff94SMatt Jacob * handle them locally (if we see them at all). 911b6b6ad2fSMatt Jacob */ 912126ec864SMatt Jacob 913126ec864SMatt Jacob if (wildcard) { 914a1bc34c6SMatt Jacob tptr = &isp->isp_osinfo.tsdflt[bus]; 915b6b6ad2fSMatt Jacob if (cel->enable) { 91667ff51f1SMatt Jacob if (tm_on) { 917b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; 91867ff51f1SMatt Jacob return (-1); 919b6b6ad2fSMatt Jacob } 920b6b6ad2fSMatt Jacob ccb->ccb_h.status = 921b6b6ad2fSMatt Jacob xpt_create_path(&tptr->owner, NULL, 922b6b6ad2fSMatt Jacob xpt_path_path_id(ccb->ccb_h.path), 923b6b6ad2fSMatt Jacob xpt_path_target_id(ccb->ccb_h.path), 924b6b6ad2fSMatt Jacob xpt_path_lun_id(ccb->ccb_h.path)); 925b6b6ad2fSMatt Jacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 92667ff51f1SMatt Jacob return (-1); 927b6b6ad2fSMatt Jacob } 928b6b6ad2fSMatt Jacob SLIST_INIT(&tptr->atios); 929b6b6ad2fSMatt Jacob SLIST_INIT(&tptr->inots); 93064edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] |= TM_WILDCARD_ENABLED; 931126ec864SMatt Jacob } else { 93267ff51f1SMatt Jacob if (tm_on == 0) { 933126ec864SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 93467ff51f1SMatt Jacob return (-1); 935126ec864SMatt Jacob } 936126ec864SMatt Jacob if (tptr->hold) { 937126ec864SMatt Jacob ccb->ccb_h.status = CAM_SCSI_BUSY; 93867ff51f1SMatt Jacob return (-1); 939126ec864SMatt Jacob } 940126ec864SMatt Jacob xpt_free_path(tptr->owner); 94164edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_WILDCARD_ENABLED; 942126ec864SMatt Jacob } 943126ec864SMatt Jacob } 944126ec864SMatt Jacob 945126ec864SMatt Jacob /* 946126ec864SMatt Jacob * Now check to see whether this bus needs to be 947126ec864SMatt Jacob * enabled/disabled with respect to target mode. 948126ec864SMatt Jacob */ 949126ec864SMatt Jacob av = bus << 31; 950746e9c85SMatt Jacob if (cel->enable && tm_on == 0) { 951a1bc34c6SMatt Jacob av |= ENABLE_TARGET_FLAG; 952b6b6ad2fSMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 953b6b6ad2fSMatt Jacob if (av) { 954b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 955126ec864SMatt Jacob if (wildcard) { 95664edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= 95764edff94SMatt Jacob ~TM_WILDCARD_ENABLED; 958b6b6ad2fSMatt Jacob xpt_free_path(tptr->owner); 9595d571944SMatt Jacob } 96067ff51f1SMatt Jacob return (-1); 961b6b6ad2fSMatt Jacob } 96264edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] |= TM_TMODE_ENABLED; 963126ec864SMatt Jacob isp_prt(isp, ISP_LOGINFO, 964126ec864SMatt Jacob "Target Mode enabled on channel %d", bus); 965746e9c85SMatt Jacob } else if (cel->enable == 0 && tm_on && wildcard) { 966a1bc34c6SMatt Jacob if (are_any_luns_enabled(isp, bus)) { 967b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_SCSI_BUSY; 96867ff51f1SMatt Jacob return (-1); 969b6b6ad2fSMatt Jacob } 970b6b6ad2fSMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 971b6b6ad2fSMatt Jacob if (av) { 972b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 97367ff51f1SMatt Jacob return (-1); 974b6b6ad2fSMatt Jacob } 97564edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED; 976126ec864SMatt Jacob isp_prt(isp, ISP_LOGINFO, 977126ec864SMatt Jacob "Target Mode disabled on channel %d", bus); 978126ec864SMatt Jacob } 979126ec864SMatt Jacob 980126ec864SMatt Jacob if (wildcard) { 98164edff94SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 98267ff51f1SMatt Jacob return (-1); 983b6b6ad2fSMatt Jacob } 984b6b6ad2fSMatt Jacob 98567ff51f1SMatt Jacob /* 98667ff51f1SMatt Jacob * Find an empty slot 98767ff51f1SMatt Jacob */ 98867ff51f1SMatt Jacob for (seq = 0; seq < NLEACT; seq++) { 98967ff51f1SMatt Jacob if (isp->isp_osinfo.leact[seq] == 0) { 99067ff51f1SMatt Jacob break; 99167ff51f1SMatt Jacob } 99267ff51f1SMatt Jacob } 99367ff51f1SMatt Jacob if (seq >= NLEACT) { 99467ff51f1SMatt Jacob ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 99567ff51f1SMatt Jacob return (-1); 99667ff51f1SMatt Jacob 99767ff51f1SMatt Jacob } 99867ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = ccb; 99967ff51f1SMatt Jacob 1000d81ba9d5SMatt Jacob if (cel->enable) { 1001d81ba9d5SMatt Jacob ccb->ccb_h.status = 1002a1bc34c6SMatt Jacob create_lun_state(isp, bus, ccb->ccb_h.path, &tptr); 1003d81ba9d5SMatt Jacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 100467ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 100567ff51f1SMatt Jacob return (-1); 1006d81ba9d5SMatt Jacob } 1007d81ba9d5SMatt Jacob } else { 1008a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, lun); 1009d81ba9d5SMatt Jacob if (tptr == NULL) { 1010d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 101167ff51f1SMatt Jacob return (-1); 1012d81ba9d5SMatt Jacob } 1013d81ba9d5SMatt Jacob } 1014d81ba9d5SMatt Jacob 1015d81ba9d5SMatt Jacob if (cel->enable) { 10165d571944SMatt Jacob int c, n, ulun = lun; 10175d571944SMatt Jacob 10185d571944SMatt Jacob cmd = RQSTYPE_ENABLE_LUN; 10195d571944SMatt Jacob c = DFLT_CMND_CNT; 10205d571944SMatt Jacob n = DFLT_INOT_CNT; 10215d571944SMatt Jacob if (IS_FC(isp) && lun != 0) { 10225d571944SMatt Jacob cmd = RQSTYPE_MODIFY_LUN; 10235d571944SMatt Jacob n = 0; 10245d571944SMatt Jacob /* 10255d571944SMatt Jacob * For SCC firmware, we only deal with setting 10265d571944SMatt Jacob * (enabling or modifying) lun 0. 10275d571944SMatt Jacob */ 10285d571944SMatt Jacob ulun = 0; 10295d571944SMatt Jacob } 103067ff51f1SMatt Jacob if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq+1) == 0) { 103167ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 103267ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_INPROG; 103367ff51f1SMatt Jacob return (seq); 1034d81ba9d5SMatt Jacob } 1035d81ba9d5SMatt Jacob } else { 10365d571944SMatt Jacob int c, n, ulun = lun; 1037d81ba9d5SMatt Jacob 10385d571944SMatt Jacob cmd = -RQSTYPE_MODIFY_LUN; 10395d571944SMatt Jacob c = DFLT_CMND_CNT; 10405d571944SMatt Jacob n = DFLT_INOT_CNT; 10415d571944SMatt Jacob if (IS_FC(isp) && lun != 0) { 10425d571944SMatt Jacob n = 0; 10435d571944SMatt Jacob /* 10445d571944SMatt Jacob * For SCC firmware, we only deal with setting 10455d571944SMatt Jacob * (enabling or modifying) lun 0. 10465d571944SMatt Jacob */ 10475d571944SMatt Jacob ulun = 0; 10485d571944SMatt Jacob } 104967ff51f1SMatt Jacob if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq+1) == 0) { 105067ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 105167ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_INPROG; 105267ff51f1SMatt Jacob return (seq); 1053d81ba9d5SMatt Jacob } 1054d81ba9d5SMatt Jacob } 105567ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 1056d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 105767ff51f1SMatt Jacob printf("isp_lun_cmd failed\n"); 105867ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 105967ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 106067ff51f1SMatt Jacob return (-1); 10615d571944SMatt Jacob } 10625d571944SMatt Jacob 106367ff51f1SMatt Jacob static void 10649cd7268eSMatt Jacob isp_ledone(ispsoftc_t *isp, lun_entry_t *lep) 106567ff51f1SMatt Jacob { 106667ff51f1SMatt Jacob const char lfmt[] = "lun %d now %sabled for target mode on channel %d"; 106767ff51f1SMatt Jacob union ccb *ccb; 10681dae40ebSMatt Jacob uint32_t seq; 106967ff51f1SMatt Jacob tstate_t *tptr; 107067ff51f1SMatt Jacob int av; 107167ff51f1SMatt Jacob struct ccb_en_lun *cel; 1072d81ba9d5SMatt Jacob 107367ff51f1SMatt Jacob seq = lep->le_reserved - 1; 107467ff51f1SMatt Jacob if (seq >= NLEACT) { 10753c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, 107667ff51f1SMatt Jacob "seq out of range (%u) in isp_ledone", seq); 107767ff51f1SMatt Jacob return; 1078d81ba9d5SMatt Jacob } 107967ff51f1SMatt Jacob ccb = isp->isp_osinfo.leact[seq]; 108067ff51f1SMatt Jacob if (ccb == 0) { 108167ff51f1SMatt Jacob isp_prt(isp, ISP_LOGERR, 108267ff51f1SMatt Jacob "no ccb for seq %u in isp_ledone", seq); 108367ff51f1SMatt Jacob return; 108467ff51f1SMatt Jacob } 108567ff51f1SMatt Jacob cel = &ccb->cel; 108667ff51f1SMatt Jacob tptr = get_lun_statep(isp, XS_CHANNEL(ccb), XS_LUN(ccb)); 108767ff51f1SMatt Jacob if (tptr == NULL) { 1088d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 108967ff51f1SMatt Jacob printf("null tptr in isp_ledone\n"); 109067ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 109167ff51f1SMatt Jacob return; 1092d81ba9d5SMatt Jacob } 109367ff51f1SMatt Jacob 109467ff51f1SMatt Jacob if (lep->le_status != LUN_OK) { 109567ff51f1SMatt Jacob xpt_print_path(ccb->ccb_h.path); 109667ff51f1SMatt Jacob printf("ENABLE/MODIFY LUN returned 0x%x\n", lep->le_status); 109767ff51f1SMatt Jacob err: 109867ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 109967ff51f1SMatt Jacob xpt_print_path(ccb->ccb_h.path); 110067ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 110167ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 110267ff51f1SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 110367ff51f1SMatt Jacob xpt_done(ccb); 110467ff51f1SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 110567ff51f1SMatt Jacob return; 110667ff51f1SMatt Jacob } else { 110767ff51f1SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 110867ff51f1SMatt Jacob "isp_ledone: ENABLE/MODIFY done okay"); 110967ff51f1SMatt Jacob } 111067ff51f1SMatt Jacob 111167ff51f1SMatt Jacob 111267ff51f1SMatt Jacob if (cel->enable) { 111367ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 11149cd7268eSMatt Jacob isp_prt(isp, ISP_LOGINFO, lfmt, 111567ff51f1SMatt Jacob XS_LUN(ccb), "en", XS_CHANNEL(ccb)); 111667ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 111767ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 111867ff51f1SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 111967ff51f1SMatt Jacob xpt_done(ccb); 112067ff51f1SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 112167ff51f1SMatt Jacob return; 112267ff51f1SMatt Jacob } 112367ff51f1SMatt Jacob 112467ff51f1SMatt Jacob if (lep->le_header.rqs_entry_type == RQSTYPE_MODIFY_LUN) { 112567ff51f1SMatt Jacob if (isp_lun_cmd(isp, -RQSTYPE_ENABLE_LUN, XS_CHANNEL(ccb), 112667ff51f1SMatt Jacob XS_TGT(ccb), XS_LUN(ccb), 0, 0, seq+1)) { 112767ff51f1SMatt Jacob xpt_print_path(ccb->ccb_h.path); 112867ff51f1SMatt Jacob printf("isp_ledone: isp_lun_cmd failed\n"); 112967ff51f1SMatt Jacob goto err; 113067ff51f1SMatt Jacob } 113167ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 113267ff51f1SMatt Jacob return; 113367ff51f1SMatt Jacob } 113467ff51f1SMatt Jacob 113567ff51f1SMatt Jacob isp_prt(isp, ISP_LOGINFO, lfmt, XS_LUN(ccb), "dis", XS_CHANNEL(ccb)); 113667ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 113767ff51f1SMatt Jacob destroy_lun_state(isp, tptr); 113867ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 113967ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 114067ff51f1SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 114167ff51f1SMatt Jacob xpt_done(ccb); 114267ff51f1SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 114367ff51f1SMatt Jacob if (are_any_luns_enabled(isp, XS_CHANNEL(ccb)) == 0) { 114467ff51f1SMatt Jacob int bus = XS_CHANNEL(ccb); 114567ff51f1SMatt Jacob av = bus << 31; 1146126ec864SMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 1147126ec864SMatt Jacob if (av) { 1148126ec864SMatt Jacob isp_prt(isp, ISP_LOGWARN, 114967ff51f1SMatt Jacob "disable target mode on channel %d failed", bus); 115067ff51f1SMatt Jacob } else { 1151126ec864SMatt Jacob isp_prt(isp, ISP_LOGINFO, 1152126ec864SMatt Jacob "Target Mode disabled on channel %d", bus); 1153126ec864SMatt Jacob } 115467ff51f1SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED; 115567ff51f1SMatt Jacob } 1156126ec864SMatt Jacob } 1157126ec864SMatt Jacob 1158d81ba9d5SMatt Jacob 1159d81ba9d5SMatt Jacob static cam_status 11609cd7268eSMatt Jacob isp_abort_tgt_ccb(ispsoftc_t *isp, union ccb *ccb) 1161d81ba9d5SMatt Jacob { 1162d81ba9d5SMatt Jacob tstate_t *tptr; 1163d81ba9d5SMatt Jacob struct ccb_hdr_slist *lp; 1164d81ba9d5SMatt Jacob struct ccb_hdr *curelm; 1165746e9c85SMatt Jacob int found, *ctr; 1166d81ba9d5SMatt Jacob union ccb *accb = ccb->cab.abort_ccb; 1167d81ba9d5SMatt Jacob 1168746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "aborting ccb %p", accb); 1169d81ba9d5SMatt Jacob if (accb->ccb_h.target_id != CAM_TARGET_WILDCARD) { 1170746e9c85SMatt Jacob int badpath = 0; 1171d81ba9d5SMatt Jacob if (IS_FC(isp) && (accb->ccb_h.target_id != 1172d81ba9d5SMatt Jacob ((fcparam *) isp->isp_param)->isp_loopid)) { 1173746e9c85SMatt Jacob badpath = 1; 1174d81ba9d5SMatt Jacob } else if (IS_SCSI(isp) && (accb->ccb_h.target_id != 1175d81ba9d5SMatt Jacob ((sdparam *) isp->isp_param)->isp_initiator_id)) { 1176746e9c85SMatt Jacob badpath = 1; 1177746e9c85SMatt Jacob } 1178746e9c85SMatt Jacob if (badpath) { 1179746e9c85SMatt Jacob /* 1180746e9c85SMatt Jacob * Being restrictive about target ids is really about 1181746e9c85SMatt Jacob * making sure we're aborting for the right multi-tid 1182746e9c85SMatt Jacob * path. This doesn't really make much sense at present. 1183746e9c85SMatt Jacob */ 1184746e9c85SMatt Jacob #if 0 1185d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 1186746e9c85SMatt Jacob #endif 1187d81ba9d5SMatt Jacob } 1188d81ba9d5SMatt Jacob } 1189a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, XS_CHANNEL(ccb), accb->ccb_h.target_lun); 1190d81ba9d5SMatt Jacob if (tptr == NULL) { 1191746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1192746e9c85SMatt Jacob "isp_abort_tgt_ccb: can't get statep"); 1193d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 1194d81ba9d5SMatt Jacob } 1195d81ba9d5SMatt Jacob if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 1196d81ba9d5SMatt Jacob lp = &tptr->atios; 1197746e9c85SMatt Jacob ctr = &tptr->atio_count; 1198d81ba9d5SMatt Jacob } else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY) { 1199d81ba9d5SMatt Jacob lp = &tptr->inots; 1200746e9c85SMatt Jacob ctr = &tptr->inot_count; 1201d81ba9d5SMatt Jacob } else { 1202d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1203746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1204746e9c85SMatt Jacob "isp_abort_tgt_ccb: bad func %d\n", accb->ccb_h.func_code); 1205d81ba9d5SMatt Jacob return (CAM_UA_ABORT); 1206d81ba9d5SMatt Jacob } 1207d81ba9d5SMatt Jacob curelm = SLIST_FIRST(lp); 1208d81ba9d5SMatt Jacob found = 0; 1209d81ba9d5SMatt Jacob if (curelm == &accb->ccb_h) { 1210d81ba9d5SMatt Jacob found = 1; 1211d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(lp, sim_links.sle); 1212d81ba9d5SMatt Jacob } else { 1213d81ba9d5SMatt Jacob while(curelm != NULL) { 1214d81ba9d5SMatt Jacob struct ccb_hdr *nextelm; 1215d81ba9d5SMatt Jacob 1216d81ba9d5SMatt Jacob nextelm = SLIST_NEXT(curelm, sim_links.sle); 1217d81ba9d5SMatt Jacob if (nextelm == &accb->ccb_h) { 1218d81ba9d5SMatt Jacob found = 1; 1219d81ba9d5SMatt Jacob SLIST_NEXT(curelm, sim_links.sle) = 1220d81ba9d5SMatt Jacob SLIST_NEXT(nextelm, sim_links.sle); 1221d81ba9d5SMatt Jacob break; 1222d81ba9d5SMatt Jacob } 1223d81ba9d5SMatt Jacob curelm = nextelm; 1224d81ba9d5SMatt Jacob } 1225d81ba9d5SMatt Jacob } 1226d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1227d81ba9d5SMatt Jacob if (found) { 1228c1504bc0SMatt Jacob (*ctr)--; 1229d81ba9d5SMatt Jacob accb->ccb_h.status = CAM_REQ_ABORTED; 1230746e9c85SMatt Jacob xpt_done(accb); 1231d81ba9d5SMatt Jacob return (CAM_REQ_CMP); 1232d81ba9d5SMatt Jacob } 1233746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1234746e9c85SMatt Jacob "isp_abort_tgt_ccb: CCB %p not found\n", ccb); 1235d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 1236d81ba9d5SMatt Jacob } 1237d81ba9d5SMatt Jacob 12389cd7268eSMatt Jacob static void 12399cd7268eSMatt Jacob isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb) 1240d81ba9d5SMatt Jacob { 1241d81ba9d5SMatt Jacob void *qe; 124200a8e174SMatt Jacob struct ccb_scsiio *cso = &ccb->csio; 12431dae40ebSMatt Jacob uint16_t *hp, save_handle; 12441dae40ebSMatt Jacob uint16_t nxti, optr; 12451dae40ebSMatt Jacob uint8_t local[QENTRY_LEN]; 1246d81ba9d5SMatt Jacob 1247f48ce188SMatt Jacob 12484fd13c1bSMatt Jacob if (isp_getrqentry(isp, &nxti, &optr, &qe)) { 124992a1e549SMatt Jacob xpt_print_path(ccb->ccb_h.path); 125092a1e549SMatt Jacob printf("Request Queue Overflow in isp_target_start_ctio\n"); 12519cd7268eSMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 12529cd7268eSMatt Jacob goto out; 1253d81ba9d5SMatt Jacob } 125429f76675SMatt Jacob memset(local, 0, QENTRY_LEN); 1255d81ba9d5SMatt Jacob 1256d81ba9d5SMatt Jacob /* 1257d81ba9d5SMatt Jacob * We're either moving data or completing a command here. 1258d81ba9d5SMatt Jacob */ 1259d81ba9d5SMatt Jacob 1260d81ba9d5SMatt Jacob if (IS_FC(isp)) { 126153036e92SMatt Jacob atio_private_data_t *atp; 12624fd13c1bSMatt Jacob ct2_entry_t *cto = (ct2_entry_t *) local; 126300a8e174SMatt Jacob 1264d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; 1265d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_count = 1; 126629f76675SMatt Jacob if (IS_2KLOGIN(isp)) { 126729f76675SMatt Jacob ((ct2e_entry_t *)cto)->ct_iid = cso->init_id; 126829f76675SMatt Jacob } else { 126900a8e174SMatt Jacob cto->ct_iid = cso->init_id; 127029f76675SMatt Jacob if (!(FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN)) { 1271d81ba9d5SMatt Jacob cto->ct_lun = ccb->ccb_h.target_lun; 12722ad50ca5SMatt Jacob } 127329f76675SMatt Jacob } 127453036e92SMatt Jacob 127553036e92SMatt Jacob atp = isp_get_atpd(isp, cso->tag_id); 127653036e92SMatt Jacob if (atp == NULL) { 1277570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGERR, 1278570c7a3fSMatt Jacob "cannot find private data adjunct for tag %x", 127953036e92SMatt Jacob cso->tag_id); 12809cd7268eSMatt Jacob XS_SETERR(ccb, CAM_REQ_CMP_ERR); 12819cd7268eSMatt Jacob goto out; 128253036e92SMatt Jacob } 1283f48ce188SMatt Jacob 128400a8e174SMatt Jacob cto->ct_rxid = cso->tag_id; 128500a8e174SMatt Jacob if (cso->dxfer_len == 0) { 128600a8e174SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA; 1287f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 128800a8e174SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 1289f48ce188SMatt Jacob cto->rsp.m1.ct_scsi_status = cso->scsi_status; 129053036e92SMatt Jacob cto->ct_resid = 129153036e92SMatt Jacob atp->orig_datalen - atp->bytes_xfered; 1292570c7a3fSMatt Jacob if (cto->ct_resid < 0) { 1293570c7a3fSMatt Jacob cto->rsp.m1.ct_scsi_status |= 1294570c7a3fSMatt Jacob CT2_DATA_OVER; 1295570c7a3fSMatt Jacob } else if (cto->ct_resid > 0) { 1296570c7a3fSMatt Jacob cto->rsp.m1.ct_scsi_status |= 1297570c7a3fSMatt Jacob CT2_DATA_UNDER; 1298570c7a3fSMatt Jacob } 1299f48ce188SMatt Jacob } 130000a8e174SMatt Jacob if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) { 130100a8e174SMatt Jacob int m = min(cso->sense_len, MAXRESPLEN); 130229f76675SMatt Jacob memcpy(cto->rsp.m1.ct_resp, 130329f76675SMatt Jacob &cso->sense_data, m); 130400a8e174SMatt Jacob cto->rsp.m1.ct_senselen = m; 130500a8e174SMatt Jacob cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID; 130600a8e174SMatt Jacob } 130700a8e174SMatt Jacob } else { 130800a8e174SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE0; 130900a8e174SMatt Jacob if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 131000a8e174SMatt Jacob cto->ct_flags |= CT2_DATA_IN; 131100a8e174SMatt Jacob } else { 131200a8e174SMatt Jacob cto->ct_flags |= CT2_DATA_OUT; 1313d81ba9d5SMatt Jacob } 1314570c7a3fSMatt Jacob cto->ct_reloff = atp->bytes_xfered; 1315d81ba9d5SMatt Jacob if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 1316d81ba9d5SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 131700a8e174SMatt Jacob cto->rsp.m0.ct_scsi_status = cso->scsi_status; 131853036e92SMatt Jacob cto->ct_resid = 131953036e92SMatt Jacob atp->orig_datalen - 132053036e92SMatt Jacob (atp->bytes_xfered + cso->dxfer_len); 1321570c7a3fSMatt Jacob if (cto->ct_resid < 0) { 1322570c7a3fSMatt Jacob cto->rsp.m0.ct_scsi_status |= 1323570c7a3fSMatt Jacob CT2_DATA_OVER; 1324570c7a3fSMatt Jacob } else if (cto->ct_resid > 0) { 1325570c7a3fSMatt Jacob cto->rsp.m0.ct_scsi_status |= 1326570c7a3fSMatt Jacob CT2_DATA_UNDER; 1327570c7a3fSMatt Jacob } 132853036e92SMatt Jacob } else { 132953036e92SMatt Jacob atp->last_xframt = cso->dxfer_len; 1330d81ba9d5SMatt Jacob } 1331f48ce188SMatt Jacob /* 1332f48ce188SMatt Jacob * If we're sending data and status back together, 1333f48ce188SMatt Jacob * we can't also send back sense data as well. 1334f48ce188SMatt Jacob */ 133500a8e174SMatt Jacob ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 133600a8e174SMatt Jacob } 133753036e92SMatt Jacob 1338290dc24bSMatt Jacob if (cto->ct_flags & CT2_SENDSTATUS) { 133964edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 134053036e92SMatt Jacob "CTIO2[%x] STATUS %x origd %u curd %u resid %u", 134153036e92SMatt Jacob cto->ct_rxid, cso->scsi_status, atp->orig_datalen, 134253036e92SMatt Jacob cso->dxfer_len, cto->ct_resid); 1343a1bc34c6SMatt Jacob cto->ct_flags |= CT2_CCINCR; 1344570c7a3fSMatt Jacob atp->state = ATPD_STATE_LAST_CTIO; 13459cd7268eSMatt Jacob } else { 1346570c7a3fSMatt Jacob atp->state = ATPD_STATE_CTIO; 13479cd7268eSMatt Jacob } 1348a1bc34c6SMatt Jacob cto->ct_timeout = 10; 13495f5aafe1SMatt Jacob hp = &cto->ct_syshandle; 1350d81ba9d5SMatt Jacob } else { 13514fd13c1bSMatt Jacob ct_entry_t *cto = (ct_entry_t *) local; 135200a8e174SMatt Jacob 1353d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 1354d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_count = 1; 135500a8e174SMatt Jacob cto->ct_iid = cso->init_id; 1356a1bc34c6SMatt Jacob cto->ct_iid |= XS_CHANNEL(ccb) << 7; 1357d81ba9d5SMatt Jacob cto->ct_tgt = ccb->ccb_h.target_id; 1358d81ba9d5SMatt Jacob cto->ct_lun = ccb->ccb_h.target_lun; 1359a1bc34c6SMatt Jacob cto->ct_fwhandle = AT_GET_HANDLE(cso->tag_id); 1360a1bc34c6SMatt Jacob if (AT_HAS_TAG(cso->tag_id)) { 13611dae40ebSMatt Jacob cto->ct_tag_val = (uint8_t) AT_GET_TAG(cso->tag_id); 1362f48ce188SMatt Jacob cto->ct_flags |= CT_TQAE; 1363f48ce188SMatt Jacob } 1364f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) { 1365f48ce188SMatt Jacob cto->ct_flags |= CT_NODISC; 1366f48ce188SMatt Jacob } 1367f48ce188SMatt Jacob if (cso->dxfer_len == 0) { 1368d81ba9d5SMatt Jacob cto->ct_flags |= CT_NO_DATA; 136900a8e174SMatt Jacob } else if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 137000a8e174SMatt Jacob cto->ct_flags |= CT_DATA_IN; 137100a8e174SMatt Jacob } else { 137200a8e174SMatt Jacob cto->ct_flags |= CT_DATA_OUT; 1373d81ba9d5SMatt Jacob } 1374f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 137553036e92SMatt Jacob cto->ct_flags |= CT_SENDSTATUS|CT_CCINCR; 137600a8e174SMatt Jacob cto->ct_scsi_status = cso->scsi_status; 137700a8e174SMatt Jacob cto->ct_resid = cso->resid; 137864edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1379a1bc34c6SMatt Jacob "CTIO[%x] SCSI STATUS 0x%x resid %d tag_id %x", 1380a1bc34c6SMatt Jacob cto->ct_fwhandle, cso->scsi_status, cso->resid, 1381a1bc34c6SMatt Jacob cso->tag_id); 138292a1e549SMatt Jacob } 138364edff94SMatt Jacob ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 1384a1bc34c6SMatt Jacob cto->ct_timeout = 10; 13855f5aafe1SMatt Jacob hp = &cto->ct_syshandle; 1386d81ba9d5SMatt Jacob } 1387d81ba9d5SMatt Jacob 138851e23558SNate Lawson if (isp_save_xs_tgt(isp, ccb, hp)) { 138992a1e549SMatt Jacob xpt_print_path(ccb->ccb_h.path); 139092a1e549SMatt Jacob printf("No XFLIST pointers for isp_target_start_ctio\n"); 13919cd7268eSMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 13929cd7268eSMatt Jacob goto out; 1393d81ba9d5SMatt Jacob } 1394d81ba9d5SMatt Jacob 1395d81ba9d5SMatt Jacob 1396d81ba9d5SMatt Jacob /* 1397d81ba9d5SMatt Jacob * Call the dma setup routines for this entry (and any subsequent 1398d81ba9d5SMatt Jacob * CTIOs) if there's data to move, and then tell the f/w it's got 1399b09b0095SMatt Jacob * new things to play with. As with isp_start's usage of DMA setup, 1400d81ba9d5SMatt Jacob * any swizzling is done in the machine dependent layer. Because 1401d81ba9d5SMatt Jacob * of this, we put the request onto the queue area first in native 1402d81ba9d5SMatt Jacob * format. 1403d81ba9d5SMatt Jacob */ 1404d81ba9d5SMatt Jacob 1405d81ba9d5SMatt Jacob save_handle = *hp; 1406a1bc34c6SMatt Jacob 14074fd13c1bSMatt Jacob switch (ISP_DMASETUP(isp, cso, (ispreq_t *) local, &nxti, optr)) { 1408d81ba9d5SMatt Jacob case CMD_QUEUED: 14094fd13c1bSMatt Jacob ISP_ADD_REQUEST(isp, nxti); 14109cd7268eSMatt Jacob ccb->ccb_h.status |= CAM_SIM_QUEUED; 14119cd7268eSMatt Jacob return; 1412d81ba9d5SMatt Jacob 1413d81ba9d5SMatt Jacob case CMD_EAGAIN: 14149cd7268eSMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 14159cd7268eSMatt Jacob break; 1416d81ba9d5SMatt Jacob 1417d81ba9d5SMatt Jacob default: 14189cd7268eSMatt Jacob break; 1419d81ba9d5SMatt Jacob } 14209cd7268eSMatt Jacob isp_destroy_tgt_handle(isp, save_handle); 14219cd7268eSMatt Jacob 14229cd7268eSMatt Jacob out: 14239cd7268eSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 14249cd7268eSMatt Jacob xpt_done(ccb); 14259cd7268eSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 1426d81ba9d5SMatt Jacob } 1427d81ba9d5SMatt Jacob 1428a1bc34c6SMatt Jacob static void 1429a1bc34c6SMatt Jacob isp_refire_putback_atio(void *arg) 1430f48ce188SMatt Jacob { 1431a1bc34c6SMatt Jacob int s = splcam(); 1432a1bc34c6SMatt Jacob isp_target_putback_atio(arg); 1433a1bc34c6SMatt Jacob splx(s); 1434a1bc34c6SMatt Jacob } 1435a1bc34c6SMatt Jacob 1436a1bc34c6SMatt Jacob static void 1437a1bc34c6SMatt Jacob isp_target_putback_atio(union ccb *ccb) 1438a1bc34c6SMatt Jacob { 14399cd7268eSMatt Jacob ispsoftc_t *isp; 1440a1bc34c6SMatt Jacob struct ccb_scsiio *cso; 14411dae40ebSMatt Jacob uint16_t nxti, optr; 1442a1bc34c6SMatt Jacob void *qe; 1443a1bc34c6SMatt Jacob 1444a1bc34c6SMatt Jacob isp = XS_ISP(ccb); 1445f48ce188SMatt Jacob 14464fd13c1bSMatt Jacob if (isp_getrqentry(isp, &nxti, &optr, &qe)) { 1447a1bc34c6SMatt Jacob (void) timeout(isp_refire_putback_atio, ccb, 10); 1448a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGWARN, 1449a1bc34c6SMatt Jacob "isp_target_putback_atio: Request Queue Overflow"); 1450a1bc34c6SMatt Jacob return; 1451f48ce188SMatt Jacob } 145229f76675SMatt Jacob memset(qe, 0, QENTRY_LEN); 1453a1bc34c6SMatt Jacob cso = &ccb->csio; 1454f48ce188SMatt Jacob if (IS_FC(isp)) { 14554fd13c1bSMatt Jacob at2_entry_t local, *at = &local; 14564fd13c1bSMatt Jacob MEMZERO(at, sizeof (at2_entry_t)); 1457f48ce188SMatt Jacob at->at_header.rqs_entry_type = RQSTYPE_ATIO2; 1458f48ce188SMatt Jacob at->at_header.rqs_entry_count = 1; 145964edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) != 0) { 1460a1bc34c6SMatt Jacob at->at_scclun = (uint16_t) ccb->ccb_h.target_lun; 1461f48ce188SMatt Jacob } else { 1462a1bc34c6SMatt Jacob at->at_lun = (uint8_t) ccb->ccb_h.target_lun; 1463f48ce188SMatt Jacob } 1464f48ce188SMatt Jacob at->at_status = CT_OK; 1465a1bc34c6SMatt Jacob at->at_rxid = cso->tag_id; 1466570c7a3fSMatt Jacob at->at_iid = cso->ccb_h.target_id; 14674fd13c1bSMatt Jacob isp_put_atio2(isp, at, qe); 1468f48ce188SMatt Jacob } else { 14694fd13c1bSMatt Jacob at_entry_t local, *at = &local; 14704fd13c1bSMatt Jacob MEMZERO(at, sizeof (at_entry_t)); 1471f48ce188SMatt Jacob at->at_header.rqs_entry_type = RQSTYPE_ATIO; 1472f48ce188SMatt Jacob at->at_header.rqs_entry_count = 1; 1473a1bc34c6SMatt Jacob at->at_iid = cso->init_id; 1474a1bc34c6SMatt Jacob at->at_iid |= XS_CHANNEL(ccb) << 7; 1475a1bc34c6SMatt Jacob at->at_tgt = cso->ccb_h.target_id; 1476a1bc34c6SMatt Jacob at->at_lun = cso->ccb_h.target_lun; 1477f48ce188SMatt Jacob at->at_status = CT_OK; 1478a1bc34c6SMatt Jacob at->at_tag_val = AT_GET_TAG(cso->tag_id); 1479a1bc34c6SMatt Jacob at->at_handle = AT_GET_HANDLE(cso->tag_id); 14804fd13c1bSMatt Jacob isp_put_atio(isp, at, qe); 1481f48ce188SMatt Jacob } 1482f48ce188SMatt Jacob ISP_TDQE(isp, "isp_target_putback_atio", (int) optr, qe); 14834fd13c1bSMatt Jacob ISP_ADD_REQUEST(isp, nxti); 1484a1bc34c6SMatt Jacob isp_complete_ctio(ccb); 1485f48ce188SMatt Jacob } 1486f48ce188SMatt Jacob 1487f48ce188SMatt Jacob static void 1488a1bc34c6SMatt Jacob isp_complete_ctio(union ccb *ccb) 1489f48ce188SMatt Jacob { 14909cd7268eSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1491a1bc34c6SMatt Jacob if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { 1492a1bc34c6SMatt Jacob ccb->ccb_h.status |= CAM_REQ_CMP; 1493f48ce188SMatt Jacob } 1494a1bc34c6SMatt Jacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1495a1bc34c6SMatt Jacob xpt_done(ccb); 14969cd7268eSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 1497f48ce188SMatt Jacob } 1498f48ce188SMatt Jacob 1499d81ba9d5SMatt Jacob /* 1500d81ba9d5SMatt Jacob * Handle ATIO stuff that the generic code can't. 1501d81ba9d5SMatt Jacob * This means handling CDBs. 1502d81ba9d5SMatt Jacob */ 1503d81ba9d5SMatt Jacob 1504d81ba9d5SMatt Jacob static int 15059cd7268eSMatt Jacob isp_handle_platform_atio(ispsoftc_t *isp, at_entry_t *aep) 1506d81ba9d5SMatt Jacob { 1507d81ba9d5SMatt Jacob tstate_t *tptr; 150864edff94SMatt Jacob int status, bus, iswildcard; 1509d81ba9d5SMatt Jacob struct ccb_accept_tio *atiop; 1510d81ba9d5SMatt Jacob 1511d81ba9d5SMatt Jacob /* 1512d81ba9d5SMatt Jacob * The firmware status (except for the QLTM_SVALID bit) 1513d81ba9d5SMatt Jacob * indicates why this ATIO was sent to us. 1514d81ba9d5SMatt Jacob * 1515d81ba9d5SMatt Jacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 1516d81ba9d5SMatt Jacob * 1517d81ba9d5SMatt Jacob * If the DISCONNECTS DISABLED bit is set in the flags field, 15185d571944SMatt Jacob * we're still connected on the SCSI bus. 1519d81ba9d5SMatt Jacob */ 1520d81ba9d5SMatt Jacob status = aep->at_status; 1521d81ba9d5SMatt Jacob if ((status & ~QLTM_SVALID) == AT_PHASE_ERROR) { 1522d81ba9d5SMatt Jacob /* 1523d81ba9d5SMatt Jacob * Bus Phase Sequence error. We should have sense data 1524d81ba9d5SMatt Jacob * suggested by the f/w. I'm not sure quite yet what 1525d81ba9d5SMatt Jacob * to do about this for CAM. 1526d81ba9d5SMatt Jacob */ 15273c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, "PHASE ERROR"); 1528d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1529d81ba9d5SMatt Jacob return (0); 1530d81ba9d5SMatt Jacob } 1531d81ba9d5SMatt Jacob if ((status & ~QLTM_SVALID) != AT_CDB) { 15325d571944SMatt Jacob isp_prt(isp, ISP_LOGWARN, "bad atio (0x%x) leaked to platform", 15333c75bb14SMatt Jacob status); 1534d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1535d81ba9d5SMatt Jacob return (0); 1536d81ba9d5SMatt Jacob } 1537d81ba9d5SMatt Jacob 15385d571944SMatt Jacob bus = GET_BUS_VAL(aep->at_iid); 1539a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, aep->at_lun); 1540d81ba9d5SMatt Jacob if (tptr == NULL) { 1541a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD); 1542746e9c85SMatt Jacob if (tptr == NULL) { 1543d81ba9d5SMatt Jacob /* 1544d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1545d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1546d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a BUSY status 1547d81ba9d5SMatt Jacob * instead. This works out okay because the only 1548d81ba9d5SMatt Jacob * time we should, in fact, get this, is in the 1549d81ba9d5SMatt Jacob * case that somebody configured us without the 1550d81ba9d5SMatt Jacob * blackhole driver, so they get what they deserve. 1551d81ba9d5SMatt Jacob */ 1552d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1553d81ba9d5SMatt Jacob return (0); 1554d81ba9d5SMatt Jacob } 15558c4e89e2SMatt Jacob iswildcard = 1; 15568c4e89e2SMatt Jacob } else { 15578c4e89e2SMatt Jacob iswildcard = 0; 15588c4e89e2SMatt Jacob } 1559d81ba9d5SMatt Jacob 1560d81ba9d5SMatt Jacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 1561d81ba9d5SMatt Jacob if (atiop == NULL) { 1562d81ba9d5SMatt Jacob /* 1563d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1564d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1565d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a QUEUE FULL status 1566d81ba9d5SMatt Jacob * instead. This works out okay because the only time we 1567d81ba9d5SMatt Jacob * should, in fact, get this, is in the case that we've 1568d81ba9d5SMatt Jacob * run out of ATIOS. 1569d81ba9d5SMatt Jacob */ 1570d81ba9d5SMatt Jacob xpt_print_path(tptr->owner); 15713c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 1572a1bc34c6SMatt Jacob "no ATIOS for lun %d from initiator %d on channel %d", 15735d571944SMatt Jacob aep->at_lun, GET_IID_VAL(aep->at_iid), bus); 1574d81ba9d5SMatt Jacob if (aep->at_flags & AT_TQAE) 1575d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); 1576d81ba9d5SMatt Jacob else 1577d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 157864edff94SMatt Jacob rls_lun_statep(isp, tptr); 1579d81ba9d5SMatt Jacob return (0); 1580d81ba9d5SMatt Jacob } 1581d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 1582746e9c85SMatt Jacob tptr->atio_count--; 1583746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO lun %d, count now %d", 1584746e9c85SMatt Jacob aep->at_lun, tptr->atio_count); 158564edff94SMatt Jacob if (iswildcard) { 1586d81ba9d5SMatt Jacob atiop->ccb_h.target_id = aep->at_tgt; 1587d81ba9d5SMatt Jacob atiop->ccb_h.target_lun = aep->at_lun; 1588d81ba9d5SMatt Jacob } 1589d81ba9d5SMatt Jacob if (aep->at_flags & AT_NODISC) { 1590f48ce188SMatt Jacob atiop->ccb_h.flags = CAM_DIS_DISCONNECT; 1591f48ce188SMatt Jacob } else { 1592f48ce188SMatt Jacob atiop->ccb_h.flags = 0; 1593d81ba9d5SMatt Jacob } 1594d81ba9d5SMatt Jacob 1595f48ce188SMatt Jacob if (status & QLTM_SVALID) { 1596f48ce188SMatt Jacob size_t amt = imin(QLTM_SENSELEN, sizeof (atiop->sense_data)); 1597f48ce188SMatt Jacob atiop->sense_len = amt; 1598f48ce188SMatt Jacob MEMCPY(&atiop->sense_data, aep->at_sense, amt); 1599f48ce188SMatt Jacob } else { 1600f48ce188SMatt Jacob atiop->sense_len = 0; 1601f48ce188SMatt Jacob } 1602d81ba9d5SMatt Jacob 16035d571944SMatt Jacob atiop->init_id = GET_IID_VAL(aep->at_iid); 1604d81ba9d5SMatt Jacob atiop->cdb_len = aep->at_cdblen; 1605d81ba9d5SMatt Jacob MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen); 1606d81ba9d5SMatt Jacob atiop->ccb_h.status = CAM_CDB_RECVD; 1607a1bc34c6SMatt Jacob /* 1608a1bc34c6SMatt Jacob * Construct a tag 'id' based upon tag value (which may be 0..255) 1609a1bc34c6SMatt Jacob * and the handle (which we have to preserve). 1610a1bc34c6SMatt Jacob */ 16119f242f78SMatt Jacob AT_MAKE_TAGID(atiop->tag_id, device_get_unit(isp->isp_dev), aep); 1612a1bc34c6SMatt Jacob if (aep->at_flags & AT_TQAE) { 1613a1bc34c6SMatt Jacob atiop->tag_action = aep->at_tag_type; 1614d81ba9d5SMatt Jacob atiop->ccb_h.status |= CAM_TAG_ACTION_VALID; 1615d81ba9d5SMatt Jacob } 1616d81ba9d5SMatt Jacob xpt_done((union ccb*)atiop); 161764edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 16185d571944SMatt Jacob "ATIO[%x] CDB=0x%x bus %d iid%d->lun%d tag 0x%x ttype 0x%x %s", 16195d571944SMatt Jacob aep->at_handle, aep->at_cdb[0] & 0xff, GET_BUS_VAL(aep->at_iid), 16205d571944SMatt Jacob GET_IID_VAL(aep->at_iid), aep->at_lun, aep->at_tag_val & 0xff, 16215d571944SMatt Jacob aep->at_tag_type, (aep->at_flags & AT_NODISC)? 16225d571944SMatt Jacob "nondisc" : "disconnecting"); 1623d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1624d81ba9d5SMatt Jacob return (0); 1625d81ba9d5SMatt Jacob } 1626d81ba9d5SMatt Jacob 1627d81ba9d5SMatt Jacob static int 16289cd7268eSMatt Jacob isp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep) 1629d81ba9d5SMatt Jacob { 163092a1e549SMatt Jacob lun_id_t lun; 1631d81ba9d5SMatt Jacob tstate_t *tptr; 1632d81ba9d5SMatt Jacob struct ccb_accept_tio *atiop; 163353036e92SMatt Jacob atio_private_data_t *atp; 1634d81ba9d5SMatt Jacob 1635d81ba9d5SMatt Jacob /* 1636d81ba9d5SMatt Jacob * The firmware status (except for the QLTM_SVALID bit) 1637d81ba9d5SMatt Jacob * indicates why this ATIO was sent to us. 1638d81ba9d5SMatt Jacob * 1639d81ba9d5SMatt Jacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 1640d81ba9d5SMatt Jacob */ 1641d81ba9d5SMatt Jacob if ((aep->at_status & ~QLTM_SVALID) != AT_CDB) { 16423c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 16433c75bb14SMatt Jacob "bogus atio (0x%x) leaked to platform", aep->at_status); 1644d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1645d81ba9d5SMatt Jacob return (0); 1646d81ba9d5SMatt Jacob } 1647d81ba9d5SMatt Jacob 164864edff94SMatt Jacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) != 0) { 164992a1e549SMatt Jacob lun = aep->at_scclun; 16502ad50ca5SMatt Jacob } else { 165192a1e549SMatt Jacob lun = aep->at_lun; 16522ad50ca5SMatt Jacob } 1653a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, 0, lun); 1654d81ba9d5SMatt Jacob if (tptr == NULL) { 1655746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1656746e9c85SMatt Jacob "[0x%x] no state pointer for lun %d", aep->at_rxid, lun); 1657a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD); 1658746e9c85SMatt Jacob if (tptr == NULL) { 1659746e9c85SMatt Jacob isp_endcmd(isp, aep, 1660746e9c85SMatt Jacob SCSI_STATUS_CHECK_COND | ECMD_SVALID | 1661746e9c85SMatt Jacob (0x5 << 12) | (0x25 << 16), 0); 1662746e9c85SMatt Jacob return (0); 1663746e9c85SMatt Jacob } 1664d81ba9d5SMatt Jacob } 1665d81ba9d5SMatt Jacob 166653036e92SMatt Jacob atp = isp_get_atpd(isp, 0); 1667d81ba9d5SMatt Jacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 166853036e92SMatt Jacob if (atiop == NULL || atp == NULL) { 1669746e9c85SMatt Jacob 1670d81ba9d5SMatt Jacob /* 1671d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1672d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1673d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a QUEUE FULL status 1674d81ba9d5SMatt Jacob * instead. This works out okay because the only time we 1675d81ba9d5SMatt Jacob * should, in fact, get this, is in the case that we've 1676d81ba9d5SMatt Jacob * run out of ATIOS. 1677d81ba9d5SMatt Jacob */ 1678d81ba9d5SMatt Jacob xpt_print_path(tptr->owner); 16793c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 1680570c7a3fSMatt Jacob "no %s for lun %d from initiator %d", 1681570c7a3fSMatt Jacob (atp == NULL && atiop == NULL)? "ATIO2s *or* ATPS" : 1682570c7a3fSMatt Jacob ((atp == NULL)? "ATPs" : "ATIO2s"), lun, aep->at_iid); 1683d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1684d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); 1685d81ba9d5SMatt Jacob return (0); 1686d81ba9d5SMatt Jacob } 1687570c7a3fSMatt Jacob atp->state = ATPD_STATE_ATIO; 1688d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 1689570c7a3fSMatt Jacob tptr->atio_count--; 1690746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO lun %d, count now %d", 1691570c7a3fSMatt Jacob lun, tptr->atio_count); 1692f48ce188SMatt Jacob 1693a1bc34c6SMatt Jacob if (tptr == &isp->isp_osinfo.tsdflt[0]) { 1694d81ba9d5SMatt Jacob atiop->ccb_h.target_id = 1695d81ba9d5SMatt Jacob ((fcparam *)isp->isp_param)->isp_loopid; 169692a1e549SMatt Jacob atiop->ccb_h.target_lun = lun; 1697d81ba9d5SMatt Jacob } 1698b0a3ba7eSMatt Jacob /* 1699b0a3ba7eSMatt Jacob * We don't get 'suggested' sense data as we do with SCSI cards. 1700b0a3ba7eSMatt Jacob */ 1701f48ce188SMatt Jacob atiop->sense_len = 0; 1702f48ce188SMatt Jacob 1703d81ba9d5SMatt Jacob atiop->init_id = aep->at_iid; 1704d81ba9d5SMatt Jacob atiop->cdb_len = ATIO2_CDBLEN; 1705d81ba9d5SMatt Jacob MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, ATIO2_CDBLEN); 1706d81ba9d5SMatt Jacob atiop->ccb_h.status = CAM_CDB_RECVD; 1707d81ba9d5SMatt Jacob atiop->tag_id = aep->at_rxid; 1708d81ba9d5SMatt Jacob switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) { 1709d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_SIMPLEQ: 1710d81ba9d5SMatt Jacob atiop->tag_action = MSG_SIMPLE_Q_TAG; 1711d81ba9d5SMatt Jacob break; 1712d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_HEADOFQ: 1713d81ba9d5SMatt Jacob atiop->tag_action = MSG_HEAD_OF_Q_TAG; 1714d81ba9d5SMatt Jacob break; 1715d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_ORDERED: 1716d81ba9d5SMatt Jacob atiop->tag_action = MSG_ORDERED_Q_TAG; 1717d81ba9d5SMatt Jacob break; 1718d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_ACAQ: /* ?? */ 1719d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_UNTAGGED: 1720d81ba9d5SMatt Jacob default: 1721d81ba9d5SMatt Jacob atiop->tag_action = 0; 1722d81ba9d5SMatt Jacob break; 1723d81ba9d5SMatt Jacob } 1724570c7a3fSMatt Jacob atiop->ccb_h.flags = CAM_TAG_ACTION_VALID; 1725f48ce188SMatt Jacob 172653036e92SMatt Jacob atp->tag = atiop->tag_id; 1727570c7a3fSMatt Jacob atp->lun = lun; 172853036e92SMatt Jacob atp->orig_datalen = aep->at_datalen; 172953036e92SMatt Jacob atp->last_xframt = 0; 173053036e92SMatt Jacob atp->bytes_xfered = 0; 1731570c7a3fSMatt Jacob atp->state = ATPD_STATE_CAM; 173267ff51f1SMatt Jacob ISPLOCK_2_CAMLOCK(siP); 1733d81ba9d5SMatt Jacob xpt_done((union ccb*)atiop); 1734570c7a3fSMatt Jacob 173564edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 17365f5aafe1SMatt Jacob "ATIO2[%x] CDB=0x%x iid%d->lun%d tattr 0x%x datalen %u", 17375f5aafe1SMatt Jacob aep->at_rxid, aep->at_cdb[0] & 0xff, aep->at_iid, 1738b09b0095SMatt Jacob lun, aep->at_taskflags, aep->at_datalen); 1739d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1740d81ba9d5SMatt Jacob return (0); 1741d81ba9d5SMatt Jacob } 1742d81ba9d5SMatt Jacob 1743d81ba9d5SMatt Jacob static int 17449cd7268eSMatt Jacob isp_handle_platform_ctio(ispsoftc_t *isp, void *arg) 1745d81ba9d5SMatt Jacob { 1746d81ba9d5SMatt Jacob union ccb *ccb; 1747a1bc34c6SMatt Jacob int sentstatus, ok, notify_cam, resid = 0; 17481dae40ebSMatt Jacob uint16_t tval; 1749d81ba9d5SMatt Jacob 1750d81ba9d5SMatt Jacob /* 1751d81ba9d5SMatt Jacob * CTIO and CTIO2 are close enough.... 1752d81ba9d5SMatt Jacob */ 1753d81ba9d5SMatt Jacob 175451e23558SNate Lawson ccb = isp_find_xs_tgt(isp, ((ct_entry_t *)arg)->ct_syshandle); 1755d81ba9d5SMatt Jacob KASSERT((ccb != NULL), ("null ccb in isp_handle_platform_ctio")); 175651e23558SNate Lawson isp_destroy_tgt_handle(isp, ((ct_entry_t *)arg)->ct_syshandle); 1757d81ba9d5SMatt Jacob 1758d81ba9d5SMatt Jacob if (IS_FC(isp)) { 1759d81ba9d5SMatt Jacob ct2_entry_t *ct = arg; 1760570c7a3fSMatt Jacob atio_private_data_t *atp = isp_get_atpd(isp, ct->ct_rxid); 1761570c7a3fSMatt Jacob if (atp == NULL) { 1762570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGERR, 1763570c7a3fSMatt Jacob "cannot find adjunct for %x after I/O", 1764570c7a3fSMatt Jacob ct->ct_rxid); 1765570c7a3fSMatt Jacob return (0); 1766570c7a3fSMatt Jacob } 1767d81ba9d5SMatt Jacob sentstatus = ct->ct_flags & CT2_SENDSTATUS; 1768d81ba9d5SMatt Jacob ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; 1769a1bc34c6SMatt Jacob if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) { 177000a8e174SMatt Jacob ccb->ccb_h.status |= CAM_SENT_SENSE; 177100a8e174SMatt Jacob } 1772a1bc34c6SMatt Jacob notify_cam = ct->ct_header.rqs_seqno & 0x1; 17735d571944SMatt Jacob if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) { 1774a1bc34c6SMatt Jacob resid = ct->ct_resid; 177553036e92SMatt Jacob atp->bytes_xfered += (atp->last_xframt - resid); 177653036e92SMatt Jacob atp->last_xframt = 0; 1777570c7a3fSMatt Jacob } 1778570c7a3fSMatt Jacob if (sentstatus || !ok) { 177953036e92SMatt Jacob atp->tag = 0; 178053036e92SMatt Jacob } 1781570c7a3fSMatt Jacob isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, 178264edff94SMatt Jacob "CTIO2[%x] sts 0x%x flg 0x%x sns %d resid %d %s", 178364edff94SMatt Jacob ct->ct_rxid, ct->ct_status, ct->ct_flags, 178464edff94SMatt Jacob (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, 178564edff94SMatt Jacob resid, sentstatus? "FIN" : "MID"); 178664edff94SMatt Jacob tval = ct->ct_rxid; 1787570c7a3fSMatt Jacob 1788570c7a3fSMatt Jacob /* XXX: should really come after isp_complete_ctio */ 1789570c7a3fSMatt Jacob atp->state = ATPD_STATE_PDON; 1790d81ba9d5SMatt Jacob } else { 1791d81ba9d5SMatt Jacob ct_entry_t *ct = arg; 1792d81ba9d5SMatt Jacob sentstatus = ct->ct_flags & CT_SENDSTATUS; 1793d81ba9d5SMatt Jacob ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; 1794d81ba9d5SMatt Jacob /* 1795a1bc34c6SMatt Jacob * We *ought* to be able to get back to the original ATIO 1796a1bc34c6SMatt Jacob * here, but for some reason this gets lost. It's just as 1797a1bc34c6SMatt Jacob * well because it's squirrelled away as part of periph 1798a1bc34c6SMatt Jacob * private data. 1799a1bc34c6SMatt Jacob * 1800a1bc34c6SMatt Jacob * We can live without it as long as we continue to use 1801a1bc34c6SMatt Jacob * the auto-replenish feature for CTIOs. 1802a1bc34c6SMatt Jacob */ 1803a1bc34c6SMatt Jacob notify_cam = ct->ct_header.rqs_seqno & 0x1; 1804a1bc34c6SMatt Jacob if (ct->ct_status & QLTM_SVALID) { 1805a1bc34c6SMatt Jacob char *sp = (char *)ct; 1806a1bc34c6SMatt Jacob sp += CTIO_SENSE_OFFSET; 1807a1bc34c6SMatt Jacob ccb->csio.sense_len = 1808a1bc34c6SMatt Jacob min(sizeof (ccb->csio.sense_data), QLTM_SENSELEN); 1809a1bc34c6SMatt Jacob MEMCPY(&ccb->csio.sense_data, sp, ccb->csio.sense_len); 1810a1bc34c6SMatt Jacob ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 1811a1bc34c6SMatt Jacob } 18125d571944SMatt Jacob if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) { 1813a1bc34c6SMatt Jacob resid = ct->ct_resid; 1814a1bc34c6SMatt Jacob } 181564edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 181664edff94SMatt Jacob "CTIO[%x] tag %x iid %d lun %d sts %x flg %x resid %d %s", 181764edff94SMatt Jacob ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_lun, 181864edff94SMatt Jacob ct->ct_status, ct->ct_flags, resid, 181964edff94SMatt Jacob sentstatus? "FIN" : "MID"); 182064edff94SMatt Jacob tval = ct->ct_fwhandle; 18215d571944SMatt Jacob } 1822a1bc34c6SMatt Jacob ccb->csio.resid += resid; 1823a1bc34c6SMatt Jacob 1824a1bc34c6SMatt Jacob /* 1825a1bc34c6SMatt Jacob * We're here either because intermediate data transfers are done 1826a1bc34c6SMatt Jacob * and/or the final status CTIO (which may have joined with a 1827a1bc34c6SMatt Jacob * Data Transfer) is done. 1828d81ba9d5SMatt Jacob * 1829d81ba9d5SMatt Jacob * In any case, for this platform, the upper layers figure out 1830d81ba9d5SMatt Jacob * what to do next, so all we do here is collect status and 1831a1bc34c6SMatt Jacob * pass information along. Any DMA handles have already been 1832a1bc34c6SMatt Jacob * freed. 1833d81ba9d5SMatt Jacob */ 1834f48ce188SMatt Jacob if (notify_cam == 0) { 183564edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, " INTER CTIO[0x%x] done", tval); 1836f48ce188SMatt Jacob return (0); 1837f48ce188SMatt Jacob } 1838d81ba9d5SMatt Jacob 183953036e92SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO[0x%x] done", 184053036e92SMatt Jacob (sentstatus)? " FINAL " : "MIDTERM ", tval); 1841a1bc34c6SMatt Jacob 1842a1bc34c6SMatt Jacob if (!ok) { 1843a1bc34c6SMatt Jacob isp_target_putback_atio(ccb); 1844d81ba9d5SMatt Jacob } else { 1845a1bc34c6SMatt Jacob isp_complete_ctio(ccb); 1846a1bc34c6SMatt Jacob 1847d81ba9d5SMatt Jacob } 1848a1bc34c6SMatt Jacob return (0); 1849d81ba9d5SMatt Jacob } 1850570c7a3fSMatt Jacob 1851570c7a3fSMatt Jacob static int 18529cd7268eSMatt Jacob isp_handle_platform_notify_scsi(ispsoftc_t *isp, in_entry_t *inp) 1853570c7a3fSMatt Jacob { 1854570c7a3fSMatt Jacob return (0); /* XXXX */ 1855570c7a3fSMatt Jacob } 1856570c7a3fSMatt Jacob 1857570c7a3fSMatt Jacob static int 18589cd7268eSMatt Jacob isp_handle_platform_notify_fc(ispsoftc_t *isp, in_fcentry_t *inp) 1859570c7a3fSMatt Jacob { 1860570c7a3fSMatt Jacob 1861570c7a3fSMatt Jacob switch (inp->in_status) { 1862570c7a3fSMatt Jacob case IN_PORT_LOGOUT: 1863570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, "port logout of iid %d", 1864570c7a3fSMatt Jacob inp->in_iid); 1865570c7a3fSMatt Jacob break; 1866570c7a3fSMatt Jacob case IN_PORT_CHANGED: 1867570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, "port changed for iid %d", 1868570c7a3fSMatt Jacob inp->in_iid); 1869570c7a3fSMatt Jacob break; 1870570c7a3fSMatt Jacob case IN_GLOBAL_LOGO: 1871570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGINFO, "all ports logged out"); 1872570c7a3fSMatt Jacob break; 1873570c7a3fSMatt Jacob case IN_ABORT_TASK: 1874570c7a3fSMatt Jacob { 1875570c7a3fSMatt Jacob atio_private_data_t *atp = isp_get_atpd(isp, inp->in_seqid); 1876570c7a3fSMatt Jacob struct ccb_immed_notify *inot = NULL; 1877570c7a3fSMatt Jacob 1878570c7a3fSMatt Jacob if (atp) { 1879570c7a3fSMatt Jacob tstate_t *tptr = get_lun_statep(isp, 0, atp->lun); 1880570c7a3fSMatt Jacob if (tptr) { 1881570c7a3fSMatt Jacob inot = (struct ccb_immed_notify *) 1882570c7a3fSMatt Jacob SLIST_FIRST(&tptr->inots); 1883570c7a3fSMatt Jacob if (inot) { 1884746e9c85SMatt Jacob tptr->inot_count--; 1885570c7a3fSMatt Jacob SLIST_REMOVE_HEAD(&tptr->inots, 1886570c7a3fSMatt Jacob sim_links.sle); 1887746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1888746e9c85SMatt Jacob "Take FREE INOT count now %d", 1889746e9c85SMatt Jacob tptr->inot_count); 1890570c7a3fSMatt Jacob } 1891570c7a3fSMatt Jacob } 1892570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, 1893570c7a3fSMatt Jacob "abort task RX_ID %x IID %d state %d", 1894570c7a3fSMatt Jacob inp->in_seqid, inp->in_iid, atp->state); 1895570c7a3fSMatt Jacob } else { 1896570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, 1897570c7a3fSMatt Jacob "abort task RX_ID %x from iid %d, state unknown", 1898570c7a3fSMatt Jacob inp->in_seqid, inp->in_iid); 1899570c7a3fSMatt Jacob } 1900570c7a3fSMatt Jacob if (inot) { 1901570c7a3fSMatt Jacob inot->initiator_id = inp->in_iid; 1902570c7a3fSMatt Jacob inot->sense_len = 0; 1903570c7a3fSMatt Jacob inot->message_args[0] = MSG_ABORT_TAG; 1904570c7a3fSMatt Jacob inot->message_args[1] = inp->in_seqid & 0xff; 1905570c7a3fSMatt Jacob inot->message_args[2] = (inp->in_seqid >> 8) & 0xff; 19066b5ec766SMatt Jacob inot->ccb_h.status = CAM_MESSAGE_RECV; 1907570c7a3fSMatt Jacob xpt_done((union ccb *)inot); 1908570c7a3fSMatt Jacob } 1909570c7a3fSMatt Jacob break; 1910570c7a3fSMatt Jacob } 1911570c7a3fSMatt Jacob default: 1912570c7a3fSMatt Jacob break; 1913570c7a3fSMatt Jacob } 1914570c7a3fSMatt Jacob return (0); 1915570c7a3fSMatt Jacob } 1916d81ba9d5SMatt Jacob #endif 1917d81ba9d5SMatt Jacob 1918478f8a96SJustin T. Gibbs static void 19191dae40ebSMatt Jacob isp_cam_async(void *cbarg, uint32_t code, struct cam_path *path, void *arg) 1920478f8a96SJustin T. Gibbs { 1921478f8a96SJustin T. Gibbs struct cam_sim *sim; 19229cd7268eSMatt Jacob ispsoftc_t *isp; 1923478f8a96SJustin T. Gibbs 1924478f8a96SJustin T. Gibbs sim = (struct cam_sim *)cbarg; 19259cd7268eSMatt Jacob isp = (ispsoftc_t *) cam_sim_softc(sim); 1926478f8a96SJustin T. Gibbs switch (code) { 1927478f8a96SJustin T. Gibbs case AC_LOST_DEVICE: 1928ab6c4b31SMatt Jacob if (IS_SCSI(isp)) { 19291dae40ebSMatt Jacob uint16_t oflags, nflags; 1930478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 1931a1bc34c6SMatt Jacob int tgt; 1932478f8a96SJustin T. Gibbs 1933f9e908dcSMatt Jacob tgt = xpt_path_target_id(path); 193441ed683eSMatt Jacob if (tgt >= 0) { 1935ea6f23cdSMatt Jacob sdp += cam_sim_bus(sim); 193641ed683eSMatt Jacob ISP_LOCK(isp); 19379ce9bdafSMatt Jacob nflags = sdp->isp_devparam[tgt].nvrm_flags; 1938a1bc34c6SMatt Jacob #ifndef ISP_TARGET_MODE 19399ce9bdafSMatt Jacob nflags &= DPARM_SAFE_DFLT; 1940a1bc34c6SMatt Jacob if (isp->isp_loaded_fw) { 1941478f8a96SJustin T. Gibbs nflags |= DPARM_NARROW | DPARM_ASYNC; 1942478f8a96SJustin T. Gibbs } 1943a1bc34c6SMatt Jacob #else 1944a1bc34c6SMatt Jacob nflags = DPARM_DEFAULT; 1945a1bc34c6SMatt Jacob #endif 19469ce9bdafSMatt Jacob oflags = sdp->isp_devparam[tgt].goal_flags; 19479ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_flags = nflags; 1948478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_update = 1; 1949a1bc34c6SMatt Jacob isp->isp_update |= (1 << cam_sim_bus(sim)); 195041ed683eSMatt Jacob (void) isp_control(isp, 195141ed683eSMatt Jacob ISPCTL_UPDATE_PARAMS, NULL); 19529ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_flags = oflags; 1953f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1954478f8a96SJustin T. Gibbs } 195541ed683eSMatt Jacob } 1956478f8a96SJustin T. Gibbs break; 1957478f8a96SJustin T. Gibbs default: 19583c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, "isp_cam_async: Code 0x%x", code); 1959478f8a96SJustin T. Gibbs break; 1960478f8a96SJustin T. Gibbs } 1961478f8a96SJustin T. Gibbs } 1962478f8a96SJustin T. Gibbs 1963478f8a96SJustin T. Gibbs static void 1964c3055363SMatt Jacob isp_poll(struct cam_sim *sim) 1965478f8a96SJustin T. Gibbs { 19669cd7268eSMatt Jacob ispsoftc_t *isp = cam_sim_softc(sim); 19671dae40ebSMatt Jacob uint16_t isr, sema, mbox; 1968126ec864SMatt Jacob 1969c40e096eSMatt Jacob ISP_LOCK(isp); 1970126ec864SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 1971126ec864SMatt Jacob isp_intr(isp, isr, sema, mbox); 1972126ec864SMatt Jacob } 1973c40e096eSMatt Jacob ISP_UNLOCK(isp); 1974478f8a96SJustin T. Gibbs } 1975478f8a96SJustin T. Gibbs 1976ab6c4b31SMatt Jacob 1977478f8a96SJustin T. Gibbs static void 1978b85389e1SMatt Jacob isp_watchdog(void *arg) 1979cc8df88bSMatt Jacob { 1980b09b0095SMatt Jacob XS_T *xs = arg; 19819cd7268eSMatt Jacob ispsoftc_t *isp = XS_ISP(xs); 19821dae40ebSMatt Jacob uint32_t handle; 1983fdeb9f2fSMatt Jacob int iok; 1984b85389e1SMatt Jacob 1985cc8df88bSMatt Jacob /* 1986b85389e1SMatt Jacob * We've decided this command is dead. Make sure we're not trying 1987b85389e1SMatt Jacob * to kill a command that's already dead by getting it's handle and 1988b85389e1SMatt Jacob * and seeing whether it's still alive. 1989cc8df88bSMatt Jacob */ 1990f6e75de2SMatt Jacob ISP_LOCK(isp); 1991fdeb9f2fSMatt Jacob iok = isp->isp_osinfo.intsok; 1992fdeb9f2fSMatt Jacob isp->isp_osinfo.intsok = 0; 1993cc8df88bSMatt Jacob handle = isp_find_handle(isp, xs); 1994cc8df88bSMatt Jacob if (handle) { 19951dae40ebSMatt Jacob uint16_t isr, sema, mbox; 1996126ec864SMatt Jacob 1997b85389e1SMatt Jacob if (XS_CMD_DONE_P(xs)) { 1998b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG1, 1999b09b0095SMatt Jacob "watchdog found done cmd (handle 0x%x)", handle); 2000f6e75de2SMatt Jacob ISP_UNLOCK(isp); 2001b85389e1SMatt Jacob return; 2002b85389e1SMatt Jacob } 2003b85389e1SMatt Jacob 2004b85389e1SMatt Jacob if (XS_CMD_WDOG_P(xs)) { 2005b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2006b09b0095SMatt Jacob "recursive watchdog (handle 0x%x)", handle); 2007f6e75de2SMatt Jacob ISP_UNLOCK(isp); 2008b85389e1SMatt Jacob return; 2009b85389e1SMatt Jacob } 2010b85389e1SMatt Jacob 2011b85389e1SMatt Jacob XS_CMD_S_WDOG(xs); 2012126ec864SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 2013126ec864SMatt Jacob isp_intr(isp, isr, sema, mbox); 2014126ec864SMatt Jacob } 2015126ec864SMatt Jacob if (XS_CMD_DONE_P(xs)) { 2016b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2017126ec864SMatt Jacob "watchdog cleanup for handle 0x%x", handle); 2018b85389e1SMatt Jacob xpt_done((union ccb *) xs); 2019b85389e1SMatt Jacob } else if (XS_CMD_GRACE_P(xs)) { 20201fcf5debSMatt Jacob /* 20211fcf5debSMatt Jacob * Make sure the command is *really* dead before we 20221fcf5debSMatt Jacob * release the handle (and DMA resources) for reuse. 20231fcf5debSMatt Jacob */ 20241fcf5debSMatt Jacob (void) isp_control(isp, ISPCTL_ABORT_CMD, arg); 20251fcf5debSMatt Jacob 20261fcf5debSMatt Jacob /* 20271fcf5debSMatt Jacob * After this point, the comamnd is really dead. 20281fcf5debSMatt Jacob */ 2029f6e75de2SMatt Jacob if (XS_XFRLEN(xs)) { 2030f6e75de2SMatt Jacob ISP_DMAFREE(isp, xs, handle); 2031f6e75de2SMatt Jacob } 2032cc8df88bSMatt Jacob isp_destroy_handle(isp, handle); 2033cc8df88bSMatt Jacob xpt_print_path(xs->ccb_h.path); 20343c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 20352903b272SMatt Jacob "watchdog timeout for handle 0x%x", handle); 2036cc8df88bSMatt Jacob XS_SETERR(xs, CAM_CMD_TIMEOUT); 2037b85389e1SMatt Jacob XS_CMD_C_WDOG(xs); 2038cc8df88bSMatt Jacob isp_done(xs); 2039b85389e1SMatt Jacob } else { 20401dae40ebSMatt Jacob uint16_t nxti, optr; 20414fd13c1bSMatt Jacob ispreq_t local, *mp= &local, *qe; 2042b85389e1SMatt Jacob 2043b85389e1SMatt Jacob XS_CMD_C_WDOG(xs); 2044b85389e1SMatt Jacob xs->ccb_h.timeout_ch = timeout(isp_watchdog, xs, hz); 20454fd13c1bSMatt Jacob if (isp_getrqentry(isp, &nxti, &optr, (void **) &qe)) { 2046f6e75de2SMatt Jacob ISP_UNLOCK(isp); 2047b85389e1SMatt Jacob return; 2048b85389e1SMatt Jacob } 2049b85389e1SMatt Jacob XS_CMD_S_GRACE(xs); 2050b85389e1SMatt Jacob MEMZERO((void *) mp, sizeof (*mp)); 2051b85389e1SMatt Jacob mp->req_header.rqs_entry_count = 1; 2052b85389e1SMatt Jacob mp->req_header.rqs_entry_type = RQSTYPE_MARKER; 2053b85389e1SMatt Jacob mp->req_modifier = SYNC_ALL; 2054b85389e1SMatt Jacob mp->req_target = XS_CHANNEL(xs) << 7; 20554fd13c1bSMatt Jacob isp_put_request(isp, mp, qe); 20564fd13c1bSMatt Jacob ISP_ADD_REQUEST(isp, nxti); 2057b85389e1SMatt Jacob } 2058b85389e1SMatt Jacob } else { 2059b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "watchdog with no command"); 2060cc8df88bSMatt Jacob } 2061fdeb9f2fSMatt Jacob isp->isp_osinfo.intsok = iok; 2062f6e75de2SMatt Jacob ISP_UNLOCK(isp); 2063cc8df88bSMatt Jacob } 2064cc8df88bSMatt Jacob 20655d571944SMatt Jacob static void 20665d571944SMatt Jacob isp_kthread(void *arg) 20675d571944SMatt Jacob { 20689cd7268eSMatt Jacob ispsoftc_t *isp = arg; 20695d571944SMatt Jacob 20709cd7268eSMatt Jacob 20719cd7268eSMatt Jacob #if __FreeBSD_version < 500000 20729cd7268eSMatt Jacob int s; 20739cd7268eSMatt Jacob 20749cd7268eSMatt Jacob s = splcam(); 20759cd7268eSMatt Jacob isp->isp_osinfo.intsok = 1; 20769cd7268eSMatt Jacob #else 2077162e9893SMatt Jacob #ifdef ISP_SMPLOCK 20785d571944SMatt Jacob mtx_lock(&isp->isp_lock); 2079ee76282eSMatt Jacob #else 2080ee76282eSMatt Jacob mtx_lock(&Giant); 2081162e9893SMatt Jacob #endif 20829cd7268eSMatt Jacob #endif 2083fdeb9f2fSMatt Jacob /* 2084fdeb9f2fSMatt Jacob * The first loop is for our usage where we have yet to have 2085fdeb9f2fSMatt Jacob * gotten good fibre channel state. 2086fdeb9f2fSMatt Jacob */ 20875d571944SMatt Jacob for (;;) { 2088fdeb9f2fSMatt Jacob int wasfrozen; 2089fdeb9f2fSMatt Jacob 2090fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "kthread: checking FC state"); 20915d571944SMatt Jacob while (isp_fc_runstate(isp, 2 * 1000000) != 0) { 2092fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "kthread: FC state ungood"); 2093f44257c2SMatt Jacob if (FCPARAM(isp)->isp_fwstate != FW_READY || 2094f44257c2SMatt Jacob FCPARAM(isp)->isp_loopstate < LOOP_PDB_RCVD) { 2095f44257c2SMatt Jacob if (FCPARAM(isp)->loop_seen_once == 0 || 2096fdeb9f2fSMatt Jacob isp->isp_osinfo.ktmature == 0) { 2097f44257c2SMatt Jacob break; 2098f44257c2SMatt Jacob } 2099f44257c2SMatt Jacob } 2100162e9893SMatt Jacob #ifdef ISP_SMPLOCK 21015d571944SMatt Jacob msleep(isp_kthread, &isp->isp_lock, 21025d571944SMatt Jacob PRIBIO, "isp_fcthrd", hz); 2103162e9893SMatt Jacob #else 2104162e9893SMatt Jacob (void) tsleep(isp_kthread, PRIBIO, "isp_fcthrd", hz); 2105162e9893SMatt Jacob #endif 21065d571944SMatt Jacob } 2107fdeb9f2fSMatt Jacob 2108f44257c2SMatt Jacob /* 2109f44257c2SMatt Jacob * Even if we didn't get good loop state we may be 2110f44257c2SMatt Jacob * unfreezing the SIMQ so that we can kill off 2111fdeb9f2fSMatt Jacob * commands (if we've never seen loop before, for example). 2112f44257c2SMatt Jacob */ 2113fdeb9f2fSMatt Jacob isp->isp_osinfo.ktmature = 1; 21145d571944SMatt Jacob wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN; 21155d571944SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN; 21165d571944SMatt Jacob if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) { 2117fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "kthread: releasing simq"); 21185d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 21195d571944SMatt Jacob xpt_release_simq(isp->isp_sim, 1); 21205d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 21215d571944SMatt Jacob } 2122fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "kthread: waiting until called"); 21239cd7268eSMatt Jacob #if __FreeBSD_version < 500000 21249cd7268eSMatt Jacob tsleep(&isp->isp_osinfo.kproc, PRIBIO, "isp_fc_worker", 0); 21259cd7268eSMatt Jacob #else 2126162e9893SMatt Jacob #ifdef ISP_SMPLOCK 21275d571944SMatt Jacob cv_wait(&isp->isp_osinfo.kthread_cv, &isp->isp_lock); 2128162e9893SMatt Jacob #else 2129162e9893SMatt Jacob (void) tsleep(&isp->isp_osinfo.kthread_cv, PRIBIO, "fc_cv", 0); 2130162e9893SMatt Jacob #endif 21319cd7268eSMatt Jacob #endif 21325d571944SMatt Jacob } 21335d571944SMatt Jacob } 21345d571944SMatt Jacob 2135cc8df88bSMatt Jacob static void 2136c3055363SMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb) 2137478f8a96SJustin T. Gibbs { 2138f6e75de2SMatt Jacob int bus, tgt, error; 21399cd7268eSMatt Jacob ispsoftc_t *isp; 21404663e367SJustin T. Gibbs struct ccb_trans_settings *cts; 2141478f8a96SJustin T. Gibbs 2142478f8a96SJustin T. Gibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n")); 2143478f8a96SJustin T. Gibbs 21449cd7268eSMatt Jacob isp = (ispsoftc_t *)cam_sim_softc(sim); 2145478f8a96SJustin T. Gibbs ccb->ccb_h.sim_priv.entries[0].field = 0; 2146478f8a96SJustin T. Gibbs ccb->ccb_h.sim_priv.entries[1].ptr = isp; 21470470d791SMatt Jacob if (isp->isp_state != ISP_RUNSTATE && 21480470d791SMatt Jacob ccb->ccb_h.func_code == XPT_SCSI_IO) { 21495d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 215057c801f5SMatt Jacob isp_init(isp); 215157c801f5SMatt Jacob if (isp->isp_state != ISP_INITSTATE) { 2152f6e75de2SMatt Jacob ISP_UNLOCK(isp); 215357c801f5SMatt Jacob /* 215457c801f5SMatt Jacob * Lie. Say it was a selection timeout. 215557c801f5SMatt Jacob */ 2156b85389e1SMatt Jacob ccb->ccb_h.status = CAM_SEL_TIMEOUT | CAM_DEV_QFRZN; 21570470d791SMatt Jacob xpt_freeze_devq(ccb->ccb_h.path, 1); 215857c801f5SMatt Jacob xpt_done(ccb); 215957c801f5SMatt Jacob return; 216057c801f5SMatt Jacob } 216157c801f5SMatt Jacob isp->isp_state = ISP_RUNSTATE; 21625d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 216357c801f5SMatt Jacob } 2164b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "isp_action code %x", ccb->ccb_h.func_code); 2165478f8a96SJustin T. Gibbs 21665d571944SMatt Jacob 2167478f8a96SJustin T. Gibbs switch (ccb->ccb_h.func_code) { 2168478f8a96SJustin T. Gibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 2169478f8a96SJustin T. Gibbs /* 2170478f8a96SJustin T. Gibbs * Do a couple of preliminary checks... 2171478f8a96SJustin T. Gibbs */ 2172478f8a96SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { 2173478f8a96SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) { 2174478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2175478f8a96SJustin T. Gibbs xpt_done(ccb); 2176478f8a96SJustin T. Gibbs break; 2177478f8a96SJustin T. Gibbs } 2178478f8a96SJustin T. Gibbs } 21790470d791SMatt Jacob #ifdef DIAGNOSTIC 21800470d791SMatt Jacob if (ccb->ccb_h.target_id > (ISP_MAX_TARGETS(isp) - 1)) { 2181478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 21820470d791SMatt Jacob } else if (ccb->ccb_h.target_lun > (ISP_MAX_LUNS(isp) - 1)) { 2183478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 2184478f8a96SJustin T. Gibbs } 2185478f8a96SJustin T. Gibbs if (ccb->ccb_h.status == CAM_PATH_INVALID) { 2186bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 2187bfbab170SMatt Jacob "invalid tgt/lun (%d.%d) in XPT_SCSI_IO", 2188bfbab170SMatt Jacob ccb->ccb_h.target_id, ccb->ccb_h.target_lun); 2189478f8a96SJustin T. Gibbs xpt_done(ccb); 2190478f8a96SJustin T. Gibbs break; 2191478f8a96SJustin T. Gibbs } 21920470d791SMatt Jacob #endif 21930470d791SMatt Jacob ((struct ccb_scsiio *) ccb)->scsi_status = SCSI_STATUS_OK; 21945d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2195b09b0095SMatt Jacob error = isp_start((XS_T *) ccb); 21960470d791SMatt Jacob switch (error) { 2197478f8a96SJustin T. Gibbs case CMD_QUEUED: 2198478f8a96SJustin T. Gibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 2199cc8df88bSMatt Jacob if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { 22001dae40ebSMatt Jacob uint64_t ticks = (uint64_t) hz; 2201cc8df88bSMatt Jacob if (ccb->ccb_h.timeout == CAM_TIME_DEFAULT) 2202d69a5f7dSMatt Jacob ticks = 60 * 1000 * ticks; 2203b85389e1SMatt Jacob else 2204b85389e1SMatt Jacob ticks = ccb->ccb_h.timeout * hz; 2205b85389e1SMatt Jacob ticks = ((ticks + 999) / 1000) + hz + hz; 2206d69a5f7dSMatt Jacob if (ticks >= 0x80000000) { 2207d69a5f7dSMatt Jacob isp_prt(isp, ISP_LOGERR, 2208d69a5f7dSMatt Jacob "timeout overflow"); 2209fdeb9f2fSMatt Jacob ticks = 0x7fffffff; 2210d69a5f7dSMatt Jacob } 2211d69a5f7dSMatt Jacob ccb->ccb_h.timeout_ch = timeout(isp_watchdog, 2212d69a5f7dSMatt Jacob (caddr_t)ccb, (int)ticks); 2213b85389e1SMatt Jacob } else { 2214b85389e1SMatt Jacob callout_handle_init(&ccb->ccb_h.timeout_ch); 2215cc8df88bSMatt Jacob } 22165d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2217478f8a96SJustin T. Gibbs break; 22180470d791SMatt Jacob case CMD_RQLATER: 2219f44257c2SMatt Jacob /* 2220f44257c2SMatt Jacob * This can only happen for Fibre Channel 2221f44257c2SMatt Jacob */ 2222f44257c2SMatt Jacob KASSERT((IS_FC(isp)), ("CMD_RQLATER for FC only")); 2223fdeb9f2fSMatt Jacob if (FCPARAM(isp)->loop_seen_once == 0 && 2224fdeb9f2fSMatt Jacob isp->isp_osinfo.ktmature) { 2225f44257c2SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2226f44257c2SMatt Jacob XS_SETERR(ccb, CAM_SEL_TIMEOUT); 2227f44257c2SMatt Jacob xpt_done(ccb); 2228f44257c2SMatt Jacob break; 2229f44257c2SMatt Jacob } 22309cd7268eSMatt Jacob #if __FreeBSD_version < 500000 22319cd7268eSMatt Jacob wakeup(&isp->isp_osinfo.kproc); 22329cd7268eSMatt Jacob #else 2233162e9893SMatt Jacob #ifdef ISP_SMPLOCK 22345d571944SMatt Jacob cv_signal(&isp->isp_osinfo.kthread_cv); 2235162e9893SMatt Jacob #else 2236162e9893SMatt Jacob wakeup(&isp->isp_osinfo.kthread_cv); 2237162e9893SMatt Jacob #endif 22389cd7268eSMatt Jacob #endif 2239fdeb9f2fSMatt Jacob isp_freeze_loopdown(isp, "isp_action(RQLATER)"); 2240b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 2241fdeb9f2fSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2242478f8a96SJustin T. Gibbs xpt_done(ccb); 2243478f8a96SJustin T. Gibbs break; 22440470d791SMatt Jacob case CMD_EAGAIN: 2245b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 22465d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2247478f8a96SJustin T. Gibbs xpt_done(ccb); 2248478f8a96SJustin T. Gibbs break; 22490470d791SMatt Jacob case CMD_COMPLETE: 22500470d791SMatt Jacob isp_done((struct ccb_scsiio *) ccb); 22515d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 22520470d791SMatt Jacob break; 22530470d791SMatt Jacob default: 2254bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 2255bfbab170SMatt Jacob "What's this? 0x%x at %d in file %s", 225691f1caa2SMatt Jacob error, __LINE__, __FILE__); 2257b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQ_CMP_ERR); 22580470d791SMatt Jacob xpt_done(ccb); 22595d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2260478f8a96SJustin T. Gibbs } 2261478f8a96SJustin T. Gibbs break; 2262478f8a96SJustin T. Gibbs 2263d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2264478f8a96SJustin T. Gibbs case XPT_EN_LUN: /* Enable LUN as a target */ 226564edff94SMatt Jacob { 226667ff51f1SMatt Jacob int seq, iok, i; 22675d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 226864edff94SMatt Jacob iok = isp->isp_osinfo.intsok; 226964edff94SMatt Jacob isp->isp_osinfo.intsok = 0; 227067ff51f1SMatt Jacob seq = isp_en_lun(isp, ccb); 227167ff51f1SMatt Jacob if (seq < 0) { 227264edff94SMatt Jacob isp->isp_osinfo.intsok = iok; 22735d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2274478f8a96SJustin T. Gibbs xpt_done(ccb); 2275478f8a96SJustin T. Gibbs break; 227664edff94SMatt Jacob } 227767ff51f1SMatt Jacob for (i = 0; isp->isp_osinfo.leact[seq] && i < 30 * 1000; i++) { 22781dae40ebSMatt Jacob uint16_t isr, sema, mbox; 227967ff51f1SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 228067ff51f1SMatt Jacob isp_intr(isp, isr, sema, mbox); 228167ff51f1SMatt Jacob } 228267ff51f1SMatt Jacob DELAY(1000); 228367ff51f1SMatt Jacob } 228467ff51f1SMatt Jacob isp->isp_osinfo.intsok = iok; 228567ff51f1SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 228667ff51f1SMatt Jacob break; 228767ff51f1SMatt Jacob } 2288d81ba9d5SMatt Jacob case XPT_NOTIFY_ACK: /* recycle notify ack */ 2289d81ba9d5SMatt Jacob case XPT_IMMED_NOTIFY: /* Add Immediate Notify Resource */ 2290d81ba9d5SMatt Jacob case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */ 2291d81ba9d5SMatt Jacob { 2292a1bc34c6SMatt Jacob tstate_t *tptr = 2293a1bc34c6SMatt Jacob get_lun_statep(isp, XS_CHANNEL(ccb), ccb->ccb_h.target_lun); 2294d81ba9d5SMatt Jacob if (tptr == NULL) { 2295d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 2296d81ba9d5SMatt Jacob xpt_done(ccb); 2297d81ba9d5SMatt Jacob break; 2298d81ba9d5SMatt Jacob } 2299f48ce188SMatt Jacob ccb->ccb_h.sim_priv.entries[0].field = 0; 2300f48ce188SMatt Jacob ccb->ccb_h.sim_priv.entries[1].ptr = isp; 2301570c7a3fSMatt Jacob ccb->ccb_h.flags = 0; 2302570c7a3fSMatt Jacob 23035d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2304d81ba9d5SMatt Jacob if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 2305570c7a3fSMatt Jacob /* 2306570c7a3fSMatt Jacob * Note that the command itself may not be done- 2307570c7a3fSMatt Jacob * it may not even have had the first CTIO sent. 2308570c7a3fSMatt Jacob */ 2309570c7a3fSMatt Jacob tptr->atio_count++; 2310570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 2311746e9c85SMatt Jacob "Put FREE ATIO, lun %d, count now %d", 2312570c7a3fSMatt Jacob ccb->ccb_h.target_lun, tptr->atio_count); 2313570c7a3fSMatt Jacob SLIST_INSERT_HEAD(&tptr->atios, &ccb->ccb_h, 2314570c7a3fSMatt Jacob sim_links.sle); 2315570c7a3fSMatt Jacob } else if (ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) { 2316746e9c85SMatt Jacob tptr->inot_count++; 2317746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 2318746e9c85SMatt Jacob "Put FREE INOT, lun %d, count now %d", 2319746e9c85SMatt Jacob ccb->ccb_h.target_lun, tptr->inot_count); 2320d81ba9d5SMatt Jacob SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, 2321d81ba9d5SMatt Jacob sim_links.sle); 2322570c7a3fSMatt Jacob } else { 2323746e9c85SMatt Jacob isp_prt(isp, ISP_LOGWARN, "Got Notify ACK");; 2324d81ba9d5SMatt Jacob } 2325d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 2326d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_INPROG; 23275d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2328d81ba9d5SMatt Jacob break; 2329d81ba9d5SMatt Jacob } 2330d81ba9d5SMatt Jacob case XPT_CONT_TARGET_IO: 2331d81ba9d5SMatt Jacob { 23325d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 23339cd7268eSMatt Jacob isp_target_start_ctio(isp, ccb); 23345d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2335d81ba9d5SMatt Jacob break; 2336d81ba9d5SMatt Jacob } 2337d81ba9d5SMatt Jacob #endif 2338478f8a96SJustin T. Gibbs case XPT_RESET_DEV: /* BDR the specified SCSI device */ 2339d81ba9d5SMatt Jacob 2340d81ba9d5SMatt Jacob bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path)); 2341d81ba9d5SMatt Jacob tgt = ccb->ccb_h.target_id; 2342d81ba9d5SMatt Jacob tgt |= (bus << 16); 2343d81ba9d5SMatt Jacob 23445d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2345ea6f23cdSMatt Jacob error = isp_control(isp, ISPCTL_RESET_DEV, &tgt); 23465d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2347478f8a96SJustin T. Gibbs if (error) { 2348478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2349478f8a96SJustin T. Gibbs } else { 2350478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2351478f8a96SJustin T. Gibbs } 2352478f8a96SJustin T. Gibbs xpt_done(ccb); 2353478f8a96SJustin T. Gibbs break; 2354478f8a96SJustin T. Gibbs case XPT_ABORT: /* Abort the specified CCB */ 2355d81ba9d5SMatt Jacob { 2356d81ba9d5SMatt Jacob union ccb *accb = ccb->cab.abort_ccb; 23575d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2358d81ba9d5SMatt Jacob switch (accb->ccb_h.func_code) { 2359d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2360d81ba9d5SMatt Jacob case XPT_ACCEPT_TARGET_IO: 2361d81ba9d5SMatt Jacob case XPT_IMMED_NOTIFY: 2362d81ba9d5SMatt Jacob ccb->ccb_h.status = isp_abort_tgt_ccb(isp, ccb); 2363d81ba9d5SMatt Jacob break; 2364d81ba9d5SMatt Jacob case XPT_CONT_TARGET_IO: 2365b09b0095SMatt Jacob isp_prt(isp, ISP_LOGERR, "cannot abort CTIOs yet"); 2366d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_UA_ABORT; 2367d81ba9d5SMatt Jacob break; 2368d81ba9d5SMatt Jacob #endif 2369d81ba9d5SMatt Jacob case XPT_SCSI_IO: 2370478f8a96SJustin T. Gibbs error = isp_control(isp, ISPCTL_ABORT_CMD, ccb); 2371478f8a96SJustin T. Gibbs if (error) { 2372d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_UA_ABORT; 2373478f8a96SJustin T. Gibbs } else { 2374478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2375478f8a96SJustin T. Gibbs } 2376d81ba9d5SMatt Jacob break; 2377d81ba9d5SMatt Jacob default: 2378d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_INVALID; 2379d81ba9d5SMatt Jacob break; 2380d81ba9d5SMatt Jacob } 23815d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2382478f8a96SJustin T. Gibbs xpt_done(ccb); 2383478f8a96SJustin T. Gibbs break; 2384d81ba9d5SMatt Jacob } 2385ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2386ab163f5fSMatt Jacob #define IS_CURRENT_SETTINGS(c) (c->type == CTS_TYPE_CURRENT_SETTINGS) 2387ab163f5fSMatt Jacob #else 2388ab163f5fSMatt Jacob #define IS_CURRENT_SETTINGS(c) (c->flags & CCB_TRANS_CURRENT_SETTINGS) 2389ab163f5fSMatt Jacob #endif 2390478f8a96SJustin T. Gibbs case XPT_SET_TRAN_SETTINGS: /* Nexus Settings */ 2391478f8a96SJustin T. Gibbs cts = &ccb->cts; 23929ce9bdafSMatt Jacob if (!IS_CURRENT_SETTINGS(cts)) { 23939ce9bdafSMatt Jacob ccb->ccb_h.status = CAM_REQ_INVALID; 23949ce9bdafSMatt Jacob xpt_done(ccb); 23959ce9bdafSMatt Jacob break; 23969ce9bdafSMatt Jacob } 2397478f8a96SJustin T. Gibbs tgt = cts->ccb_h.target_id; 23985d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2399ab6c4b31SMatt Jacob if (IS_SCSI(isp)) { 2400ab163f5fSMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2401478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 24021dae40ebSMatt Jacob uint16_t *dptr; 2403d81ba9d5SMatt Jacob 2404d81ba9d5SMatt Jacob bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 2405478f8a96SJustin T. Gibbs 2406ea6f23cdSMatt Jacob sdp += bus; 2407478f8a96SJustin T. Gibbs /* 24089ce9bdafSMatt Jacob * We always update (internally) from goal_flags 2409478f8a96SJustin T. Gibbs * so any request to change settings just gets 2410478f8a96SJustin T. Gibbs * vectored to that location. 2411478f8a96SJustin T. Gibbs */ 24129ce9bdafSMatt Jacob dptr = &sdp->isp_devparam[tgt].goal_flags; 2413478f8a96SJustin T. Gibbs 2414478f8a96SJustin T. Gibbs /* 2415478f8a96SJustin T. Gibbs * Note that these operations affect the 24169ce9bdafSMatt Jacob * the goal flags (goal_flags)- not 2417478f8a96SJustin T. Gibbs * the current state flags. Then we mark 2418478f8a96SJustin T. Gibbs * things so that the next operation to 2419478f8a96SJustin T. Gibbs * this HBA will cause the update to occur. 2420478f8a96SJustin T. Gibbs */ 2421478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_DISC_VALID) { 2422478f8a96SJustin T. Gibbs if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) { 2423478f8a96SJustin T. Gibbs *dptr |= DPARM_DISC; 2424478f8a96SJustin T. Gibbs } else { 2425478f8a96SJustin T. Gibbs *dptr &= ~DPARM_DISC; 2426478f8a96SJustin T. Gibbs } 2427478f8a96SJustin T. Gibbs } 2428478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_TQ_VALID) { 2429478f8a96SJustin T. Gibbs if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) { 2430478f8a96SJustin T. Gibbs *dptr |= DPARM_TQING; 2431478f8a96SJustin T. Gibbs } else { 2432478f8a96SJustin T. Gibbs *dptr &= ~DPARM_TQING; 2433478f8a96SJustin T. Gibbs } 2434478f8a96SJustin T. Gibbs } 2435478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) { 2436478f8a96SJustin T. Gibbs switch (cts->bus_width) { 2437478f8a96SJustin T. Gibbs case MSG_EXT_WDTR_BUS_16_BIT: 2438478f8a96SJustin T. Gibbs *dptr |= DPARM_WIDE; 2439478f8a96SJustin T. Gibbs break; 2440478f8a96SJustin T. Gibbs default: 2441478f8a96SJustin T. Gibbs *dptr &= ~DPARM_WIDE; 2442478f8a96SJustin T. Gibbs } 2443478f8a96SJustin T. Gibbs } 2444478f8a96SJustin T. Gibbs /* 2445478f8a96SJustin T. Gibbs * Any SYNC RATE of nonzero and SYNC_OFFSET 2446478f8a96SJustin T. Gibbs * of nonzero will cause us to go to the 2447478f8a96SJustin T. Gibbs * selected (from NVRAM) maximum value for 2448478f8a96SJustin T. Gibbs * this device. At a later point, we'll 2449478f8a96SJustin T. Gibbs * allow finer control. 2450478f8a96SJustin T. Gibbs */ 2451478f8a96SJustin T. Gibbs if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) && 2452478f8a96SJustin T. Gibbs (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) && 2453478f8a96SJustin T. Gibbs (cts->sync_offset > 0)) { 2454478f8a96SJustin T. Gibbs *dptr |= DPARM_SYNC; 2455478f8a96SJustin T. Gibbs } else { 2456478f8a96SJustin T. Gibbs *dptr &= ~DPARM_SYNC; 2457478f8a96SJustin T. Gibbs } 2458ab6c4b31SMatt Jacob *dptr |= DPARM_SAFE_DFLT; 2459ab163f5fSMatt Jacob #else 2460ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi = 2461ab163f5fSMatt Jacob &cts->proto_specific.scsi; 2462ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi = 2463ab163f5fSMatt Jacob &cts->xport_specific.spi; 2464ab163f5fSMatt Jacob sdparam *sdp = isp->isp_param; 24651dae40ebSMatt Jacob uint16_t *dptr; 2466ab163f5fSMatt Jacob 2467ab163f5fSMatt Jacob bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 2468ab163f5fSMatt Jacob sdp += bus; 2469ab163f5fSMatt Jacob /* 24709ce9bdafSMatt Jacob * We always update (internally) from goal_flags 2471ab163f5fSMatt Jacob * so any request to change settings just gets 2472ab163f5fSMatt Jacob * vectored to that location. 2473ab163f5fSMatt Jacob */ 24749ce9bdafSMatt Jacob dptr = &sdp->isp_devparam[tgt].goal_flags; 2475ab163f5fSMatt Jacob 2476ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_DISC) != 0) { 2477ab163f5fSMatt Jacob if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) 2478ab163f5fSMatt Jacob *dptr |= DPARM_DISC; 2479ab163f5fSMatt Jacob else 2480ab163f5fSMatt Jacob *dptr &= ~DPARM_DISC; 2481ab163f5fSMatt Jacob } 2482ab163f5fSMatt Jacob 2483ab163f5fSMatt Jacob if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 2484ab163f5fSMatt Jacob if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) 2485ab163f5fSMatt Jacob *dptr |= DPARM_TQING; 2486ab163f5fSMatt Jacob else 2487ab163f5fSMatt Jacob *dptr &= ~DPARM_TQING; 2488ab163f5fSMatt Jacob } 2489ab163f5fSMatt Jacob 2490ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 2491ab163f5fSMatt Jacob if (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT) 2492ab163f5fSMatt Jacob *dptr |= DPARM_WIDE; 2493ab163f5fSMatt Jacob else 2494ab163f5fSMatt Jacob *dptr &= ~DPARM_WIDE; 2495ab163f5fSMatt Jacob } 2496ab163f5fSMatt Jacob 2497ab163f5fSMatt Jacob /* 2498ab163f5fSMatt Jacob * XXX: FIX ME 2499ab163f5fSMatt Jacob */ 2500ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) && 25019ce9bdafSMatt Jacob (spi->valid & CTS_SPI_VALID_SYNC_RATE) && 25029ce9bdafSMatt Jacob (spi->sync_period && spi->sync_offset)) { 2503ab163f5fSMatt Jacob *dptr |= DPARM_SYNC; 25049ce9bdafSMatt Jacob /* 25059ce9bdafSMatt Jacob * XXX: CHECK FOR LEGALITY 25069ce9bdafSMatt Jacob */ 25079ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_period = 25089ce9bdafSMatt Jacob spi->sync_period; 25099ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_offset = 25109ce9bdafSMatt Jacob spi->sync_offset; 2511ab163f5fSMatt Jacob } else { 2512ab163f5fSMatt Jacob *dptr &= ~DPARM_SYNC; 2513ab163f5fSMatt Jacob } 2514ab163f5fSMatt Jacob #endif 2515bfbab170SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 25169ce9bdafSMatt Jacob "SET bus %d targ %d to flags %x off %x per %x", 25179ce9bdafSMatt Jacob bus, tgt, sdp->isp_devparam[tgt].goal_flags, 25189ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_offset, 25199ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_period); 2520478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_update = 1; 2521ea6f23cdSMatt Jacob isp->isp_update |= (1 << bus); 2522478f8a96SJustin T. Gibbs } 25235d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2524478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2525478f8a96SJustin T. Gibbs xpt_done(ccb); 2526478f8a96SJustin T. Gibbs break; 2527478f8a96SJustin T. Gibbs case XPT_GET_TRAN_SETTINGS: 2528478f8a96SJustin T. Gibbs cts = &ccb->cts; 2529478f8a96SJustin T. Gibbs tgt = cts->ccb_h.target_id; 2530ab163f5fSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2531ab6c4b31SMatt Jacob if (IS_FC(isp)) { 2532ab163f5fSMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2533478f8a96SJustin T. Gibbs /* 2534478f8a96SJustin T. Gibbs * a lot of normal SCSI things don't make sense. 2535478f8a96SJustin T. Gibbs */ 2536478f8a96SJustin T. Gibbs cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB; 2537478f8a96SJustin T. Gibbs cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2538478f8a96SJustin T. Gibbs /* 2539478f8a96SJustin T. Gibbs * How do you measure the width of a high 2540478f8a96SJustin T. Gibbs * speed serial bus? Well, in bytes. 2541478f8a96SJustin T. Gibbs * 2542478f8a96SJustin T. Gibbs * Offset and period make no sense, though, so we set 2543478f8a96SJustin T. Gibbs * (above) a 'base' transfer speed to be gigabit. 2544478f8a96SJustin T. Gibbs */ 2545478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2546ab163f5fSMatt Jacob #else 2547ab163f5fSMatt Jacob fcparam *fcp = isp->isp_param; 2548ab163f5fSMatt Jacob struct ccb_trans_settings_fc *fc = 2549ab163f5fSMatt Jacob &cts->xport_specific.fc; 2550478f8a96SJustin T. Gibbs 2551ab163f5fSMatt Jacob cts->protocol = PROTO_SCSI; 2552ab163f5fSMatt Jacob cts->protocol_version = SCSI_REV_2; 2553ab163f5fSMatt Jacob cts->transport = XPORT_FC; 2554ab163f5fSMatt Jacob cts->transport_version = 0; 2555ab163f5fSMatt Jacob 2556ab163f5fSMatt Jacob fc->valid = CTS_FC_VALID_SPEED; 255753036e92SMatt Jacob if (fcp->isp_gbspeed == 2) 255853036e92SMatt Jacob fc->bitrate = 200000; 255953036e92SMatt Jacob else 2560ab163f5fSMatt Jacob fc->bitrate = 100000; 2561ab163f5fSMatt Jacob if (tgt > 0 && tgt < MAX_FC_TARG) { 2562ab163f5fSMatt Jacob struct lportdb *lp = &fcp->portdb[tgt]; 2563ab163f5fSMatt Jacob fc->wwnn = lp->node_wwn; 2564ab163f5fSMatt Jacob fc->wwpn = lp->port_wwn; 2565ab163f5fSMatt Jacob fc->port = lp->portid; 2566ab163f5fSMatt Jacob fc->valid |= CTS_FC_VALID_WWNN | 2567ab163f5fSMatt Jacob CTS_FC_VALID_WWPN | CTS_FC_VALID_PORT; 2568ab163f5fSMatt Jacob } 2569ab163f5fSMatt Jacob #endif 2570ab163f5fSMatt Jacob } else { 2571ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2572ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi = 2573ab163f5fSMatt Jacob &cts->proto_specific.scsi; 2574ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi = 2575ab163f5fSMatt Jacob &cts->xport_specific.spi; 2576ab163f5fSMatt Jacob #endif 2577ab163f5fSMatt Jacob sdparam *sdp = isp->isp_param; 2578ab163f5fSMatt Jacob int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 25791dae40ebSMatt Jacob uint16_t dval, pval, oval; 2580ab163f5fSMatt Jacob 2581ea6f23cdSMatt Jacob sdp += bus; 2582ab163f5fSMatt Jacob 2583ab163f5fSMatt Jacob if (IS_CURRENT_SETTINGS(cts)) { 258483ae4407SMatt Jacob sdp->isp_devparam[tgt].dev_refresh = 1; 258583ae4407SMatt Jacob isp->isp_update |= (1 << bus); 258683ae4407SMatt Jacob (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, 258783ae4407SMatt Jacob NULL); 25889ce9bdafSMatt Jacob dval = sdp->isp_devparam[tgt].actv_flags; 25899ce9bdafSMatt Jacob oval = sdp->isp_devparam[tgt].actv_offset; 25909ce9bdafSMatt Jacob pval = sdp->isp_devparam[tgt].actv_period; 25914394c92fSMatt Jacob } else { 25929ce9bdafSMatt Jacob dval = sdp->isp_devparam[tgt].nvrm_flags; 25939ce9bdafSMatt Jacob oval = sdp->isp_devparam[tgt].nvrm_offset; 25949ce9bdafSMatt Jacob pval = sdp->isp_devparam[tgt].nvrm_period; 25954394c92fSMatt Jacob } 2596478f8a96SJustin T. Gibbs 2597ab163f5fSMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2598478f8a96SJustin T. Gibbs cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); 2599478f8a96SJustin T. Gibbs 2600478f8a96SJustin T. Gibbs if (dval & DPARM_DISC) { 2601478f8a96SJustin T. Gibbs cts->flags |= CCB_TRANS_DISC_ENB; 2602478f8a96SJustin T. Gibbs } 2603478f8a96SJustin T. Gibbs if (dval & DPARM_TQING) { 2604478f8a96SJustin T. Gibbs cts->flags |= CCB_TRANS_TAG_ENB; 2605478f8a96SJustin T. Gibbs } 2606478f8a96SJustin T. Gibbs if (dval & DPARM_WIDE) { 2607478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2608478f8a96SJustin T. Gibbs } else { 2609478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2610478f8a96SJustin T. Gibbs } 2611478f8a96SJustin T. Gibbs cts->valid = CCB_TRANS_BUS_WIDTH_VALID | 2612478f8a96SJustin T. Gibbs CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2613478f8a96SJustin T. Gibbs 26144394c92fSMatt Jacob if ((dval & DPARM_SYNC) && oval != 0) { 26154394c92fSMatt Jacob cts->sync_period = pval; 26164394c92fSMatt Jacob cts->sync_offset = oval; 2617478f8a96SJustin T. Gibbs cts->valid |= 2618478f8a96SJustin T. Gibbs CCB_TRANS_SYNC_RATE_VALID | 2619478f8a96SJustin T. Gibbs CCB_TRANS_SYNC_OFFSET_VALID; 2620478f8a96SJustin T. Gibbs } 2621ab163f5fSMatt Jacob #else 2622ab163f5fSMatt Jacob cts->protocol = PROTO_SCSI; 2623ab163f5fSMatt Jacob cts->protocol_version = SCSI_REV_2; 2624ab163f5fSMatt Jacob cts->transport = XPORT_SPI; 2625ab163f5fSMatt Jacob cts->transport_version = 2; 2626ab163f5fSMatt Jacob 2627ab163f5fSMatt Jacob scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 2628ab163f5fSMatt Jacob spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 2629ab163f5fSMatt Jacob if (dval & DPARM_DISC) { 2630ab163f5fSMatt Jacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 2631ab163f5fSMatt Jacob } 2632ab163f5fSMatt Jacob if (dval & DPARM_TQING) { 2633ab163f5fSMatt Jacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 2634ab163f5fSMatt Jacob } 26359ce9bdafSMatt Jacob if ((dval & DPARM_SYNC) && oval && pval) { 2636ab163f5fSMatt Jacob spi->sync_offset = oval; 2637ab163f5fSMatt Jacob spi->sync_period = pval; 2638ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 2639ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 2640ab163f5fSMatt Jacob } 2641ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_BUS_WIDTH; 2642ab163f5fSMatt Jacob if (dval & DPARM_WIDE) { 2643ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2644ab163f5fSMatt Jacob } else { 2645ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2646ab163f5fSMatt Jacob } 2647ab163f5fSMatt Jacob if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { 2648ab163f5fSMatt Jacob scsi->valid = CTS_SCSI_VALID_TQ; 2649ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_DISC; 2650ab163f5fSMatt Jacob } else { 2651ab163f5fSMatt Jacob scsi->valid = 0; 2652ab163f5fSMatt Jacob } 2653ab163f5fSMatt Jacob #endif 2654bfbab170SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 26559ce9bdafSMatt Jacob "GET %s bus %d targ %d to flags %x off %x per %x", 26569ce9bdafSMatt Jacob IS_CURRENT_SETTINGS(cts)? "ACTIVE" : "NVRAM", 26579ce9bdafSMatt Jacob bus, tgt, dval, oval, pval); 2658478f8a96SJustin T. Gibbs } 2659ab163f5fSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2660478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2661478f8a96SJustin T. Gibbs xpt_done(ccb); 2662478f8a96SJustin T. Gibbs break; 2663478f8a96SJustin T. Gibbs 2664478f8a96SJustin T. Gibbs case XPT_CALC_GEOMETRY: 26659cd7268eSMatt Jacob #if __FreeBSD_version < 500000 2666478f8a96SJustin T. Gibbs { 2667478f8a96SJustin T. Gibbs struct ccb_calc_geometry *ccg; 26689cd7268eSMatt Jacob u_int32_t secs_per_cylinder; 26699cd7268eSMatt Jacob u_int32_t size_mb; 2670478f8a96SJustin T. Gibbs 2671478f8a96SJustin T. Gibbs ccg = &ccb->ccg; 2672478f8a96SJustin T. Gibbs if (ccg->block_size == 0) { 2673478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2674478f8a96SJustin T. Gibbs xpt_done(ccb); 2675478f8a96SJustin T. Gibbs break; 2676478f8a96SJustin T. Gibbs } 26779cd7268eSMatt Jacob size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size); 26789cd7268eSMatt Jacob if (size_mb > 1024) { 26799cd7268eSMatt Jacob ccg->heads = 255; 26809cd7268eSMatt Jacob ccg->secs_per_track = 63; 26819cd7268eSMatt Jacob } else { 26829cd7268eSMatt Jacob ccg->heads = 64; 26839cd7268eSMatt Jacob ccg->secs_per_track = 32; 26849cd7268eSMatt Jacob } 26859cd7268eSMatt Jacob secs_per_cylinder = ccg->heads * ccg->secs_per_track; 26869cd7268eSMatt Jacob ccg->cylinders = ccg->volume_size / secs_per_cylinder; 26879cd7268eSMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 2688478f8a96SJustin T. Gibbs xpt_done(ccb); 2689478f8a96SJustin T. Gibbs break; 2690478f8a96SJustin T. Gibbs } 26919cd7268eSMatt Jacob #else 26929cd7268eSMatt Jacob { 26939cd7268eSMatt Jacob cam_calc_geometry(&ccb->ccg, /*extended*/1); 26949cd7268eSMatt Jacob xpt_done(ccb); 26959cd7268eSMatt Jacob break; 26969cd7268eSMatt Jacob } 26979cd7268eSMatt Jacob #endif 2698478f8a96SJustin T. Gibbs case XPT_RESET_BUS: /* Reset the specified bus */ 2699ab6c4b31SMatt Jacob bus = cam_sim_bus(sim); 27005d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2701ab6c4b31SMatt Jacob error = isp_control(isp, ISPCTL_RESET_BUS, &bus); 27025d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2703478f8a96SJustin T. Gibbs if (error) 2704478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 27052b052931SMatt Jacob else { 2706ea6f23cdSMatt Jacob if (cam_sim_bus(sim) && isp->isp_path2 != NULL) 2707ea6f23cdSMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); 2708ea6f23cdSMatt Jacob else if (isp->isp_path != NULL) 27092b052931SMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path, NULL); 2710478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 27112b052931SMatt Jacob } 2712478f8a96SJustin T. Gibbs xpt_done(ccb); 2713478f8a96SJustin T. Gibbs break; 2714478f8a96SJustin T. Gibbs 2715478f8a96SJustin T. Gibbs case XPT_TERM_IO: /* Terminate the I/O process */ 2716478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2717478f8a96SJustin T. Gibbs xpt_done(ccb); 2718478f8a96SJustin T. Gibbs break; 2719478f8a96SJustin T. Gibbs 2720478f8a96SJustin T. Gibbs case XPT_PATH_INQ: /* Path routing inquiry */ 2721478f8a96SJustin T. Gibbs { 2722478f8a96SJustin T. Gibbs struct ccb_pathinq *cpi = &ccb->cpi; 2723478f8a96SJustin T. Gibbs 2724478f8a96SJustin T. Gibbs cpi->version_num = 1; 2725d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2726a1bc34c6SMatt Jacob cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO; 2727d81ba9d5SMatt Jacob #else 2728478f8a96SJustin T. Gibbs cpi->target_sprt = 0; 2729d81ba9d5SMatt Jacob #endif 2730478f8a96SJustin T. Gibbs cpi->hba_eng_cnt = 0; 27310470d791SMatt Jacob cpi->max_target = ISP_MAX_TARGETS(isp) - 1; 27320470d791SMatt Jacob cpi->max_lun = ISP_MAX_LUNS(isp) - 1; 27330470d791SMatt Jacob cpi->bus_id = cam_sim_bus(sim); 27344394c92fSMatt Jacob if (IS_FC(isp)) { 27354394c92fSMatt Jacob cpi->hba_misc = PIM_NOBUSRESET; 27360470d791SMatt Jacob /* 27370470d791SMatt Jacob * Because our loop ID can shift from time to time, 27380470d791SMatt Jacob * make our initiator ID out of range of our bus. 27390470d791SMatt Jacob */ 27400470d791SMatt Jacob cpi->initiator_id = cpi->max_target + 1; 27410470d791SMatt Jacob 27429deea857SKenneth D. Merry /* 27439deea857SKenneth D. Merry * Set base transfer capabilities for Fibre Channel. 27449deea857SKenneth D. Merry * Technically not correct because we don't know 27459deea857SKenneth D. Merry * what media we're running on top of- but we'll 27469deea857SKenneth D. Merry * look good if we always say 100MB/s. 27479deea857SKenneth D. Merry */ 274853036e92SMatt Jacob if (FCPARAM(isp)->isp_gbspeed == 2) 274953036e92SMatt Jacob cpi->base_transfer_speed = 200000; 275053036e92SMatt Jacob else 27519deea857SKenneth D. Merry cpi->base_transfer_speed = 100000; 27520470d791SMatt Jacob cpi->hba_inquiry = PI_TAG_ABLE; 2753ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2754ab163f5fSMatt Jacob cpi->transport = XPORT_FC; 2755ab163f5fSMatt Jacob cpi->transport_version = 0; /* WHAT'S THIS FOR? */ 2756ab163f5fSMatt Jacob #endif 2757478f8a96SJustin T. Gibbs } else { 2758ea6f23cdSMatt Jacob sdparam *sdp = isp->isp_param; 2759ea6f23cdSMatt Jacob sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path)); 27600470d791SMatt Jacob cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; 27614394c92fSMatt Jacob cpi->hba_misc = 0; 2762ea6f23cdSMatt Jacob cpi->initiator_id = sdp->isp_initiator_id; 27639deea857SKenneth D. Merry cpi->base_transfer_speed = 3300; 2764ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2765ab163f5fSMatt Jacob cpi->transport = XPORT_SPI; 2766ab163f5fSMatt Jacob cpi->transport_version = 2; /* WHAT'S THIS FOR? */ 2767ab163f5fSMatt Jacob #endif 2768478f8a96SJustin T. Gibbs } 2769ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2770ab163f5fSMatt Jacob cpi->protocol = PROTO_SCSI; 2771ab163f5fSMatt Jacob cpi->protocol_version = SCSI_REV_2; 2772ab163f5fSMatt Jacob #endif 2773478f8a96SJustin T. Gibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 2774478f8a96SJustin T. Gibbs strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN); 2775478f8a96SJustin T. Gibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 2776478f8a96SJustin T. Gibbs cpi->unit_number = cam_sim_unit(sim); 2777478f8a96SJustin T. Gibbs cpi->ccb_h.status = CAM_REQ_CMP; 2778478f8a96SJustin T. Gibbs xpt_done(ccb); 2779478f8a96SJustin T. Gibbs break; 2780478f8a96SJustin T. Gibbs } 2781478f8a96SJustin T. Gibbs default: 2782478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2783478f8a96SJustin T. Gibbs xpt_done(ccb); 2784478f8a96SJustin T. Gibbs break; 2785478f8a96SJustin T. Gibbs } 2786478f8a96SJustin T. Gibbs } 2787d3a9eb2eSMatt Jacob 2788d3a9eb2eSMatt Jacob #define ISPDDB (CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB) 2789d3a9eb2eSMatt Jacob void 2790c3055363SMatt Jacob isp_done(struct ccb_scsiio *sccb) 2791d3a9eb2eSMatt Jacob { 27929cd7268eSMatt Jacob ispsoftc_t *isp = XS_ISP(sccb); 2793d3a9eb2eSMatt Jacob 2794d3a9eb2eSMatt Jacob if (XS_NOERR(sccb)) 2795d3a9eb2eSMatt Jacob XS_SETERR(sccb, CAM_REQ_CMP); 2796b85389e1SMatt Jacob 2797d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP && 2798d3a9eb2eSMatt Jacob (sccb->scsi_status != SCSI_STATUS_OK)) { 2799d3a9eb2eSMatt Jacob sccb->ccb_h.status &= ~CAM_STATUS_MASK; 280092a1e549SMatt Jacob if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) && 280192a1e549SMatt Jacob (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) { 280292a1e549SMatt Jacob sccb->ccb_h.status |= CAM_AUTOSENSE_FAIL; 280392a1e549SMatt Jacob } else { 2804d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 2805d3a9eb2eSMatt Jacob } 280692a1e549SMatt Jacob } 2807b85389e1SMatt Jacob 28080470d791SMatt Jacob sccb->ccb_h.status &= ~CAM_SIM_QUEUED; 2809d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2810d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 2811d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_DEV_QFRZN; 28120470d791SMatt Jacob xpt_freeze_devq(sccb->ccb_h.path, 1); 2813fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 2814fdeb9f2fSMatt Jacob "freeze devq %d.%d cam sts %x scsi sts %x", 2815fdeb9f2fSMatt Jacob sccb->ccb_h.target_id, sccb->ccb_h.target_lun, 2816fdeb9f2fSMatt Jacob sccb->ccb_h.status, sccb->scsi_status); 2817d3a9eb2eSMatt Jacob } 2818d3a9eb2eSMatt Jacob } 2819b85389e1SMatt Jacob 2820b85389e1SMatt Jacob if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) && 2821d3a9eb2eSMatt Jacob (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2822d3a9eb2eSMatt Jacob xpt_print_path(sccb->ccb_h.path); 28233c75bb14SMatt Jacob isp_prt(isp, ISP_LOGINFO, 28243c75bb14SMatt Jacob "cam completion status 0x%x", sccb->ccb_h.status); 2825d3a9eb2eSMatt Jacob } 2826b85389e1SMatt Jacob 2827b85389e1SMatt Jacob XS_CMD_S_DONE(sccb); 2828b85389e1SMatt Jacob if (XS_CMD_WDOG_P(sccb) == 0) { 2829b85389e1SMatt Jacob untimeout(isp_watchdog, (caddr_t)sccb, sccb->ccb_h.timeout_ch); 2830b85389e1SMatt Jacob if (XS_CMD_GRACE_P(sccb)) { 2831b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2832b09b0095SMatt Jacob "finished command on borrowed time"); 2833b85389e1SMatt Jacob } 2834b85389e1SMatt Jacob XS_CMD_S_CLEAR(sccb); 28355d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2836d3a9eb2eSMatt Jacob xpt_done((union ccb *) sccb); 28375d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2838d3a9eb2eSMatt Jacob } 2839b85389e1SMatt Jacob } 2840d3a9eb2eSMatt Jacob 2841cbf57b47SMatt Jacob int 28429cd7268eSMatt Jacob isp_async(ispsoftc_t *isp, ispasync_t cmd, void *arg) 2843cbf57b47SMatt Jacob { 2844ea6f23cdSMatt Jacob int bus, rv = 0; 2845cbf57b47SMatt Jacob switch (cmd) { 2846cbf57b47SMatt Jacob case ISPASYNC_NEW_TGT_PARAMS: 28470470d791SMatt Jacob { 2848ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2849ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi; 2850ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi; 2851ab163f5fSMatt Jacob #endif 2852cbf57b47SMatt Jacob int flags, tgt; 2853cbf57b47SMatt Jacob sdparam *sdp = isp->isp_param; 2854ab163f5fSMatt Jacob struct ccb_trans_settings cts; 2855cbf57b47SMatt Jacob struct cam_path *tmppath; 2856cbf57b47SMatt Jacob 285729f76675SMatt Jacob memset(&cts, 0, sizeof (struct ccb_trans_settings)); 2858ab163f5fSMatt Jacob 2859cbf57b47SMatt Jacob tgt = *((int *)arg); 2860ea6f23cdSMatt Jacob bus = (tgt >> 16) & 0xffff; 2861ea6f23cdSMatt Jacob tgt &= 0xffff; 2862ea6f23cdSMatt Jacob sdp += bus; 286345c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2864cbf57b47SMatt Jacob if (xpt_create_path(&tmppath, NULL, 2865ea6f23cdSMatt Jacob cam_sim_path(bus? isp->isp_sim2 : isp->isp_sim), 2866ea6f23cdSMatt Jacob tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 286745c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2868bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 2869bfbab170SMatt Jacob "isp_async cannot make temp path for %d.%d", 2870bfbab170SMatt Jacob tgt, bus); 2871cbf57b47SMatt Jacob rv = -1; 2872cbf57b47SMatt Jacob break; 2873cbf57b47SMatt Jacob } 287445c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 28759ce9bdafSMatt Jacob flags = sdp->isp_devparam[tgt].actv_flags; 2876ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2877ab163f5fSMatt Jacob cts.type = CTS_TYPE_CURRENT_SETTINGS; 2878ab163f5fSMatt Jacob cts.protocol = PROTO_SCSI; 2879ab163f5fSMatt Jacob cts.transport = XPORT_SPI; 2880ab163f5fSMatt Jacob 2881ab163f5fSMatt Jacob scsi = &cts.proto_specific.scsi; 2882ab163f5fSMatt Jacob spi = &cts.xport_specific.spi; 2883ab163f5fSMatt Jacob 2884ab163f5fSMatt Jacob if (flags & DPARM_TQING) { 2885ab163f5fSMatt Jacob scsi->valid |= CTS_SCSI_VALID_TQ; 2886ab163f5fSMatt Jacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 2887ab163f5fSMatt Jacob spi->flags |= CTS_SPI_FLAGS_TAG_ENB; 2888ab163f5fSMatt Jacob } 2889ab163f5fSMatt Jacob 2890cbf57b47SMatt Jacob if (flags & DPARM_DISC) { 2891ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_DISC; 2892ab163f5fSMatt Jacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 2893ab163f5fSMatt Jacob } 2894ab163f5fSMatt Jacob spi->flags |= CTS_SPI_VALID_BUS_WIDTH; 2895ab163f5fSMatt Jacob if (flags & DPARM_WIDE) { 2896ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2897ab163f5fSMatt Jacob } else { 2898ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2899ab163f5fSMatt Jacob } 2900ab163f5fSMatt Jacob if (flags & DPARM_SYNC) { 2901ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 2902ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 29039ce9bdafSMatt Jacob spi->sync_period = sdp->isp_devparam[tgt].actv_period; 29049ce9bdafSMatt Jacob spi->sync_offset = sdp->isp_devparam[tgt].actv_offset; 2905ab163f5fSMatt Jacob } 2906ab163f5fSMatt Jacob #else 2907ab163f5fSMatt Jacob cts.flags = CCB_TRANS_CURRENT_SETTINGS; 2908ab163f5fSMatt Jacob cts.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2909ab163f5fSMatt Jacob if (flags & DPARM_DISC) { 2910ab163f5fSMatt Jacob cts.flags |= CCB_TRANS_DISC_ENB; 2911cbf57b47SMatt Jacob } 2912cbf57b47SMatt Jacob if (flags & DPARM_TQING) { 2913ab163f5fSMatt Jacob cts.flags |= CCB_TRANS_TAG_ENB; 2914cbf57b47SMatt Jacob } 2915ab163f5fSMatt Jacob cts.valid |= CCB_TRANS_BUS_WIDTH_VALID; 2916ab163f5fSMatt Jacob cts.bus_width = (flags & DPARM_WIDE)? 2917cbf57b47SMatt Jacob MSG_EXT_WDTR_BUS_8_BIT : MSG_EXT_WDTR_BUS_16_BIT; 29189ce9bdafSMatt Jacob cts.sync_period = sdp->isp_devparam[tgt].actv_period; 29199ce9bdafSMatt Jacob cts.sync_offset = sdp->isp_devparam[tgt].actv_offset; 2920cbf57b47SMatt Jacob if (flags & DPARM_SYNC) { 2921ab163f5fSMatt Jacob cts.valid |= 29224394c92fSMatt Jacob CCB_TRANS_SYNC_RATE_VALID | 2923cbf57b47SMatt Jacob CCB_TRANS_SYNC_OFFSET_VALID; 2924cbf57b47SMatt Jacob } 2925ab163f5fSMatt Jacob #endif 2926b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2927b09b0095SMatt Jacob "NEW_TGT_PARAMS bus %d tgt %d period %x offset %x flags %x", 29289ce9bdafSMatt Jacob bus, tgt, sdp->isp_devparam[tgt].actv_period, 29299ce9bdafSMatt Jacob sdp->isp_devparam[tgt].actv_offset, flags); 2930ab163f5fSMatt Jacob xpt_setup_ccb(&cts.ccb_h, tmppath, 1); 29315d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2932ab163f5fSMatt Jacob xpt_async(AC_TRANSFER_NEG, tmppath, &cts); 2933cbf57b47SMatt Jacob xpt_free_path(tmppath); 2934f44257c2SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2935cbf57b47SMatt Jacob break; 29360470d791SMatt Jacob } 293757c801f5SMatt Jacob case ISPASYNC_BUS_RESET: 2938ea6f23cdSMatt Jacob bus = *((int *)arg); 2939b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected", 2940b09b0095SMatt Jacob bus); 2941ea6f23cdSMatt Jacob if (bus > 0 && isp->isp_path2) { 29425d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2943ea6f23cdSMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); 29445d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2945ea6f23cdSMatt Jacob } else if (isp->isp_path) { 29465d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 294757c801f5SMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path, NULL); 29485d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 294957c801f5SMatt Jacob } 295057c801f5SMatt Jacob break; 29515d571944SMatt Jacob case ISPASYNC_LIP: 29525d571944SMatt Jacob if (isp->isp_path) { 2953fdeb9f2fSMatt Jacob isp_freeze_loopdown(isp, "ISPASYNC_LIP"); 29545d571944SMatt Jacob } 29555d571944SMatt Jacob isp_prt(isp, ISP_LOGINFO, "LIP Received"); 29565d571944SMatt Jacob break; 29575d571944SMatt Jacob case ISPASYNC_LOOP_RESET: 29585d571944SMatt Jacob if (isp->isp_path) { 2959fdeb9f2fSMatt Jacob isp_freeze_loopdown(isp, "ISPASYNC_LOOP_RESET"); 29605d571944SMatt Jacob } 29615d571944SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop Reset Received"); 29625d571944SMatt Jacob break; 296357c801f5SMatt Jacob case ISPASYNC_LOOP_DOWN: 296457c801f5SMatt Jacob if (isp->isp_path) { 2965fdeb9f2fSMatt Jacob isp_freeze_loopdown(isp, "ISPASYNC_LOOP_DOWN"); 296657c801f5SMatt Jacob } 2967b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop DOWN"); 296857c801f5SMatt Jacob break; 296957c801f5SMatt Jacob case ISPASYNC_LOOP_UP: 29705d571944SMatt Jacob /* 29715d571944SMatt Jacob * Now we just note that Loop has come up. We don't 29725d571944SMatt Jacob * actually do anything because we're waiting for a 29735d571944SMatt Jacob * Change Notify before activating the FC cleanup 29745d571944SMatt Jacob * thread to look at the state of the loop again. 29755d571944SMatt Jacob */ 2976b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop UP"); 297757c801f5SMatt Jacob break; 2978d6e5500fSMatt Jacob case ISPASYNC_PROMENADE: 29790470d791SMatt Jacob { 2980b09b0095SMatt Jacob const char *fmt = "Target %d (Loop 0x%x) Port ID 0x%x " 2981d6e5500fSMatt Jacob "(role %s) %s\n Port WWN 0x%08x%08x\n Node WWN 0x%08x%08x"; 2982d6e5500fSMatt Jacob static const char *roles[4] = { 29830470d791SMatt Jacob "(none)", "Target", "Initiator", "Target/Initiator" 298457c801f5SMatt Jacob }; 298502ab3379SMatt Jacob fcparam *fcp = isp->isp_param; 298602ab3379SMatt Jacob int tgt = *((int *) arg); 29879cd7268eSMatt Jacob #if __FreeBSD_version >= 500000 2988f44257c2SMatt Jacob int is_tgt_mask = (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT); 29899cd7268eSMatt Jacob struct cam_path *tmppath; 29909cd7268eSMatt Jacob #endif 299102ab3379SMatt Jacob struct lportdb *lp = &fcp->portdb[tgt]; 299202ab3379SMatt Jacob 2993b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, fmt, tgt, lp->loopid, lp->portid, 2994d6e5500fSMatt Jacob roles[lp->roles & 0x3], 2995d6e5500fSMatt Jacob (lp->valid)? "Arrived" : "Departed", 29961dae40ebSMatt Jacob (uint32_t) (lp->port_wwn >> 32), 29971dae40ebSMatt Jacob (uint32_t) (lp->port_wwn & 0xffffffffLL), 29981dae40ebSMatt Jacob (uint32_t) (lp->node_wwn >> 32), 29991dae40ebSMatt Jacob (uint32_t) (lp->node_wwn & 0xffffffffLL)); 3000ab163f5fSMatt Jacob 300145c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 30029cd7268eSMatt Jacob #if __FreeBSD_version >= 500000 3003ab163f5fSMatt Jacob if (xpt_create_path(&tmppath, NULL, cam_sim_path(isp->isp_sim), 3004ab163f5fSMatt Jacob (target_id_t)tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 300545c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 3006ab163f5fSMatt Jacob break; 3007ab163f5fSMatt Jacob } 3008f44257c2SMatt Jacob /* 3009f44257c2SMatt Jacob * Policy: only announce targets. 3010f44257c2SMatt Jacob */ 3011f44257c2SMatt Jacob if (lp->roles & is_tgt_mask) { 3012f44257c2SMatt Jacob if (lp->valid) { 3013ab163f5fSMatt Jacob xpt_async(AC_FOUND_DEVICE, tmppath, NULL); 3014ab163f5fSMatt Jacob } else { 3015ab163f5fSMatt Jacob xpt_async(AC_LOST_DEVICE, tmppath, NULL); 3016ab163f5fSMatt Jacob } 3017f44257c2SMatt Jacob } 3018ab163f5fSMatt Jacob xpt_free_path(tmppath); 30199cd7268eSMatt Jacob #endif 3020f44257c2SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 30214394c92fSMatt Jacob break; 30224394c92fSMatt Jacob } 302357c801f5SMatt Jacob case ISPASYNC_CHANGE_NOTIFY: 3024f44257c2SMatt Jacob if (arg == ISPASYNC_CHANGE_PDB) { 30254b9d588eSMatt Jacob isp_prt(isp, ISP_LOGINFO, 3026f44257c2SMatt Jacob "Port Database Changed"); 3027f44257c2SMatt Jacob } else if (arg == ISPASYNC_CHANGE_SNS) { 30284b9d588eSMatt Jacob isp_prt(isp, ISP_LOGINFO, 30294b9d588eSMatt Jacob "Name Server Database Changed"); 30304b9d588eSMatt Jacob } 30319cd7268eSMatt Jacob #if __FreeBSD_version < 500000 30329cd7268eSMatt Jacob wakeup(&isp->isp_osinfo.kproc); 30339cd7268eSMatt Jacob #else 3034162e9893SMatt Jacob #ifdef ISP_SMPLOCK 30355d571944SMatt Jacob cv_signal(&isp->isp_osinfo.kthread_cv); 3036162e9893SMatt Jacob #else 3037162e9893SMatt Jacob wakeup(&isp->isp_osinfo.kthread_cv); 3038162e9893SMatt Jacob #endif 30399cd7268eSMatt Jacob #endif 304057c801f5SMatt Jacob break; 304102ab3379SMatt Jacob case ISPASYNC_FABRIC_DEV: 304202ab3379SMatt Jacob { 3043029f13c6SMatt Jacob int target, base, lim; 304402ab3379SMatt Jacob fcparam *fcp = isp->isp_param; 3045029f13c6SMatt Jacob struct lportdb *lp = NULL; 3046029f13c6SMatt Jacob struct lportdb *clp = (struct lportdb *) arg; 3047029f13c6SMatt Jacob char *pt; 304802ab3379SMatt Jacob 3049029f13c6SMatt Jacob switch (clp->port_type) { 305040cfc8feSMatt Jacob case 1: 305140cfc8feSMatt Jacob pt = " N_Port"; 305240cfc8feSMatt Jacob break; 305340cfc8feSMatt Jacob case 2: 305440cfc8feSMatt Jacob pt = " NL_Port"; 305540cfc8feSMatt Jacob break; 305640cfc8feSMatt Jacob case 3: 305740cfc8feSMatt Jacob pt = "F/NL_Port"; 305840cfc8feSMatt Jacob break; 305940cfc8feSMatt Jacob case 0x7f: 306040cfc8feSMatt Jacob pt = " Nx_Port"; 306140cfc8feSMatt Jacob break; 306240cfc8feSMatt Jacob case 0x81: 306340cfc8feSMatt Jacob pt = " F_port"; 306440cfc8feSMatt Jacob break; 306540cfc8feSMatt Jacob case 0x82: 306640cfc8feSMatt Jacob pt = " FL_Port"; 306740cfc8feSMatt Jacob break; 306840cfc8feSMatt Jacob case 0x84: 306940cfc8feSMatt Jacob pt = " E_port"; 307040cfc8feSMatt Jacob break; 307140cfc8feSMatt Jacob default: 3072029f13c6SMatt Jacob pt = " "; 307340cfc8feSMatt Jacob break; 307440cfc8feSMatt Jacob } 3075029f13c6SMatt Jacob 3076b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, 3077029f13c6SMatt Jacob "%s Fabric Device @ PortID 0x%x", pt, clp->portid); 3078029f13c6SMatt Jacob 307970d2ccceSMatt Jacob /* 3080029f13c6SMatt Jacob * If we don't have an initiator role we bail. 3081029f13c6SMatt Jacob * 3082029f13c6SMatt Jacob * We just use ISPASYNC_FABRIC_DEV for announcement purposes. 308370d2ccceSMatt Jacob */ 3084029f13c6SMatt Jacob 3085029f13c6SMatt Jacob if ((isp->isp_role & ISP_ROLE_INITIATOR) == 0) { 308602ab3379SMatt Jacob break; 308702ab3379SMatt Jacob } 3088029f13c6SMatt Jacob 3089029f13c6SMatt Jacob /* 3090029f13c6SMatt Jacob * Is this entry for us? If so, we bail. 3091029f13c6SMatt Jacob */ 3092029f13c6SMatt Jacob 3093029f13c6SMatt Jacob if (fcp->isp_portid == clp->portid) { 3094029f13c6SMatt Jacob break; 3095029f13c6SMatt Jacob } 3096029f13c6SMatt Jacob 3097029f13c6SMatt Jacob /* 3098029f13c6SMatt Jacob * Else, the default policy is to find room for it in 3099029f13c6SMatt Jacob * our local port database. Later, when we execute 3100029f13c6SMatt Jacob * the call to isp_pdb_sync either this newly arrived 3101029f13c6SMatt Jacob * or already logged in device will be (re)announced. 3102029f13c6SMatt Jacob */ 3103029f13c6SMatt Jacob 3104029f13c6SMatt Jacob if (fcp->isp_topo == TOPO_FL_PORT) 3105029f13c6SMatt Jacob base = FC_SNS_ID+1; 310670d2ccceSMatt Jacob else 3107029f13c6SMatt Jacob base = 0; 3108029f13c6SMatt Jacob 3109029f13c6SMatt Jacob if (fcp->isp_topo == TOPO_N_PORT) 3110029f13c6SMatt Jacob lim = 1; 3111029f13c6SMatt Jacob else 3112029f13c6SMatt Jacob lim = MAX_FC_TARG; 3113029f13c6SMatt Jacob 311470d2ccceSMatt Jacob /* 311570d2ccceSMatt Jacob * Is it already in our list? 311670d2ccceSMatt Jacob */ 3117029f13c6SMatt Jacob for (target = base; target < lim; target++) { 311870d2ccceSMatt Jacob if (target >= FL_PORT_ID && target <= FC_SNS_ID) { 311970d2ccceSMatt Jacob continue; 312070d2ccceSMatt Jacob } 312170d2ccceSMatt Jacob lp = &fcp->portdb[target]; 3122029f13c6SMatt Jacob if (lp->port_wwn == clp->port_wwn && 3123029f13c6SMatt Jacob lp->node_wwn == clp->node_wwn) { 312470d2ccceSMatt Jacob lp->fabric_dev = 1; 312570d2ccceSMatt Jacob break; 312670d2ccceSMatt Jacob } 312770d2ccceSMatt Jacob } 3128029f13c6SMatt Jacob if (target < lim) { 312902ab3379SMatt Jacob break; 313002ab3379SMatt Jacob } 3131029f13c6SMatt Jacob for (target = base; target < lim; target++) { 313270d2ccceSMatt Jacob if (target >= FL_PORT_ID && target <= FC_SNS_ID) { 313370d2ccceSMatt Jacob continue; 313470d2ccceSMatt Jacob } 313502ab3379SMatt Jacob lp = &fcp->portdb[target]; 313670d2ccceSMatt Jacob if (lp->port_wwn == 0) { 313702ab3379SMatt Jacob break; 313802ab3379SMatt Jacob } 313970d2ccceSMatt Jacob } 3140029f13c6SMatt Jacob if (target == lim) { 3141bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 3142029f13c6SMatt Jacob "out of space for fabric devices"); 314302ab3379SMatt Jacob break; 314402ab3379SMatt Jacob } 3145029f13c6SMatt Jacob lp->port_type = clp->port_type; 3146029f13c6SMatt Jacob lp->fc4_type = clp->fc4_type; 3147029f13c6SMatt Jacob lp->node_wwn = clp->node_wwn; 3148029f13c6SMatt Jacob lp->port_wwn = clp->port_wwn; 3149029f13c6SMatt Jacob lp->portid = clp->portid; 315070d2ccceSMatt Jacob lp->fabric_dev = 1; 315102ab3379SMatt Jacob break; 315202ab3379SMatt Jacob } 3153d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 3154e5265237SMatt Jacob case ISPASYNC_TARGET_NOTIFY: 3155d81ba9d5SMatt Jacob { 3156e5265237SMatt Jacob tmd_notify_t *nt = arg; 315764edff94SMatt Jacob isp_prt(isp, ISP_LOGALL, 3158e5265237SMatt Jacob "target notify code 0x%x", nt->nt_ncode); 3159d81ba9d5SMatt Jacob break; 3160d81ba9d5SMatt Jacob } 3161d81ba9d5SMatt Jacob case ISPASYNC_TARGET_ACTION: 3162d81ba9d5SMatt Jacob switch (((isphdr_t *)arg)->rqs_entry_type) { 3163cbf57b47SMatt Jacob default: 3164bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 3165bfbab170SMatt Jacob "event 0x%x for unhandled target action", 3166bfbab170SMatt Jacob ((isphdr_t *)arg)->rqs_entry_type); 3167d81ba9d5SMatt Jacob break; 3168570c7a3fSMatt Jacob case RQSTYPE_NOTIFY: 3169570c7a3fSMatt Jacob if (IS_SCSI(isp)) { 3170570c7a3fSMatt Jacob rv = isp_handle_platform_notify_scsi(isp, 3171570c7a3fSMatt Jacob (in_entry_t *) arg); 3172570c7a3fSMatt Jacob } else { 3173570c7a3fSMatt Jacob rv = isp_handle_platform_notify_fc(isp, 3174570c7a3fSMatt Jacob (in_fcentry_t *) arg); 3175570c7a3fSMatt Jacob } 3176570c7a3fSMatt Jacob break; 3177d81ba9d5SMatt Jacob case RQSTYPE_ATIO: 3178d81ba9d5SMatt Jacob rv = isp_handle_platform_atio(isp, (at_entry_t *) arg); 3179d81ba9d5SMatt Jacob break; 3180d81ba9d5SMatt Jacob case RQSTYPE_ATIO2: 3181d81ba9d5SMatt Jacob rv = isp_handle_platform_atio2(isp, (at2_entry_t *)arg); 3182d81ba9d5SMatt Jacob break; 3183d4a6993aSMatt Jacob case RQSTYPE_CTIO3: 3184d81ba9d5SMatt Jacob case RQSTYPE_CTIO2: 3185d81ba9d5SMatt Jacob case RQSTYPE_CTIO: 3186d81ba9d5SMatt Jacob rv = isp_handle_platform_ctio(isp, arg); 3187d81ba9d5SMatt Jacob break; 3188d81ba9d5SMatt Jacob case RQSTYPE_ENABLE_LUN: 3189d81ba9d5SMatt Jacob case RQSTYPE_MODIFY_LUN: 319067ff51f1SMatt Jacob isp_ledone(isp, (lun_entry_t *) arg); 3191d81ba9d5SMatt Jacob break; 3192d81ba9d5SMatt Jacob } 3193d81ba9d5SMatt Jacob break; 3194d81ba9d5SMatt Jacob #endif 3195ab163f5fSMatt Jacob case ISPASYNC_FW_CRASH: 3196ab163f5fSMatt Jacob { 31971dae40ebSMatt Jacob uint16_t mbox1, mbox6; 3198ab163f5fSMatt Jacob mbox1 = ISP_READ(isp, OUTMAILBOX1); 3199ab163f5fSMatt Jacob if (IS_DUALBUS(isp)) { 3200ab163f5fSMatt Jacob mbox6 = ISP_READ(isp, OUTMAILBOX6); 3201ab163f5fSMatt Jacob } else { 3202ab163f5fSMatt Jacob mbox6 = 0; 3203ab163f5fSMatt Jacob } 3204ab163f5fSMatt Jacob isp_prt(isp, ISP_LOGERR, 3205570c7a3fSMatt Jacob "Internal Firmware Error on bus %d @ RISC Address 0x%x", 3206ab163f5fSMatt Jacob mbox6, mbox1); 32078a5f89b9SMatt Jacob #ifdef ISP_FW_CRASH_DUMP 32088a5f89b9SMatt Jacob /* 32098a5f89b9SMatt Jacob * XXX: really need a thread to do this right. 32108a5f89b9SMatt Jacob */ 32118a5f89b9SMatt Jacob if (IS_FC(isp)) { 32128a5f89b9SMatt Jacob FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; 32138a5f89b9SMatt Jacob FCPARAM(isp)->isp_loopstate = LOOP_NIL; 32148a5f89b9SMatt Jacob isp_freeze_loopdown(isp, "f/w crash"); 32158a5f89b9SMatt Jacob isp_fw_dump(isp); 32168a5f89b9SMatt Jacob } 3217ab163f5fSMatt Jacob isp_reinit(isp); 32188a5f89b9SMatt Jacob isp_async(isp, ISPASYNC_FW_RESTARTED, NULL); 32198a5f89b9SMatt Jacob #endif 3220ab163f5fSMatt Jacob break; 3221ab163f5fSMatt Jacob } 3222be534d5fSMatt Jacob case ISPASYNC_UNHANDLED_RESPONSE: 3223be534d5fSMatt Jacob break; 3224d81ba9d5SMatt Jacob default: 3225b09b0095SMatt Jacob isp_prt(isp, ISP_LOGERR, "unknown isp_async event %d", cmd); 3226cbf57b47SMatt Jacob break; 3227cbf57b47SMatt Jacob } 3228cbf57b47SMatt Jacob return (rv); 3229cbf57b47SMatt Jacob } 3230cbf57b47SMatt Jacob 323192718a7fSMatt Jacob 323292718a7fSMatt Jacob /* 323392718a7fSMatt Jacob * Locks are held before coming here. 323492718a7fSMatt Jacob */ 323592718a7fSMatt Jacob void 32369cd7268eSMatt Jacob isp_uninit(ispsoftc_t *isp) 323792718a7fSMatt Jacob { 3238ea6f23cdSMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_RESET); 323992718a7fSMatt Jacob DISABLE_INTS(isp); 324092718a7fSMatt Jacob } 3241b09b0095SMatt Jacob 3242b09b0095SMatt Jacob void 32439cd7268eSMatt Jacob isp_prt(ispsoftc_t *isp, int level, const char *fmt, ...) 3244b09b0095SMatt Jacob { 3245b09b0095SMatt Jacob va_list ap; 3246b09b0095SMatt Jacob if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) { 3247b09b0095SMatt Jacob return; 3248b09b0095SMatt Jacob } 32493c75bb14SMatt Jacob printf("%s: ", device_get_nameunit(isp->isp_dev)); 3250b09b0095SMatt Jacob va_start(ap, fmt); 3251b09b0095SMatt Jacob vprintf(fmt, ap); 3252b09b0095SMatt Jacob va_end(ap); 3253b09b0095SMatt Jacob printf("\n"); 3254b09b0095SMatt Jacob } 3255