1098ca2bdSWarner Losh /*- 2e5265237SMatt Jacob * Copyright (c) 1997-2006 by Matthew Jacob 3e5265237SMatt Jacob * All rights reserved. 46054c3f6SMatt Jacob * 56054c3f6SMatt Jacob * Redistribution and use in source and binary forms, with or without 66054c3f6SMatt Jacob * modification, are permitted provided that the following conditions 76054c3f6SMatt Jacob * are met: 86054c3f6SMatt Jacob * 1. Redistributions of source code must retain the above copyright 96054c3f6SMatt Jacob * notice immediately at the beginning of the file, without modification, 106054c3f6SMatt Jacob * this list of conditions, and the following disclaimer. 11aa57fd6fSMatt Jacob * 2. The name of the author may not be used to endorse or promote products 12aa57fd6fSMatt Jacob * derived from this software without specific prior written permission. 136054c3f6SMatt Jacob * 146054c3f6SMatt Jacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 156054c3f6SMatt Jacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 166054c3f6SMatt Jacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 176054c3f6SMatt Jacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 186054c3f6SMatt Jacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 196054c3f6SMatt Jacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 206054c3f6SMatt Jacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 216054c3f6SMatt Jacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 226054c3f6SMatt Jacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 236054c3f6SMatt Jacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 246054c3f6SMatt Jacob * SUCH DAMAGE. 256054c3f6SMatt Jacob */ 26aad970f1SDavid E. O'Brien 27799881e0SMatt Jacob /* 28799881e0SMatt Jacob * Platform (FreeBSD) dependent common attachment code for Qlogic adapters. 29799881e0SMatt Jacob */ 30aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 31aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 326054c3f6SMatt Jacob #include <dev/isp/isp_freebsd.h> 335d571944SMatt Jacob #include <sys/unistd.h> 345d571944SMatt Jacob #include <sys/kthread.h> 353ea883b4SMatt Jacob #include <machine/stdarg.h> /* for use by isp_prt below */ 365d571944SMatt Jacob #include <sys/conf.h> 374eb49427SMatt Jacob #include <sys/module.h> 385d571944SMatt Jacob #include <sys/ioccom.h> 395d571944SMatt Jacob #include <dev/isp/isp_ioctl.h> 409311717dSMatt Jacob #if __FreeBSD_version >= 500000 419311717dSMatt Jacob #include <sys/sysctl.h> 4270273f90SMatt Jacob #else 4370273f90SMatt Jacob #include <sys/devicestat.h> 449311717dSMatt Jacob #endif 45f7c631bcSMatt Jacob #include <cam/cam_periph.h> 466c81a0aeSMatt Jacob #include <cam/cam_xpt_periph.h> 476054c3f6SMatt Jacob 48805e1f82SMatt Jacob #if !defined(CAM_NEW_TRAN_CODE) && __FreeBSD_version >= 700025 49805e1f82SMatt Jacob #define CAM_NEW_TRAN_CODE 1 50805e1f82SMatt Jacob #endif 51805e1f82SMatt Jacob 52a1bc34c6SMatt Jacob 534eb49427SMatt Jacob MODULE_VERSION(isp, 1); 5456c5b842SMark Murray MODULE_DEPEND(isp, cam, 1, 1, 1); 5573030e03SMatt Jacob int isp_announced = 0; 5610365e5aSMatt Jacob int isp_fabric_hysteresis = 5; 5710365e5aSMatt Jacob int isp_loop_down_limit = 300; /* default loop down limit */ 58f7c631bcSMatt Jacob int isp_change_is_bad = 0; /* "changed" devices are bad */ 59f7c631bcSMatt Jacob int isp_quickboot_time = 15; /* don't wait more than N secs for loop up */ 60f7c631bcSMatt Jacob int isp_gone_device_time = 30; /* grace time before reporting device lost */ 61f7c631bcSMatt Jacob static const char *roles[4] = { 62f7c631bcSMatt Jacob "(none)", "Target", "Initiator", "Target/Initiator" 63f7c631bcSMatt Jacob }; 64f7c631bcSMatt Jacob static const char prom3[] = 65f7c631bcSMatt Jacob "PortID 0x%06x Departed from Target %u because of %s"; 6673030e03SMatt Jacob 67f7c631bcSMatt Jacob static void isp_freeze_loopdown(ispsoftc_t *, char *); 685d571944SMatt Jacob static d_ioctl_t ispioctl; 69f6e75de2SMatt Jacob static void isp_intr_enable(void *); 701dae40ebSMatt Jacob static void isp_cam_async(void *, uint32_t, struct cam_path *, void *); 710470d791SMatt Jacob static void isp_poll(struct cam_sim *); 72b85389e1SMatt Jacob static timeout_t isp_watchdog; 73f7c631bcSMatt Jacob static timeout_t isp_ldt; 745d571944SMatt Jacob static void isp_kthread(void *); 75d81ba9d5SMatt Jacob static void isp_action(struct cam_sim *, union ccb *); 760470d791SMatt Jacob 77784ed707SMatt Jacob #if __FreeBSD_version < 700000 78784ed707SMatt Jacob ispfwfunc *isp_get_firmware_p = NULL; 79784ed707SMatt Jacob #endif 80cc8df88bSMatt Jacob 819cd7268eSMatt Jacob #if __FreeBSD_version < 500000 829cd7268eSMatt Jacob #define ISP_CDEV_MAJOR 248 839cd7268eSMatt Jacob static struct cdevsw isp_cdevsw = { 849cd7268eSMatt Jacob /* open */ nullopen, 859cd7268eSMatt Jacob /* close */ nullclose, 869cd7268eSMatt Jacob /* read */ noread, 879cd7268eSMatt Jacob /* write */ nowrite, 889cd7268eSMatt Jacob /* ioctl */ ispioctl, 899cd7268eSMatt Jacob /* poll */ nopoll, 909cd7268eSMatt Jacob /* mmap */ nommap, 919cd7268eSMatt Jacob /* strategy */ nostrategy, 929cd7268eSMatt Jacob /* name */ "isp", 939cd7268eSMatt Jacob /* maj */ ISP_CDEV_MAJOR, 949cd7268eSMatt Jacob /* dump */ nodump, 959cd7268eSMatt Jacob /* psize */ nopsize, 969cd7268eSMatt Jacob /* flags */ D_TAPE, 979cd7268eSMatt Jacob }; 989311717dSMatt Jacob #define isp_sysctl_update(x) do { ; } while (0) 999cd7268eSMatt Jacob #else 1005d571944SMatt Jacob static struct cdevsw isp_cdevsw = { 101dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 1020a70657fSMatt Jacob #if __FreeBSD_version < 700037 103dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, 1040a70657fSMatt Jacob #endif 1057ac40f5fSPoul-Henning Kamp .d_ioctl = ispioctl, 1067ac40f5fSPoul-Henning Kamp .d_name = "isp", 1075d571944SMatt Jacob }; 1089311717dSMatt Jacob static void isp_sysctl_update(ispsoftc_t *); 1099cd7268eSMatt Jacob #endif 1105d571944SMatt Jacob 1119cd7268eSMatt Jacob static ispsoftc_t *isplist = NULL; 112478f8a96SJustin T. Gibbs 113478f8a96SJustin T. Gibbs void 1149cd7268eSMatt Jacob isp_attach(ispsoftc_t *isp) 115478f8a96SJustin T. Gibbs { 116ea6f23cdSMatt Jacob int primary, secondary; 117478f8a96SJustin T. Gibbs struct ccb_setasync csa; 118478f8a96SJustin T. Gibbs struct cam_devq *devq; 119ea6f23cdSMatt Jacob struct cam_sim *sim; 120ea6f23cdSMatt Jacob struct cam_path *path; 121478f8a96SJustin T. Gibbs 122478f8a96SJustin T. Gibbs /* 123ea6f23cdSMatt Jacob * Establish (in case of 12X0) which bus is the primary. 124ea6f23cdSMatt Jacob */ 125ea6f23cdSMatt Jacob 126ea6f23cdSMatt Jacob primary = 0; 127ea6f23cdSMatt Jacob secondary = 1; 128ea6f23cdSMatt Jacob 129ea6f23cdSMatt Jacob /* 130ea6f23cdSMatt Jacob * Create the device queue for our SIM(s). 131478f8a96SJustin T. Gibbs */ 132ab6c4b31SMatt Jacob devq = cam_simq_alloc(isp->isp_maxcmds); 133478f8a96SJustin T. Gibbs if (devq == NULL) { 134478f8a96SJustin T. Gibbs return; 135478f8a96SJustin T. Gibbs } 136478f8a96SJustin T. Gibbs 137478f8a96SJustin T. Gibbs /* 138ea6f23cdSMatt Jacob * Construct our SIM entry. 139478f8a96SJustin T. Gibbs */ 1400a70657fSMatt Jacob sim = isp_sim_alloc(isp_action, isp_poll, "isp", isp, 1410a70657fSMatt Jacob device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq); 142ea6f23cdSMatt Jacob if (sim == NULL) { 143478f8a96SJustin T. Gibbs cam_simq_free(devq); 144478f8a96SJustin T. Gibbs return; 145478f8a96SJustin T. Gibbs } 146f6e75de2SMatt Jacob 147f6e75de2SMatt Jacob isp->isp_osinfo.ehook.ich_func = isp_intr_enable; 148f6e75de2SMatt Jacob isp->isp_osinfo.ehook.ich_arg = isp; 149abeda21eSMatt Jacob ISP_UNLOCK(isp); 150f6e75de2SMatt Jacob if (config_intrhook_establish(&isp->isp_osinfo.ehook) != 0) { 151abeda21eSMatt Jacob ISP_LOCK(isp); 15245c9a36aSMatt Jacob cam_sim_free(sim, TRUE); 153bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 154bfbab170SMatt Jacob "could not establish interrupt enable hook"); 155f6e75de2SMatt Jacob return; 156f6e75de2SMatt Jacob } 157abeda21eSMatt Jacob ISP_LOCK(isp); 158f6e75de2SMatt Jacob 159ea6f23cdSMatt Jacob if (xpt_bus_register(sim, primary) != CAM_SUCCESS) { 160ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 161478f8a96SJustin T. Gibbs return; 162478f8a96SJustin T. Gibbs } 163478f8a96SJustin T. Gibbs 164ea6f23cdSMatt Jacob if (xpt_create_path(&path, NULL, cam_sim_path(sim), 165478f8a96SJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 166ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 167ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 1685d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 169478f8a96SJustin T. Gibbs return; 170478f8a96SJustin T. Gibbs } 171478f8a96SJustin T. Gibbs 172ea6f23cdSMatt Jacob xpt_setup_ccb(&csa.ccb_h, path, 5); 173478f8a96SJustin T. Gibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 174478f8a96SJustin T. Gibbs csa.event_enable = AC_LOST_DEVICE; 175cbf57b47SMatt Jacob csa.callback = isp_cam_async; 176ea6f23cdSMatt Jacob csa.callback_arg = sim; 177478f8a96SJustin T. Gibbs xpt_action((union ccb *)&csa); 178ea6f23cdSMatt Jacob isp->isp_sim = sim; 179ea6f23cdSMatt Jacob isp->isp_path = path; 180478f8a96SJustin T. Gibbs 181ea6f23cdSMatt Jacob /* 182ea6f23cdSMatt Jacob * If we have a second channel, construct SIM entry for that. 183ea6f23cdSMatt Jacob */ 18422e1dc85SMatt Jacob if (IS_DUALBUS(isp)) { 1850a70657fSMatt Jacob sim = isp_sim_alloc(isp_action, isp_poll, "isp", isp, 1860a70657fSMatt Jacob device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq); 187ea6f23cdSMatt Jacob if (sim == NULL) { 188ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 189ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 190ea6f23cdSMatt Jacob cam_simq_free(devq); 1915d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 192ea6f23cdSMatt Jacob return; 193ea6f23cdSMatt Jacob } 194ea6f23cdSMatt Jacob if (xpt_bus_register(sim, secondary) != CAM_SUCCESS) { 195ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 196ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 197ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 1985d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 199ea6f23cdSMatt Jacob return; 200ea6f23cdSMatt Jacob } 201ea6f23cdSMatt Jacob 202ea6f23cdSMatt Jacob if (xpt_create_path(&path, NULL, cam_sim_path(sim), 203ea6f23cdSMatt Jacob CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 204ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 205ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 206ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 207ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 2085d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 209ea6f23cdSMatt Jacob return; 210ea6f23cdSMatt Jacob } 211ea6f23cdSMatt Jacob 212ea6f23cdSMatt Jacob xpt_setup_ccb(&csa.ccb_h, path, 5); 213ea6f23cdSMatt Jacob csa.ccb_h.func_code = XPT_SASYNC_CB; 214ea6f23cdSMatt Jacob csa.event_enable = AC_LOST_DEVICE; 215ea6f23cdSMatt Jacob csa.callback = isp_cam_async; 216ea6f23cdSMatt Jacob csa.callback_arg = sim; 217ea6f23cdSMatt Jacob xpt_action((union ccb *)&csa); 218ea6f23cdSMatt Jacob isp->isp_sim2 = sim; 219ea6f23cdSMatt Jacob isp->isp_path2 = path; 220ea6f23cdSMatt Jacob } 2215d571944SMatt Jacob 2225d571944SMatt Jacob /* 2235d571944SMatt Jacob * Create device nodes 2245d571944SMatt Jacob */ 2250a70657fSMatt Jacob ISP_UNLOCK(isp); 2265d571944SMatt Jacob (void) make_dev(&isp_cdevsw, device_get_unit(isp->isp_dev), UID_ROOT, 2275d571944SMatt Jacob GID_OPERATOR, 0600, "%s", device_get_nameunit(isp->isp_dev)); 2280a70657fSMatt Jacob isp_sysctl_update(isp); 2290a70657fSMatt Jacob ISP_LOCK(isp); 2305d571944SMatt Jacob 231d6e5500fSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE) { 232478f8a96SJustin T. Gibbs isp->isp_state = ISP_RUNSTATE; 23310365e5aSMatt Jacob ISP_ENABLE_INTS(isp); 234d6e5500fSMatt Jacob } 235d81ba9d5SMatt Jacob if (isplist == NULL) { 236d81ba9d5SMatt Jacob isplist = isp; 237d81ba9d5SMatt Jacob } else { 2389cd7268eSMatt Jacob ispsoftc_t *tmp = isplist; 239d81ba9d5SMatt Jacob while (tmp->isp_osinfo.next) { 240d81ba9d5SMatt Jacob tmp = tmp->isp_osinfo.next; 241d81ba9d5SMatt Jacob } 242d81ba9d5SMatt Jacob tmp->isp_osinfo.next = isp; 243478f8a96SJustin T. Gibbs } 2440a70657fSMatt Jacob 2450a70657fSMatt Jacob /* 2460a70657fSMatt Jacob * Create a kernel thread for fibre channel instances. 2470a70657fSMatt Jacob */ 2480a70657fSMatt Jacob if (IS_FC(isp)) { 2490a70657fSMatt Jacob isp_callout_init(&isp->isp_osinfo.ldt); 2500a70657fSMatt Jacob isp_callout_init(&isp->isp_osinfo.gdt); 2510a70657fSMatt Jacob ISP_UNLOCK(isp); 2520a70657fSMatt Jacob #if __FreeBSD_version >= 500000 2530a70657fSMatt Jacob if (kthread_create(isp_kthread, isp, &isp->isp_osinfo.kproc, 2540a70657fSMatt Jacob RFHIGHPID, 0, "%s: fc_thrd", 2550a70657fSMatt Jacob device_get_nameunit(isp->isp_dev))) 2560a70657fSMatt Jacob #else 2570a70657fSMatt Jacob if (kthread_create(isp_kthread, isp, &isp->isp_osinfo.kproc, 2580a70657fSMatt Jacob "%s: fc_thrd", device_get_nameunit(isp->isp_dev))) 2590a70657fSMatt Jacob #endif 2600a70657fSMatt Jacob { 2610a70657fSMatt Jacob ISP_LOCK(isp); 2620a70657fSMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 2630a70657fSMatt Jacob cam_sim_free(sim, TRUE); 2640a70657fSMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 2650a70657fSMatt Jacob isp_prt(isp, ISP_LOGERR, "could not create kthread"); 2660a70657fSMatt Jacob return; 2670a70657fSMatt Jacob } 2680a70657fSMatt Jacob ISP_LOCK(isp); 2690a70657fSMatt Jacob /* 2700a70657fSMatt Jacob * We start by being "loop down" if we have an initiator role 2710a70657fSMatt Jacob */ 2720a70657fSMatt Jacob if (isp->isp_role & ISP_ROLE_INITIATOR) { 2730a70657fSMatt Jacob isp_freeze_loopdown(isp, "isp_attach"); 2740a70657fSMatt Jacob isp->isp_osinfo.ldt_running = 1; 2750a70657fSMatt Jacob callout_reset(&isp->isp_osinfo.ldt, 2760a70657fSMatt Jacob isp_quickboot_time * hz, isp_ldt, isp); 2770a70657fSMatt Jacob isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, 2780a70657fSMatt Jacob "Starting Initial Loop Down Timer"); 2790a70657fSMatt Jacob } 2800a70657fSMatt Jacob } 2815d571944SMatt Jacob } 2825d571944SMatt Jacob 283f7c631bcSMatt Jacob static void 2849cd7268eSMatt Jacob isp_freeze_loopdown(ispsoftc_t *isp, char *msg) 285fdeb9f2fSMatt Jacob { 286fdeb9f2fSMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 287fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "%s: freeze simq (loopdown)", msg); 288fdeb9f2fSMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; 289fdeb9f2fSMatt Jacob xpt_freeze_simq(isp->isp_sim, 1); 290fdeb9f2fSMatt Jacob } else { 291fdeb9f2fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "%s: mark frozen (loopdown)", msg); 292fdeb9f2fSMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; 293fdeb9f2fSMatt Jacob } 294fdeb9f2fSMatt Jacob } 295fdeb9f2fSMatt Jacob 2969cd7268eSMatt Jacob 2979cd7268eSMatt Jacob #if __FreeBSD_version < 500000 2989cd7268eSMatt Jacob #define _DEV dev_t 2999cd7268eSMatt Jacob #define _IOP struct proc 3009cd7268eSMatt Jacob #else 3019cd7268eSMatt Jacob #define _IOP struct thread 3029cd7268eSMatt Jacob #define _DEV struct cdev * 3039cd7268eSMatt Jacob #endif 3049cd7268eSMatt Jacob 3055d571944SMatt Jacob static int 3069cd7268eSMatt Jacob ispioctl(_DEV dev, u_long c, caddr_t addr, int flags, _IOP *td) 3075d571944SMatt Jacob { 3089cd7268eSMatt Jacob ispsoftc_t *isp; 309746e9c85SMatt Jacob int nr, retval = ENOTTY; 3100a70657fSMatt Jacob #if __FreeBSD_version < 500000 3110a70657fSMatt Jacob int s = splcam(); 3120a70657fSMatt Jacob #else 3130a70657fSMatt Jacob GIANT_REQUIRED; 3140a70657fSMatt Jacob #endif 3155d571944SMatt Jacob 3165d571944SMatt Jacob isp = isplist; 3175d571944SMatt Jacob while (isp) { 3185d571944SMatt Jacob if (minor(dev) == device_get_unit(isp->isp_dev)) { 3195d571944SMatt Jacob break; 3205d571944SMatt Jacob } 3215d571944SMatt Jacob isp = isp->isp_osinfo.next; 3225d571944SMatt Jacob } 3230a70657fSMatt Jacob if (isp == NULL) { 3240a70657fSMatt Jacob #if __FreeBSD_version < 500000 3250a70657fSMatt Jacob splx(s); 3260a70657fSMatt Jacob #endif 3275d571944SMatt Jacob return (ENXIO); 3280a70657fSMatt Jacob } 3295d571944SMatt Jacob 330c1504bc0SMatt Jacob switch (c) { 331d134aa0bSMatt Jacob #ifdef ISP_FW_CRASH_DUMP 332d134aa0bSMatt Jacob case ISP_GET_FW_CRASH_DUMP: 33302e2b2d9SMatt Jacob if (IS_FC(isp)) { 3341dae40ebSMatt Jacob uint16_t *ptr = FCPARAM(isp)->isp_dump_data; 335d134aa0bSMatt Jacob size_t sz; 336d134aa0bSMatt Jacob 337d134aa0bSMatt Jacob retval = 0; 33802e2b2d9SMatt Jacob if (IS_2200(isp)) { 339d134aa0bSMatt Jacob sz = QLA2200_RISC_IMAGE_DUMP_SIZE; 34002e2b2d9SMatt Jacob } else { 341d134aa0bSMatt Jacob sz = QLA2300_RISC_IMAGE_DUMP_SIZE; 34202e2b2d9SMatt Jacob } 343d134aa0bSMatt Jacob if (ptr && *ptr) { 344d134aa0bSMatt Jacob void *uaddr = *((void **) addr); 345d134aa0bSMatt Jacob if (copyout(ptr, uaddr, sz)) { 346d134aa0bSMatt Jacob retval = EFAULT; 347d134aa0bSMatt Jacob } else { 348d134aa0bSMatt Jacob *ptr = 0; 349d134aa0bSMatt Jacob } 350d134aa0bSMatt Jacob } else { 351d134aa0bSMatt Jacob retval = ENXIO; 352d134aa0bSMatt Jacob } 353d134aa0bSMatt Jacob } 35402e2b2d9SMatt Jacob break; 355d134aa0bSMatt Jacob case ISP_FORCE_CRASH_DUMP: 35602e2b2d9SMatt Jacob if (IS_FC(isp)) { 35702e2b2d9SMatt Jacob isp_freeze_loopdown(isp, 35802e2b2d9SMatt Jacob "ispioctl(ISP_FORCE_CRASH_DUMP)"); 359d134aa0bSMatt Jacob isp_fw_dump(isp); 360d134aa0bSMatt Jacob isp_reinit(isp); 361d134aa0bSMatt Jacob retval = 0; 36202e2b2d9SMatt Jacob } 363d134aa0bSMatt Jacob break; 364d134aa0bSMatt Jacob #endif 3655d571944SMatt Jacob case ISP_SDBLEV: 3665d571944SMatt Jacob { 3675d571944SMatt Jacob int olddblev = isp->isp_dblev; 3685d571944SMatt Jacob isp->isp_dblev = *(int *)addr; 3695d571944SMatt Jacob *(int *)addr = olddblev; 3705d571944SMatt Jacob retval = 0; 3715d571944SMatt Jacob break; 3725d571944SMatt Jacob } 373746e9c85SMatt Jacob case ISP_GETROLE: 374746e9c85SMatt Jacob *(int *)addr = isp->isp_role; 375746e9c85SMatt Jacob retval = 0; 376746e9c85SMatt Jacob break; 377746e9c85SMatt Jacob case ISP_SETROLE: 378746e9c85SMatt Jacob nr = *(int *)addr; 379746e9c85SMatt Jacob if (nr & ~(ISP_ROLE_INITIATOR|ISP_ROLE_TARGET)) { 380746e9c85SMatt Jacob retval = EINVAL; 381746e9c85SMatt Jacob break; 382746e9c85SMatt Jacob } 3839a1b0d43SMatt Jacob /* 3849a1b0d43SMatt Jacob * XXX: Current 3859a1b0d43SMatt Jacob */ 3869a1b0d43SMatt Jacob if (nr == ISP_ROLE_BOTH) { 3879a1b0d43SMatt Jacob isp_prt(isp, ISP_LOGERR, "dual roles not supported"); 3889a1b0d43SMatt Jacob retval = EINVAL; 3899a1b0d43SMatt Jacob break; 3909a1b0d43SMatt Jacob } 391746e9c85SMatt Jacob *(int *)addr = isp->isp_role; 392746e9c85SMatt Jacob isp->isp_role = nr; 393746e9c85SMatt Jacob /* FALLTHROUGH */ 3945d571944SMatt Jacob case ISP_RESETHBA: 3955d571944SMatt Jacob isp_reinit(isp); 3965d571944SMatt Jacob retval = 0; 3975d571944SMatt Jacob break; 398f553351eSMatt Jacob case ISP_RESCAN: 3995d571944SMatt Jacob if (IS_FC(isp)) { 4005d571944SMatt Jacob if (isp_fc_runstate(isp, 5 * 1000000)) { 4015d571944SMatt Jacob retval = EIO; 4025d571944SMatt Jacob } else { 4035d571944SMatt Jacob retval = 0; 4045d571944SMatt Jacob } 4055d571944SMatt Jacob } 4065d571944SMatt Jacob break; 4075d571944SMatt Jacob case ISP_FC_LIP: 4085d571944SMatt Jacob if (IS_FC(isp)) { 4095d571944SMatt Jacob if (isp_control(isp, ISPCTL_SEND_LIP, 0)) { 4105d571944SMatt Jacob retval = EIO; 4115d571944SMatt Jacob } else { 4125d571944SMatt Jacob retval = 0; 4135d571944SMatt Jacob } 4145d571944SMatt Jacob } 4155d571944SMatt Jacob break; 4165d571944SMatt Jacob case ISP_FC_GETDINFO: 4175d571944SMatt Jacob { 4185d571944SMatt Jacob struct isp_fc_device *ifc = (struct isp_fc_device *) addr; 41910365e5aSMatt Jacob fcportdb_t *lp; 4205d571944SMatt Jacob 42102e2b2d9SMatt Jacob if (IS_SCSI(isp)) { 42202e2b2d9SMatt Jacob break; 42302e2b2d9SMatt Jacob } 4245d571944SMatt Jacob if (ifc->loopid < 0 || ifc->loopid >= MAX_FC_TARG) { 4255d571944SMatt Jacob retval = EINVAL; 4265d571944SMatt Jacob break; 4275d571944SMatt Jacob } 4285d571944SMatt Jacob lp = &FCPARAM(isp)->portdb[ifc->loopid]; 42910365e5aSMatt Jacob if (lp->state == FC_PORTDB_STATE_VALID) { 430c6435ff3SMatt Jacob ifc->role = lp->roles; 43110365e5aSMatt Jacob ifc->loopid = lp->handle; 4325d571944SMatt Jacob ifc->portid = lp->portid; 4335d571944SMatt Jacob ifc->node_wwn = lp->node_wwn; 4345d571944SMatt Jacob ifc->port_wwn = lp->port_wwn; 4355d571944SMatt Jacob retval = 0; 4365d571944SMatt Jacob } else { 4375d571944SMatt Jacob retval = ENODEV; 4385d571944SMatt Jacob } 4395d571944SMatt Jacob break; 4405d571944SMatt Jacob } 4412903b272SMatt Jacob case ISP_GET_STATS: 4422903b272SMatt Jacob { 4432903b272SMatt Jacob isp_stats_t *sp = (isp_stats_t *) addr; 4442903b272SMatt Jacob 4452903b272SMatt Jacob MEMZERO(sp, sizeof (*sp)); 4462903b272SMatt Jacob sp->isp_stat_version = ISP_STATS_VERSION; 4472903b272SMatt Jacob sp->isp_type = isp->isp_type; 4482903b272SMatt Jacob sp->isp_revision = isp->isp_revision; 4492903b272SMatt Jacob sp->isp_stats[ISP_INTCNT] = isp->isp_intcnt; 4502903b272SMatt Jacob sp->isp_stats[ISP_INTBOGUS] = isp->isp_intbogus; 4512903b272SMatt Jacob sp->isp_stats[ISP_INTMBOXC] = isp->isp_intmboxc; 4522903b272SMatt Jacob sp->isp_stats[ISP_INGOASYNC] = isp->isp_intoasync; 4532903b272SMatt Jacob sp->isp_stats[ISP_RSLTCCMPLT] = isp->isp_rsltccmplt; 4542903b272SMatt Jacob sp->isp_stats[ISP_FPHCCMCPLT] = isp->isp_fphccmplt; 4552903b272SMatt Jacob sp->isp_stats[ISP_RSCCHIWAT] = isp->isp_rscchiwater; 4562903b272SMatt Jacob sp->isp_stats[ISP_FPCCHIWAT] = isp->isp_fpcchiwater; 4572903b272SMatt Jacob retval = 0; 4582903b272SMatt Jacob break; 4592903b272SMatt Jacob } 4602903b272SMatt Jacob case ISP_CLR_STATS: 4612903b272SMatt Jacob isp->isp_intcnt = 0; 4622903b272SMatt Jacob isp->isp_intbogus = 0; 4632903b272SMatt Jacob isp->isp_intmboxc = 0; 4642903b272SMatt Jacob isp->isp_intoasync = 0; 4652903b272SMatt Jacob isp->isp_rsltccmplt = 0; 4662903b272SMatt Jacob isp->isp_fphccmplt = 0; 4672903b272SMatt Jacob isp->isp_rscchiwater = 0; 4682903b272SMatt Jacob isp->isp_fpcchiwater = 0; 4692903b272SMatt Jacob retval = 0; 4702903b272SMatt Jacob break; 471570c7a3fSMatt Jacob case ISP_FC_GETHINFO: 472570c7a3fSMatt Jacob { 473570c7a3fSMatt Jacob struct isp_hba_device *hba = (struct isp_hba_device *) addr; 474570c7a3fSMatt Jacob MEMZERO(hba, sizeof (*hba)); 47502e2b2d9SMatt Jacob 476a556b68eSMatt Jacob hba->fc_fw_major = ISP_FW_MAJORX(isp->isp_fwrev); 477a556b68eSMatt Jacob hba->fc_fw_minor = ISP_FW_MINORX(isp->isp_fwrev); 478a556b68eSMatt Jacob hba->fc_fw_micro = ISP_FW_MICROX(isp->isp_fwrev); 47902e2b2d9SMatt Jacob if (IS_FC(isp)) { 480570c7a3fSMatt Jacob hba->fc_speed = FCPARAM(isp)->isp_gbspeed; 481570c7a3fSMatt Jacob hba->fc_scsi_supported = 1; 482570c7a3fSMatt Jacob hba->fc_topology = FCPARAM(isp)->isp_topo + 1; 483570c7a3fSMatt Jacob hba->fc_loopid = FCPARAM(isp)->isp_loopid; 4846c81a0aeSMatt Jacob hba->nvram_node_wwn = FCPARAM(isp)->isp_wwnn_nvram; 4856c81a0aeSMatt Jacob hba->nvram_port_wwn = FCPARAM(isp)->isp_wwpn_nvram; 486fd6eb9f7SMatt Jacob hba->active_node_wwn = ISP_NODEWWN(isp); 487fd6eb9f7SMatt Jacob hba->active_port_wwn = ISP_PORTWWN(isp); 48802e2b2d9SMatt Jacob } 489570c7a3fSMatt Jacob retval = 0; 490570c7a3fSMatt Jacob break; 491570c7a3fSMatt Jacob } 492fdeb9f2fSMatt Jacob case ISP_GET_FC_PARAM: 493fdeb9f2fSMatt Jacob { 494fdeb9f2fSMatt Jacob struct isp_fc_param *f = (struct isp_fc_param *) addr; 495fdeb9f2fSMatt Jacob 49602e2b2d9SMatt Jacob if (IS_SCSI(isp)) { 497fdeb9f2fSMatt Jacob break; 498fdeb9f2fSMatt Jacob } 499fdeb9f2fSMatt Jacob f->parameter = 0; 500fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "framelength") == 0) { 501fdeb9f2fSMatt Jacob f->parameter = FCPARAM(isp)->isp_maxfrmlen; 502fdeb9f2fSMatt Jacob retval = 0; 503fdeb9f2fSMatt Jacob break; 504fdeb9f2fSMatt Jacob } 505fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "exec_throttle") == 0) { 506fdeb9f2fSMatt Jacob f->parameter = FCPARAM(isp)->isp_execthrottle; 507fdeb9f2fSMatt Jacob retval = 0; 508fdeb9f2fSMatt Jacob break; 509fdeb9f2fSMatt Jacob } 510fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "fullduplex") == 0) { 511fdeb9f2fSMatt Jacob if (FCPARAM(isp)->isp_fwoptions & ICBOPT_FULL_DUPLEX) 512fdeb9f2fSMatt Jacob f->parameter = 1; 513fdeb9f2fSMatt Jacob retval = 0; 514fdeb9f2fSMatt Jacob break; 515fdeb9f2fSMatt Jacob } 516fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "loopid") == 0) { 517fdeb9f2fSMatt Jacob f->parameter = FCPARAM(isp)->isp_loopid; 518fdeb9f2fSMatt Jacob retval = 0; 519fdeb9f2fSMatt Jacob break; 520fdeb9f2fSMatt Jacob } 521fdeb9f2fSMatt Jacob retval = EINVAL; 522fdeb9f2fSMatt Jacob break; 523fdeb9f2fSMatt Jacob } 524fdeb9f2fSMatt Jacob case ISP_SET_FC_PARAM: 525fdeb9f2fSMatt Jacob { 526fdeb9f2fSMatt Jacob struct isp_fc_param *f = (struct isp_fc_param *) addr; 5271dae40ebSMatt Jacob uint32_t param = f->parameter; 528fdeb9f2fSMatt Jacob 52902e2b2d9SMatt Jacob if (IS_SCSI(isp)) { 530fdeb9f2fSMatt Jacob break; 531fdeb9f2fSMatt Jacob } 532fdeb9f2fSMatt Jacob f->parameter = 0; 533fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "framelength") == 0) { 534fdeb9f2fSMatt Jacob if (param != 512 && param != 1024 && param != 1024) { 535fdeb9f2fSMatt Jacob retval = EINVAL; 536fdeb9f2fSMatt Jacob break; 537fdeb9f2fSMatt Jacob } 538fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_maxfrmlen = param; 539fdeb9f2fSMatt Jacob retval = 0; 540fdeb9f2fSMatt Jacob break; 541fdeb9f2fSMatt Jacob } 542fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "exec_throttle") == 0) { 543fdeb9f2fSMatt Jacob if (param < 16 || param > 255) { 544fdeb9f2fSMatt Jacob retval = EINVAL; 545fdeb9f2fSMatt Jacob break; 546fdeb9f2fSMatt Jacob } 547fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_execthrottle = param; 548fdeb9f2fSMatt Jacob retval = 0; 549fdeb9f2fSMatt Jacob break; 550fdeb9f2fSMatt Jacob } 551fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "fullduplex") == 0) { 552fdeb9f2fSMatt Jacob if (param != 0 && param != 1) { 553fdeb9f2fSMatt Jacob retval = EINVAL; 554fdeb9f2fSMatt Jacob break; 555fdeb9f2fSMatt Jacob } 556fdeb9f2fSMatt Jacob if (param) { 557fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_fwoptions |= 558fdeb9f2fSMatt Jacob ICBOPT_FULL_DUPLEX; 559fdeb9f2fSMatt Jacob } else { 560fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_fwoptions &= 561fdeb9f2fSMatt Jacob ~ICBOPT_FULL_DUPLEX; 562fdeb9f2fSMatt Jacob } 563fdeb9f2fSMatt Jacob retval = 0; 564fdeb9f2fSMatt Jacob break; 565fdeb9f2fSMatt Jacob } 566fdeb9f2fSMatt Jacob if (strcmp(f->param_name, "loopid") == 0) { 567fdeb9f2fSMatt Jacob if (param < 0 || param > 125) { 568fdeb9f2fSMatt Jacob retval = EINVAL; 569fdeb9f2fSMatt Jacob break; 570fdeb9f2fSMatt Jacob } 571fdeb9f2fSMatt Jacob FCPARAM(isp)->isp_loopid = param; 572fdeb9f2fSMatt Jacob retval = 0; 573fdeb9f2fSMatt Jacob break; 574fdeb9f2fSMatt Jacob } 575fdeb9f2fSMatt Jacob retval = EINVAL; 576fdeb9f2fSMatt Jacob break; 577fdeb9f2fSMatt Jacob } 5788e62a8acSMatt Jacob case ISP_TSK_MGMT: 5798e62a8acSMatt Jacob { 5808e62a8acSMatt Jacob int needmarker; 5818e62a8acSMatt Jacob struct isp_fc_tsk_mgmt *fct = (struct isp_fc_tsk_mgmt *) addr; 5821dae40ebSMatt Jacob uint16_t loopid; 5838e62a8acSMatt Jacob mbreg_t mbs; 5848e62a8acSMatt Jacob 5858e62a8acSMatt Jacob if (IS_SCSI(isp)) { 5868e62a8acSMatt Jacob break; 5878e62a8acSMatt Jacob } 5888e62a8acSMatt Jacob 5898e62a8acSMatt Jacob memset(&mbs, 0, sizeof (mbs)); 5908e62a8acSMatt Jacob needmarker = retval = 0; 591e5265237SMatt Jacob loopid = fct->loopid; 59210365e5aSMatt Jacob if (FCPARAM(isp)->isp_2klogin == 0) { 593e5265237SMatt Jacob loopid <<= 8; 594e5265237SMatt Jacob } 5958e62a8acSMatt Jacob switch (fct->action) { 596f0f536d1SMatt Jacob case IPT_CLEAR_ACA: 5978e62a8acSMatt Jacob mbs.param[0] = MBOX_CLEAR_ACA; 598e5265237SMatt Jacob mbs.param[1] = loopid; 5998e62a8acSMatt Jacob mbs.param[2] = fct->lun; 6008e62a8acSMatt Jacob break; 601f0f536d1SMatt Jacob case IPT_TARGET_RESET: 6028e62a8acSMatt Jacob mbs.param[0] = MBOX_TARGET_RESET; 603e5265237SMatt Jacob mbs.param[1] = loopid; 6048e62a8acSMatt Jacob needmarker = 1; 6058e62a8acSMatt Jacob break; 606f0f536d1SMatt Jacob case IPT_LUN_RESET: 6078e62a8acSMatt Jacob mbs.param[0] = MBOX_LUN_RESET; 608e5265237SMatt Jacob mbs.param[1] = loopid; 6098e62a8acSMatt Jacob mbs.param[2] = fct->lun; 6108e62a8acSMatt Jacob needmarker = 1; 6118e62a8acSMatt Jacob break; 612f0f536d1SMatt Jacob case IPT_CLEAR_TASK_SET: 6138e62a8acSMatt Jacob mbs.param[0] = MBOX_CLEAR_TASK_SET; 614e5265237SMatt Jacob mbs.param[1] = loopid; 6158e62a8acSMatt Jacob mbs.param[2] = fct->lun; 6168e62a8acSMatt Jacob needmarker = 1; 6178e62a8acSMatt Jacob break; 618f0f536d1SMatt Jacob case IPT_ABORT_TASK_SET: 6198e62a8acSMatt Jacob mbs.param[0] = MBOX_ABORT_TASK_SET; 620e5265237SMatt Jacob mbs.param[1] = loopid; 6218e62a8acSMatt Jacob mbs.param[2] = fct->lun; 6228e62a8acSMatt Jacob needmarker = 1; 6238e62a8acSMatt Jacob break; 6248e62a8acSMatt Jacob default: 6258e62a8acSMatt Jacob retval = EINVAL; 6268e62a8acSMatt Jacob break; 6278e62a8acSMatt Jacob } 6288e62a8acSMatt Jacob if (retval == 0) { 6298e62a8acSMatt Jacob if (needmarker) { 6308e62a8acSMatt Jacob isp->isp_sendmarker |= 1; 6318e62a8acSMatt Jacob } 6328e62a8acSMatt Jacob retval = isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); 6338e62a8acSMatt Jacob if (retval) 6348e62a8acSMatt Jacob retval = EIO; 6358e62a8acSMatt Jacob } 6368e62a8acSMatt Jacob break; 6378e62a8acSMatt Jacob } 6385d571944SMatt Jacob default: 6395d571944SMatt Jacob break; 6405d571944SMatt Jacob } 6410a70657fSMatt Jacob #if __FreeBSD_version < 500000 6420a70657fSMatt Jacob splx(s); 6430a70657fSMatt Jacob #endif 6445d571944SMatt Jacob return (retval); 6450470d791SMatt Jacob } 646478f8a96SJustin T. Gibbs 6479311717dSMatt Jacob #if __FreeBSD_version >= 500000 6489311717dSMatt Jacob static void 6499311717dSMatt Jacob isp_sysctl_update(ispsoftc_t *isp) 6509311717dSMatt Jacob { 6519311717dSMatt Jacob struct sysctl_ctx_list *ctx = 6529311717dSMatt Jacob device_get_sysctl_ctx(isp->isp_osinfo.dev); 6539311717dSMatt Jacob struct sysctl_oid *tree = device_get_sysctl_tree(isp->isp_osinfo.dev); 6549311717dSMatt Jacob 6559311717dSMatt Jacob if (IS_SCSI(isp)) { 6569311717dSMatt Jacob return; 6579311717dSMatt Jacob } 658f7c631bcSMatt Jacob 6599311717dSMatt Jacob snprintf(isp->isp_osinfo.sysctl_info.fc.wwnn, 6609311717dSMatt Jacob sizeof (isp->isp_osinfo.sysctl_info.fc.wwnn), "0x%08x%08x", 6619311717dSMatt Jacob (uint32_t) (ISP_NODEWWN(isp) >> 32), (uint32_t) ISP_NODEWWN(isp)); 6629311717dSMatt Jacob 6639311717dSMatt Jacob snprintf(isp->isp_osinfo.sysctl_info.fc.wwpn, 6649311717dSMatt Jacob sizeof (isp->isp_osinfo.sysctl_info.fc.wwpn), "0x%08x%08x", 6659311717dSMatt Jacob (uint32_t) (ISP_PORTWWN(isp) >> 32), (uint32_t) ISP_PORTWWN(isp)); 6669311717dSMatt Jacob 6679311717dSMatt Jacob SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 6689311717dSMatt Jacob "wwnn", CTLFLAG_RD, isp->isp_osinfo.sysctl_info.fc.wwnn, 0, 6699311717dSMatt Jacob "World Wide Node Name"); 670f7c631bcSMatt Jacob 6719311717dSMatt Jacob SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 6729311717dSMatt Jacob "wwpn", CTLFLAG_RD, isp->isp_osinfo.sysctl_info.fc.wwpn, 0, 6739311717dSMatt Jacob "World Wide Port Name"); 674f7c631bcSMatt Jacob 675f7c631bcSMatt Jacob SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 676f7c631bcSMatt Jacob "loop_down_limit", 677f7c631bcSMatt Jacob CTLFLAG_RW, &isp->isp_osinfo.loop_down_limit, 0, 678f7c631bcSMatt Jacob "How long to wait for loop to come back up"); 679f7c631bcSMatt Jacob 680f7c631bcSMatt Jacob SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 681f7c631bcSMatt Jacob "gone_device_time", 682f7c631bcSMatt Jacob CTLFLAG_RW, &isp->isp_osinfo.gone_device_time, 0, 683f7c631bcSMatt Jacob "How long to wait for a device to reappear"); 6849311717dSMatt Jacob } 6859311717dSMatt Jacob #endif 6869311717dSMatt Jacob 687f6e75de2SMatt Jacob static void 688f6e75de2SMatt Jacob isp_intr_enable(void *arg) 689f6e75de2SMatt Jacob { 6909cd7268eSMatt Jacob ispsoftc_t *isp = arg; 6910a70657fSMatt Jacob ISP_LOCK(isp); 692d6e5500fSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE) { 69310365e5aSMatt Jacob ISP_ENABLE_INTS(isp); 694d6e5500fSMatt Jacob } 6950a70657fSMatt Jacob ISP_UNLOCK(isp); 696f6e75de2SMatt Jacob /* Release our hook so that the boot can continue. */ 697f6e75de2SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 698f6e75de2SMatt Jacob } 699d81ba9d5SMatt Jacob 700d81ba9d5SMatt Jacob /* 701d81ba9d5SMatt Jacob * Put the target mode functions here, because some are inlines 702d81ba9d5SMatt Jacob */ 703d81ba9d5SMatt Jacob 704d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 705d81ba9d5SMatt Jacob 7069cd7268eSMatt Jacob static __inline int is_lun_enabled(ispsoftc_t *, int, lun_id_t); 7079cd7268eSMatt Jacob static __inline int are_any_luns_enabled(ispsoftc_t *, int); 7089cd7268eSMatt Jacob static __inline tstate_t *get_lun_statep(ispsoftc_t *, int, lun_id_t); 7099cd7268eSMatt Jacob static __inline void rls_lun_statep(ispsoftc_t *, tstate_t *); 7109cd7268eSMatt Jacob static __inline atio_private_data_t *isp_get_atpd(ispsoftc_t *, int); 711d81ba9d5SMatt Jacob static cam_status 7129cd7268eSMatt Jacob create_lun_state(ispsoftc_t *, int, struct cam_path *, tstate_t **); 7139cd7268eSMatt Jacob static void destroy_lun_state(ispsoftc_t *, tstate_t *); 7149cd7268eSMatt Jacob static int isp_en_lun(ispsoftc_t *, union ccb *); 7159cd7268eSMatt Jacob static void isp_ledone(ispsoftc_t *, lun_entry_t *); 7169cd7268eSMatt Jacob static cam_status isp_abort_tgt_ccb(ispsoftc_t *, union ccb *); 717f48ce188SMatt Jacob static timeout_t isp_refire_putback_atio; 718a1bc34c6SMatt Jacob static void isp_complete_ctio(union ccb *); 719a1bc34c6SMatt Jacob static void isp_target_putback_atio(union ccb *); 7209cd7268eSMatt Jacob static void isp_target_start_ctio(ispsoftc_t *, union ccb *); 7219cd7268eSMatt Jacob static int isp_handle_platform_atio(ispsoftc_t *, at_entry_t *); 7229cd7268eSMatt Jacob static int isp_handle_platform_atio2(ispsoftc_t *, at2_entry_t *); 7239cd7268eSMatt Jacob static int isp_handle_platform_ctio(ispsoftc_t *, void *); 7249cd7268eSMatt Jacob static int isp_handle_platform_notify_scsi(ispsoftc_t *, in_entry_t *); 7259cd7268eSMatt Jacob static int isp_handle_platform_notify_fc(ispsoftc_t *, in_fcentry_t *); 726d81ba9d5SMatt Jacob 72753af7d22SMatt Jacob static __inline int 7289cd7268eSMatt Jacob is_lun_enabled(ispsoftc_t *isp, int bus, lun_id_t lun) 729d81ba9d5SMatt Jacob { 730d81ba9d5SMatt Jacob tstate_t *tptr; 731a1bc34c6SMatt Jacob tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)]; 732a1bc34c6SMatt Jacob if (tptr == NULL) { 733d81ba9d5SMatt Jacob return (0); 734d81ba9d5SMatt Jacob } 735d81ba9d5SMatt Jacob do { 736a1bc34c6SMatt Jacob if (tptr->lun == (lun_id_t) lun && tptr->bus == bus) { 737d81ba9d5SMatt Jacob return (1); 738d81ba9d5SMatt Jacob } 739d81ba9d5SMatt Jacob } while ((tptr = tptr->next) != NULL); 740d81ba9d5SMatt Jacob return (0); 741d81ba9d5SMatt Jacob } 742d81ba9d5SMatt Jacob 74353af7d22SMatt Jacob static __inline int 7449cd7268eSMatt Jacob are_any_luns_enabled(ispsoftc_t *isp, int port) 745d81ba9d5SMatt Jacob { 746a1bc34c6SMatt Jacob int lo, hi; 747a1bc34c6SMatt Jacob if (IS_DUALBUS(isp)) { 748a1bc34c6SMatt Jacob lo = (port * (LUN_HASH_SIZE >> 1)); 749a1bc34c6SMatt Jacob hi = lo + (LUN_HASH_SIZE >> 1); 750a1bc34c6SMatt Jacob } else { 751a1bc34c6SMatt Jacob lo = 0; 752a1bc34c6SMatt Jacob hi = LUN_HASH_SIZE; 753a1bc34c6SMatt Jacob } 754a1bc34c6SMatt Jacob for (lo = 0; lo < hi; lo++) { 755a1bc34c6SMatt Jacob if (isp->isp_osinfo.lun_hash[lo]) { 756d81ba9d5SMatt Jacob return (1); 757d81ba9d5SMatt Jacob } 758d81ba9d5SMatt Jacob } 759d81ba9d5SMatt Jacob return (0); 760d81ba9d5SMatt Jacob } 761d81ba9d5SMatt Jacob 76253af7d22SMatt Jacob static __inline tstate_t * 7639cd7268eSMatt Jacob get_lun_statep(ispsoftc_t *isp, int bus, lun_id_t lun) 764d81ba9d5SMatt Jacob { 76564edff94SMatt Jacob tstate_t *tptr = NULL; 766d81ba9d5SMatt Jacob 767d81ba9d5SMatt Jacob if (lun == CAM_LUN_WILDCARD) { 76864edff94SMatt Jacob if (isp->isp_osinfo.tmflags[bus] & TM_WILDCARD_ENABLED) { 769a1bc34c6SMatt Jacob tptr = &isp->isp_osinfo.tsdflt[bus]; 770d81ba9d5SMatt Jacob tptr->hold++; 771d81ba9d5SMatt Jacob return (tptr); 772d81ba9d5SMatt Jacob } 77367ff51f1SMatt Jacob return (NULL); 774126ec864SMatt Jacob } else { 775126ec864SMatt Jacob tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)]; 77664edff94SMatt Jacob if (tptr == NULL) { 77764edff94SMatt Jacob return (NULL); 77864edff94SMatt Jacob } 779126ec864SMatt Jacob } 780d81ba9d5SMatt Jacob 781d81ba9d5SMatt Jacob do { 782a1bc34c6SMatt Jacob if (tptr->lun == lun && tptr->bus == bus) { 783d81ba9d5SMatt Jacob tptr->hold++; 784d81ba9d5SMatt Jacob return (tptr); 785d81ba9d5SMatt Jacob } 786d81ba9d5SMatt Jacob } while ((tptr = tptr->next) != NULL); 787d81ba9d5SMatt Jacob return (tptr); 788d81ba9d5SMatt Jacob } 789d81ba9d5SMatt Jacob 79053af7d22SMatt Jacob static __inline void 7919cd7268eSMatt Jacob rls_lun_statep(ispsoftc_t *isp, tstate_t *tptr) 792d81ba9d5SMatt Jacob { 793d81ba9d5SMatt Jacob if (tptr->hold) 794d81ba9d5SMatt Jacob tptr->hold--; 795d81ba9d5SMatt Jacob } 796d81ba9d5SMatt Jacob 79753af7d22SMatt Jacob static __inline atio_private_data_t * 7989cd7268eSMatt Jacob isp_get_atpd(ispsoftc_t *isp, int tag) 79953036e92SMatt Jacob { 80053036e92SMatt Jacob atio_private_data_t *atp; 80153036e92SMatt Jacob for (atp = isp->isp_osinfo.atpdp; 80253036e92SMatt Jacob atp < &isp->isp_osinfo.atpdp[ATPDPSIZE]; atp++) { 80353036e92SMatt Jacob if (atp->tag == tag) 80453036e92SMatt Jacob return (atp); 80553036e92SMatt Jacob } 80653036e92SMatt Jacob return (NULL); 80753036e92SMatt Jacob } 80853036e92SMatt Jacob 809d81ba9d5SMatt Jacob static cam_status 8109cd7268eSMatt Jacob create_lun_state(ispsoftc_t *isp, int bus, 811a1bc34c6SMatt Jacob struct cam_path *path, tstate_t **rslt) 812d81ba9d5SMatt Jacob { 813d81ba9d5SMatt Jacob cam_status status; 814d81ba9d5SMatt Jacob lun_id_t lun; 815a1bc34c6SMatt Jacob int hfx; 816d81ba9d5SMatt Jacob tstate_t *tptr, *new; 817d81ba9d5SMatt Jacob 818d81ba9d5SMatt Jacob lun = xpt_path_lun_id(path); 819d81ba9d5SMatt Jacob if (lun < 0) { 820d81ba9d5SMatt Jacob return (CAM_LUN_INVALID); 821d81ba9d5SMatt Jacob } 822a1bc34c6SMatt Jacob if (is_lun_enabled(isp, bus, lun)) { 823d81ba9d5SMatt Jacob return (CAM_LUN_ALRDY_ENA); 824d81ba9d5SMatt Jacob } 825ea8b5a9aSDavid Malone new = (tstate_t *) malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO); 826d81ba9d5SMatt Jacob if (new == NULL) { 827d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 828d81ba9d5SMatt Jacob } 829d81ba9d5SMatt Jacob 830d81ba9d5SMatt Jacob status = xpt_create_path(&new->owner, NULL, xpt_path_path_id(path), 831d81ba9d5SMatt Jacob xpt_path_target_id(path), xpt_path_lun_id(path)); 832d81ba9d5SMatt Jacob if (status != CAM_REQ_CMP) { 833d81ba9d5SMatt Jacob free(new, M_DEVBUF); 834d81ba9d5SMatt Jacob return (status); 835d81ba9d5SMatt Jacob } 836a1bc34c6SMatt Jacob new->bus = bus; 837d81ba9d5SMatt Jacob new->lun = lun; 838d81ba9d5SMatt Jacob SLIST_INIT(&new->atios); 839d81ba9d5SMatt Jacob SLIST_INIT(&new->inots); 840d81ba9d5SMatt Jacob new->hold = 1; 841d81ba9d5SMatt Jacob 842a1bc34c6SMatt Jacob hfx = LUN_HASH_FUNC(isp, new->bus, new->lun); 843a1bc34c6SMatt Jacob tptr = isp->isp_osinfo.lun_hash[hfx]; 844a1bc34c6SMatt Jacob if (tptr == NULL) { 845a1bc34c6SMatt Jacob isp->isp_osinfo.lun_hash[hfx] = new; 846d81ba9d5SMatt Jacob } else { 847d81ba9d5SMatt Jacob while (tptr->next) 848d81ba9d5SMatt Jacob tptr = tptr->next; 849d81ba9d5SMatt Jacob tptr->next = new; 850d81ba9d5SMatt Jacob } 851d81ba9d5SMatt Jacob *rslt = new; 852d81ba9d5SMatt Jacob return (CAM_REQ_CMP); 853d81ba9d5SMatt Jacob } 854d81ba9d5SMatt Jacob 85553af7d22SMatt Jacob static __inline void 8569cd7268eSMatt Jacob destroy_lun_state(ispsoftc_t *isp, tstate_t *tptr) 857d81ba9d5SMatt Jacob { 858a1bc34c6SMatt Jacob int hfx; 859d81ba9d5SMatt Jacob tstate_t *lw, *pw; 860d81ba9d5SMatt Jacob 861d81ba9d5SMatt Jacob if (tptr->hold) { 862d81ba9d5SMatt Jacob return; 863d81ba9d5SMatt Jacob } 86467ff51f1SMatt Jacob hfx = LUN_HASH_FUNC(isp, tptr->bus, tptr->lun); 865a1bc34c6SMatt Jacob pw = isp->isp_osinfo.lun_hash[hfx]; 866d81ba9d5SMatt Jacob if (pw == NULL) { 867d81ba9d5SMatt Jacob return; 868a1bc34c6SMatt Jacob } else if (pw->lun == tptr->lun && pw->bus == tptr->bus) { 869a1bc34c6SMatt Jacob isp->isp_osinfo.lun_hash[hfx] = pw->next; 870d81ba9d5SMatt Jacob } else { 871d81ba9d5SMatt Jacob lw = pw; 872d81ba9d5SMatt Jacob pw = lw->next; 873d81ba9d5SMatt Jacob while (pw) { 874a1bc34c6SMatt Jacob if (pw->lun == tptr->lun && pw->bus == tptr->bus) { 875d81ba9d5SMatt Jacob lw->next = pw->next; 876d81ba9d5SMatt Jacob break; 877d81ba9d5SMatt Jacob } 878d81ba9d5SMatt Jacob lw = pw; 879d81ba9d5SMatt Jacob pw = pw->next; 880d81ba9d5SMatt Jacob } 881d81ba9d5SMatt Jacob if (pw == NULL) { 882d81ba9d5SMatt Jacob return; 883d81ba9d5SMatt Jacob } 884d81ba9d5SMatt Jacob } 885d81ba9d5SMatt Jacob free(tptr, M_DEVBUF); 886d81ba9d5SMatt Jacob } 887d81ba9d5SMatt Jacob 8885d571944SMatt Jacob /* 88967ff51f1SMatt Jacob * Enable luns. 8905d571944SMatt Jacob */ 89167ff51f1SMatt Jacob static int 8929cd7268eSMatt Jacob isp_en_lun(ispsoftc_t *isp, union ccb *ccb) 893d81ba9d5SMatt Jacob { 894d81ba9d5SMatt Jacob struct ccb_en_lun *cel = &ccb->cel; 8951fd47020SMatt Jacob tstate_t *tptr = NULL; 8961dae40ebSMatt Jacob uint32_t seq; 897746e9c85SMatt Jacob int bus, cmd, av, wildcard, tm_on; 898d81ba9d5SMatt Jacob lun_id_t lun; 899d81ba9d5SMatt Jacob target_id_t tgt; 900d81ba9d5SMatt Jacob 90167ff51f1SMatt Jacob bus = XS_CHANNEL(ccb); 90267ff51f1SMatt Jacob if (bus > 1) { 903dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, "illegal bus %d\n", bus); 90467ff51f1SMatt Jacob ccb->ccb_h.status = CAM_PATH_INVALID; 90567ff51f1SMatt Jacob return (-1); 90667ff51f1SMatt Jacob } 907d81ba9d5SMatt Jacob tgt = ccb->ccb_h.target_id; 908d81ba9d5SMatt Jacob lun = ccb->ccb_h.target_lun; 909d81ba9d5SMatt Jacob 910dd9fc7c3SMatt Jacob if (isp->isp_dblev & ISP_LOGTDEBUG0) { 911dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, "%sabling lun 0x%x on channel %d\n", 91267ff51f1SMatt Jacob cel->enable? "en" : "dis", lun, bus); 913dd9fc7c3SMatt Jacob } 914d81ba9d5SMatt Jacob 915d6e5500fSMatt Jacob if ((lun != CAM_LUN_WILDCARD) && 916d6e5500fSMatt Jacob (lun < 0 || lun >= (lun_id_t) isp->isp_maxluns)) { 917d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 91867ff51f1SMatt Jacob return (-1); 919d81ba9d5SMatt Jacob } 92064edff94SMatt Jacob 9212ad50ca5SMatt Jacob if (IS_SCSI(isp)) { 922a1bc34c6SMatt Jacob sdparam *sdp = isp->isp_param; 923a1bc34c6SMatt Jacob sdp += bus; 924d81ba9d5SMatt Jacob if (tgt != CAM_TARGET_WILDCARD && 925a1bc34c6SMatt Jacob tgt != sdp->isp_initiator_id) { 926d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_TID_INVALID; 92767ff51f1SMatt Jacob return (-1); 928d81ba9d5SMatt Jacob } 929d81ba9d5SMatt Jacob } else { 930746e9c85SMatt Jacob /* 931746e9c85SMatt Jacob * There's really no point in doing this yet w/o multi-tid 932746e9c85SMatt Jacob * capability. Even then, it's problematic. 933746e9c85SMatt Jacob */ 934746e9c85SMatt Jacob #if 0 935d81ba9d5SMatt Jacob if (tgt != CAM_TARGET_WILDCARD && 936d6e5500fSMatt Jacob tgt != FCPARAM(isp)->isp_iid) { 937d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_TID_INVALID; 93867ff51f1SMatt Jacob return (-1); 939d81ba9d5SMatt Jacob } 940746e9c85SMatt Jacob #endif 94164edff94SMatt Jacob /* 94264edff94SMatt Jacob * This is as a good a place as any to check f/w capabilities. 94364edff94SMatt Jacob */ 94410365e5aSMatt Jacob if (FCPARAM(isp)->isp_tmode == 0) { 945dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, 946dd9fc7c3SMatt Jacob "firmware does not support target mode\n"); 94764edff94SMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 94867ff51f1SMatt Jacob return (-1); 94964edff94SMatt Jacob } 95064edff94SMatt Jacob /* 95164edff94SMatt Jacob * XXX: We *could* handle non-SCCLUN f/w, but we'd have to 952dd9fc7c3SMatt Jacob * XXX: dork with our already fragile enable/disable code. 95364edff94SMatt Jacob */ 95410365e5aSMatt Jacob if (FCPARAM(isp)->isp_sccfw == 0) { 955dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, 956dd9fc7c3SMatt Jacob "firmware not SCCLUN capable\n"); 957746e9c85SMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 95867ff51f1SMatt Jacob return (-1); 95964edff94SMatt Jacob } 960d81ba9d5SMatt Jacob } 961d81ba9d5SMatt Jacob 962d6e5500fSMatt Jacob if (tgt == CAM_TARGET_WILDCARD) { 96364edff94SMatt Jacob if (lun == CAM_LUN_WILDCARD) { 96464edff94SMatt Jacob wildcard = 1; 96564edff94SMatt Jacob } else { 966d6e5500fSMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 96767ff51f1SMatt Jacob return (-1); 968d6e5500fSMatt Jacob } 969126ec864SMatt Jacob } else { 970126ec864SMatt Jacob wildcard = 0; 971126ec864SMatt Jacob } 972b6b6ad2fSMatt Jacob 973746e9c85SMatt Jacob tm_on = (isp->isp_osinfo.tmflags[bus] & TM_TMODE_ENABLED) != 0; 974746e9c85SMatt Jacob 975b6b6ad2fSMatt Jacob /* 976b6b6ad2fSMatt Jacob * Next check to see whether this is a target/lun wildcard action. 97764edff94SMatt Jacob * 97864edff94SMatt Jacob * If so, we know that we can accept commands for luns that haven't 97964edff94SMatt Jacob * been enabled yet and send them upstream. Otherwise, we have to 98064edff94SMatt Jacob * handle them locally (if we see them at all). 981b6b6ad2fSMatt Jacob */ 982126ec864SMatt Jacob 983126ec864SMatt Jacob if (wildcard) { 984a1bc34c6SMatt Jacob tptr = &isp->isp_osinfo.tsdflt[bus]; 985b6b6ad2fSMatt Jacob if (cel->enable) { 98667ff51f1SMatt Jacob if (tm_on) { 987b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; 98867ff51f1SMatt Jacob return (-1); 989b6b6ad2fSMatt Jacob } 990b6b6ad2fSMatt Jacob ccb->ccb_h.status = 991b6b6ad2fSMatt Jacob xpt_create_path(&tptr->owner, NULL, 992b6b6ad2fSMatt Jacob xpt_path_path_id(ccb->ccb_h.path), 993b6b6ad2fSMatt Jacob xpt_path_target_id(ccb->ccb_h.path), 994b6b6ad2fSMatt Jacob xpt_path_lun_id(ccb->ccb_h.path)); 995b6b6ad2fSMatt Jacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 99667ff51f1SMatt Jacob return (-1); 997b6b6ad2fSMatt Jacob } 998b6b6ad2fSMatt Jacob SLIST_INIT(&tptr->atios); 999b6b6ad2fSMatt Jacob SLIST_INIT(&tptr->inots); 100064edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] |= TM_WILDCARD_ENABLED; 1001126ec864SMatt Jacob } else { 100267ff51f1SMatt Jacob if (tm_on == 0) { 1003126ec864SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 100467ff51f1SMatt Jacob return (-1); 1005126ec864SMatt Jacob } 1006126ec864SMatt Jacob if (tptr->hold) { 1007126ec864SMatt Jacob ccb->ccb_h.status = CAM_SCSI_BUSY; 100867ff51f1SMatt Jacob return (-1); 1009126ec864SMatt Jacob } 1010126ec864SMatt Jacob xpt_free_path(tptr->owner); 101164edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_WILDCARD_ENABLED; 1012126ec864SMatt Jacob } 1013126ec864SMatt Jacob } 1014126ec864SMatt Jacob 1015126ec864SMatt Jacob /* 1016126ec864SMatt Jacob * Now check to see whether this bus needs to be 1017126ec864SMatt Jacob * enabled/disabled with respect to target mode. 1018126ec864SMatt Jacob */ 1019126ec864SMatt Jacob av = bus << 31; 1020746e9c85SMatt Jacob if (cel->enable && tm_on == 0) { 1021a1bc34c6SMatt Jacob av |= ENABLE_TARGET_FLAG; 1022b6b6ad2fSMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 1023b6b6ad2fSMatt Jacob if (av) { 1024b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 1025126ec864SMatt Jacob if (wildcard) { 102664edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= 102764edff94SMatt Jacob ~TM_WILDCARD_ENABLED; 1028b6b6ad2fSMatt Jacob xpt_free_path(tptr->owner); 10295d571944SMatt Jacob } 103067ff51f1SMatt Jacob return (-1); 1031b6b6ad2fSMatt Jacob } 103264edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] |= TM_TMODE_ENABLED; 1033dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, "Target Mode Enabled\n"); 1034746e9c85SMatt Jacob } else if (cel->enable == 0 && tm_on && wildcard) { 1035a1bc34c6SMatt Jacob if (are_any_luns_enabled(isp, bus)) { 1036b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_SCSI_BUSY; 103767ff51f1SMatt Jacob return (-1); 1038b6b6ad2fSMatt Jacob } 1039b6b6ad2fSMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 1040b6b6ad2fSMatt Jacob if (av) { 1041b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 104267ff51f1SMatt Jacob return (-1); 1043b6b6ad2fSMatt Jacob } 104464edff94SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED; 1045dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, "Target Mode Disabled\n"); 1046126ec864SMatt Jacob } 1047126ec864SMatt Jacob 1048126ec864SMatt Jacob if (wildcard) { 104964edff94SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 105067ff51f1SMatt Jacob return (-1); 1051b6b6ad2fSMatt Jacob } 1052b6b6ad2fSMatt Jacob 105367ff51f1SMatt Jacob /* 105467ff51f1SMatt Jacob * Find an empty slot 105567ff51f1SMatt Jacob */ 105667ff51f1SMatt Jacob for (seq = 0; seq < NLEACT; seq++) { 105767ff51f1SMatt Jacob if (isp->isp_osinfo.leact[seq] == 0) { 105867ff51f1SMatt Jacob break; 105967ff51f1SMatt Jacob } 106067ff51f1SMatt Jacob } 106167ff51f1SMatt Jacob if (seq >= NLEACT) { 106267ff51f1SMatt Jacob ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 106367ff51f1SMatt Jacob return (-1); 106467ff51f1SMatt Jacob 106567ff51f1SMatt Jacob } 106667ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = ccb; 106767ff51f1SMatt Jacob 1068d81ba9d5SMatt Jacob if (cel->enable) { 1069d81ba9d5SMatt Jacob ccb->ccb_h.status = 1070a1bc34c6SMatt Jacob create_lun_state(isp, bus, ccb->ccb_h.path, &tptr); 1071d81ba9d5SMatt Jacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 107267ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 107367ff51f1SMatt Jacob return (-1); 1074d81ba9d5SMatt Jacob } 1075d81ba9d5SMatt Jacob } else { 1076a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, lun); 1077d81ba9d5SMatt Jacob if (tptr == NULL) { 1078d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 107967ff51f1SMatt Jacob return (-1); 1080d81ba9d5SMatt Jacob } 1081d81ba9d5SMatt Jacob } 1082d81ba9d5SMatt Jacob 1083d81ba9d5SMatt Jacob if (cel->enable) { 10845d571944SMatt Jacob int c, n, ulun = lun; 10855d571944SMatt Jacob 10865d571944SMatt Jacob cmd = RQSTYPE_ENABLE_LUN; 10875d571944SMatt Jacob c = DFLT_CMND_CNT; 10885d571944SMatt Jacob n = DFLT_INOT_CNT; 10895d571944SMatt Jacob if (IS_FC(isp) && lun != 0) { 10905d571944SMatt Jacob cmd = RQSTYPE_MODIFY_LUN; 10915d571944SMatt Jacob n = 0; 10925d571944SMatt Jacob /* 10935d571944SMatt Jacob * For SCC firmware, we only deal with setting 10945d571944SMatt Jacob * (enabling or modifying) lun 0. 10955d571944SMatt Jacob */ 10965d571944SMatt Jacob ulun = 0; 10975d571944SMatt Jacob } 109867ff51f1SMatt Jacob if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq+1) == 0) { 109967ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 110067ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_INPROG; 110167ff51f1SMatt Jacob return (seq); 1102d81ba9d5SMatt Jacob } 1103d81ba9d5SMatt Jacob } else { 11045d571944SMatt Jacob int c, n, ulun = lun; 1105d81ba9d5SMatt Jacob 11065d571944SMatt Jacob cmd = -RQSTYPE_MODIFY_LUN; 11075d571944SMatt Jacob c = DFLT_CMND_CNT; 11085d571944SMatt Jacob n = DFLT_INOT_CNT; 11095d571944SMatt Jacob if (IS_FC(isp) && lun != 0) { 11105d571944SMatt Jacob n = 0; 11115d571944SMatt Jacob /* 11125d571944SMatt Jacob * For SCC firmware, we only deal with setting 11135d571944SMatt Jacob * (enabling or modifying) lun 0. 11145d571944SMatt Jacob */ 11155d571944SMatt Jacob ulun = 0; 11165d571944SMatt Jacob } 111767ff51f1SMatt Jacob if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq+1) == 0) { 111867ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 111967ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_INPROG; 112067ff51f1SMatt Jacob return (seq); 1121d81ba9d5SMatt Jacob } 1122d81ba9d5SMatt Jacob } 112367ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 1124dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, "isp_lun_cmd failed\n"); 112567ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 112667ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 112767ff51f1SMatt Jacob return (-1); 11285d571944SMatt Jacob } 11295d571944SMatt Jacob 113067ff51f1SMatt Jacob static void 11319cd7268eSMatt Jacob isp_ledone(ispsoftc_t *isp, lun_entry_t *lep) 113267ff51f1SMatt Jacob { 11339a1b0d43SMatt Jacob const char lfmt[] = "now %sabled for target mode\n"; 113467ff51f1SMatt Jacob union ccb *ccb; 11351dae40ebSMatt Jacob uint32_t seq; 113667ff51f1SMatt Jacob tstate_t *tptr; 113767ff51f1SMatt Jacob int av; 113867ff51f1SMatt Jacob struct ccb_en_lun *cel; 1139d81ba9d5SMatt Jacob 114067ff51f1SMatt Jacob seq = lep->le_reserved - 1; 114167ff51f1SMatt Jacob if (seq >= NLEACT) { 11423c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, 114367ff51f1SMatt Jacob "seq out of range (%u) in isp_ledone", seq); 114467ff51f1SMatt Jacob return; 1145d81ba9d5SMatt Jacob } 114667ff51f1SMatt Jacob ccb = isp->isp_osinfo.leact[seq]; 114767ff51f1SMatt Jacob if (ccb == 0) { 114867ff51f1SMatt Jacob isp_prt(isp, ISP_LOGERR, 114967ff51f1SMatt Jacob "no ccb for seq %u in isp_ledone", seq); 115067ff51f1SMatt Jacob return; 115167ff51f1SMatt Jacob } 115267ff51f1SMatt Jacob cel = &ccb->cel; 115367ff51f1SMatt Jacob tptr = get_lun_statep(isp, XS_CHANNEL(ccb), XS_LUN(ccb)); 115467ff51f1SMatt Jacob if (tptr == NULL) { 1155dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, "null tptr in isp_ledone\n"); 115667ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 115767ff51f1SMatt Jacob return; 1158d81ba9d5SMatt Jacob } 115967ff51f1SMatt Jacob 116067ff51f1SMatt Jacob if (lep->le_status != LUN_OK) { 1161dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, 1162dd9fc7c3SMatt Jacob "ENABLE/MODIFY LUN returned 0x%x\n", lep->le_status); 116367ff51f1SMatt Jacob err: 116467ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 116567ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 116667ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 116767ff51f1SMatt Jacob xpt_done(ccb); 116867ff51f1SMatt Jacob return; 116967ff51f1SMatt Jacob } else { 117067ff51f1SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 117167ff51f1SMatt Jacob "isp_ledone: ENABLE/MODIFY done okay"); 117267ff51f1SMatt Jacob } 117367ff51f1SMatt Jacob 117467ff51f1SMatt Jacob 117567ff51f1SMatt Jacob if (cel->enable) { 117667ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 1177dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, lfmt, "en"); 117867ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 117967ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 118067ff51f1SMatt Jacob xpt_done(ccb); 118167ff51f1SMatt Jacob return; 118267ff51f1SMatt Jacob } 118367ff51f1SMatt Jacob 118467ff51f1SMatt Jacob if (lep->le_header.rqs_entry_type == RQSTYPE_MODIFY_LUN) { 118567ff51f1SMatt Jacob if (isp_lun_cmd(isp, -RQSTYPE_ENABLE_LUN, XS_CHANNEL(ccb), 118667ff51f1SMatt Jacob XS_TGT(ccb), XS_LUN(ccb), 0, 0, seq+1)) { 1187dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, 1188dd9fc7c3SMatt Jacob "isp_ledone: isp_lun_cmd failed\n"); 118967ff51f1SMatt Jacob goto err; 119067ff51f1SMatt Jacob } 119167ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 119267ff51f1SMatt Jacob return; 119367ff51f1SMatt Jacob } 119467ff51f1SMatt Jacob 1195dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, lfmt, "dis"); 119667ff51f1SMatt Jacob rls_lun_statep(isp, tptr); 119767ff51f1SMatt Jacob destroy_lun_state(isp, tptr); 119867ff51f1SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 119967ff51f1SMatt Jacob isp->isp_osinfo.leact[seq] = 0; 120067ff51f1SMatt Jacob xpt_done(ccb); 120167ff51f1SMatt Jacob if (are_any_luns_enabled(isp, XS_CHANNEL(ccb)) == 0) { 120267ff51f1SMatt Jacob int bus = XS_CHANNEL(ccb); 120367ff51f1SMatt Jacob av = bus << 31; 1204126ec864SMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 1205126ec864SMatt Jacob if (av) { 1206126ec864SMatt Jacob isp_prt(isp, ISP_LOGWARN, 120767ff51f1SMatt Jacob "disable target mode on channel %d failed", bus); 1208126ec864SMatt Jacob } 120967ff51f1SMatt Jacob isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED; 121067ff51f1SMatt Jacob } 1211126ec864SMatt Jacob } 1212126ec864SMatt Jacob 1213d81ba9d5SMatt Jacob 1214d81ba9d5SMatt Jacob static cam_status 12159cd7268eSMatt Jacob isp_abort_tgt_ccb(ispsoftc_t *isp, union ccb *ccb) 1216d81ba9d5SMatt Jacob { 1217d81ba9d5SMatt Jacob tstate_t *tptr; 1218d81ba9d5SMatt Jacob struct ccb_hdr_slist *lp; 1219d81ba9d5SMatt Jacob struct ccb_hdr *curelm; 1220746e9c85SMatt Jacob int found, *ctr; 1221d81ba9d5SMatt Jacob union ccb *accb = ccb->cab.abort_ccb; 1222d81ba9d5SMatt Jacob 1223dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, "aborting ccb %p\n", accb); 1224d81ba9d5SMatt Jacob if (accb->ccb_h.target_id != CAM_TARGET_WILDCARD) { 1225746e9c85SMatt Jacob int badpath = 0; 1226d81ba9d5SMatt Jacob if (IS_FC(isp) && (accb->ccb_h.target_id != 1227d81ba9d5SMatt Jacob ((fcparam *) isp->isp_param)->isp_loopid)) { 1228746e9c85SMatt Jacob badpath = 1; 1229d81ba9d5SMatt Jacob } else if (IS_SCSI(isp) && (accb->ccb_h.target_id != 1230d81ba9d5SMatt Jacob ((sdparam *) isp->isp_param)->isp_initiator_id)) { 1231746e9c85SMatt Jacob badpath = 1; 1232746e9c85SMatt Jacob } 1233746e9c85SMatt Jacob if (badpath) { 1234746e9c85SMatt Jacob /* 1235746e9c85SMatt Jacob * Being restrictive about target ids is really about 1236746e9c85SMatt Jacob * making sure we're aborting for the right multi-tid 1237746e9c85SMatt Jacob * path. This doesn't really make much sense at present. 1238746e9c85SMatt Jacob */ 1239746e9c85SMatt Jacob #if 0 1240d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 1241746e9c85SMatt Jacob #endif 1242d81ba9d5SMatt Jacob } 1243d81ba9d5SMatt Jacob } 1244a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, XS_CHANNEL(ccb), accb->ccb_h.target_lun); 1245d81ba9d5SMatt Jacob if (tptr == NULL) { 1246dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, "can't get statep\n"); 1247d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 1248d81ba9d5SMatt Jacob } 1249d81ba9d5SMatt Jacob if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 1250d81ba9d5SMatt Jacob lp = &tptr->atios; 1251746e9c85SMatt Jacob ctr = &tptr->atio_count; 1252d81ba9d5SMatt Jacob } else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY) { 1253d81ba9d5SMatt Jacob lp = &tptr->inots; 1254746e9c85SMatt Jacob ctr = &tptr->inot_count; 1255d81ba9d5SMatt Jacob } else { 1256d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1257dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, "bad function code %d\n", 1258dd9fc7c3SMatt Jacob accb->ccb_h.func_code); 1259d81ba9d5SMatt Jacob return (CAM_UA_ABORT); 1260d81ba9d5SMatt Jacob } 1261d81ba9d5SMatt Jacob curelm = SLIST_FIRST(lp); 1262d81ba9d5SMatt Jacob found = 0; 1263d81ba9d5SMatt Jacob if (curelm == &accb->ccb_h) { 1264d81ba9d5SMatt Jacob found = 1; 1265d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(lp, sim_links.sle); 1266d81ba9d5SMatt Jacob } else { 1267d81ba9d5SMatt Jacob while(curelm != NULL) { 1268d81ba9d5SMatt Jacob struct ccb_hdr *nextelm; 1269d81ba9d5SMatt Jacob 1270d81ba9d5SMatt Jacob nextelm = SLIST_NEXT(curelm, sim_links.sle); 1271d81ba9d5SMatt Jacob if (nextelm == &accb->ccb_h) { 1272d81ba9d5SMatt Jacob found = 1; 1273d81ba9d5SMatt Jacob SLIST_NEXT(curelm, sim_links.sle) = 1274d81ba9d5SMatt Jacob SLIST_NEXT(nextelm, sim_links.sle); 1275d81ba9d5SMatt Jacob break; 1276d81ba9d5SMatt Jacob } 1277d81ba9d5SMatt Jacob curelm = nextelm; 1278d81ba9d5SMatt Jacob } 1279d81ba9d5SMatt Jacob } 1280d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1281d81ba9d5SMatt Jacob if (found) { 1282c1504bc0SMatt Jacob (*ctr)--; 1283d81ba9d5SMatt Jacob accb->ccb_h.status = CAM_REQ_ABORTED; 1284746e9c85SMatt Jacob xpt_done(accb); 1285d81ba9d5SMatt Jacob return (CAM_REQ_CMP); 1286d81ba9d5SMatt Jacob } 1287dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, "ccb %p not found\n", accb); 1288d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 1289d81ba9d5SMatt Jacob } 1290d81ba9d5SMatt Jacob 12919cd7268eSMatt Jacob static void 12929cd7268eSMatt Jacob isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb) 1293d81ba9d5SMatt Jacob { 1294d81ba9d5SMatt Jacob void *qe; 129500a8e174SMatt Jacob struct ccb_scsiio *cso = &ccb->csio; 129610365e5aSMatt Jacob uint32_t nxti, optr, handle; 12971dae40ebSMatt Jacob uint8_t local[QENTRY_LEN]; 1298d81ba9d5SMatt Jacob 1299f48ce188SMatt Jacob 13004fd13c1bSMatt Jacob if (isp_getrqentry(isp, &nxti, &optr, &qe)) { 1301dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, 1302dd9fc7c3SMatt Jacob "Request Queue Overflow in isp_target_start_ctio\n"); 13039cd7268eSMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 13049cd7268eSMatt Jacob goto out; 1305d81ba9d5SMatt Jacob } 130629f76675SMatt Jacob memset(local, 0, QENTRY_LEN); 1307d81ba9d5SMatt Jacob 1308d81ba9d5SMatt Jacob /* 1309d81ba9d5SMatt Jacob * We're either moving data or completing a command here. 1310d81ba9d5SMatt Jacob */ 1311d81ba9d5SMatt Jacob 1312d81ba9d5SMatt Jacob if (IS_FC(isp)) { 131353036e92SMatt Jacob atio_private_data_t *atp; 13144fd13c1bSMatt Jacob ct2_entry_t *cto = (ct2_entry_t *) local; 131500a8e174SMatt Jacob 1316d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; 1317d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_count = 1; 131810365e5aSMatt Jacob if (FCPARAM(isp)->isp_2klogin) { 131929f76675SMatt Jacob ((ct2e_entry_t *)cto)->ct_iid = cso->init_id; 132029f76675SMatt Jacob } else { 132100a8e174SMatt Jacob cto->ct_iid = cso->init_id; 132210365e5aSMatt Jacob if (FCPARAM(isp)->isp_sccfw == 0) { 1323d81ba9d5SMatt Jacob cto->ct_lun = ccb->ccb_h.target_lun; 13242ad50ca5SMatt Jacob } 132529f76675SMatt Jacob } 132653036e92SMatt Jacob 132753036e92SMatt Jacob atp = isp_get_atpd(isp, cso->tag_id); 132853036e92SMatt Jacob if (atp == NULL) { 1329dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, 1330dd9fc7c3SMatt Jacob "cannot find private data adjunct for tag %x\n", 133153036e92SMatt Jacob cso->tag_id); 13329cd7268eSMatt Jacob XS_SETERR(ccb, CAM_REQ_CMP_ERR); 13339cd7268eSMatt Jacob goto out; 133453036e92SMatt Jacob } 1335f48ce188SMatt Jacob 133600a8e174SMatt Jacob cto->ct_rxid = cso->tag_id; 133700a8e174SMatt Jacob if (cso->dxfer_len == 0) { 133800a8e174SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA; 1339f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 134000a8e174SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 1341f48ce188SMatt Jacob cto->rsp.m1.ct_scsi_status = cso->scsi_status; 134253036e92SMatt Jacob cto->ct_resid = 134353036e92SMatt Jacob atp->orig_datalen - atp->bytes_xfered; 1344570c7a3fSMatt Jacob if (cto->ct_resid < 0) { 1345570c7a3fSMatt Jacob cto->rsp.m1.ct_scsi_status |= 1346570c7a3fSMatt Jacob CT2_DATA_OVER; 1347570c7a3fSMatt Jacob } else if (cto->ct_resid > 0) { 1348570c7a3fSMatt Jacob cto->rsp.m1.ct_scsi_status |= 1349570c7a3fSMatt Jacob CT2_DATA_UNDER; 1350570c7a3fSMatt Jacob } 1351f48ce188SMatt Jacob } 135200a8e174SMatt Jacob if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) { 135300a8e174SMatt Jacob int m = min(cso->sense_len, MAXRESPLEN); 135429f76675SMatt Jacob memcpy(cto->rsp.m1.ct_resp, 135529f76675SMatt Jacob &cso->sense_data, m); 135600a8e174SMatt Jacob cto->rsp.m1.ct_senselen = m; 135700a8e174SMatt Jacob cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID; 135800a8e174SMatt Jacob } 135900a8e174SMatt Jacob } else { 136000a8e174SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE0; 136100a8e174SMatt Jacob if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 136200a8e174SMatt Jacob cto->ct_flags |= CT2_DATA_IN; 136300a8e174SMatt Jacob } else { 136400a8e174SMatt Jacob cto->ct_flags |= CT2_DATA_OUT; 1365d81ba9d5SMatt Jacob } 1366570c7a3fSMatt Jacob cto->ct_reloff = atp->bytes_xfered; 1367d81ba9d5SMatt Jacob if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 1368d81ba9d5SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 136900a8e174SMatt Jacob cto->rsp.m0.ct_scsi_status = cso->scsi_status; 137053036e92SMatt Jacob cto->ct_resid = 137153036e92SMatt Jacob atp->orig_datalen - 137253036e92SMatt Jacob (atp->bytes_xfered + cso->dxfer_len); 1373570c7a3fSMatt Jacob if (cto->ct_resid < 0) { 1374570c7a3fSMatt Jacob cto->rsp.m0.ct_scsi_status |= 1375570c7a3fSMatt Jacob CT2_DATA_OVER; 1376570c7a3fSMatt Jacob } else if (cto->ct_resid > 0) { 1377570c7a3fSMatt Jacob cto->rsp.m0.ct_scsi_status |= 1378570c7a3fSMatt Jacob CT2_DATA_UNDER; 1379570c7a3fSMatt Jacob } 138053036e92SMatt Jacob } else { 138153036e92SMatt Jacob atp->last_xframt = cso->dxfer_len; 1382d81ba9d5SMatt Jacob } 1383f48ce188SMatt Jacob /* 1384f48ce188SMatt Jacob * If we're sending data and status back together, 1385f48ce188SMatt Jacob * we can't also send back sense data as well. 1386f48ce188SMatt Jacob */ 138700a8e174SMatt Jacob ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 138800a8e174SMatt Jacob } 138953036e92SMatt Jacob 1390290dc24bSMatt Jacob if (cto->ct_flags & CT2_SENDSTATUS) { 139164edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 139253036e92SMatt Jacob "CTIO2[%x] STATUS %x origd %u curd %u resid %u", 139353036e92SMatt Jacob cto->ct_rxid, cso->scsi_status, atp->orig_datalen, 139453036e92SMatt Jacob cso->dxfer_len, cto->ct_resid); 1395a1bc34c6SMatt Jacob cto->ct_flags |= CT2_CCINCR; 1396570c7a3fSMatt Jacob atp->state = ATPD_STATE_LAST_CTIO; 13979cd7268eSMatt Jacob } else { 1398570c7a3fSMatt Jacob atp->state = ATPD_STATE_CTIO; 13999cd7268eSMatt Jacob } 1400a1bc34c6SMatt Jacob cto->ct_timeout = 10; 1401d81ba9d5SMatt Jacob } else { 14024fd13c1bSMatt Jacob ct_entry_t *cto = (ct_entry_t *) local; 140300a8e174SMatt Jacob 1404d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 1405d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_count = 1; 140600a8e174SMatt Jacob cto->ct_iid = cso->init_id; 1407a1bc34c6SMatt Jacob cto->ct_iid |= XS_CHANNEL(ccb) << 7; 1408d81ba9d5SMatt Jacob cto->ct_tgt = ccb->ccb_h.target_id; 1409d81ba9d5SMatt Jacob cto->ct_lun = ccb->ccb_h.target_lun; 1410a1bc34c6SMatt Jacob cto->ct_fwhandle = AT_GET_HANDLE(cso->tag_id); 1411a1bc34c6SMatt Jacob if (AT_HAS_TAG(cso->tag_id)) { 14121dae40ebSMatt Jacob cto->ct_tag_val = (uint8_t) AT_GET_TAG(cso->tag_id); 1413f48ce188SMatt Jacob cto->ct_flags |= CT_TQAE; 1414f48ce188SMatt Jacob } 1415f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) { 1416f48ce188SMatt Jacob cto->ct_flags |= CT_NODISC; 1417f48ce188SMatt Jacob } 1418f48ce188SMatt Jacob if (cso->dxfer_len == 0) { 1419d81ba9d5SMatt Jacob cto->ct_flags |= CT_NO_DATA; 142000a8e174SMatt Jacob } else if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 142100a8e174SMatt Jacob cto->ct_flags |= CT_DATA_IN; 142200a8e174SMatt Jacob } else { 142300a8e174SMatt Jacob cto->ct_flags |= CT_DATA_OUT; 1424d81ba9d5SMatt Jacob } 1425f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 142653036e92SMatt Jacob cto->ct_flags |= CT_SENDSTATUS|CT_CCINCR; 142700a8e174SMatt Jacob cto->ct_scsi_status = cso->scsi_status; 142800a8e174SMatt Jacob cto->ct_resid = cso->resid; 142964edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1430a1bc34c6SMatt Jacob "CTIO[%x] SCSI STATUS 0x%x resid %d tag_id %x", 1431a1bc34c6SMatt Jacob cto->ct_fwhandle, cso->scsi_status, cso->resid, 1432a1bc34c6SMatt Jacob cso->tag_id); 143392a1e549SMatt Jacob } 143464edff94SMatt Jacob ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 1435a1bc34c6SMatt Jacob cto->ct_timeout = 10; 1436d81ba9d5SMatt Jacob } 1437d81ba9d5SMatt Jacob 143810365e5aSMatt Jacob if (isp_save_xs_tgt(isp, ccb, &handle)) { 1439dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, 1440dd9fc7c3SMatt Jacob "No XFLIST pointers for isp_target_start_ctio\n"); 14419cd7268eSMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 14429cd7268eSMatt Jacob goto out; 1443d81ba9d5SMatt Jacob } 1444d81ba9d5SMatt Jacob 1445d81ba9d5SMatt Jacob 1446d81ba9d5SMatt Jacob /* 1447d81ba9d5SMatt Jacob * Call the dma setup routines for this entry (and any subsequent 1448d81ba9d5SMatt Jacob * CTIOs) if there's data to move, and then tell the f/w it's got 1449b09b0095SMatt Jacob * new things to play with. As with isp_start's usage of DMA setup, 1450d81ba9d5SMatt Jacob * any swizzling is done in the machine dependent layer. Because 1451d81ba9d5SMatt Jacob * of this, we put the request onto the queue area first in native 1452d81ba9d5SMatt Jacob * format. 1453d81ba9d5SMatt Jacob */ 1454d81ba9d5SMatt Jacob 145510365e5aSMatt Jacob if (IS_FC(isp)) { 145610365e5aSMatt Jacob ct2_entry_t *cto = (ct2_entry_t *) local; 145710365e5aSMatt Jacob cto->ct_syshandle = handle; 145810365e5aSMatt Jacob } else { 145910365e5aSMatt Jacob ct_entry_t *cto = (ct_entry_t *) local; 146010365e5aSMatt Jacob cto->ct_syshandle = handle; 146110365e5aSMatt Jacob } 1462a1bc34c6SMatt Jacob 14634fd13c1bSMatt Jacob switch (ISP_DMASETUP(isp, cso, (ispreq_t *) local, &nxti, optr)) { 1464d81ba9d5SMatt Jacob case CMD_QUEUED: 14654fd13c1bSMatt Jacob ISP_ADD_REQUEST(isp, nxti); 14669cd7268eSMatt Jacob ccb->ccb_h.status |= CAM_SIM_QUEUED; 14679cd7268eSMatt Jacob return; 1468d81ba9d5SMatt Jacob 1469d81ba9d5SMatt Jacob case CMD_EAGAIN: 14709cd7268eSMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 14719cd7268eSMatt Jacob break; 1472d81ba9d5SMatt Jacob 1473d81ba9d5SMatt Jacob default: 14749cd7268eSMatt Jacob break; 1475d81ba9d5SMatt Jacob } 147610365e5aSMatt Jacob isp_destroy_tgt_handle(isp, handle); 14779cd7268eSMatt Jacob 14789cd7268eSMatt Jacob out: 14799cd7268eSMatt Jacob xpt_done(ccb); 1480d81ba9d5SMatt Jacob } 1481d81ba9d5SMatt Jacob 1482a1bc34c6SMatt Jacob static void 1483a1bc34c6SMatt Jacob isp_refire_putback_atio(void *arg) 1484f48ce188SMatt Jacob { 1485a1bc34c6SMatt Jacob int s = splcam(); 1486a1bc34c6SMatt Jacob isp_target_putback_atio(arg); 1487a1bc34c6SMatt Jacob splx(s); 1488a1bc34c6SMatt Jacob } 1489a1bc34c6SMatt Jacob 1490a1bc34c6SMatt Jacob static void 1491a1bc34c6SMatt Jacob isp_target_putback_atio(union ccb *ccb) 1492a1bc34c6SMatt Jacob { 14939cd7268eSMatt Jacob ispsoftc_t *isp; 1494a1bc34c6SMatt Jacob struct ccb_scsiio *cso; 149510365e5aSMatt Jacob uint32_t nxti, optr; 1496a1bc34c6SMatt Jacob void *qe; 1497a1bc34c6SMatt Jacob 1498a1bc34c6SMatt Jacob isp = XS_ISP(ccb); 1499f48ce188SMatt Jacob 15004fd13c1bSMatt Jacob if (isp_getrqentry(isp, &nxti, &optr, &qe)) { 1501dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, 1502dd9fc7c3SMatt Jacob "isp_target_putback_atio: Request Queue Overflow\n"); 1503a1bc34c6SMatt Jacob (void) timeout(isp_refire_putback_atio, ccb, 10); 1504a1bc34c6SMatt Jacob return; 1505f48ce188SMatt Jacob } 150629f76675SMatt Jacob memset(qe, 0, QENTRY_LEN); 1507a1bc34c6SMatt Jacob cso = &ccb->csio; 1508f48ce188SMatt Jacob if (IS_FC(isp)) { 15094fd13c1bSMatt Jacob at2_entry_t local, *at = &local; 15104fd13c1bSMatt Jacob MEMZERO(at, sizeof (at2_entry_t)); 1511f48ce188SMatt Jacob at->at_header.rqs_entry_type = RQSTYPE_ATIO2; 1512f48ce188SMatt Jacob at->at_header.rqs_entry_count = 1; 151310365e5aSMatt Jacob if (FCPARAM(isp)->isp_sccfw) { 1514a1bc34c6SMatt Jacob at->at_scclun = (uint16_t) ccb->ccb_h.target_lun; 1515f48ce188SMatt Jacob } else { 1516a1bc34c6SMatt Jacob at->at_lun = (uint8_t) ccb->ccb_h.target_lun; 1517f48ce188SMatt Jacob } 1518f48ce188SMatt Jacob at->at_status = CT_OK; 1519a1bc34c6SMatt Jacob at->at_rxid = cso->tag_id; 1520570c7a3fSMatt Jacob at->at_iid = cso->ccb_h.target_id; 15214fd13c1bSMatt Jacob isp_put_atio2(isp, at, qe); 1522f48ce188SMatt Jacob } else { 15234fd13c1bSMatt Jacob at_entry_t local, *at = &local; 15244fd13c1bSMatt Jacob MEMZERO(at, sizeof (at_entry_t)); 1525f48ce188SMatt Jacob at->at_header.rqs_entry_type = RQSTYPE_ATIO; 1526f48ce188SMatt Jacob at->at_header.rqs_entry_count = 1; 1527a1bc34c6SMatt Jacob at->at_iid = cso->init_id; 1528a1bc34c6SMatt Jacob at->at_iid |= XS_CHANNEL(ccb) << 7; 1529a1bc34c6SMatt Jacob at->at_tgt = cso->ccb_h.target_id; 1530a1bc34c6SMatt Jacob at->at_lun = cso->ccb_h.target_lun; 1531f48ce188SMatt Jacob at->at_status = CT_OK; 1532a1bc34c6SMatt Jacob at->at_tag_val = AT_GET_TAG(cso->tag_id); 1533a1bc34c6SMatt Jacob at->at_handle = AT_GET_HANDLE(cso->tag_id); 15344fd13c1bSMatt Jacob isp_put_atio(isp, at, qe); 1535f48ce188SMatt Jacob } 1536f48ce188SMatt Jacob ISP_TDQE(isp, "isp_target_putback_atio", (int) optr, qe); 15374fd13c1bSMatt Jacob ISP_ADD_REQUEST(isp, nxti); 1538a1bc34c6SMatt Jacob isp_complete_ctio(ccb); 1539f48ce188SMatt Jacob } 1540f48ce188SMatt Jacob 1541f48ce188SMatt Jacob static void 1542a1bc34c6SMatt Jacob isp_complete_ctio(union ccb *ccb) 1543f48ce188SMatt Jacob { 1544a1bc34c6SMatt Jacob if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { 1545a1bc34c6SMatt Jacob ccb->ccb_h.status |= CAM_REQ_CMP; 1546f48ce188SMatt Jacob } 1547a1bc34c6SMatt Jacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1548a1bc34c6SMatt Jacob xpt_done(ccb); 1549f48ce188SMatt Jacob } 1550f48ce188SMatt Jacob 1551d81ba9d5SMatt Jacob /* 1552d81ba9d5SMatt Jacob * Handle ATIO stuff that the generic code can't. 1553d81ba9d5SMatt Jacob * This means handling CDBs. 1554d81ba9d5SMatt Jacob */ 1555d81ba9d5SMatt Jacob 1556d81ba9d5SMatt Jacob static int 15579cd7268eSMatt Jacob isp_handle_platform_atio(ispsoftc_t *isp, at_entry_t *aep) 1558d81ba9d5SMatt Jacob { 1559d81ba9d5SMatt Jacob tstate_t *tptr; 156064edff94SMatt Jacob int status, bus, iswildcard; 1561d81ba9d5SMatt Jacob struct ccb_accept_tio *atiop; 1562d81ba9d5SMatt Jacob 1563d81ba9d5SMatt Jacob /* 1564d81ba9d5SMatt Jacob * The firmware status (except for the QLTM_SVALID bit) 1565d81ba9d5SMatt Jacob * indicates why this ATIO was sent to us. 1566d81ba9d5SMatt Jacob * 1567d81ba9d5SMatt Jacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 1568d81ba9d5SMatt Jacob * 1569d81ba9d5SMatt Jacob * If the DISCONNECTS DISABLED bit is set in the flags field, 15705d571944SMatt Jacob * we're still connected on the SCSI bus. 1571d81ba9d5SMatt Jacob */ 1572d81ba9d5SMatt Jacob status = aep->at_status; 1573d81ba9d5SMatt Jacob if ((status & ~QLTM_SVALID) == AT_PHASE_ERROR) { 1574d81ba9d5SMatt Jacob /* 1575d81ba9d5SMatt Jacob * Bus Phase Sequence error. We should have sense data 1576d81ba9d5SMatt Jacob * suggested by the f/w. I'm not sure quite yet what 1577d81ba9d5SMatt Jacob * to do about this for CAM. 1578d81ba9d5SMatt Jacob */ 15793c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, "PHASE ERROR"); 1580d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1581d81ba9d5SMatt Jacob return (0); 1582d81ba9d5SMatt Jacob } 1583d81ba9d5SMatt Jacob if ((status & ~QLTM_SVALID) != AT_CDB) { 15845d571944SMatt Jacob isp_prt(isp, ISP_LOGWARN, "bad atio (0x%x) leaked to platform", 15853c75bb14SMatt Jacob status); 1586d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1587d81ba9d5SMatt Jacob return (0); 1588d81ba9d5SMatt Jacob } 1589d81ba9d5SMatt Jacob 15905d571944SMatt Jacob bus = GET_BUS_VAL(aep->at_iid); 1591a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, aep->at_lun); 1592d81ba9d5SMatt Jacob if (tptr == NULL) { 1593a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD); 1594746e9c85SMatt Jacob if (tptr == NULL) { 1595d81ba9d5SMatt Jacob /* 1596d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1597d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1598d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a BUSY status 1599d81ba9d5SMatt Jacob * instead. This works out okay because the only 1600d81ba9d5SMatt Jacob * time we should, in fact, get this, is in the 1601d81ba9d5SMatt Jacob * case that somebody configured us without the 1602d81ba9d5SMatt Jacob * blackhole driver, so they get what they deserve. 1603d81ba9d5SMatt Jacob */ 1604d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1605d81ba9d5SMatt Jacob return (0); 1606d81ba9d5SMatt Jacob } 16078c4e89e2SMatt Jacob iswildcard = 1; 16088c4e89e2SMatt Jacob } else { 16098c4e89e2SMatt Jacob iswildcard = 0; 16108c4e89e2SMatt Jacob } 1611d81ba9d5SMatt Jacob 1612d81ba9d5SMatt Jacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 1613d81ba9d5SMatt Jacob if (atiop == NULL) { 1614d81ba9d5SMatt Jacob /* 1615d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1616d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1617d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a QUEUE FULL status 1618d81ba9d5SMatt Jacob * instead. This works out okay because the only time we 1619d81ba9d5SMatt Jacob * should, in fact, get this, is in the case that we've 1620d81ba9d5SMatt Jacob * run out of ATIOS. 1621d81ba9d5SMatt Jacob */ 1622dd9fc7c3SMatt Jacob xpt_print(tptr->owner, 1623dd9fc7c3SMatt Jacob "no ATIOS for lun %d from initiator %d on channel %d\n", 16245d571944SMatt Jacob aep->at_lun, GET_IID_VAL(aep->at_iid), bus); 1625d81ba9d5SMatt Jacob if (aep->at_flags & AT_TQAE) 1626d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); 1627d81ba9d5SMatt Jacob else 1628d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 162964edff94SMatt Jacob rls_lun_statep(isp, tptr); 1630d81ba9d5SMatt Jacob return (0); 1631d81ba9d5SMatt Jacob } 1632d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 1633746e9c85SMatt Jacob tptr->atio_count--; 1634746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO lun %d, count now %d", 1635746e9c85SMatt Jacob aep->at_lun, tptr->atio_count); 163664edff94SMatt Jacob if (iswildcard) { 1637d81ba9d5SMatt Jacob atiop->ccb_h.target_id = aep->at_tgt; 1638d81ba9d5SMatt Jacob atiop->ccb_h.target_lun = aep->at_lun; 1639d81ba9d5SMatt Jacob } 1640d81ba9d5SMatt Jacob if (aep->at_flags & AT_NODISC) { 1641f48ce188SMatt Jacob atiop->ccb_h.flags = CAM_DIS_DISCONNECT; 1642f48ce188SMatt Jacob } else { 1643f48ce188SMatt Jacob atiop->ccb_h.flags = 0; 1644d81ba9d5SMatt Jacob } 1645d81ba9d5SMatt Jacob 1646f48ce188SMatt Jacob if (status & QLTM_SVALID) { 1647f48ce188SMatt Jacob size_t amt = imin(QLTM_SENSELEN, sizeof (atiop->sense_data)); 1648f48ce188SMatt Jacob atiop->sense_len = amt; 1649f48ce188SMatt Jacob MEMCPY(&atiop->sense_data, aep->at_sense, amt); 1650f48ce188SMatt Jacob } else { 1651f48ce188SMatt Jacob atiop->sense_len = 0; 1652f48ce188SMatt Jacob } 1653d81ba9d5SMatt Jacob 16545d571944SMatt Jacob atiop->init_id = GET_IID_VAL(aep->at_iid); 1655d81ba9d5SMatt Jacob atiop->cdb_len = aep->at_cdblen; 1656d81ba9d5SMatt Jacob MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen); 1657d81ba9d5SMatt Jacob atiop->ccb_h.status = CAM_CDB_RECVD; 1658a1bc34c6SMatt Jacob /* 1659a1bc34c6SMatt Jacob * Construct a tag 'id' based upon tag value (which may be 0..255) 1660a1bc34c6SMatt Jacob * and the handle (which we have to preserve). 1661a1bc34c6SMatt Jacob */ 16626c81a0aeSMatt Jacob AT_MAKE_TAGID(atiop->tag_id, bus, device_get_unit(isp->isp_dev), aep); 1663a1bc34c6SMatt Jacob if (aep->at_flags & AT_TQAE) { 1664a1bc34c6SMatt Jacob atiop->tag_action = aep->at_tag_type; 1665d81ba9d5SMatt Jacob atiop->ccb_h.status |= CAM_TAG_ACTION_VALID; 1666d81ba9d5SMatt Jacob } 1667d81ba9d5SMatt Jacob xpt_done((union ccb*)atiop); 166864edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 16695d571944SMatt Jacob "ATIO[%x] CDB=0x%x bus %d iid%d->lun%d tag 0x%x ttype 0x%x %s", 16705d571944SMatt Jacob aep->at_handle, aep->at_cdb[0] & 0xff, GET_BUS_VAL(aep->at_iid), 16715d571944SMatt Jacob GET_IID_VAL(aep->at_iid), aep->at_lun, aep->at_tag_val & 0xff, 16725d571944SMatt Jacob aep->at_tag_type, (aep->at_flags & AT_NODISC)? 16735d571944SMatt Jacob "nondisc" : "disconnecting"); 1674d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1675d81ba9d5SMatt Jacob return (0); 1676d81ba9d5SMatt Jacob } 1677d81ba9d5SMatt Jacob 1678d81ba9d5SMatt Jacob static int 16799cd7268eSMatt Jacob isp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep) 1680d81ba9d5SMatt Jacob { 168192a1e549SMatt Jacob lun_id_t lun; 1682d81ba9d5SMatt Jacob tstate_t *tptr; 1683d81ba9d5SMatt Jacob struct ccb_accept_tio *atiop; 168453036e92SMatt Jacob atio_private_data_t *atp; 1685d81ba9d5SMatt Jacob 1686d81ba9d5SMatt Jacob /* 1687d81ba9d5SMatt Jacob * The firmware status (except for the QLTM_SVALID bit) 1688d81ba9d5SMatt Jacob * indicates why this ATIO was sent to us. 1689d81ba9d5SMatt Jacob * 1690d81ba9d5SMatt Jacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 1691d81ba9d5SMatt Jacob */ 1692d81ba9d5SMatt Jacob if ((aep->at_status & ~QLTM_SVALID) != AT_CDB) { 16933c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 16943c75bb14SMatt Jacob "bogus atio (0x%x) leaked to platform", aep->at_status); 1695d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1696d81ba9d5SMatt Jacob return (0); 1697d81ba9d5SMatt Jacob } 1698d81ba9d5SMatt Jacob 169910365e5aSMatt Jacob if (FCPARAM(isp)->isp_sccfw) { 170092a1e549SMatt Jacob lun = aep->at_scclun; 17012ad50ca5SMatt Jacob } else { 170292a1e549SMatt Jacob lun = aep->at_lun; 17032ad50ca5SMatt Jacob } 1704a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, 0, lun); 1705d81ba9d5SMatt Jacob if (tptr == NULL) { 1706746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1707746e9c85SMatt Jacob "[0x%x] no state pointer for lun %d", aep->at_rxid, lun); 1708a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD); 1709746e9c85SMatt Jacob if (tptr == NULL) { 1710746e9c85SMatt Jacob isp_endcmd(isp, aep, 1711746e9c85SMatt Jacob SCSI_STATUS_CHECK_COND | ECMD_SVALID | 1712746e9c85SMatt Jacob (0x5 << 12) | (0x25 << 16), 0); 1713746e9c85SMatt Jacob return (0); 1714746e9c85SMatt Jacob } 1715d81ba9d5SMatt Jacob } 1716d81ba9d5SMatt Jacob 171753036e92SMatt Jacob atp = isp_get_atpd(isp, 0); 1718d81ba9d5SMatt Jacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 171953036e92SMatt Jacob if (atiop == NULL || atp == NULL) { 1720746e9c85SMatt Jacob 1721d81ba9d5SMatt Jacob /* 1722d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1723d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1724d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a QUEUE FULL status 1725d81ba9d5SMatt Jacob * instead. This works out okay because the only time we 1726d81ba9d5SMatt Jacob * should, in fact, get this, is in the case that we've 1727d81ba9d5SMatt Jacob * run out of ATIOS. 1728d81ba9d5SMatt Jacob */ 1729dd9fc7c3SMatt Jacob xpt_print(tptr->owner, 1730dd9fc7c3SMatt Jacob "no %s for lun %d from initiator %d\n", 1731570c7a3fSMatt Jacob (atp == NULL && atiop == NULL)? "ATIO2s *or* ATPS" : 1732570c7a3fSMatt Jacob ((atp == NULL)? "ATPs" : "ATIO2s"), lun, aep->at_iid); 1733d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1734d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); 1735d81ba9d5SMatt Jacob return (0); 1736d81ba9d5SMatt Jacob } 1737570c7a3fSMatt Jacob atp->state = ATPD_STATE_ATIO; 1738d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 1739570c7a3fSMatt Jacob tptr->atio_count--; 1740746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO lun %d, count now %d", 1741570c7a3fSMatt Jacob lun, tptr->atio_count); 1742f48ce188SMatt Jacob 1743a1bc34c6SMatt Jacob if (tptr == &isp->isp_osinfo.tsdflt[0]) { 174410365e5aSMatt Jacob atiop->ccb_h.target_id = FCPARAM(isp)->isp_loopid; 174592a1e549SMatt Jacob atiop->ccb_h.target_lun = lun; 1746d81ba9d5SMatt Jacob } 1747b0a3ba7eSMatt Jacob /* 1748b0a3ba7eSMatt Jacob * We don't get 'suggested' sense data as we do with SCSI cards. 1749b0a3ba7eSMatt Jacob */ 1750f48ce188SMatt Jacob atiop->sense_len = 0; 1751f48ce188SMatt Jacob 1752d81ba9d5SMatt Jacob atiop->init_id = aep->at_iid; 1753d81ba9d5SMatt Jacob atiop->cdb_len = ATIO2_CDBLEN; 1754d81ba9d5SMatt Jacob MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, ATIO2_CDBLEN); 1755d81ba9d5SMatt Jacob atiop->ccb_h.status = CAM_CDB_RECVD; 1756d81ba9d5SMatt Jacob atiop->tag_id = aep->at_rxid; 1757d81ba9d5SMatt Jacob switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) { 1758d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_SIMPLEQ: 1759d81ba9d5SMatt Jacob atiop->tag_action = MSG_SIMPLE_Q_TAG; 1760d81ba9d5SMatt Jacob break; 1761d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_HEADOFQ: 1762d81ba9d5SMatt Jacob atiop->tag_action = MSG_HEAD_OF_Q_TAG; 1763d81ba9d5SMatt Jacob break; 1764d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_ORDERED: 1765d81ba9d5SMatt Jacob atiop->tag_action = MSG_ORDERED_Q_TAG; 1766d81ba9d5SMatt Jacob break; 1767d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_ACAQ: /* ?? */ 1768d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_UNTAGGED: 1769d81ba9d5SMatt Jacob default: 1770d81ba9d5SMatt Jacob atiop->tag_action = 0; 1771d81ba9d5SMatt Jacob break; 1772d81ba9d5SMatt Jacob } 1773570c7a3fSMatt Jacob atiop->ccb_h.flags = CAM_TAG_ACTION_VALID; 1774f48ce188SMatt Jacob 177553036e92SMatt Jacob atp->tag = atiop->tag_id; 1776570c7a3fSMatt Jacob atp->lun = lun; 177753036e92SMatt Jacob atp->orig_datalen = aep->at_datalen; 177853036e92SMatt Jacob atp->last_xframt = 0; 177953036e92SMatt Jacob atp->bytes_xfered = 0; 1780570c7a3fSMatt Jacob atp->state = ATPD_STATE_CAM; 1781d81ba9d5SMatt Jacob xpt_done((union ccb*)atiop); 1782570c7a3fSMatt Jacob 178364edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 17845f5aafe1SMatt Jacob "ATIO2[%x] CDB=0x%x iid%d->lun%d tattr 0x%x datalen %u", 17855f5aafe1SMatt Jacob aep->at_rxid, aep->at_cdb[0] & 0xff, aep->at_iid, 1786b09b0095SMatt Jacob lun, aep->at_taskflags, aep->at_datalen); 1787d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1788d81ba9d5SMatt Jacob return (0); 1789d81ba9d5SMatt Jacob } 1790d81ba9d5SMatt Jacob 1791d81ba9d5SMatt Jacob static int 17929cd7268eSMatt Jacob isp_handle_platform_ctio(ispsoftc_t *isp, void *arg) 1793d81ba9d5SMatt Jacob { 1794d81ba9d5SMatt Jacob union ccb *ccb; 1795a1bc34c6SMatt Jacob int sentstatus, ok, notify_cam, resid = 0; 17961dae40ebSMatt Jacob uint16_t tval; 1797d81ba9d5SMatt Jacob 1798d81ba9d5SMatt Jacob /* 1799d81ba9d5SMatt Jacob * CTIO and CTIO2 are close enough.... 1800d81ba9d5SMatt Jacob */ 1801d81ba9d5SMatt Jacob 180251e23558SNate Lawson ccb = isp_find_xs_tgt(isp, ((ct_entry_t *)arg)->ct_syshandle); 1803d81ba9d5SMatt Jacob KASSERT((ccb != NULL), ("null ccb in isp_handle_platform_ctio")); 180451e23558SNate Lawson isp_destroy_tgt_handle(isp, ((ct_entry_t *)arg)->ct_syshandle); 1805d81ba9d5SMatt Jacob 1806d81ba9d5SMatt Jacob if (IS_FC(isp)) { 1807d81ba9d5SMatt Jacob ct2_entry_t *ct = arg; 1808570c7a3fSMatt Jacob atio_private_data_t *atp = isp_get_atpd(isp, ct->ct_rxid); 1809570c7a3fSMatt Jacob if (atp == NULL) { 1810570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGERR, 1811570c7a3fSMatt Jacob "cannot find adjunct for %x after I/O", 1812570c7a3fSMatt Jacob ct->ct_rxid); 1813570c7a3fSMatt Jacob return (0); 1814570c7a3fSMatt Jacob } 1815d81ba9d5SMatt Jacob sentstatus = ct->ct_flags & CT2_SENDSTATUS; 1816d81ba9d5SMatt Jacob ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; 1817a1bc34c6SMatt Jacob if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) { 181800a8e174SMatt Jacob ccb->ccb_h.status |= CAM_SENT_SENSE; 181900a8e174SMatt Jacob } 1820a1bc34c6SMatt Jacob notify_cam = ct->ct_header.rqs_seqno & 0x1; 18215d571944SMatt Jacob if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) { 1822a1bc34c6SMatt Jacob resid = ct->ct_resid; 182353036e92SMatt Jacob atp->bytes_xfered += (atp->last_xframt - resid); 182453036e92SMatt Jacob atp->last_xframt = 0; 1825570c7a3fSMatt Jacob } 1826570c7a3fSMatt Jacob if (sentstatus || !ok) { 182753036e92SMatt Jacob atp->tag = 0; 182853036e92SMatt Jacob } 1829570c7a3fSMatt Jacob isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, 183064edff94SMatt Jacob "CTIO2[%x] sts 0x%x flg 0x%x sns %d resid %d %s", 183164edff94SMatt Jacob ct->ct_rxid, ct->ct_status, ct->ct_flags, 183264edff94SMatt Jacob (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, 183364edff94SMatt Jacob resid, sentstatus? "FIN" : "MID"); 183464edff94SMatt Jacob tval = ct->ct_rxid; 1835570c7a3fSMatt Jacob 1836570c7a3fSMatt Jacob /* XXX: should really come after isp_complete_ctio */ 1837570c7a3fSMatt Jacob atp->state = ATPD_STATE_PDON; 1838d81ba9d5SMatt Jacob } else { 1839d81ba9d5SMatt Jacob ct_entry_t *ct = arg; 1840d81ba9d5SMatt Jacob sentstatus = ct->ct_flags & CT_SENDSTATUS; 1841d81ba9d5SMatt Jacob ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; 1842d81ba9d5SMatt Jacob /* 1843a1bc34c6SMatt Jacob * We *ought* to be able to get back to the original ATIO 1844a1bc34c6SMatt Jacob * here, but for some reason this gets lost. It's just as 1845a1bc34c6SMatt Jacob * well because it's squirrelled away as part of periph 1846a1bc34c6SMatt Jacob * private data. 1847a1bc34c6SMatt Jacob * 1848a1bc34c6SMatt Jacob * We can live without it as long as we continue to use 1849a1bc34c6SMatt Jacob * the auto-replenish feature for CTIOs. 1850a1bc34c6SMatt Jacob */ 1851a1bc34c6SMatt Jacob notify_cam = ct->ct_header.rqs_seqno & 0x1; 1852a1bc34c6SMatt Jacob if (ct->ct_status & QLTM_SVALID) { 1853a1bc34c6SMatt Jacob char *sp = (char *)ct; 1854a1bc34c6SMatt Jacob sp += CTIO_SENSE_OFFSET; 1855a1bc34c6SMatt Jacob ccb->csio.sense_len = 1856a1bc34c6SMatt Jacob min(sizeof (ccb->csio.sense_data), QLTM_SENSELEN); 1857a1bc34c6SMatt Jacob MEMCPY(&ccb->csio.sense_data, sp, ccb->csio.sense_len); 1858a1bc34c6SMatt Jacob ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 1859a1bc34c6SMatt Jacob } 18605d571944SMatt Jacob if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) { 1861a1bc34c6SMatt Jacob resid = ct->ct_resid; 1862a1bc34c6SMatt Jacob } 186364edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 186464edff94SMatt Jacob "CTIO[%x] tag %x iid %d lun %d sts %x flg %x resid %d %s", 186564edff94SMatt Jacob ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_lun, 186664edff94SMatt Jacob ct->ct_status, ct->ct_flags, resid, 186764edff94SMatt Jacob sentstatus? "FIN" : "MID"); 186864edff94SMatt Jacob tval = ct->ct_fwhandle; 18695d571944SMatt Jacob } 1870a1bc34c6SMatt Jacob ccb->csio.resid += resid; 1871a1bc34c6SMatt Jacob 1872a1bc34c6SMatt Jacob /* 1873a1bc34c6SMatt Jacob * We're here either because intermediate data transfers are done 1874a1bc34c6SMatt Jacob * and/or the final status CTIO (which may have joined with a 1875a1bc34c6SMatt Jacob * Data Transfer) is done. 1876d81ba9d5SMatt Jacob * 1877d81ba9d5SMatt Jacob * In any case, for this platform, the upper layers figure out 1878d81ba9d5SMatt Jacob * what to do next, so all we do here is collect status and 1879a1bc34c6SMatt Jacob * pass information along. Any DMA handles have already been 1880a1bc34c6SMatt Jacob * freed. 1881d81ba9d5SMatt Jacob */ 1882f48ce188SMatt Jacob if (notify_cam == 0) { 188364edff94SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, " INTER CTIO[0x%x] done", tval); 1884f48ce188SMatt Jacob return (0); 1885f48ce188SMatt Jacob } 1886d81ba9d5SMatt Jacob 188753036e92SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO[0x%x] done", 188853036e92SMatt Jacob (sentstatus)? " FINAL " : "MIDTERM ", tval); 1889a1bc34c6SMatt Jacob 1890a1bc34c6SMatt Jacob if (!ok) { 1891a1bc34c6SMatt Jacob isp_target_putback_atio(ccb); 1892d81ba9d5SMatt Jacob } else { 1893a1bc34c6SMatt Jacob isp_complete_ctio(ccb); 1894a1bc34c6SMatt Jacob 1895d81ba9d5SMatt Jacob } 1896a1bc34c6SMatt Jacob return (0); 1897d81ba9d5SMatt Jacob } 1898570c7a3fSMatt Jacob 1899570c7a3fSMatt Jacob static int 19009cd7268eSMatt Jacob isp_handle_platform_notify_scsi(ispsoftc_t *isp, in_entry_t *inp) 1901570c7a3fSMatt Jacob { 1902570c7a3fSMatt Jacob return (0); /* XXXX */ 1903570c7a3fSMatt Jacob } 1904570c7a3fSMatt Jacob 1905570c7a3fSMatt Jacob static int 19069cd7268eSMatt Jacob isp_handle_platform_notify_fc(ispsoftc_t *isp, in_fcentry_t *inp) 1907570c7a3fSMatt Jacob { 1908570c7a3fSMatt Jacob 1909570c7a3fSMatt Jacob switch (inp->in_status) { 1910570c7a3fSMatt Jacob case IN_PORT_LOGOUT: 1911570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, "port logout of iid %d", 1912570c7a3fSMatt Jacob inp->in_iid); 1913570c7a3fSMatt Jacob break; 1914570c7a3fSMatt Jacob case IN_PORT_CHANGED: 1915570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, "port changed for iid %d", 1916570c7a3fSMatt Jacob inp->in_iid); 1917570c7a3fSMatt Jacob break; 1918570c7a3fSMatt Jacob case IN_GLOBAL_LOGO: 1919570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGINFO, "all ports logged out"); 1920570c7a3fSMatt Jacob break; 1921570c7a3fSMatt Jacob case IN_ABORT_TASK: 1922570c7a3fSMatt Jacob { 1923570c7a3fSMatt Jacob atio_private_data_t *atp = isp_get_atpd(isp, inp->in_seqid); 1924570c7a3fSMatt Jacob struct ccb_immed_notify *inot = NULL; 1925570c7a3fSMatt Jacob 1926570c7a3fSMatt Jacob if (atp) { 1927570c7a3fSMatt Jacob tstate_t *tptr = get_lun_statep(isp, 0, atp->lun); 1928570c7a3fSMatt Jacob if (tptr) { 1929570c7a3fSMatt Jacob inot = (struct ccb_immed_notify *) 1930570c7a3fSMatt Jacob SLIST_FIRST(&tptr->inots); 1931570c7a3fSMatt Jacob if (inot) { 1932746e9c85SMatt Jacob tptr->inot_count--; 1933570c7a3fSMatt Jacob SLIST_REMOVE_HEAD(&tptr->inots, 1934570c7a3fSMatt Jacob sim_links.sle); 1935746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1936746e9c85SMatt Jacob "Take FREE INOT count now %d", 1937746e9c85SMatt Jacob tptr->inot_count); 1938570c7a3fSMatt Jacob } 1939570c7a3fSMatt Jacob } 1940570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, 1941570c7a3fSMatt Jacob "abort task RX_ID %x IID %d state %d", 1942570c7a3fSMatt Jacob inp->in_seqid, inp->in_iid, atp->state); 1943570c7a3fSMatt Jacob } else { 1944570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGWARN, 1945570c7a3fSMatt Jacob "abort task RX_ID %x from iid %d, state unknown", 1946570c7a3fSMatt Jacob inp->in_seqid, inp->in_iid); 1947570c7a3fSMatt Jacob } 1948570c7a3fSMatt Jacob if (inot) { 1949570c7a3fSMatt Jacob inot->initiator_id = inp->in_iid; 1950570c7a3fSMatt Jacob inot->sense_len = 0; 1951570c7a3fSMatt Jacob inot->message_args[0] = MSG_ABORT_TAG; 1952570c7a3fSMatt Jacob inot->message_args[1] = inp->in_seqid & 0xff; 1953570c7a3fSMatt Jacob inot->message_args[2] = (inp->in_seqid >> 8) & 0xff; 19546b5ec766SMatt Jacob inot->ccb_h.status = CAM_MESSAGE_RECV; 1955570c7a3fSMatt Jacob xpt_done((union ccb *)inot); 1956570c7a3fSMatt Jacob } 1957570c7a3fSMatt Jacob break; 1958570c7a3fSMatt Jacob } 1959570c7a3fSMatt Jacob default: 1960570c7a3fSMatt Jacob break; 1961570c7a3fSMatt Jacob } 1962570c7a3fSMatt Jacob return (0); 1963570c7a3fSMatt Jacob } 1964d81ba9d5SMatt Jacob #endif 1965d81ba9d5SMatt Jacob 1966478f8a96SJustin T. Gibbs static void 19671dae40ebSMatt Jacob isp_cam_async(void *cbarg, uint32_t code, struct cam_path *path, void *arg) 1968478f8a96SJustin T. Gibbs { 1969478f8a96SJustin T. Gibbs struct cam_sim *sim; 19709cd7268eSMatt Jacob ispsoftc_t *isp; 1971478f8a96SJustin T. Gibbs 1972478f8a96SJustin T. Gibbs sim = (struct cam_sim *)cbarg; 19739cd7268eSMatt Jacob isp = (ispsoftc_t *) cam_sim_softc(sim); 1974478f8a96SJustin T. Gibbs switch (code) { 1975478f8a96SJustin T. Gibbs case AC_LOST_DEVICE: 1976ab6c4b31SMatt Jacob if (IS_SCSI(isp)) { 19771dae40ebSMatt Jacob uint16_t oflags, nflags; 1978478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 1979a1bc34c6SMatt Jacob int tgt; 1980478f8a96SJustin T. Gibbs 1981f9e908dcSMatt Jacob tgt = xpt_path_target_id(path); 198241ed683eSMatt Jacob if (tgt >= 0) { 1983ea6f23cdSMatt Jacob sdp += cam_sim_bus(sim); 19849ce9bdafSMatt Jacob nflags = sdp->isp_devparam[tgt].nvrm_flags; 1985a1bc34c6SMatt Jacob #ifndef ISP_TARGET_MODE 19869ce9bdafSMatt Jacob nflags &= DPARM_SAFE_DFLT; 1987a1bc34c6SMatt Jacob if (isp->isp_loaded_fw) { 1988478f8a96SJustin T. Gibbs nflags |= DPARM_NARROW | DPARM_ASYNC; 1989478f8a96SJustin T. Gibbs } 1990a1bc34c6SMatt Jacob #else 1991a1bc34c6SMatt Jacob nflags = DPARM_DEFAULT; 1992a1bc34c6SMatt Jacob #endif 19939ce9bdafSMatt Jacob oflags = sdp->isp_devparam[tgt].goal_flags; 19949ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_flags = nflags; 1995478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_update = 1; 1996a1bc34c6SMatt Jacob isp->isp_update |= (1 << cam_sim_bus(sim)); 199741ed683eSMatt Jacob (void) isp_control(isp, 199841ed683eSMatt Jacob ISPCTL_UPDATE_PARAMS, NULL); 19999ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_flags = oflags; 2000478f8a96SJustin T. Gibbs } 200141ed683eSMatt Jacob } 2002478f8a96SJustin T. Gibbs break; 2003478f8a96SJustin T. Gibbs default: 20043c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, "isp_cam_async: Code 0x%x", code); 2005478f8a96SJustin T. Gibbs break; 2006478f8a96SJustin T. Gibbs } 2007478f8a96SJustin T. Gibbs } 2008478f8a96SJustin T. Gibbs 2009478f8a96SJustin T. Gibbs static void 2010c3055363SMatt Jacob isp_poll(struct cam_sim *sim) 2011478f8a96SJustin T. Gibbs { 20129cd7268eSMatt Jacob ispsoftc_t *isp = cam_sim_softc(sim); 201310365e5aSMatt Jacob uint32_t isr; 201410365e5aSMatt Jacob uint16_t sema, mbox; 2015126ec864SMatt Jacob 2016126ec864SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 2017126ec864SMatt Jacob isp_intr(isp, isr, sema, mbox); 2018126ec864SMatt Jacob } 2019478f8a96SJustin T. Gibbs } 2020478f8a96SJustin T. Gibbs 2021ab6c4b31SMatt Jacob 2022f7c631bcSMatt Jacob static int isp_watchdog_work(ispsoftc_t *, XS_T *); 2023f7c631bcSMatt Jacob 2024f7c631bcSMatt Jacob static int 2025f7c631bcSMatt Jacob isp_watchdog_work(ispsoftc_t *isp, XS_T *xs) 2026cc8df88bSMatt Jacob { 20271dae40ebSMatt Jacob uint32_t handle; 2028b85389e1SMatt Jacob 2029cc8df88bSMatt Jacob /* 2030b85389e1SMatt Jacob * We've decided this command is dead. Make sure we're not trying 2031b85389e1SMatt Jacob * to kill a command that's already dead by getting it's handle and 2032b85389e1SMatt Jacob * and seeing whether it's still alive. 2033cc8df88bSMatt Jacob */ 2034cc8df88bSMatt Jacob handle = isp_find_handle(isp, xs); 2035cc8df88bSMatt Jacob if (handle) { 203610365e5aSMatt Jacob uint32_t isr; 203710365e5aSMatt Jacob uint16_t sema, mbox; 2038126ec864SMatt Jacob 2039b85389e1SMatt Jacob if (XS_CMD_DONE_P(xs)) { 2040b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG1, 2041b09b0095SMatt Jacob "watchdog found done cmd (handle 0x%x)", handle); 2042f7c631bcSMatt Jacob return (1);; 2043b85389e1SMatt Jacob } 2044b85389e1SMatt Jacob 2045b85389e1SMatt Jacob if (XS_CMD_WDOG_P(xs)) { 2046b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2047b09b0095SMatt Jacob "recursive watchdog (handle 0x%x)", handle); 2048f7c631bcSMatt Jacob return (1); 2049b85389e1SMatt Jacob } 2050b85389e1SMatt Jacob 2051b85389e1SMatt Jacob XS_CMD_S_WDOG(xs); 2052126ec864SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 2053126ec864SMatt Jacob isp_intr(isp, isr, sema, mbox); 2054126ec864SMatt Jacob } 2055126ec864SMatt Jacob if (XS_CMD_DONE_P(xs)) { 2056b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2057126ec864SMatt Jacob "watchdog cleanup for handle 0x%x", handle); 20580a70657fSMatt Jacob isp_free_pcmd(isp, (union ccb *)xs); 2059b85389e1SMatt Jacob xpt_done((union ccb *) xs); 2060b85389e1SMatt Jacob } else if (XS_CMD_GRACE_P(xs)) { 20611fcf5debSMatt Jacob /* 20621fcf5debSMatt Jacob * Make sure the command is *really* dead before we 20631fcf5debSMatt Jacob * release the handle (and DMA resources) for reuse. 20641fcf5debSMatt Jacob */ 2065f7c631bcSMatt Jacob (void) isp_control(isp, ISPCTL_ABORT_CMD, xs); 20661fcf5debSMatt Jacob 20671fcf5debSMatt Jacob /* 20681fcf5debSMatt Jacob * After this point, the comamnd is really dead. 20691fcf5debSMatt Jacob */ 2070f6e75de2SMatt Jacob if (XS_XFRLEN(xs)) { 2071f6e75de2SMatt Jacob ISP_DMAFREE(isp, xs, handle); 2072f6e75de2SMatt Jacob } 2073cc8df88bSMatt Jacob isp_destroy_handle(isp, handle); 2074dd9fc7c3SMatt Jacob xpt_print(xs->ccb_h.path, 2075dd9fc7c3SMatt Jacob "watchdog timeout for handle 0x%x\n", handle); 2076cc8df88bSMatt Jacob XS_SETERR(xs, CAM_CMD_TIMEOUT); 2077b85389e1SMatt Jacob XS_CMD_C_WDOG(xs); 2078cc8df88bSMatt Jacob isp_done(xs); 2079b85389e1SMatt Jacob } else { 2080b85389e1SMatt Jacob XS_CMD_C_WDOG(xs); 2081b85389e1SMatt Jacob xs->ccb_h.timeout_ch = timeout(isp_watchdog, xs, hz); 2082b85389e1SMatt Jacob XS_CMD_S_GRACE(xs); 208310365e5aSMatt Jacob isp->isp_sendmarker |= 1 << XS_CHANNEL(xs); 2084b85389e1SMatt Jacob } 2085f7c631bcSMatt Jacob return (1); 2086cc8df88bSMatt Jacob } 2087f7c631bcSMatt Jacob return (0); 2088f7c631bcSMatt Jacob } 2089f7c631bcSMatt Jacob 2090f7c631bcSMatt Jacob static void 2091f7c631bcSMatt Jacob isp_watchdog(void *arg) 2092f7c631bcSMatt Jacob { 2093f7c631bcSMatt Jacob ispsoftc_t *isp; 2094f7c631bcSMatt Jacob XS_T *xs = arg; 20950a70657fSMatt Jacob int r; 20960a70657fSMatt Jacob 20970a70657fSMatt Jacob for (r = 0, isp = isplist; r && isp; isp = isp->isp_osinfo.next) { 20980a70657fSMatt Jacob ISP_LOCK(isp); 20990a70657fSMatt Jacob r = isp_watchdog_work(isp, xs); 21000a70657fSMatt Jacob ISP_UNLOCK(isp); 2101f7c631bcSMatt Jacob } 2102f7c631bcSMatt Jacob if (isp == NULL) { 2103f7c631bcSMatt Jacob printf("isp_watchdog: nobody had %p active\n", arg); 2104f7c631bcSMatt Jacob } 2105f7c631bcSMatt Jacob } 2106f7c631bcSMatt Jacob 2107f7c631bcSMatt Jacob 210870273f90SMatt Jacob #if __FreeBSD_version >= 600000 2109f7c631bcSMatt Jacob static void 2110ffcf6651SMatt Jacob isp_make_here(ispsoftc_t *isp, int tgt) 2111f7c631bcSMatt Jacob { 2112ffcf6651SMatt Jacob union ccb *ccb; 2113ffcf6651SMatt Jacob /* 2114ffcf6651SMatt Jacob * Allocate a CCB, create a wildcard path for this bus, 2115ffcf6651SMatt Jacob * and schedule a rescan. 2116ffcf6651SMatt Jacob */ 21178008a935SScott Long ccb = xpt_alloc_ccb_nowait(); 2118ffcf6651SMatt Jacob if (ccb == NULL) { 2119ffcf6651SMatt Jacob isp_prt(isp, ISP_LOGWARN, "unable to alloc CCB for rescan"); 2120ffcf6651SMatt Jacob return; 2121ffcf6651SMatt Jacob } 2122ffcf6651SMatt Jacob if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, 2123ffcf6651SMatt Jacob cam_sim_path(isp->isp_sim), tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 2124ffcf6651SMatt Jacob isp_prt(isp, ISP_LOGWARN, "unable to create path for rescan"); 2125ffcf6651SMatt Jacob xpt_free_ccb(ccb); 2126ffcf6651SMatt Jacob return; 2127ffcf6651SMatt Jacob } 2128ffcf6651SMatt Jacob xpt_rescan(ccb); 2129ffcf6651SMatt Jacob } 2130ffcf6651SMatt Jacob 2131ffcf6651SMatt Jacob static void 2132ffcf6651SMatt Jacob isp_make_gone(ispsoftc_t *isp, int tgt) 2133ffcf6651SMatt Jacob { 2134ffcf6651SMatt Jacob struct cam_path *tp; 2135ffcf6651SMatt Jacob if (xpt_create_path(&tp, NULL, cam_sim_path(isp->isp_sim), tgt, 2136f7c631bcSMatt Jacob CAM_LUN_WILDCARD) == CAM_REQ_CMP) { 2137ffcf6651SMatt Jacob xpt_async(AC_LOST_DEVICE, tp, NULL); 2138ffcf6651SMatt Jacob xpt_free_path(tp); 2139f7c631bcSMatt Jacob } 2140f7c631bcSMatt Jacob } 2141f7c631bcSMatt Jacob #else 2142f7c631bcSMatt Jacob #define isp_make_here(isp, tgt) do { ; } while (0) 2143f7c631bcSMatt Jacob #define isp_make_gone(isp, tgt) do { ; } while (0) 2144f7c631bcSMatt Jacob #endif 2145f7c631bcSMatt Jacob 2146f7c631bcSMatt Jacob 2147f7c631bcSMatt Jacob /* 2148f7c631bcSMatt Jacob * Gone Device Timer Function- when we have decided that a device has gone 2149f7c631bcSMatt Jacob * away, we wait a specific period of time prior to telling the OS it has 2150f7c631bcSMatt Jacob * gone away. 2151f7c631bcSMatt Jacob * 2152f7c631bcSMatt Jacob * This timer function fires once a second and then scans the port database 2153f7c631bcSMatt Jacob * for devices that are marked dead but still have a virtual target assigned. 2154f7c631bcSMatt Jacob * We decrement a counter for that port database entry, and when it hits zero, 2155f7c631bcSMatt Jacob * we tell the OS the device has gone away. 2156f7c631bcSMatt Jacob */ 2157f7c631bcSMatt Jacob static void 2158f7c631bcSMatt Jacob isp_gdt(void *arg) 2159f7c631bcSMatt Jacob { 2160f7c631bcSMatt Jacob ispsoftc_t *isp = arg; 2161f7c631bcSMatt Jacob fcportdb_t *lp; 2162f7c631bcSMatt Jacob int dbidx, tgt, more_to_do = 0; 2163f7c631bcSMatt Jacob 2164f7c631bcSMatt Jacob ISP_LOCK(isp); 21650a70657fSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "GDT timer expired"); 2166f7c631bcSMatt Jacob for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { 2167f7c631bcSMatt Jacob lp = &FCPARAM(isp)->portdb[dbidx]; 2168f7c631bcSMatt Jacob 2169f7c631bcSMatt Jacob if (lp->state != FC_PORTDB_STATE_ZOMBIE) { 2170f7c631bcSMatt Jacob continue; 2171f7c631bcSMatt Jacob } 2172f7c631bcSMatt Jacob if (lp->ini_map_idx == 0) { 2173f7c631bcSMatt Jacob continue; 2174f7c631bcSMatt Jacob } 2175f7c631bcSMatt Jacob if (lp->new_reserved == 0) { 2176f7c631bcSMatt Jacob continue; 2177f7c631bcSMatt Jacob } 2178f7c631bcSMatt Jacob lp->new_reserved -= 1; 2179f7c631bcSMatt Jacob if (lp->new_reserved != 0) { 2180f7c631bcSMatt Jacob more_to_do++; 2181f7c631bcSMatt Jacob continue; 2182f7c631bcSMatt Jacob } 2183f7c631bcSMatt Jacob tgt = lp->ini_map_idx - 1; 2184f7c631bcSMatt Jacob FCPARAM(isp)->isp_ini_map[tgt] = 0; 2185f7c631bcSMatt Jacob lp->ini_map_idx = 0; 2186f7c631bcSMatt Jacob lp->state = FC_PORTDB_STATE_NIL; 2187f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGCONFIG, prom3, lp->portid, tgt, 2188f7c631bcSMatt Jacob "Gone Device Timeout"); 2189f7c631bcSMatt Jacob isp_make_gone(isp, tgt); 2190f7c631bcSMatt Jacob } 2191f7c631bcSMatt Jacob if (more_to_do) { 21920a70657fSMatt Jacob isp->isp_osinfo.gdt_running = 1; 21930a70657fSMatt Jacob callout_reset(&isp->isp_osinfo.gdt, hz, isp_gdt, isp); 2194f7c631bcSMatt Jacob } else { 2195f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, 2196f7c631bcSMatt Jacob "stopping Gone Device Timer"); 2197f7c631bcSMatt Jacob isp->isp_osinfo.gdt_running = 0; 2198f7c631bcSMatt Jacob } 2199f7c631bcSMatt Jacob ISP_UNLOCK(isp); 2200f7c631bcSMatt Jacob } 2201f7c631bcSMatt Jacob 2202f7c631bcSMatt Jacob /* 2203f7c631bcSMatt Jacob * Loop Down Timer Function- when loop goes down, a timer is started and 2204f7c631bcSMatt Jacob * and after it expires we come here and take all probational devices that 2205f7c631bcSMatt Jacob * the OS knows about and the tell the OS that they've gone away. 2206f7c631bcSMatt Jacob * 2207f7c631bcSMatt Jacob * We don't clear the devices out of our port database because, when loop 2208f7c631bcSMatt Jacob * come back up, we have to do some actual cleanup with the chip at that 2209f7c631bcSMatt Jacob * point (implicit PLOGO, e.g., to get the chip's port database state right). 2210f7c631bcSMatt Jacob */ 2211f7c631bcSMatt Jacob static void 2212f7c631bcSMatt Jacob isp_ldt(void *arg) 2213f7c631bcSMatt Jacob { 2214f7c631bcSMatt Jacob ispsoftc_t *isp = arg; 2215f7c631bcSMatt Jacob fcportdb_t *lp; 2216f7c631bcSMatt Jacob int dbidx, tgt; 2217f7c631bcSMatt Jacob 2218f7c631bcSMatt Jacob ISP_LOCK(isp); 2219f7c631bcSMatt Jacob 22200a70657fSMatt Jacob isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Loop Down Timer expired"); 22210a70657fSMatt Jacob 2222f7c631bcSMatt Jacob /* 2223f7c631bcSMatt Jacob * Notify to the OS all targets who we now consider have departed. 2224f7c631bcSMatt Jacob */ 2225f7c631bcSMatt Jacob for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { 2226f7c631bcSMatt Jacob lp = &FCPARAM(isp)->portdb[dbidx]; 2227f7c631bcSMatt Jacob 2228f7c631bcSMatt Jacob if (lp->state != FC_PORTDB_STATE_PROBATIONAL) { 2229f7c631bcSMatt Jacob continue; 2230f7c631bcSMatt Jacob } 2231f7c631bcSMatt Jacob if (lp->ini_map_idx == 0) { 2232f7c631bcSMatt Jacob continue; 2233f7c631bcSMatt Jacob } 2234f7c631bcSMatt Jacob 2235f7c631bcSMatt Jacob /* 2236f7c631bcSMatt Jacob * XXX: CLEAN UP AND COMPLETE ANY PENDING COMMANDS FIRST! 2237f7c631bcSMatt Jacob */ 2238f7c631bcSMatt Jacob 2239f7c631bcSMatt Jacob /* 2240f7c631bcSMatt Jacob * Mark that we've announced that this device is gone.... 2241f7c631bcSMatt Jacob */ 2242f7c631bcSMatt Jacob lp->reserved = 1; 2243f7c631bcSMatt Jacob 2244f7c631bcSMatt Jacob /* 2245f7c631bcSMatt Jacob * but *don't* change the state of the entry. Just clear 2246f7c631bcSMatt Jacob * any target id stuff and announce to CAM that the 2247f7c631bcSMatt Jacob * device is gone. This way any necessary PLOGO stuff 2248f7c631bcSMatt Jacob * will happen when loop comes back up. 2249f7c631bcSMatt Jacob */ 2250f7c631bcSMatt Jacob 2251f7c631bcSMatt Jacob tgt = lp->ini_map_idx - 1; 2252f7c631bcSMatt Jacob FCPARAM(isp)->isp_ini_map[tgt] = 0; 2253f7c631bcSMatt Jacob lp->ini_map_idx = 0; 2254f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGCONFIG, prom3, lp->portid, tgt, 2255f7c631bcSMatt Jacob "Loop Down Timeout"); 2256f7c631bcSMatt Jacob isp_make_gone(isp, tgt); 2257f7c631bcSMatt Jacob } 2258f7c631bcSMatt Jacob 2259f7c631bcSMatt Jacob /* 2260f7c631bcSMatt Jacob * The loop down timer has expired. Wake up the kthread 2261f7c631bcSMatt Jacob * to notice that fact (or make it false). 2262f7c631bcSMatt Jacob */ 2263f7c631bcSMatt Jacob isp->isp_osinfo.loop_down_time = isp->isp_osinfo.loop_down_limit+1; 22640a70657fSMatt Jacob wakeup(ISP_KT_WCHAN(isp)); 2265f7c631bcSMatt Jacob ISP_UNLOCK(isp); 2266cc8df88bSMatt Jacob } 2267cc8df88bSMatt Jacob 22685d571944SMatt Jacob static void 22695d571944SMatt Jacob isp_kthread(void *arg) 22705d571944SMatt Jacob { 22719cd7268eSMatt Jacob ispsoftc_t *isp = arg; 2272f7c631bcSMatt Jacob int slp = 0; 22739cd7268eSMatt Jacob #if __FreeBSD_version < 500000 22740a70657fSMatt Jacob int s = splcam(); 22750a70657fSMatt Jacob #elif __FreeBSD_version < 700037 2276ee76282eSMatt Jacob mtx_lock(&Giant); 22770a70657fSMatt Jacob #else 22780a70657fSMatt Jacob mtx_lock(&isp->isp_osinfo.lock); 22799cd7268eSMatt Jacob #endif 2280fdeb9f2fSMatt Jacob /* 2281fdeb9f2fSMatt Jacob * The first loop is for our usage where we have yet to have 2282fdeb9f2fSMatt Jacob * gotten good fibre channel state. 2283fdeb9f2fSMatt Jacob */ 22845d571944SMatt Jacob for (;;) { 2285f7c631bcSMatt Jacob int wasfrozen, lb, lim; 2286fdeb9f2fSMatt Jacob 2287f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, 2288f7c631bcSMatt Jacob "isp_kthread: checking FC state"); 2289f7c631bcSMatt Jacob isp->isp_osinfo.mbox_sleep_ok = 1; 229010365e5aSMatt Jacob lb = isp_fc_runstate(isp, 250000); 2291f7c631bcSMatt Jacob isp->isp_osinfo.mbox_sleep_ok = 0; 229210365e5aSMatt Jacob if (lb) { 2293f7c631bcSMatt Jacob /* 2294f7c631bcSMatt Jacob * Increment loop down time by the last sleep interval 2295f7c631bcSMatt Jacob */ 2296f7c631bcSMatt Jacob isp->isp_osinfo.loop_down_time += slp; 229710365e5aSMatt Jacob 229810365e5aSMatt Jacob if (lb < 0) { 2299f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, 230010365e5aSMatt Jacob "kthread: FC loop not up (down count %d)", 230110365e5aSMatt Jacob isp->isp_osinfo.loop_down_time); 230210365e5aSMatt Jacob } else { 2303f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, 230410365e5aSMatt Jacob "kthread: FC got to %d (down count %d)", 230510365e5aSMatt Jacob lb, isp->isp_osinfo.loop_down_time); 2306f44257c2SMatt Jacob } 230710365e5aSMatt Jacob 230810365e5aSMatt Jacob 230910365e5aSMatt Jacob /* 231010365e5aSMatt Jacob * If we've never seen loop up and we've waited longer 2311f7c631bcSMatt Jacob * than quickboot time, or we've seen loop up but we've 2312f7c631bcSMatt Jacob * waited longer than loop_down_limit, give up and go 2313f7c631bcSMatt Jacob * to sleep until loop comes up. 231410365e5aSMatt Jacob */ 2315f7c631bcSMatt Jacob if (FCPARAM(isp)->loop_seen_once == 0) { 2316f7c631bcSMatt Jacob lim = isp_quickboot_time; 231710365e5aSMatt Jacob } else { 2318f7c631bcSMatt Jacob lim = isp->isp_osinfo.loop_down_limit; 2319f7c631bcSMatt Jacob } 2320f7c631bcSMatt Jacob if (isp->isp_osinfo.loop_down_time >= lim) { 2321f7c631bcSMatt Jacob isp_freeze_loopdown(isp, "loop limit hit"); 2322f7c631bcSMatt Jacob slp = 0; 2323f7c631bcSMatt Jacob } else if (isp->isp_osinfo.loop_down_time < 10) { 232410365e5aSMatt Jacob slp = 1; 2325f7c631bcSMatt Jacob } else if (isp->isp_osinfo.loop_down_time < 30) { 2326f7c631bcSMatt Jacob slp = 5; 2327f7c631bcSMatt Jacob } else if (isp->isp_osinfo.loop_down_time < 60) { 2328f7c631bcSMatt Jacob slp = 10; 2329f7c631bcSMatt Jacob } else if (isp->isp_osinfo.loop_down_time < 120) { 2330f7c631bcSMatt Jacob slp = 20; 2331f7c631bcSMatt Jacob } else { 2332f7c631bcSMatt Jacob slp = 30; 2333f44257c2SMatt Jacob } 233410365e5aSMatt Jacob 233510365e5aSMatt Jacob } else { 2336f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, 2337f7c631bcSMatt Jacob "isp_kthread: FC state OK"); 233810365e5aSMatt Jacob isp->isp_osinfo.loop_down_time = 0; 233910365e5aSMatt Jacob slp = 0; 23405d571944SMatt Jacob } 2341fdeb9f2fSMatt Jacob 2342f44257c2SMatt Jacob /* 234310365e5aSMatt Jacob * If we'd frozen the simq, unfreeze it now so that CAM 234410365e5aSMatt Jacob * can start sending us commands. If the FC state isn't 234510365e5aSMatt Jacob * okay yet, they'll hit that in isp_start which will 234610365e5aSMatt Jacob * freeze the queue again. 2347f44257c2SMatt Jacob */ 23485d571944SMatt Jacob wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN; 23495d571944SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN; 23505d571944SMatt Jacob if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) { 2351f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, 2352f7c631bcSMatt Jacob "isp_kthread: releasing simq"); 23535d571944SMatt Jacob xpt_release_simq(isp->isp_sim, 1); 23545d571944SMatt Jacob } 2355f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, 2356f7c631bcSMatt Jacob "isp_kthread: sleep time %d", slp); 23570a70657fSMatt Jacob #if __FreeBSD_version < 700037 23580a70657fSMatt Jacob tsleep(ISP_KT_WCHAN(isp), PRIBIO, "ispf", slp * hz); 23599cd7268eSMatt Jacob #else 23600a70657fSMatt Jacob msleep(ISP_KT_WCHAN(isp), &isp->isp_osinfo.lock, 23610a70657fSMatt Jacob PRIBIO, "ispf", slp * hz); 23629cd7268eSMatt Jacob #endif 236310365e5aSMatt Jacob /* 236410365e5aSMatt Jacob * If slp is zero, we're waking up for the first time after 236510365e5aSMatt Jacob * things have been okay. In this case, we set a deferral state 236610365e5aSMatt Jacob * for all commands and delay hysteresis seconds before starting 236710365e5aSMatt Jacob * the FC state evaluation. This gives the loop/fabric a chance 236810365e5aSMatt Jacob * to settle. 236910365e5aSMatt Jacob */ 237010365e5aSMatt Jacob if (slp == 0 && isp->isp_osinfo.hysteresis) { 2371f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, 2372f7c631bcSMatt Jacob "isp_kthread: sleep hysteresis tick time %d", 2373f7c631bcSMatt Jacob isp->isp_osinfo.hysteresis * hz); 23740a70657fSMatt Jacob #if __FreeBSD_version < 700037 237510365e5aSMatt Jacob (void) tsleep(&isp_fabric_hysteresis, PRIBIO, "ispT", 237610365e5aSMatt Jacob (isp->isp_osinfo.hysteresis * hz)); 23770a70657fSMatt Jacob #else 23780a70657fSMatt Jacob (void) msleep(&isp_fabric_hysteresis, 23790a70657fSMatt Jacob &isp->isp_osinfo.lock, PRIBIO, "ispT", 23800a70657fSMatt Jacob (isp->isp_osinfo.hysteresis * hz)); 23810a70657fSMatt Jacob #endif 238210365e5aSMatt Jacob } 23835d571944SMatt Jacob } 23840a70657fSMatt Jacob #if __FreeBSD_version < 500000 23850a70657fSMatt Jacob splx(s); 23860a70657fSMatt Jacob #elif __FreeBSD_version < 700037 23870a70657fSMatt Jacob mtx_unlock(&Giant); 23880a70657fSMatt Jacob #else 23890a70657fSMatt Jacob mtx_unlock(&isp->isp_osinfo.lock); 23900a70657fSMatt Jacob #endif 23915d571944SMatt Jacob } 23925d571944SMatt Jacob 23930a70657fSMatt Jacob #if __FreeBSD_version < 500000 23940a70657fSMatt Jacob static void isp_action_wrk(struct cam_sim *, union ccb *); 23950a70657fSMatt Jacob static void 23960a70657fSMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb) 23970a70657fSMatt Jacob { 23980a70657fSMatt Jacob ispsoftc_t *isp = (ispsoftc_t *)cam_sim_softc(sim); 23990a70657fSMatt Jacob ISP_LOCK(isp); 24000a70657fSMatt Jacob isp_action_wrk(sim, ccb); 24010a70657fSMatt Jacob ISP_UNLOCK(isp); 24020a70657fSMatt Jacob } 24030a70657fSMatt Jacob #define isp_action isp_action_wrk 24040a70657fSMatt Jacob #endif 24050a70657fSMatt Jacob 2406cc8df88bSMatt Jacob static void 2407c3055363SMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb) 2408478f8a96SJustin T. Gibbs { 24090a70657fSMatt Jacob int bus, tgt, ts, error, lim; 24109cd7268eSMatt Jacob ispsoftc_t *isp; 24114663e367SJustin T. Gibbs struct ccb_trans_settings *cts; 2412478f8a96SJustin T. Gibbs 2413478f8a96SJustin T. Gibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n")); 2414478f8a96SJustin T. Gibbs 24159cd7268eSMatt Jacob isp = (ispsoftc_t *)cam_sim_softc(sim); 24160470d791SMatt Jacob if (isp->isp_state != ISP_RUNSTATE && 24170470d791SMatt Jacob ccb->ccb_h.func_code == XPT_SCSI_IO) { 241857c801f5SMatt Jacob isp_init(isp); 241957c801f5SMatt Jacob if (isp->isp_state != ISP_INITSTATE) { 242057c801f5SMatt Jacob /* 242157c801f5SMatt Jacob * Lie. Say it was a selection timeout. 242257c801f5SMatt Jacob */ 2423b85389e1SMatt Jacob ccb->ccb_h.status = CAM_SEL_TIMEOUT | CAM_DEV_QFRZN; 24240470d791SMatt Jacob xpt_freeze_devq(ccb->ccb_h.path, 1); 242557c801f5SMatt Jacob xpt_done(ccb); 242657c801f5SMatt Jacob return; 242757c801f5SMatt Jacob } 242857c801f5SMatt Jacob isp->isp_state = ISP_RUNSTATE; 242957c801f5SMatt Jacob } 2430b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "isp_action code %x", ccb->ccb_h.func_code); 24310a70657fSMatt Jacob ISP_PCMD(ccb) = NULL; 24325d571944SMatt Jacob 2433478f8a96SJustin T. Gibbs switch (ccb->ccb_h.func_code) { 2434478f8a96SJustin T. Gibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 2435478f8a96SJustin T. Gibbs /* 2436478f8a96SJustin T. Gibbs * Do a couple of preliminary checks... 2437478f8a96SJustin T. Gibbs */ 2438478f8a96SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { 2439478f8a96SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) { 2440478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2441478f8a96SJustin T. Gibbs xpt_done(ccb); 2442478f8a96SJustin T. Gibbs break; 2443478f8a96SJustin T. Gibbs } 2444478f8a96SJustin T. Gibbs } 24450470d791SMatt Jacob #ifdef DIAGNOSTIC 24460470d791SMatt Jacob if (ccb->ccb_h.target_id > (ISP_MAX_TARGETS(isp) - 1)) { 2447dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, "invalid target\n"); 2448478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 24490470d791SMatt Jacob } else if (ccb->ccb_h.target_lun > (ISP_MAX_LUNS(isp) - 1)) { 2450dd9fc7c3SMatt Jacob xpt_print(ccb->ccb_h.path, "invalid lun\n"); 2451478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 2452478f8a96SJustin T. Gibbs } 2453478f8a96SJustin T. Gibbs if (ccb->ccb_h.status == CAM_PATH_INVALID) { 2454478f8a96SJustin T. Gibbs xpt_done(ccb); 2455478f8a96SJustin T. Gibbs break; 2456478f8a96SJustin T. Gibbs } 24570470d791SMatt Jacob #endif 24580a70657fSMatt Jacob ccb->csio.scsi_status = SCSI_STATUS_OK; 24590a70657fSMatt Jacob if (isp_get_pcmd(isp, ccb)) { 24600a70657fSMatt Jacob isp_prt(isp, ISP_LOGWARN, "out of PCMDs"); 24610a70657fSMatt Jacob cam_freeze_devq(ccb->ccb_h.path); 24620a70657fSMatt Jacob cam_release_devq(ccb->ccb_h.path, 24630a70657fSMatt Jacob RELSIM_RELEASE_AFTER_TIMEOUT, 0, 250, 0); 24640a70657fSMatt Jacob xpt_done(ccb); 24650a70657fSMatt Jacob break; 24660a70657fSMatt Jacob } 2467b09b0095SMatt Jacob error = isp_start((XS_T *) ccb); 24680470d791SMatt Jacob switch (error) { 2469478f8a96SJustin T. Gibbs case CMD_QUEUED: 2470f7c631bcSMatt Jacob XS_CMD_S_CLEAR(ccb); 2471478f8a96SJustin T. Gibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 24720a70657fSMatt Jacob if (ccb->ccb_h.timeout == CAM_TIME_INFINITY) { 24730a70657fSMatt Jacob break; 2474d69a5f7dSMatt Jacob } 24750a70657fSMatt Jacob ts = ccb->ccb_h.timeout; 24760a70657fSMatt Jacob if (ts == CAM_TIME_DEFAULT) { 24770a70657fSMatt Jacob ts = 60*1000; 2478cc8df88bSMatt Jacob } 24790a70657fSMatt Jacob ts = isp_mstohz(ts); 24800a70657fSMatt Jacob callout_reset(&PISP_PCMD(ccb)->wdog, ts, 24810a70657fSMatt Jacob isp_watchdog, ccb); 2482478f8a96SJustin T. Gibbs break; 24830470d791SMatt Jacob case CMD_RQLATER: 2484f44257c2SMatt Jacob /* 2485f7c631bcSMatt Jacob * Handle initial and subsequent loop down cases 248610365e5aSMatt Jacob */ 2487f7c631bcSMatt Jacob if (FCPARAM(isp)->loop_seen_once == 0) { 2488f7c631bcSMatt Jacob lim = isp_quickboot_time; 2489f7c631bcSMatt Jacob } else { 2490f7c631bcSMatt Jacob lim = isp->isp_osinfo.loop_down_limit; 2491f7c631bcSMatt Jacob } 2492f7c631bcSMatt Jacob if (isp->isp_osinfo.loop_down_time >= lim) { 2493f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 2494f7c631bcSMatt Jacob "%d.%d downtime (%d) > lim (%d)", 2495f7c631bcSMatt Jacob XS_TGT(ccb), XS_LUN(ccb), 2496f7c631bcSMatt Jacob isp->isp_osinfo.loop_down_time, lim); 2497f7c631bcSMatt Jacob ccb->ccb_h.status = 2498f7c631bcSMatt Jacob CAM_SEL_TIMEOUT|CAM_DEV_QFRZN; 2499f7c631bcSMatt Jacob xpt_freeze_devq(ccb->ccb_h.path, 1); 25000a70657fSMatt Jacob isp_free_pcmd(isp, ccb); 2501f44257c2SMatt Jacob xpt_done(ccb); 2502f44257c2SMatt Jacob break; 2503f44257c2SMatt Jacob } 2504f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 2505f7c631bcSMatt Jacob "%d.%d retry later", XS_TGT(ccb), XS_LUN(ccb)); 2506f7c631bcSMatt Jacob /* 2507f7c631bcSMatt Jacob * Otherwise, retry in a while. 2508f7c631bcSMatt Jacob */ 2509f7c631bcSMatt Jacob cam_freeze_devq(ccb->ccb_h.path); 2510f7c631bcSMatt Jacob cam_release_devq(ccb->ccb_h.path, 2511f7c631bcSMatt Jacob RELSIM_RELEASE_AFTER_TIMEOUT, 0, 1000, 0); 2512f7c631bcSMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 25130a70657fSMatt Jacob isp_free_pcmd(isp, ccb); 2514478f8a96SJustin T. Gibbs xpt_done(ccb); 2515478f8a96SJustin T. Gibbs break; 25160470d791SMatt Jacob case CMD_EAGAIN: 25170a70657fSMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 25180a70657fSMatt Jacob isp_free_pcmd(isp, ccb); 2519478f8a96SJustin T. Gibbs xpt_done(ccb); 2520478f8a96SJustin T. Gibbs break; 25210470d791SMatt Jacob case CMD_COMPLETE: 25220470d791SMatt Jacob isp_done((struct ccb_scsiio *) ccb); 25230470d791SMatt Jacob break; 25240470d791SMatt Jacob default: 2525bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 2526bfbab170SMatt Jacob "What's this? 0x%x at %d in file %s", 252791f1caa2SMatt Jacob error, __LINE__, __FILE__); 2528b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQ_CMP_ERR); 25290a70657fSMatt Jacob isp_free_pcmd(isp, ccb); 25300470d791SMatt Jacob xpt_done(ccb); 2531478f8a96SJustin T. Gibbs } 2532478f8a96SJustin T. Gibbs break; 2533478f8a96SJustin T. Gibbs 2534d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2535478f8a96SJustin T. Gibbs case XPT_EN_LUN: /* Enable LUN as a target */ 253664edff94SMatt Jacob { 253710365e5aSMatt Jacob int seq, i; 253867ff51f1SMatt Jacob seq = isp_en_lun(isp, ccb); 253967ff51f1SMatt Jacob if (seq < 0) { 2540478f8a96SJustin T. Gibbs xpt_done(ccb); 2541478f8a96SJustin T. Gibbs break; 254264edff94SMatt Jacob } 254367ff51f1SMatt Jacob for (i = 0; isp->isp_osinfo.leact[seq] && i < 30 * 1000; i++) { 254410365e5aSMatt Jacob uint32_t isr; 254510365e5aSMatt Jacob uint16_t sema, mbox; 254667ff51f1SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 254767ff51f1SMatt Jacob isp_intr(isp, isr, sema, mbox); 254867ff51f1SMatt Jacob } 254967ff51f1SMatt Jacob DELAY(1000); 255067ff51f1SMatt Jacob } 255167ff51f1SMatt Jacob break; 255267ff51f1SMatt Jacob } 2553d81ba9d5SMatt Jacob case XPT_NOTIFY_ACK: /* recycle notify ack */ 2554d81ba9d5SMatt Jacob case XPT_IMMED_NOTIFY: /* Add Immediate Notify Resource */ 2555d81ba9d5SMatt Jacob case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */ 2556d81ba9d5SMatt Jacob { 2557a1bc34c6SMatt Jacob tstate_t *tptr = 2558a1bc34c6SMatt Jacob get_lun_statep(isp, XS_CHANNEL(ccb), ccb->ccb_h.target_lun); 2559d81ba9d5SMatt Jacob if (tptr == NULL) { 2560d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 2561d81ba9d5SMatt Jacob xpt_done(ccb); 2562d81ba9d5SMatt Jacob break; 2563d81ba9d5SMatt Jacob } 2564f48ce188SMatt Jacob ccb->ccb_h.sim_priv.entries[0].field = 0; 2565f48ce188SMatt Jacob ccb->ccb_h.sim_priv.entries[1].ptr = isp; 2566570c7a3fSMatt Jacob ccb->ccb_h.flags = 0; 2567570c7a3fSMatt Jacob 2568d81ba9d5SMatt Jacob if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 2569570c7a3fSMatt Jacob /* 2570570c7a3fSMatt Jacob * Note that the command itself may not be done- 2571570c7a3fSMatt Jacob * it may not even have had the first CTIO sent. 2572570c7a3fSMatt Jacob */ 2573570c7a3fSMatt Jacob tptr->atio_count++; 2574570c7a3fSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 2575746e9c85SMatt Jacob "Put FREE ATIO, lun %d, count now %d", 2576570c7a3fSMatt Jacob ccb->ccb_h.target_lun, tptr->atio_count); 2577570c7a3fSMatt Jacob SLIST_INSERT_HEAD(&tptr->atios, &ccb->ccb_h, 2578570c7a3fSMatt Jacob sim_links.sle); 2579570c7a3fSMatt Jacob } else if (ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) { 2580746e9c85SMatt Jacob tptr->inot_count++; 2581746e9c85SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 2582746e9c85SMatt Jacob "Put FREE INOT, lun %d, count now %d", 2583746e9c85SMatt Jacob ccb->ccb_h.target_lun, tptr->inot_count); 2584d81ba9d5SMatt Jacob SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, 2585d81ba9d5SMatt Jacob sim_links.sle); 2586570c7a3fSMatt Jacob } else { 2587746e9c85SMatt Jacob isp_prt(isp, ISP_LOGWARN, "Got Notify ACK");; 2588d81ba9d5SMatt Jacob } 2589d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 2590d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_INPROG; 2591d81ba9d5SMatt Jacob break; 2592d81ba9d5SMatt Jacob } 2593d81ba9d5SMatt Jacob case XPT_CONT_TARGET_IO: 2594d81ba9d5SMatt Jacob { 25959cd7268eSMatt Jacob isp_target_start_ctio(isp, ccb); 2596d81ba9d5SMatt Jacob break; 2597d81ba9d5SMatt Jacob } 2598d81ba9d5SMatt Jacob #endif 2599478f8a96SJustin T. Gibbs case XPT_RESET_DEV: /* BDR the specified SCSI device */ 2600d81ba9d5SMatt Jacob 2601d81ba9d5SMatt Jacob bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path)); 2602d81ba9d5SMatt Jacob tgt = ccb->ccb_h.target_id; 2603d81ba9d5SMatt Jacob tgt |= (bus << 16); 2604d81ba9d5SMatt Jacob 2605ea6f23cdSMatt Jacob error = isp_control(isp, ISPCTL_RESET_DEV, &tgt); 2606478f8a96SJustin T. Gibbs if (error) { 2607478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2608478f8a96SJustin T. Gibbs } else { 2609478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2610478f8a96SJustin T. Gibbs } 2611478f8a96SJustin T. Gibbs xpt_done(ccb); 2612478f8a96SJustin T. Gibbs break; 2613478f8a96SJustin T. Gibbs case XPT_ABORT: /* Abort the specified CCB */ 2614d81ba9d5SMatt Jacob { 2615d81ba9d5SMatt Jacob union ccb *accb = ccb->cab.abort_ccb; 2616d81ba9d5SMatt Jacob switch (accb->ccb_h.func_code) { 2617d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2618d81ba9d5SMatt Jacob case XPT_ACCEPT_TARGET_IO: 2619d81ba9d5SMatt Jacob case XPT_IMMED_NOTIFY: 2620d81ba9d5SMatt Jacob ccb->ccb_h.status = isp_abort_tgt_ccb(isp, ccb); 2621d81ba9d5SMatt Jacob break; 2622d81ba9d5SMatt Jacob case XPT_CONT_TARGET_IO: 2623b09b0095SMatt Jacob isp_prt(isp, ISP_LOGERR, "cannot abort CTIOs yet"); 2624d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_UA_ABORT; 2625d81ba9d5SMatt Jacob break; 2626d81ba9d5SMatt Jacob #endif 2627d81ba9d5SMatt Jacob case XPT_SCSI_IO: 2628478f8a96SJustin T. Gibbs error = isp_control(isp, ISPCTL_ABORT_CMD, ccb); 2629478f8a96SJustin T. Gibbs if (error) { 2630d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_UA_ABORT; 2631478f8a96SJustin T. Gibbs } else { 2632478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2633478f8a96SJustin T. Gibbs } 2634d81ba9d5SMatt Jacob break; 2635d81ba9d5SMatt Jacob default: 2636d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_INVALID; 2637d81ba9d5SMatt Jacob break; 2638d81ba9d5SMatt Jacob } 2639478f8a96SJustin T. Gibbs xpt_done(ccb); 2640478f8a96SJustin T. Gibbs break; 2641d81ba9d5SMatt Jacob } 2642805e1f82SMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2643ab163f5fSMatt Jacob #define IS_CURRENT_SETTINGS(c) (c->type == CTS_TYPE_CURRENT_SETTINGS) 2644805e1f82SMatt Jacob #else 2645805e1f82SMatt Jacob #define IS_CURRENT_SETTINGS(c) (c->flags & CCB_TRANS_CURRENT_SETTINGS) 2646805e1f82SMatt Jacob #endif 2647478f8a96SJustin T. Gibbs case XPT_SET_TRAN_SETTINGS: /* Nexus Settings */ 2648478f8a96SJustin T. Gibbs cts = &ccb->cts; 26499ce9bdafSMatt Jacob if (!IS_CURRENT_SETTINGS(cts)) { 26509ce9bdafSMatt Jacob ccb->ccb_h.status = CAM_REQ_INVALID; 26519ce9bdafSMatt Jacob xpt_done(ccb); 26529ce9bdafSMatt Jacob break; 26539ce9bdafSMatt Jacob } 2654478f8a96SJustin T. Gibbs tgt = cts->ccb_h.target_id; 2655ab6c4b31SMatt Jacob if (IS_SCSI(isp)) { 2656805e1f82SMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2657805e1f82SMatt Jacob sdparam *sdp = isp->isp_param; 2658805e1f82SMatt Jacob uint16_t *dptr; 2659805e1f82SMatt Jacob 2660805e1f82SMatt Jacob bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 2661805e1f82SMatt Jacob 2662805e1f82SMatt Jacob sdp += bus; 2663805e1f82SMatt Jacob /* 2664805e1f82SMatt Jacob * We always update (internally) from goal_flags 2665805e1f82SMatt Jacob * so any request to change settings just gets 2666805e1f82SMatt Jacob * vectored to that location. 2667805e1f82SMatt Jacob */ 2668805e1f82SMatt Jacob dptr = &sdp->isp_devparam[tgt].goal_flags; 2669805e1f82SMatt Jacob 2670805e1f82SMatt Jacob /* 2671805e1f82SMatt Jacob * Note that these operations affect the 2672805e1f82SMatt Jacob * the goal flags (goal_flags)- not 2673805e1f82SMatt Jacob * the current state flags. Then we mark 2674805e1f82SMatt Jacob * things so that the next operation to 2675805e1f82SMatt Jacob * this HBA will cause the update to occur. 2676805e1f82SMatt Jacob */ 2677805e1f82SMatt Jacob if (cts->valid & CCB_TRANS_DISC_VALID) { 2678805e1f82SMatt Jacob if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) { 2679805e1f82SMatt Jacob *dptr |= DPARM_DISC; 2680805e1f82SMatt Jacob } else { 2681805e1f82SMatt Jacob *dptr &= ~DPARM_DISC; 2682805e1f82SMatt Jacob } 2683805e1f82SMatt Jacob } 2684805e1f82SMatt Jacob if (cts->valid & CCB_TRANS_TQ_VALID) { 2685805e1f82SMatt Jacob if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) { 2686805e1f82SMatt Jacob *dptr |= DPARM_TQING; 2687805e1f82SMatt Jacob } else { 2688805e1f82SMatt Jacob *dptr &= ~DPARM_TQING; 2689805e1f82SMatt Jacob } 2690805e1f82SMatt Jacob } 2691805e1f82SMatt Jacob if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) { 2692805e1f82SMatt Jacob switch (cts->bus_width) { 2693805e1f82SMatt Jacob case MSG_EXT_WDTR_BUS_16_BIT: 2694805e1f82SMatt Jacob *dptr |= DPARM_WIDE; 2695805e1f82SMatt Jacob break; 2696805e1f82SMatt Jacob default: 2697805e1f82SMatt Jacob *dptr &= ~DPARM_WIDE; 2698805e1f82SMatt Jacob } 2699805e1f82SMatt Jacob } 2700805e1f82SMatt Jacob /* 2701805e1f82SMatt Jacob * Any SYNC RATE of nonzero and SYNC_OFFSET 2702805e1f82SMatt Jacob * of nonzero will cause us to go to the 2703805e1f82SMatt Jacob * selected (from NVRAM) maximum value for 2704805e1f82SMatt Jacob * this device. At a later point, we'll 2705805e1f82SMatt Jacob * allow finer control. 2706805e1f82SMatt Jacob */ 2707805e1f82SMatt Jacob if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) && 2708805e1f82SMatt Jacob (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) && 2709805e1f82SMatt Jacob (cts->sync_offset > 0)) { 2710805e1f82SMatt Jacob *dptr |= DPARM_SYNC; 2711805e1f82SMatt Jacob } else { 2712805e1f82SMatt Jacob *dptr &= ~DPARM_SYNC; 2713805e1f82SMatt Jacob } 2714805e1f82SMatt Jacob *dptr |= DPARM_SAFE_DFLT; 2715805e1f82SMatt Jacob #else 2716ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi = 2717ab163f5fSMatt Jacob &cts->proto_specific.scsi; 2718ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi = 2719ab163f5fSMatt Jacob &cts->xport_specific.spi; 2720ab163f5fSMatt Jacob sdparam *sdp = isp->isp_param; 27211dae40ebSMatt Jacob uint16_t *dptr; 2722ab163f5fSMatt Jacob 2723b61386a4SMatt Jacob if (spi->valid == 0 && scsi->valid == 0) { 2724b61386a4SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 2725b61386a4SMatt Jacob xpt_done(ccb); 2726b61386a4SMatt Jacob break; 2727b61386a4SMatt Jacob } 2728b61386a4SMatt Jacob 2729ab163f5fSMatt Jacob bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 2730ab163f5fSMatt Jacob sdp += bus; 2731ab163f5fSMatt Jacob /* 27329ce9bdafSMatt Jacob * We always update (internally) from goal_flags 2733ab163f5fSMatt Jacob * so any request to change settings just gets 2734ab163f5fSMatt Jacob * vectored to that location. 2735ab163f5fSMatt Jacob */ 27369ce9bdafSMatt Jacob dptr = &sdp->isp_devparam[tgt].goal_flags; 2737ab163f5fSMatt Jacob 2738ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_DISC) != 0) { 2739ab163f5fSMatt Jacob if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) 2740ab163f5fSMatt Jacob *dptr |= DPARM_DISC; 2741ab163f5fSMatt Jacob else 2742ab163f5fSMatt Jacob *dptr &= ~DPARM_DISC; 2743ab163f5fSMatt Jacob } 2744ab163f5fSMatt Jacob 2745ab163f5fSMatt Jacob if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 2746ab163f5fSMatt Jacob if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) 2747ab163f5fSMatt Jacob *dptr |= DPARM_TQING; 2748ab163f5fSMatt Jacob else 2749ab163f5fSMatt Jacob *dptr &= ~DPARM_TQING; 2750ab163f5fSMatt Jacob } 2751ab163f5fSMatt Jacob 2752ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 2753ab163f5fSMatt Jacob if (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT) 2754ab163f5fSMatt Jacob *dptr |= DPARM_WIDE; 2755ab163f5fSMatt Jacob else 2756ab163f5fSMatt Jacob *dptr &= ~DPARM_WIDE; 2757ab163f5fSMatt Jacob } 2758ab163f5fSMatt Jacob 2759ab163f5fSMatt Jacob /* 2760ab163f5fSMatt Jacob * XXX: FIX ME 2761ab163f5fSMatt Jacob */ 2762ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) && 27639ce9bdafSMatt Jacob (spi->valid & CTS_SPI_VALID_SYNC_RATE) && 27649ce9bdafSMatt Jacob (spi->sync_period && spi->sync_offset)) { 2765ab163f5fSMatt Jacob *dptr |= DPARM_SYNC; 27669ce9bdafSMatt Jacob /* 27679ce9bdafSMatt Jacob * XXX: CHECK FOR LEGALITY 27689ce9bdafSMatt Jacob */ 27699ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_period = 27709ce9bdafSMatt Jacob spi->sync_period; 27719ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_offset = 27729ce9bdafSMatt Jacob spi->sync_offset; 2773ab163f5fSMatt Jacob } else { 2774ab163f5fSMatt Jacob *dptr &= ~DPARM_SYNC; 2775ab163f5fSMatt Jacob } 2776805e1f82SMatt Jacob #endif 2777bfbab170SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 2778b61386a4SMatt Jacob "SET (%d.%d.%d) to flags %x off %x per %x", 2779b61386a4SMatt Jacob bus, tgt, cts->ccb_h.target_lun, 2780b61386a4SMatt Jacob sdp->isp_devparam[tgt].goal_flags, 27819ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_offset, 27829ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_period); 2783478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_update = 1; 2784ea6f23cdSMatt Jacob isp->isp_update |= (1 << bus); 2785478f8a96SJustin T. Gibbs } 2786478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2787478f8a96SJustin T. Gibbs xpt_done(ccb); 2788478f8a96SJustin T. Gibbs break; 2789478f8a96SJustin T. Gibbs case XPT_GET_TRAN_SETTINGS: 2790478f8a96SJustin T. Gibbs cts = &ccb->cts; 2791478f8a96SJustin T. Gibbs tgt = cts->ccb_h.target_id; 2792ab6c4b31SMatt Jacob if (IS_FC(isp)) { 2793805e1f82SMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2794805e1f82SMatt Jacob /* 2795805e1f82SMatt Jacob * a lot of normal SCSI things don't make sense. 2796805e1f82SMatt Jacob */ 2797805e1f82SMatt Jacob cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB; 2798805e1f82SMatt Jacob cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2799805e1f82SMatt Jacob /* 2800805e1f82SMatt Jacob * How do you measure the width of a high 2801805e1f82SMatt Jacob * speed serial bus? Well, in bytes. 2802805e1f82SMatt Jacob * 2803805e1f82SMatt Jacob * Offset and period make no sense, though, so we set 2804805e1f82SMatt Jacob * (above) a 'base' transfer speed to be gigabit. 2805805e1f82SMatt Jacob */ 2806805e1f82SMatt Jacob cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2807805e1f82SMatt Jacob #else 2808ab163f5fSMatt Jacob fcparam *fcp = isp->isp_param; 28099b03492aSMatt Jacob struct ccb_trans_settings_scsi *scsi = 28109b03492aSMatt Jacob &cts->proto_specific.scsi; 2811ab163f5fSMatt Jacob struct ccb_trans_settings_fc *fc = 2812ab163f5fSMatt Jacob &cts->xport_specific.fc; 2813478f8a96SJustin T. Gibbs 2814ab163f5fSMatt Jacob cts->protocol = PROTO_SCSI; 2815ab163f5fSMatt Jacob cts->protocol_version = SCSI_REV_2; 2816ab163f5fSMatt Jacob cts->transport = XPORT_FC; 2817ab163f5fSMatt Jacob cts->transport_version = 0; 2818ab163f5fSMatt Jacob 28199b03492aSMatt Jacob scsi->valid = CTS_SCSI_VALID_TQ; 28209b03492aSMatt Jacob scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; 2821ab163f5fSMatt Jacob fc->valid = CTS_FC_VALID_SPEED; 28229b03492aSMatt Jacob if (fcp->isp_gbspeed == 2) { 282353036e92SMatt Jacob fc->bitrate = 200000; 28249b03492aSMatt Jacob } else { 2825ab163f5fSMatt Jacob fc->bitrate = 100000; 28269b03492aSMatt Jacob } 2827ab163f5fSMatt Jacob if (tgt > 0 && tgt < MAX_FC_TARG) { 282810365e5aSMatt Jacob fcportdb_t *lp = &fcp->portdb[tgt]; 2829ab163f5fSMatt Jacob fc->wwnn = lp->node_wwn; 2830ab163f5fSMatt Jacob fc->wwpn = lp->port_wwn; 2831ab163f5fSMatt Jacob fc->port = lp->portid; 2832ab163f5fSMatt Jacob fc->valid |= CTS_FC_VALID_WWNN | 2833ab163f5fSMatt Jacob CTS_FC_VALID_WWPN | CTS_FC_VALID_PORT; 2834ab163f5fSMatt Jacob } 2835805e1f82SMatt Jacob #endif 2836ab163f5fSMatt Jacob } else { 2837805e1f82SMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2838ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi = 2839ab163f5fSMatt Jacob &cts->proto_specific.scsi; 2840ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi = 2841ab163f5fSMatt Jacob &cts->xport_specific.spi; 2842805e1f82SMatt Jacob #endif 2843ab163f5fSMatt Jacob sdparam *sdp = isp->isp_param; 2844ab163f5fSMatt Jacob int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 28451dae40ebSMatt Jacob uint16_t dval, pval, oval; 2846ab163f5fSMatt Jacob 2847ea6f23cdSMatt Jacob sdp += bus; 2848ab163f5fSMatt Jacob 2849ab163f5fSMatt Jacob if (IS_CURRENT_SETTINGS(cts)) { 285083ae4407SMatt Jacob sdp->isp_devparam[tgt].dev_refresh = 1; 285183ae4407SMatt Jacob isp->isp_update |= (1 << bus); 285283ae4407SMatt Jacob (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, 285383ae4407SMatt Jacob NULL); 28549ce9bdafSMatt Jacob dval = sdp->isp_devparam[tgt].actv_flags; 28559ce9bdafSMatt Jacob oval = sdp->isp_devparam[tgt].actv_offset; 28569ce9bdafSMatt Jacob pval = sdp->isp_devparam[tgt].actv_period; 28574394c92fSMatt Jacob } else { 28589ce9bdafSMatt Jacob dval = sdp->isp_devparam[tgt].nvrm_flags; 28599ce9bdafSMatt Jacob oval = sdp->isp_devparam[tgt].nvrm_offset; 28609ce9bdafSMatt Jacob pval = sdp->isp_devparam[tgt].nvrm_period; 28614394c92fSMatt Jacob } 2862478f8a96SJustin T. Gibbs 2863805e1f82SMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2864805e1f82SMatt Jacob cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); 2865805e1f82SMatt Jacob 2866805e1f82SMatt Jacob if (dval & DPARM_DISC) { 2867805e1f82SMatt Jacob cts->flags |= CCB_TRANS_DISC_ENB; 2868805e1f82SMatt Jacob } 2869805e1f82SMatt Jacob if (dval & DPARM_TQING) { 2870805e1f82SMatt Jacob cts->flags |= CCB_TRANS_TAG_ENB; 2871805e1f82SMatt Jacob } 2872805e1f82SMatt Jacob if (dval & DPARM_WIDE) { 2873805e1f82SMatt Jacob cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2874805e1f82SMatt Jacob } else { 2875805e1f82SMatt Jacob cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2876805e1f82SMatt Jacob } 2877805e1f82SMatt Jacob cts->valid = CCB_TRANS_BUS_WIDTH_VALID | 2878805e1f82SMatt Jacob CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2879805e1f82SMatt Jacob 2880805e1f82SMatt Jacob if ((dval & DPARM_SYNC) && oval != 0) { 2881805e1f82SMatt Jacob cts->sync_period = pval; 2882805e1f82SMatt Jacob cts->sync_offset = oval; 2883805e1f82SMatt Jacob cts->valid |= 2884805e1f82SMatt Jacob CCB_TRANS_SYNC_RATE_VALID | 2885805e1f82SMatt Jacob CCB_TRANS_SYNC_OFFSET_VALID; 2886805e1f82SMatt Jacob } 2887805e1f82SMatt Jacob #else 2888ab163f5fSMatt Jacob cts->protocol = PROTO_SCSI; 2889ab163f5fSMatt Jacob cts->protocol_version = SCSI_REV_2; 2890ab163f5fSMatt Jacob cts->transport = XPORT_SPI; 2891ab163f5fSMatt Jacob cts->transport_version = 2; 2892ab163f5fSMatt Jacob 2893b61386a4SMatt Jacob spi->valid = 0; 2894b61386a4SMatt Jacob scsi->valid = 0; 2895b61386a4SMatt Jacob spi->flags = 0; 2896b61386a4SMatt Jacob scsi->flags = 0; 2897ab163f5fSMatt Jacob if (dval & DPARM_DISC) { 2898ab163f5fSMatt Jacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 2899ab163f5fSMatt Jacob } 29009ce9bdafSMatt Jacob if ((dval & DPARM_SYNC) && oval && pval) { 2901ab163f5fSMatt Jacob spi->sync_offset = oval; 2902ab163f5fSMatt Jacob spi->sync_period = pval; 2903b61386a4SMatt Jacob } else { 2904b61386a4SMatt Jacob spi->sync_offset = 0; 2905b61386a4SMatt Jacob spi->sync_period = 0; 2906b61386a4SMatt Jacob } 2907ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 2908ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 2909ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_BUS_WIDTH; 2910ab163f5fSMatt Jacob if (dval & DPARM_WIDE) { 2911ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2912ab163f5fSMatt Jacob } else { 2913ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2914ab163f5fSMatt Jacob } 2915ab163f5fSMatt Jacob if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { 2916ab163f5fSMatt Jacob scsi->valid = CTS_SCSI_VALID_TQ; 2917b61386a4SMatt Jacob if (dval & DPARM_TQING) { 2918b61386a4SMatt Jacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 2919b61386a4SMatt Jacob } 2920ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_DISC; 2921ab163f5fSMatt Jacob } 2922805e1f82SMatt Jacob #endif 2923bfbab170SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 2924b61386a4SMatt Jacob "GET %s (%d.%d.%d) to flags %x off %x per %x", 29259ce9bdafSMatt Jacob IS_CURRENT_SETTINGS(cts)? "ACTIVE" : "NVRAM", 2926b61386a4SMatt Jacob bus, tgt, cts->ccb_h.target_lun, dval, oval, pval); 2927478f8a96SJustin T. Gibbs } 2928478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2929478f8a96SJustin T. Gibbs xpt_done(ccb); 2930478f8a96SJustin T. Gibbs break; 2931478f8a96SJustin T. Gibbs 2932478f8a96SJustin T. Gibbs case XPT_CALC_GEOMETRY: 29339cd7268eSMatt Jacob #if __FreeBSD_version < 500000 2934478f8a96SJustin T. Gibbs { 2935478f8a96SJustin T. Gibbs struct ccb_calc_geometry *ccg; 29369cd7268eSMatt Jacob u_int32_t secs_per_cylinder; 29379cd7268eSMatt Jacob u_int32_t size_mb; 2938478f8a96SJustin T. Gibbs 2939478f8a96SJustin T. Gibbs ccg = &ccb->ccg; 2940478f8a96SJustin T. Gibbs if (ccg->block_size == 0) { 2941478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2942478f8a96SJustin T. Gibbs xpt_done(ccb); 2943478f8a96SJustin T. Gibbs break; 2944478f8a96SJustin T. Gibbs } 29459cd7268eSMatt Jacob size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size); 29469cd7268eSMatt Jacob if (size_mb > 1024) { 29479cd7268eSMatt Jacob ccg->heads = 255; 29489cd7268eSMatt Jacob ccg->secs_per_track = 63; 29499cd7268eSMatt Jacob } else { 29509cd7268eSMatt Jacob ccg->heads = 64; 29519cd7268eSMatt Jacob ccg->secs_per_track = 32; 29529cd7268eSMatt Jacob } 29539cd7268eSMatt Jacob secs_per_cylinder = ccg->heads * ccg->secs_per_track; 29549cd7268eSMatt Jacob ccg->cylinders = ccg->volume_size / secs_per_cylinder; 29559cd7268eSMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 2956478f8a96SJustin T. Gibbs xpt_done(ccb); 2957478f8a96SJustin T. Gibbs break; 2958478f8a96SJustin T. Gibbs } 29599cd7268eSMatt Jacob #else 29609cd7268eSMatt Jacob { 29619cd7268eSMatt Jacob cam_calc_geometry(&ccb->ccg, /*extended*/1); 29629cd7268eSMatt Jacob xpt_done(ccb); 29639cd7268eSMatt Jacob break; 29649cd7268eSMatt Jacob } 29659cd7268eSMatt Jacob #endif 2966478f8a96SJustin T. Gibbs case XPT_RESET_BUS: /* Reset the specified bus */ 2967ab6c4b31SMatt Jacob bus = cam_sim_bus(sim); 2968ab6c4b31SMatt Jacob error = isp_control(isp, ISPCTL_RESET_BUS, &bus); 2969478f8a96SJustin T. Gibbs if (error) 2970478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 29712b052931SMatt Jacob else { 29720a70657fSMatt Jacob if (bootverbose) { 29730a70657fSMatt Jacob xpt_print(ccb->ccb_h.path, "reset bus\n"); 29740a70657fSMatt Jacob } 2975ea6f23cdSMatt Jacob if (cam_sim_bus(sim) && isp->isp_path2 != NULL) 2976ea6f23cdSMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); 2977ea6f23cdSMatt Jacob else if (isp->isp_path != NULL) 29782b052931SMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path, NULL); 2979478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 29802b052931SMatt Jacob } 2981478f8a96SJustin T. Gibbs xpt_done(ccb); 2982478f8a96SJustin T. Gibbs break; 2983478f8a96SJustin T. Gibbs 2984478f8a96SJustin T. Gibbs case XPT_TERM_IO: /* Terminate the I/O process */ 2985478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2986478f8a96SJustin T. Gibbs xpt_done(ccb); 2987478f8a96SJustin T. Gibbs break; 2988478f8a96SJustin T. Gibbs 2989478f8a96SJustin T. Gibbs case XPT_PATH_INQ: /* Path routing inquiry */ 2990478f8a96SJustin T. Gibbs { 2991478f8a96SJustin T. Gibbs struct ccb_pathinq *cpi = &ccb->cpi; 2992478f8a96SJustin T. Gibbs 2993478f8a96SJustin T. Gibbs cpi->version_num = 1; 2994d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2995a1bc34c6SMatt Jacob cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO; 2996d81ba9d5SMatt Jacob #else 2997478f8a96SJustin T. Gibbs cpi->target_sprt = 0; 2998d81ba9d5SMatt Jacob #endif 2999478f8a96SJustin T. Gibbs cpi->hba_eng_cnt = 0; 30000470d791SMatt Jacob cpi->max_target = ISP_MAX_TARGETS(isp) - 1; 30010470d791SMatt Jacob cpi->max_lun = ISP_MAX_LUNS(isp) - 1; 30020470d791SMatt Jacob cpi->bus_id = cam_sim_bus(sim); 30034394c92fSMatt Jacob if (IS_FC(isp)) { 30044394c92fSMatt Jacob cpi->hba_misc = PIM_NOBUSRESET; 30050470d791SMatt Jacob /* 30060470d791SMatt Jacob * Because our loop ID can shift from time to time, 30070470d791SMatt Jacob * make our initiator ID out of range of our bus. 30080470d791SMatt Jacob */ 30090470d791SMatt Jacob cpi->initiator_id = cpi->max_target + 1; 30100470d791SMatt Jacob 30119deea857SKenneth D. Merry /* 30129deea857SKenneth D. Merry * Set base transfer capabilities for Fibre Channel. 30139deea857SKenneth D. Merry * Technically not correct because we don't know 30149deea857SKenneth D. Merry * what media we're running on top of- but we'll 30159deea857SKenneth D. Merry * look good if we always say 100MB/s. 30169deea857SKenneth D. Merry */ 301753036e92SMatt Jacob if (FCPARAM(isp)->isp_gbspeed == 2) 301853036e92SMatt Jacob cpi->base_transfer_speed = 200000; 301953036e92SMatt Jacob else 30209deea857SKenneth D. Merry cpi->base_transfer_speed = 100000; 30210470d791SMatt Jacob cpi->hba_inquiry = PI_TAG_ABLE; 3022805e1f82SMatt Jacob #ifdef CAM_NEW_TRAN_CODE 3023ab163f5fSMatt Jacob cpi->transport = XPORT_FC; 3024805e1f82SMatt Jacob cpi->transport_version = 0; 3025805e1f82SMatt Jacob #endif 3026478f8a96SJustin T. Gibbs } else { 3027ea6f23cdSMatt Jacob sdparam *sdp = isp->isp_param; 3028ea6f23cdSMatt Jacob sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path)); 30290470d791SMatt Jacob cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; 30304394c92fSMatt Jacob cpi->hba_misc = 0; 3031ea6f23cdSMatt Jacob cpi->initiator_id = sdp->isp_initiator_id; 30329deea857SKenneth D. Merry cpi->base_transfer_speed = 3300; 3033805e1f82SMatt Jacob #ifdef CAM_NEW_TRAN_CODE 3034ab163f5fSMatt Jacob cpi->transport = XPORT_SPI; 3035805e1f82SMatt Jacob cpi->transport_version = 2; 3036805e1f82SMatt Jacob #endif 3037478f8a96SJustin T. Gibbs } 3038805e1f82SMatt Jacob #ifdef CAM_NEW_TRAN_CODE 3039ab163f5fSMatt Jacob cpi->protocol = PROTO_SCSI; 3040ab163f5fSMatt Jacob cpi->protocol_version = SCSI_REV_2; 3041805e1f82SMatt Jacob #endif 3042478f8a96SJustin T. Gibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 3043478f8a96SJustin T. Gibbs strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN); 3044478f8a96SJustin T. Gibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 3045478f8a96SJustin T. Gibbs cpi->unit_number = cam_sim_unit(sim); 3046478f8a96SJustin T. Gibbs cpi->ccb_h.status = CAM_REQ_CMP; 3047478f8a96SJustin T. Gibbs xpt_done(ccb); 3048478f8a96SJustin T. Gibbs break; 3049478f8a96SJustin T. Gibbs } 3050478f8a96SJustin T. Gibbs default: 3051478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 3052478f8a96SJustin T. Gibbs xpt_done(ccb); 3053478f8a96SJustin T. Gibbs break; 3054478f8a96SJustin T. Gibbs } 3055478f8a96SJustin T. Gibbs } 3056d3a9eb2eSMatt Jacob 3057d3a9eb2eSMatt Jacob #define ISPDDB (CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB) 3058f7c631bcSMatt Jacob 3059d3a9eb2eSMatt Jacob void 3060c3055363SMatt Jacob isp_done(struct ccb_scsiio *sccb) 3061d3a9eb2eSMatt Jacob { 30629cd7268eSMatt Jacob ispsoftc_t *isp = XS_ISP(sccb); 3063d3a9eb2eSMatt Jacob 3064d3a9eb2eSMatt Jacob if (XS_NOERR(sccb)) 3065d3a9eb2eSMatt Jacob XS_SETERR(sccb, CAM_REQ_CMP); 3066b85389e1SMatt Jacob 3067d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP && 3068d3a9eb2eSMatt Jacob (sccb->scsi_status != SCSI_STATUS_OK)) { 3069d3a9eb2eSMatt Jacob sccb->ccb_h.status &= ~CAM_STATUS_MASK; 307092a1e549SMatt Jacob if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) && 307192a1e549SMatt Jacob (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) { 307292a1e549SMatt Jacob sccb->ccb_h.status |= CAM_AUTOSENSE_FAIL; 307392a1e549SMatt Jacob } else { 3074d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 3075d3a9eb2eSMatt Jacob } 307692a1e549SMatt Jacob } 3077b85389e1SMatt Jacob 30780470d791SMatt Jacob sccb->ccb_h.status &= ~CAM_SIM_QUEUED; 3079d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 3080f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 3081f7c631bcSMatt Jacob "target %d lun %d CAM status 0x%x SCSI status 0x%x", 3082f7c631bcSMatt Jacob XS_TGT(sccb), XS_LUN(sccb), sccb->ccb_h.status, 3083f7c631bcSMatt Jacob sccb->scsi_status); 3084d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 3085d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_DEV_QFRZN; 30860470d791SMatt Jacob xpt_freeze_devq(sccb->ccb_h.path, 1); 3087d3a9eb2eSMatt Jacob } 3088d3a9eb2eSMatt Jacob } 3089b85389e1SMatt Jacob 3090b85389e1SMatt Jacob if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) && 3091d3a9eb2eSMatt Jacob (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 3092dd9fc7c3SMatt Jacob xpt_print(sccb->ccb_h.path, 3093dd9fc7c3SMatt Jacob "cam completion status 0x%x\n", sccb->ccb_h.status); 3094d3a9eb2eSMatt Jacob } 3095b85389e1SMatt Jacob 3096b85389e1SMatt Jacob XS_CMD_S_DONE(sccb); 3097b85389e1SMatt Jacob if (XS_CMD_WDOG_P(sccb) == 0) { 3098f7c631bcSMatt Jacob untimeout(isp_watchdog, sccb, sccb->ccb_h.timeout_ch); 3099b85389e1SMatt Jacob if (XS_CMD_GRACE_P(sccb)) { 3100b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 3101b09b0095SMatt Jacob "finished command on borrowed time"); 3102b85389e1SMatt Jacob } 3103b85389e1SMatt Jacob XS_CMD_S_CLEAR(sccb); 31040a70657fSMatt Jacob isp_free_pcmd(isp, (union ccb *) sccb); 3105d3a9eb2eSMatt Jacob xpt_done((union ccb *) sccb); 3106d3a9eb2eSMatt Jacob } 3107b85389e1SMatt Jacob } 3108d3a9eb2eSMatt Jacob 3109cbf57b47SMatt Jacob int 31109cd7268eSMatt Jacob isp_async(ispsoftc_t *isp, ispasync_t cmd, void *arg) 3111cbf57b47SMatt Jacob { 3112ea6f23cdSMatt Jacob int bus, rv = 0; 311310365e5aSMatt Jacob static const char prom[] = 311410365e5aSMatt Jacob "PortID 0x%06x handle 0x%x role %s %s\n" 311510365e5aSMatt Jacob " WWNN 0x%08x%08x WWPN 0x%08x%08x"; 311610365e5aSMatt Jacob static const char prom2[] = 311710365e5aSMatt Jacob "PortID 0x%06x handle 0x%x role %s %s tgt %u\n" 311810365e5aSMatt Jacob " WWNN 0x%08x%08x WWPN 0x%08x%08x"; 3119f7c631bcSMatt Jacob char *msg = NULL; 312010365e5aSMatt Jacob target_id_t tgt; 312110365e5aSMatt Jacob fcportdb_t *lp; 312210365e5aSMatt Jacob struct cam_path *tmppath; 312310365e5aSMatt Jacob 3124cbf57b47SMatt Jacob switch (cmd) { 3125cbf57b47SMatt Jacob case ISPASYNC_NEW_TGT_PARAMS: 31260470d791SMatt Jacob { 3127805e1f82SMatt Jacob #ifdef CAM_NEW_TRAN_CODE 3128ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi; 3129ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi; 3130805e1f82SMatt Jacob #endif 3131cbf57b47SMatt Jacob int flags, tgt; 3132cbf57b47SMatt Jacob sdparam *sdp = isp->isp_param; 3133ab163f5fSMatt Jacob struct ccb_trans_settings cts; 3134cbf57b47SMatt Jacob 313529f76675SMatt Jacob memset(&cts, 0, sizeof (struct ccb_trans_settings)); 3136ab163f5fSMatt Jacob 3137cbf57b47SMatt Jacob tgt = *((int *)arg); 3138ea6f23cdSMatt Jacob bus = (tgt >> 16) & 0xffff; 3139ea6f23cdSMatt Jacob tgt &= 0xffff; 3140ea6f23cdSMatt Jacob sdp += bus; 3141cbf57b47SMatt Jacob if (xpt_create_path(&tmppath, NULL, 3142ea6f23cdSMatt Jacob cam_sim_path(bus? isp->isp_sim2 : isp->isp_sim), 3143ea6f23cdSMatt Jacob tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 3144bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 3145bfbab170SMatt Jacob "isp_async cannot make temp path for %d.%d", 3146bfbab170SMatt Jacob tgt, bus); 3147cbf57b47SMatt Jacob rv = -1; 3148cbf57b47SMatt Jacob break; 3149cbf57b47SMatt Jacob } 31509ce9bdafSMatt Jacob flags = sdp->isp_devparam[tgt].actv_flags; 3151805e1f82SMatt Jacob #ifdef CAM_NEW_TRAN_CODE 3152ab163f5fSMatt Jacob cts.type = CTS_TYPE_CURRENT_SETTINGS; 3153ab163f5fSMatt Jacob cts.protocol = PROTO_SCSI; 3154ab163f5fSMatt Jacob cts.transport = XPORT_SPI; 3155ab163f5fSMatt Jacob 3156ab163f5fSMatt Jacob scsi = &cts.proto_specific.scsi; 3157ab163f5fSMatt Jacob spi = &cts.xport_specific.spi; 3158ab163f5fSMatt Jacob 3159ab163f5fSMatt Jacob if (flags & DPARM_TQING) { 3160ab163f5fSMatt Jacob scsi->valid |= CTS_SCSI_VALID_TQ; 3161ab163f5fSMatt Jacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 3162ab163f5fSMatt Jacob } 3163ab163f5fSMatt Jacob 3164cbf57b47SMatt Jacob if (flags & DPARM_DISC) { 3165ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_DISC; 3166ab163f5fSMatt Jacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 3167ab163f5fSMatt Jacob } 3168ab163f5fSMatt Jacob spi->flags |= CTS_SPI_VALID_BUS_WIDTH; 3169ab163f5fSMatt Jacob if (flags & DPARM_WIDE) { 3170ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 3171ab163f5fSMatt Jacob } else { 3172ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 3173ab163f5fSMatt Jacob } 3174ab163f5fSMatt Jacob if (flags & DPARM_SYNC) { 3175ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 3176ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 31779ce9bdafSMatt Jacob spi->sync_period = sdp->isp_devparam[tgt].actv_period; 31789ce9bdafSMatt Jacob spi->sync_offset = sdp->isp_devparam[tgt].actv_offset; 3179ab163f5fSMatt Jacob } 3180805e1f82SMatt Jacob #else 3181805e1f82SMatt Jacob cts.flags = CCB_TRANS_CURRENT_SETTINGS; 3182805e1f82SMatt Jacob cts.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 3183805e1f82SMatt Jacob if (flags & DPARM_DISC) { 3184805e1f82SMatt Jacob cts.flags |= CCB_TRANS_DISC_ENB; 3185805e1f82SMatt Jacob } 3186805e1f82SMatt Jacob if (flags & DPARM_TQING) { 3187805e1f82SMatt Jacob cts.flags |= CCB_TRANS_TAG_ENB; 3188805e1f82SMatt Jacob } 3189805e1f82SMatt Jacob cts.valid |= CCB_TRANS_BUS_WIDTH_VALID; 3190805e1f82SMatt Jacob cts.bus_width = (flags & DPARM_WIDE)? 3191805e1f82SMatt Jacob MSG_EXT_WDTR_BUS_8_BIT : MSG_EXT_WDTR_BUS_16_BIT; 3192805e1f82SMatt Jacob cts.sync_period = sdp->isp_devparam[tgt].actv_period; 3193805e1f82SMatt Jacob cts.sync_offset = sdp->isp_devparam[tgt].actv_offset; 3194805e1f82SMatt Jacob if (flags & DPARM_SYNC) { 3195805e1f82SMatt Jacob cts.valid |= 3196805e1f82SMatt Jacob CCB_TRANS_SYNC_RATE_VALID | 3197805e1f82SMatt Jacob CCB_TRANS_SYNC_OFFSET_VALID; 3198805e1f82SMatt Jacob } 3199805e1f82SMatt Jacob #endif 3200b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 3201b09b0095SMatt Jacob "NEW_TGT_PARAMS bus %d tgt %d period %x offset %x flags %x", 32029ce9bdafSMatt Jacob bus, tgt, sdp->isp_devparam[tgt].actv_period, 32039ce9bdafSMatt Jacob sdp->isp_devparam[tgt].actv_offset, flags); 3204ab163f5fSMatt Jacob xpt_setup_ccb(&cts.ccb_h, tmppath, 1); 3205ab163f5fSMatt Jacob xpt_async(AC_TRANSFER_NEG, tmppath, &cts); 3206cbf57b47SMatt Jacob xpt_free_path(tmppath); 3207cbf57b47SMatt Jacob break; 32080470d791SMatt Jacob } 320957c801f5SMatt Jacob case ISPASYNC_BUS_RESET: 3210ea6f23cdSMatt Jacob bus = *((int *)arg); 3211b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected", 3212b09b0095SMatt Jacob bus); 3213ea6f23cdSMatt Jacob if (bus > 0 && isp->isp_path2) { 3214ea6f23cdSMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); 3215ea6f23cdSMatt Jacob } else if (isp->isp_path) { 321657c801f5SMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path, NULL); 321757c801f5SMatt Jacob } 321857c801f5SMatt Jacob break; 32195d571944SMatt Jacob case ISPASYNC_LIP: 3220f7c631bcSMatt Jacob if (msg == NULL) { 3221f7c631bcSMatt Jacob msg = "LIP Received"; 32225d571944SMatt Jacob } 3223f7c631bcSMatt Jacob /* FALLTHROUGH */ 32245d571944SMatt Jacob case ISPASYNC_LOOP_RESET: 3225f7c631bcSMatt Jacob if (msg == NULL) { 3226f7c631bcSMatt Jacob msg = "LOOP Reset"; 32275d571944SMatt Jacob } 3228f7c631bcSMatt Jacob /* FALLTHROUGH */ 322957c801f5SMatt Jacob case ISPASYNC_LOOP_DOWN: 3230f7c631bcSMatt Jacob if (msg == NULL) { 3231f7c631bcSMatt Jacob msg = "LOOP Down"; 323257c801f5SMatt Jacob } 3233f7c631bcSMatt Jacob if (isp->isp_path) { 3234f7c631bcSMatt Jacob isp_freeze_loopdown(isp, msg); 3235f7c631bcSMatt Jacob } 3236f7c631bcSMatt Jacob if (isp->isp_osinfo.ldt_running == 0) { 3237f7c631bcSMatt Jacob isp->isp_osinfo.ldt_running = 1; 32380a70657fSMatt Jacob callout_reset(&isp->isp_osinfo.ldt, 32390a70657fSMatt Jacob isp->isp_osinfo.loop_down_limit * hz, isp_ldt, isp); 3240f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, 3241f7c631bcSMatt Jacob "starting Loop Down Timer"); 3242f7c631bcSMatt Jacob } 3243f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGINFO, msg); 324457c801f5SMatt Jacob break; 324557c801f5SMatt Jacob case ISPASYNC_LOOP_UP: 32465d571944SMatt Jacob /* 32475d571944SMatt Jacob * Now we just note that Loop has come up. We don't 32485d571944SMatt Jacob * actually do anything because we're waiting for a 32495d571944SMatt Jacob * Change Notify before activating the FC cleanup 32505d571944SMatt Jacob * thread to look at the state of the loop again. 32515d571944SMatt Jacob */ 3252b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop UP"); 325357c801f5SMatt Jacob break; 325410365e5aSMatt Jacob case ISPASYNC_DEV_ARRIVED: 325510365e5aSMatt Jacob lp = arg; 3256f7c631bcSMatt Jacob lp->reserved = 0; 3257f7c631bcSMatt Jacob if ((isp->isp_role & ISP_ROLE_INITIATOR) && 3258f7c631bcSMatt Jacob (lp->roles & (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT))) { 3259f7c631bcSMatt Jacob int dbidx = lp - FCPARAM(isp)->portdb; 3260f7c631bcSMatt Jacob int i; 326102ab3379SMatt Jacob 3262f7c631bcSMatt Jacob for (i = 0; i < MAX_FC_TARG; i++) { 3263f7c631bcSMatt Jacob if (i >= FL_ID && i <= SNS_ID) { 3264f7c631bcSMatt Jacob continue; 3265f7c631bcSMatt Jacob } 3266f7c631bcSMatt Jacob if (FCPARAM(isp)->isp_ini_map[i] == 0) { 3267f7c631bcSMatt Jacob break; 3268f7c631bcSMatt Jacob } 3269f7c631bcSMatt Jacob } 3270f7c631bcSMatt Jacob if (i < MAX_FC_TARG) { 3271f7c631bcSMatt Jacob FCPARAM(isp)->isp_ini_map[i] = dbidx + 1; 3272f7c631bcSMatt Jacob lp->ini_map_idx = i + 1; 3273f7c631bcSMatt Jacob } else { 3274f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGWARN, "out of target ids"); 3275f7c631bcSMatt Jacob isp_dump_portdb(isp); 3276f7c631bcSMatt Jacob } 3277f7c631bcSMatt Jacob } 327810365e5aSMatt Jacob if (lp->ini_map_idx) { 327910365e5aSMatt Jacob tgt = lp->ini_map_idx - 1; 328010365e5aSMatt Jacob isp_prt(isp, ISP_LOGCONFIG, prom2, 328110365e5aSMatt Jacob lp->portid, lp->handle, 3282f7c631bcSMatt Jacob roles[lp->roles], "arrived at", tgt, 32831dae40ebSMatt Jacob (uint32_t) (lp->node_wwn >> 32), 328410365e5aSMatt Jacob (uint32_t) lp->node_wwn, 328510365e5aSMatt Jacob (uint32_t) (lp->port_wwn >> 32), 328610365e5aSMatt Jacob (uint32_t) lp->port_wwn); 3287f7c631bcSMatt Jacob isp_make_here(isp, tgt); 328810365e5aSMatt Jacob } else { 328910365e5aSMatt Jacob isp_prt(isp, ISP_LOGCONFIG, prom, 329010365e5aSMatt Jacob lp->portid, lp->handle, 3291f7c631bcSMatt Jacob roles[lp->roles], "arrived", 329210365e5aSMatt Jacob (uint32_t) (lp->node_wwn >> 32), 329310365e5aSMatt Jacob (uint32_t) lp->node_wwn, 329410365e5aSMatt Jacob (uint32_t) (lp->port_wwn >> 32), 329510365e5aSMatt Jacob (uint32_t) lp->port_wwn); 329610365e5aSMatt Jacob } 329710365e5aSMatt Jacob break; 329810365e5aSMatt Jacob case ISPASYNC_DEV_CHANGED: 329910365e5aSMatt Jacob lp = arg; 3300f7c631bcSMatt Jacob if (isp_change_is_bad) { 3301f7c631bcSMatt Jacob lp->state = FC_PORTDB_STATE_NIL; 330210365e5aSMatt Jacob if (lp->ini_map_idx) { 330310365e5aSMatt Jacob tgt = lp->ini_map_idx - 1; 3304f7c631bcSMatt Jacob FCPARAM(isp)->isp_ini_map[tgt] = 0; 3305f7c631bcSMatt Jacob lp->ini_map_idx = 0; 3306f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGCONFIG, prom3, 3307f7c631bcSMatt Jacob lp->portid, tgt, "change is bad"); 3308f7c631bcSMatt Jacob isp_make_gone(isp, tgt); 3309f7c631bcSMatt Jacob } else { 3310f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGCONFIG, prom, 3311f7c631bcSMatt Jacob lp->portid, lp->handle, 3312f7c631bcSMatt Jacob roles[lp->roles], 3313f7c631bcSMatt Jacob "changed and departed", 3314f7c631bcSMatt Jacob (uint32_t) (lp->node_wwn >> 32), 3315f7c631bcSMatt Jacob (uint32_t) lp->node_wwn, 3316f7c631bcSMatt Jacob (uint32_t) (lp->port_wwn >> 32), 3317f7c631bcSMatt Jacob (uint32_t) lp->port_wwn); 3318f7c631bcSMatt Jacob } 3319f7c631bcSMatt Jacob } else { 3320f7c631bcSMatt Jacob lp->portid = lp->new_portid; 3321f7c631bcSMatt Jacob lp->roles = lp->new_roles; 3322f7c631bcSMatt Jacob if (lp->ini_map_idx) { 3323f7c631bcSMatt Jacob int t = lp->ini_map_idx - 1; 3324f7c631bcSMatt Jacob FCPARAM(isp)->isp_ini_map[t] = 3325f7c631bcSMatt Jacob (lp - FCPARAM(isp)->portdb) + 1; 3326f7c631bcSMatt Jacob tgt = lp->ini_map_idx - 1; 332710365e5aSMatt Jacob isp_prt(isp, ISP_LOGCONFIG, prom2, 332810365e5aSMatt Jacob lp->portid, lp->handle, 3329f7c631bcSMatt Jacob roles[lp->roles], "changed at", tgt, 333010365e5aSMatt Jacob (uint32_t) (lp->node_wwn >> 32), 333110365e5aSMatt Jacob (uint32_t) lp->node_wwn, 333210365e5aSMatt Jacob (uint32_t) (lp->port_wwn >> 32), 333310365e5aSMatt Jacob (uint32_t) lp->port_wwn); 333410365e5aSMatt Jacob } else { 333510365e5aSMatt Jacob isp_prt(isp, ISP_LOGCONFIG, prom, 333610365e5aSMatt Jacob lp->portid, lp->handle, 3337f7c631bcSMatt Jacob roles[lp->roles], "changed", 333810365e5aSMatt Jacob (uint32_t) (lp->node_wwn >> 32), 333910365e5aSMatt Jacob (uint32_t) lp->node_wwn, 334010365e5aSMatt Jacob (uint32_t) (lp->port_wwn >> 32), 334110365e5aSMatt Jacob (uint32_t) lp->port_wwn); 334210365e5aSMatt Jacob } 3343f7c631bcSMatt Jacob } 334410365e5aSMatt Jacob break; 334510365e5aSMatt Jacob case ISPASYNC_DEV_STAYED: 334610365e5aSMatt Jacob lp = arg; 334710365e5aSMatt Jacob if (lp->ini_map_idx) { 334810365e5aSMatt Jacob tgt = lp->ini_map_idx - 1; 334910365e5aSMatt Jacob isp_prt(isp, ISP_LOGCONFIG, prom2, 335010365e5aSMatt Jacob lp->portid, lp->handle, 3351f7c631bcSMatt Jacob roles[lp->roles], "stayed at", tgt, 335210365e5aSMatt Jacob (uint32_t) (lp->node_wwn >> 32), 335310365e5aSMatt Jacob (uint32_t) lp->node_wwn, 335410365e5aSMatt Jacob (uint32_t) (lp->port_wwn >> 32), 335510365e5aSMatt Jacob (uint32_t) lp->port_wwn); 335610365e5aSMatt Jacob } else { 335710365e5aSMatt Jacob isp_prt(isp, ISP_LOGCONFIG, prom, 335810365e5aSMatt Jacob lp->portid, lp->handle, 3359f7c631bcSMatt Jacob roles[lp->roles], "stayed", 336010365e5aSMatt Jacob (uint32_t) (lp->node_wwn >> 32), 336110365e5aSMatt Jacob (uint32_t) lp->node_wwn, 336210365e5aSMatt Jacob (uint32_t) (lp->port_wwn >> 32), 336310365e5aSMatt Jacob (uint32_t) lp->port_wwn); 336410365e5aSMatt Jacob } 336510365e5aSMatt Jacob break; 336610365e5aSMatt Jacob case ISPASYNC_DEV_GONE: 336710365e5aSMatt Jacob lp = arg; 3368f7c631bcSMatt Jacob /* 3369f7c631bcSMatt Jacob * If this has a virtual target and we haven't marked it 3370f7c631bcSMatt Jacob * that we're going to have isp_gdt tell the OS it's gone, 3371f7c631bcSMatt Jacob * set the isp_gdt timer running on it. 3372f7c631bcSMatt Jacob * 3373f7c631bcSMatt Jacob * If it isn't marked that isp_gdt is going to get rid of it, 3374f7c631bcSMatt Jacob * announce that it's gone. 3375f7c631bcSMatt Jacob */ 3376f7c631bcSMatt Jacob if (lp->ini_map_idx && lp->reserved == 0) { 3377f7c631bcSMatt Jacob lp->reserved = 1; 3378f7c631bcSMatt Jacob lp->new_reserved = isp->isp_osinfo.gone_device_time; 3379f7c631bcSMatt Jacob lp->state = FC_PORTDB_STATE_ZOMBIE; 3380f7c631bcSMatt Jacob if (isp->isp_osinfo.gdt_running == 0) { 3381f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, 3382f7c631bcSMatt Jacob "starting Gone Device Timer"); 3383f7c631bcSMatt Jacob isp->isp_osinfo.gdt_running = 1; 33840a70657fSMatt Jacob callout_reset(&isp->isp_osinfo.gdt, hz, 33850a70657fSMatt Jacob isp_gdt, isp); 3386f7c631bcSMatt Jacob } 338710365e5aSMatt Jacob tgt = lp->ini_map_idx - 1; 338810365e5aSMatt Jacob isp_prt(isp, ISP_LOGCONFIG, prom2, 338910365e5aSMatt Jacob lp->portid, lp->handle, 3390f7c631bcSMatt Jacob roles[lp->roles], "gone zombie at", tgt, 339110365e5aSMatt Jacob (uint32_t) (lp->node_wwn >> 32), 339210365e5aSMatt Jacob (uint32_t) lp->node_wwn, 339310365e5aSMatt Jacob (uint32_t) (lp->port_wwn >> 32), 339410365e5aSMatt Jacob (uint32_t) lp->port_wwn); 3395f7c631bcSMatt Jacob } else if (lp->reserved == 0) { 339610365e5aSMatt Jacob isp_prt(isp, ISP_LOGCONFIG, prom, 339710365e5aSMatt Jacob lp->portid, lp->handle, 3398f7c631bcSMatt Jacob roles[lp->roles], "departed", 339910365e5aSMatt Jacob (uint32_t) (lp->node_wwn >> 32), 340010365e5aSMatt Jacob (uint32_t) lp->node_wwn, 340110365e5aSMatt Jacob (uint32_t) (lp->port_wwn >> 32), 340210365e5aSMatt Jacob (uint32_t) lp->port_wwn); 34034b9d588eSMatt Jacob } 340410365e5aSMatt Jacob break; 340510365e5aSMatt Jacob case ISPASYNC_CHANGE_NOTIFY: 340610365e5aSMatt Jacob { 340710365e5aSMatt Jacob char *msg; 340810365e5aSMatt Jacob if (arg == ISPASYNC_CHANGE_PDB) { 340910365e5aSMatt Jacob msg = "Port Database Changed"; 341010365e5aSMatt Jacob } else if (arg == ISPASYNC_CHANGE_SNS) { 341110365e5aSMatt Jacob msg = "Name Server Database Changed"; 341210365e5aSMatt Jacob } else { 341310365e5aSMatt Jacob msg = "Other Change Notify"; 341410365e5aSMatt Jacob } 3415f7c631bcSMatt Jacob /* 3416f7c631bcSMatt Jacob * If the loop down timer is running, cancel it. 3417f7c631bcSMatt Jacob */ 3418f7c631bcSMatt Jacob if (isp->isp_osinfo.ldt_running) { 3419f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, 3420f7c631bcSMatt Jacob "Stopping Loop Down Timer"); 3421f7c631bcSMatt Jacob isp->isp_osinfo.ldt_running = 0; 34220a70657fSMatt Jacob callout_stop(&isp->isp_osinfo.ldt); 3423f7c631bcSMatt Jacob } 342410365e5aSMatt Jacob isp_prt(isp, ISP_LOGINFO, msg); 342510365e5aSMatt Jacob isp_freeze_loopdown(isp, msg); 34260a70657fSMatt Jacob wakeup(ISP_KT_WCHAN(isp)); 342757c801f5SMatt Jacob break; 342802ab3379SMatt Jacob } 3429d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 3430e5265237SMatt Jacob case ISPASYNC_TARGET_NOTIFY: 3431d81ba9d5SMatt Jacob { 3432e5265237SMatt Jacob tmd_notify_t *nt = arg; 343364edff94SMatt Jacob isp_prt(isp, ISP_LOGALL, 3434e5265237SMatt Jacob "target notify code 0x%x", nt->nt_ncode); 3435d81ba9d5SMatt Jacob break; 3436d81ba9d5SMatt Jacob } 3437d81ba9d5SMatt Jacob case ISPASYNC_TARGET_ACTION: 3438d81ba9d5SMatt Jacob switch (((isphdr_t *)arg)->rqs_entry_type) { 3439cbf57b47SMatt Jacob default: 3440bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 3441bfbab170SMatt Jacob "event 0x%x for unhandled target action", 3442bfbab170SMatt Jacob ((isphdr_t *)arg)->rqs_entry_type); 3443d81ba9d5SMatt Jacob break; 3444570c7a3fSMatt Jacob case RQSTYPE_NOTIFY: 3445570c7a3fSMatt Jacob if (IS_SCSI(isp)) { 3446570c7a3fSMatt Jacob rv = isp_handle_platform_notify_scsi(isp, 3447570c7a3fSMatt Jacob (in_entry_t *) arg); 3448570c7a3fSMatt Jacob } else { 3449570c7a3fSMatt Jacob rv = isp_handle_platform_notify_fc(isp, 3450570c7a3fSMatt Jacob (in_fcentry_t *) arg); 3451570c7a3fSMatt Jacob } 3452570c7a3fSMatt Jacob break; 3453d81ba9d5SMatt Jacob case RQSTYPE_ATIO: 3454d81ba9d5SMatt Jacob rv = isp_handle_platform_atio(isp, (at_entry_t *) arg); 3455d81ba9d5SMatt Jacob break; 3456d81ba9d5SMatt Jacob case RQSTYPE_ATIO2: 3457d81ba9d5SMatt Jacob rv = isp_handle_platform_atio2(isp, (at2_entry_t *)arg); 3458d81ba9d5SMatt Jacob break; 3459d4a6993aSMatt Jacob case RQSTYPE_CTIO3: 3460d81ba9d5SMatt Jacob case RQSTYPE_CTIO2: 3461d81ba9d5SMatt Jacob case RQSTYPE_CTIO: 3462d81ba9d5SMatt Jacob rv = isp_handle_platform_ctio(isp, arg); 3463d81ba9d5SMatt Jacob break; 3464d81ba9d5SMatt Jacob case RQSTYPE_ENABLE_LUN: 3465d81ba9d5SMatt Jacob case RQSTYPE_MODIFY_LUN: 346667ff51f1SMatt Jacob isp_ledone(isp, (lun_entry_t *) arg); 3467d81ba9d5SMatt Jacob break; 3468d81ba9d5SMatt Jacob } 3469d81ba9d5SMatt Jacob break; 3470d81ba9d5SMatt Jacob #endif 3471ab163f5fSMatt Jacob case ISPASYNC_FW_CRASH: 3472ab163f5fSMatt Jacob { 34731dae40ebSMatt Jacob uint16_t mbox1, mbox6; 3474ab163f5fSMatt Jacob mbox1 = ISP_READ(isp, OUTMAILBOX1); 3475ab163f5fSMatt Jacob if (IS_DUALBUS(isp)) { 3476ab163f5fSMatt Jacob mbox6 = ISP_READ(isp, OUTMAILBOX6); 3477ab163f5fSMatt Jacob } else { 3478ab163f5fSMatt Jacob mbox6 = 0; 3479ab163f5fSMatt Jacob } 3480ab163f5fSMatt Jacob isp_prt(isp, ISP_LOGERR, 3481570c7a3fSMatt Jacob "Internal Firmware Error on bus %d @ RISC Address 0x%x", 3482ab163f5fSMatt Jacob mbox6, mbox1); 34838a5f89b9SMatt Jacob #ifdef ISP_FW_CRASH_DUMP 34840a70657fSMatt Jacob mbox1 = isp->isp_osinfo.mbox_sleep_ok; 34850a70657fSMatt Jacob isp->isp_osinfo.mbox_sleep_ok = 0; 34868a5f89b9SMatt Jacob if (IS_FC(isp)) { 34878a5f89b9SMatt Jacob FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; 34888a5f89b9SMatt Jacob FCPARAM(isp)->isp_loopstate = LOOP_NIL; 34898a5f89b9SMatt Jacob isp_freeze_loopdown(isp, "f/w crash"); 34908a5f89b9SMatt Jacob isp_fw_dump(isp); 34918a5f89b9SMatt Jacob } 3492ab163f5fSMatt Jacob isp_reinit(isp); 34930a70657fSMatt Jacob isp->isp_osinfo.mbox_sleep_ok = mbox1; 34940a70657fSMatt Jacob #else 34950a70657fSMatt Jacob mbox1 = isp->isp_osinfo.mbox_sleep_ok; 34960a70657fSMatt Jacob isp->isp_osinfo.mbox_sleep_ok = 0; 34970a70657fSMatt Jacob isp_reinit(isp); 34980a70657fSMatt Jacob isp->isp_osinfo.mbox_sleep_ok = mbox1; 34998a5f89b9SMatt Jacob #endif 35000a70657fSMatt Jacob isp_async(isp, ISPASYNC_FW_RESTARTED, NULL); 3501ab163f5fSMatt Jacob break; 3502ab163f5fSMatt Jacob } 3503be534d5fSMatt Jacob case ISPASYNC_UNHANDLED_RESPONSE: 3504be534d5fSMatt Jacob break; 3505d81ba9d5SMatt Jacob default: 3506b09b0095SMatt Jacob isp_prt(isp, ISP_LOGERR, "unknown isp_async event %d", cmd); 3507cbf57b47SMatt Jacob break; 3508cbf57b47SMatt Jacob } 3509cbf57b47SMatt Jacob return (rv); 3510cbf57b47SMatt Jacob } 3511cbf57b47SMatt Jacob 351292718a7fSMatt Jacob 351392718a7fSMatt Jacob /* 351492718a7fSMatt Jacob * Locks are held before coming here. 351592718a7fSMatt Jacob */ 351692718a7fSMatt Jacob void 35179cd7268eSMatt Jacob isp_uninit(ispsoftc_t *isp) 351892718a7fSMatt Jacob { 351910365e5aSMatt Jacob if (IS_24XX(isp)) { 352010365e5aSMatt Jacob ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_RESET); 352110365e5aSMatt Jacob } else { 3522ea6f23cdSMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_RESET); 352310365e5aSMatt Jacob } 352410365e5aSMatt Jacob ISP_DISABLE_INTS(isp); 352592718a7fSMatt Jacob } 3526b09b0095SMatt Jacob 3527b09b0095SMatt Jacob void 35289cd7268eSMatt Jacob isp_prt(ispsoftc_t *isp, int level, const char *fmt, ...) 3529b09b0095SMatt Jacob { 3530b09b0095SMatt Jacob va_list ap; 3531b09b0095SMatt Jacob if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) { 3532b09b0095SMatt Jacob return; 3533b09b0095SMatt Jacob } 35343c75bb14SMatt Jacob printf("%s: ", device_get_nameunit(isp->isp_dev)); 3535b09b0095SMatt Jacob va_start(ap, fmt); 3536b09b0095SMatt Jacob vprintf(fmt, ap); 3537b09b0095SMatt Jacob va_end(ap); 3538b09b0095SMatt Jacob printf("\n"); 3539b09b0095SMatt Jacob } 3540f7c631bcSMatt Jacob 3541f7c631bcSMatt Jacob uint64_t 3542f7c631bcSMatt Jacob isp_nanotime_sub(struct timespec *b, struct timespec *a) 3543f7c631bcSMatt Jacob { 3544f7c631bcSMatt Jacob uint64_t elapsed; 3545f7c631bcSMatt Jacob struct timespec x = *b; 3546f7c631bcSMatt Jacob timespecsub(&x, a); 3547f7c631bcSMatt Jacob elapsed = GET_NANOSEC(&x); 3548f7c631bcSMatt Jacob if (elapsed == 0) 3549f7c631bcSMatt Jacob elapsed++; 3550f7c631bcSMatt Jacob return (elapsed); 3551f7c631bcSMatt Jacob } 3552f7c631bcSMatt Jacob 3553f7c631bcSMatt Jacob int 3554f7c631bcSMatt Jacob isp_mbox_acquire(ispsoftc_t *isp) 3555f7c631bcSMatt Jacob { 3556f7c631bcSMatt Jacob if (isp->isp_osinfo.mboxbsy) { 3557f7c631bcSMatt Jacob return (1); 3558f7c631bcSMatt Jacob } else { 3559f7c631bcSMatt Jacob isp->isp_osinfo.mboxcmd_done = 0; 3560f7c631bcSMatt Jacob isp->isp_osinfo.mboxbsy = 1; 3561f7c631bcSMatt Jacob return (0); 3562f7c631bcSMatt Jacob } 3563f7c631bcSMatt Jacob } 3564f7c631bcSMatt Jacob 3565f7c631bcSMatt Jacob void 3566f7c631bcSMatt Jacob isp_mbox_wait_complete(ispsoftc_t *isp, mbreg_t *mbp) 3567f7c631bcSMatt Jacob { 3568a4f3a2beSMatt Jacob unsigned int usecs = mbp->timeout; 3569a4f3a2beSMatt Jacob unsigned int max, olim, ilim; 3570f7c631bcSMatt Jacob 3571f7c631bcSMatt Jacob if (usecs == 0) { 3572f7c631bcSMatt Jacob usecs = MBCMD_DEFAULT_TIMEOUT; 3573f7c631bcSMatt Jacob } 3574a4f3a2beSMatt Jacob max = isp->isp_mbxwrk0 + 1; 3575a4f3a2beSMatt Jacob 3576f7c631bcSMatt Jacob if (isp->isp_osinfo.mbox_sleep_ok) { 3577a4f3a2beSMatt Jacob unsigned int ms = (usecs + 999) / 1000; 3578a4f3a2beSMatt Jacob 3579f7c631bcSMatt Jacob isp->isp_osinfo.mbox_sleep_ok = 0; 3580f7c631bcSMatt Jacob isp->isp_osinfo.mbox_sleeping = 1; 3581a4f3a2beSMatt Jacob for (olim = 0; olim < max; olim++) { 35820a70657fSMatt Jacob #if __FreeBSD_version < 700037 3583f7c631bcSMatt Jacob tsleep(&isp->isp_mbxworkp, PRIBIO, "ispmbx_sleep", 3584f7c631bcSMatt Jacob isp_mstohz(ms)); 3585f7c631bcSMatt Jacob #else 35860a70657fSMatt Jacob msleep(&isp->isp_mbxworkp, &isp->isp_osinfo.lock, 35870a70657fSMatt Jacob PRIBIO, "ispmbx_sleep", isp_mstohz(ms)); 3588f7c631bcSMatt Jacob #endif 3589a4f3a2beSMatt Jacob if (isp->isp_osinfo.mboxcmd_done) { 3590a4f3a2beSMatt Jacob break; 3591a4f3a2beSMatt Jacob } 3592a4f3a2beSMatt Jacob } 3593f7c631bcSMatt Jacob isp->isp_osinfo.mbox_sleep_ok = 1; 3594f7c631bcSMatt Jacob isp->isp_osinfo.mbox_sleeping = 0; 3595f7c631bcSMatt Jacob } else { 3596a4f3a2beSMatt Jacob for (olim = 0; olim < max; olim++) { 3597a4f3a2beSMatt Jacob for (ilim = 0; ilim < usecs; ilim += 100) { 3598f7c631bcSMatt Jacob uint32_t isr; 3599f7c631bcSMatt Jacob uint16_t sema, mbox; 3600f7c631bcSMatt Jacob if (isp->isp_osinfo.mboxcmd_done) { 3601f7c631bcSMatt Jacob break; 3602f7c631bcSMatt Jacob } 3603f7c631bcSMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 3604f7c631bcSMatt Jacob isp_intr(isp, isr, sema, mbox); 3605f7c631bcSMatt Jacob if (isp->isp_osinfo.mboxcmd_done) { 3606f7c631bcSMatt Jacob break; 3607f7c631bcSMatt Jacob } 3608f7c631bcSMatt Jacob } 3609f7c631bcSMatt Jacob USEC_DELAY(100); 3610f7c631bcSMatt Jacob } 3611a4f3a2beSMatt Jacob if (isp->isp_osinfo.mboxcmd_done) { 3612a4f3a2beSMatt Jacob break; 3613a4f3a2beSMatt Jacob } 3614a4f3a2beSMatt Jacob } 3615f7c631bcSMatt Jacob } 3616f7c631bcSMatt Jacob if (isp->isp_osinfo.mboxcmd_done == 0) { 3617f7c631bcSMatt Jacob isp_prt(isp, ISP_LOGWARN, 3618ffcf6651SMatt Jacob "%s Mailbox Command (0x%x) Timeout (%uus)", 3619f7c631bcSMatt Jacob isp->isp_osinfo.mbox_sleep_ok? "Interrupting" : "Polled", 3620ffcf6651SMatt Jacob isp->isp_lastmbxcmd, usecs); 3621f7c631bcSMatt Jacob mbp->param[0] = MBOX_TIMEOUT; 3622f7c631bcSMatt Jacob isp->isp_osinfo.mboxcmd_done = 1; 3623f7c631bcSMatt Jacob } 3624f7c631bcSMatt Jacob } 3625f7c631bcSMatt Jacob 3626f7c631bcSMatt Jacob void 3627f7c631bcSMatt Jacob isp_mbox_notify_done(ispsoftc_t *isp) 3628f7c631bcSMatt Jacob { 3629f7c631bcSMatt Jacob if (isp->isp_osinfo.mbox_sleeping) { 3630f7c631bcSMatt Jacob wakeup(&isp->isp_mbxworkp); 3631f7c631bcSMatt Jacob } 3632f7c631bcSMatt Jacob isp->isp_osinfo.mboxcmd_done = 1; 3633f7c631bcSMatt Jacob } 3634f7c631bcSMatt Jacob 3635f7c631bcSMatt Jacob void 3636f7c631bcSMatt Jacob isp_mbox_release(ispsoftc_t *isp) 3637f7c631bcSMatt Jacob { 3638f7c631bcSMatt Jacob isp->isp_osinfo.mboxbsy = 0; 3639f7c631bcSMatt Jacob } 3640f7c631bcSMatt Jacob 3641f7c631bcSMatt Jacob int 3642f7c631bcSMatt Jacob isp_mstohz(int ms) 3643f7c631bcSMatt Jacob { 3644a4f3a2beSMatt Jacob int hz; 3645f7c631bcSMatt Jacob struct timeval t; 3646f7c631bcSMatt Jacob t.tv_sec = ms / 1000; 3647f7c631bcSMatt Jacob t.tv_usec = (ms % 1000) * 1000; 3648a4f3a2beSMatt Jacob hz = tvtohz(&t); 3649a4f3a2beSMatt Jacob if (hz < 0) { 3650a4f3a2beSMatt Jacob hz = 0x7fffffff; 3651f7c631bcSMatt Jacob } 3652a4f3a2beSMatt Jacob if (hz == 0) { 3653a4f3a2beSMatt Jacob hz = 1; 3654a4f3a2beSMatt Jacob } 3655a4f3a2beSMatt Jacob return (hz); 3656f7c631bcSMatt Jacob } 36570a70657fSMatt Jacob 36580a70657fSMatt Jacob void 36590a70657fSMatt Jacob isp_platform_intr(void *arg) 36600a70657fSMatt Jacob { 36610a70657fSMatt Jacob ispsoftc_t *isp = arg; 36620a70657fSMatt Jacob uint32_t isr; 36630a70657fSMatt Jacob uint16_t sema, mbox; 36640a70657fSMatt Jacob 36650a70657fSMatt Jacob ISP_LOCK(isp); 36660a70657fSMatt Jacob isp->isp_intcnt++; 36670a70657fSMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox) == 0) { 36680a70657fSMatt Jacob isp->isp_intbogus++; 36690a70657fSMatt Jacob } else { 36700a70657fSMatt Jacob isp_intr(isp, isr, sema, mbox); 36710a70657fSMatt Jacob } 36720a70657fSMatt Jacob ISP_UNLOCK(isp); 36730a70657fSMatt Jacob } 36740a70657fSMatt Jacob 36750a70657fSMatt Jacob void 36760a70657fSMatt Jacob isp_common_dmateardown(ispsoftc_t *isp, struct ccb_scsiio *csio, uint32_t hdl) 36770a70657fSMatt Jacob { 36780a70657fSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 36790a70657fSMatt Jacob bus_dmamap_sync(isp->isp_osinfo.dmat, 36800a70657fSMatt Jacob PISP_PCMD(csio)->dmap, BUS_DMASYNC_POSTREAD); 36810a70657fSMatt Jacob } else { 36820a70657fSMatt Jacob bus_dmamap_sync(isp->isp_osinfo.dmat, 36830a70657fSMatt Jacob PISP_PCMD(csio)->dmap, BUS_DMASYNC_POSTWRITE); 36840a70657fSMatt Jacob } 36850a70657fSMatt Jacob bus_dmamap_unload(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap); 36860a70657fSMatt Jacob } 3687