1c3aac50fSPeter Wemm /* $FreeBSD$ */ 26054c3f6SMatt Jacob /* 36054c3f6SMatt Jacob * Platform (FreeBSD) dependent common attachment code for Qlogic adapters. 46054c3f6SMatt Jacob * 5b6b6ad2fSMatt Jacob * Copyright (c) 1997, 1998, 1999, 2000 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> 293ea883b4SMatt Jacob #include <machine/stdarg.h> /* for use by isp_prt below */ 306054c3f6SMatt Jacob 31f6e75de2SMatt Jacob static void isp_intr_enable(void *); 320470d791SMatt Jacob static void isp_cam_async(void *, u_int32_t, struct cam_path *, void *); 330470d791SMatt Jacob static void isp_poll(struct cam_sim *); 340470d791SMatt Jacob static void isp_relsim(void *); 35b85389e1SMatt Jacob static timeout_t isp_watchdog; 36d81ba9d5SMatt Jacob static void isp_action(struct cam_sim *, union ccb *); 370470d791SMatt Jacob 38cc8df88bSMatt Jacob 39d81ba9d5SMatt Jacob static struct ispsoftc *isplist = NULL; 40478f8a96SJustin T. Gibbs 41478f8a96SJustin T. Gibbs void 42c3055363SMatt Jacob isp_attach(struct ispsoftc *isp) 43478f8a96SJustin T. Gibbs { 44ea6f23cdSMatt Jacob int primary, secondary; 45478f8a96SJustin T. Gibbs struct ccb_setasync csa; 46478f8a96SJustin T. Gibbs struct cam_devq *devq; 47ea6f23cdSMatt Jacob struct cam_sim *sim; 48ea6f23cdSMatt Jacob struct cam_path *path; 49478f8a96SJustin T. Gibbs 50478f8a96SJustin T. Gibbs /* 51ea6f23cdSMatt Jacob * Establish (in case of 12X0) which bus is the primary. 52ea6f23cdSMatt Jacob */ 53ea6f23cdSMatt Jacob 54ea6f23cdSMatt Jacob primary = 0; 55ea6f23cdSMatt Jacob secondary = 1; 56ea6f23cdSMatt Jacob 57ea6f23cdSMatt Jacob /* 58ea6f23cdSMatt Jacob * Create the device queue for our SIM(s). 59478f8a96SJustin T. Gibbs */ 60ab6c4b31SMatt Jacob devq = cam_simq_alloc(isp->isp_maxcmds); 61478f8a96SJustin T. Gibbs if (devq == NULL) { 62478f8a96SJustin T. Gibbs return; 63478f8a96SJustin T. Gibbs } 64478f8a96SJustin T. Gibbs 65478f8a96SJustin T. Gibbs /* 66ea6f23cdSMatt Jacob * Construct our SIM entry. 67478f8a96SJustin T. Gibbs */ 68ea6f23cdSMatt Jacob sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp, 69ab6c4b31SMatt Jacob isp->isp_unit, 1, isp->isp_maxcmds, devq); 70ea6f23cdSMatt Jacob if (sim == NULL) { 71478f8a96SJustin T. Gibbs cam_simq_free(devq); 72478f8a96SJustin T. Gibbs return; 73478f8a96SJustin T. Gibbs } 74f6e75de2SMatt Jacob 75f6e75de2SMatt Jacob isp->isp_osinfo.ehook.ich_func = isp_intr_enable; 76f6e75de2SMatt Jacob isp->isp_osinfo.ehook.ich_arg = isp; 77f6e75de2SMatt Jacob if (config_intrhook_establish(&isp->isp_osinfo.ehook) != 0) { 78bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 79bfbab170SMatt Jacob "could not establish interrupt enable hook"); 80f6e75de2SMatt Jacob cam_sim_free(sim, TRUE); 81f6e75de2SMatt Jacob return; 82f6e75de2SMatt Jacob } 83f6e75de2SMatt Jacob 84ea6f23cdSMatt Jacob if (xpt_bus_register(sim, primary) != CAM_SUCCESS) { 85ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 86478f8a96SJustin T. Gibbs return; 87478f8a96SJustin T. Gibbs } 88478f8a96SJustin T. Gibbs 89ea6f23cdSMatt Jacob if (xpt_create_path(&path, NULL, cam_sim_path(sim), 90478f8a96SJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 91ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 92ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 93478f8a96SJustin T. Gibbs return; 94478f8a96SJustin T. Gibbs } 95478f8a96SJustin T. Gibbs 96ea6f23cdSMatt Jacob xpt_setup_ccb(&csa.ccb_h, path, 5); 97478f8a96SJustin T. Gibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 98478f8a96SJustin T. Gibbs csa.event_enable = AC_LOST_DEVICE; 99cbf57b47SMatt Jacob csa.callback = isp_cam_async; 100ea6f23cdSMatt Jacob csa.callback_arg = sim; 101478f8a96SJustin T. Gibbs xpt_action((union ccb *)&csa); 102ea6f23cdSMatt Jacob isp->isp_sim = sim; 103ea6f23cdSMatt Jacob isp->isp_path = path; 104478f8a96SJustin T. Gibbs 105ea6f23cdSMatt Jacob /* 106ea6f23cdSMatt Jacob * If we have a second channel, construct SIM entry for that. 107ea6f23cdSMatt Jacob */ 10822e1dc85SMatt Jacob if (IS_DUALBUS(isp)) { 109ea6f23cdSMatt Jacob sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp, 110ab6c4b31SMatt Jacob isp->isp_unit, 1, isp->isp_maxcmds, devq); 111ea6f23cdSMatt Jacob if (sim == NULL) { 112ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 113ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 114ea6f23cdSMatt Jacob cam_simq_free(devq); 115ea6f23cdSMatt Jacob return; 116ea6f23cdSMatt Jacob } 117ea6f23cdSMatt Jacob if (xpt_bus_register(sim, secondary) != CAM_SUCCESS) { 118ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 119ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 120ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 121ea6f23cdSMatt Jacob return; 122ea6f23cdSMatt Jacob } 123ea6f23cdSMatt Jacob 124ea6f23cdSMatt Jacob if (xpt_create_path(&path, NULL, cam_sim_path(sim), 125ea6f23cdSMatt Jacob CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 126ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 127ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 128ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 129ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 130ea6f23cdSMatt Jacob return; 131ea6f23cdSMatt Jacob } 132ea6f23cdSMatt Jacob 133ea6f23cdSMatt Jacob xpt_setup_ccb(&csa.ccb_h, path, 5); 134ea6f23cdSMatt Jacob csa.ccb_h.func_code = XPT_SASYNC_CB; 135ea6f23cdSMatt Jacob csa.event_enable = AC_LOST_DEVICE; 136ea6f23cdSMatt Jacob csa.callback = isp_cam_async; 137ea6f23cdSMatt Jacob csa.callback_arg = sim; 138ea6f23cdSMatt Jacob xpt_action((union ccb *)&csa); 139ea6f23cdSMatt Jacob isp->isp_sim2 = sim; 140ea6f23cdSMatt Jacob isp->isp_path2 = path; 141ea6f23cdSMatt Jacob } 142478f8a96SJustin T. Gibbs isp->isp_state = ISP_RUNSTATE; 143b85389e1SMatt Jacob ENABLE_INTS(isp); 144d81ba9d5SMatt Jacob if (isplist == NULL) { 145d81ba9d5SMatt Jacob isplist = isp; 146d81ba9d5SMatt Jacob } else { 147d81ba9d5SMatt Jacob struct ispsoftc *tmp = isplist; 148d81ba9d5SMatt Jacob while (tmp->isp_osinfo.next) { 149d81ba9d5SMatt Jacob tmp = tmp->isp_osinfo.next; 150d81ba9d5SMatt Jacob } 151d81ba9d5SMatt Jacob tmp->isp_osinfo.next = isp; 152478f8a96SJustin T. Gibbs } 1530470d791SMatt Jacob } 154478f8a96SJustin T. Gibbs 155f6e75de2SMatt Jacob static void 156f6e75de2SMatt Jacob isp_intr_enable(void *arg) 157f6e75de2SMatt Jacob { 158f6e75de2SMatt Jacob struct ispsoftc *isp = arg; 159f6e75de2SMatt Jacob ENABLE_INTS(isp); 160f6e75de2SMatt Jacob isp->isp_osinfo.intsok = 1; 161f6e75de2SMatt Jacob /* Release our hook so that the boot can continue. */ 162f6e75de2SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 163f6e75de2SMatt Jacob } 164d81ba9d5SMatt Jacob 165d81ba9d5SMatt Jacob /* 166d81ba9d5SMatt Jacob * Put the target mode functions here, because some are inlines 167d81ba9d5SMatt Jacob */ 168d81ba9d5SMatt Jacob 169d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 170d81ba9d5SMatt Jacob 171d81ba9d5SMatt Jacob static __inline int is_lun_enabled(struct ispsoftc *, lun_id_t); 172d81ba9d5SMatt Jacob static __inline int are_any_luns_enabled(struct ispsoftc *); 173d81ba9d5SMatt Jacob static __inline tstate_t *get_lun_statep(struct ispsoftc *, lun_id_t); 174d81ba9d5SMatt Jacob static __inline void rls_lun_statep(struct ispsoftc *, tstate_t *); 175d81ba9d5SMatt Jacob static __inline int isp_psema_sig_rqe(struct ispsoftc *); 176d81ba9d5SMatt Jacob static __inline int isp_cv_wait_timed_rqe(struct ispsoftc *, int); 177d81ba9d5SMatt Jacob static __inline void isp_cv_signal_rqe(struct ispsoftc *, int); 178d81ba9d5SMatt Jacob static __inline void isp_vsema_rqe(struct ispsoftc *); 179d81ba9d5SMatt Jacob static cam_status 180d81ba9d5SMatt Jacob create_lun_state(struct ispsoftc *, struct cam_path *, tstate_t **); 181d81ba9d5SMatt Jacob static void destroy_lun_state(struct ispsoftc *, tstate_t *); 182d81ba9d5SMatt Jacob static void isp_en_lun(struct ispsoftc *, union ccb *); 183d81ba9d5SMatt Jacob static cam_status isp_abort_tgt_ccb(struct ispsoftc *, union ccb *); 184d81ba9d5SMatt Jacob static cam_status isp_target_start_ctio(struct ispsoftc *, union ccb *); 185f48ce188SMatt Jacob static cam_status isp_target_putback_atio(struct ispsoftc *, union ccb *); 186f48ce188SMatt Jacob static timeout_t isp_refire_putback_atio; 187d81ba9d5SMatt Jacob 188d81ba9d5SMatt Jacob static int isp_handle_platform_atio(struct ispsoftc *, at_entry_t *); 189d81ba9d5SMatt Jacob static int isp_handle_platform_atio2(struct ispsoftc *, at2_entry_t *); 190d81ba9d5SMatt Jacob static int isp_handle_platform_ctio(struct ispsoftc *, void *); 191f48ce188SMatt Jacob static void isp_handle_platform_ctio_part2(struct ispsoftc *, union ccb *); 192d81ba9d5SMatt Jacob 193d81ba9d5SMatt Jacob static __inline int 194d81ba9d5SMatt Jacob is_lun_enabled(struct ispsoftc *isp, lun_id_t lun) 195d81ba9d5SMatt Jacob { 196d81ba9d5SMatt Jacob tstate_t *tptr; 197f6e75de2SMatt Jacob ISP_LOCK(isp); 198d81ba9d5SMatt Jacob if ((tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(lun)]) == NULL) { 199f6e75de2SMatt Jacob ISP_UNLOCK(isp); 200d81ba9d5SMatt Jacob return (0); 201d81ba9d5SMatt Jacob } 202d81ba9d5SMatt Jacob do { 203d81ba9d5SMatt Jacob if (tptr->lun == (lun_id_t) lun) { 204f6e75de2SMatt Jacob ISP_UNLOCK(isp); 205d81ba9d5SMatt Jacob return (1); 206d81ba9d5SMatt Jacob } 207d81ba9d5SMatt Jacob } while ((tptr = tptr->next) != NULL); 208f6e75de2SMatt Jacob ISP_UNLOCK(isp); 209d81ba9d5SMatt Jacob return (0); 210d81ba9d5SMatt Jacob } 211d81ba9d5SMatt Jacob 212d81ba9d5SMatt Jacob static __inline int 213d81ba9d5SMatt Jacob are_any_luns_enabled(struct ispsoftc *isp) 214d81ba9d5SMatt Jacob { 215d81ba9d5SMatt Jacob int i; 216d81ba9d5SMatt Jacob for (i = 0; i < LUN_HASH_SIZE; i++) { 217d81ba9d5SMatt Jacob if (isp->isp_osinfo.lun_hash[i]) { 218d81ba9d5SMatt Jacob return (1); 219d81ba9d5SMatt Jacob } 220d81ba9d5SMatt Jacob } 221d81ba9d5SMatt Jacob return (0); 222d81ba9d5SMatt Jacob } 223d81ba9d5SMatt Jacob 224d81ba9d5SMatt Jacob static __inline tstate_t * 225d81ba9d5SMatt Jacob get_lun_statep(struct ispsoftc *isp, lun_id_t lun) 226d81ba9d5SMatt Jacob { 227d81ba9d5SMatt Jacob tstate_t *tptr; 228d81ba9d5SMatt Jacob 229f6e75de2SMatt Jacob ISP_LOCK(isp); 230d81ba9d5SMatt Jacob if (lun == CAM_LUN_WILDCARD) { 231d81ba9d5SMatt Jacob tptr = &isp->isp_osinfo.tsdflt; 232d81ba9d5SMatt Jacob tptr->hold++; 233f6e75de2SMatt Jacob ISP_UNLOCK(isp); 234d81ba9d5SMatt Jacob return (tptr); 235d81ba9d5SMatt Jacob } else { 236d81ba9d5SMatt Jacob tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(lun)]; 237d81ba9d5SMatt Jacob } 238d81ba9d5SMatt Jacob if (tptr == NULL) { 239f6e75de2SMatt Jacob ISP_UNLOCK(isp); 240d81ba9d5SMatt Jacob return (NULL); 241d81ba9d5SMatt Jacob } 242d81ba9d5SMatt Jacob 243d81ba9d5SMatt Jacob do { 244d81ba9d5SMatt Jacob if (tptr->lun == lun) { 245d81ba9d5SMatt Jacob tptr->hold++; 246f6e75de2SMatt Jacob ISP_UNLOCK(isp); 247d81ba9d5SMatt Jacob return (tptr); 248d81ba9d5SMatt Jacob } 249d81ba9d5SMatt Jacob } while ((tptr = tptr->next) != NULL); 250f6e75de2SMatt Jacob ISP_UNLOCK(isp); 251d81ba9d5SMatt Jacob return (tptr); 252d81ba9d5SMatt Jacob } 253d81ba9d5SMatt Jacob 254d81ba9d5SMatt Jacob static __inline void 255d81ba9d5SMatt Jacob rls_lun_statep(struct ispsoftc *isp, tstate_t *tptr) 256d81ba9d5SMatt Jacob { 257d81ba9d5SMatt Jacob if (tptr->hold) 258d81ba9d5SMatt Jacob tptr->hold--; 259d81ba9d5SMatt Jacob } 260d81ba9d5SMatt Jacob 261d81ba9d5SMatt Jacob static __inline int 262d81ba9d5SMatt Jacob isp_psema_sig_rqe(struct ispsoftc *isp) 263d81ba9d5SMatt Jacob { 264f6e75de2SMatt Jacob ISP_LOCK(isp); 265d81ba9d5SMatt Jacob while (isp->isp_osinfo.tmflags & TM_BUSY) { 266d81ba9d5SMatt Jacob isp->isp_osinfo.tmflags |= TM_WANTED; 267d81ba9d5SMatt Jacob if (tsleep(&isp->isp_osinfo.tmflags, PRIBIO|PCATCH, "i0", 0)) { 268f6e75de2SMatt Jacob ISP_UNLOCK(isp); 269d81ba9d5SMatt Jacob return (-1); 270d81ba9d5SMatt Jacob } 271d81ba9d5SMatt Jacob isp->isp_osinfo.tmflags |= TM_BUSY; 272d81ba9d5SMatt Jacob } 273f6e75de2SMatt Jacob ISP_UNLOCK(isp); 274d81ba9d5SMatt Jacob return (0); 275d81ba9d5SMatt Jacob } 276d81ba9d5SMatt Jacob 277d81ba9d5SMatt Jacob static __inline int 278d81ba9d5SMatt Jacob isp_cv_wait_timed_rqe(struct ispsoftc *isp, int timo) 279d81ba9d5SMatt Jacob { 280f6e75de2SMatt Jacob ISP_LOCK(isp); 281d81ba9d5SMatt Jacob if (tsleep(&isp->isp_osinfo.rstatus, PRIBIO, "qt1", timo)) { 282f6e75de2SMatt Jacob ISP_UNLOCK(isp); 283d81ba9d5SMatt Jacob return (-1); 284d81ba9d5SMatt Jacob } 285f6e75de2SMatt Jacob ISP_UNLOCK(isp); 286d81ba9d5SMatt Jacob return (0); 287d81ba9d5SMatt Jacob } 288d81ba9d5SMatt Jacob 289d81ba9d5SMatt Jacob static __inline void 290d81ba9d5SMatt Jacob isp_cv_signal_rqe(struct ispsoftc *isp, int status) 291d81ba9d5SMatt Jacob { 292d81ba9d5SMatt Jacob isp->isp_osinfo.rstatus = status; 293d81ba9d5SMatt Jacob wakeup(&isp->isp_osinfo.rstatus); 294d81ba9d5SMatt Jacob } 295d81ba9d5SMatt Jacob 296d81ba9d5SMatt Jacob static __inline void 297d81ba9d5SMatt Jacob isp_vsema_rqe(struct ispsoftc *isp) 298d81ba9d5SMatt Jacob { 299f6e75de2SMatt Jacob ISP_LOCK(isp); 300d81ba9d5SMatt Jacob if (isp->isp_osinfo.tmflags & TM_WANTED) { 301d81ba9d5SMatt Jacob isp->isp_osinfo.tmflags &= ~TM_WANTED; 302d81ba9d5SMatt Jacob wakeup(&isp->isp_osinfo.tmflags); 303d81ba9d5SMatt Jacob } 304d81ba9d5SMatt Jacob isp->isp_osinfo.tmflags &= ~TM_BUSY; 305f6e75de2SMatt Jacob ISP_UNLOCK(isp); 306d81ba9d5SMatt Jacob } 307d81ba9d5SMatt Jacob 308d81ba9d5SMatt Jacob static cam_status 309d81ba9d5SMatt Jacob create_lun_state(struct ispsoftc *isp, struct cam_path *path, tstate_t **rslt) 310d81ba9d5SMatt Jacob { 311d81ba9d5SMatt Jacob cam_status status; 312d81ba9d5SMatt Jacob lun_id_t lun; 313d81ba9d5SMatt Jacob tstate_t *tptr, *new; 314d81ba9d5SMatt Jacob 315d81ba9d5SMatt Jacob lun = xpt_path_lun_id(path); 316d81ba9d5SMatt Jacob if (lun < 0) { 317d81ba9d5SMatt Jacob return (CAM_LUN_INVALID); 318d81ba9d5SMatt Jacob } 319d81ba9d5SMatt Jacob if (is_lun_enabled(isp, lun)) { 320d81ba9d5SMatt Jacob return (CAM_LUN_ALRDY_ENA); 321d81ba9d5SMatt Jacob } 322ea8b5a9aSDavid Malone new = (tstate_t *) malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO); 323d81ba9d5SMatt Jacob if (new == NULL) { 324d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 325d81ba9d5SMatt Jacob } 326d81ba9d5SMatt Jacob 327d81ba9d5SMatt Jacob status = xpt_create_path(&new->owner, NULL, xpt_path_path_id(path), 328d81ba9d5SMatt Jacob xpt_path_target_id(path), xpt_path_lun_id(path)); 329d81ba9d5SMatt Jacob if (status != CAM_REQ_CMP) { 330d81ba9d5SMatt Jacob free(new, M_DEVBUF); 331d81ba9d5SMatt Jacob return (status); 332d81ba9d5SMatt Jacob } 333d81ba9d5SMatt Jacob new->lun = lun; 334d81ba9d5SMatt Jacob SLIST_INIT(&new->atios); 335d81ba9d5SMatt Jacob SLIST_INIT(&new->inots); 336d81ba9d5SMatt Jacob new->hold = 1; 337d81ba9d5SMatt Jacob 338f6e75de2SMatt Jacob ISP_LOCK(isp); 339d81ba9d5SMatt Jacob if ((tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(lun)]) == NULL) { 340d81ba9d5SMatt Jacob isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(lun)] = new; 341d81ba9d5SMatt Jacob } else { 342d81ba9d5SMatt Jacob while (tptr->next) 343d81ba9d5SMatt Jacob tptr = tptr->next; 344d81ba9d5SMatt Jacob tptr->next = new; 345d81ba9d5SMatt Jacob } 346f6e75de2SMatt Jacob ISP_UNLOCK(isp); 347d81ba9d5SMatt Jacob *rslt = new; 348d81ba9d5SMatt Jacob return (CAM_REQ_CMP); 349d81ba9d5SMatt Jacob } 350d81ba9d5SMatt Jacob 351d81ba9d5SMatt Jacob static __inline void 352d81ba9d5SMatt Jacob destroy_lun_state(struct ispsoftc *isp, tstate_t *tptr) 353d81ba9d5SMatt Jacob { 354d81ba9d5SMatt Jacob tstate_t *lw, *pw; 355d81ba9d5SMatt Jacob 356f6e75de2SMatt Jacob ISP_LOCK(isp); 357d81ba9d5SMatt Jacob if (tptr->hold) { 358f6e75de2SMatt Jacob ISP_UNLOCK(isp); 359d81ba9d5SMatt Jacob return; 360d81ba9d5SMatt Jacob } 361d81ba9d5SMatt Jacob pw = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(tptr->lun)]; 362d81ba9d5SMatt Jacob if (pw == NULL) { 363f6e75de2SMatt Jacob ISP_UNLOCK(isp); 364d81ba9d5SMatt Jacob return; 365d81ba9d5SMatt Jacob } else if (pw->lun == tptr->lun) { 366d81ba9d5SMatt Jacob isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(tptr->lun)] = pw->next; 367d81ba9d5SMatt Jacob } else { 368d81ba9d5SMatt Jacob lw = pw; 369d81ba9d5SMatt Jacob pw = lw->next; 370d81ba9d5SMatt Jacob while (pw) { 371d81ba9d5SMatt Jacob if (pw->lun == tptr->lun) { 372d81ba9d5SMatt Jacob lw->next = pw->next; 373d81ba9d5SMatt Jacob break; 374d81ba9d5SMatt Jacob } 375d81ba9d5SMatt Jacob lw = pw; 376d81ba9d5SMatt Jacob pw = pw->next; 377d81ba9d5SMatt Jacob } 378d81ba9d5SMatt Jacob if (pw == NULL) { 379f6e75de2SMatt Jacob ISP_UNLOCK(isp); 380d81ba9d5SMatt Jacob return; 381d81ba9d5SMatt Jacob } 382d81ba9d5SMatt Jacob } 383d81ba9d5SMatt Jacob free(tptr, M_DEVBUF); 384f6e75de2SMatt Jacob ISP_UNLOCK(isp); 385d81ba9d5SMatt Jacob } 386d81ba9d5SMatt Jacob 387d81ba9d5SMatt Jacob static void 388d81ba9d5SMatt Jacob isp_en_lun(struct ispsoftc *isp, union ccb *ccb) 389d81ba9d5SMatt Jacob { 390d81ba9d5SMatt Jacob const char *lfmt = "Lun now %sabled for target mode\n"; 391d81ba9d5SMatt Jacob struct ccb_en_lun *cel = &ccb->cel; 392d81ba9d5SMatt Jacob tstate_t *tptr; 393d81ba9d5SMatt Jacob u_int16_t rstat; 394b6b6ad2fSMatt Jacob int bus, frozen = 0; 395d81ba9d5SMatt Jacob lun_id_t lun; 396d81ba9d5SMatt Jacob target_id_t tgt; 397d81ba9d5SMatt Jacob 398d81ba9d5SMatt Jacob 399d81ba9d5SMatt Jacob bus = XS_CHANNEL(ccb); 400d81ba9d5SMatt Jacob tgt = ccb->ccb_h.target_id; 401d81ba9d5SMatt Jacob lun = ccb->ccb_h.target_lun; 402d81ba9d5SMatt Jacob 403d81ba9d5SMatt Jacob /* 404d81ba9d5SMatt Jacob * Do some sanity checking first. 405d81ba9d5SMatt Jacob */ 406d81ba9d5SMatt Jacob 4072ad50ca5SMatt Jacob if (lun < 0 || lun >= (lun_id_t) isp->isp_maxluns) { 408d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 409d81ba9d5SMatt Jacob return; 410d81ba9d5SMatt Jacob } 4112ad50ca5SMatt Jacob if (IS_SCSI(isp)) { 412d81ba9d5SMatt Jacob if (tgt != CAM_TARGET_WILDCARD && 413d81ba9d5SMatt Jacob tgt != ((sdparam *) isp->isp_param)->isp_initiator_id) { 414d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_TID_INVALID; 415d81ba9d5SMatt Jacob return; 416d81ba9d5SMatt Jacob } 417d81ba9d5SMatt Jacob } else { 418d81ba9d5SMatt Jacob if (tgt != CAM_TARGET_WILDCARD && 419d81ba9d5SMatt Jacob tgt != ((fcparam *) isp->isp_param)->isp_loopid) { 420d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_TID_INVALID; 421d81ba9d5SMatt Jacob return; 422d81ba9d5SMatt Jacob } 423d81ba9d5SMatt Jacob } 424d81ba9d5SMatt Jacob 425b6b6ad2fSMatt Jacob /* 426b6b6ad2fSMatt Jacob * If Fibre Channel, stop and drain all activity to this bus. 427b6b6ad2fSMatt Jacob */ 428b6b6ad2fSMatt Jacob if (IS_FC(isp)) { 429b6b6ad2fSMatt Jacob ISP_LOCK(isp); 430b6b6ad2fSMatt Jacob frozen = 1; 431b6b6ad2fSMatt Jacob xpt_freeze_simq(isp->isp_sim, 1); 432b6b6ad2fSMatt Jacob isp->isp_osinfo.drain = 1; 433b6b6ad2fSMatt Jacob /* ISP_UNLOCK(isp); XXX NEED CV_WAIT HERE XXX */ 434b6b6ad2fSMatt Jacob while (isp->isp_osinfo.drain) { 435b6b6ad2fSMatt Jacob tsleep(&isp->isp_osinfo.drain, PRIBIO, "ispdrain", 0); 436b6b6ad2fSMatt Jacob } 437b6b6ad2fSMatt Jacob ISP_UNLOCK(isp); 438b6b6ad2fSMatt Jacob } 439b6b6ad2fSMatt Jacob 440b6b6ad2fSMatt Jacob /* 441b6b6ad2fSMatt Jacob * Check to see if we're enabling on fibre channel and 442b6b6ad2fSMatt Jacob * don't yet have a notion of who the heck we are (no 443b6b6ad2fSMatt Jacob * loop yet). 444b6b6ad2fSMatt Jacob */ 445b6b6ad2fSMatt Jacob if (IS_FC(isp) && cel->enable && 446b6b6ad2fSMatt Jacob (isp->isp_osinfo.tmflags & TM_TMODE_ENABLED) == 0) { 447b6b6ad2fSMatt Jacob int rv= 2 * 1000000; 448b6b6ad2fSMatt Jacob fcparam *fcp = isp->isp_param; 449b6b6ad2fSMatt Jacob 450b6b6ad2fSMatt Jacob ISP_LOCK(isp); 451b6b6ad2fSMatt Jacob rv = isp_control(isp, ISPCTL_FCLINK_TEST, &rv); 452b6b6ad2fSMatt Jacob ISP_UNLOCK(isp); 453b6b6ad2fSMatt Jacob if (rv || fcp->isp_fwstate != FW_READY) { 454b6b6ad2fSMatt Jacob xpt_print_path(ccb->ccb_h.path); 455b6b6ad2fSMatt Jacob printf("link status not good yet\n"); 456b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 457b6b6ad2fSMatt Jacob if (frozen) 458b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 459b6b6ad2fSMatt Jacob return; 460b6b6ad2fSMatt Jacob } 461b6b6ad2fSMatt Jacob ISP_LOCK(isp); 462b6b6ad2fSMatt Jacob rv = isp_control(isp, ISPCTL_PDB_SYNC, NULL); 463b6b6ad2fSMatt Jacob ISP_UNLOCK(isp); 464b6b6ad2fSMatt Jacob if (rv || fcp->isp_fwstate != FW_READY) { 465b6b6ad2fSMatt Jacob xpt_print_path(ccb->ccb_h.path); 466b6b6ad2fSMatt Jacob printf("could not get a good port database read\n"); 467b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 468b6b6ad2fSMatt Jacob if (frozen) 469b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 470b6b6ad2fSMatt Jacob return; 471b6b6ad2fSMatt Jacob } 472b6b6ad2fSMatt Jacob } 473b6b6ad2fSMatt Jacob 474b6b6ad2fSMatt Jacob 475b6b6ad2fSMatt Jacob /* 476b6b6ad2fSMatt Jacob * Next check to see whether this is a target/lun wildcard action. 477b6b6ad2fSMatt Jacob * 478b6b6ad2fSMatt Jacob * If so, we enable/disable target mode but don't do any lun enabling. 479b6b6ad2fSMatt Jacob */ 480b6b6ad2fSMatt Jacob if (lun == CAM_LUN_WILDCARD && tgt == CAM_TARGET_WILDCARD) { 481b6b6ad2fSMatt Jacob int av; 482b6b6ad2fSMatt Jacob tptr = &isp->isp_osinfo.tsdflt; 483b6b6ad2fSMatt Jacob if (cel->enable) { 484b6b6ad2fSMatt Jacob if (isp->isp_osinfo.tmflags & TM_TMODE_ENABLED) { 485b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; 486b6b6ad2fSMatt Jacob if (frozen) 487b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 488b6b6ad2fSMatt Jacob return; 489b6b6ad2fSMatt Jacob } 490b6b6ad2fSMatt Jacob ccb->ccb_h.status = 491b6b6ad2fSMatt Jacob xpt_create_path(&tptr->owner, NULL, 492b6b6ad2fSMatt Jacob xpt_path_path_id(ccb->ccb_h.path), 493b6b6ad2fSMatt Jacob xpt_path_target_id(ccb->ccb_h.path), 494b6b6ad2fSMatt Jacob xpt_path_lun_id(ccb->ccb_h.path)); 495b6b6ad2fSMatt Jacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 496b6b6ad2fSMatt Jacob if (frozen) 497b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 498b6b6ad2fSMatt Jacob return; 499b6b6ad2fSMatt Jacob } 500b6b6ad2fSMatt Jacob SLIST_INIT(&tptr->atios); 501b6b6ad2fSMatt Jacob SLIST_INIT(&tptr->inots); 502b6b6ad2fSMatt Jacob av = 1; 503b6b6ad2fSMatt Jacob ISP_LOCK(isp); 504b6b6ad2fSMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 505b6b6ad2fSMatt Jacob if (av) { 506b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 507b6b6ad2fSMatt Jacob xpt_free_path(tptr->owner); 508b6b6ad2fSMatt Jacob ISP_UNLOCK(isp); 509b6b6ad2fSMatt Jacob if (frozen) 510b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 511b6b6ad2fSMatt Jacob return; 512b6b6ad2fSMatt Jacob } 513b6b6ad2fSMatt Jacob isp->isp_osinfo.tmflags |= TM_TMODE_ENABLED; 514b6b6ad2fSMatt Jacob ISP_UNLOCK(isp); 515b6b6ad2fSMatt Jacob } else { 516b6b6ad2fSMatt Jacob if ((isp->isp_osinfo.tmflags & TM_TMODE_ENABLED) == 0) { 517b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 518b6b6ad2fSMatt Jacob if (frozen) 519b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 520b6b6ad2fSMatt Jacob return; 521b6b6ad2fSMatt Jacob } 522b6b6ad2fSMatt Jacob if (are_any_luns_enabled(isp)) { 523b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_SCSI_BUSY; 524b6b6ad2fSMatt Jacob if (frozen) 525b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 526b6b6ad2fSMatt Jacob return; 527b6b6ad2fSMatt Jacob } 528b6b6ad2fSMatt Jacob av = 0; 529b6b6ad2fSMatt Jacob ISP_LOCK(isp); 530b6b6ad2fSMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 531b6b6ad2fSMatt Jacob if (av) { 532b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 533b6b6ad2fSMatt Jacob ISP_UNLOCK(isp); 534b6b6ad2fSMatt Jacob if (frozen) 535b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 536b6b6ad2fSMatt Jacob return; 537b6b6ad2fSMatt Jacob } 538b6b6ad2fSMatt Jacob isp->isp_osinfo.tmflags &= ~TM_TMODE_ENABLED; 539b6b6ad2fSMatt Jacob ISP_UNLOCK(isp); 540b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 541b6b6ad2fSMatt Jacob } 542b6b6ad2fSMatt Jacob xpt_print_path(ccb->ccb_h.path); 543b6b6ad2fSMatt Jacob printf(lfmt, (cel->enable) ? "en" : "dis"); 544b6b6ad2fSMatt Jacob if (frozen) 545b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 546b6b6ad2fSMatt Jacob return; 547b6b6ad2fSMatt Jacob } 548b6b6ad2fSMatt Jacob 549b6b6ad2fSMatt Jacob /* 550b6b6ad2fSMatt Jacob * We can move along now... 551b6b6ad2fSMatt Jacob */ 552b6b6ad2fSMatt Jacob 553b6b6ad2fSMatt Jacob if (frozen) 554b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 555b6b6ad2fSMatt Jacob 556d81ba9d5SMatt Jacob 557d81ba9d5SMatt Jacob if (cel->enable) { 558d81ba9d5SMatt Jacob ccb->ccb_h.status = 559d81ba9d5SMatt Jacob create_lun_state(isp, ccb->ccb_h.path, &tptr); 560d81ba9d5SMatt Jacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 561d81ba9d5SMatt Jacob return; 562d81ba9d5SMatt Jacob } 563d81ba9d5SMatt Jacob } else { 564d81ba9d5SMatt Jacob tptr = get_lun_statep(isp, lun); 565d81ba9d5SMatt Jacob if (tptr == NULL) { 566d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 567d81ba9d5SMatt Jacob return; 568d81ba9d5SMatt Jacob } 569d81ba9d5SMatt Jacob } 570d81ba9d5SMatt Jacob 571d81ba9d5SMatt Jacob if (isp_psema_sig_rqe(isp)) { 572d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 573d81ba9d5SMatt Jacob if (cel->enable) 574d81ba9d5SMatt Jacob destroy_lun_state(isp, tptr); 575d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 576d81ba9d5SMatt Jacob return; 577d81ba9d5SMatt Jacob } 578d81ba9d5SMatt Jacob 579f6e75de2SMatt Jacob ISP_LOCK(isp); 580d81ba9d5SMatt Jacob if (cel->enable) { 581d81ba9d5SMatt Jacob u_int32_t seq = isp->isp_osinfo.rollinfo++; 582d81ba9d5SMatt Jacob rstat = LUN_ERR; 583d81ba9d5SMatt Jacob if (isp_lun_cmd(isp, RQSTYPE_ENABLE_LUN, bus, tgt, lun, seq)) { 584d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 585d81ba9d5SMatt Jacob printf("isp_lun_cmd failed\n"); 586d81ba9d5SMatt Jacob goto out; 587d81ba9d5SMatt Jacob } 588d81ba9d5SMatt Jacob if (isp_cv_wait_timed_rqe(isp, 30 * hz)) { 589d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 590d81ba9d5SMatt Jacob printf("wait for ENABLE LUN timed out\n"); 591d81ba9d5SMatt Jacob goto out; 592d81ba9d5SMatt Jacob } 593d81ba9d5SMatt Jacob rstat = isp->isp_osinfo.rstatus; 594d81ba9d5SMatt Jacob if (rstat != LUN_OK) { 595d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 596d81ba9d5SMatt Jacob printf("ENABLE LUN returned 0x%x\n", rstat); 597d81ba9d5SMatt Jacob goto out; 598d81ba9d5SMatt Jacob } 599d81ba9d5SMatt Jacob } else { 600d81ba9d5SMatt Jacob u_int32_t seq; 601d81ba9d5SMatt Jacob 602d81ba9d5SMatt Jacob seq = isp->isp_osinfo.rollinfo++; 603d81ba9d5SMatt Jacob rstat = LUN_ERR; 604d81ba9d5SMatt Jacob 605d81ba9d5SMatt Jacob if (isp_lun_cmd(isp, -RQSTYPE_MODIFY_LUN, bus, tgt, lun, seq)) { 606d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 607d81ba9d5SMatt Jacob printf("isp_lun_cmd failed\n"); 608d81ba9d5SMatt Jacob goto out; 609d81ba9d5SMatt Jacob } 610d81ba9d5SMatt Jacob if (isp_cv_wait_timed_rqe(isp, 30 * hz)) { 611d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 612d81ba9d5SMatt Jacob printf("wait for MODIFY LUN timed out\n"); 613d81ba9d5SMatt Jacob goto out; 614d81ba9d5SMatt Jacob } 615d81ba9d5SMatt Jacob rstat = isp->isp_osinfo.rstatus; 616d81ba9d5SMatt Jacob if (rstat != LUN_OK) { 617d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 618d81ba9d5SMatt Jacob printf("MODIFY LUN returned 0x%x\n", rstat); 619d81ba9d5SMatt Jacob goto out; 620d81ba9d5SMatt Jacob } 621d81ba9d5SMatt Jacob rstat = LUN_ERR; 622d81ba9d5SMatt Jacob seq = isp->isp_osinfo.rollinfo++; 623d81ba9d5SMatt Jacob 624d81ba9d5SMatt Jacob if (isp_lun_cmd(isp, -RQSTYPE_ENABLE_LUN, bus, tgt, lun, seq)) { 625d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 626d81ba9d5SMatt Jacob printf("isp_lun_cmd failed\n"); 627d81ba9d5SMatt Jacob goto out; 628d81ba9d5SMatt Jacob } 629d81ba9d5SMatt Jacob if (isp_cv_wait_timed_rqe(isp, 30 * hz)) { 630d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 631d81ba9d5SMatt Jacob printf("wait for ENABLE LUN timed out\n"); 632d81ba9d5SMatt Jacob goto out; 633d81ba9d5SMatt Jacob } 634d81ba9d5SMatt Jacob rstat = isp->isp_osinfo.rstatus; 635d81ba9d5SMatt Jacob if (rstat != LUN_OK) { 636d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 637d81ba9d5SMatt Jacob printf("ENABLE LUN returned 0x%x\n", rstat); 638d81ba9d5SMatt Jacob goto out; 639d81ba9d5SMatt Jacob } 640d81ba9d5SMatt Jacob } 641d81ba9d5SMatt Jacob out: 642d81ba9d5SMatt Jacob isp_vsema_rqe(isp); 643f6e75de2SMatt Jacob ISP_UNLOCK(isp); 644d81ba9d5SMatt Jacob 645d81ba9d5SMatt Jacob if (rstat != LUN_OK) { 646d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 647d81ba9d5SMatt Jacob printf("lun %sable failed\n", (cel->enable) ? "en" : "dis"); 648d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 649d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 650d81ba9d5SMatt Jacob if (cel->enable) 651d81ba9d5SMatt Jacob destroy_lun_state(isp, tptr); 652d81ba9d5SMatt Jacob } else { 653d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 654d81ba9d5SMatt Jacob printf(lfmt, (cel->enable) ? "en" : "dis"); 655d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 656d81ba9d5SMatt Jacob if (cel->enable == 0) { 657d81ba9d5SMatt Jacob destroy_lun_state(isp, tptr); 658d81ba9d5SMatt Jacob } 659d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 660d81ba9d5SMatt Jacob } 661d81ba9d5SMatt Jacob } 662d81ba9d5SMatt Jacob 663d81ba9d5SMatt Jacob static cam_status 664d81ba9d5SMatt Jacob isp_abort_tgt_ccb(struct ispsoftc *isp, union ccb *ccb) 665d81ba9d5SMatt Jacob { 666d81ba9d5SMatt Jacob tstate_t *tptr; 667d81ba9d5SMatt Jacob struct ccb_hdr_slist *lp; 668d81ba9d5SMatt Jacob struct ccb_hdr *curelm; 669d81ba9d5SMatt Jacob int found; 670d81ba9d5SMatt Jacob union ccb *accb = ccb->cab.abort_ccb; 671d81ba9d5SMatt Jacob 672d81ba9d5SMatt Jacob if (accb->ccb_h.target_id != CAM_TARGET_WILDCARD) { 673d81ba9d5SMatt Jacob if (IS_FC(isp) && (accb->ccb_h.target_id != 674d81ba9d5SMatt Jacob ((fcparam *) isp->isp_param)->isp_loopid)) { 675d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 676d81ba9d5SMatt Jacob } else if (IS_SCSI(isp) && (accb->ccb_h.target_id != 677d81ba9d5SMatt Jacob ((sdparam *) isp->isp_param)->isp_initiator_id)) { 678d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 679d81ba9d5SMatt Jacob } 680d81ba9d5SMatt Jacob } 681d81ba9d5SMatt Jacob tptr = get_lun_statep(isp, accb->ccb_h.target_lun); 682d81ba9d5SMatt Jacob if (tptr == NULL) { 683d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 684d81ba9d5SMatt Jacob } 685d81ba9d5SMatt Jacob if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 686d81ba9d5SMatt Jacob lp = &tptr->atios; 687d81ba9d5SMatt Jacob } else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY) { 688d81ba9d5SMatt Jacob lp = &tptr->inots; 689d81ba9d5SMatt Jacob } else { 690d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 691d81ba9d5SMatt Jacob return (CAM_UA_ABORT); 692d81ba9d5SMatt Jacob } 693d81ba9d5SMatt Jacob curelm = SLIST_FIRST(lp); 694d81ba9d5SMatt Jacob found = 0; 695d81ba9d5SMatt Jacob if (curelm == &accb->ccb_h) { 696d81ba9d5SMatt Jacob found = 1; 697d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(lp, sim_links.sle); 698d81ba9d5SMatt Jacob } else { 699d81ba9d5SMatt Jacob while(curelm != NULL) { 700d81ba9d5SMatt Jacob struct ccb_hdr *nextelm; 701d81ba9d5SMatt Jacob 702d81ba9d5SMatt Jacob nextelm = SLIST_NEXT(curelm, sim_links.sle); 703d81ba9d5SMatt Jacob if (nextelm == &accb->ccb_h) { 704d81ba9d5SMatt Jacob found = 1; 705d81ba9d5SMatt Jacob SLIST_NEXT(curelm, sim_links.sle) = 706d81ba9d5SMatt Jacob SLIST_NEXT(nextelm, sim_links.sle); 707d81ba9d5SMatt Jacob break; 708d81ba9d5SMatt Jacob } 709d81ba9d5SMatt Jacob curelm = nextelm; 710d81ba9d5SMatt Jacob } 711d81ba9d5SMatt Jacob } 712d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 713d81ba9d5SMatt Jacob if (found) { 714d81ba9d5SMatt Jacob accb->ccb_h.status = CAM_REQ_ABORTED; 715d81ba9d5SMatt Jacob return (CAM_REQ_CMP); 716d81ba9d5SMatt Jacob } 717d81ba9d5SMatt Jacob return(CAM_PATH_INVALID); 718d81ba9d5SMatt Jacob } 719d81ba9d5SMatt Jacob 720d81ba9d5SMatt Jacob static cam_status 721d81ba9d5SMatt Jacob isp_target_start_ctio(struct ispsoftc *isp, union ccb *ccb) 722d81ba9d5SMatt Jacob { 723d81ba9d5SMatt Jacob void *qe; 72400a8e174SMatt Jacob struct ccb_scsiio *cso = &ccb->csio; 725d81ba9d5SMatt Jacob u_int32_t *hp, save_handle; 726d81ba9d5SMatt Jacob u_int16_t iptr, optr; 727d81ba9d5SMatt Jacob 728f48ce188SMatt Jacob 729d81ba9d5SMatt Jacob if (isp_getrqentry(isp, &iptr, &optr, &qe)) { 73092a1e549SMatt Jacob xpt_print_path(ccb->ccb_h.path); 73192a1e549SMatt Jacob printf("Request Queue Overflow in isp_target_start_ctio\n"); 732d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 733d81ba9d5SMatt Jacob } 73492a1e549SMatt Jacob bzero(qe, QENTRY_LEN); 735d81ba9d5SMatt Jacob 736d81ba9d5SMatt Jacob /* 737d81ba9d5SMatt Jacob * We're either moving data or completing a command here. 738d81ba9d5SMatt Jacob */ 739d81ba9d5SMatt Jacob 740d81ba9d5SMatt Jacob if (IS_FC(isp)) { 741f48ce188SMatt Jacob struct ccb_accept_tio *atiop; 742d81ba9d5SMatt Jacob ct2_entry_t *cto = qe; 74300a8e174SMatt Jacob 744d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; 745d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_count = 1; 74600a8e174SMatt Jacob cto->ct_iid = cso->init_id; 7472ad50ca5SMatt Jacob if (isp->isp_maxluns <= 16) { 748d81ba9d5SMatt Jacob cto->ct_lun = ccb->ccb_h.target_lun; 7492ad50ca5SMatt Jacob } 750f48ce188SMatt Jacob /* 751f48ce188SMatt Jacob * Start with a residual based on what the original datalength 752f48ce188SMatt Jacob * was supposed to be. Basically, we ignore what CAM has set 753f48ce188SMatt Jacob * for residuals. The data transfer routines will knock off 754f48ce188SMatt Jacob * the residual for each byte actually moved- and also will 755f48ce188SMatt Jacob * be responsible for setting the underrun flag. 756f48ce188SMatt Jacob */ 757f48ce188SMatt Jacob /* HACK! HACK! */ 758f48ce188SMatt Jacob if ((atiop = ccb->ccb_h.periph_priv.entries[1].ptr) != NULL) { 759f48ce188SMatt Jacob cto->ct_resid = atiop->ccb_h.spriv_field0; 760f48ce188SMatt Jacob } 761f48ce188SMatt Jacob 762f48ce188SMatt Jacob /* 763f48ce188SMatt Jacob * We always have to use the tag_id- it has the RX_ID 764f48ce188SMatt Jacob * for this exchage. 765f48ce188SMatt Jacob */ 76600a8e174SMatt Jacob cto->ct_rxid = cso->tag_id; 76700a8e174SMatt Jacob if (cso->dxfer_len == 0) { 76800a8e174SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA; 769f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 77000a8e174SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 771f48ce188SMatt Jacob cto->rsp.m1.ct_scsi_status = cso->scsi_status; 772f48ce188SMatt Jacob } 77300a8e174SMatt Jacob if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) { 77400a8e174SMatt Jacob int m = min(cso->sense_len, MAXRESPLEN); 77500a8e174SMatt Jacob bcopy(&cso->sense_data, cto->rsp.m1.ct_resp, m); 77600a8e174SMatt Jacob cto->rsp.m1.ct_senselen = m; 77700a8e174SMatt Jacob cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID; 77800a8e174SMatt Jacob } 77900a8e174SMatt Jacob } else { 78000a8e174SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE0; 78100a8e174SMatt Jacob if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 78200a8e174SMatt Jacob cto->ct_flags |= CT2_DATA_IN; 78300a8e174SMatt Jacob } else { 78400a8e174SMatt Jacob cto->ct_flags |= CT2_DATA_OUT; 785d81ba9d5SMatt Jacob } 786d81ba9d5SMatt Jacob if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 787d81ba9d5SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 78800a8e174SMatt Jacob cto->rsp.m0.ct_scsi_status = cso->scsi_status; 789d81ba9d5SMatt Jacob } 790f48ce188SMatt Jacob /* 791f48ce188SMatt Jacob * If we're sending data and status back together, 792f48ce188SMatt Jacob * we can't also send back sense data as well. 793f48ce188SMatt Jacob */ 79400a8e174SMatt Jacob ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 79500a8e174SMatt Jacob } 796b09b0095SMatt Jacob if (cto->ct_flags & CAM_SEND_STATUS) { 797b09b0095SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG2, 798b09b0095SMatt Jacob "CTIO2 RX_ID 0x%x SCSI STATUS 0x%x datalength %u", 799b09b0095SMatt Jacob cto->ct_rxid, cso->scsi_status, cto->ct_resid); 800d81ba9d5SMatt Jacob } 801d81ba9d5SMatt Jacob hp = &cto->ct_reserved; 802d81ba9d5SMatt Jacob } else { 803d81ba9d5SMatt Jacob ct_entry_t *cto = qe; 80400a8e174SMatt Jacob 805d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 806d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_count = 1; 80700a8e174SMatt Jacob cto->ct_iid = cso->init_id; 808d81ba9d5SMatt Jacob cto->ct_tgt = ccb->ccb_h.target_id; 809d81ba9d5SMatt Jacob cto->ct_lun = ccb->ccb_h.target_lun; 810f48ce188SMatt Jacob if (cso->tag_id && cso->tag_action) { 811f48ce188SMatt Jacob /* 812f48ce188SMatt Jacob * We don't specify a tag type for regular SCSI. 813f48ce188SMatt Jacob * Just the tag value and set the flag. 814f48ce188SMatt Jacob */ 81500a8e174SMatt Jacob cto->ct_tag_val = cso->tag_id; 816f48ce188SMatt Jacob cto->ct_flags |= CT_TQAE; 817f48ce188SMatt Jacob } 818f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) { 819f48ce188SMatt Jacob cto->ct_flags |= CT_NODISC; 820f48ce188SMatt Jacob } 821f48ce188SMatt Jacob if (cso->dxfer_len == 0) { 822d81ba9d5SMatt Jacob cto->ct_flags |= CT_NO_DATA; 82300a8e174SMatt Jacob } else if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 82400a8e174SMatt Jacob cto->ct_flags |= CT_DATA_IN; 82500a8e174SMatt Jacob } else { 82600a8e174SMatt Jacob cto->ct_flags |= CT_DATA_OUT; 827d81ba9d5SMatt Jacob } 828f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 829d81ba9d5SMatt Jacob cto->ct_flags |= CT_SENDSTATUS; 83000a8e174SMatt Jacob cto->ct_scsi_status = cso->scsi_status; 83100a8e174SMatt Jacob cto->ct_resid = cso->resid; 832d81ba9d5SMatt Jacob } 833b09b0095SMatt Jacob if (cto->ct_flags & CAM_SEND_STATUS) { 834b09b0095SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG2, 835b09b0095SMatt Jacob "CTIO SCSI STATUS 0x%x resid %d", 836b09b0095SMatt Jacob cso->scsi_status, cso->resid); 83792a1e549SMatt Jacob } 838d81ba9d5SMatt Jacob hp = &cto->ct_reserved; 83900a8e174SMatt Jacob ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 840d81ba9d5SMatt Jacob } 841d81ba9d5SMatt Jacob 842b09b0095SMatt Jacob if (isp_save_xs(isp, (XS_T *)ccb, hp)) { 84392a1e549SMatt Jacob xpt_print_path(ccb->ccb_h.path); 84492a1e549SMatt Jacob printf("No XFLIST pointers for isp_target_start_ctio\n"); 845d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 846d81ba9d5SMatt Jacob } 847d81ba9d5SMatt Jacob 848d81ba9d5SMatt Jacob 849d81ba9d5SMatt Jacob /* 850d81ba9d5SMatt Jacob * Call the dma setup routines for this entry (and any subsequent 851d81ba9d5SMatt Jacob * CTIOs) if there's data to move, and then tell the f/w it's got 852b09b0095SMatt Jacob * new things to play with. As with isp_start's usage of DMA setup, 853d81ba9d5SMatt Jacob * any swizzling is done in the machine dependent layer. Because 854d81ba9d5SMatt Jacob * of this, we put the request onto the queue area first in native 855d81ba9d5SMatt Jacob * format. 856d81ba9d5SMatt Jacob */ 857d81ba9d5SMatt Jacob 858d81ba9d5SMatt Jacob save_handle = *hp; 85900a8e174SMatt Jacob switch (ISP_DMASETUP(isp, cso, qe, &iptr, optr)) { 860d81ba9d5SMatt Jacob case CMD_QUEUED: 861d81ba9d5SMatt Jacob ISP_ADD_REQUEST(isp, iptr); 862d81ba9d5SMatt Jacob return (CAM_REQ_INPROG); 863d81ba9d5SMatt Jacob 864d81ba9d5SMatt Jacob case CMD_EAGAIN: 865d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 866d81ba9d5SMatt Jacob isp_destroy_handle(isp, save_handle); 867d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 868d81ba9d5SMatt Jacob 869d81ba9d5SMatt Jacob default: 870d81ba9d5SMatt Jacob isp_destroy_handle(isp, save_handle); 871b85389e1SMatt Jacob return (XS_ERR(ccb)); 872d81ba9d5SMatt Jacob } 873d81ba9d5SMatt Jacob } 874d81ba9d5SMatt Jacob 875f48ce188SMatt Jacob static cam_status 876f48ce188SMatt Jacob isp_target_putback_atio(struct ispsoftc *isp, union ccb *ccb) 877f48ce188SMatt Jacob { 878f48ce188SMatt Jacob void *qe; 879f48ce188SMatt Jacob struct ccb_accept_tio *atiop; 880f48ce188SMatt Jacob u_int16_t iptr, optr; 881f48ce188SMatt Jacob 882f48ce188SMatt Jacob if (isp_getrqentry(isp, &iptr, &optr, &qe)) { 883f48ce188SMatt Jacob xpt_print_path(ccb->ccb_h.path); 884f48ce188SMatt Jacob printf("Request Queue Overflow in isp_target_putback_atio\n"); 885f48ce188SMatt Jacob return (CAM_RESRC_UNAVAIL); 886f48ce188SMatt Jacob } 887f48ce188SMatt Jacob bzero(qe, QENTRY_LEN); 888f48ce188SMatt Jacob atiop = (struct ccb_accept_tio *) ccb; 889f48ce188SMatt Jacob if (IS_FC(isp)) { 890f48ce188SMatt Jacob at2_entry_t *at = qe; 891f48ce188SMatt Jacob at->at_header.rqs_entry_type = RQSTYPE_ATIO2; 892f48ce188SMatt Jacob at->at_header.rqs_entry_count = 1; 893f48ce188SMatt Jacob if (isp->isp_maxluns > 16) { 894f48ce188SMatt Jacob at->at_scclun = (uint16_t) atiop->ccb_h.target_lun; 895f48ce188SMatt Jacob } else { 896f48ce188SMatt Jacob at->at_lun = (uint8_t) atiop->ccb_h.target_lun; 897f48ce188SMatt Jacob } 898f48ce188SMatt Jacob at->at_status = CT_OK; 899f48ce188SMatt Jacob at->at_rxid = atiop->tag_id; 900f48ce188SMatt Jacob ISP_SWIZ_ATIO2(isp, qe, qe); 901f48ce188SMatt Jacob } else { 902f48ce188SMatt Jacob at_entry_t *at = qe; 903f48ce188SMatt Jacob at->at_header.rqs_entry_type = RQSTYPE_ATIO; 904f48ce188SMatt Jacob at->at_header.rqs_entry_count = 1; 905f48ce188SMatt Jacob at->at_iid = atiop->init_id; 906f48ce188SMatt Jacob at->at_tgt = atiop->ccb_h.target_id; 907f48ce188SMatt Jacob at->at_lun = atiop->ccb_h.target_lun; 908f48ce188SMatt Jacob at->at_status = CT_OK; 909f48ce188SMatt Jacob if (atiop->ccb_h.status & CAM_TAG_ACTION_VALID) { 910f48ce188SMatt Jacob at->at_tag_type = atiop->tag_action; 911f48ce188SMatt Jacob } 912f48ce188SMatt Jacob at->at_tag_val = atiop->tag_id; 913f48ce188SMatt Jacob ISP_SWIZ_ATIO(isp, qe, qe); 914f48ce188SMatt Jacob } 915f48ce188SMatt Jacob ISP_TDQE(isp, "isp_target_putback_atio", (int) optr, qe); 916f48ce188SMatt Jacob ISP_ADD_REQUEST(isp, iptr); 917f48ce188SMatt Jacob return (CAM_REQ_CMP); 918f48ce188SMatt Jacob } 919f48ce188SMatt Jacob 920f48ce188SMatt Jacob static void 921f48ce188SMatt Jacob isp_refire_putback_atio(void *arg) 922f48ce188SMatt Jacob { 923f48ce188SMatt Jacob union ccb *ccb = arg; 924f48ce188SMatt Jacob int s = splcam(); 925f48ce188SMatt Jacob if (isp_target_putback_atio(XS_ISP(ccb), ccb) != CAM_REQ_CMP) { 926f48ce188SMatt Jacob (void) timeout(isp_refire_putback_atio, ccb, 10); 927f48ce188SMatt Jacob } else { 928f48ce188SMatt Jacob isp_handle_platform_ctio_part2(XS_ISP(ccb), ccb); 929f48ce188SMatt Jacob } 930f48ce188SMatt Jacob splx(s); 931f48ce188SMatt Jacob } 932f48ce188SMatt Jacob 933d81ba9d5SMatt Jacob /* 934d81ba9d5SMatt Jacob * Handle ATIO stuff that the generic code can't. 935d81ba9d5SMatt Jacob * This means handling CDBs. 936d81ba9d5SMatt Jacob */ 937d81ba9d5SMatt Jacob 938d81ba9d5SMatt Jacob static int 939d81ba9d5SMatt Jacob isp_handle_platform_atio(struct ispsoftc *isp, at_entry_t *aep) 940d81ba9d5SMatt Jacob { 941d81ba9d5SMatt Jacob tstate_t *tptr; 942d81ba9d5SMatt Jacob int status; 943d81ba9d5SMatt Jacob struct ccb_accept_tio *atiop; 944d81ba9d5SMatt Jacob 945d81ba9d5SMatt Jacob /* 946d81ba9d5SMatt Jacob * The firmware status (except for the QLTM_SVALID bit) 947d81ba9d5SMatt Jacob * indicates why this ATIO was sent to us. 948d81ba9d5SMatt Jacob * 949d81ba9d5SMatt Jacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 950d81ba9d5SMatt Jacob * 951d81ba9d5SMatt Jacob * If the DISCONNECTS DISABLED bit is set in the flags field, 952d81ba9d5SMatt Jacob * we're still connected on the SCSI bus - i.e. the initiator 953d81ba9d5SMatt Jacob * did not set DiscPriv in the identify message. We don't care 954d81ba9d5SMatt Jacob * about this so it's ignored. 955d81ba9d5SMatt Jacob */ 956d81ba9d5SMatt Jacob status = aep->at_status; 957d81ba9d5SMatt Jacob if ((status & ~QLTM_SVALID) == AT_PHASE_ERROR) { 958d81ba9d5SMatt Jacob /* 959d81ba9d5SMatt Jacob * Bus Phase Sequence error. We should have sense data 960d81ba9d5SMatt Jacob * suggested by the f/w. I'm not sure quite yet what 961d81ba9d5SMatt Jacob * to do about this for CAM. 962d81ba9d5SMatt Jacob */ 963d81ba9d5SMatt Jacob printf("%s: PHASE ERROR\n", isp->isp_name); 964d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 965d81ba9d5SMatt Jacob return (0); 966d81ba9d5SMatt Jacob } 967d81ba9d5SMatt Jacob if ((status & ~QLTM_SVALID) != AT_CDB) { 968d81ba9d5SMatt Jacob printf("%s: bogus atio (0x%x) leaked to platform\n", 969d81ba9d5SMatt Jacob isp->isp_name, status); 970d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 971d81ba9d5SMatt Jacob return (0); 972d81ba9d5SMatt Jacob } 973d81ba9d5SMatt Jacob 974d81ba9d5SMatt Jacob tptr = get_lun_statep(isp, aep->at_lun); 975d81ba9d5SMatt Jacob if (tptr == NULL) { 976d81ba9d5SMatt Jacob tptr = get_lun_statep(isp, CAM_LUN_WILDCARD); 977d81ba9d5SMatt Jacob } 978d81ba9d5SMatt Jacob 979d81ba9d5SMatt Jacob if (tptr == NULL) { 980d81ba9d5SMatt Jacob /* 981d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 982d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 983d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a BUSY status 984d81ba9d5SMatt Jacob * instead. This works out okay because the only 985d81ba9d5SMatt Jacob * time we should, in fact, get this, is in the 986d81ba9d5SMatt Jacob * case that somebody configured us without the 987d81ba9d5SMatt Jacob * blackhole driver, so they get what they deserve. 988d81ba9d5SMatt Jacob */ 989d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 990d81ba9d5SMatt Jacob return (0); 991d81ba9d5SMatt Jacob } 992d81ba9d5SMatt Jacob 993d81ba9d5SMatt Jacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 994d81ba9d5SMatt Jacob if (atiop == NULL) { 995d81ba9d5SMatt Jacob /* 996d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 997d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 998d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a QUEUE FULL status 999d81ba9d5SMatt Jacob * instead. This works out okay because the only time we 1000d81ba9d5SMatt Jacob * should, in fact, get this, is in the case that we've 1001d81ba9d5SMatt Jacob * run out of ATIOS. 1002d81ba9d5SMatt Jacob */ 1003d81ba9d5SMatt Jacob xpt_print_path(tptr->owner); 1004d81ba9d5SMatt Jacob printf("no ATIOS for lun %d from initiator %d\n", 1005d81ba9d5SMatt Jacob aep->at_lun, aep->at_iid); 1006d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1007d81ba9d5SMatt Jacob if (aep->at_flags & AT_TQAE) 1008d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); 1009d81ba9d5SMatt Jacob else 1010d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1011d81ba9d5SMatt Jacob return (0); 1012d81ba9d5SMatt Jacob } 1013d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 1014d81ba9d5SMatt Jacob if (tptr == &isp->isp_osinfo.tsdflt) { 1015d81ba9d5SMatt Jacob atiop->ccb_h.target_id = aep->at_tgt; 1016d81ba9d5SMatt Jacob atiop->ccb_h.target_lun = aep->at_lun; 1017d81ba9d5SMatt Jacob } 1018d81ba9d5SMatt Jacob if (aep->at_flags & AT_NODISC) { 1019f48ce188SMatt Jacob atiop->ccb_h.flags = CAM_DIS_DISCONNECT; 1020f48ce188SMatt Jacob } else { 1021f48ce188SMatt Jacob atiop->ccb_h.flags = 0; 1022d81ba9d5SMatt Jacob } 1023d81ba9d5SMatt Jacob 1024f48ce188SMatt Jacob if (status & QLTM_SVALID) { 1025f48ce188SMatt Jacob size_t amt = imin(QLTM_SENSELEN, sizeof (atiop->sense_data)); 1026f48ce188SMatt Jacob atiop->sense_len = amt; 1027f48ce188SMatt Jacob MEMCPY(&atiop->sense_data, aep->at_sense, amt); 1028f48ce188SMatt Jacob } else { 1029f48ce188SMatt Jacob atiop->sense_len = 0; 1030f48ce188SMatt Jacob } 1031d81ba9d5SMatt Jacob 1032d81ba9d5SMatt Jacob atiop->init_id = aep->at_iid; 1033d81ba9d5SMatt Jacob atiop->cdb_len = aep->at_cdblen; 1034d81ba9d5SMatt Jacob MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen); 1035d81ba9d5SMatt Jacob atiop->ccb_h.status = CAM_CDB_RECVD; 1036d81ba9d5SMatt Jacob atiop->tag_id = aep->at_tag_val; 1037f48ce188SMatt Jacob if ((atiop->tag_action = aep->at_tag_type) != 0) { 1038d81ba9d5SMatt Jacob atiop->ccb_h.status |= CAM_TAG_ACTION_VALID; 1039d81ba9d5SMatt Jacob } 1040d81ba9d5SMatt Jacob xpt_done((union ccb*)atiop); 1041b09b0095SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG2, 1042b09b0095SMatt Jacob "ATIO CDB=0x%x iid%d->lun%d tag 0x%x ttype 0x%x %s", 1043b09b0095SMatt Jacob aep->at_cdb[0] & 0xff, aep->at_iid, aep->at_lun, 1044b09b0095SMatt Jacob aep->at_tag_val & 0xff, aep->at_tag_type, 1045b09b0095SMatt Jacob (aep->at_flags & AT_NODISC)? "nondisc" : "disconnecting"); 1046d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1047d81ba9d5SMatt Jacob return (0); 1048d81ba9d5SMatt Jacob } 1049d81ba9d5SMatt Jacob 1050d81ba9d5SMatt Jacob static int 1051d81ba9d5SMatt Jacob isp_handle_platform_atio2(struct ispsoftc *isp, at2_entry_t *aep) 1052d81ba9d5SMatt Jacob { 105392a1e549SMatt Jacob lun_id_t lun; 1054d81ba9d5SMatt Jacob tstate_t *tptr; 1055d81ba9d5SMatt Jacob struct ccb_accept_tio *atiop; 1056d81ba9d5SMatt Jacob 1057d81ba9d5SMatt Jacob /* 1058d81ba9d5SMatt Jacob * The firmware status (except for the QLTM_SVALID bit) 1059d81ba9d5SMatt Jacob * indicates why this ATIO was sent to us. 1060d81ba9d5SMatt Jacob * 1061d81ba9d5SMatt Jacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 1062d81ba9d5SMatt Jacob */ 1063d81ba9d5SMatt Jacob if ((aep->at_status & ~QLTM_SVALID) != AT_CDB) { 1064d81ba9d5SMatt Jacob printf("%s: bogus atio (0x%x) leaked to platform\n", 1065d81ba9d5SMatt Jacob isp->isp_name, aep->at_status); 1066d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1067d81ba9d5SMatt Jacob return (0); 1068d81ba9d5SMatt Jacob } 1069d81ba9d5SMatt Jacob 10702ad50ca5SMatt Jacob if (isp->isp_maxluns > 16) { 107192a1e549SMatt Jacob lun = aep->at_scclun; 10722ad50ca5SMatt Jacob } else { 107392a1e549SMatt Jacob lun = aep->at_lun; 10742ad50ca5SMatt Jacob } 107592a1e549SMatt Jacob tptr = get_lun_statep(isp, lun); 1076d81ba9d5SMatt Jacob if (tptr == NULL) { 1077d81ba9d5SMatt Jacob tptr = get_lun_statep(isp, CAM_LUN_WILDCARD); 1078d81ba9d5SMatt Jacob } 1079d81ba9d5SMatt Jacob 1080d81ba9d5SMatt Jacob if (tptr == NULL) { 108152df5dfdSMatt Jacob /* 108252df5dfdSMatt Jacob * What we'd like to know is whether or not we have a listener 108352df5dfdSMatt Jacob * upstream that really hasn't configured yet. If we do, then 108452df5dfdSMatt Jacob * we can give a more sensible reply here. If not, then we can 108552df5dfdSMatt Jacob * reject this out of hand. 108652df5dfdSMatt Jacob * 108752df5dfdSMatt Jacob * Choices for what to send were 108852df5dfdSMatt Jacob * 108952df5dfdSMatt Jacob * Not Ready, Unit Not Self-Configured Yet 109052df5dfdSMatt Jacob * (0x2,0x3e,0x00) 109152df5dfdSMatt Jacob * 109252df5dfdSMatt Jacob * for the former and 109352df5dfdSMatt Jacob * 109452df5dfdSMatt Jacob * Illegal Request, Logical Unit Not Supported 109552df5dfdSMatt Jacob * (0x5,0x25,0x00) 109652df5dfdSMatt Jacob * 109752df5dfdSMatt Jacob * for the latter. 109852df5dfdSMatt Jacob * 109952df5dfdSMatt Jacob * We used to decide whether there was at least one listener 110052df5dfdSMatt Jacob * based upon whether the black hole driver was configured. 110152df5dfdSMatt Jacob * However, recent config(8) changes have made this hard to do 110252df5dfdSMatt Jacob * at this time. 110352df5dfdSMatt Jacob * 110452df5dfdSMatt Jacob */ 1105d81ba9d5SMatt Jacob u_int32_t ccode = SCSI_STATUS_BUSY; 1106d81ba9d5SMatt Jacob 1107d81ba9d5SMatt Jacob /* 1108d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1109d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1110d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a BUSY status 1111d81ba9d5SMatt Jacob * instead. This works out okay because the only 1112d81ba9d5SMatt Jacob * time we should, in fact, get this, is in the 1113d81ba9d5SMatt Jacob * case that somebody configured us without the 1114d81ba9d5SMatt Jacob * blackhole driver, so they get what they deserve. 1115d81ba9d5SMatt Jacob */ 1116d81ba9d5SMatt Jacob isp_endcmd(isp, aep, ccode, 0); 1117d81ba9d5SMatt Jacob return (0); 1118d81ba9d5SMatt Jacob } 1119d81ba9d5SMatt Jacob 1120d81ba9d5SMatt Jacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 1121d81ba9d5SMatt Jacob if (atiop == NULL) { 1122d81ba9d5SMatt Jacob /* 1123d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1124d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1125d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a QUEUE FULL status 1126d81ba9d5SMatt Jacob * instead. This works out okay because the only time we 1127d81ba9d5SMatt Jacob * should, in fact, get this, is in the case that we've 1128d81ba9d5SMatt Jacob * run out of ATIOS. 1129d81ba9d5SMatt Jacob */ 1130d81ba9d5SMatt Jacob xpt_print_path(tptr->owner); 1131d81ba9d5SMatt Jacob printf("no ATIOS for lun %d from initiator %d\n", 113292a1e549SMatt Jacob lun, aep->at_iid); 1133d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1134d81ba9d5SMatt Jacob if (aep->at_flags & AT_TQAE) 1135d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); 1136d81ba9d5SMatt Jacob else 1137d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1138d81ba9d5SMatt Jacob return (0); 1139d81ba9d5SMatt Jacob } 1140d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 1141f48ce188SMatt Jacob 1142d81ba9d5SMatt Jacob if (tptr == &isp->isp_osinfo.tsdflt) { 1143d81ba9d5SMatt Jacob atiop->ccb_h.target_id = 1144d81ba9d5SMatt Jacob ((fcparam *)isp->isp_param)->isp_loopid; 114592a1e549SMatt Jacob atiop->ccb_h.target_lun = lun; 1146d81ba9d5SMatt Jacob } 1147f48ce188SMatt Jacob if (aep->at_status & QLTM_SVALID) { 1148f48ce188SMatt Jacob size_t amt = imin(QLTM_SENSELEN, sizeof (atiop->sense_data)); 1149f48ce188SMatt Jacob atiop->sense_len = amt; 1150f48ce188SMatt Jacob MEMCPY(&atiop->sense_data, aep->at_sense, amt); 1151f48ce188SMatt Jacob } else { 1152f48ce188SMatt Jacob atiop->sense_len = 0; 1153f48ce188SMatt Jacob } 1154f48ce188SMatt Jacob 1155d81ba9d5SMatt Jacob atiop->init_id = aep->at_iid; 1156d81ba9d5SMatt Jacob atiop->cdb_len = ATIO2_CDBLEN; 1157d81ba9d5SMatt Jacob MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, ATIO2_CDBLEN); 1158d81ba9d5SMatt Jacob atiop->ccb_h.status = CAM_CDB_RECVD; 1159d81ba9d5SMatt Jacob atiop->tag_id = aep->at_rxid; 1160d81ba9d5SMatt Jacob switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) { 1161d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_SIMPLEQ: 1162d81ba9d5SMatt Jacob atiop->tag_action = MSG_SIMPLE_Q_TAG; 1163d81ba9d5SMatt Jacob break; 1164d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_HEADOFQ: 1165d81ba9d5SMatt Jacob atiop->tag_action = MSG_HEAD_OF_Q_TAG; 1166d81ba9d5SMatt Jacob break; 1167d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_ORDERED: 1168d81ba9d5SMatt Jacob atiop->tag_action = MSG_ORDERED_Q_TAG; 1169d81ba9d5SMatt Jacob break; 1170d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_ACAQ: /* ?? */ 1171d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_UNTAGGED: 1172d81ba9d5SMatt Jacob default: 1173d81ba9d5SMatt Jacob atiop->tag_action = 0; 1174d81ba9d5SMatt Jacob break; 1175d81ba9d5SMatt Jacob } 1176d81ba9d5SMatt Jacob if (atiop->tag_action != 0) { 1177d81ba9d5SMatt Jacob atiop->ccb_h.status |= CAM_TAG_ACTION_VALID; 1178d81ba9d5SMatt Jacob } 1179f48ce188SMatt Jacob 1180f48ce188SMatt Jacob /* 1181f48ce188SMatt Jacob * Preserve overall command datalength in private field. 1182f48ce188SMatt Jacob */ 1183f48ce188SMatt Jacob atiop->ccb_h.spriv_field0 = aep->at_datalen; 1184f48ce188SMatt Jacob 1185d81ba9d5SMatt Jacob xpt_done((union ccb*)atiop); 1186b09b0095SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG2, 1187b09b0095SMatt Jacob "ATIO2 RX_ID 0x%x CDB=0x%x iid%d->lun%d tattr 0x%x datalen %u", 1188b09b0095SMatt Jacob aep->at_rxid & 0xffff, aep->at_cdb[0] & 0xff, aep->at_iid, 1189b09b0095SMatt Jacob lun, aep->at_taskflags, aep->at_datalen); 1190d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1191d81ba9d5SMatt Jacob return (0); 1192d81ba9d5SMatt Jacob } 1193d81ba9d5SMatt Jacob 1194d81ba9d5SMatt Jacob static int 1195d81ba9d5SMatt Jacob isp_handle_platform_ctio(struct ispsoftc *isp, void *arg) 1196d81ba9d5SMatt Jacob { 1197d81ba9d5SMatt Jacob union ccb *ccb; 1198f48ce188SMatt Jacob int sentstatus, ok, notify_cam; 1199d81ba9d5SMatt Jacob 1200d81ba9d5SMatt Jacob /* 1201d81ba9d5SMatt Jacob * CTIO and CTIO2 are close enough.... 1202d81ba9d5SMatt Jacob */ 1203d81ba9d5SMatt Jacob 1204d81ba9d5SMatt Jacob ccb = (union ccb *) isp_find_xs(isp, ((ct_entry_t *)arg)->ct_reserved); 1205d81ba9d5SMatt Jacob KASSERT((ccb != NULL), ("null ccb in isp_handle_platform_ctio")); 1206d81ba9d5SMatt Jacob isp_destroy_handle(isp, ((ct_entry_t *)arg)->ct_reserved); 1207d81ba9d5SMatt Jacob 1208d81ba9d5SMatt Jacob if (IS_FC(isp)) { 1209d81ba9d5SMatt Jacob ct2_entry_t *ct = arg; 1210d81ba9d5SMatt Jacob sentstatus = ct->ct_flags & CT2_SENDSTATUS; 1211d81ba9d5SMatt Jacob ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; 1212f48ce188SMatt Jacob if (ok && (ccb->ccb_h.flags & CAM_SEND_SENSE)) { 121300a8e174SMatt Jacob ccb->ccb_h.status |= CAM_SENT_SENSE; 121400a8e174SMatt Jacob } 1215b09b0095SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG2, 1216b09b0095SMatt Jacob "CTIO2 RX_ID 0x%x sts 0x%x flg 0x%x sns %d FIN", 1217b09b0095SMatt Jacob ct->ct_rxid, ct->ct_status, ct->ct_flags, 121800a8e174SMatt Jacob (ccb->ccb_h.status & CAM_SENT_SENSE) != 0); 1219f48ce188SMatt Jacob notify_cam = ct->ct_header.rqs_seqno; 1220d81ba9d5SMatt Jacob } else { 1221d81ba9d5SMatt Jacob ct_entry_t *ct = arg; 1222d81ba9d5SMatt Jacob sentstatus = ct->ct_flags & CT_SENDSTATUS; 1223d81ba9d5SMatt Jacob ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; 1224b09b0095SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG2, 1225b09b0095SMatt Jacob "CTIO tag 0x%x sts 0x%x flg 0x%x FIN", 1226b09b0095SMatt Jacob ct->ct_tag_val, ct->ct_status, ct->ct_flags); 1227f48ce188SMatt Jacob notify_cam = ct->ct_header.rqs_seqno; 1228d81ba9d5SMatt Jacob } 1229d81ba9d5SMatt Jacob 1230d81ba9d5SMatt Jacob /* 1231d81ba9d5SMatt Jacob * We're here either because data transfers are done (and 1232d81ba9d5SMatt Jacob * it's time to send a final status CTIO) or because the final 1233d81ba9d5SMatt Jacob * status CTIO is done. We don't get called for all intermediate 1234d81ba9d5SMatt Jacob * CTIOs that happen for a large data transfer. 1235d81ba9d5SMatt Jacob * 1236d81ba9d5SMatt Jacob * In any case, for this platform, the upper layers figure out 1237d81ba9d5SMatt Jacob * what to do next, so all we do here is collect status and 1238f48ce188SMatt Jacob * pass information along. The exception is that we clear 1239f48ce188SMatt Jacob * the notion of handling a non-disconnecting command here. 1240d81ba9d5SMatt Jacob */ 1241d81ba9d5SMatt Jacob 1242d81ba9d5SMatt Jacob if (sentstatus) { 1243d81ba9d5SMatt Jacob /* 1244d81ba9d5SMatt Jacob * Data transfer done. See if all went okay. 1245d81ba9d5SMatt Jacob */ 1246d81ba9d5SMatt Jacob if (ok) { 1247d81ba9d5SMatt Jacob ccb->csio.resid = 0; 1248d81ba9d5SMatt Jacob } else { 1249d81ba9d5SMatt Jacob ccb->csio.resid = ccb->csio.dxfer_len; 1250d81ba9d5SMatt Jacob } 1251d81ba9d5SMatt Jacob } 1252d81ba9d5SMatt Jacob 1253f48ce188SMatt Jacob if (notify_cam == 0) { 1254b09b0095SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, "Intermediate CTIO done"); 1255f48ce188SMatt Jacob return (0); 1256f48ce188SMatt Jacob } 1257b09b0095SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, "Final CTIO done"); 1258f48ce188SMatt Jacob if (isp_target_putback_atio(isp, ccb) != CAM_REQ_CMP) { 1259f48ce188SMatt Jacob (void) timeout(isp_refire_putback_atio, ccb, 10); 1260f48ce188SMatt Jacob } else { 1261f48ce188SMatt Jacob isp_handle_platform_ctio_part2(isp, ccb); 1262f48ce188SMatt Jacob } 1263f48ce188SMatt Jacob return (0); 1264f48ce188SMatt Jacob } 1265d81ba9d5SMatt Jacob 1266f48ce188SMatt Jacob static void 1267f48ce188SMatt Jacob isp_handle_platform_ctio_part2(struct ispsoftc *isp, union ccb *ccb) 1268f48ce188SMatt Jacob { 1269d81ba9d5SMatt Jacob if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { 1270d81ba9d5SMatt Jacob ccb->ccb_h.status |= CAM_REQ_CMP; 1271d81ba9d5SMatt Jacob } 1272d81ba9d5SMatt Jacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1273d81ba9d5SMatt Jacob if (isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE) { 1274d81ba9d5SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_RESOURCE; 1275d81ba9d5SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 1276d81ba9d5SMatt Jacob if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 1277b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "ctio->relsimq"); 1278d81ba9d5SMatt Jacob ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 1279d81ba9d5SMatt Jacob } else { 1280b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "ctio->devqfrozen"); 1281d81ba9d5SMatt Jacob } 1282d81ba9d5SMatt Jacob } else { 1283b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1284b09b0095SMatt Jacob "ctio->simqfrozen(%x)", isp->isp_osinfo.simqfrozen); 1285d81ba9d5SMatt Jacob } 1286d81ba9d5SMatt Jacob } 1287d81ba9d5SMatt Jacob xpt_done(ccb); 1288d81ba9d5SMatt Jacob } 1289d81ba9d5SMatt Jacob #endif 1290d81ba9d5SMatt Jacob 1291478f8a96SJustin T. Gibbs static void 1292cbf57b47SMatt Jacob isp_cam_async(void *cbarg, u_int32_t code, struct cam_path *path, void *arg) 1293478f8a96SJustin T. Gibbs { 1294478f8a96SJustin T. Gibbs struct cam_sim *sim; 1295478f8a96SJustin T. Gibbs struct ispsoftc *isp; 1296478f8a96SJustin T. Gibbs 1297478f8a96SJustin T. Gibbs sim = (struct cam_sim *)cbarg; 1298478f8a96SJustin T. Gibbs isp = (struct ispsoftc *) cam_sim_softc(sim); 1299478f8a96SJustin T. Gibbs switch (code) { 1300478f8a96SJustin T. Gibbs case AC_LOST_DEVICE: 1301ab6c4b31SMatt Jacob if (IS_SCSI(isp)) { 1302478f8a96SJustin T. Gibbs u_int16_t oflags, nflags; 1303478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 1304f6e75de2SMatt Jacob int rvf, tgt; 1305478f8a96SJustin T. Gibbs 1306f9e908dcSMatt Jacob tgt = xpt_path_target_id(path); 1307f9e908dcSMatt Jacob rvf = ISP_FW_REVX(isp->isp_fwrev); 1308f6e75de2SMatt Jacob ISP_LOCK(isp); 1309ea6f23cdSMatt Jacob sdp += cam_sim_bus(sim); 1310ea6f23cdSMatt Jacob isp->isp_update |= (1 << cam_sim_bus(sim)); 1311478f8a96SJustin T. Gibbs nflags = DPARM_SAFE_DFLT; 1312f9e908dcSMatt Jacob if (rvf >= ISP_FW_REV(7, 55, 0) || 1313f9e908dcSMatt Jacob (ISP_FW_REV(4, 55, 0) <= rvf && 1314f9e908dcSMatt Jacob (rvf < ISP_FW_REV(5, 0, 0)))) { 1315478f8a96SJustin T. Gibbs nflags |= DPARM_NARROW | DPARM_ASYNC; 1316478f8a96SJustin T. Gibbs } 1317478f8a96SJustin T. Gibbs oflags = sdp->isp_devparam[tgt].dev_flags; 1318478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_flags = nflags; 1319478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_update = 1; 1320478f8a96SJustin T. Gibbs (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL); 1321478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_flags = oflags; 1322f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1323478f8a96SJustin T. Gibbs } 1324478f8a96SJustin T. Gibbs break; 1325478f8a96SJustin T. Gibbs default: 13260470d791SMatt Jacob printf("%s: isp_attach Async Code 0x%x\n", isp->isp_name, code); 1327478f8a96SJustin T. Gibbs break; 1328478f8a96SJustin T. Gibbs } 1329478f8a96SJustin T. Gibbs } 1330478f8a96SJustin T. Gibbs 1331478f8a96SJustin T. Gibbs static void 1332c3055363SMatt Jacob isp_poll(struct cam_sim *sim) 1333478f8a96SJustin T. Gibbs { 1334c40e096eSMatt Jacob struct ispsoftc *isp = cam_sim_softc(sim); 1335c40e096eSMatt Jacob ISP_LOCK(isp); 1336c40e096eSMatt Jacob (void) isp_intr(isp); 1337c40e096eSMatt Jacob ISP_UNLOCK(isp); 1338478f8a96SJustin T. Gibbs } 1339478f8a96SJustin T. Gibbs 13400470d791SMatt Jacob static void 13410470d791SMatt Jacob isp_relsim(void *arg) 13420470d791SMatt Jacob { 13430470d791SMatt Jacob struct ispsoftc *isp = arg; 1344f6e75de2SMatt Jacob ISP_LOCK(isp); 13450470d791SMatt Jacob if (isp->isp_osinfo.simqfrozen & SIMQFRZ_TIMED) { 13460470d791SMatt Jacob int wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_TIMED; 13470470d791SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_TIMED; 13480470d791SMatt Jacob if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) { 13490470d791SMatt Jacob xpt_release_simq(isp->isp_sim, 1); 1350b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "timed relsimq"); 13510470d791SMatt Jacob } 13520470d791SMatt Jacob } 1353f6e75de2SMatt Jacob ISP_UNLOCK(isp); 13540470d791SMatt Jacob } 1355ab6c4b31SMatt Jacob 1356478f8a96SJustin T. Gibbs static void 1357b85389e1SMatt Jacob isp_watchdog(void *arg) 1358cc8df88bSMatt Jacob { 1359b09b0095SMatt Jacob XS_T *xs = arg; 1360cc8df88bSMatt Jacob struct ispsoftc *isp = XS_ISP(xs); 1361cc8df88bSMatt Jacob u_int32_t handle; 1362b85389e1SMatt Jacob 1363cc8df88bSMatt Jacob /* 1364b85389e1SMatt Jacob * We've decided this command is dead. Make sure we're not trying 1365b85389e1SMatt Jacob * to kill a command that's already dead by getting it's handle and 1366b85389e1SMatt Jacob * and seeing whether it's still alive. 1367cc8df88bSMatt Jacob */ 1368f6e75de2SMatt Jacob ISP_LOCK(isp); 1369cc8df88bSMatt Jacob handle = isp_find_handle(isp, xs); 1370cc8df88bSMatt Jacob if (handle) { 1371b85389e1SMatt Jacob u_int16_t r; 1372b85389e1SMatt Jacob 1373b85389e1SMatt Jacob if (XS_CMD_DONE_P(xs)) { 1374b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG1, 1375b09b0095SMatt Jacob "watchdog found done cmd (handle 0x%x)", handle); 1376f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1377b85389e1SMatt Jacob return; 1378b85389e1SMatt Jacob } 1379b85389e1SMatt Jacob 1380b85389e1SMatt Jacob if (XS_CMD_WDOG_P(xs)) { 1381b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1382b09b0095SMatt Jacob "recursive watchdog (handle 0x%x)", handle); 1383f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1384b85389e1SMatt Jacob return; 1385b85389e1SMatt Jacob } 1386b85389e1SMatt Jacob 1387b85389e1SMatt Jacob XS_CMD_S_WDOG(xs); 1388b85389e1SMatt Jacob 1389b85389e1SMatt Jacob r = ISP_READ(isp, BIU_ISR); 1390b85389e1SMatt Jacob 1391b85389e1SMatt Jacob if (INT_PENDING(isp, r) && isp_intr(isp) && XS_CMD_DONE_P(xs)) { 1392b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1393b09b0095SMatt Jacob "watchdog cleanup (%x, %x)", handle, r); 1394b85389e1SMatt Jacob xpt_done((union ccb *) xs); 1395b85389e1SMatt Jacob } else if (XS_CMD_GRACE_P(xs)) { 13961fcf5debSMatt Jacob /* 13971fcf5debSMatt Jacob * Make sure the command is *really* dead before we 13981fcf5debSMatt Jacob * release the handle (and DMA resources) for reuse. 13991fcf5debSMatt Jacob */ 14001fcf5debSMatt Jacob (void) isp_control(isp, ISPCTL_ABORT_CMD, arg); 14011fcf5debSMatt Jacob 14021fcf5debSMatt Jacob /* 14031fcf5debSMatt Jacob * After this point, the comamnd is really dead. 14041fcf5debSMatt Jacob */ 1405f6e75de2SMatt Jacob if (XS_XFRLEN(xs)) { 1406f6e75de2SMatt Jacob ISP_DMAFREE(isp, xs, handle); 1407f6e75de2SMatt Jacob } 1408cc8df88bSMatt Jacob isp_destroy_handle(isp, handle); 1409cc8df88bSMatt Jacob xpt_print_path(xs->ccb_h.path); 1410b85389e1SMatt Jacob printf("%s: watchdog timeout (%x, %x)\n", 1411b85389e1SMatt Jacob isp->isp_name, handle, r); 1412cc8df88bSMatt Jacob XS_SETERR(xs, CAM_CMD_TIMEOUT); 1413b85389e1SMatt Jacob XS_CMD_C_WDOG(xs); 1414cc8df88bSMatt Jacob isp_done(xs); 1415b85389e1SMatt Jacob } else { 1416b85389e1SMatt Jacob u_int16_t iptr, optr; 1417b85389e1SMatt Jacob ispreq_t *mp; 1418b85389e1SMatt Jacob 1419b85389e1SMatt Jacob XS_CMD_C_WDOG(xs); 1420b85389e1SMatt Jacob xs->ccb_h.timeout_ch = timeout(isp_watchdog, xs, hz); 1421b85389e1SMatt Jacob if (isp_getrqentry(isp, &iptr, &optr, (void **) &mp)) { 1422f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1423b85389e1SMatt Jacob return; 1424b85389e1SMatt Jacob } 1425b85389e1SMatt Jacob XS_CMD_S_GRACE(xs); 1426b85389e1SMatt Jacob MEMZERO((void *) mp, sizeof (*mp)); 1427b85389e1SMatt Jacob mp->req_header.rqs_entry_count = 1; 1428b85389e1SMatt Jacob mp->req_header.rqs_entry_type = RQSTYPE_MARKER; 1429b85389e1SMatt Jacob mp->req_modifier = SYNC_ALL; 1430b85389e1SMatt Jacob mp->req_target = XS_CHANNEL(xs) << 7; 1431b85389e1SMatt Jacob ISP_SWIZZLE_REQUEST(isp, mp); 1432b85389e1SMatt Jacob ISP_ADD_REQUEST(isp, iptr); 1433b85389e1SMatt Jacob } 1434b85389e1SMatt Jacob } else { 1435b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "watchdog with no command"); 1436cc8df88bSMatt Jacob } 1437f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1438cc8df88bSMatt Jacob } 1439cc8df88bSMatt Jacob 1440cc8df88bSMatt Jacob static void 1441c3055363SMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb) 1442478f8a96SJustin T. Gibbs { 1443f6e75de2SMatt Jacob int bus, tgt, error; 1444478f8a96SJustin T. Gibbs struct ispsoftc *isp; 14454663e367SJustin T. Gibbs struct ccb_trans_settings *cts; 1446478f8a96SJustin T. Gibbs 1447478f8a96SJustin T. Gibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n")); 1448478f8a96SJustin T. Gibbs 1449478f8a96SJustin T. Gibbs isp = (struct ispsoftc *)cam_sim_softc(sim); 1450478f8a96SJustin T. Gibbs ccb->ccb_h.sim_priv.entries[0].field = 0; 1451478f8a96SJustin T. Gibbs ccb->ccb_h.sim_priv.entries[1].ptr = isp; 14520470d791SMatt Jacob if (isp->isp_state != ISP_RUNSTATE && 14530470d791SMatt Jacob ccb->ccb_h.func_code == XPT_SCSI_IO) { 1454f6e75de2SMatt Jacob ISP_LOCK(isp); 145557c801f5SMatt Jacob isp_init(isp); 145657c801f5SMatt Jacob if (isp->isp_state != ISP_INITSTATE) { 1457f6e75de2SMatt Jacob ISP_UNLOCK(isp); 145857c801f5SMatt Jacob /* 145957c801f5SMatt Jacob * Lie. Say it was a selection timeout. 146057c801f5SMatt Jacob */ 1461b85389e1SMatt Jacob ccb->ccb_h.status = CAM_SEL_TIMEOUT | CAM_DEV_QFRZN; 14620470d791SMatt Jacob xpt_freeze_devq(ccb->ccb_h.path, 1); 146357c801f5SMatt Jacob xpt_done(ccb); 146457c801f5SMatt Jacob return; 146557c801f5SMatt Jacob } 146657c801f5SMatt Jacob isp->isp_state = ISP_RUNSTATE; 1467f6e75de2SMatt Jacob ISP_UNLOCK(isp); 146857c801f5SMatt Jacob } 1469b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "isp_action code %x", ccb->ccb_h.func_code); 1470478f8a96SJustin T. Gibbs 1471478f8a96SJustin T. Gibbs switch (ccb->ccb_h.func_code) { 1472478f8a96SJustin T. Gibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 1473478f8a96SJustin T. Gibbs /* 1474478f8a96SJustin T. Gibbs * Do a couple of preliminary checks... 1475478f8a96SJustin T. Gibbs */ 1476478f8a96SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { 1477478f8a96SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) { 1478478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 1479478f8a96SJustin T. Gibbs xpt_done(ccb); 1480478f8a96SJustin T. Gibbs break; 1481478f8a96SJustin T. Gibbs } 1482478f8a96SJustin T. Gibbs } 14830470d791SMatt Jacob #ifdef DIAGNOSTIC 14840470d791SMatt Jacob if (ccb->ccb_h.target_id > (ISP_MAX_TARGETS(isp) - 1)) { 1485478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 14860470d791SMatt Jacob } else if (ccb->ccb_h.target_lun > (ISP_MAX_LUNS(isp) - 1)) { 1487478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 1488478f8a96SJustin T. Gibbs } 1489478f8a96SJustin T. Gibbs if (ccb->ccb_h.status == CAM_PATH_INVALID) { 1490bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 1491bfbab170SMatt Jacob "invalid tgt/lun (%d.%d) in XPT_SCSI_IO", 1492bfbab170SMatt Jacob ccb->ccb_h.target_id, ccb->ccb_h.target_lun); 1493478f8a96SJustin T. Gibbs xpt_done(ccb); 1494478f8a96SJustin T. Gibbs break; 1495478f8a96SJustin T. Gibbs } 14960470d791SMatt Jacob #endif 14970470d791SMatt Jacob ((struct ccb_scsiio *) ccb)->scsi_status = SCSI_STATUS_OK; 1498f6e75de2SMatt Jacob ISP_LOCK(isp); 1499b09b0095SMatt Jacob error = isp_start((XS_T *) ccb); 1500f6e75de2SMatt Jacob ISP_UNLOCK(isp); 15010470d791SMatt Jacob switch (error) { 1502478f8a96SJustin T. Gibbs case CMD_QUEUED: 1503478f8a96SJustin T. Gibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 1504cc8df88bSMatt Jacob if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { 1505b85389e1SMatt Jacob int ticks; 1506cc8df88bSMatt Jacob if (ccb->ccb_h.timeout == CAM_TIME_DEFAULT) 1507b85389e1SMatt Jacob ticks = 60 * 1000 * hz; 1508b85389e1SMatt Jacob else 1509b85389e1SMatt Jacob ticks = ccb->ccb_h.timeout * hz; 1510b85389e1SMatt Jacob ticks = ((ticks + 999) / 1000) + hz + hz; 1511cc8df88bSMatt Jacob ccb->ccb_h.timeout_ch = 1512b85389e1SMatt Jacob timeout(isp_watchdog, (caddr_t)ccb, ticks); 1513b85389e1SMatt Jacob } else { 1514b85389e1SMatt Jacob callout_handle_init(&ccb->ccb_h.timeout_ch); 1515cc8df88bSMatt Jacob } 1516478f8a96SJustin T. Gibbs break; 15170470d791SMatt Jacob case CMD_RQLATER: 15180470d791SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 1519b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1520b09b0095SMatt Jacob "RQLATER freeze simq"); 15210470d791SMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_TIMED; 15220470d791SMatt Jacob timeout(isp_relsim, isp, 500); 1523478f8a96SJustin T. Gibbs xpt_freeze_simq(sim, 1); 152400f50ce8SMatt Jacob } 1525b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 1526478f8a96SJustin T. Gibbs xpt_done(ccb); 1527478f8a96SJustin T. Gibbs break; 15280470d791SMatt Jacob case CMD_EAGAIN: 15290470d791SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 15300470d791SMatt Jacob xpt_freeze_simq(sim, 1); 1531b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1532b09b0095SMatt Jacob "EAGAIN freeze simq"); 1533478f8a96SJustin T. Gibbs } 15340470d791SMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_RESOURCE; 1535b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 1536478f8a96SJustin T. Gibbs xpt_done(ccb); 1537478f8a96SJustin T. Gibbs break; 15380470d791SMatt Jacob case CMD_COMPLETE: 1539c40e096eSMatt Jacob ISP_LOCK(isp); 15400470d791SMatt Jacob isp_done((struct ccb_scsiio *) ccb); 1541c40e096eSMatt Jacob ISP_UNLOCK(isp); 15420470d791SMatt Jacob break; 15430470d791SMatt Jacob default: 1544bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 1545bfbab170SMatt Jacob "What's this? 0x%x at %d in file %s", 154691f1caa2SMatt Jacob error, __LINE__, __FILE__); 1547b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQ_CMP_ERR); 15480470d791SMatt Jacob xpt_done(ccb); 1549478f8a96SJustin T. Gibbs } 1550478f8a96SJustin T. Gibbs break; 1551478f8a96SJustin T. Gibbs 1552d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 1553478f8a96SJustin T. Gibbs case XPT_EN_LUN: /* Enable LUN as a target */ 1554d81ba9d5SMatt Jacob isp_en_lun(isp, ccb); 1555478f8a96SJustin T. Gibbs xpt_done(ccb); 1556478f8a96SJustin T. Gibbs break; 1557478f8a96SJustin T. Gibbs 1558d81ba9d5SMatt Jacob case XPT_NOTIFY_ACK: /* recycle notify ack */ 1559d81ba9d5SMatt Jacob case XPT_IMMED_NOTIFY: /* Add Immediate Notify Resource */ 1560d81ba9d5SMatt Jacob case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */ 1561d81ba9d5SMatt Jacob { 1562d81ba9d5SMatt Jacob tstate_t *tptr = get_lun_statep(isp, ccb->ccb_h.target_lun); 1563d81ba9d5SMatt Jacob if (tptr == NULL) { 1564d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 1565d81ba9d5SMatt Jacob xpt_done(ccb); 1566d81ba9d5SMatt Jacob break; 1567d81ba9d5SMatt Jacob } 1568f48ce188SMatt Jacob ccb->ccb_h.sim_priv.entries[0].field = 0; 1569f48ce188SMatt Jacob ccb->ccb_h.sim_priv.entries[1].ptr = isp; 1570f6e75de2SMatt Jacob ISP_LOCK(isp); 1571d81ba9d5SMatt Jacob if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 1572f48ce188SMatt Jacob #if 0 1573f48ce188SMatt Jacob (void) isp_target_putback_atio(isp, ccb); 1574f48ce188SMatt Jacob #endif 1575d81ba9d5SMatt Jacob SLIST_INSERT_HEAD(&tptr->atios, 1576d81ba9d5SMatt Jacob &ccb->ccb_h, sim_links.sle); 1577d81ba9d5SMatt Jacob } else { 1578d81ba9d5SMatt Jacob SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, 1579d81ba9d5SMatt Jacob sim_links.sle); 1580d81ba9d5SMatt Jacob } 1581f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1582d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1583d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_INPROG; 1584d81ba9d5SMatt Jacob break; 1585d81ba9d5SMatt Jacob } 1586d81ba9d5SMatt Jacob case XPT_CONT_TARGET_IO: 1587d81ba9d5SMatt Jacob { 1588f6e75de2SMatt Jacob ISP_LOCK(isp); 1589d81ba9d5SMatt Jacob ccb->ccb_h.status = isp_target_start_ctio(isp, ccb); 1590d81ba9d5SMatt Jacob if (ccb->ccb_h.status != CAM_REQ_INPROG) { 1591d81ba9d5SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 1592d81ba9d5SMatt Jacob xpt_freeze_simq(sim, 1); 1593d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 1594d81ba9d5SMatt Jacob printf("XPT_CONT_TARGET_IO freeze simq\n"); 1595d81ba9d5SMatt Jacob } 1596d81ba9d5SMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_RESOURCE; 1597b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 1598d81ba9d5SMatt Jacob xpt_done(ccb); 1599d81ba9d5SMatt Jacob } else { 1600d81ba9d5SMatt Jacob ccb->ccb_h.status |= CAM_SIM_QUEUED; 1601d81ba9d5SMatt Jacob } 1602f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1603d81ba9d5SMatt Jacob break; 1604d81ba9d5SMatt Jacob } 1605d81ba9d5SMatt Jacob #endif 1606478f8a96SJustin T. Gibbs case XPT_RESET_DEV: /* BDR the specified SCSI device */ 1607d81ba9d5SMatt Jacob 1608d81ba9d5SMatt Jacob bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path)); 1609d81ba9d5SMatt Jacob tgt = ccb->ccb_h.target_id; 1610d81ba9d5SMatt Jacob tgt |= (bus << 16); 1611d81ba9d5SMatt Jacob 1612f6e75de2SMatt Jacob ISP_LOCK(isp); 1613ea6f23cdSMatt Jacob error = isp_control(isp, ISPCTL_RESET_DEV, &tgt); 1614f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1615478f8a96SJustin T. Gibbs if (error) { 1616478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 1617478f8a96SJustin T. Gibbs } else { 1618478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 1619478f8a96SJustin T. Gibbs } 1620478f8a96SJustin T. Gibbs xpt_done(ccb); 1621478f8a96SJustin T. Gibbs break; 1622478f8a96SJustin T. Gibbs case XPT_ABORT: /* Abort the specified CCB */ 1623d81ba9d5SMatt Jacob { 1624d81ba9d5SMatt Jacob union ccb *accb = ccb->cab.abort_ccb; 1625d81ba9d5SMatt Jacob switch (accb->ccb_h.func_code) { 1626d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 1627d81ba9d5SMatt Jacob case XPT_ACCEPT_TARGET_IO: 1628d81ba9d5SMatt Jacob case XPT_IMMED_NOTIFY: 1629d81ba9d5SMatt Jacob ccb->ccb_h.status = isp_abort_tgt_ccb(isp, ccb); 1630d81ba9d5SMatt Jacob break; 1631d81ba9d5SMatt Jacob case XPT_CONT_TARGET_IO: 1632b09b0095SMatt Jacob isp_prt(isp, ISP_LOGERR, "cannot abort CTIOs yet"); 1633d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_UA_ABORT; 1634d81ba9d5SMatt Jacob break; 1635d81ba9d5SMatt Jacob #endif 1636d81ba9d5SMatt Jacob case XPT_SCSI_IO: 1637f6e75de2SMatt Jacob ISP_LOCK(isp); 1638478f8a96SJustin T. Gibbs error = isp_control(isp, ISPCTL_ABORT_CMD, ccb); 1639f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1640478f8a96SJustin T. Gibbs if (error) { 1641d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_UA_ABORT; 1642478f8a96SJustin T. Gibbs } else { 1643478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 1644478f8a96SJustin T. Gibbs } 1645d81ba9d5SMatt Jacob break; 1646d81ba9d5SMatt Jacob default: 1647d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_INVALID; 1648d81ba9d5SMatt Jacob break; 1649d81ba9d5SMatt Jacob } 1650478f8a96SJustin T. Gibbs xpt_done(ccb); 1651478f8a96SJustin T. Gibbs break; 1652d81ba9d5SMatt Jacob } 1653478f8a96SJustin T. Gibbs case XPT_SET_TRAN_SETTINGS: /* Nexus Settings */ 1654478f8a96SJustin T. Gibbs 1655478f8a96SJustin T. Gibbs cts = &ccb->cts; 1656478f8a96SJustin T. Gibbs tgt = cts->ccb_h.target_id; 1657f6e75de2SMatt Jacob ISP_LOCK(isp); 1658ab6c4b31SMatt Jacob if (IS_SCSI(isp)) { 1659478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 1660478f8a96SJustin T. Gibbs u_int16_t *dptr; 1661d81ba9d5SMatt Jacob 1662d81ba9d5SMatt Jacob bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 1663478f8a96SJustin T. Gibbs 1664ea6f23cdSMatt Jacob sdp += bus; 1665478f8a96SJustin T. Gibbs #if 0 1666478f8a96SJustin T. Gibbs if (cts->flags & CCB_TRANS_CURRENT_SETTINGS) 1667478f8a96SJustin T. Gibbs dptr = &sdp->isp_devparam[tgt].cur_dflags; 1668478f8a96SJustin T. Gibbs else 1669478f8a96SJustin T. Gibbs dptr = &sdp->isp_devparam[tgt].dev_flags; 1670478f8a96SJustin T. Gibbs #else 1671478f8a96SJustin T. Gibbs /* 1672478f8a96SJustin T. Gibbs * We always update (internally) from dev_flags 1673478f8a96SJustin T. Gibbs * so any request to change settings just gets 1674478f8a96SJustin T. Gibbs * vectored to that location. 1675478f8a96SJustin T. Gibbs */ 1676478f8a96SJustin T. Gibbs dptr = &sdp->isp_devparam[tgt].dev_flags; 1677478f8a96SJustin T. Gibbs #endif 1678478f8a96SJustin T. Gibbs 1679478f8a96SJustin T. Gibbs /* 1680478f8a96SJustin T. Gibbs * Note that these operations affect the 16814394c92fSMatt Jacob * the goal flags (dev_flags)- not 1682478f8a96SJustin T. Gibbs * the current state flags. Then we mark 1683478f8a96SJustin T. Gibbs * things so that the next operation to 1684478f8a96SJustin T. Gibbs * this HBA will cause the update to occur. 1685478f8a96SJustin T. Gibbs */ 1686478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_DISC_VALID) { 1687478f8a96SJustin T. Gibbs if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) { 1688478f8a96SJustin T. Gibbs *dptr |= DPARM_DISC; 1689478f8a96SJustin T. Gibbs } else { 1690478f8a96SJustin T. Gibbs *dptr &= ~DPARM_DISC; 1691478f8a96SJustin T. Gibbs } 1692478f8a96SJustin T. Gibbs } 1693478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_TQ_VALID) { 1694478f8a96SJustin T. Gibbs if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) { 1695478f8a96SJustin T. Gibbs *dptr |= DPARM_TQING; 1696478f8a96SJustin T. Gibbs } else { 1697478f8a96SJustin T. Gibbs *dptr &= ~DPARM_TQING; 1698478f8a96SJustin T. Gibbs } 1699478f8a96SJustin T. Gibbs } 1700478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) { 1701478f8a96SJustin T. Gibbs switch (cts->bus_width) { 1702478f8a96SJustin T. Gibbs case MSG_EXT_WDTR_BUS_16_BIT: 1703478f8a96SJustin T. Gibbs *dptr |= DPARM_WIDE; 1704478f8a96SJustin T. Gibbs break; 1705478f8a96SJustin T. Gibbs default: 1706478f8a96SJustin T. Gibbs *dptr &= ~DPARM_WIDE; 1707478f8a96SJustin T. Gibbs } 1708478f8a96SJustin T. Gibbs } 1709478f8a96SJustin T. Gibbs /* 1710478f8a96SJustin T. Gibbs * Any SYNC RATE of nonzero and SYNC_OFFSET 1711478f8a96SJustin T. Gibbs * of nonzero will cause us to go to the 1712478f8a96SJustin T. Gibbs * selected (from NVRAM) maximum value for 1713478f8a96SJustin T. Gibbs * this device. At a later point, we'll 1714478f8a96SJustin T. Gibbs * allow finer control. 1715478f8a96SJustin T. Gibbs */ 1716478f8a96SJustin T. Gibbs if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) && 1717478f8a96SJustin T. Gibbs (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) && 1718478f8a96SJustin T. Gibbs (cts->sync_offset > 0)) { 1719478f8a96SJustin T. Gibbs *dptr |= DPARM_SYNC; 1720478f8a96SJustin T. Gibbs } else { 1721478f8a96SJustin T. Gibbs *dptr &= ~DPARM_SYNC; 1722478f8a96SJustin T. Gibbs } 1723ab6c4b31SMatt Jacob *dptr |= DPARM_SAFE_DFLT; 1724bfbab170SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 1725bfbab170SMatt Jacob "%d.%d set %s period 0x%x offset 0x%x flags 0x%x", 172691f1caa2SMatt Jacob bus, tgt, (cts->flags & CCB_TRANS_CURRENT_SETTINGS)? 17274394c92fSMatt Jacob "current" : "user", 17282b052931SMatt Jacob sdp->isp_devparam[tgt].sync_period, 17292b052931SMatt Jacob sdp->isp_devparam[tgt].sync_offset, 173083ae4407SMatt Jacob sdp->isp_devparam[tgt].dev_flags); 1731478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_update = 1; 1732ea6f23cdSMatt Jacob isp->isp_update |= (1 << bus); 1733478f8a96SJustin T. Gibbs } 1734f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1735478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 1736478f8a96SJustin T. Gibbs xpt_done(ccb); 1737478f8a96SJustin T. Gibbs break; 1738478f8a96SJustin T. Gibbs 1739478f8a96SJustin T. Gibbs case XPT_GET_TRAN_SETTINGS: 1740478f8a96SJustin T. Gibbs 1741478f8a96SJustin T. Gibbs cts = &ccb->cts; 1742478f8a96SJustin T. Gibbs tgt = cts->ccb_h.target_id; 1743ab6c4b31SMatt Jacob if (IS_FC(isp)) { 1744478f8a96SJustin T. Gibbs /* 1745478f8a96SJustin T. Gibbs * a lot of normal SCSI things don't make sense. 1746478f8a96SJustin T. Gibbs */ 1747478f8a96SJustin T. Gibbs cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB; 1748478f8a96SJustin T. Gibbs cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 1749478f8a96SJustin T. Gibbs /* 1750478f8a96SJustin T. Gibbs * How do you measure the width of a high 1751478f8a96SJustin T. Gibbs * speed serial bus? Well, in bytes. 1752478f8a96SJustin T. Gibbs * 1753478f8a96SJustin T. Gibbs * Offset and period make no sense, though, so we set 1754478f8a96SJustin T. Gibbs * (above) a 'base' transfer speed to be gigabit. 1755478f8a96SJustin T. Gibbs */ 1756478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 1757478f8a96SJustin T. Gibbs } else { 1758478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 17594394c92fSMatt Jacob u_int16_t dval, pval, oval; 1760ea6f23cdSMatt Jacob int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 1761478f8a96SJustin T. Gibbs 1762ea6f23cdSMatt Jacob sdp += bus; 17634394c92fSMatt Jacob if (cts->flags & CCB_TRANS_CURRENT_SETTINGS) { 1764f6e75de2SMatt Jacob ISP_LOCK(isp); 176583ae4407SMatt Jacob sdp->isp_devparam[tgt].dev_refresh = 1; 176683ae4407SMatt Jacob isp->isp_update |= (1 << bus); 176783ae4407SMatt Jacob (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, 176883ae4407SMatt Jacob NULL); 1769f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1770478f8a96SJustin T. Gibbs dval = sdp->isp_devparam[tgt].cur_dflags; 17714394c92fSMatt Jacob oval = sdp->isp_devparam[tgt].cur_offset; 17724394c92fSMatt Jacob pval = sdp->isp_devparam[tgt].cur_period; 17734394c92fSMatt Jacob } else { 1774478f8a96SJustin T. Gibbs dval = sdp->isp_devparam[tgt].dev_flags; 17754394c92fSMatt Jacob oval = sdp->isp_devparam[tgt].sync_offset; 17764394c92fSMatt Jacob pval = sdp->isp_devparam[tgt].sync_period; 17774394c92fSMatt Jacob } 1778478f8a96SJustin T. Gibbs 1779f6e75de2SMatt Jacob ISP_LOCK(isp); 1780478f8a96SJustin T. Gibbs cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); 1781478f8a96SJustin T. Gibbs 1782478f8a96SJustin T. Gibbs if (dval & DPARM_DISC) { 1783478f8a96SJustin T. Gibbs cts->flags |= CCB_TRANS_DISC_ENB; 1784478f8a96SJustin T. Gibbs } 1785478f8a96SJustin T. Gibbs if (dval & DPARM_TQING) { 1786478f8a96SJustin T. Gibbs cts->flags |= CCB_TRANS_TAG_ENB; 1787478f8a96SJustin T. Gibbs } 1788478f8a96SJustin T. Gibbs if (dval & DPARM_WIDE) { 1789478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 1790478f8a96SJustin T. Gibbs } else { 1791478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 1792478f8a96SJustin T. Gibbs } 1793478f8a96SJustin T. Gibbs cts->valid = CCB_TRANS_BUS_WIDTH_VALID | 1794478f8a96SJustin T. Gibbs CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 1795478f8a96SJustin T. Gibbs 17964394c92fSMatt Jacob if ((dval & DPARM_SYNC) && oval != 0) { 17974394c92fSMatt Jacob cts->sync_period = pval; 17984394c92fSMatt Jacob cts->sync_offset = oval; 1799478f8a96SJustin T. Gibbs cts->valid |= 1800478f8a96SJustin T. Gibbs CCB_TRANS_SYNC_RATE_VALID | 1801478f8a96SJustin T. Gibbs CCB_TRANS_SYNC_OFFSET_VALID; 1802478f8a96SJustin T. Gibbs } 1803f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1804bfbab170SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, 1805bfbab170SMatt Jacob "%d.%d get %s period 0x%x offset 0x%x flags 0x%x", 180691f1caa2SMatt Jacob bus, tgt, (cts->flags & CCB_TRANS_CURRENT_SETTINGS)? 180783ae4407SMatt Jacob "current" : "user", pval, oval, dval); 1808478f8a96SJustin T. Gibbs } 1809478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 1810478f8a96SJustin T. Gibbs xpt_done(ccb); 1811478f8a96SJustin T. Gibbs break; 1812478f8a96SJustin T. Gibbs 1813478f8a96SJustin T. Gibbs case XPT_CALC_GEOMETRY: 1814478f8a96SJustin T. Gibbs { 1815478f8a96SJustin T. Gibbs struct ccb_calc_geometry *ccg; 1816478f8a96SJustin T. Gibbs u_int32_t secs_per_cylinder; 1817478f8a96SJustin T. Gibbs u_int32_t size_mb; 1818478f8a96SJustin T. Gibbs 1819478f8a96SJustin T. Gibbs ccg = &ccb->ccg; 1820478f8a96SJustin T. Gibbs if (ccg->block_size == 0) { 1821bfbab170SMatt Jacob isp_prt(isp, ISP_LOGERR, 1822bfbab170SMatt Jacob "%d.%d XPT_CALC_GEOMETRY block size 0?", 1823bfbab170SMatt Jacob ccg->ccb_h.target_id, ccg->ccb_h.target_lun); 1824478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 1825478f8a96SJustin T. Gibbs xpt_done(ccb); 1826478f8a96SJustin T. Gibbs break; 1827478f8a96SJustin T. Gibbs } 1828478f8a96SJustin T. Gibbs size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size); 1829478f8a96SJustin T. Gibbs if (size_mb > 1024) { 1830478f8a96SJustin T. Gibbs ccg->heads = 255; 1831478f8a96SJustin T. Gibbs ccg->secs_per_track = 63; 1832478f8a96SJustin T. Gibbs } else { 1833478f8a96SJustin T. Gibbs ccg->heads = 64; 1834478f8a96SJustin T. Gibbs ccg->secs_per_track = 32; 1835478f8a96SJustin T. Gibbs } 1836478f8a96SJustin T. Gibbs secs_per_cylinder = ccg->heads * ccg->secs_per_track; 1837478f8a96SJustin T. Gibbs ccg->cylinders = ccg->volume_size / secs_per_cylinder; 1838478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 1839478f8a96SJustin T. Gibbs xpt_done(ccb); 1840478f8a96SJustin T. Gibbs break; 1841478f8a96SJustin T. Gibbs } 1842478f8a96SJustin T. Gibbs case XPT_RESET_BUS: /* Reset the specified bus */ 1843ab6c4b31SMatt Jacob bus = cam_sim_bus(sim); 1844f6e75de2SMatt Jacob ISP_LOCK(isp); 1845ab6c4b31SMatt Jacob error = isp_control(isp, ISPCTL_RESET_BUS, &bus); 1846f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1847478f8a96SJustin T. Gibbs if (error) 1848478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 18492b052931SMatt Jacob else { 1850ea6f23cdSMatt Jacob if (cam_sim_bus(sim) && isp->isp_path2 != NULL) 1851ea6f23cdSMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); 1852ea6f23cdSMatt Jacob else if (isp->isp_path != NULL) 18532b052931SMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path, NULL); 1854478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 18552b052931SMatt Jacob } 1856478f8a96SJustin T. Gibbs xpt_done(ccb); 1857478f8a96SJustin T. Gibbs break; 1858478f8a96SJustin T. Gibbs 1859478f8a96SJustin T. Gibbs case XPT_TERM_IO: /* Terminate the I/O process */ 1860478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 1861478f8a96SJustin T. Gibbs xpt_done(ccb); 1862478f8a96SJustin T. Gibbs break; 1863478f8a96SJustin T. Gibbs 1864478f8a96SJustin T. Gibbs case XPT_PATH_INQ: /* Path routing inquiry */ 1865478f8a96SJustin T. Gibbs { 1866478f8a96SJustin T. Gibbs struct ccb_pathinq *cpi = &ccb->cpi; 1867478f8a96SJustin T. Gibbs 1868478f8a96SJustin T. Gibbs cpi->version_num = 1; 1869d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 1870d81ba9d5SMatt Jacob cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO; 1871d81ba9d5SMatt Jacob #else 1872478f8a96SJustin T. Gibbs cpi->target_sprt = 0; 1873d81ba9d5SMatt Jacob #endif 1874478f8a96SJustin T. Gibbs cpi->hba_eng_cnt = 0; 18750470d791SMatt Jacob cpi->max_target = ISP_MAX_TARGETS(isp) - 1; 18760470d791SMatt Jacob cpi->max_lun = ISP_MAX_LUNS(isp) - 1; 18770470d791SMatt Jacob cpi->bus_id = cam_sim_bus(sim); 18784394c92fSMatt Jacob if (IS_FC(isp)) { 18794394c92fSMatt Jacob cpi->hba_misc = PIM_NOBUSRESET; 18800470d791SMatt Jacob /* 18810470d791SMatt Jacob * Because our loop ID can shift from time to time, 18820470d791SMatt Jacob * make our initiator ID out of range of our bus. 18830470d791SMatt Jacob */ 18840470d791SMatt Jacob cpi->initiator_id = cpi->max_target + 1; 18850470d791SMatt Jacob 18869deea857SKenneth D. Merry /* 18879deea857SKenneth D. Merry * Set base transfer capabilities for Fibre Channel. 18889deea857SKenneth D. Merry * Technically not correct because we don't know 18899deea857SKenneth D. Merry * what media we're running on top of- but we'll 18909deea857SKenneth D. Merry * look good if we always say 100MB/s. 18919deea857SKenneth D. Merry */ 18929deea857SKenneth D. Merry cpi->base_transfer_speed = 100000; 18930470d791SMatt Jacob cpi->hba_inquiry = PI_TAG_ABLE; 1894478f8a96SJustin T. Gibbs } else { 1895ea6f23cdSMatt Jacob sdparam *sdp = isp->isp_param; 1896ea6f23cdSMatt Jacob sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path)); 18970470d791SMatt Jacob cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; 18984394c92fSMatt Jacob cpi->hba_misc = 0; 1899ea6f23cdSMatt Jacob cpi->initiator_id = sdp->isp_initiator_id; 19009deea857SKenneth D. Merry cpi->base_transfer_speed = 3300; 1901478f8a96SJustin T. Gibbs } 1902478f8a96SJustin T. Gibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 1903478f8a96SJustin T. Gibbs strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN); 1904478f8a96SJustin T. Gibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 1905478f8a96SJustin T. Gibbs cpi->unit_number = cam_sim_unit(sim); 1906478f8a96SJustin T. Gibbs cpi->ccb_h.status = CAM_REQ_CMP; 1907478f8a96SJustin T. Gibbs xpt_done(ccb); 1908478f8a96SJustin T. Gibbs break; 1909478f8a96SJustin T. Gibbs } 1910478f8a96SJustin T. Gibbs default: 1911478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 1912478f8a96SJustin T. Gibbs xpt_done(ccb); 1913478f8a96SJustin T. Gibbs break; 1914478f8a96SJustin T. Gibbs } 1915478f8a96SJustin T. Gibbs } 1916d3a9eb2eSMatt Jacob 1917d3a9eb2eSMatt Jacob #define ISPDDB (CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB) 1918d3a9eb2eSMatt Jacob void 1919c3055363SMatt Jacob isp_done(struct ccb_scsiio *sccb) 1920d3a9eb2eSMatt Jacob { 1921d3a9eb2eSMatt Jacob struct ispsoftc *isp = XS_ISP(sccb); 1922d3a9eb2eSMatt Jacob 1923d3a9eb2eSMatt Jacob if (XS_NOERR(sccb)) 1924d3a9eb2eSMatt Jacob XS_SETERR(sccb, CAM_REQ_CMP); 1925b85389e1SMatt Jacob 1926d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP && 1927d3a9eb2eSMatt Jacob (sccb->scsi_status != SCSI_STATUS_OK)) { 1928d3a9eb2eSMatt Jacob sccb->ccb_h.status &= ~CAM_STATUS_MASK; 192992a1e549SMatt Jacob if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) && 193092a1e549SMatt Jacob (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) { 193192a1e549SMatt Jacob sccb->ccb_h.status |= CAM_AUTOSENSE_FAIL; 193292a1e549SMatt Jacob } else { 1933d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 1934d3a9eb2eSMatt Jacob } 193592a1e549SMatt Jacob } 1936b85389e1SMatt Jacob 19370470d791SMatt Jacob sccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1938d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1939d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 1940d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_DEV_QFRZN; 19410470d791SMatt Jacob xpt_freeze_devq(sccb->ccb_h.path, 1); 19420470d791SMatt Jacob if (sccb->scsi_status != SCSI_STATUS_OK) 1943b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1944b09b0095SMatt Jacob "freeze devq %d.%d %x %x", 1945b09b0095SMatt Jacob sccb->ccb_h.target_id, 19460470d791SMatt Jacob sccb->ccb_h.target_lun, sccb->ccb_h.status, 1947b09b0095SMatt Jacob sccb->scsi_status); 1948d3a9eb2eSMatt Jacob } 1949d3a9eb2eSMatt Jacob } 1950b85389e1SMatt Jacob 19510470d791SMatt Jacob /* 19520470d791SMatt Jacob * If we were frozen waiting resources, clear that we were frozen 19530470d791SMatt Jacob * waiting for resources. If we are no longer frozen, and the devq 19540470d791SMatt Jacob * isn't frozen, mark the completing CCB to have the XPT layer 19550470d791SMatt Jacob * release the simq. 19560470d791SMatt Jacob */ 195757c801f5SMatt Jacob if (isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE) { 195857c801f5SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_RESOURCE; 19590470d791SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 19600470d791SMatt Jacob if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 1961b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1962b09b0095SMatt Jacob "isp_done->relsimq"); 1963d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_RELEASE_SIMQ; 19640470d791SMatt Jacob } else { 1965b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1966b09b0095SMatt Jacob "isp_done->devq frozen"); 1967d3a9eb2eSMatt Jacob } 19680470d791SMatt Jacob } else { 1969b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1970b09b0095SMatt Jacob "isp_done -> simqfrozen = %x", 1971b09b0095SMatt Jacob isp->isp_osinfo.simqfrozen); 19720470d791SMatt Jacob } 19730470d791SMatt Jacob } 1974b85389e1SMatt Jacob if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) && 1975d3a9eb2eSMatt Jacob (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1976d3a9eb2eSMatt Jacob xpt_print_path(sccb->ccb_h.path); 1977d3a9eb2eSMatt Jacob printf("cam completion status 0x%x\n", sccb->ccb_h.status); 1978d3a9eb2eSMatt Jacob } 1979b85389e1SMatt Jacob 1980b85389e1SMatt Jacob XS_CMD_S_DONE(sccb); 1981b85389e1SMatt Jacob if (XS_CMD_WDOG_P(sccb) == 0) { 1982b85389e1SMatt Jacob untimeout(isp_watchdog, (caddr_t)sccb, sccb->ccb_h.timeout_ch); 1983b85389e1SMatt Jacob if (XS_CMD_GRACE_P(sccb)) { 1984b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1985b09b0095SMatt Jacob "finished command on borrowed time"); 1986b85389e1SMatt Jacob } 1987b85389e1SMatt Jacob XS_CMD_S_CLEAR(sccb); 1988c40e096eSMatt Jacob ISP_UNLOCK(isp); 1989c40e096eSMatt Jacob #ifdef ISP_SMPLOCK 1990c40e096eSMatt Jacob mtx_enter(&Giant, MTX_DEF); 1991d3a9eb2eSMatt Jacob xpt_done((union ccb *) sccb); 1992c40e096eSMatt Jacob mtx_exit(&Giant, MTX_DEF); 1993c40e096eSMatt Jacob #else 1994c40e096eSMatt Jacob xpt_done((union ccb *) sccb); 1995c40e096eSMatt Jacob #endif 1996c40e096eSMatt Jacob ISP_LOCK(isp); 1997d3a9eb2eSMatt Jacob } 1998b85389e1SMatt Jacob } 1999d3a9eb2eSMatt Jacob 2000cbf57b47SMatt Jacob int 20010470d791SMatt Jacob isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg) 2002cbf57b47SMatt Jacob { 2003ea6f23cdSMatt Jacob int bus, rv = 0; 2004cbf57b47SMatt Jacob switch (cmd) { 2005cbf57b47SMatt Jacob case ISPASYNC_NEW_TGT_PARAMS: 20060470d791SMatt Jacob { 2007cbf57b47SMatt Jacob int flags, tgt; 2008cbf57b47SMatt Jacob sdparam *sdp = isp->isp_param; 2009cbf57b47SMatt Jacob struct ccb_trans_settings neg; 2010cbf57b47SMatt Jacob struct cam_path *tmppath; 2011cbf57b47SMatt Jacob 2012cbf57b47SMatt Jacob tgt = *((int *)arg); 2013ea6f23cdSMatt Jacob bus = (tgt >> 16) & 0xffff; 2014ea6f23cdSMatt Jacob tgt &= 0xffff; 2015ea6f23cdSMatt Jacob sdp += bus; 2016cbf57b47SMatt Jacob if (xpt_create_path(&tmppath, NULL, 2017ea6f23cdSMatt Jacob cam_sim_path(bus? isp->isp_sim2 : isp->isp_sim), 2018ea6f23cdSMatt Jacob tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 2019bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 2020bfbab170SMatt Jacob "isp_async cannot make temp path for %d.%d", 2021bfbab170SMatt Jacob tgt, bus); 2022cbf57b47SMatt Jacob rv = -1; 2023cbf57b47SMatt Jacob break; 2024cbf57b47SMatt Jacob } 20254394c92fSMatt Jacob flags = sdp->isp_devparam[tgt].cur_dflags; 2026cbf57b47SMatt Jacob neg.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2027cbf57b47SMatt Jacob if (flags & DPARM_DISC) { 2028cbf57b47SMatt Jacob neg.flags |= CCB_TRANS_DISC_ENB; 2029cbf57b47SMatt Jacob } 2030cbf57b47SMatt Jacob if (flags & DPARM_TQING) { 2031cbf57b47SMatt Jacob neg.flags |= CCB_TRANS_TAG_ENB; 2032cbf57b47SMatt Jacob } 2033cbf57b47SMatt Jacob neg.valid |= CCB_TRANS_BUS_WIDTH_VALID; 2034cbf57b47SMatt Jacob neg.bus_width = (flags & DPARM_WIDE)? 2035cbf57b47SMatt Jacob MSG_EXT_WDTR_BUS_8_BIT : MSG_EXT_WDTR_BUS_16_BIT; 20364394c92fSMatt Jacob neg.sync_period = sdp->isp_devparam[tgt].cur_period; 20374394c92fSMatt Jacob neg.sync_offset = sdp->isp_devparam[tgt].cur_offset; 2038cbf57b47SMatt Jacob if (flags & DPARM_SYNC) { 20394394c92fSMatt Jacob neg.valid |= 20404394c92fSMatt Jacob CCB_TRANS_SYNC_RATE_VALID | 2041cbf57b47SMatt Jacob CCB_TRANS_SYNC_OFFSET_VALID; 2042cbf57b47SMatt Jacob } 2043b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2044b09b0095SMatt Jacob "NEW_TGT_PARAMS bus %d tgt %d period %x offset %x flags %x", 2045b09b0095SMatt Jacob bus, tgt, neg.sync_period, neg.sync_offset, flags); 2046cbf57b47SMatt Jacob xpt_setup_ccb(&neg.ccb_h, tmppath, 1); 2047cbf57b47SMatt Jacob xpt_async(AC_TRANSFER_NEG, tmppath, &neg); 2048cbf57b47SMatt Jacob xpt_free_path(tmppath); 2049cbf57b47SMatt Jacob break; 20500470d791SMatt Jacob } 205157c801f5SMatt Jacob case ISPASYNC_BUS_RESET: 2052ea6f23cdSMatt Jacob bus = *((int *)arg); 2053b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected", 2054b09b0095SMatt Jacob bus); 2055ea6f23cdSMatt Jacob if (bus > 0 && isp->isp_path2) { 2056ea6f23cdSMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); 2057ea6f23cdSMatt Jacob } else if (isp->isp_path) { 205857c801f5SMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path, NULL); 205957c801f5SMatt Jacob } 206057c801f5SMatt Jacob break; 206157c801f5SMatt Jacob case ISPASYNC_LOOP_DOWN: 206257c801f5SMatt Jacob if (isp->isp_path) { 20630470d791SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 2064b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2065b09b0095SMatt Jacob "loop down freeze simq"); 206657c801f5SMatt Jacob xpt_freeze_simq(isp->isp_sim, 1); 20670470d791SMatt Jacob } 206857c801f5SMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; 206957c801f5SMatt Jacob } 2070b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop DOWN"); 207157c801f5SMatt Jacob break; 207257c801f5SMatt Jacob case ISPASYNC_LOOP_UP: 207357c801f5SMatt Jacob if (isp->isp_path) { 20740470d791SMatt Jacob int wasfrozen = 20750470d791SMatt Jacob isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN; 207657c801f5SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN; 20770470d791SMatt Jacob if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) { 20780470d791SMatt Jacob xpt_release_simq(isp->isp_sim, 1); 2079b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2080b09b0095SMatt Jacob "loop up release simq"); 208157c801f5SMatt Jacob } 208257c801f5SMatt Jacob } 2083b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop UP"); 208457c801f5SMatt Jacob break; 20854b9d588eSMatt Jacob case ISPASYNC_LOGGED_INOUT: 20860470d791SMatt Jacob { 2087b09b0095SMatt Jacob const char *fmt = "Target %d (Loop 0x%x) Port ID 0x%x " 2088b09b0095SMatt Jacob "role %s %s\n Port WWN 0x%08x%08x\n Node WWN 0x%08x%08x"; 208902ab3379SMatt Jacob const static char *roles[4] = { 20900470d791SMatt Jacob "(none)", "Target", "Initiator", "Target/Initiator" 209157c801f5SMatt Jacob }; 209202ab3379SMatt Jacob char *ptr; 209302ab3379SMatt Jacob fcparam *fcp = isp->isp_param; 209402ab3379SMatt Jacob int tgt = *((int *) arg); 209502ab3379SMatt Jacob struct lportdb *lp = &fcp->portdb[tgt]; 209602ab3379SMatt Jacob 209702ab3379SMatt Jacob if (lp->valid) { 209802ab3379SMatt Jacob ptr = "arrived"; 209902ab3379SMatt Jacob } else { 210002ab3379SMatt Jacob ptr = "disappeared"; 210102ab3379SMatt Jacob } 2102b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, fmt, tgt, lp->loopid, lp->portid, 210302ab3379SMatt Jacob roles[lp->roles & 0x3], ptr, 210402ab3379SMatt Jacob (u_int32_t) (lp->port_wwn >> 32), 210502ab3379SMatt Jacob (u_int32_t) (lp->port_wwn & 0xffffffffLL), 210602ab3379SMatt Jacob (u_int32_t) (lp->node_wwn >> 32), 210702ab3379SMatt Jacob (u_int32_t) (lp->node_wwn & 0xffffffffLL)); 21084394c92fSMatt Jacob break; 21094394c92fSMatt Jacob } 211057c801f5SMatt Jacob case ISPASYNC_CHANGE_NOTIFY: 21114b9d588eSMatt Jacob if (arg == (void *) 1) { 21124b9d588eSMatt Jacob isp_prt(isp, ISP_LOGINFO, 21134b9d588eSMatt Jacob "Name Server Database Changed"); 21144b9d588eSMatt Jacob } else { 21154b9d588eSMatt Jacob isp_prt(isp, ISP_LOGINFO, 21164b9d588eSMatt Jacob "Name Server Database Changed"); 21174b9d588eSMatt Jacob } 211857c801f5SMatt Jacob break; 21190470d791SMatt Jacob #ifdef ISP2100_FABRIC 212002ab3379SMatt Jacob case ISPASYNC_FABRIC_DEV: 212102ab3379SMatt Jacob { 212202ab3379SMatt Jacob int target; 212302ab3379SMatt Jacob struct lportdb *lp; 212440cfc8feSMatt Jacob char *pt; 212540cfc8feSMatt Jacob sns_ganrsp_t *resp = (sns_ganrsp_t *) arg; 212602ab3379SMatt Jacob u_int32_t portid; 212740cfc8feSMatt Jacob u_int64_t wwpn, wwnn; 212802ab3379SMatt Jacob fcparam *fcp = isp->isp_param; 212902ab3379SMatt Jacob 213002ab3379SMatt Jacob rv = -1; 213102ab3379SMatt Jacob 213202ab3379SMatt Jacob portid = 213302ab3379SMatt Jacob (((u_int32_t) resp->snscb_port_id[0]) << 16) | 213402ab3379SMatt Jacob (((u_int32_t) resp->snscb_port_id[1]) << 8) | 213502ab3379SMatt Jacob (((u_int32_t) resp->snscb_port_id[2])); 213640cfc8feSMatt Jacob 213740cfc8feSMatt Jacob wwpn = 213802ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[0]) << 56) | 213902ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[1]) << 48) | 214002ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[2]) << 40) | 214102ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[3]) << 32) | 214202ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[4]) << 24) | 214302ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[5]) << 16) | 214402ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[6]) << 8) | 214502ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[7])); 214640cfc8feSMatt Jacob 214740cfc8feSMatt Jacob wwnn = 214840cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[0]) << 56) | 214940cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[1]) << 48) | 215040cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[2]) << 40) | 215140cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[3]) << 32) | 215240cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[4]) << 24) | 215340cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[5]) << 16) | 215440cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[6]) << 8) | 215540cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[7])); 215640cfc8feSMatt Jacob if (portid == 0 || wwpn == 0) { 215702ab3379SMatt Jacob rv = 0; 215802ab3379SMatt Jacob break; 215902ab3379SMatt Jacob } 216040cfc8feSMatt Jacob 216140cfc8feSMatt Jacob switch (resp->snscb_port_type) { 216240cfc8feSMatt Jacob case 1: 216340cfc8feSMatt Jacob pt = " N_Port"; 216440cfc8feSMatt Jacob break; 216540cfc8feSMatt Jacob case 2: 216640cfc8feSMatt Jacob pt = " NL_Port"; 216740cfc8feSMatt Jacob break; 216840cfc8feSMatt Jacob case 3: 216940cfc8feSMatt Jacob pt = "F/NL_Port"; 217040cfc8feSMatt Jacob break; 217140cfc8feSMatt Jacob case 0x7f: 217240cfc8feSMatt Jacob pt = " Nx_Port"; 217340cfc8feSMatt Jacob break; 217440cfc8feSMatt Jacob case 0x81: 217540cfc8feSMatt Jacob pt = " F_port"; 217640cfc8feSMatt Jacob break; 217740cfc8feSMatt Jacob case 0x82: 217840cfc8feSMatt Jacob pt = " FL_Port"; 217940cfc8feSMatt Jacob break; 218040cfc8feSMatt Jacob case 0x84: 218140cfc8feSMatt Jacob pt = " E_port"; 218240cfc8feSMatt Jacob break; 218340cfc8feSMatt Jacob default: 218440cfc8feSMatt Jacob pt = "?"; 218540cfc8feSMatt Jacob break; 218640cfc8feSMatt Jacob } 2187b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, 2188b09b0095SMatt Jacob "%s @ 0x%x, Node 0x%08x%08x Port %08x%08x", 2189b09b0095SMatt Jacob pt, portid, ((u_int32_t) (wwnn >> 32)), ((u_int32_t) wwnn), 219040cfc8feSMatt Jacob ((u_int32_t) (wwpn >> 32)), ((u_int32_t) wwpn)); 219102ab3379SMatt Jacob for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) { 219202ab3379SMatt Jacob lp = &fcp->portdb[target]; 219340cfc8feSMatt Jacob if (lp->port_wwn == wwpn && lp->node_wwn == wwnn) 219402ab3379SMatt Jacob break; 219502ab3379SMatt Jacob } 219602ab3379SMatt Jacob if (target < MAX_FC_TARG) { 219702ab3379SMatt Jacob rv = 0; 219802ab3379SMatt Jacob break; 219902ab3379SMatt Jacob } 220002ab3379SMatt Jacob for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) { 220102ab3379SMatt Jacob lp = &fcp->portdb[target]; 220202ab3379SMatt Jacob if (lp->port_wwn == 0) 220302ab3379SMatt Jacob break; 220402ab3379SMatt Jacob } 220502ab3379SMatt Jacob if (target == MAX_FC_TARG) { 2206bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 2207bfbab170SMatt Jacob "no more space for fabric devices"); 220802ab3379SMatt Jacob break; 220902ab3379SMatt Jacob } 221040cfc8feSMatt Jacob lp->node_wwn = wwnn; 221140cfc8feSMatt Jacob lp->port_wwn = wwpn; 221202ab3379SMatt Jacob lp->portid = portid; 221302ab3379SMatt Jacob rv = 0; 221402ab3379SMatt Jacob break; 221502ab3379SMatt Jacob } 221602ab3379SMatt Jacob #endif 2217d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2218d81ba9d5SMatt Jacob case ISPASYNC_TARGET_MESSAGE: 2219d81ba9d5SMatt Jacob { 2220d81ba9d5SMatt Jacob tmd_msg_t *mp = arg; 2221b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2222b09b0095SMatt Jacob "bus %d iid %d tgt %d lun %d ttype %x tval %x msg[0]=%x", 2223b09b0095SMatt Jacob mp->nt_bus, (int) mp->nt_iid, (int) mp->nt_tgt, 2224b09b0095SMatt Jacob (int) mp->nt_lun, mp->nt_tagtype, mp->nt_tagval, 2225b09b0095SMatt Jacob mp->nt_msg[0]); 2226d81ba9d5SMatt Jacob break; 2227d81ba9d5SMatt Jacob } 2228d81ba9d5SMatt Jacob case ISPASYNC_TARGET_EVENT: 2229d81ba9d5SMatt Jacob { 2230d81ba9d5SMatt Jacob tmd_event_t *ep = arg; 2231b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2232b09b0095SMatt Jacob "bus %d event code 0x%x", ep->ev_bus, ep->ev_event); 2233d81ba9d5SMatt Jacob break; 2234d81ba9d5SMatt Jacob } 2235d81ba9d5SMatt Jacob case ISPASYNC_TARGET_ACTION: 2236d81ba9d5SMatt Jacob switch (((isphdr_t *)arg)->rqs_entry_type) { 2237cbf57b47SMatt Jacob default: 2238bfbab170SMatt Jacob isp_prt(isp, ISP_LOGWARN, 2239bfbab170SMatt Jacob "event 0x%x for unhandled target action", 2240bfbab170SMatt Jacob ((isphdr_t *)arg)->rqs_entry_type); 2241d81ba9d5SMatt Jacob break; 2242d81ba9d5SMatt Jacob case RQSTYPE_ATIO: 2243d81ba9d5SMatt Jacob rv = isp_handle_platform_atio(isp, (at_entry_t *) arg); 2244d81ba9d5SMatt Jacob break; 2245d81ba9d5SMatt Jacob case RQSTYPE_ATIO2: 2246d81ba9d5SMatt Jacob rv = isp_handle_platform_atio2(isp, (at2_entry_t *)arg); 2247d81ba9d5SMatt Jacob break; 2248d81ba9d5SMatt Jacob case RQSTYPE_CTIO2: 2249d81ba9d5SMatt Jacob case RQSTYPE_CTIO: 2250d81ba9d5SMatt Jacob rv = isp_handle_platform_ctio(isp, arg); 2251d81ba9d5SMatt Jacob break; 2252d81ba9d5SMatt Jacob case RQSTYPE_ENABLE_LUN: 2253d81ba9d5SMatt Jacob case RQSTYPE_MODIFY_LUN: 2254d81ba9d5SMatt Jacob isp_cv_signal_rqe(isp, ((lun_entry_t *)arg)->le_status); 2255d81ba9d5SMatt Jacob break; 2256d81ba9d5SMatt Jacob } 2257d81ba9d5SMatt Jacob break; 2258d81ba9d5SMatt Jacob #endif 2259d81ba9d5SMatt Jacob default: 2260b09b0095SMatt Jacob isp_prt(isp, ISP_LOGERR, "unknown isp_async event %d", cmd); 226102ab3379SMatt Jacob rv = -1; 2262cbf57b47SMatt Jacob break; 2263cbf57b47SMatt Jacob } 2264cbf57b47SMatt Jacob return (rv); 2265cbf57b47SMatt Jacob } 2266cbf57b47SMatt Jacob 226792718a7fSMatt Jacob 226892718a7fSMatt Jacob /* 226992718a7fSMatt Jacob * Locks are held before coming here. 227092718a7fSMatt Jacob */ 227192718a7fSMatt Jacob void 227292718a7fSMatt Jacob isp_uninit(struct ispsoftc *isp) 227392718a7fSMatt Jacob { 2274ea6f23cdSMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_RESET); 227592718a7fSMatt Jacob DISABLE_INTS(isp); 227692718a7fSMatt Jacob } 2277b09b0095SMatt Jacob 2278b09b0095SMatt Jacob void 2279b09b0095SMatt Jacob isp_prt(struct ispsoftc *isp, int level, const char *fmt, ...) 2280b09b0095SMatt Jacob { 2281b09b0095SMatt Jacob va_list ap; 2282b09b0095SMatt Jacob if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) { 2283b09b0095SMatt Jacob return; 2284b09b0095SMatt Jacob } 2285b09b0095SMatt Jacob printf("%s: ", isp->isp_name); 2286b09b0095SMatt Jacob va_start(ap, fmt); 2287b09b0095SMatt Jacob vprintf(fmt, ap); 2288b09b0095SMatt Jacob va_end(ap); 2289b09b0095SMatt Jacob printf("\n"); 2290b09b0095SMatt Jacob } 2291