1c3aac50fSPeter Wemm /* $FreeBSD$ */ 26054c3f6SMatt Jacob /* 36054c3f6SMatt Jacob * Platform (FreeBSD) dependent common attachment code for Qlogic adapters. 46054c3f6SMatt Jacob * 55f5aafe1SMatt Jacob * Copyright (c) 1997, 1998, 1999, 2000, 2001 by Matthew Jacob 66054c3f6SMatt Jacob * 76054c3f6SMatt Jacob * Redistribution and use in source and binary forms, with or without 86054c3f6SMatt Jacob * modification, are permitted provided that the following conditions 96054c3f6SMatt Jacob * are met: 106054c3f6SMatt Jacob * 1. Redistributions of source code must retain the above copyright 116054c3f6SMatt Jacob * notice immediately at the beginning of the file, without modification, 126054c3f6SMatt Jacob * this list of conditions, and the following disclaimer. 13aa57fd6fSMatt Jacob * 2. The name of the author may not be used to endorse or promote products 14aa57fd6fSMatt Jacob * derived from this software without specific prior written permission. 156054c3f6SMatt Jacob * 166054c3f6SMatt Jacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 176054c3f6SMatt Jacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 186054c3f6SMatt Jacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 196054c3f6SMatt Jacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 206054c3f6SMatt Jacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 216054c3f6SMatt Jacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 226054c3f6SMatt Jacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 236054c3f6SMatt Jacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 246054c3f6SMatt Jacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 256054c3f6SMatt Jacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 266054c3f6SMatt Jacob * SUCH DAMAGE. 276054c3f6SMatt Jacob */ 286054c3f6SMatt Jacob #include <dev/isp/isp_freebsd.h> 295d571944SMatt Jacob #include <sys/unistd.h> 305d571944SMatt Jacob #include <sys/kthread.h> 313ea883b4SMatt Jacob #include <machine/stdarg.h> /* for use by isp_prt below */ 325d571944SMatt Jacob #include <sys/conf.h> 335d571944SMatt Jacob #include <sys/ioccom.h> 345d571944SMatt Jacob #include <dev/isp/isp_ioctl.h> 356054c3f6SMatt Jacob 36a1bc34c6SMatt Jacob 375d571944SMatt Jacob static d_ioctl_t ispioctl; 38f6e75de2SMatt Jacob static void isp_intr_enable(void *); 390470d791SMatt Jacob static void isp_cam_async(void *, u_int32_t, struct cam_path *, void *); 400470d791SMatt Jacob static void isp_poll(struct cam_sim *); 415d571944SMatt Jacob #if 0 420470d791SMatt Jacob static void isp_relsim(void *); 435d571944SMatt Jacob #endif 44b85389e1SMatt Jacob static timeout_t isp_watchdog; 455d571944SMatt Jacob static void isp_kthread(void *); 46d81ba9d5SMatt Jacob static void isp_action(struct cam_sim *, union ccb *); 470470d791SMatt Jacob 48cc8df88bSMatt Jacob 495d571944SMatt Jacob #define ISP_CDEV_MAJOR 248 505d571944SMatt Jacob static struct cdevsw isp_cdevsw = { 515d571944SMatt Jacob /* open */ nullopen, 525d571944SMatt Jacob /* close */ nullclose, 535d571944SMatt Jacob /* read */ noread, 545d571944SMatt Jacob /* write */ nowrite, 555d571944SMatt Jacob /* ioctl */ ispioctl, 565d571944SMatt Jacob /* poll */ nopoll, 575d571944SMatt Jacob /* mmap */ nommap, 585d571944SMatt Jacob /* strategy */ nostrategy, 595d571944SMatt Jacob /* name */ "isp", 605d571944SMatt Jacob /* maj */ ISP_CDEV_MAJOR, 615d571944SMatt Jacob /* dump */ nodump, 625d571944SMatt Jacob /* psize */ nopsize, 635d571944SMatt Jacob /* flags */ D_TAPE, 645d571944SMatt Jacob }; 655d571944SMatt Jacob 66d81ba9d5SMatt Jacob static struct ispsoftc *isplist = NULL; 67478f8a96SJustin T. Gibbs 68478f8a96SJustin T. Gibbs void 69c3055363SMatt Jacob isp_attach(struct ispsoftc *isp) 70478f8a96SJustin T. Gibbs { 71ea6f23cdSMatt Jacob int primary, secondary; 72478f8a96SJustin T. Gibbs struct ccb_setasync csa; 73478f8a96SJustin T. Gibbs struct cam_devq *devq; 74ea6f23cdSMatt Jacob struct cam_sim *sim; 75ea6f23cdSMatt Jacob struct cam_path *path; 76478f8a96SJustin T. Gibbs 77478f8a96SJustin T. Gibbs /* 78ea6f23cdSMatt Jacob * Establish (in case of 12X0) which bus is the primary. 79ea6f23cdSMatt Jacob */ 80ea6f23cdSMatt Jacob 81ea6f23cdSMatt Jacob primary = 0; 82ea6f23cdSMatt Jacob secondary = 1; 83ea6f23cdSMatt Jacob 84ea6f23cdSMatt Jacob /* 85ea6f23cdSMatt Jacob * Create the device queue for our SIM(s). 86478f8a96SJustin T. Gibbs */ 87ab6c4b31SMatt Jacob devq = cam_simq_alloc(isp->isp_maxcmds); 88478f8a96SJustin T. Gibbs if (devq == NULL) { 89478f8a96SJustin T. Gibbs return; 90478f8a96SJustin T. Gibbs } 91478f8a96SJustin T. Gibbs 92478f8a96SJustin T. Gibbs /* 93ea6f23cdSMatt Jacob * Construct our SIM entry. 94478f8a96SJustin T. Gibbs */ 9545c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 96ea6f23cdSMatt Jacob sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp, 973c75bb14SMatt Jacob device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq); 98ea6f23cdSMatt Jacob if (sim == NULL) { 99478f8a96SJustin T. Gibbs cam_simq_free(devq); 10045c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 101478f8a96SJustin T. Gibbs return; 102478f8a96SJustin T. Gibbs } 10345c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 104f6e75de2SMatt Jacob 105f6e75de2SMatt Jacob isp->isp_osinfo.ehook.ich_func = isp_intr_enable; 106f6e75de2SMatt Jacob isp->isp_osinfo.ehook.ich_arg = isp; 10745c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 108f6e75de2SMatt Jacob if (config_intrhook_establish(&isp->isp_osinfo.ehook) != 0) { 10945c9a36aSMatt Jacob cam_sim_free(sim, TRUE); 11045c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 111bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 112bfbab170SMatt Jacob "could not establish interrupt enable hook"); 113f6e75de2SMatt Jacob return; 114f6e75de2SMatt Jacob } 115f6e75de2SMatt Jacob 116ea6f23cdSMatt Jacob if (xpt_bus_register(sim, primary) != CAM_SUCCESS) { 117ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 11845c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 119478f8a96SJustin T. Gibbs return; 120478f8a96SJustin T. Gibbs } 121478f8a96SJustin T. Gibbs 122ea6f23cdSMatt Jacob if (xpt_create_path(&path, NULL, cam_sim_path(sim), 123478f8a96SJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 124ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 125ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 1265d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 12745c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 128478f8a96SJustin T. Gibbs return; 129478f8a96SJustin T. Gibbs } 130478f8a96SJustin T. Gibbs 131ea6f23cdSMatt Jacob xpt_setup_ccb(&csa.ccb_h, path, 5); 132478f8a96SJustin T. Gibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 133478f8a96SJustin T. Gibbs csa.event_enable = AC_LOST_DEVICE; 134cbf57b47SMatt Jacob csa.callback = isp_cam_async; 135ea6f23cdSMatt Jacob csa.callback_arg = sim; 136478f8a96SJustin T. Gibbs xpt_action((union ccb *)&csa); 13745c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 138ea6f23cdSMatt Jacob isp->isp_sim = sim; 139ea6f23cdSMatt Jacob isp->isp_path = path; 1405d571944SMatt Jacob /* 1415d571944SMatt Jacob * Create a kernel thread for fibre channel instances. We 1425d571944SMatt Jacob * don't have dual channel FC cards. 1435d571944SMatt Jacob */ 1445d571944SMatt Jacob if (IS_FC(isp)) { 14545c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 14645c9a36aSMatt Jacob /* XXX: LOCK VIOLATION */ 1475d571944SMatt Jacob cv_init(&isp->isp_osinfo.kthread_cv, "isp_kthread_cv"); 1485d571944SMatt Jacob if (kthread_create(isp_kthread, isp, &isp->isp_osinfo.kproc, 1495d571944SMatt Jacob RFHIGHPID, "%s: fc_thrd", 1505d571944SMatt Jacob device_get_nameunit(isp->isp_dev))) { 1515d571944SMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 1525d571944SMatt Jacob cam_sim_free(sim, TRUE); 1535d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 15445c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 15545c9a36aSMatt Jacob isp_prt(isp, ISP_LOGERR, "could not create kthread"); 1565d571944SMatt Jacob return; 1575d571944SMatt Jacob } 1588e6a12fcSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 1595d571944SMatt Jacob } 1605d571944SMatt Jacob 161478f8a96SJustin T. Gibbs 162ea6f23cdSMatt Jacob /* 163ea6f23cdSMatt Jacob * If we have a second channel, construct SIM entry for that. 164ea6f23cdSMatt Jacob */ 16522e1dc85SMatt Jacob if (IS_DUALBUS(isp)) { 16645c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 167ea6f23cdSMatt Jacob sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp, 1683c75bb14SMatt Jacob device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq); 169ea6f23cdSMatt Jacob if (sim == NULL) { 170ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 171ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 172ea6f23cdSMatt Jacob cam_simq_free(devq); 1735d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 174ea6f23cdSMatt Jacob return; 175ea6f23cdSMatt Jacob } 176ea6f23cdSMatt Jacob if (xpt_bus_register(sim, secondary) != CAM_SUCCESS) { 177ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 178ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 179ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 1805d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 18145c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 182ea6f23cdSMatt Jacob return; 183ea6f23cdSMatt Jacob } 184ea6f23cdSMatt Jacob 185ea6f23cdSMatt Jacob if (xpt_create_path(&path, NULL, cam_sim_path(sim), 186ea6f23cdSMatt Jacob CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 187ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 188ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 189ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 190ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 1915d571944SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 19245c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 193ea6f23cdSMatt Jacob return; 194ea6f23cdSMatt Jacob } 195ea6f23cdSMatt Jacob 196ea6f23cdSMatt Jacob xpt_setup_ccb(&csa.ccb_h, path, 5); 197ea6f23cdSMatt Jacob csa.ccb_h.func_code = XPT_SASYNC_CB; 198ea6f23cdSMatt Jacob csa.event_enable = AC_LOST_DEVICE; 199ea6f23cdSMatt Jacob csa.callback = isp_cam_async; 200ea6f23cdSMatt Jacob csa.callback_arg = sim; 201ea6f23cdSMatt Jacob xpt_action((union ccb *)&csa); 20245c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 203ea6f23cdSMatt Jacob isp->isp_sim2 = sim; 204ea6f23cdSMatt Jacob isp->isp_path2 = path; 205ea6f23cdSMatt Jacob } 2065d571944SMatt Jacob 2075d571944SMatt Jacob /* 2085d571944SMatt Jacob * Create device nodes 2095d571944SMatt Jacob */ 2105d571944SMatt Jacob (void) make_dev(&isp_cdevsw, device_get_unit(isp->isp_dev), UID_ROOT, 2115d571944SMatt Jacob GID_OPERATOR, 0600, "%s", device_get_nameunit(isp->isp_dev)); 2125d571944SMatt Jacob 213d6e5500fSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE) { 214478f8a96SJustin T. Gibbs isp->isp_state = ISP_RUNSTATE; 215b85389e1SMatt Jacob ENABLE_INTS(isp); 216d6e5500fSMatt Jacob } 217d81ba9d5SMatt Jacob if (isplist == NULL) { 218d81ba9d5SMatt Jacob isplist = isp; 219d81ba9d5SMatt Jacob } else { 220d81ba9d5SMatt Jacob struct ispsoftc *tmp = isplist; 221d81ba9d5SMatt Jacob while (tmp->isp_osinfo.next) { 222d81ba9d5SMatt Jacob tmp = tmp->isp_osinfo.next; 223d81ba9d5SMatt Jacob } 224d81ba9d5SMatt Jacob tmp->isp_osinfo.next = isp; 225478f8a96SJustin T. Gibbs } 2265d571944SMatt Jacob 2275d571944SMatt Jacob } 2285d571944SMatt Jacob 2295d571944SMatt Jacob static int 2305d571944SMatt Jacob ispioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) 2315d571944SMatt Jacob { 2325d571944SMatt Jacob struct ispsoftc *isp; 2335d571944SMatt Jacob int retval = ENOTTY; 2345d571944SMatt Jacob 2355d571944SMatt Jacob isp = isplist; 2365d571944SMatt Jacob while (isp) { 2375d571944SMatt Jacob if (minor(dev) == device_get_unit(isp->isp_dev)) { 2385d571944SMatt Jacob break; 2395d571944SMatt Jacob } 2405d571944SMatt Jacob isp = isp->isp_osinfo.next; 2415d571944SMatt Jacob } 2425d571944SMatt Jacob if (isp == NULL) 2435d571944SMatt Jacob return (ENXIO); 2445d571944SMatt Jacob 2455d571944SMatt Jacob switch (cmd) { 2465d571944SMatt Jacob case ISP_SDBLEV: 2475d571944SMatt Jacob { 2485d571944SMatt Jacob int olddblev = isp->isp_dblev; 2495d571944SMatt Jacob isp->isp_dblev = *(int *)addr; 2505d571944SMatt Jacob *(int *)addr = olddblev; 2515d571944SMatt Jacob retval = 0; 2525d571944SMatt Jacob break; 2535d571944SMatt Jacob } 2545d571944SMatt Jacob case ISP_RESETHBA: 2555d571944SMatt Jacob ISP_LOCK(isp); 2565d571944SMatt Jacob isp_reinit(isp); 2575d571944SMatt Jacob ISP_UNLOCK(isp); 2585d571944SMatt Jacob retval = 0; 2595d571944SMatt Jacob break; 2605d571944SMatt Jacob case ISP_FC_RESCAN: 2615d571944SMatt Jacob if (IS_FC(isp)) { 2625d571944SMatt Jacob ISP_LOCK(isp); 2635d571944SMatt Jacob if (isp_fc_runstate(isp, 5 * 1000000)) { 2645d571944SMatt Jacob retval = EIO; 2655d571944SMatt Jacob } else { 2665d571944SMatt Jacob retval = 0; 2675d571944SMatt Jacob } 2685d571944SMatt Jacob ISP_UNLOCK(isp); 2695d571944SMatt Jacob } 2705d571944SMatt Jacob break; 2715d571944SMatt Jacob case ISP_FC_LIP: 2725d571944SMatt Jacob if (IS_FC(isp)) { 2735d571944SMatt Jacob ISP_LOCK(isp); 2745d571944SMatt Jacob if (isp_control(isp, ISPCTL_SEND_LIP, 0)) { 2755d571944SMatt Jacob retval = EIO; 2765d571944SMatt Jacob } else { 2775d571944SMatt Jacob retval = 0; 2785d571944SMatt Jacob } 2795d571944SMatt Jacob ISP_UNLOCK(isp); 2805d571944SMatt Jacob } 2815d571944SMatt Jacob break; 2825d571944SMatt Jacob case ISP_FC_GETDINFO: 2835d571944SMatt Jacob { 2845d571944SMatt Jacob struct isp_fc_device *ifc = (struct isp_fc_device *) addr; 2855d571944SMatt Jacob struct lportdb *lp; 2865d571944SMatt Jacob 2875d571944SMatt Jacob if (ifc->loopid < 0 || ifc->loopid >= MAX_FC_TARG) { 2885d571944SMatt Jacob retval = EINVAL; 2895d571944SMatt Jacob break; 2905d571944SMatt Jacob } 2915d571944SMatt Jacob ISP_LOCK(isp); 2925d571944SMatt Jacob lp = &FCPARAM(isp)->portdb[ifc->loopid]; 2935d571944SMatt Jacob if (lp->valid) { 2945d571944SMatt Jacob ifc->loopid = lp->loopid; 2955d571944SMatt Jacob ifc->portid = lp->portid; 2965d571944SMatt Jacob ifc->node_wwn = lp->node_wwn; 2975d571944SMatt Jacob ifc->port_wwn = lp->port_wwn; 2985d571944SMatt Jacob retval = 0; 2995d571944SMatt Jacob } else { 3005d571944SMatt Jacob retval = ENODEV; 3015d571944SMatt Jacob } 3025d571944SMatt Jacob ISP_UNLOCK(isp); 3035d571944SMatt Jacob break; 3045d571944SMatt Jacob } 3055d571944SMatt Jacob default: 3065d571944SMatt Jacob break; 3075d571944SMatt Jacob } 3085d571944SMatt Jacob return (retval); 3090470d791SMatt Jacob } 310478f8a96SJustin T. Gibbs 311f6e75de2SMatt Jacob static void 312f6e75de2SMatt Jacob isp_intr_enable(void *arg) 313f6e75de2SMatt Jacob { 314f6e75de2SMatt Jacob struct ispsoftc *isp = arg; 315d6e5500fSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE) { 316f6e75de2SMatt Jacob ENABLE_INTS(isp); 317f6e75de2SMatt Jacob isp->isp_osinfo.intsok = 1; 318d6e5500fSMatt Jacob } 319f6e75de2SMatt Jacob /* Release our hook so that the boot can continue. */ 320f6e75de2SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 321f6e75de2SMatt Jacob } 322d81ba9d5SMatt Jacob 323d81ba9d5SMatt Jacob /* 324d81ba9d5SMatt Jacob * Put the target mode functions here, because some are inlines 325d81ba9d5SMatt Jacob */ 326d81ba9d5SMatt Jacob 327d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 328d81ba9d5SMatt Jacob 329a1bc34c6SMatt Jacob static __inline int is_lun_enabled(struct ispsoftc *, int, lun_id_t); 330a1bc34c6SMatt Jacob static __inline int are_any_luns_enabled(struct ispsoftc *, int); 331a1bc34c6SMatt Jacob static __inline tstate_t *get_lun_statep(struct ispsoftc *, int, lun_id_t); 332d81ba9d5SMatt Jacob static __inline void rls_lun_statep(struct ispsoftc *, tstate_t *); 333d81ba9d5SMatt Jacob static __inline int isp_psema_sig_rqe(struct ispsoftc *); 334d81ba9d5SMatt Jacob static __inline int isp_cv_wait_timed_rqe(struct ispsoftc *, int); 335d81ba9d5SMatt Jacob static __inline void isp_cv_signal_rqe(struct ispsoftc *, int); 336d81ba9d5SMatt Jacob static __inline void isp_vsema_rqe(struct ispsoftc *); 337d81ba9d5SMatt Jacob static cam_status 338a1bc34c6SMatt Jacob create_lun_state(struct ispsoftc *, int, struct cam_path *, tstate_t **); 339d81ba9d5SMatt Jacob static void destroy_lun_state(struct ispsoftc *, tstate_t *); 340d81ba9d5SMatt Jacob static void isp_en_lun(struct ispsoftc *, union ccb *); 341d81ba9d5SMatt Jacob static cam_status isp_abort_tgt_ccb(struct ispsoftc *, union ccb *); 342f48ce188SMatt Jacob static timeout_t isp_refire_putback_atio; 343a1bc34c6SMatt Jacob static void isp_complete_ctio(union ccb *); 344a1bc34c6SMatt Jacob static void isp_target_putback_atio(union ccb *); 345a1bc34c6SMatt Jacob static cam_status isp_target_start_ctio(struct ispsoftc *, union ccb *); 346d81ba9d5SMatt Jacob static int isp_handle_platform_atio(struct ispsoftc *, at_entry_t *); 347d81ba9d5SMatt Jacob static int isp_handle_platform_atio2(struct ispsoftc *, at2_entry_t *); 348d81ba9d5SMatt Jacob static int isp_handle_platform_ctio(struct ispsoftc *, void *); 349d81ba9d5SMatt Jacob 350d81ba9d5SMatt Jacob static __inline int 351a1bc34c6SMatt Jacob is_lun_enabled(struct ispsoftc *isp, int bus, lun_id_t lun) 352d81ba9d5SMatt Jacob { 353d81ba9d5SMatt Jacob tstate_t *tptr; 354a1bc34c6SMatt Jacob tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)]; 355a1bc34c6SMatt Jacob if (tptr == NULL) { 356f6e75de2SMatt Jacob ISP_UNLOCK(isp); 357d81ba9d5SMatt Jacob return (0); 358d81ba9d5SMatt Jacob } 359d81ba9d5SMatt Jacob do { 360a1bc34c6SMatt Jacob if (tptr->lun == (lun_id_t) lun && tptr->bus == bus) { 361f6e75de2SMatt Jacob ISP_UNLOCK(isp); 362d81ba9d5SMatt Jacob return (1); 363d81ba9d5SMatt Jacob } 364d81ba9d5SMatt Jacob } while ((tptr = tptr->next) != NULL); 365d81ba9d5SMatt Jacob return (0); 366d81ba9d5SMatt Jacob } 367d81ba9d5SMatt Jacob 368d81ba9d5SMatt Jacob static __inline int 369a1bc34c6SMatt Jacob are_any_luns_enabled(struct ispsoftc *isp, int port) 370d81ba9d5SMatt Jacob { 371a1bc34c6SMatt Jacob int lo, hi; 372a1bc34c6SMatt Jacob if (IS_DUALBUS(isp)) { 373a1bc34c6SMatt Jacob lo = (port * (LUN_HASH_SIZE >> 1)); 374a1bc34c6SMatt Jacob hi = lo + (LUN_HASH_SIZE >> 1); 375a1bc34c6SMatt Jacob } else { 376a1bc34c6SMatt Jacob lo = 0; 377a1bc34c6SMatt Jacob hi = LUN_HASH_SIZE; 378a1bc34c6SMatt Jacob } 379a1bc34c6SMatt Jacob for (lo = 0; lo < hi; lo++) { 380a1bc34c6SMatt Jacob if (isp->isp_osinfo.lun_hash[lo]) { 381d81ba9d5SMatt Jacob return (1); 382d81ba9d5SMatt Jacob } 383d81ba9d5SMatt Jacob } 384d81ba9d5SMatt Jacob return (0); 385d81ba9d5SMatt Jacob } 386d81ba9d5SMatt Jacob 387d81ba9d5SMatt Jacob static __inline tstate_t * 388a1bc34c6SMatt Jacob get_lun_statep(struct ispsoftc *isp, int bus, lun_id_t lun) 389d81ba9d5SMatt Jacob { 390d81ba9d5SMatt Jacob tstate_t *tptr; 391d81ba9d5SMatt Jacob 392d81ba9d5SMatt Jacob if (lun == CAM_LUN_WILDCARD) { 393126ec864SMatt Jacob if (isp->isp_osinfo.tmflags & TM_WILDCARD_ENABLED) { 394a1bc34c6SMatt Jacob tptr = &isp->isp_osinfo.tsdflt[bus]; 395d81ba9d5SMatt Jacob tptr->hold++; 396d81ba9d5SMatt Jacob return (tptr); 397d81ba9d5SMatt Jacob } else { 398d81ba9d5SMatt Jacob return (NULL); 399d81ba9d5SMatt Jacob } 400126ec864SMatt Jacob } else { 401126ec864SMatt Jacob tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)]; 402126ec864SMatt Jacob } 403d81ba9d5SMatt Jacob 404d81ba9d5SMatt Jacob do { 405a1bc34c6SMatt Jacob if (tptr->lun == lun && tptr->bus == bus) { 406d81ba9d5SMatt Jacob tptr->hold++; 407d81ba9d5SMatt Jacob return (tptr); 408d81ba9d5SMatt Jacob } 409d81ba9d5SMatt Jacob } while ((tptr = tptr->next) != NULL); 410d81ba9d5SMatt Jacob return (tptr); 411d81ba9d5SMatt Jacob } 412d81ba9d5SMatt Jacob 413d81ba9d5SMatt Jacob static __inline void 414d81ba9d5SMatt Jacob rls_lun_statep(struct ispsoftc *isp, tstate_t *tptr) 415d81ba9d5SMatt Jacob { 416d81ba9d5SMatt Jacob if (tptr->hold) 417d81ba9d5SMatt Jacob tptr->hold--; 418d81ba9d5SMatt Jacob } 419d81ba9d5SMatt Jacob 420d81ba9d5SMatt Jacob static __inline int 421d81ba9d5SMatt Jacob isp_psema_sig_rqe(struct ispsoftc *isp) 422d81ba9d5SMatt Jacob { 423d81ba9d5SMatt Jacob while (isp->isp_osinfo.tmflags & TM_BUSY) { 424d81ba9d5SMatt Jacob isp->isp_osinfo.tmflags |= TM_WANTED; 425d81ba9d5SMatt Jacob if (tsleep(&isp->isp_osinfo.tmflags, PRIBIO|PCATCH, "i0", 0)) { 426d81ba9d5SMatt Jacob return (-1); 427d81ba9d5SMatt Jacob } 428d81ba9d5SMatt Jacob isp->isp_osinfo.tmflags |= TM_BUSY; 429d81ba9d5SMatt Jacob } 430d81ba9d5SMatt Jacob return (0); 431d81ba9d5SMatt Jacob } 432d81ba9d5SMatt Jacob 433d81ba9d5SMatt Jacob static __inline int 434d81ba9d5SMatt Jacob isp_cv_wait_timed_rqe(struct ispsoftc *isp, int timo) 435d81ba9d5SMatt Jacob { 436d81ba9d5SMatt Jacob if (tsleep(&isp->isp_osinfo.rstatus, PRIBIO, "qt1", timo)) { 437f6e75de2SMatt Jacob ISP_UNLOCK(isp); 438d81ba9d5SMatt Jacob return (-1); 439d81ba9d5SMatt Jacob } 440d81ba9d5SMatt Jacob return (0); 441d81ba9d5SMatt Jacob } 442d81ba9d5SMatt Jacob 443d81ba9d5SMatt Jacob static __inline void 444d81ba9d5SMatt Jacob isp_cv_signal_rqe(struct ispsoftc *isp, int status) 445d81ba9d5SMatt Jacob { 446d81ba9d5SMatt Jacob isp->isp_osinfo.rstatus = status; 447d81ba9d5SMatt Jacob wakeup(&isp->isp_osinfo.rstatus); 448d81ba9d5SMatt Jacob } 449d81ba9d5SMatt Jacob 450d81ba9d5SMatt Jacob static __inline void 451d81ba9d5SMatt Jacob isp_vsema_rqe(struct ispsoftc *isp) 452d81ba9d5SMatt Jacob { 453d81ba9d5SMatt Jacob if (isp->isp_osinfo.tmflags & TM_WANTED) { 454d81ba9d5SMatt Jacob isp->isp_osinfo.tmflags &= ~TM_WANTED; 455d81ba9d5SMatt Jacob wakeup(&isp->isp_osinfo.tmflags); 456d81ba9d5SMatt Jacob } 457d81ba9d5SMatt Jacob isp->isp_osinfo.tmflags &= ~TM_BUSY; 458d81ba9d5SMatt Jacob } 459d81ba9d5SMatt Jacob 460d81ba9d5SMatt Jacob static cam_status 461a1bc34c6SMatt Jacob create_lun_state(struct ispsoftc *isp, int bus, 462a1bc34c6SMatt Jacob struct cam_path *path, tstate_t **rslt) 463d81ba9d5SMatt Jacob { 464d81ba9d5SMatt Jacob cam_status status; 465d81ba9d5SMatt Jacob lun_id_t lun; 466a1bc34c6SMatt Jacob int hfx; 467d81ba9d5SMatt Jacob tstate_t *tptr, *new; 468d81ba9d5SMatt Jacob 469d81ba9d5SMatt Jacob lun = xpt_path_lun_id(path); 470d81ba9d5SMatt Jacob if (lun < 0) { 471d81ba9d5SMatt Jacob return (CAM_LUN_INVALID); 472d81ba9d5SMatt Jacob } 473a1bc34c6SMatt Jacob if (is_lun_enabled(isp, bus, lun)) { 474d81ba9d5SMatt Jacob return (CAM_LUN_ALRDY_ENA); 475d81ba9d5SMatt Jacob } 476ea8b5a9aSDavid Malone new = (tstate_t *) malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO); 477d81ba9d5SMatt Jacob if (new == NULL) { 478d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 479d81ba9d5SMatt Jacob } 480d81ba9d5SMatt Jacob 481d81ba9d5SMatt Jacob status = xpt_create_path(&new->owner, NULL, xpt_path_path_id(path), 482d81ba9d5SMatt Jacob xpt_path_target_id(path), xpt_path_lun_id(path)); 483d81ba9d5SMatt Jacob if (status != CAM_REQ_CMP) { 484d81ba9d5SMatt Jacob free(new, M_DEVBUF); 485d81ba9d5SMatt Jacob return (status); 486d81ba9d5SMatt Jacob } 487a1bc34c6SMatt Jacob new->bus = bus; 488d81ba9d5SMatt Jacob new->lun = lun; 489d81ba9d5SMatt Jacob SLIST_INIT(&new->atios); 490d81ba9d5SMatt Jacob SLIST_INIT(&new->inots); 491d81ba9d5SMatt Jacob new->hold = 1; 492d81ba9d5SMatt Jacob 493a1bc34c6SMatt Jacob hfx = LUN_HASH_FUNC(isp, new->bus, new->lun); 494a1bc34c6SMatt Jacob tptr = isp->isp_osinfo.lun_hash[hfx]; 495a1bc34c6SMatt Jacob if (tptr == NULL) { 496a1bc34c6SMatt Jacob isp->isp_osinfo.lun_hash[hfx] = new; 497d81ba9d5SMatt Jacob } else { 498d81ba9d5SMatt Jacob while (tptr->next) 499d81ba9d5SMatt Jacob tptr = tptr->next; 500d81ba9d5SMatt Jacob tptr->next = new; 501d81ba9d5SMatt Jacob } 502d81ba9d5SMatt Jacob *rslt = new; 503d81ba9d5SMatt Jacob return (CAM_REQ_CMP); 504d81ba9d5SMatt Jacob } 505d81ba9d5SMatt Jacob 506d81ba9d5SMatt Jacob static __inline void 507d81ba9d5SMatt Jacob destroy_lun_state(struct ispsoftc *isp, tstate_t *tptr) 508d81ba9d5SMatt Jacob { 509a1bc34c6SMatt Jacob int hfx; 510d81ba9d5SMatt Jacob tstate_t *lw, *pw; 511d81ba9d5SMatt Jacob 512a1bc34c6SMatt Jacob hfx = LUN_HASH_FUNC(isp, tptr->bus, tptr->lun); 513d81ba9d5SMatt Jacob if (tptr->hold) { 514d81ba9d5SMatt Jacob return; 515d81ba9d5SMatt Jacob } 516a1bc34c6SMatt Jacob pw = isp->isp_osinfo.lun_hash[hfx]; 517d81ba9d5SMatt Jacob if (pw == NULL) { 518d81ba9d5SMatt Jacob return; 519a1bc34c6SMatt Jacob } else if (pw->lun == tptr->lun && pw->bus == tptr->bus) { 520a1bc34c6SMatt Jacob isp->isp_osinfo.lun_hash[hfx] = pw->next; 521d81ba9d5SMatt Jacob } else { 522d81ba9d5SMatt Jacob lw = pw; 523d81ba9d5SMatt Jacob pw = lw->next; 524d81ba9d5SMatt Jacob while (pw) { 525a1bc34c6SMatt Jacob if (pw->lun == tptr->lun && pw->bus == tptr->bus) { 526d81ba9d5SMatt Jacob lw->next = pw->next; 527d81ba9d5SMatt Jacob break; 528d81ba9d5SMatt Jacob } 529d81ba9d5SMatt Jacob lw = pw; 530d81ba9d5SMatt Jacob pw = pw->next; 531d81ba9d5SMatt Jacob } 532d81ba9d5SMatt Jacob if (pw == NULL) { 533f6e75de2SMatt Jacob ISP_UNLOCK(isp); 534d81ba9d5SMatt Jacob return; 535d81ba9d5SMatt Jacob } 536d81ba9d5SMatt Jacob } 537d81ba9d5SMatt Jacob free(tptr, M_DEVBUF); 538d81ba9d5SMatt Jacob } 539d81ba9d5SMatt Jacob 5405d571944SMatt Jacob /* 5415d571944SMatt Jacob * we enter with our locks held. 5425d571944SMatt Jacob */ 543d81ba9d5SMatt Jacob static void 544d81ba9d5SMatt Jacob isp_en_lun(struct ispsoftc *isp, union ccb *ccb) 545d81ba9d5SMatt Jacob { 546a1bc34c6SMatt Jacob const char lfmt[] = "Lun now %sabled for target mode on channel %d"; 547d81ba9d5SMatt Jacob struct ccb_en_lun *cel = &ccb->cel; 548d81ba9d5SMatt Jacob tstate_t *tptr; 549d81ba9d5SMatt Jacob u_int16_t rstat; 550126ec864SMatt Jacob int bus, cmd, av, wildcard, frozen = 0; 551d81ba9d5SMatt Jacob lun_id_t lun; 552d81ba9d5SMatt Jacob target_id_t tgt; 553d81ba9d5SMatt Jacob 554d81ba9d5SMatt Jacob 555a1bc34c6SMatt Jacob bus = XS_CHANNEL(ccb) & 0x1; 556d81ba9d5SMatt Jacob tgt = ccb->ccb_h.target_id; 557d81ba9d5SMatt Jacob lun = ccb->ccb_h.target_lun; 558d81ba9d5SMatt Jacob 559d81ba9d5SMatt Jacob /* 560d81ba9d5SMatt Jacob * Do some sanity checking first. 561d81ba9d5SMatt Jacob */ 562d81ba9d5SMatt Jacob 563d6e5500fSMatt Jacob if ((lun != CAM_LUN_WILDCARD) && 564d6e5500fSMatt Jacob (lun < 0 || lun >= (lun_id_t) isp->isp_maxluns)) { 565d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 566d81ba9d5SMatt Jacob return; 567d81ba9d5SMatt Jacob } 5682ad50ca5SMatt Jacob if (IS_SCSI(isp)) { 569a1bc34c6SMatt Jacob sdparam *sdp = isp->isp_param; 570a1bc34c6SMatt Jacob sdp += bus; 571d81ba9d5SMatt Jacob if (tgt != CAM_TARGET_WILDCARD && 572a1bc34c6SMatt Jacob tgt != sdp->isp_initiator_id) { 573d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_TID_INVALID; 574d81ba9d5SMatt Jacob return; 575d81ba9d5SMatt Jacob } 576d81ba9d5SMatt Jacob } else { 577d81ba9d5SMatt Jacob if (tgt != CAM_TARGET_WILDCARD && 578d6e5500fSMatt Jacob tgt != FCPARAM(isp)->isp_iid) { 579d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_TID_INVALID; 580d81ba9d5SMatt Jacob return; 581d81ba9d5SMatt Jacob } 582d81ba9d5SMatt Jacob } 583d81ba9d5SMatt Jacob 584d6e5500fSMatt Jacob if (tgt == CAM_TARGET_WILDCARD) { 585d6e5500fSMatt Jacob if (lun != CAM_LUN_WILDCARD) { 586d6e5500fSMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 587d6e5500fSMatt Jacob return; 588d6e5500fSMatt Jacob } 589d6e5500fSMatt Jacob } 590d6e5500fSMatt Jacob 591b6b6ad2fSMatt Jacob /* 592b6b6ad2fSMatt Jacob * If Fibre Channel, stop and drain all activity to this bus. 593b6b6ad2fSMatt Jacob */ 594d6e5500fSMatt Jacob #if 0 595b6b6ad2fSMatt Jacob if (IS_FC(isp)) { 596b6b6ad2fSMatt Jacob ISP_LOCK(isp); 597b6b6ad2fSMatt Jacob frozen = 1; 598b6b6ad2fSMatt Jacob xpt_freeze_simq(isp->isp_sim, 1); 599b6b6ad2fSMatt Jacob isp->isp_osinfo.drain = 1; 600b6b6ad2fSMatt Jacob while (isp->isp_osinfo.drain) { 6015d571944SMatt Jacob (void) msleep(&isp->isp_osinfo.drain, &isp->isp_lock, 6025d571944SMatt Jacob PRIBIO, "ispdrain", 10 * hz); 603b6b6ad2fSMatt Jacob } 604b6b6ad2fSMatt Jacob ISP_UNLOCK(isp); 605b6b6ad2fSMatt Jacob } 606d6e5500fSMatt Jacob #endif 607b6b6ad2fSMatt Jacob 608b6b6ad2fSMatt Jacob /* 609b6b6ad2fSMatt Jacob * Check to see if we're enabling on fibre channel and 610b6b6ad2fSMatt Jacob * don't yet have a notion of who the heck we are (no 611b6b6ad2fSMatt Jacob * loop yet). 612b6b6ad2fSMatt Jacob */ 613b6b6ad2fSMatt Jacob if (IS_FC(isp) && cel->enable && 614b6b6ad2fSMatt Jacob (isp->isp_osinfo.tmflags & TM_TMODE_ENABLED) == 0) { 615b6b6ad2fSMatt Jacob fcparam *fcp = isp->isp_param; 616d6e5500fSMatt Jacob int rv; 617b6b6ad2fSMatt Jacob 618d6e5500fSMatt Jacob rv = isp_fc_runstate(isp, 2 * 1000000); 619d6e5500fSMatt Jacob if (fcp->isp_fwstate != FW_READY || 620d6e5500fSMatt Jacob fcp->isp_loopstate != LOOP_READY) { 621b6b6ad2fSMatt Jacob xpt_print_path(ccb->ccb_h.path); 6223c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 6233c75bb14SMatt Jacob "could not get a good port database read"); 624b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 6255d571944SMatt Jacob if (frozen) { 6265d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 627b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 6285d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 6295d571944SMatt Jacob } 630b6b6ad2fSMatt Jacob return; 631b6b6ad2fSMatt Jacob } 632b6b6ad2fSMatt Jacob } 633b6b6ad2fSMatt Jacob 634126ec864SMatt Jacob if (lun == CAM_LUN_WILDCARD && tgt == CAM_TARGET_WILDCARD) { 635126ec864SMatt Jacob wildcard = 1; 636126ec864SMatt Jacob } else { 637126ec864SMatt Jacob wildcard = 0; 638126ec864SMatt Jacob } 639b6b6ad2fSMatt Jacob 640b6b6ad2fSMatt Jacob /* 641b6b6ad2fSMatt Jacob * Next check to see whether this is a target/lun wildcard action. 642126ec864SMatt Jacob * If so, we know that we can accept commands and send them 643126ec864SMatt Jacob * upstream. Otherwise, we have to handle them locally. 644b6b6ad2fSMatt Jacob */ 645126ec864SMatt Jacob 646126ec864SMatt Jacob if (wildcard) { 647a1bc34c6SMatt Jacob tptr = &isp->isp_osinfo.tsdflt[bus]; 648b6b6ad2fSMatt Jacob if (cel->enable) { 649126ec864SMatt Jacob if (isp->isp_osinfo.tmflags & TM_WILDCARD_ENABLED) { 650b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; 651b6b6ad2fSMatt Jacob return; 652b6b6ad2fSMatt Jacob } 653b6b6ad2fSMatt Jacob ccb->ccb_h.status = 654b6b6ad2fSMatt Jacob xpt_create_path(&tptr->owner, NULL, 655b6b6ad2fSMatt Jacob xpt_path_path_id(ccb->ccb_h.path), 656b6b6ad2fSMatt Jacob xpt_path_target_id(ccb->ccb_h.path), 657b6b6ad2fSMatt Jacob xpt_path_lun_id(ccb->ccb_h.path)); 658b6b6ad2fSMatt Jacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 6595d571944SMatt Jacob if (frozen) { 6605d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 661b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 6625d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 6635d571944SMatt Jacob } 664b6b6ad2fSMatt Jacob return; 665b6b6ad2fSMatt Jacob } 666b6b6ad2fSMatt Jacob SLIST_INIT(&tptr->atios); 667b6b6ad2fSMatt Jacob SLIST_INIT(&tptr->inots); 668126ec864SMatt Jacob isp->isp_osinfo.tmflags |= TM_WILDCARD_ENABLED; 669126ec864SMatt Jacob } else { 670126ec864SMatt Jacob if (!(isp->isp_osinfo.tmflags & TM_WILDCARD_ENABLED)) { 671126ec864SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 672126ec864SMatt Jacob return; 673126ec864SMatt Jacob } 674126ec864SMatt Jacob if (tptr->hold) { 675126ec864SMatt Jacob ccb->ccb_h.status = CAM_SCSI_BUSY; 676126ec864SMatt Jacob return; 677126ec864SMatt Jacob } 678126ec864SMatt Jacob xpt_free_path(tptr->owner); 679126ec864SMatt Jacob isp->isp_osinfo.tmflags &= ~TM_WILDCARD_ENABLED; 680126ec864SMatt Jacob } 681126ec864SMatt Jacob } 682126ec864SMatt Jacob 683126ec864SMatt Jacob /* 684126ec864SMatt Jacob * Now check to see whether this bus needs to be 685126ec864SMatt Jacob * enabled/disabled with respect to target mode. 686126ec864SMatt Jacob */ 687126ec864SMatt Jacob 688126ec864SMatt Jacob av = bus << 31; 689126ec864SMatt Jacob if (cel->enable && (isp->isp_osinfo.tmflags & (1 << bus)) == 0) { 690a1bc34c6SMatt Jacob av |= ENABLE_TARGET_FLAG; 691b6b6ad2fSMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 692b6b6ad2fSMatt Jacob if (av) { 693b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 694126ec864SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 695126ec864SMatt Jacob xpt_release_simq(isp->isp_sim, 1); 696126ec864SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 697126ec864SMatt Jacob if (wildcard) { 698126ec864SMatt Jacob isp->isp_osinfo.tmflags &= ~TM_WILDCARD_ENABLED; 699b6b6ad2fSMatt Jacob xpt_free_path(tptr->owner); 7005d571944SMatt Jacob } 701b6b6ad2fSMatt Jacob return; 702b6b6ad2fSMatt Jacob } 703126ec864SMatt Jacob isp_prt(isp, ISP_LOGINFO, 704126ec864SMatt Jacob "Target Mode enabled on channel %d", bus); 705126ec864SMatt Jacob } else if (cel->enable == 0 && (isp->isp_osinfo.tmflags & (1 << bus)) && 706126ec864SMatt Jacob wildcard) { 707a1bc34c6SMatt Jacob if (are_any_luns_enabled(isp, bus)) { 708b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_SCSI_BUSY; 7095d571944SMatt Jacob if (frozen) { 7105d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 711b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 7125d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 7135d571944SMatt Jacob } 714b6b6ad2fSMatt Jacob return; 715b6b6ad2fSMatt Jacob } 716b6b6ad2fSMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 717b6b6ad2fSMatt Jacob if (av) { 718b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 7195d571944SMatt Jacob if (frozen) { 7205d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 721b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 7225d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 7235d571944SMatt Jacob } 724b6b6ad2fSMatt Jacob return; 725b6b6ad2fSMatt Jacob } 726a1bc34c6SMatt Jacob isp->isp_osinfo.tmflags &= ~(1 << bus); 727b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 728b6b6ad2fSMatt Jacob xpt_print_path(ccb->ccb_h.path); 729126ec864SMatt Jacob isp_prt(isp, ISP_LOGINFO, 730126ec864SMatt Jacob "Target Mode disabled on channel %d", bus); 731126ec864SMatt Jacob } 732126ec864SMatt Jacob 733126ec864SMatt Jacob if (wildcard) { 7345d571944SMatt Jacob if (frozen) { 7355d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 736b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 7375d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 7385d571944SMatt Jacob } 739b6b6ad2fSMatt Jacob return; 740b6b6ad2fSMatt Jacob } 741b6b6ad2fSMatt Jacob 742b6b6ad2fSMatt Jacob /* 743b6b6ad2fSMatt Jacob * We can move along now... 744b6b6ad2fSMatt Jacob */ 745b6b6ad2fSMatt Jacob 7465d571944SMatt Jacob if (frozen) { 7475d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 748b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 7495d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 7505d571944SMatt Jacob } 751b6b6ad2fSMatt Jacob 752d81ba9d5SMatt Jacob 753d81ba9d5SMatt Jacob if (cel->enable) { 754d81ba9d5SMatt Jacob ccb->ccb_h.status = 755a1bc34c6SMatt Jacob create_lun_state(isp, bus, ccb->ccb_h.path, &tptr); 756d81ba9d5SMatt Jacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 757d81ba9d5SMatt Jacob return; 758d81ba9d5SMatt Jacob } 759d81ba9d5SMatt Jacob } else { 760a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, lun); 761d81ba9d5SMatt Jacob if (tptr == NULL) { 762d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 763d81ba9d5SMatt Jacob return; 764d81ba9d5SMatt Jacob } 765d81ba9d5SMatt Jacob } 766d81ba9d5SMatt Jacob 767d81ba9d5SMatt Jacob if (isp_psema_sig_rqe(isp)) { 768d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 769d81ba9d5SMatt Jacob if (cel->enable) 770d81ba9d5SMatt Jacob destroy_lun_state(isp, tptr); 771d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 772d81ba9d5SMatt Jacob return; 773d81ba9d5SMatt Jacob } 774d81ba9d5SMatt Jacob 775d81ba9d5SMatt Jacob if (cel->enable) { 776d81ba9d5SMatt Jacob u_int32_t seq = isp->isp_osinfo.rollinfo++; 7775d571944SMatt Jacob int c, n, ulun = lun; 7785d571944SMatt Jacob 7795d571944SMatt Jacob cmd = RQSTYPE_ENABLE_LUN; 7805d571944SMatt Jacob c = DFLT_CMND_CNT; 7815d571944SMatt Jacob n = DFLT_INOT_CNT; 7825d571944SMatt Jacob if (IS_FC(isp) && lun != 0) { 7835d571944SMatt Jacob cmd = RQSTYPE_MODIFY_LUN; 7845d571944SMatt Jacob n = 0; 7855d571944SMatt Jacob /* 7865d571944SMatt Jacob * For SCC firmware, we only deal with setting 7875d571944SMatt Jacob * (enabling or modifying) lun 0. 7885d571944SMatt Jacob */ 7895d571944SMatt Jacob ulun = 0; 7905d571944SMatt Jacob } 791d81ba9d5SMatt Jacob rstat = LUN_ERR; 7925d571944SMatt Jacob if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq)) { 793d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 7943c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, "isp_lun_cmd failed"); 795d81ba9d5SMatt Jacob goto out; 796d81ba9d5SMatt Jacob } 797d81ba9d5SMatt Jacob if (isp_cv_wait_timed_rqe(isp, 30 * hz)) { 798d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 7993c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, 8005d571944SMatt Jacob "wait for ENABLE/MODIFY LUN timed out"); 801d81ba9d5SMatt Jacob goto out; 802d81ba9d5SMatt Jacob } 803d81ba9d5SMatt Jacob rstat = isp->isp_osinfo.rstatus; 804d81ba9d5SMatt Jacob if (rstat != LUN_OK) { 805d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 8063c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, 8075d571944SMatt Jacob "ENABLE/MODIFY LUN returned 0x%x", rstat); 808d81ba9d5SMatt Jacob goto out; 809d81ba9d5SMatt Jacob } 810d81ba9d5SMatt Jacob } else { 8115d571944SMatt Jacob int c, n, ulun = lun; 812d81ba9d5SMatt Jacob u_int32_t seq; 813d81ba9d5SMatt Jacob 814d81ba9d5SMatt Jacob rstat = LUN_ERR; 8155d571944SMatt Jacob seq = isp->isp_osinfo.rollinfo++; 8165d571944SMatt Jacob cmd = -RQSTYPE_MODIFY_LUN; 817d81ba9d5SMatt Jacob 8185d571944SMatt Jacob c = DFLT_CMND_CNT; 8195d571944SMatt Jacob n = DFLT_INOT_CNT; 8205d571944SMatt Jacob if (IS_FC(isp) && lun != 0) { 8215d571944SMatt Jacob n = 0; 8225d571944SMatt Jacob /* 8235d571944SMatt Jacob * For SCC firmware, we only deal with setting 8245d571944SMatt Jacob * (enabling or modifying) lun 0. 8255d571944SMatt Jacob */ 8265d571944SMatt Jacob ulun = 0; 8275d571944SMatt Jacob } 8285d571944SMatt Jacob if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq)) { 829d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 8303c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, "isp_lun_cmd failed"); 831d81ba9d5SMatt Jacob goto out; 832d81ba9d5SMatt Jacob } 833d81ba9d5SMatt Jacob if (isp_cv_wait_timed_rqe(isp, 30 * hz)) { 834d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 8353c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, 8363c75bb14SMatt Jacob "wait for MODIFY LUN timed out"); 837d81ba9d5SMatt Jacob goto out; 838d81ba9d5SMatt Jacob } 839d81ba9d5SMatt Jacob rstat = isp->isp_osinfo.rstatus; 840d81ba9d5SMatt Jacob if (rstat != LUN_OK) { 841d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 8423c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, 8433c75bb14SMatt Jacob "MODIFY LUN returned 0x%x", rstat); 844d81ba9d5SMatt Jacob goto out; 845d81ba9d5SMatt Jacob } 8465d571944SMatt Jacob if (IS_FC(isp) && lun) { 8475d571944SMatt Jacob goto out; 8485d571944SMatt Jacob } 8495d571944SMatt Jacob 850d81ba9d5SMatt Jacob seq = isp->isp_osinfo.rollinfo++; 851d81ba9d5SMatt Jacob 8525d571944SMatt Jacob rstat = LUN_ERR; 8535d571944SMatt Jacob cmd = -RQSTYPE_ENABLE_LUN; 8545d571944SMatt Jacob if (isp_lun_cmd(isp, cmd, bus, tgt, lun, 0, 0, seq)) { 855d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 8563c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, "isp_lun_cmd failed"); 857d81ba9d5SMatt Jacob goto out; 858d81ba9d5SMatt Jacob } 859d81ba9d5SMatt Jacob if (isp_cv_wait_timed_rqe(isp, 30 * hz)) { 860d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 8613c75bb14SMatt Jacob isp_prt(isp, ISP_LOGERR, 8625d571944SMatt Jacob "wait for DISABLE LUN timed out"); 863d81ba9d5SMatt Jacob goto out; 864d81ba9d5SMatt Jacob } 865d81ba9d5SMatt Jacob rstat = isp->isp_osinfo.rstatus; 866d81ba9d5SMatt Jacob if (rstat != LUN_OK) { 867d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 8683c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 8695d571944SMatt Jacob "DISABLE LUN returned 0x%x", rstat); 870d81ba9d5SMatt Jacob goto out; 871d81ba9d5SMatt Jacob } 872126ec864SMatt Jacob if (are_any_luns_enabled(isp, bus) == 0) { 873126ec864SMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 874126ec864SMatt Jacob if (av) { 875126ec864SMatt Jacob isp_prt(isp, ISP_LOGWARN, 876126ec864SMatt Jacob "disable target mode on channel %d failed", 877126ec864SMatt Jacob bus); 878126ec864SMatt Jacob goto out; 879d81ba9d5SMatt Jacob } 880126ec864SMatt Jacob isp->isp_osinfo.tmflags &= ~(1 << bus); 881126ec864SMatt Jacob xpt_print_path(ccb->ccb_h.path); 882126ec864SMatt Jacob isp_prt(isp, ISP_LOGINFO, 883126ec864SMatt Jacob "Target Mode disabled on channel %d", bus); 884126ec864SMatt Jacob } 885126ec864SMatt Jacob } 886126ec864SMatt Jacob 887d81ba9d5SMatt Jacob out: 888d81ba9d5SMatt Jacob isp_vsema_rqe(isp); 889d81ba9d5SMatt Jacob 890d81ba9d5SMatt Jacob if (rstat != LUN_OK) { 891d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 8923c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 8933c75bb14SMatt Jacob "lun %sable failed", (cel->enable) ? "en" : "dis"); 894d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 895d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 896d81ba9d5SMatt Jacob if (cel->enable) 897d81ba9d5SMatt Jacob destroy_lun_state(isp, tptr); 898d81ba9d5SMatt Jacob } else { 899d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 900a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGINFO, lfmt, 901a1bc34c6SMatt Jacob (cel->enable) ? "en" : "dis", bus); 902d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 903d81ba9d5SMatt Jacob if (cel->enable == 0) { 904d81ba9d5SMatt Jacob destroy_lun_state(isp, tptr); 905d81ba9d5SMatt Jacob } 906d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 907d81ba9d5SMatt Jacob } 908d81ba9d5SMatt Jacob } 909d81ba9d5SMatt Jacob 910d81ba9d5SMatt Jacob static cam_status 911d81ba9d5SMatt Jacob isp_abort_tgt_ccb(struct ispsoftc *isp, union ccb *ccb) 912d81ba9d5SMatt Jacob { 913d81ba9d5SMatt Jacob tstate_t *tptr; 914d81ba9d5SMatt Jacob struct ccb_hdr_slist *lp; 915d81ba9d5SMatt Jacob struct ccb_hdr *curelm; 916d81ba9d5SMatt Jacob int found; 917d81ba9d5SMatt Jacob union ccb *accb = ccb->cab.abort_ccb; 918d81ba9d5SMatt Jacob 919d81ba9d5SMatt Jacob if (accb->ccb_h.target_id != CAM_TARGET_WILDCARD) { 920d81ba9d5SMatt Jacob if (IS_FC(isp) && (accb->ccb_h.target_id != 921d81ba9d5SMatt Jacob ((fcparam *) isp->isp_param)->isp_loopid)) { 922d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 923d81ba9d5SMatt Jacob } else if (IS_SCSI(isp) && (accb->ccb_h.target_id != 924d81ba9d5SMatt Jacob ((sdparam *) isp->isp_param)->isp_initiator_id)) { 925d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 926d81ba9d5SMatt Jacob } 927d81ba9d5SMatt Jacob } 928a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, XS_CHANNEL(ccb), accb->ccb_h.target_lun); 929d81ba9d5SMatt Jacob if (tptr == NULL) { 930d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 931d81ba9d5SMatt Jacob } 932d81ba9d5SMatt Jacob if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 933d81ba9d5SMatt Jacob lp = &tptr->atios; 934d81ba9d5SMatt Jacob } else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY) { 935d81ba9d5SMatt Jacob lp = &tptr->inots; 936d81ba9d5SMatt Jacob } else { 937d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 938d81ba9d5SMatt Jacob return (CAM_UA_ABORT); 939d81ba9d5SMatt Jacob } 940d81ba9d5SMatt Jacob curelm = SLIST_FIRST(lp); 941d81ba9d5SMatt Jacob found = 0; 942d81ba9d5SMatt Jacob if (curelm == &accb->ccb_h) { 943d81ba9d5SMatt Jacob found = 1; 944d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(lp, sim_links.sle); 945d81ba9d5SMatt Jacob } else { 946d81ba9d5SMatt Jacob while(curelm != NULL) { 947d81ba9d5SMatt Jacob struct ccb_hdr *nextelm; 948d81ba9d5SMatt Jacob 949d81ba9d5SMatt Jacob nextelm = SLIST_NEXT(curelm, sim_links.sle); 950d81ba9d5SMatt Jacob if (nextelm == &accb->ccb_h) { 951d81ba9d5SMatt Jacob found = 1; 952d81ba9d5SMatt Jacob SLIST_NEXT(curelm, sim_links.sle) = 953d81ba9d5SMatt Jacob SLIST_NEXT(nextelm, sim_links.sle); 954d81ba9d5SMatt Jacob break; 955d81ba9d5SMatt Jacob } 956d81ba9d5SMatt Jacob curelm = nextelm; 957d81ba9d5SMatt Jacob } 958d81ba9d5SMatt Jacob } 959d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 960d81ba9d5SMatt Jacob if (found) { 961d81ba9d5SMatt Jacob accb->ccb_h.status = CAM_REQ_ABORTED; 962d81ba9d5SMatt Jacob return (CAM_REQ_CMP); 963d81ba9d5SMatt Jacob } 964d81ba9d5SMatt Jacob return(CAM_PATH_INVALID); 965d81ba9d5SMatt Jacob } 966d81ba9d5SMatt Jacob 967d81ba9d5SMatt Jacob static cam_status 968d81ba9d5SMatt Jacob isp_target_start_ctio(struct ispsoftc *isp, union ccb *ccb) 969d81ba9d5SMatt Jacob { 970d81ba9d5SMatt Jacob void *qe; 97100a8e174SMatt Jacob struct ccb_scsiio *cso = &ccb->csio; 9725f5aafe1SMatt Jacob u_int16_t *hp, save_handle; 973d81ba9d5SMatt Jacob u_int16_t iptr, optr; 974d81ba9d5SMatt Jacob 975f48ce188SMatt Jacob 976d81ba9d5SMatt Jacob if (isp_getrqentry(isp, &iptr, &optr, &qe)) { 97792a1e549SMatt Jacob xpt_print_path(ccb->ccb_h.path); 97892a1e549SMatt Jacob printf("Request Queue Overflow in isp_target_start_ctio\n"); 979d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 980d81ba9d5SMatt Jacob } 98192a1e549SMatt Jacob bzero(qe, QENTRY_LEN); 982d81ba9d5SMatt Jacob 983d81ba9d5SMatt Jacob /* 984d81ba9d5SMatt Jacob * We're either moving data or completing a command here. 985d81ba9d5SMatt Jacob */ 986d81ba9d5SMatt Jacob 987d81ba9d5SMatt Jacob if (IS_FC(isp)) { 988f48ce188SMatt Jacob struct ccb_accept_tio *atiop; 989d81ba9d5SMatt Jacob ct2_entry_t *cto = qe; 99000a8e174SMatt Jacob 991d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; 992d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_count = 1; 99300a8e174SMatt Jacob cto->ct_iid = cso->init_id; 9942ad50ca5SMatt Jacob if (isp->isp_maxluns <= 16) { 995d81ba9d5SMatt Jacob cto->ct_lun = ccb->ccb_h.target_lun; 9962ad50ca5SMatt Jacob } 997f48ce188SMatt Jacob /* 998f48ce188SMatt Jacob * Start with a residual based on what the original datalength 999f48ce188SMatt Jacob * was supposed to be. Basically, we ignore what CAM has set 1000f48ce188SMatt Jacob * for residuals. The data transfer routines will knock off 1001f48ce188SMatt Jacob * the residual for each byte actually moved- and also will 1002f48ce188SMatt Jacob * be responsible for setting the underrun flag. 1003f48ce188SMatt Jacob */ 1004f48ce188SMatt Jacob /* HACK! HACK! */ 1005f48ce188SMatt Jacob if ((atiop = ccb->ccb_h.periph_priv.entries[1].ptr) != NULL) { 1006f48ce188SMatt Jacob cto->ct_resid = atiop->ccb_h.spriv_field0; 1007f48ce188SMatt Jacob } 1008f48ce188SMatt Jacob 100900a8e174SMatt Jacob cto->ct_rxid = cso->tag_id; 101000a8e174SMatt Jacob if (cso->dxfer_len == 0) { 101100a8e174SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA; 1012f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 101300a8e174SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 1014f48ce188SMatt Jacob cto->rsp.m1.ct_scsi_status = cso->scsi_status; 1015f48ce188SMatt Jacob } 101600a8e174SMatt Jacob if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) { 101700a8e174SMatt Jacob int m = min(cso->sense_len, MAXRESPLEN); 101800a8e174SMatt Jacob bcopy(&cso->sense_data, cto->rsp.m1.ct_resp, m); 101900a8e174SMatt Jacob cto->rsp.m1.ct_senselen = m; 102000a8e174SMatt Jacob cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID; 102100a8e174SMatt Jacob } 102200a8e174SMatt Jacob } else { 102300a8e174SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE0; 102400a8e174SMatt Jacob if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 102500a8e174SMatt Jacob cto->ct_flags |= CT2_DATA_IN; 102600a8e174SMatt Jacob } else { 102700a8e174SMatt Jacob cto->ct_flags |= CT2_DATA_OUT; 1028d81ba9d5SMatt Jacob } 1029d81ba9d5SMatt Jacob if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 1030d81ba9d5SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 103100a8e174SMatt Jacob cto->rsp.m0.ct_scsi_status = cso->scsi_status; 1032d81ba9d5SMatt Jacob } 1033f48ce188SMatt Jacob /* 1034f48ce188SMatt Jacob * If we're sending data and status back together, 1035f48ce188SMatt Jacob * we can't also send back sense data as well. 1036f48ce188SMatt Jacob */ 103700a8e174SMatt Jacob ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 103800a8e174SMatt Jacob } 1039290dc24bSMatt Jacob if (cto->ct_flags & CT2_SENDSTATUS) { 1040a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 10415f5aafe1SMatt Jacob "CTIO2[%x] SCSI STATUS 0x%x datalength %u", 1042b09b0095SMatt Jacob cto->ct_rxid, cso->scsi_status, cto->ct_resid); 1043d81ba9d5SMatt Jacob } 1044a1bc34c6SMatt Jacob if (cto->ct_flags & CT2_SENDSTATUS) 1045a1bc34c6SMatt Jacob cto->ct_flags |= CT2_CCINCR; 1046a1bc34c6SMatt Jacob cto->ct_timeout = 10; 10475f5aafe1SMatt Jacob hp = &cto->ct_syshandle; 1048d81ba9d5SMatt Jacob } else { 1049d81ba9d5SMatt Jacob ct_entry_t *cto = qe; 105000a8e174SMatt Jacob 1051d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 1052d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_count = 1; 105300a8e174SMatt Jacob cto->ct_iid = cso->init_id; 1054a1bc34c6SMatt Jacob cto->ct_iid |= XS_CHANNEL(ccb) << 7; 1055d81ba9d5SMatt Jacob cto->ct_tgt = ccb->ccb_h.target_id; 1056d81ba9d5SMatt Jacob cto->ct_lun = ccb->ccb_h.target_lun; 1057a1bc34c6SMatt Jacob cto->ct_fwhandle = AT_GET_HANDLE(cso->tag_id); 1058a1bc34c6SMatt Jacob if (AT_HAS_TAG(cso->tag_id)) { 1059a1bc34c6SMatt Jacob cto->ct_tag_val = (u_int8_t) AT_GET_TAG(cso->tag_id); 1060f48ce188SMatt Jacob cto->ct_flags |= CT_TQAE; 1061f48ce188SMatt Jacob } 1062f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) { 1063f48ce188SMatt Jacob cto->ct_flags |= CT_NODISC; 1064f48ce188SMatt Jacob } 1065f48ce188SMatt Jacob if (cso->dxfer_len == 0) { 1066d81ba9d5SMatt Jacob cto->ct_flags |= CT_NO_DATA; 106700a8e174SMatt Jacob } else if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 106800a8e174SMatt Jacob cto->ct_flags |= CT_DATA_IN; 106900a8e174SMatt Jacob } else { 107000a8e174SMatt Jacob cto->ct_flags |= CT_DATA_OUT; 1071d81ba9d5SMatt Jacob } 1072f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 1073d81ba9d5SMatt Jacob cto->ct_flags |= CT_SENDSTATUS; 107400a8e174SMatt Jacob cto->ct_scsi_status = cso->scsi_status; 107500a8e174SMatt Jacob cto->ct_resid = cso->resid; 1076d81ba9d5SMatt Jacob } 1077290dc24bSMatt Jacob if (cto->ct_flags & CT_SENDSTATUS) { 1078a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 1079a1bc34c6SMatt Jacob "CTIO[%x] SCSI STATUS 0x%x resid %d tag_id %x", 1080a1bc34c6SMatt Jacob cto->ct_fwhandle, cso->scsi_status, cso->resid, 1081a1bc34c6SMatt Jacob cso->tag_id); 108292a1e549SMatt Jacob } 1083a1bc34c6SMatt Jacob cto->ct_timeout = 10; 10845f5aafe1SMatt Jacob hp = &cto->ct_syshandle; 108500a8e174SMatt Jacob ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 1086a1bc34c6SMatt Jacob if (cto->ct_flags & CT_SENDSTATUS) 1087a1bc34c6SMatt Jacob cto->ct_flags |= CT_CCINCR; 1088d81ba9d5SMatt Jacob } 1089d81ba9d5SMatt Jacob 1090b09b0095SMatt Jacob if (isp_save_xs(isp, (XS_T *)ccb, hp)) { 109192a1e549SMatt Jacob xpt_print_path(ccb->ccb_h.path); 109292a1e549SMatt Jacob printf("No XFLIST pointers for isp_target_start_ctio\n"); 1093d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 1094d81ba9d5SMatt Jacob } 1095d81ba9d5SMatt Jacob 1096d81ba9d5SMatt Jacob 1097d81ba9d5SMatt Jacob /* 1098d81ba9d5SMatt Jacob * Call the dma setup routines for this entry (and any subsequent 1099d81ba9d5SMatt Jacob * CTIOs) if there's data to move, and then tell the f/w it's got 1100b09b0095SMatt Jacob * new things to play with. As with isp_start's usage of DMA setup, 1101d81ba9d5SMatt Jacob * any swizzling is done in the machine dependent layer. Because 1102d81ba9d5SMatt Jacob * of this, we put the request onto the queue area first in native 1103d81ba9d5SMatt Jacob * format. 1104d81ba9d5SMatt Jacob */ 1105d81ba9d5SMatt Jacob 1106d81ba9d5SMatt Jacob save_handle = *hp; 1107a1bc34c6SMatt Jacob 110800a8e174SMatt Jacob switch (ISP_DMASETUP(isp, cso, qe, &iptr, optr)) { 1109d81ba9d5SMatt Jacob case CMD_QUEUED: 1110d81ba9d5SMatt Jacob ISP_ADD_REQUEST(isp, iptr); 1111d81ba9d5SMatt Jacob return (CAM_REQ_INPROG); 1112d81ba9d5SMatt Jacob 1113d81ba9d5SMatt Jacob case CMD_EAGAIN: 1114d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 1115d81ba9d5SMatt Jacob isp_destroy_handle(isp, save_handle); 1116d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 1117d81ba9d5SMatt Jacob 1118d81ba9d5SMatt Jacob default: 1119d81ba9d5SMatt Jacob isp_destroy_handle(isp, save_handle); 1120b85389e1SMatt Jacob return (XS_ERR(ccb)); 1121d81ba9d5SMatt Jacob } 1122d81ba9d5SMatt Jacob } 1123d81ba9d5SMatt Jacob 1124a1bc34c6SMatt Jacob static void 1125a1bc34c6SMatt Jacob isp_refire_putback_atio(void *arg) 1126f48ce188SMatt Jacob { 1127a1bc34c6SMatt Jacob int s = splcam(); 1128a1bc34c6SMatt Jacob isp_target_putback_atio(arg); 1129a1bc34c6SMatt Jacob splx(s); 1130a1bc34c6SMatt Jacob } 1131a1bc34c6SMatt Jacob 1132a1bc34c6SMatt Jacob static void 1133a1bc34c6SMatt Jacob isp_target_putback_atio(union ccb *ccb) 1134a1bc34c6SMatt Jacob { 1135a1bc34c6SMatt Jacob struct ispsoftc *isp; 1136a1bc34c6SMatt Jacob struct ccb_scsiio *cso; 1137f48ce188SMatt Jacob u_int16_t iptr, optr; 1138a1bc34c6SMatt Jacob void *qe; 1139a1bc34c6SMatt Jacob 1140a1bc34c6SMatt Jacob isp = XS_ISP(ccb); 1141f48ce188SMatt Jacob 1142f48ce188SMatt Jacob if (isp_getrqentry(isp, &iptr, &optr, &qe)) { 1143a1bc34c6SMatt Jacob (void) timeout(isp_refire_putback_atio, ccb, 10); 1144a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGWARN, 1145a1bc34c6SMatt Jacob "isp_target_putback_atio: Request Queue Overflow"); 1146a1bc34c6SMatt Jacob return; 1147f48ce188SMatt Jacob } 1148f48ce188SMatt Jacob bzero(qe, QENTRY_LEN); 1149a1bc34c6SMatt Jacob cso = &ccb->csio; 1150f48ce188SMatt Jacob if (IS_FC(isp)) { 1151f48ce188SMatt Jacob at2_entry_t *at = qe; 1152f48ce188SMatt Jacob at->at_header.rqs_entry_type = RQSTYPE_ATIO2; 1153f48ce188SMatt Jacob at->at_header.rqs_entry_count = 1; 1154f48ce188SMatt Jacob if (isp->isp_maxluns > 16) { 1155a1bc34c6SMatt Jacob at->at_scclun = (uint16_t) ccb->ccb_h.target_lun; 1156f48ce188SMatt Jacob } else { 1157a1bc34c6SMatt Jacob at->at_lun = (uint8_t) ccb->ccb_h.target_lun; 1158f48ce188SMatt Jacob } 1159f48ce188SMatt Jacob at->at_status = CT_OK; 1160a1bc34c6SMatt Jacob at->at_rxid = cso->tag_id; 1161f48ce188SMatt Jacob ISP_SWIZ_ATIO2(isp, qe, qe); 1162f48ce188SMatt Jacob } else { 1163f48ce188SMatt Jacob at_entry_t *at = qe; 1164f48ce188SMatt Jacob at->at_header.rqs_entry_type = RQSTYPE_ATIO; 1165f48ce188SMatt Jacob at->at_header.rqs_entry_count = 1; 1166a1bc34c6SMatt Jacob at->at_iid = cso->init_id; 1167a1bc34c6SMatt Jacob at->at_iid |= XS_CHANNEL(ccb) << 7; 1168a1bc34c6SMatt Jacob at->at_tgt = cso->ccb_h.target_id; 1169a1bc34c6SMatt Jacob at->at_lun = cso->ccb_h.target_lun; 1170f48ce188SMatt Jacob at->at_status = CT_OK; 1171a1bc34c6SMatt Jacob at->at_tag_val = AT_GET_TAG(cso->tag_id); 1172a1bc34c6SMatt Jacob at->at_handle = AT_GET_HANDLE(cso->tag_id); 1173f48ce188SMatt Jacob ISP_SWIZ_ATIO(isp, qe, qe); 1174f48ce188SMatt Jacob } 1175f48ce188SMatt Jacob ISP_TDQE(isp, "isp_target_putback_atio", (int) optr, qe); 1176f48ce188SMatt Jacob ISP_ADD_REQUEST(isp, iptr); 1177a1bc34c6SMatt Jacob isp_complete_ctio(ccb); 1178f48ce188SMatt Jacob } 1179f48ce188SMatt Jacob 1180f48ce188SMatt Jacob static void 1181a1bc34c6SMatt Jacob isp_complete_ctio(union ccb *ccb) 1182f48ce188SMatt Jacob { 1183a1bc34c6SMatt Jacob struct ispsoftc *isp = XS_ISP(ccb); 1184a1bc34c6SMatt Jacob if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { 1185a1bc34c6SMatt Jacob ccb->ccb_h.status |= CAM_REQ_CMP; 1186f48ce188SMatt Jacob } 1187a1bc34c6SMatt Jacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1188a1bc34c6SMatt Jacob if (isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE) { 1189a1bc34c6SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_RESOURCE; 1190a1bc34c6SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 1191a1bc34c6SMatt Jacob if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 1192a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "ctio->relsimq"); 1193a1bc34c6SMatt Jacob ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 1194a1bc34c6SMatt Jacob } else { 1195a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGWARN, "ctio->devqfrozen"); 1196a1bc34c6SMatt Jacob } 1197a1bc34c6SMatt Jacob } else { 1198a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGWARN, 1199a1bc34c6SMatt Jacob "ctio->simqfrozen(%x)", isp->isp_osinfo.simqfrozen); 1200a1bc34c6SMatt Jacob } 1201a1bc34c6SMatt Jacob } 1202a1bc34c6SMatt Jacob xpt_done(ccb); 1203f48ce188SMatt Jacob } 1204f48ce188SMatt Jacob 1205d81ba9d5SMatt Jacob /* 1206d81ba9d5SMatt Jacob * Handle ATIO stuff that the generic code can't. 1207d81ba9d5SMatt Jacob * This means handling CDBs. 1208d81ba9d5SMatt Jacob */ 1209d81ba9d5SMatt Jacob 1210d81ba9d5SMatt Jacob static int 1211d81ba9d5SMatt Jacob isp_handle_platform_atio(struct ispsoftc *isp, at_entry_t *aep) 1212d81ba9d5SMatt Jacob { 1213d81ba9d5SMatt Jacob tstate_t *tptr; 1214a1bc34c6SMatt Jacob int status, bus; 1215d81ba9d5SMatt Jacob struct ccb_accept_tio *atiop; 1216d81ba9d5SMatt Jacob 1217d81ba9d5SMatt Jacob /* 1218d81ba9d5SMatt Jacob * The firmware status (except for the QLTM_SVALID bit) 1219d81ba9d5SMatt Jacob * indicates why this ATIO was sent to us. 1220d81ba9d5SMatt Jacob * 1221d81ba9d5SMatt Jacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 1222d81ba9d5SMatt Jacob * 1223d81ba9d5SMatt Jacob * If the DISCONNECTS DISABLED bit is set in the flags field, 12245d571944SMatt Jacob * we're still connected on the SCSI bus. 1225d81ba9d5SMatt Jacob */ 1226d81ba9d5SMatt Jacob status = aep->at_status; 1227d81ba9d5SMatt Jacob if ((status & ~QLTM_SVALID) == AT_PHASE_ERROR) { 1228d81ba9d5SMatt Jacob /* 1229d81ba9d5SMatt Jacob * Bus Phase Sequence error. We should have sense data 1230d81ba9d5SMatt Jacob * suggested by the f/w. I'm not sure quite yet what 1231d81ba9d5SMatt Jacob * to do about this for CAM. 1232d81ba9d5SMatt Jacob */ 12333c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, "PHASE ERROR"); 1234d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1235d81ba9d5SMatt Jacob return (0); 1236d81ba9d5SMatt Jacob } 1237d81ba9d5SMatt Jacob if ((status & ~QLTM_SVALID) != AT_CDB) { 12385d571944SMatt Jacob isp_prt(isp, ISP_LOGWARN, "bad atio (0x%x) leaked to platform", 12393c75bb14SMatt Jacob status); 1240d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1241d81ba9d5SMatt Jacob return (0); 1242d81ba9d5SMatt Jacob } 1243d81ba9d5SMatt Jacob 12445d571944SMatt Jacob bus = GET_BUS_VAL(aep->at_iid); 1245a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, aep->at_lun); 1246d81ba9d5SMatt Jacob if (tptr == NULL) { 1247a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD); 1248d81ba9d5SMatt Jacob } 1249d81ba9d5SMatt Jacob 1250d81ba9d5SMatt Jacob if (tptr == NULL) { 1251d81ba9d5SMatt Jacob /* 1252d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1253d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1254d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a BUSY status 1255d81ba9d5SMatt Jacob * instead. This works out okay because the only 1256d81ba9d5SMatt Jacob * time we should, in fact, get this, is in the 1257d81ba9d5SMatt Jacob * case that somebody configured us without the 1258d81ba9d5SMatt Jacob * blackhole driver, so they get what they deserve. 1259d81ba9d5SMatt Jacob */ 1260d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1261d81ba9d5SMatt Jacob return (0); 1262d81ba9d5SMatt Jacob } 1263d81ba9d5SMatt Jacob 1264d81ba9d5SMatt Jacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 1265d81ba9d5SMatt Jacob if (atiop == NULL) { 1266d81ba9d5SMatt Jacob /* 1267d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1268d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1269d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a QUEUE FULL status 1270d81ba9d5SMatt Jacob * instead. This works out okay because the only time we 1271d81ba9d5SMatt Jacob * should, in fact, get this, is in the case that we've 1272d81ba9d5SMatt Jacob * run out of ATIOS. 1273d81ba9d5SMatt Jacob */ 1274d81ba9d5SMatt Jacob xpt_print_path(tptr->owner); 12753c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 1276a1bc34c6SMatt Jacob "no ATIOS for lun %d from initiator %d on channel %d", 12775d571944SMatt Jacob aep->at_lun, GET_IID_VAL(aep->at_iid), bus); 1278d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1279d81ba9d5SMatt Jacob if (aep->at_flags & AT_TQAE) 1280d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); 1281d81ba9d5SMatt Jacob else 1282d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1283d81ba9d5SMatt Jacob return (0); 1284d81ba9d5SMatt Jacob } 1285d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 1286a1bc34c6SMatt Jacob if (tptr == &isp->isp_osinfo.tsdflt[bus]) { 1287d81ba9d5SMatt Jacob atiop->ccb_h.target_id = aep->at_tgt; 1288d81ba9d5SMatt Jacob atiop->ccb_h.target_lun = aep->at_lun; 1289d81ba9d5SMatt Jacob } 1290d81ba9d5SMatt Jacob if (aep->at_flags & AT_NODISC) { 1291f48ce188SMatt Jacob atiop->ccb_h.flags = CAM_DIS_DISCONNECT; 1292f48ce188SMatt Jacob } else { 1293f48ce188SMatt Jacob atiop->ccb_h.flags = 0; 1294d81ba9d5SMatt Jacob } 1295d81ba9d5SMatt Jacob 1296f48ce188SMatt Jacob if (status & QLTM_SVALID) { 1297f48ce188SMatt Jacob size_t amt = imin(QLTM_SENSELEN, sizeof (atiop->sense_data)); 1298f48ce188SMatt Jacob atiop->sense_len = amt; 1299f48ce188SMatt Jacob MEMCPY(&atiop->sense_data, aep->at_sense, amt); 1300f48ce188SMatt Jacob } else { 1301f48ce188SMatt Jacob atiop->sense_len = 0; 1302f48ce188SMatt Jacob } 1303d81ba9d5SMatt Jacob 13045d571944SMatt Jacob atiop->init_id = GET_IID_VAL(aep->at_iid); 1305d81ba9d5SMatt Jacob atiop->cdb_len = aep->at_cdblen; 1306d81ba9d5SMatt Jacob MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen); 1307d81ba9d5SMatt Jacob atiop->ccb_h.status = CAM_CDB_RECVD; 1308a1bc34c6SMatt Jacob /* 1309a1bc34c6SMatt Jacob * Construct a tag 'id' based upon tag value (which may be 0..255) 1310a1bc34c6SMatt Jacob * and the handle (which we have to preserve). 1311a1bc34c6SMatt Jacob */ 1312a1bc34c6SMatt Jacob AT_MAKE_TAGID(atiop->tag_id, aep); 1313a1bc34c6SMatt Jacob if (aep->at_flags & AT_TQAE) { 1314a1bc34c6SMatt Jacob atiop->tag_action = aep->at_tag_type; 1315d81ba9d5SMatt Jacob atiop->ccb_h.status |= CAM_TAG_ACTION_VALID; 1316d81ba9d5SMatt Jacob } 1317d81ba9d5SMatt Jacob xpt_done((union ccb*)atiop); 1318a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 13195d571944SMatt Jacob "ATIO[%x] CDB=0x%x bus %d iid%d->lun%d tag 0x%x ttype 0x%x %s", 13205d571944SMatt Jacob aep->at_handle, aep->at_cdb[0] & 0xff, GET_BUS_VAL(aep->at_iid), 13215d571944SMatt Jacob GET_IID_VAL(aep->at_iid), aep->at_lun, aep->at_tag_val & 0xff, 13225d571944SMatt Jacob aep->at_tag_type, (aep->at_flags & AT_NODISC)? 13235d571944SMatt Jacob "nondisc" : "disconnecting"); 1324d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1325d81ba9d5SMatt Jacob return (0); 1326d81ba9d5SMatt Jacob } 1327d81ba9d5SMatt Jacob 1328d81ba9d5SMatt Jacob static int 1329d81ba9d5SMatt Jacob isp_handle_platform_atio2(struct ispsoftc *isp, at2_entry_t *aep) 1330d81ba9d5SMatt Jacob { 133192a1e549SMatt Jacob lun_id_t lun; 1332d81ba9d5SMatt Jacob tstate_t *tptr; 1333d81ba9d5SMatt Jacob struct ccb_accept_tio *atiop; 1334d81ba9d5SMatt Jacob 1335d81ba9d5SMatt Jacob /* 1336d81ba9d5SMatt Jacob * The firmware status (except for the QLTM_SVALID bit) 1337d81ba9d5SMatt Jacob * indicates why this ATIO was sent to us. 1338d81ba9d5SMatt Jacob * 1339d81ba9d5SMatt Jacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 1340d81ba9d5SMatt Jacob */ 1341d81ba9d5SMatt Jacob if ((aep->at_status & ~QLTM_SVALID) != AT_CDB) { 13423c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 13433c75bb14SMatt Jacob "bogus atio (0x%x) leaked to platform", aep->at_status); 1344d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1345d81ba9d5SMatt Jacob return (0); 1346d81ba9d5SMatt Jacob } 1347d81ba9d5SMatt Jacob 13482ad50ca5SMatt Jacob if (isp->isp_maxluns > 16) { 134992a1e549SMatt Jacob lun = aep->at_scclun; 13502ad50ca5SMatt Jacob } else { 135192a1e549SMatt Jacob lun = aep->at_lun; 13522ad50ca5SMatt Jacob } 1353a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, 0, lun); 1354d81ba9d5SMatt Jacob if (tptr == NULL) { 1355a1bc34c6SMatt Jacob tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD); 1356d81ba9d5SMatt Jacob } 1357d81ba9d5SMatt Jacob 1358d81ba9d5SMatt Jacob if (tptr == NULL) { 135952df5dfdSMatt Jacob /* 136052df5dfdSMatt Jacob * What we'd like to know is whether or not we have a listener 136152df5dfdSMatt Jacob * upstream that really hasn't configured yet. If we do, then 136252df5dfdSMatt Jacob * we can give a more sensible reply here. If not, then we can 136352df5dfdSMatt Jacob * reject this out of hand. 136452df5dfdSMatt Jacob * 136552df5dfdSMatt Jacob * Choices for what to send were 136652df5dfdSMatt Jacob * 136752df5dfdSMatt Jacob * Not Ready, Unit Not Self-Configured Yet 136852df5dfdSMatt Jacob * (0x2,0x3e,0x00) 136952df5dfdSMatt Jacob * 137052df5dfdSMatt Jacob * for the former and 137152df5dfdSMatt Jacob * 137252df5dfdSMatt Jacob * Illegal Request, Logical Unit Not Supported 137352df5dfdSMatt Jacob * (0x5,0x25,0x00) 137452df5dfdSMatt Jacob * 137552df5dfdSMatt Jacob * for the latter. 137652df5dfdSMatt Jacob * 137752df5dfdSMatt Jacob * We used to decide whether there was at least one listener 137852df5dfdSMatt Jacob * based upon whether the black hole driver was configured. 137952df5dfdSMatt Jacob * However, recent config(8) changes have made this hard to do 138052df5dfdSMatt Jacob * at this time. 138152df5dfdSMatt Jacob * 138252df5dfdSMatt Jacob */ 1383d81ba9d5SMatt Jacob u_int32_t ccode = SCSI_STATUS_BUSY; 1384d81ba9d5SMatt Jacob 1385d81ba9d5SMatt Jacob /* 1386d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1387d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1388d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a BUSY status 1389d81ba9d5SMatt Jacob * instead. This works out okay because the only 1390d81ba9d5SMatt Jacob * time we should, in fact, get this, is in the 1391d81ba9d5SMatt Jacob * case that somebody configured us without the 1392d81ba9d5SMatt Jacob * blackhole driver, so they get what they deserve. 1393d81ba9d5SMatt Jacob */ 1394d81ba9d5SMatt Jacob isp_endcmd(isp, aep, ccode, 0); 1395d81ba9d5SMatt Jacob return (0); 1396d81ba9d5SMatt Jacob } 1397d81ba9d5SMatt Jacob 1398d81ba9d5SMatt Jacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 1399d81ba9d5SMatt Jacob if (atiop == NULL) { 1400d81ba9d5SMatt Jacob /* 1401d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1402d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1403d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a QUEUE FULL status 1404d81ba9d5SMatt Jacob * instead. This works out okay because the only time we 1405d81ba9d5SMatt Jacob * should, in fact, get this, is in the case that we've 1406d81ba9d5SMatt Jacob * run out of ATIOS. 1407d81ba9d5SMatt Jacob */ 1408d81ba9d5SMatt Jacob xpt_print_path(tptr->owner); 14093c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 14103c75bb14SMatt Jacob "no ATIOS for lun %d from initiator %d", lun, aep->at_iid); 1411d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1412d81ba9d5SMatt Jacob if (aep->at_flags & AT_TQAE) 1413d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); 1414d81ba9d5SMatt Jacob else 1415d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1416d81ba9d5SMatt Jacob return (0); 1417d81ba9d5SMatt Jacob } 1418d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 1419f48ce188SMatt Jacob 1420a1bc34c6SMatt Jacob if (tptr == &isp->isp_osinfo.tsdflt[0]) { 1421d81ba9d5SMatt Jacob atiop->ccb_h.target_id = 1422d81ba9d5SMatt Jacob ((fcparam *)isp->isp_param)->isp_loopid; 142392a1e549SMatt Jacob atiop->ccb_h.target_lun = lun; 1424d81ba9d5SMatt Jacob } 1425b0a3ba7eSMatt Jacob /* 1426b0a3ba7eSMatt Jacob * We don't get 'suggested' sense data as we do with SCSI cards. 1427b0a3ba7eSMatt Jacob */ 1428f48ce188SMatt Jacob atiop->sense_len = 0; 1429f48ce188SMatt Jacob 1430d81ba9d5SMatt Jacob atiop->init_id = aep->at_iid; 1431d81ba9d5SMatt Jacob atiop->cdb_len = ATIO2_CDBLEN; 1432d81ba9d5SMatt Jacob MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, ATIO2_CDBLEN); 1433d81ba9d5SMatt Jacob atiop->ccb_h.status = CAM_CDB_RECVD; 1434d81ba9d5SMatt Jacob atiop->tag_id = aep->at_rxid; 1435d81ba9d5SMatt Jacob switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) { 1436d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_SIMPLEQ: 1437d81ba9d5SMatt Jacob atiop->tag_action = MSG_SIMPLE_Q_TAG; 1438d81ba9d5SMatt Jacob break; 1439d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_HEADOFQ: 1440d81ba9d5SMatt Jacob atiop->tag_action = MSG_HEAD_OF_Q_TAG; 1441d81ba9d5SMatt Jacob break; 1442d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_ORDERED: 1443d81ba9d5SMatt Jacob atiop->tag_action = MSG_ORDERED_Q_TAG; 1444d81ba9d5SMatt Jacob break; 1445d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_ACAQ: /* ?? */ 1446d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_UNTAGGED: 1447d81ba9d5SMatt Jacob default: 1448d81ba9d5SMatt Jacob atiop->tag_action = 0; 1449d81ba9d5SMatt Jacob break; 1450d81ba9d5SMatt Jacob } 1451d81ba9d5SMatt Jacob if (atiop->tag_action != 0) { 1452d81ba9d5SMatt Jacob atiop->ccb_h.status |= CAM_TAG_ACTION_VALID; 1453d81ba9d5SMatt Jacob } 1454f48ce188SMatt Jacob 1455f48ce188SMatt Jacob /* 1456f48ce188SMatt Jacob * Preserve overall command datalength in private field. 1457f48ce188SMatt Jacob */ 1458f48ce188SMatt Jacob atiop->ccb_h.spriv_field0 = aep->at_datalen; 1459f48ce188SMatt Jacob 1460d81ba9d5SMatt Jacob xpt_done((union ccb*)atiop); 1461a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 14625f5aafe1SMatt Jacob "ATIO2[%x] CDB=0x%x iid%d->lun%d tattr 0x%x datalen %u", 14635f5aafe1SMatt Jacob aep->at_rxid, aep->at_cdb[0] & 0xff, aep->at_iid, 1464b09b0095SMatt Jacob lun, aep->at_taskflags, aep->at_datalen); 1465d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1466d81ba9d5SMatt Jacob return (0); 1467d81ba9d5SMatt Jacob } 1468d81ba9d5SMatt Jacob 1469d81ba9d5SMatt Jacob static int 1470d81ba9d5SMatt Jacob isp_handle_platform_ctio(struct ispsoftc *isp, void *arg) 1471d81ba9d5SMatt Jacob { 1472d81ba9d5SMatt Jacob union ccb *ccb; 1473a1bc34c6SMatt Jacob int sentstatus, ok, notify_cam, resid = 0; 1474d81ba9d5SMatt Jacob 1475d81ba9d5SMatt Jacob /* 1476d81ba9d5SMatt Jacob * CTIO and CTIO2 are close enough.... 1477d81ba9d5SMatt Jacob */ 1478d81ba9d5SMatt Jacob 14795f5aafe1SMatt Jacob ccb = (union ccb *) isp_find_xs(isp, ((ct_entry_t *)arg)->ct_syshandle); 1480d81ba9d5SMatt Jacob KASSERT((ccb != NULL), ("null ccb in isp_handle_platform_ctio")); 14815f5aafe1SMatt Jacob isp_destroy_handle(isp, ((ct_entry_t *)arg)->ct_syshandle); 1482d81ba9d5SMatt Jacob 1483d81ba9d5SMatt Jacob if (IS_FC(isp)) { 1484d81ba9d5SMatt Jacob ct2_entry_t *ct = arg; 1485d81ba9d5SMatt Jacob sentstatus = ct->ct_flags & CT2_SENDSTATUS; 1486d81ba9d5SMatt Jacob ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; 1487a1bc34c6SMatt Jacob if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) { 148800a8e174SMatt Jacob ccb->ccb_h.status |= CAM_SENT_SENSE; 148900a8e174SMatt Jacob } 1490a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 1491a1bc34c6SMatt Jacob "CTIO2[%x] sts 0x%x flg 0x%x sns %d %s", 1492b09b0095SMatt Jacob ct->ct_rxid, ct->ct_status, ct->ct_flags, 1493a1bc34c6SMatt Jacob (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, 1494a1bc34c6SMatt Jacob sentstatus? "FIN" : "MID"); 1495a1bc34c6SMatt Jacob notify_cam = ct->ct_header.rqs_seqno & 0x1; 14965d571944SMatt Jacob if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) { 1497a1bc34c6SMatt Jacob resid = ct->ct_resid; 14985d571944SMatt Jacob } 1499d81ba9d5SMatt Jacob } else { 1500d81ba9d5SMatt Jacob ct_entry_t *ct = arg; 1501d81ba9d5SMatt Jacob sentstatus = ct->ct_flags & CT_SENDSTATUS; 1502d81ba9d5SMatt Jacob ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; 1503a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 1504a1bc34c6SMatt Jacob "CTIO[%x] tag %x iid %x tgt %d lun %d sts 0x%x flg %x %s", 1505a1bc34c6SMatt Jacob ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_tgt, 1506a1bc34c6SMatt Jacob ct->ct_lun, ct->ct_status, ct->ct_flags, 1507a1bc34c6SMatt Jacob sentstatus? "FIN" : "MID"); 1508d81ba9d5SMatt Jacob 1509d81ba9d5SMatt Jacob /* 1510a1bc34c6SMatt Jacob * We *ought* to be able to get back to the original ATIO 1511a1bc34c6SMatt Jacob * here, but for some reason this gets lost. It's just as 1512a1bc34c6SMatt Jacob * well because it's squirrelled away as part of periph 1513a1bc34c6SMatt Jacob * private data. 1514a1bc34c6SMatt Jacob * 1515a1bc34c6SMatt Jacob * We can live without it as long as we continue to use 1516a1bc34c6SMatt Jacob * the auto-replenish feature for CTIOs. 1517a1bc34c6SMatt Jacob */ 1518a1bc34c6SMatt Jacob notify_cam = ct->ct_header.rqs_seqno & 0x1; 1519a1bc34c6SMatt Jacob if (ct->ct_status & QLTM_SVALID) { 1520a1bc34c6SMatt Jacob char *sp = (char *)ct; 1521a1bc34c6SMatt Jacob sp += CTIO_SENSE_OFFSET; 1522a1bc34c6SMatt Jacob ccb->csio.sense_len = 1523a1bc34c6SMatt Jacob min(sizeof (ccb->csio.sense_data), QLTM_SENSELEN); 1524a1bc34c6SMatt Jacob MEMCPY(&ccb->csio.sense_data, sp, ccb->csio.sense_len); 1525a1bc34c6SMatt Jacob ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 1526a1bc34c6SMatt Jacob } 15275d571944SMatt Jacob if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) { 1528a1bc34c6SMatt Jacob resid = ct->ct_resid; 1529a1bc34c6SMatt Jacob } 15305d571944SMatt Jacob } 1531a1bc34c6SMatt Jacob ccb->csio.resid += resid; 1532a1bc34c6SMatt Jacob 1533a1bc34c6SMatt Jacob /* 1534a1bc34c6SMatt Jacob * We're here either because intermediate data transfers are done 1535a1bc34c6SMatt Jacob * and/or the final status CTIO (which may have joined with a 1536a1bc34c6SMatt Jacob * Data Transfer) is done. 1537d81ba9d5SMatt Jacob * 1538d81ba9d5SMatt Jacob * In any case, for this platform, the upper layers figure out 1539d81ba9d5SMatt Jacob * what to do next, so all we do here is collect status and 1540a1bc34c6SMatt Jacob * pass information along. Any DMA handles have already been 1541a1bc34c6SMatt Jacob * freed. 1542d81ba9d5SMatt Jacob */ 1543f48ce188SMatt Jacob if (notify_cam == 0) { 1544a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, " INTER CTIO done"); 1545f48ce188SMatt Jacob return (0); 1546f48ce188SMatt Jacob } 1547d81ba9d5SMatt Jacob 1548a1bc34c6SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO done (resid %d)", 1549a1bc34c6SMatt Jacob (sentstatus)? " FINAL " : "MIDTERM ", ccb->csio.resid); 1550a1bc34c6SMatt Jacob 1551a1bc34c6SMatt Jacob if (!ok) { 1552a1bc34c6SMatt Jacob isp_target_putback_atio(ccb); 1553d81ba9d5SMatt Jacob } else { 1554a1bc34c6SMatt Jacob isp_complete_ctio(ccb); 1555a1bc34c6SMatt Jacob 1556d81ba9d5SMatt Jacob } 1557a1bc34c6SMatt Jacob return (0); 1558d81ba9d5SMatt Jacob } 1559d81ba9d5SMatt Jacob #endif 1560d81ba9d5SMatt Jacob 1561478f8a96SJustin T. Gibbs static void 1562cbf57b47SMatt Jacob isp_cam_async(void *cbarg, u_int32_t code, struct cam_path *path, void *arg) 1563478f8a96SJustin T. Gibbs { 1564478f8a96SJustin T. Gibbs struct cam_sim *sim; 1565478f8a96SJustin T. Gibbs struct ispsoftc *isp; 1566478f8a96SJustin T. Gibbs 1567478f8a96SJustin T. Gibbs sim = (struct cam_sim *)cbarg; 1568478f8a96SJustin T. Gibbs isp = (struct ispsoftc *) cam_sim_softc(sim); 1569478f8a96SJustin T. Gibbs switch (code) { 1570478f8a96SJustin T. Gibbs case AC_LOST_DEVICE: 1571ab6c4b31SMatt Jacob if (IS_SCSI(isp)) { 1572478f8a96SJustin T. Gibbs u_int16_t oflags, nflags; 1573478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 1574a1bc34c6SMatt Jacob int tgt; 1575478f8a96SJustin T. Gibbs 1576f9e908dcSMatt Jacob tgt = xpt_path_target_id(path); 1577f6e75de2SMatt Jacob ISP_LOCK(isp); 1578ea6f23cdSMatt Jacob sdp += cam_sim_bus(sim); 15799ce9bdafSMatt Jacob nflags = sdp->isp_devparam[tgt].nvrm_flags; 1580a1bc34c6SMatt Jacob #ifndef ISP_TARGET_MODE 15819ce9bdafSMatt Jacob nflags &= DPARM_SAFE_DFLT; 1582a1bc34c6SMatt Jacob if (isp->isp_loaded_fw) { 1583478f8a96SJustin T. Gibbs nflags |= DPARM_NARROW | DPARM_ASYNC; 1584478f8a96SJustin T. Gibbs } 1585a1bc34c6SMatt Jacob #else 1586a1bc34c6SMatt Jacob nflags = DPARM_DEFAULT; 1587a1bc34c6SMatt Jacob #endif 15889ce9bdafSMatt Jacob oflags = sdp->isp_devparam[tgt].goal_flags; 15899ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_flags = nflags; 1590478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_update = 1; 1591a1bc34c6SMatt Jacob isp->isp_update |= (1 << cam_sim_bus(sim)); 1592478f8a96SJustin T. Gibbs (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL); 15939ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_flags = oflags; 1594f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1595478f8a96SJustin T. Gibbs } 1596478f8a96SJustin T. Gibbs break; 1597478f8a96SJustin T. Gibbs default: 15983c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, "isp_cam_async: Code 0x%x", code); 1599478f8a96SJustin T. Gibbs break; 1600478f8a96SJustin T. Gibbs } 1601478f8a96SJustin T. Gibbs } 1602478f8a96SJustin T. Gibbs 1603478f8a96SJustin T. Gibbs static void 1604c3055363SMatt Jacob isp_poll(struct cam_sim *sim) 1605478f8a96SJustin T. Gibbs { 1606c40e096eSMatt Jacob struct ispsoftc *isp = cam_sim_softc(sim); 1607126ec864SMatt Jacob u_int16_t isr, sema, mbox; 1608126ec864SMatt Jacob 1609c40e096eSMatt Jacob ISP_LOCK(isp); 1610126ec864SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 1611126ec864SMatt Jacob isp_intr(isp, isr, sema, mbox); 1612126ec864SMatt Jacob } 1613c40e096eSMatt Jacob ISP_UNLOCK(isp); 1614478f8a96SJustin T. Gibbs } 1615478f8a96SJustin T. Gibbs 16165d571944SMatt Jacob #if 0 16170470d791SMatt Jacob static void 16180470d791SMatt Jacob isp_relsim(void *arg) 16190470d791SMatt Jacob { 16200470d791SMatt Jacob struct ispsoftc *isp = arg; 1621f6e75de2SMatt Jacob ISP_LOCK(isp); 16220470d791SMatt Jacob if (isp->isp_osinfo.simqfrozen & SIMQFRZ_TIMED) { 16230470d791SMatt Jacob int wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_TIMED; 16240470d791SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_TIMED; 16250470d791SMatt Jacob if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) { 16260470d791SMatt Jacob xpt_release_simq(isp->isp_sim, 1); 1627b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "timed relsimq"); 16280470d791SMatt Jacob } 16290470d791SMatt Jacob } 1630f6e75de2SMatt Jacob ISP_UNLOCK(isp); 16310470d791SMatt Jacob } 16325d571944SMatt Jacob #endif 1633ab6c4b31SMatt Jacob 1634478f8a96SJustin T. Gibbs static void 1635b85389e1SMatt Jacob isp_watchdog(void *arg) 1636cc8df88bSMatt Jacob { 1637b09b0095SMatt Jacob XS_T *xs = arg; 1638cc8df88bSMatt Jacob struct ispsoftc *isp = XS_ISP(xs); 1639cc8df88bSMatt Jacob u_int32_t handle; 1640b85389e1SMatt Jacob 1641cc8df88bSMatt Jacob /* 1642b85389e1SMatt Jacob * We've decided this command is dead. Make sure we're not trying 1643b85389e1SMatt Jacob * to kill a command that's already dead by getting it's handle and 1644b85389e1SMatt Jacob * and seeing whether it's still alive. 1645cc8df88bSMatt Jacob */ 1646f6e75de2SMatt Jacob ISP_LOCK(isp); 1647cc8df88bSMatt Jacob handle = isp_find_handle(isp, xs); 1648cc8df88bSMatt Jacob if (handle) { 1649126ec864SMatt Jacob u_int16_t isr, sema, mbox; 1650126ec864SMatt Jacob 1651b85389e1SMatt Jacob 1652b85389e1SMatt Jacob if (XS_CMD_DONE_P(xs)) { 1653b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG1, 1654b09b0095SMatt Jacob "watchdog found done cmd (handle 0x%x)", handle); 1655f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1656b85389e1SMatt Jacob return; 1657b85389e1SMatt Jacob } 1658b85389e1SMatt Jacob 1659b85389e1SMatt Jacob if (XS_CMD_WDOG_P(xs)) { 1660b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1661b09b0095SMatt Jacob "recursive watchdog (handle 0x%x)", handle); 1662f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1663b85389e1SMatt Jacob return; 1664b85389e1SMatt Jacob } 1665b85389e1SMatt Jacob 1666b85389e1SMatt Jacob XS_CMD_S_WDOG(xs); 1667126ec864SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 1668126ec864SMatt Jacob isp_intr(isp, isr, sema, mbox); 1669126ec864SMatt Jacob } 1670126ec864SMatt Jacob if (XS_CMD_DONE_P(xs)) { 1671b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1672126ec864SMatt Jacob "watchdog cleanup for handle 0x%x", handle); 1673b85389e1SMatt Jacob xpt_done((union ccb *) xs); 1674b85389e1SMatt Jacob } else if (XS_CMD_GRACE_P(xs)) { 16751fcf5debSMatt Jacob /* 16761fcf5debSMatt Jacob * Make sure the command is *really* dead before we 16771fcf5debSMatt Jacob * release the handle (and DMA resources) for reuse. 16781fcf5debSMatt Jacob */ 16791fcf5debSMatt Jacob (void) isp_control(isp, ISPCTL_ABORT_CMD, arg); 16801fcf5debSMatt Jacob 16811fcf5debSMatt Jacob /* 16821fcf5debSMatt Jacob * After this point, the comamnd is really dead. 16831fcf5debSMatt Jacob */ 1684f6e75de2SMatt Jacob if (XS_XFRLEN(xs)) { 1685f6e75de2SMatt Jacob ISP_DMAFREE(isp, xs, handle); 1686f6e75de2SMatt Jacob } 1687cc8df88bSMatt Jacob isp_destroy_handle(isp, handle); 1688cc8df88bSMatt Jacob xpt_print_path(xs->ccb_h.path); 16893c75bb14SMatt Jacob isp_prt(isp, ISP_LOGWARN, 1690126ec864SMatt Jacob "watchdog timeout for handle %x", handle); 1691cc8df88bSMatt Jacob XS_SETERR(xs, CAM_CMD_TIMEOUT); 1692b85389e1SMatt Jacob XS_CMD_C_WDOG(xs); 1693cc8df88bSMatt Jacob isp_done(xs); 1694b85389e1SMatt Jacob } else { 1695b85389e1SMatt Jacob u_int16_t iptr, optr; 1696b85389e1SMatt Jacob ispreq_t *mp; 1697b85389e1SMatt Jacob 1698b85389e1SMatt Jacob XS_CMD_C_WDOG(xs); 1699b85389e1SMatt Jacob xs->ccb_h.timeout_ch = timeout(isp_watchdog, xs, hz); 1700b85389e1SMatt Jacob if (isp_getrqentry(isp, &iptr, &optr, (void **) &mp)) { 1701f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1702b85389e1SMatt Jacob return; 1703b85389e1SMatt Jacob } 1704b85389e1SMatt Jacob XS_CMD_S_GRACE(xs); 1705b85389e1SMatt Jacob MEMZERO((void *) mp, sizeof (*mp)); 1706b85389e1SMatt Jacob mp->req_header.rqs_entry_count = 1; 1707b85389e1SMatt Jacob mp->req_header.rqs_entry_type = RQSTYPE_MARKER; 1708b85389e1SMatt Jacob mp->req_modifier = SYNC_ALL; 1709b85389e1SMatt Jacob mp->req_target = XS_CHANNEL(xs) << 7; 1710b85389e1SMatt Jacob ISP_SWIZZLE_REQUEST(isp, mp); 1711b85389e1SMatt Jacob ISP_ADD_REQUEST(isp, iptr); 1712b85389e1SMatt Jacob } 1713b85389e1SMatt Jacob } else { 1714b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "watchdog with no command"); 1715cc8df88bSMatt Jacob } 1716f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1717cc8df88bSMatt Jacob } 1718cc8df88bSMatt Jacob 1719f44257c2SMatt Jacob static int isp_ktmature = 0; 1720f44257c2SMatt Jacob 17215d571944SMatt Jacob static void 17225d571944SMatt Jacob isp_kthread(void *arg) 17235d571944SMatt Jacob { 17245d571944SMatt Jacob int wasfrozen; 17255d571944SMatt Jacob struct ispsoftc *isp = arg; 17265d571944SMatt Jacob 17275d571944SMatt Jacob mtx_lock(&isp->isp_lock); 17285d571944SMatt Jacob for (;;) { 17295d571944SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "kthread checking FC state"); 17305d571944SMatt Jacob while (isp_fc_runstate(isp, 2 * 1000000) != 0) { 1731f44257c2SMatt Jacob if (FCPARAM(isp)->isp_fwstate != FW_READY || 1732f44257c2SMatt Jacob FCPARAM(isp)->isp_loopstate < LOOP_PDB_RCVD) { 1733f44257c2SMatt Jacob if (FCPARAM(isp)->loop_seen_once == 0 || 1734f44257c2SMatt Jacob isp_ktmature == 0) { 1735f44257c2SMatt Jacob break; 1736f44257c2SMatt Jacob } 1737f44257c2SMatt Jacob } 17385d571944SMatt Jacob msleep(isp_kthread, &isp->isp_lock, 17395d571944SMatt Jacob PRIBIO, "isp_fcthrd", hz); 17405d571944SMatt Jacob } 1741f44257c2SMatt Jacob /* 1742f44257c2SMatt Jacob * Even if we didn't get good loop state we may be 1743f44257c2SMatt Jacob * unfreezing the SIMQ so that we can kill off 1744f44257c2SMatt Jacob * commands (if we've never seen loop before, e.g.) 1745f44257c2SMatt Jacob */ 1746f44257c2SMatt Jacob isp_ktmature = 1; 17475d571944SMatt Jacob wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN; 17485d571944SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN; 17495d571944SMatt Jacob if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) { 17505d571944SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "kthread up release simq"); 17515d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 17525d571944SMatt Jacob xpt_release_simq(isp->isp_sim, 1); 17535d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 17545d571944SMatt Jacob } 17555d571944SMatt Jacob cv_wait(&isp->isp_osinfo.kthread_cv, &isp->isp_lock); 17565d571944SMatt Jacob } 17575d571944SMatt Jacob } 17585d571944SMatt Jacob 1759cc8df88bSMatt Jacob static void 1760c3055363SMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb) 1761478f8a96SJustin T. Gibbs { 1762f6e75de2SMatt Jacob int bus, tgt, error; 1763478f8a96SJustin T. Gibbs struct ispsoftc *isp; 17644663e367SJustin T. Gibbs struct ccb_trans_settings *cts; 1765478f8a96SJustin T. Gibbs 1766478f8a96SJustin T. Gibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n")); 1767478f8a96SJustin T. Gibbs 1768478f8a96SJustin T. Gibbs isp = (struct ispsoftc *)cam_sim_softc(sim); 1769478f8a96SJustin T. Gibbs ccb->ccb_h.sim_priv.entries[0].field = 0; 1770478f8a96SJustin T. Gibbs ccb->ccb_h.sim_priv.entries[1].ptr = isp; 17710470d791SMatt Jacob if (isp->isp_state != ISP_RUNSTATE && 17720470d791SMatt Jacob ccb->ccb_h.func_code == XPT_SCSI_IO) { 17735d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 177457c801f5SMatt Jacob isp_init(isp); 177557c801f5SMatt Jacob if (isp->isp_state != ISP_INITSTATE) { 1776f6e75de2SMatt Jacob ISP_UNLOCK(isp); 177757c801f5SMatt Jacob /* 177857c801f5SMatt Jacob * Lie. Say it was a selection timeout. 177957c801f5SMatt Jacob */ 1780b85389e1SMatt Jacob ccb->ccb_h.status = CAM_SEL_TIMEOUT | CAM_DEV_QFRZN; 17810470d791SMatt Jacob xpt_freeze_devq(ccb->ccb_h.path, 1); 178257c801f5SMatt Jacob xpt_done(ccb); 178357c801f5SMatt Jacob return; 178457c801f5SMatt Jacob } 178557c801f5SMatt Jacob isp->isp_state = ISP_RUNSTATE; 17865d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 178757c801f5SMatt Jacob } 1788b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "isp_action code %x", ccb->ccb_h.func_code); 1789478f8a96SJustin T. Gibbs 17905d571944SMatt Jacob 1791478f8a96SJustin T. Gibbs switch (ccb->ccb_h.func_code) { 1792478f8a96SJustin T. Gibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 1793478f8a96SJustin T. Gibbs /* 1794478f8a96SJustin T. Gibbs * Do a couple of preliminary checks... 1795478f8a96SJustin T. Gibbs */ 1796478f8a96SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { 1797478f8a96SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) { 1798478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 1799478f8a96SJustin T. Gibbs xpt_done(ccb); 1800478f8a96SJustin T. Gibbs break; 1801478f8a96SJustin T. Gibbs } 1802478f8a96SJustin T. Gibbs } 18030470d791SMatt Jacob #ifdef DIAGNOSTIC 18040470d791SMatt Jacob if (ccb->ccb_h.target_id > (ISP_MAX_TARGETS(isp) - 1)) { 1805478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 18060470d791SMatt Jacob } else if (ccb->ccb_h.target_lun > (ISP_MAX_LUNS(isp) - 1)) { 1807478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 1808478f8a96SJustin T. Gibbs } 1809478f8a96SJustin T. Gibbs if (ccb->ccb_h.status == CAM_PATH_INVALID) { 1810bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 1811bfbab170SMatt Jacob "invalid tgt/lun (%d.%d) in XPT_SCSI_IO", 1812bfbab170SMatt Jacob ccb->ccb_h.target_id, ccb->ccb_h.target_lun); 1813478f8a96SJustin T. Gibbs xpt_done(ccb); 1814478f8a96SJustin T. Gibbs break; 1815478f8a96SJustin T. Gibbs } 18160470d791SMatt Jacob #endif 18170470d791SMatt Jacob ((struct ccb_scsiio *) ccb)->scsi_status = SCSI_STATUS_OK; 18185d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 1819b09b0095SMatt Jacob error = isp_start((XS_T *) ccb); 18200470d791SMatt Jacob switch (error) { 1821478f8a96SJustin T. Gibbs case CMD_QUEUED: 1822478f8a96SJustin T. Gibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 1823cc8df88bSMatt Jacob if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { 1824d69a5f7dSMatt Jacob u_int64_t ticks = (u_int64_t) hz; 1825cc8df88bSMatt Jacob if (ccb->ccb_h.timeout == CAM_TIME_DEFAULT) 1826d69a5f7dSMatt Jacob ticks = 60 * 1000 * ticks; 1827b85389e1SMatt Jacob else 1828b85389e1SMatt Jacob ticks = ccb->ccb_h.timeout * hz; 1829b85389e1SMatt Jacob ticks = ((ticks + 999) / 1000) + hz + hz; 1830d69a5f7dSMatt Jacob if (ticks >= 0x80000000) { 1831d69a5f7dSMatt Jacob isp_prt(isp, ISP_LOGERR, 1832d69a5f7dSMatt Jacob "timeout overflow"); 1833d69a5f7dSMatt Jacob ticks = 0x80000000; 1834d69a5f7dSMatt Jacob } 1835d69a5f7dSMatt Jacob ccb->ccb_h.timeout_ch = timeout(isp_watchdog, 1836d69a5f7dSMatt Jacob (caddr_t)ccb, (int)ticks); 1837b85389e1SMatt Jacob } else { 1838b85389e1SMatt Jacob callout_handle_init(&ccb->ccb_h.timeout_ch); 1839cc8df88bSMatt Jacob } 18405d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1841478f8a96SJustin T. Gibbs break; 18420470d791SMatt Jacob case CMD_RQLATER: 1843f44257c2SMatt Jacob /* 1844f44257c2SMatt Jacob * This can only happen for Fibre Channel 1845f44257c2SMatt Jacob */ 1846f44257c2SMatt Jacob KASSERT((IS_FC(isp)), ("CMD_RQLATER for FC only")); 1847f44257c2SMatt Jacob if (FCPARAM(isp)->loop_seen_once == 0 && isp_ktmature) { 1848f44257c2SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1849f44257c2SMatt Jacob XS_SETERR(ccb, CAM_SEL_TIMEOUT); 1850f44257c2SMatt Jacob xpt_done(ccb); 1851f44257c2SMatt Jacob break; 1852f44257c2SMatt Jacob } 18535d571944SMatt Jacob cv_signal(&isp->isp_osinfo.kthread_cv); 18540470d791SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 1855b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1856b09b0095SMatt Jacob "RQLATER freeze simq"); 18575d571944SMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; 18585d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1859478f8a96SJustin T. Gibbs xpt_freeze_simq(sim, 1); 18605d571944SMatt Jacob } else { 18615d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 186200f50ce8SMatt Jacob } 1863b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 1864478f8a96SJustin T. Gibbs xpt_done(ccb); 1865478f8a96SJustin T. Gibbs break; 18660470d791SMatt Jacob case CMD_EAGAIN: 18670470d791SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 18680470d791SMatt Jacob xpt_freeze_simq(sim, 1); 1869b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1870b09b0095SMatt Jacob "EAGAIN freeze simq"); 1871478f8a96SJustin T. Gibbs } 18720470d791SMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_RESOURCE; 1873b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 18745d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1875478f8a96SJustin T. Gibbs xpt_done(ccb); 1876478f8a96SJustin T. Gibbs break; 18770470d791SMatt Jacob case CMD_COMPLETE: 18780470d791SMatt Jacob isp_done((struct ccb_scsiio *) ccb); 18795d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 18800470d791SMatt Jacob break; 18810470d791SMatt Jacob default: 1882bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 1883bfbab170SMatt Jacob "What's this? 0x%x at %d in file %s", 188491f1caa2SMatt Jacob error, __LINE__, __FILE__); 1885b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQ_CMP_ERR); 18860470d791SMatt Jacob xpt_done(ccb); 18875d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1888478f8a96SJustin T. Gibbs } 1889478f8a96SJustin T. Gibbs break; 1890478f8a96SJustin T. Gibbs 1891d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 1892478f8a96SJustin T. Gibbs case XPT_EN_LUN: /* Enable LUN as a target */ 18935d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 1894d81ba9d5SMatt Jacob isp_en_lun(isp, ccb); 18955d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1896478f8a96SJustin T. Gibbs xpt_done(ccb); 1897478f8a96SJustin T. Gibbs break; 1898478f8a96SJustin T. Gibbs 1899d81ba9d5SMatt Jacob case XPT_NOTIFY_ACK: /* recycle notify ack */ 1900d81ba9d5SMatt Jacob case XPT_IMMED_NOTIFY: /* Add Immediate Notify Resource */ 1901d81ba9d5SMatt Jacob case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */ 1902d81ba9d5SMatt Jacob { 1903a1bc34c6SMatt Jacob tstate_t *tptr = 1904a1bc34c6SMatt Jacob get_lun_statep(isp, XS_CHANNEL(ccb), ccb->ccb_h.target_lun); 1905d81ba9d5SMatt Jacob if (tptr == NULL) { 1906d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 1907d81ba9d5SMatt Jacob xpt_done(ccb); 1908d81ba9d5SMatt Jacob break; 1909d81ba9d5SMatt Jacob } 1910f48ce188SMatt Jacob ccb->ccb_h.sim_priv.entries[0].field = 0; 1911f48ce188SMatt Jacob ccb->ccb_h.sim_priv.entries[1].ptr = isp; 19125d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 1913d81ba9d5SMatt Jacob if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 1914d81ba9d5SMatt Jacob SLIST_INSERT_HEAD(&tptr->atios, 1915d81ba9d5SMatt Jacob &ccb->ccb_h, sim_links.sle); 1916d81ba9d5SMatt Jacob } else { 1917d81ba9d5SMatt Jacob SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, 1918d81ba9d5SMatt Jacob sim_links.sle); 1919d81ba9d5SMatt Jacob } 1920d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1921d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_INPROG; 19225d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1923d81ba9d5SMatt Jacob break; 1924d81ba9d5SMatt Jacob } 1925d81ba9d5SMatt Jacob case XPT_CONT_TARGET_IO: 1926d81ba9d5SMatt Jacob { 19275d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 1928d81ba9d5SMatt Jacob ccb->ccb_h.status = isp_target_start_ctio(isp, ccb); 1929d81ba9d5SMatt Jacob if (ccb->ccb_h.status != CAM_REQ_INPROG) { 1930d81ba9d5SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 1931d81ba9d5SMatt Jacob xpt_freeze_simq(sim, 1); 1932d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 19333c75bb14SMatt Jacob isp_prt(isp, ISP_LOGINFO, 19343c75bb14SMatt Jacob "XPT_CONT_TARGET_IO freeze simq"); 1935d81ba9d5SMatt Jacob } 1936d81ba9d5SMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_RESOURCE; 1937b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 19385d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1939d81ba9d5SMatt Jacob xpt_done(ccb); 1940d81ba9d5SMatt Jacob } else { 19415d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1942d81ba9d5SMatt Jacob ccb->ccb_h.status |= CAM_SIM_QUEUED; 1943d81ba9d5SMatt Jacob } 1944d81ba9d5SMatt Jacob break; 1945d81ba9d5SMatt Jacob } 1946d81ba9d5SMatt Jacob #endif 1947478f8a96SJustin T. Gibbs case XPT_RESET_DEV: /* BDR the specified SCSI device */ 1948d81ba9d5SMatt Jacob 1949d81ba9d5SMatt Jacob bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path)); 1950d81ba9d5SMatt Jacob tgt = ccb->ccb_h.target_id; 1951d81ba9d5SMatt Jacob tgt |= (bus << 16); 1952d81ba9d5SMatt Jacob 19535d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 1954ea6f23cdSMatt Jacob error = isp_control(isp, ISPCTL_RESET_DEV, &tgt); 19555d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1956478f8a96SJustin T. Gibbs if (error) { 1957478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 1958478f8a96SJustin T. Gibbs } else { 1959478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 1960478f8a96SJustin T. Gibbs } 1961478f8a96SJustin T. Gibbs xpt_done(ccb); 1962478f8a96SJustin T. Gibbs break; 1963478f8a96SJustin T. Gibbs case XPT_ABORT: /* Abort the specified CCB */ 1964d81ba9d5SMatt Jacob { 1965d81ba9d5SMatt Jacob union ccb *accb = ccb->cab.abort_ccb; 19665d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 1967d81ba9d5SMatt Jacob switch (accb->ccb_h.func_code) { 1968d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 1969d81ba9d5SMatt Jacob case XPT_ACCEPT_TARGET_IO: 1970d81ba9d5SMatt Jacob case XPT_IMMED_NOTIFY: 1971d81ba9d5SMatt Jacob ccb->ccb_h.status = isp_abort_tgt_ccb(isp, ccb); 1972d81ba9d5SMatt Jacob break; 1973d81ba9d5SMatt Jacob case XPT_CONT_TARGET_IO: 1974b09b0095SMatt Jacob isp_prt(isp, ISP_LOGERR, "cannot abort CTIOs yet"); 1975d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_UA_ABORT; 1976d81ba9d5SMatt Jacob break; 1977d81ba9d5SMatt Jacob #endif 1978d81ba9d5SMatt Jacob case XPT_SCSI_IO: 1979478f8a96SJustin T. Gibbs error = isp_control(isp, ISPCTL_ABORT_CMD, ccb); 1980478f8a96SJustin T. Gibbs if (error) { 1981d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_UA_ABORT; 1982478f8a96SJustin T. Gibbs } else { 1983478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 1984478f8a96SJustin T. Gibbs } 1985d81ba9d5SMatt Jacob break; 1986d81ba9d5SMatt Jacob default: 1987d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_INVALID; 1988d81ba9d5SMatt Jacob break; 1989d81ba9d5SMatt Jacob } 19905d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 1991478f8a96SJustin T. Gibbs xpt_done(ccb); 1992478f8a96SJustin T. Gibbs break; 1993d81ba9d5SMatt Jacob } 1994ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 1995ab163f5fSMatt Jacob #define IS_CURRENT_SETTINGS(c) (c->type == CTS_TYPE_CURRENT_SETTINGS) 1996ab163f5fSMatt Jacob #else 1997ab163f5fSMatt Jacob #define IS_CURRENT_SETTINGS(c) (c->flags & CCB_TRANS_CURRENT_SETTINGS) 1998ab163f5fSMatt Jacob #endif 1999478f8a96SJustin T. Gibbs case XPT_SET_TRAN_SETTINGS: /* Nexus Settings */ 2000478f8a96SJustin T. Gibbs cts = &ccb->cts; 20019ce9bdafSMatt Jacob if (!IS_CURRENT_SETTINGS(cts)) { 20029ce9bdafSMatt Jacob ccb->ccb_h.status = CAM_REQ_INVALID; 20039ce9bdafSMatt Jacob xpt_done(ccb); 20049ce9bdafSMatt Jacob break; 20059ce9bdafSMatt Jacob } 2006478f8a96SJustin T. Gibbs tgt = cts->ccb_h.target_id; 20075d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2008ab6c4b31SMatt Jacob if (IS_SCSI(isp)) { 2009ab163f5fSMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2010478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 2011478f8a96SJustin T. Gibbs u_int16_t *dptr; 2012d81ba9d5SMatt Jacob 2013d81ba9d5SMatt Jacob bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 2014478f8a96SJustin T. Gibbs 2015ea6f23cdSMatt Jacob sdp += bus; 2016478f8a96SJustin T. Gibbs /* 20179ce9bdafSMatt Jacob * We always update (internally) from goal_flags 2018478f8a96SJustin T. Gibbs * so any request to change settings just gets 2019478f8a96SJustin T. Gibbs * vectored to that location. 2020478f8a96SJustin T. Gibbs */ 20219ce9bdafSMatt Jacob dptr = &sdp->isp_devparam[tgt].goal_flags; 2022478f8a96SJustin T. Gibbs 2023478f8a96SJustin T. Gibbs /* 2024478f8a96SJustin T. Gibbs * Note that these operations affect the 20259ce9bdafSMatt Jacob * the goal flags (goal_flags)- not 2026478f8a96SJustin T. Gibbs * the current state flags. Then we mark 2027478f8a96SJustin T. Gibbs * things so that the next operation to 2028478f8a96SJustin T. Gibbs * this HBA will cause the update to occur. 2029478f8a96SJustin T. Gibbs */ 2030478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_DISC_VALID) { 2031478f8a96SJustin T. Gibbs if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) { 2032478f8a96SJustin T. Gibbs *dptr |= DPARM_DISC; 2033478f8a96SJustin T. Gibbs } else { 2034478f8a96SJustin T. Gibbs *dptr &= ~DPARM_DISC; 2035478f8a96SJustin T. Gibbs } 2036478f8a96SJustin T. Gibbs } 2037478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_TQ_VALID) { 2038478f8a96SJustin T. Gibbs if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) { 2039478f8a96SJustin T. Gibbs *dptr |= DPARM_TQING; 2040478f8a96SJustin T. Gibbs } else { 2041478f8a96SJustin T. Gibbs *dptr &= ~DPARM_TQING; 2042478f8a96SJustin T. Gibbs } 2043478f8a96SJustin T. Gibbs } 2044478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) { 2045478f8a96SJustin T. Gibbs switch (cts->bus_width) { 2046478f8a96SJustin T. Gibbs case MSG_EXT_WDTR_BUS_16_BIT: 2047478f8a96SJustin T. Gibbs *dptr |= DPARM_WIDE; 2048478f8a96SJustin T. Gibbs break; 2049478f8a96SJustin T. Gibbs default: 2050478f8a96SJustin T. Gibbs *dptr &= ~DPARM_WIDE; 2051478f8a96SJustin T. Gibbs } 2052478f8a96SJustin T. Gibbs } 2053478f8a96SJustin T. Gibbs /* 2054478f8a96SJustin T. Gibbs * Any SYNC RATE of nonzero and SYNC_OFFSET 2055478f8a96SJustin T. Gibbs * of nonzero will cause us to go to the 2056478f8a96SJustin T. Gibbs * selected (from NVRAM) maximum value for 2057478f8a96SJustin T. Gibbs * this device. At a later point, we'll 2058478f8a96SJustin T. Gibbs * allow finer control. 2059478f8a96SJustin T. Gibbs */ 2060478f8a96SJustin T. Gibbs if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) && 2061478f8a96SJustin T. Gibbs (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) && 2062478f8a96SJustin T. Gibbs (cts->sync_offset > 0)) { 2063478f8a96SJustin T. Gibbs *dptr |= DPARM_SYNC; 2064478f8a96SJustin T. Gibbs } else { 2065478f8a96SJustin T. Gibbs *dptr &= ~DPARM_SYNC; 2066478f8a96SJustin T. Gibbs } 2067ab6c4b31SMatt Jacob *dptr |= DPARM_SAFE_DFLT; 2068ab163f5fSMatt Jacob #else 2069ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi = 2070ab163f5fSMatt Jacob &cts->proto_specific.scsi; 2071ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi = 2072ab163f5fSMatt Jacob &cts->xport_specific.spi; 2073ab163f5fSMatt Jacob sdparam *sdp = isp->isp_param; 2074ab163f5fSMatt Jacob u_int16_t *dptr; 2075ab163f5fSMatt Jacob 2076ab163f5fSMatt Jacob bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 2077ab163f5fSMatt Jacob sdp += bus; 2078ab163f5fSMatt Jacob /* 20799ce9bdafSMatt Jacob * We always update (internally) from goal_flags 2080ab163f5fSMatt Jacob * so any request to change settings just gets 2081ab163f5fSMatt Jacob * vectored to that location. 2082ab163f5fSMatt Jacob */ 20839ce9bdafSMatt Jacob dptr = &sdp->isp_devparam[tgt].goal_flags; 2084ab163f5fSMatt Jacob 2085ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_DISC) != 0) { 2086ab163f5fSMatt Jacob if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) 2087ab163f5fSMatt Jacob *dptr |= DPARM_DISC; 2088ab163f5fSMatt Jacob else 2089ab163f5fSMatt Jacob *dptr &= ~DPARM_DISC; 2090ab163f5fSMatt Jacob } 2091ab163f5fSMatt Jacob 2092ab163f5fSMatt Jacob if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 2093ab163f5fSMatt Jacob if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) 2094ab163f5fSMatt Jacob *dptr |= DPARM_TQING; 2095ab163f5fSMatt Jacob else 2096ab163f5fSMatt Jacob *dptr &= ~DPARM_TQING; 2097ab163f5fSMatt Jacob } 2098ab163f5fSMatt Jacob 2099ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 2100ab163f5fSMatt Jacob if (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT) 2101ab163f5fSMatt Jacob *dptr |= DPARM_WIDE; 2102ab163f5fSMatt Jacob else 2103ab163f5fSMatt Jacob *dptr &= ~DPARM_WIDE; 2104ab163f5fSMatt Jacob } 2105ab163f5fSMatt Jacob 2106ab163f5fSMatt Jacob /* 2107ab163f5fSMatt Jacob * XXX: FIX ME 2108ab163f5fSMatt Jacob */ 2109ab163f5fSMatt Jacob if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) && 21109ce9bdafSMatt Jacob (spi->valid & CTS_SPI_VALID_SYNC_RATE) && 21119ce9bdafSMatt Jacob (spi->sync_period && spi->sync_offset)) { 2112ab163f5fSMatt Jacob *dptr |= DPARM_SYNC; 21139ce9bdafSMatt Jacob /* 21149ce9bdafSMatt Jacob * XXX: CHECK FOR LEGALITY 21159ce9bdafSMatt Jacob */ 21169ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_period = 21179ce9bdafSMatt Jacob spi->sync_period; 21189ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_offset = 21199ce9bdafSMatt Jacob spi->sync_offset; 2120ab163f5fSMatt Jacob } else { 2121ab163f5fSMatt Jacob *dptr &= ~DPARM_SYNC; 2122ab163f5fSMatt Jacob } 2123ab163f5fSMatt Jacob #endif 2124bfbab170SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 21259ce9bdafSMatt Jacob "SET bus %d targ %d to flags %x off %x per %x", 21269ce9bdafSMatt Jacob bus, tgt, sdp->isp_devparam[tgt].goal_flags, 21279ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_offset, 21289ce9bdafSMatt Jacob sdp->isp_devparam[tgt].goal_period); 2129478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_update = 1; 2130ea6f23cdSMatt Jacob isp->isp_update |= (1 << bus); 2131478f8a96SJustin T. Gibbs } 21325d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2133478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2134478f8a96SJustin T. Gibbs xpt_done(ccb); 2135478f8a96SJustin T. Gibbs break; 2136478f8a96SJustin T. Gibbs case XPT_GET_TRAN_SETTINGS: 2137478f8a96SJustin T. Gibbs cts = &ccb->cts; 2138478f8a96SJustin T. Gibbs tgt = cts->ccb_h.target_id; 2139ab163f5fSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2140ab6c4b31SMatt Jacob if (IS_FC(isp)) { 2141ab163f5fSMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2142478f8a96SJustin T. Gibbs /* 2143478f8a96SJustin T. Gibbs * a lot of normal SCSI things don't make sense. 2144478f8a96SJustin T. Gibbs */ 2145478f8a96SJustin T. Gibbs cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB; 2146478f8a96SJustin T. Gibbs cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2147478f8a96SJustin T. Gibbs /* 2148478f8a96SJustin T. Gibbs * How do you measure the width of a high 2149478f8a96SJustin T. Gibbs * speed serial bus? Well, in bytes. 2150478f8a96SJustin T. Gibbs * 2151478f8a96SJustin T. Gibbs * Offset and period make no sense, though, so we set 2152478f8a96SJustin T. Gibbs * (above) a 'base' transfer speed to be gigabit. 2153478f8a96SJustin T. Gibbs */ 2154478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2155ab163f5fSMatt Jacob #else 2156ab163f5fSMatt Jacob fcparam *fcp = isp->isp_param; 2157ab163f5fSMatt Jacob struct ccb_trans_settings_fc *fc = 2158ab163f5fSMatt Jacob &cts->xport_specific.fc; 2159478f8a96SJustin T. Gibbs 2160ab163f5fSMatt Jacob cts->protocol = PROTO_SCSI; 2161ab163f5fSMatt Jacob cts->protocol_version = SCSI_REV_2; 2162ab163f5fSMatt Jacob cts->transport = XPORT_FC; 2163ab163f5fSMatt Jacob cts->transport_version = 0; 2164ab163f5fSMatt Jacob 2165ab163f5fSMatt Jacob fc->valid = CTS_FC_VALID_SPEED; 2166ab163f5fSMatt Jacob fc->bitrate = 100000; 2167ab163f5fSMatt Jacob if (tgt > 0 && tgt < MAX_FC_TARG) { 2168ab163f5fSMatt Jacob struct lportdb *lp = &fcp->portdb[tgt]; 2169ab163f5fSMatt Jacob fc->wwnn = lp->node_wwn; 2170ab163f5fSMatt Jacob fc->wwpn = lp->port_wwn; 2171ab163f5fSMatt Jacob fc->port = lp->portid; 2172ab163f5fSMatt Jacob fc->valid |= CTS_FC_VALID_WWNN | 2173ab163f5fSMatt Jacob CTS_FC_VALID_WWPN | CTS_FC_VALID_PORT; 2174ab163f5fSMatt Jacob } 2175ab163f5fSMatt Jacob #endif 2176ab163f5fSMatt Jacob } else { 2177ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2178ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi = 2179ab163f5fSMatt Jacob &cts->proto_specific.scsi; 2180ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi = 2181ab163f5fSMatt Jacob &cts->xport_specific.spi; 2182ab163f5fSMatt Jacob #endif 2183ab163f5fSMatt Jacob sdparam *sdp = isp->isp_param; 2184ab163f5fSMatt Jacob int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 2185ab163f5fSMatt Jacob u_int16_t dval, pval, oval; 2186ab163f5fSMatt Jacob 2187ea6f23cdSMatt Jacob sdp += bus; 2188ab163f5fSMatt Jacob 2189ab163f5fSMatt Jacob if (IS_CURRENT_SETTINGS(cts)) { 219083ae4407SMatt Jacob sdp->isp_devparam[tgt].dev_refresh = 1; 219183ae4407SMatt Jacob isp->isp_update |= (1 << bus); 219283ae4407SMatt Jacob (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, 219383ae4407SMatt Jacob NULL); 21949ce9bdafSMatt Jacob dval = sdp->isp_devparam[tgt].actv_flags; 21959ce9bdafSMatt Jacob oval = sdp->isp_devparam[tgt].actv_offset; 21969ce9bdafSMatt Jacob pval = sdp->isp_devparam[tgt].actv_period; 21974394c92fSMatt Jacob } else { 21989ce9bdafSMatt Jacob dval = sdp->isp_devparam[tgt].nvrm_flags; 21999ce9bdafSMatt Jacob oval = sdp->isp_devparam[tgt].nvrm_offset; 22009ce9bdafSMatt Jacob pval = sdp->isp_devparam[tgt].nvrm_period; 22014394c92fSMatt Jacob } 2202478f8a96SJustin T. Gibbs 2203ab163f5fSMatt Jacob #ifndef CAM_NEW_TRAN_CODE 2204478f8a96SJustin T. Gibbs cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); 2205478f8a96SJustin T. Gibbs 2206478f8a96SJustin T. Gibbs if (dval & DPARM_DISC) { 2207478f8a96SJustin T. Gibbs cts->flags |= CCB_TRANS_DISC_ENB; 2208478f8a96SJustin T. Gibbs } 2209478f8a96SJustin T. Gibbs if (dval & DPARM_TQING) { 2210478f8a96SJustin T. Gibbs cts->flags |= CCB_TRANS_TAG_ENB; 2211478f8a96SJustin T. Gibbs } 2212478f8a96SJustin T. Gibbs if (dval & DPARM_WIDE) { 2213478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2214478f8a96SJustin T. Gibbs } else { 2215478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2216478f8a96SJustin T. Gibbs } 2217478f8a96SJustin T. Gibbs cts->valid = CCB_TRANS_BUS_WIDTH_VALID | 2218478f8a96SJustin T. Gibbs CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2219478f8a96SJustin T. Gibbs 22204394c92fSMatt Jacob if ((dval & DPARM_SYNC) && oval != 0) { 22214394c92fSMatt Jacob cts->sync_period = pval; 22224394c92fSMatt Jacob cts->sync_offset = oval; 2223478f8a96SJustin T. Gibbs cts->valid |= 2224478f8a96SJustin T. Gibbs CCB_TRANS_SYNC_RATE_VALID | 2225478f8a96SJustin T. Gibbs CCB_TRANS_SYNC_OFFSET_VALID; 2226478f8a96SJustin T. Gibbs } 2227ab163f5fSMatt Jacob #else 2228ab163f5fSMatt Jacob cts->protocol = PROTO_SCSI; 2229ab163f5fSMatt Jacob cts->protocol_version = SCSI_REV_2; 2230ab163f5fSMatt Jacob cts->transport = XPORT_SPI; 2231ab163f5fSMatt Jacob cts->transport_version = 2; 2232ab163f5fSMatt Jacob 2233ab163f5fSMatt Jacob scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 2234ab163f5fSMatt Jacob spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 2235ab163f5fSMatt Jacob if (dval & DPARM_DISC) { 2236ab163f5fSMatt Jacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 2237ab163f5fSMatt Jacob } 2238ab163f5fSMatt Jacob if (dval & DPARM_TQING) { 2239ab163f5fSMatt Jacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 2240ab163f5fSMatt Jacob } 22419ce9bdafSMatt Jacob if ((dval & DPARM_SYNC) && oval && pval) { 2242ab163f5fSMatt Jacob spi->sync_offset = oval; 2243ab163f5fSMatt Jacob spi->sync_period = pval; 2244ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 2245ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 2246ab163f5fSMatt Jacob } 2247ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_BUS_WIDTH; 2248ab163f5fSMatt Jacob if (dval & DPARM_WIDE) { 2249ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2250ab163f5fSMatt Jacob } else { 2251ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2252ab163f5fSMatt Jacob } 2253ab163f5fSMatt Jacob if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { 2254ab163f5fSMatt Jacob scsi->valid = CTS_SCSI_VALID_TQ; 2255ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_DISC; 2256ab163f5fSMatt Jacob } else { 2257ab163f5fSMatt Jacob scsi->valid = 0; 2258ab163f5fSMatt Jacob } 2259ab163f5fSMatt Jacob #endif 2260bfbab170SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 22619ce9bdafSMatt Jacob "GET %s bus %d targ %d to flags %x off %x per %x", 22629ce9bdafSMatt Jacob IS_CURRENT_SETTINGS(cts)? "ACTIVE" : "NVRAM", 22639ce9bdafSMatt Jacob bus, tgt, dval, oval, pval); 2264478f8a96SJustin T. Gibbs } 2265ab163f5fSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2266478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2267478f8a96SJustin T. Gibbs xpt_done(ccb); 2268478f8a96SJustin T. Gibbs break; 2269478f8a96SJustin T. Gibbs 2270478f8a96SJustin T. Gibbs case XPT_CALC_GEOMETRY: 2271478f8a96SJustin T. Gibbs { 2272478f8a96SJustin T. Gibbs struct ccb_calc_geometry *ccg; 2273478f8a96SJustin T. Gibbs u_int32_t secs_per_cylinder; 2274478f8a96SJustin T. Gibbs u_int32_t size_mb; 2275478f8a96SJustin T. Gibbs 2276478f8a96SJustin T. Gibbs ccg = &ccb->ccg; 2277478f8a96SJustin T. Gibbs if (ccg->block_size == 0) { 2278bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 2279bfbab170SMatt Jacob "%d.%d XPT_CALC_GEOMETRY block size 0?", 2280bfbab170SMatt Jacob ccg->ccb_h.target_id, ccg->ccb_h.target_lun); 2281478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2282478f8a96SJustin T. Gibbs xpt_done(ccb); 2283478f8a96SJustin T. Gibbs break; 2284478f8a96SJustin T. Gibbs } 2285478f8a96SJustin T. Gibbs size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size); 2286478f8a96SJustin T. Gibbs if (size_mb > 1024) { 2287478f8a96SJustin T. Gibbs ccg->heads = 255; 2288478f8a96SJustin T. Gibbs ccg->secs_per_track = 63; 2289478f8a96SJustin T. Gibbs } else { 2290478f8a96SJustin T. Gibbs ccg->heads = 64; 2291478f8a96SJustin T. Gibbs ccg->secs_per_track = 32; 2292478f8a96SJustin T. Gibbs } 2293478f8a96SJustin T. Gibbs secs_per_cylinder = ccg->heads * ccg->secs_per_track; 2294478f8a96SJustin T. Gibbs ccg->cylinders = ccg->volume_size / secs_per_cylinder; 2295478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 2296478f8a96SJustin T. Gibbs xpt_done(ccb); 2297478f8a96SJustin T. Gibbs break; 2298478f8a96SJustin T. Gibbs } 2299478f8a96SJustin T. Gibbs case XPT_RESET_BUS: /* Reset the specified bus */ 2300ab6c4b31SMatt Jacob bus = cam_sim_bus(sim); 23015d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2302ab6c4b31SMatt Jacob error = isp_control(isp, ISPCTL_RESET_BUS, &bus); 23035d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2304478f8a96SJustin T. Gibbs if (error) 2305478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 23062b052931SMatt Jacob else { 2307ea6f23cdSMatt Jacob if (cam_sim_bus(sim) && isp->isp_path2 != NULL) 2308ea6f23cdSMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); 2309ea6f23cdSMatt Jacob else if (isp->isp_path != NULL) 23102b052931SMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path, NULL); 2311478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 23122b052931SMatt Jacob } 2313478f8a96SJustin T. Gibbs xpt_done(ccb); 2314478f8a96SJustin T. Gibbs break; 2315478f8a96SJustin T. Gibbs 2316478f8a96SJustin T. Gibbs case XPT_TERM_IO: /* Terminate the I/O process */ 2317478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2318478f8a96SJustin T. Gibbs xpt_done(ccb); 2319478f8a96SJustin T. Gibbs break; 2320478f8a96SJustin T. Gibbs 2321478f8a96SJustin T. Gibbs case XPT_PATH_INQ: /* Path routing inquiry */ 2322478f8a96SJustin T. Gibbs { 2323478f8a96SJustin T. Gibbs struct ccb_pathinq *cpi = &ccb->cpi; 2324478f8a96SJustin T. Gibbs 2325478f8a96SJustin T. Gibbs cpi->version_num = 1; 2326d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2327a1bc34c6SMatt Jacob cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO; 2328d81ba9d5SMatt Jacob #else 2329478f8a96SJustin T. Gibbs cpi->target_sprt = 0; 2330d81ba9d5SMatt Jacob #endif 2331478f8a96SJustin T. Gibbs cpi->hba_eng_cnt = 0; 23320470d791SMatt Jacob cpi->max_target = ISP_MAX_TARGETS(isp) - 1; 23330470d791SMatt Jacob cpi->max_lun = ISP_MAX_LUNS(isp) - 1; 23340470d791SMatt Jacob cpi->bus_id = cam_sim_bus(sim); 23354394c92fSMatt Jacob if (IS_FC(isp)) { 23364394c92fSMatt Jacob cpi->hba_misc = PIM_NOBUSRESET; 23370470d791SMatt Jacob /* 23380470d791SMatt Jacob * Because our loop ID can shift from time to time, 23390470d791SMatt Jacob * make our initiator ID out of range of our bus. 23400470d791SMatt Jacob */ 23410470d791SMatt Jacob cpi->initiator_id = cpi->max_target + 1; 23420470d791SMatt Jacob 23439deea857SKenneth D. Merry /* 23449deea857SKenneth D. Merry * Set base transfer capabilities for Fibre Channel. 23459deea857SKenneth D. Merry * Technically not correct because we don't know 23469deea857SKenneth D. Merry * what media we're running on top of- but we'll 23479deea857SKenneth D. Merry * look good if we always say 100MB/s. 23489deea857SKenneth D. Merry */ 23499deea857SKenneth D. Merry cpi->base_transfer_speed = 100000; 23500470d791SMatt Jacob cpi->hba_inquiry = PI_TAG_ABLE; 2351ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2352ab163f5fSMatt Jacob cpi->transport = XPORT_FC; 2353ab163f5fSMatt Jacob cpi->transport_version = 0; /* WHAT'S THIS FOR? */ 2354ab163f5fSMatt Jacob #endif 2355478f8a96SJustin T. Gibbs } else { 2356ea6f23cdSMatt Jacob sdparam *sdp = isp->isp_param; 2357ea6f23cdSMatt Jacob sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path)); 23580470d791SMatt Jacob cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; 23594394c92fSMatt Jacob cpi->hba_misc = 0; 2360ea6f23cdSMatt Jacob cpi->initiator_id = sdp->isp_initiator_id; 23619deea857SKenneth D. Merry cpi->base_transfer_speed = 3300; 2362ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2363ab163f5fSMatt Jacob cpi->transport = XPORT_SPI; 2364ab163f5fSMatt Jacob cpi->transport_version = 2; /* WHAT'S THIS FOR? */ 2365ab163f5fSMatt Jacob #endif 2366478f8a96SJustin T. Gibbs } 2367ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2368ab163f5fSMatt Jacob cpi->protocol = PROTO_SCSI; 2369ab163f5fSMatt Jacob cpi->protocol_version = SCSI_REV_2; 2370ab163f5fSMatt Jacob #endif 2371478f8a96SJustin T. Gibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 2372478f8a96SJustin T. Gibbs strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN); 2373478f8a96SJustin T. Gibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 2374478f8a96SJustin T. Gibbs cpi->unit_number = cam_sim_unit(sim); 2375478f8a96SJustin T. Gibbs cpi->ccb_h.status = CAM_REQ_CMP; 2376478f8a96SJustin T. Gibbs xpt_done(ccb); 2377478f8a96SJustin T. Gibbs break; 2378478f8a96SJustin T. Gibbs } 2379478f8a96SJustin T. Gibbs default: 2380478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 2381478f8a96SJustin T. Gibbs xpt_done(ccb); 2382478f8a96SJustin T. Gibbs break; 2383478f8a96SJustin T. Gibbs } 2384478f8a96SJustin T. Gibbs } 2385d3a9eb2eSMatt Jacob 2386d3a9eb2eSMatt Jacob #define ISPDDB (CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB) 2387d3a9eb2eSMatt Jacob void 2388c3055363SMatt Jacob isp_done(struct ccb_scsiio *sccb) 2389d3a9eb2eSMatt Jacob { 2390d3a9eb2eSMatt Jacob struct ispsoftc *isp = XS_ISP(sccb); 2391d3a9eb2eSMatt Jacob 2392d3a9eb2eSMatt Jacob if (XS_NOERR(sccb)) 2393d3a9eb2eSMatt Jacob XS_SETERR(sccb, CAM_REQ_CMP); 2394b85389e1SMatt Jacob 2395d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP && 2396d3a9eb2eSMatt Jacob (sccb->scsi_status != SCSI_STATUS_OK)) { 2397d3a9eb2eSMatt Jacob sccb->ccb_h.status &= ~CAM_STATUS_MASK; 239892a1e549SMatt Jacob if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) && 239992a1e549SMatt Jacob (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) { 240092a1e549SMatt Jacob sccb->ccb_h.status |= CAM_AUTOSENSE_FAIL; 240192a1e549SMatt Jacob } else { 2402d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 2403d3a9eb2eSMatt Jacob } 240492a1e549SMatt Jacob } 2405b85389e1SMatt Jacob 24060470d791SMatt Jacob sccb->ccb_h.status &= ~CAM_SIM_QUEUED; 2407d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2408d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 2409d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_DEV_QFRZN; 24100470d791SMatt Jacob xpt_freeze_devq(sccb->ccb_h.path, 1); 24110470d791SMatt Jacob if (sccb->scsi_status != SCSI_STATUS_OK) 2412b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2413b09b0095SMatt Jacob "freeze devq %d.%d %x %x", 2414b09b0095SMatt Jacob sccb->ccb_h.target_id, 24150470d791SMatt Jacob sccb->ccb_h.target_lun, sccb->ccb_h.status, 2416b09b0095SMatt Jacob sccb->scsi_status); 2417d3a9eb2eSMatt Jacob } 2418d3a9eb2eSMatt Jacob } 2419b85389e1SMatt Jacob 24200470d791SMatt Jacob /* 24210470d791SMatt Jacob * If we were frozen waiting resources, clear that we were frozen 24220470d791SMatt Jacob * waiting for resources. If we are no longer frozen, and the devq 24230470d791SMatt Jacob * isn't frozen, mark the completing CCB to have the XPT layer 24240470d791SMatt Jacob * release the simq. 24250470d791SMatt Jacob */ 242657c801f5SMatt Jacob if (isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE) { 242757c801f5SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_RESOURCE; 24280470d791SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 24290470d791SMatt Jacob if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 2430b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2431b09b0095SMatt Jacob "isp_done->relsimq"); 2432d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_RELEASE_SIMQ; 24330470d791SMatt Jacob } else { 2434b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2435b09b0095SMatt Jacob "isp_done->devq frozen"); 2436d3a9eb2eSMatt Jacob } 24370470d791SMatt Jacob } else { 2438b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2439b09b0095SMatt Jacob "isp_done -> simqfrozen = %x", 2440b09b0095SMatt Jacob isp->isp_osinfo.simqfrozen); 24410470d791SMatt Jacob } 24420470d791SMatt Jacob } 2443b85389e1SMatt Jacob if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) && 2444d3a9eb2eSMatt Jacob (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2445d3a9eb2eSMatt Jacob xpt_print_path(sccb->ccb_h.path); 24463c75bb14SMatt Jacob isp_prt(isp, ISP_LOGINFO, 24473c75bb14SMatt Jacob "cam completion status 0x%x", sccb->ccb_h.status); 2448d3a9eb2eSMatt Jacob } 2449b85389e1SMatt Jacob 2450b85389e1SMatt Jacob XS_CMD_S_DONE(sccb); 2451b85389e1SMatt Jacob if (XS_CMD_WDOG_P(sccb) == 0) { 2452b85389e1SMatt Jacob untimeout(isp_watchdog, (caddr_t)sccb, sccb->ccb_h.timeout_ch); 2453b85389e1SMatt Jacob if (XS_CMD_GRACE_P(sccb)) { 2454b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2455b09b0095SMatt Jacob "finished command on borrowed time"); 2456b85389e1SMatt Jacob } 2457b85389e1SMatt Jacob XS_CMD_S_CLEAR(sccb); 24585d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2459d3a9eb2eSMatt Jacob xpt_done((union ccb *) sccb); 24605d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2461d3a9eb2eSMatt Jacob } 2462b85389e1SMatt Jacob } 2463d3a9eb2eSMatt Jacob 2464cbf57b47SMatt Jacob int 24650470d791SMatt Jacob isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg) 2466cbf57b47SMatt Jacob { 2467ea6f23cdSMatt Jacob int bus, rv = 0; 2468cbf57b47SMatt Jacob switch (cmd) { 2469cbf57b47SMatt Jacob case ISPASYNC_NEW_TGT_PARAMS: 24700470d791SMatt Jacob { 2471ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2472ab163f5fSMatt Jacob struct ccb_trans_settings_scsi *scsi; 2473ab163f5fSMatt Jacob struct ccb_trans_settings_spi *spi; 2474ab163f5fSMatt Jacob #endif 2475cbf57b47SMatt Jacob int flags, tgt; 2476cbf57b47SMatt Jacob sdparam *sdp = isp->isp_param; 2477ab163f5fSMatt Jacob struct ccb_trans_settings cts; 2478cbf57b47SMatt Jacob struct cam_path *tmppath; 2479cbf57b47SMatt Jacob 2480ab163f5fSMatt Jacob bzero(&cts, sizeof (struct ccb_trans_settings)); 2481ab163f5fSMatt Jacob 2482cbf57b47SMatt Jacob tgt = *((int *)arg); 2483ea6f23cdSMatt Jacob bus = (tgt >> 16) & 0xffff; 2484ea6f23cdSMatt Jacob tgt &= 0xffff; 2485ea6f23cdSMatt Jacob sdp += bus; 248645c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2487cbf57b47SMatt Jacob if (xpt_create_path(&tmppath, NULL, 2488ea6f23cdSMatt Jacob cam_sim_path(bus? isp->isp_sim2 : isp->isp_sim), 2489ea6f23cdSMatt Jacob tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 249045c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2491bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 2492bfbab170SMatt Jacob "isp_async cannot make temp path for %d.%d", 2493bfbab170SMatt Jacob tgt, bus); 2494cbf57b47SMatt Jacob rv = -1; 2495cbf57b47SMatt Jacob break; 2496cbf57b47SMatt Jacob } 249745c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 24989ce9bdafSMatt Jacob flags = sdp->isp_devparam[tgt].actv_flags; 2499ab163f5fSMatt Jacob #ifdef CAM_NEW_TRAN_CODE 2500ab163f5fSMatt Jacob cts.type = CTS_TYPE_CURRENT_SETTINGS; 2501ab163f5fSMatt Jacob cts.protocol = PROTO_SCSI; 2502ab163f5fSMatt Jacob cts.transport = XPORT_SPI; 2503ab163f5fSMatt Jacob 2504ab163f5fSMatt Jacob scsi = &cts.proto_specific.scsi; 2505ab163f5fSMatt Jacob spi = &cts.xport_specific.spi; 2506ab163f5fSMatt Jacob 2507ab163f5fSMatt Jacob if (flags & DPARM_TQING) { 2508ab163f5fSMatt Jacob scsi->valid |= CTS_SCSI_VALID_TQ; 2509ab163f5fSMatt Jacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 2510ab163f5fSMatt Jacob spi->flags |= CTS_SPI_FLAGS_TAG_ENB; 2511ab163f5fSMatt Jacob } 2512ab163f5fSMatt Jacob 2513cbf57b47SMatt Jacob if (flags & DPARM_DISC) { 2514ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_DISC; 2515ab163f5fSMatt Jacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 2516ab163f5fSMatt Jacob } 2517ab163f5fSMatt Jacob spi->flags |= CTS_SPI_VALID_BUS_WIDTH; 2518ab163f5fSMatt Jacob if (flags & DPARM_WIDE) { 2519ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2520ab163f5fSMatt Jacob } else { 2521ab163f5fSMatt Jacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2522ab163f5fSMatt Jacob } 2523ab163f5fSMatt Jacob if (flags & DPARM_SYNC) { 2524ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 2525ab163f5fSMatt Jacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 25269ce9bdafSMatt Jacob spi->sync_period = sdp->isp_devparam[tgt].actv_period; 25279ce9bdafSMatt Jacob spi->sync_offset = sdp->isp_devparam[tgt].actv_offset; 2528ab163f5fSMatt Jacob } 2529ab163f5fSMatt Jacob #else 2530ab163f5fSMatt Jacob cts.flags = CCB_TRANS_CURRENT_SETTINGS; 2531ab163f5fSMatt Jacob cts.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2532ab163f5fSMatt Jacob if (flags & DPARM_DISC) { 2533ab163f5fSMatt Jacob cts.flags |= CCB_TRANS_DISC_ENB; 2534cbf57b47SMatt Jacob } 2535cbf57b47SMatt Jacob if (flags & DPARM_TQING) { 2536ab163f5fSMatt Jacob cts.flags |= CCB_TRANS_TAG_ENB; 2537cbf57b47SMatt Jacob } 2538ab163f5fSMatt Jacob cts.valid |= CCB_TRANS_BUS_WIDTH_VALID; 2539ab163f5fSMatt Jacob cts.bus_width = (flags & DPARM_WIDE)? 2540cbf57b47SMatt Jacob MSG_EXT_WDTR_BUS_8_BIT : MSG_EXT_WDTR_BUS_16_BIT; 25419ce9bdafSMatt Jacob cts.sync_period = sdp->isp_devparam[tgt].actv_period; 25429ce9bdafSMatt Jacob cts.sync_offset = sdp->isp_devparam[tgt].actv_offset; 2543cbf57b47SMatt Jacob if (flags & DPARM_SYNC) { 2544ab163f5fSMatt Jacob cts.valid |= 25454394c92fSMatt Jacob CCB_TRANS_SYNC_RATE_VALID | 2546cbf57b47SMatt Jacob CCB_TRANS_SYNC_OFFSET_VALID; 2547cbf57b47SMatt Jacob } 2548ab163f5fSMatt Jacob #endif 2549b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2550b09b0095SMatt Jacob "NEW_TGT_PARAMS bus %d tgt %d period %x offset %x flags %x", 25519ce9bdafSMatt Jacob bus, tgt, sdp->isp_devparam[tgt].actv_period, 25529ce9bdafSMatt Jacob sdp->isp_devparam[tgt].actv_offset, flags); 2553ab163f5fSMatt Jacob xpt_setup_ccb(&cts.ccb_h, tmppath, 1); 25545d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2555ab163f5fSMatt Jacob xpt_async(AC_TRANSFER_NEG, tmppath, &cts); 2556cbf57b47SMatt Jacob xpt_free_path(tmppath); 2557f44257c2SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2558cbf57b47SMatt Jacob break; 25590470d791SMatt Jacob } 256057c801f5SMatt Jacob case ISPASYNC_BUS_RESET: 2561ea6f23cdSMatt Jacob bus = *((int *)arg); 2562b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected", 2563b09b0095SMatt Jacob bus); 2564ea6f23cdSMatt Jacob if (bus > 0 && isp->isp_path2) { 25655d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2566ea6f23cdSMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); 25675d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2568ea6f23cdSMatt Jacob } else if (isp->isp_path) { 25695d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 257057c801f5SMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path, NULL); 25715d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 257257c801f5SMatt Jacob } 257357c801f5SMatt Jacob break; 25745d571944SMatt Jacob case ISPASYNC_LIP: 25755d571944SMatt Jacob if (isp->isp_path) { 25765d571944SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 25775d571944SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "LIP freeze simq"); 25785d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 25795d571944SMatt Jacob xpt_freeze_simq(isp->isp_sim, 1); 25805d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 25815d571944SMatt Jacob } 25825d571944SMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; 25835d571944SMatt Jacob } 25845d571944SMatt Jacob isp_prt(isp, ISP_LOGINFO, "LIP Received"); 25855d571944SMatt Jacob break; 25865d571944SMatt Jacob case ISPASYNC_LOOP_RESET: 25875d571944SMatt Jacob if (isp->isp_path) { 25885d571944SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 25895d571944SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 25905d571944SMatt Jacob "Loop Reset freeze simq"); 25915d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 25925d571944SMatt Jacob xpt_freeze_simq(isp->isp_sim, 1); 25935d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 25945d571944SMatt Jacob } 25955d571944SMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; 25965d571944SMatt Jacob } 25975d571944SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop Reset Received"); 25985d571944SMatt Jacob break; 259957c801f5SMatt Jacob case ISPASYNC_LOOP_DOWN: 260057c801f5SMatt Jacob if (isp->isp_path) { 26010470d791SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 26025d571944SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 2603b09b0095SMatt Jacob "loop down freeze simq"); 26045d571944SMatt Jacob ISPLOCK_2_CAMLOCK(isp); 260557c801f5SMatt Jacob xpt_freeze_simq(isp->isp_sim, 1); 26065d571944SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 26070470d791SMatt Jacob } 260857c801f5SMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; 260957c801f5SMatt Jacob } 2610b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop DOWN"); 261157c801f5SMatt Jacob break; 261257c801f5SMatt Jacob case ISPASYNC_LOOP_UP: 26135d571944SMatt Jacob /* 26145d571944SMatt Jacob * Now we just note that Loop has come up. We don't 26155d571944SMatt Jacob * actually do anything because we're waiting for a 26165d571944SMatt Jacob * Change Notify before activating the FC cleanup 26175d571944SMatt Jacob * thread to look at the state of the loop again. 26185d571944SMatt Jacob */ 2619b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop UP"); 262057c801f5SMatt Jacob break; 2621d6e5500fSMatt Jacob case ISPASYNC_PROMENADE: 26220470d791SMatt Jacob { 2623ab163f5fSMatt Jacob struct cam_path *tmppath; 2624b09b0095SMatt Jacob const char *fmt = "Target %d (Loop 0x%x) Port ID 0x%x " 2625d6e5500fSMatt Jacob "(role %s) %s\n Port WWN 0x%08x%08x\n Node WWN 0x%08x%08x"; 2626d6e5500fSMatt Jacob static const char *roles[4] = { 26270470d791SMatt Jacob "(none)", "Target", "Initiator", "Target/Initiator" 262857c801f5SMatt Jacob }; 262902ab3379SMatt Jacob fcparam *fcp = isp->isp_param; 263002ab3379SMatt Jacob int tgt = *((int *) arg); 2631f44257c2SMatt Jacob int is_tgt_mask = (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT); 263202ab3379SMatt Jacob struct lportdb *lp = &fcp->portdb[tgt]; 263302ab3379SMatt Jacob 2634b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, fmt, tgt, lp->loopid, lp->portid, 2635d6e5500fSMatt Jacob roles[lp->roles & 0x3], 2636d6e5500fSMatt Jacob (lp->valid)? "Arrived" : "Departed", 263702ab3379SMatt Jacob (u_int32_t) (lp->port_wwn >> 32), 263802ab3379SMatt Jacob (u_int32_t) (lp->port_wwn & 0xffffffffLL), 263902ab3379SMatt Jacob (u_int32_t) (lp->node_wwn >> 32), 264002ab3379SMatt Jacob (u_int32_t) (lp->node_wwn & 0xffffffffLL)); 2641ab163f5fSMatt Jacob 264245c9a36aSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 2643ab163f5fSMatt Jacob if (xpt_create_path(&tmppath, NULL, cam_sim_path(isp->isp_sim), 2644ab163f5fSMatt Jacob (target_id_t)tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 264545c9a36aSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2646ab163f5fSMatt Jacob break; 2647ab163f5fSMatt Jacob } 2648f44257c2SMatt Jacob /* 2649f44257c2SMatt Jacob * Policy: only announce targets. 2650f44257c2SMatt Jacob */ 2651f44257c2SMatt Jacob if (lp->roles & is_tgt_mask) { 2652f44257c2SMatt Jacob if (lp->valid) { 2653ab163f5fSMatt Jacob xpt_async(AC_FOUND_DEVICE, tmppath, NULL); 2654ab163f5fSMatt Jacob } else { 2655ab163f5fSMatt Jacob xpt_async(AC_LOST_DEVICE, tmppath, NULL); 2656ab163f5fSMatt Jacob } 2657f44257c2SMatt Jacob } 2658ab163f5fSMatt Jacob xpt_free_path(tmppath); 2659f44257c2SMatt Jacob CAMLOCK_2_ISPLOCK(isp); 26604394c92fSMatt Jacob break; 26614394c92fSMatt Jacob } 266257c801f5SMatt Jacob case ISPASYNC_CHANGE_NOTIFY: 2663f44257c2SMatt Jacob if (arg == ISPASYNC_CHANGE_PDB) { 26644b9d588eSMatt Jacob isp_prt(isp, ISP_LOGINFO, 2665f44257c2SMatt Jacob "Port Database Changed"); 2666f44257c2SMatt Jacob } else if (arg == ISPASYNC_CHANGE_SNS) { 26674b9d588eSMatt Jacob isp_prt(isp, ISP_LOGINFO, 26684b9d588eSMatt Jacob "Name Server Database Changed"); 26694b9d588eSMatt Jacob } 26705d571944SMatt Jacob cv_signal(&isp->isp_osinfo.kthread_cv); 267157c801f5SMatt Jacob break; 267202ab3379SMatt Jacob case ISPASYNC_FABRIC_DEV: 267302ab3379SMatt Jacob { 267470d2ccceSMatt Jacob int target, lrange; 267570d2ccceSMatt Jacob struct lportdb *lp = NULL; 267640cfc8feSMatt Jacob char *pt; 267740cfc8feSMatt Jacob sns_ganrsp_t *resp = (sns_ganrsp_t *) arg; 267802ab3379SMatt Jacob u_int32_t portid; 267940cfc8feSMatt Jacob u_int64_t wwpn, wwnn; 268002ab3379SMatt Jacob fcparam *fcp = isp->isp_param; 268102ab3379SMatt Jacob 268202ab3379SMatt Jacob portid = 268302ab3379SMatt Jacob (((u_int32_t) resp->snscb_port_id[0]) << 16) | 268402ab3379SMatt Jacob (((u_int32_t) resp->snscb_port_id[1]) << 8) | 268502ab3379SMatt Jacob (((u_int32_t) resp->snscb_port_id[2])); 268640cfc8feSMatt Jacob 268740cfc8feSMatt Jacob wwpn = 268802ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[0]) << 56) | 268902ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[1]) << 48) | 269002ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[2]) << 40) | 269102ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[3]) << 32) | 269202ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[4]) << 24) | 269302ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[5]) << 16) | 269402ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[6]) << 8) | 269502ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[7])); 269640cfc8feSMatt Jacob 269740cfc8feSMatt Jacob wwnn = 269840cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[0]) << 56) | 269940cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[1]) << 48) | 270040cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[2]) << 40) | 270140cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[3]) << 32) | 270240cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[4]) << 24) | 270340cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[5]) << 16) | 270440cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[6]) << 8) | 270540cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[7])); 270640cfc8feSMatt Jacob if (portid == 0 || wwpn == 0) { 270702ab3379SMatt Jacob break; 270802ab3379SMatt Jacob } 270940cfc8feSMatt Jacob 271040cfc8feSMatt Jacob switch (resp->snscb_port_type) { 271140cfc8feSMatt Jacob case 1: 271240cfc8feSMatt Jacob pt = " N_Port"; 271340cfc8feSMatt Jacob break; 271440cfc8feSMatt Jacob case 2: 271540cfc8feSMatt Jacob pt = " NL_Port"; 271640cfc8feSMatt Jacob break; 271740cfc8feSMatt Jacob case 3: 271840cfc8feSMatt Jacob pt = "F/NL_Port"; 271940cfc8feSMatt Jacob break; 272040cfc8feSMatt Jacob case 0x7f: 272140cfc8feSMatt Jacob pt = " Nx_Port"; 272240cfc8feSMatt Jacob break; 272340cfc8feSMatt Jacob case 0x81: 272440cfc8feSMatt Jacob pt = " F_port"; 272540cfc8feSMatt Jacob break; 272640cfc8feSMatt Jacob case 0x82: 272740cfc8feSMatt Jacob pt = " FL_Port"; 272840cfc8feSMatt Jacob break; 272940cfc8feSMatt Jacob case 0x84: 273040cfc8feSMatt Jacob pt = " E_port"; 273140cfc8feSMatt Jacob break; 273240cfc8feSMatt Jacob default: 273340cfc8feSMatt Jacob pt = "?"; 273440cfc8feSMatt Jacob break; 273540cfc8feSMatt Jacob } 2736b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, 2737b09b0095SMatt Jacob "%s @ 0x%x, Node 0x%08x%08x Port %08x%08x", 2738b09b0095SMatt Jacob pt, portid, ((u_int32_t) (wwnn >> 32)), ((u_int32_t) wwnn), 273940cfc8feSMatt Jacob ((u_int32_t) (wwpn >> 32)), ((u_int32_t) wwpn)); 274070d2ccceSMatt Jacob /* 274170d2ccceSMatt Jacob * We're only interested in SCSI_FCP types (for now) 274270d2ccceSMatt Jacob */ 274370d2ccceSMatt Jacob if ((resp->snscb_fc4_types[2] & 1) == 0) { 274402ab3379SMatt Jacob break; 274502ab3379SMatt Jacob } 274670d2ccceSMatt Jacob if (fcp->isp_topo != TOPO_F_PORT) 274770d2ccceSMatt Jacob lrange = FC_SNS_ID+1; 274870d2ccceSMatt Jacob else 274970d2ccceSMatt Jacob lrange = 0; 275070d2ccceSMatt Jacob /* 275170d2ccceSMatt Jacob * Is it already in our list? 275270d2ccceSMatt Jacob */ 275370d2ccceSMatt Jacob for (target = lrange; target < MAX_FC_TARG; target++) { 275470d2ccceSMatt Jacob if (target >= FL_PORT_ID && target <= FC_SNS_ID) { 275570d2ccceSMatt Jacob continue; 275670d2ccceSMatt Jacob } 275770d2ccceSMatt Jacob lp = &fcp->portdb[target]; 275870d2ccceSMatt Jacob if (lp->port_wwn == wwpn && lp->node_wwn == wwnn) { 275970d2ccceSMatt Jacob lp->fabric_dev = 1; 276070d2ccceSMatt Jacob break; 276170d2ccceSMatt Jacob } 276270d2ccceSMatt Jacob } 276302ab3379SMatt Jacob if (target < MAX_FC_TARG) { 276402ab3379SMatt Jacob break; 276502ab3379SMatt Jacob } 276670d2ccceSMatt Jacob for (target = lrange; target < MAX_FC_TARG; target++) { 276770d2ccceSMatt Jacob if (target >= FL_PORT_ID && target <= FC_SNS_ID) { 276870d2ccceSMatt Jacob continue; 276970d2ccceSMatt Jacob } 277002ab3379SMatt Jacob lp = &fcp->portdb[target]; 277170d2ccceSMatt Jacob if (lp->port_wwn == 0) { 277202ab3379SMatt Jacob break; 277302ab3379SMatt Jacob } 277470d2ccceSMatt Jacob } 277502ab3379SMatt Jacob if (target == MAX_FC_TARG) { 2776bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 2777bfbab170SMatt Jacob "no more space for fabric devices"); 277802ab3379SMatt Jacob break; 277902ab3379SMatt Jacob } 278040cfc8feSMatt Jacob lp->node_wwn = wwnn; 278140cfc8feSMatt Jacob lp->port_wwn = wwpn; 278202ab3379SMatt Jacob lp->portid = portid; 278370d2ccceSMatt Jacob lp->fabric_dev = 1; 278402ab3379SMatt Jacob break; 278502ab3379SMatt Jacob } 2786d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2787d81ba9d5SMatt Jacob case ISPASYNC_TARGET_MESSAGE: 2788d81ba9d5SMatt Jacob { 2789d81ba9d5SMatt Jacob tmd_msg_t *mp = arg; 2790b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2791b09b0095SMatt Jacob "bus %d iid %d tgt %d lun %d ttype %x tval %x msg[0]=%x", 2792b09b0095SMatt Jacob mp->nt_bus, (int) mp->nt_iid, (int) mp->nt_tgt, 2793b09b0095SMatt Jacob (int) mp->nt_lun, mp->nt_tagtype, mp->nt_tagval, 2794b09b0095SMatt Jacob mp->nt_msg[0]); 2795d81ba9d5SMatt Jacob break; 2796d81ba9d5SMatt Jacob } 2797d81ba9d5SMatt Jacob case ISPASYNC_TARGET_EVENT: 2798d81ba9d5SMatt Jacob { 2799d81ba9d5SMatt Jacob tmd_event_t *ep = arg; 2800b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2801b09b0095SMatt Jacob "bus %d event code 0x%x", ep->ev_bus, ep->ev_event); 2802d81ba9d5SMatt Jacob break; 2803d81ba9d5SMatt Jacob } 2804d81ba9d5SMatt Jacob case ISPASYNC_TARGET_ACTION: 2805d81ba9d5SMatt Jacob switch (((isphdr_t *)arg)->rqs_entry_type) { 2806cbf57b47SMatt Jacob default: 2807bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 2808bfbab170SMatt Jacob "event 0x%x for unhandled target action", 2809bfbab170SMatt Jacob ((isphdr_t *)arg)->rqs_entry_type); 2810d81ba9d5SMatt Jacob break; 2811d81ba9d5SMatt Jacob case RQSTYPE_ATIO: 2812d81ba9d5SMatt Jacob rv = isp_handle_platform_atio(isp, (at_entry_t *) arg); 2813d81ba9d5SMatt Jacob break; 2814d81ba9d5SMatt Jacob case RQSTYPE_ATIO2: 2815d81ba9d5SMatt Jacob rv = isp_handle_platform_atio2(isp, (at2_entry_t *)arg); 2816d81ba9d5SMatt Jacob break; 2817d81ba9d5SMatt Jacob case RQSTYPE_CTIO2: 2818d81ba9d5SMatt Jacob case RQSTYPE_CTIO: 2819d81ba9d5SMatt Jacob rv = isp_handle_platform_ctio(isp, arg); 2820d81ba9d5SMatt Jacob break; 2821d81ba9d5SMatt Jacob case RQSTYPE_ENABLE_LUN: 2822d81ba9d5SMatt Jacob case RQSTYPE_MODIFY_LUN: 2823d81ba9d5SMatt Jacob isp_cv_signal_rqe(isp, ((lun_entry_t *)arg)->le_status); 2824d81ba9d5SMatt Jacob break; 2825d81ba9d5SMatt Jacob } 2826d81ba9d5SMatt Jacob break; 2827d81ba9d5SMatt Jacob #endif 2828ab163f5fSMatt Jacob case ISPASYNC_FW_CRASH: 2829ab163f5fSMatt Jacob { 2830ab163f5fSMatt Jacob u_int16_t mbox1, mbox6; 2831ab163f5fSMatt Jacob mbox1 = ISP_READ(isp, OUTMAILBOX1); 2832ab163f5fSMatt Jacob if (IS_DUALBUS(isp)) { 2833ab163f5fSMatt Jacob mbox6 = ISP_READ(isp, OUTMAILBOX6); 2834ab163f5fSMatt Jacob } else { 2835ab163f5fSMatt Jacob mbox6 = 0; 2836ab163f5fSMatt Jacob } 2837ab163f5fSMatt Jacob isp_prt(isp, ISP_LOGERR, 2838ab163f5fSMatt Jacob "Internal Firmware on bus %d Error @ RISC Address 0x%x", 2839ab163f5fSMatt Jacob mbox6, mbox1); 2840ab163f5fSMatt Jacob isp_reinit(isp); 2841ab163f5fSMatt Jacob break; 2842ab163f5fSMatt Jacob } 2843be534d5fSMatt Jacob case ISPASYNC_UNHANDLED_RESPONSE: 2844be534d5fSMatt Jacob break; 2845d81ba9d5SMatt Jacob default: 2846b09b0095SMatt Jacob isp_prt(isp, ISP_LOGERR, "unknown isp_async event %d", cmd); 2847cbf57b47SMatt Jacob break; 2848cbf57b47SMatt Jacob } 2849cbf57b47SMatt Jacob return (rv); 2850cbf57b47SMatt Jacob } 2851cbf57b47SMatt Jacob 285292718a7fSMatt Jacob 285392718a7fSMatt Jacob /* 285492718a7fSMatt Jacob * Locks are held before coming here. 285592718a7fSMatt Jacob */ 285692718a7fSMatt Jacob void 285792718a7fSMatt Jacob isp_uninit(struct ispsoftc *isp) 285892718a7fSMatt Jacob { 2859ea6f23cdSMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_RESET); 286092718a7fSMatt Jacob DISABLE_INTS(isp); 286192718a7fSMatt Jacob } 2862b09b0095SMatt Jacob 2863b09b0095SMatt Jacob void 2864b09b0095SMatt Jacob isp_prt(struct ispsoftc *isp, int level, const char *fmt, ...) 2865b09b0095SMatt Jacob { 2866b09b0095SMatt Jacob va_list ap; 2867b09b0095SMatt Jacob if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) { 2868b09b0095SMatt Jacob return; 2869b09b0095SMatt Jacob } 28703c75bb14SMatt Jacob printf("%s: ", device_get_nameunit(isp->isp_dev)); 2871b09b0095SMatt Jacob va_start(ap, fmt); 2872b09b0095SMatt Jacob vprintf(fmt, ap); 2873b09b0095SMatt Jacob va_end(ap); 2874b09b0095SMatt Jacob printf("\n"); 2875b09b0095SMatt Jacob } 2876