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) { 78f6e75de2SMatt Jacob printf("%s: could not establish interrupt enable hook\n", 79f6e75de2SMatt Jacob isp->isp_name); 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); 160b6b6ad2fSMatt Jacob #ifdef SERVICING_INTERRUPT 161f6e75de2SMatt Jacob isp->isp_osinfo.intsok = 1; 162b6b6ad2fSMatt Jacob #endif 163f6e75de2SMatt Jacob /* Release our hook so that the boot can continue. */ 164f6e75de2SMatt Jacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 165f6e75de2SMatt Jacob } 166d81ba9d5SMatt Jacob 167d81ba9d5SMatt Jacob /* 168d81ba9d5SMatt Jacob * Put the target mode functions here, because some are inlines 169d81ba9d5SMatt Jacob */ 170d81ba9d5SMatt Jacob 171d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 172d81ba9d5SMatt Jacob 173d81ba9d5SMatt Jacob static __inline int is_lun_enabled(struct ispsoftc *, lun_id_t); 174d81ba9d5SMatt Jacob static __inline int are_any_luns_enabled(struct ispsoftc *); 175d81ba9d5SMatt Jacob static __inline tstate_t *get_lun_statep(struct ispsoftc *, lun_id_t); 176d81ba9d5SMatt Jacob static __inline void rls_lun_statep(struct ispsoftc *, tstate_t *); 177d81ba9d5SMatt Jacob static __inline int isp_psema_sig_rqe(struct ispsoftc *); 178d81ba9d5SMatt Jacob static __inline int isp_cv_wait_timed_rqe(struct ispsoftc *, int); 179d81ba9d5SMatt Jacob static __inline void isp_cv_signal_rqe(struct ispsoftc *, int); 180d81ba9d5SMatt Jacob static __inline void isp_vsema_rqe(struct ispsoftc *); 181d81ba9d5SMatt Jacob static cam_status 182d81ba9d5SMatt Jacob create_lun_state(struct ispsoftc *, struct cam_path *, tstate_t **); 183d81ba9d5SMatt Jacob static void destroy_lun_state(struct ispsoftc *, tstate_t *); 184d81ba9d5SMatt Jacob static void isp_en_lun(struct ispsoftc *, union ccb *); 185d81ba9d5SMatt Jacob static cam_status isp_abort_tgt_ccb(struct ispsoftc *, union ccb *); 186d81ba9d5SMatt Jacob static cam_status isp_target_start_ctio(struct ispsoftc *, union ccb *); 187f48ce188SMatt Jacob static cam_status isp_target_putback_atio(struct ispsoftc *, union ccb *); 188f48ce188SMatt Jacob static timeout_t isp_refire_putback_atio; 189d81ba9d5SMatt Jacob 190d81ba9d5SMatt Jacob static int isp_handle_platform_atio(struct ispsoftc *, at_entry_t *); 191d81ba9d5SMatt Jacob static int isp_handle_platform_atio2(struct ispsoftc *, at2_entry_t *); 192d81ba9d5SMatt Jacob static int isp_handle_platform_ctio(struct ispsoftc *, void *); 193f48ce188SMatt Jacob static void isp_handle_platform_ctio_part2(struct ispsoftc *, union ccb *); 194d81ba9d5SMatt Jacob 195d81ba9d5SMatt Jacob static __inline int 196d81ba9d5SMatt Jacob is_lun_enabled(struct ispsoftc *isp, lun_id_t lun) 197d81ba9d5SMatt Jacob { 198d81ba9d5SMatt Jacob tstate_t *tptr; 199f6e75de2SMatt Jacob ISP_LOCK(isp); 200d81ba9d5SMatt Jacob if ((tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(lun)]) == NULL) { 201f6e75de2SMatt Jacob ISP_UNLOCK(isp); 202d81ba9d5SMatt Jacob return (0); 203d81ba9d5SMatt Jacob } 204d81ba9d5SMatt Jacob do { 205d81ba9d5SMatt Jacob if (tptr->lun == (lun_id_t) lun) { 206f6e75de2SMatt Jacob ISP_UNLOCK(isp); 207d81ba9d5SMatt Jacob return (1); 208d81ba9d5SMatt Jacob } 209d81ba9d5SMatt Jacob } while ((tptr = tptr->next) != NULL); 210f6e75de2SMatt Jacob ISP_UNLOCK(isp); 211d81ba9d5SMatt Jacob return (0); 212d81ba9d5SMatt Jacob } 213d81ba9d5SMatt Jacob 214d81ba9d5SMatt Jacob static __inline int 215d81ba9d5SMatt Jacob are_any_luns_enabled(struct ispsoftc *isp) 216d81ba9d5SMatt Jacob { 217d81ba9d5SMatt Jacob int i; 218d81ba9d5SMatt Jacob for (i = 0; i < LUN_HASH_SIZE; i++) { 219d81ba9d5SMatt Jacob if (isp->isp_osinfo.lun_hash[i]) { 220d81ba9d5SMatt Jacob return (1); 221d81ba9d5SMatt Jacob } 222d81ba9d5SMatt Jacob } 223d81ba9d5SMatt Jacob return (0); 224d81ba9d5SMatt Jacob } 225d81ba9d5SMatt Jacob 226d81ba9d5SMatt Jacob static __inline tstate_t * 227d81ba9d5SMatt Jacob get_lun_statep(struct ispsoftc *isp, lun_id_t lun) 228d81ba9d5SMatt Jacob { 229d81ba9d5SMatt Jacob tstate_t *tptr; 230d81ba9d5SMatt Jacob 231f6e75de2SMatt Jacob ISP_LOCK(isp); 232d81ba9d5SMatt Jacob if (lun == CAM_LUN_WILDCARD) { 233d81ba9d5SMatt Jacob tptr = &isp->isp_osinfo.tsdflt; 234d81ba9d5SMatt Jacob tptr->hold++; 235f6e75de2SMatt Jacob ISP_UNLOCK(isp); 236d81ba9d5SMatt Jacob return (tptr); 237d81ba9d5SMatt Jacob } else { 238d81ba9d5SMatt Jacob tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(lun)]; 239d81ba9d5SMatt Jacob } 240d81ba9d5SMatt Jacob if (tptr == NULL) { 241f6e75de2SMatt Jacob ISP_UNLOCK(isp); 242d81ba9d5SMatt Jacob return (NULL); 243d81ba9d5SMatt Jacob } 244d81ba9d5SMatt Jacob 245d81ba9d5SMatt Jacob do { 246d81ba9d5SMatt Jacob if (tptr->lun == lun) { 247d81ba9d5SMatt Jacob tptr->hold++; 248f6e75de2SMatt Jacob ISP_UNLOCK(isp); 249d81ba9d5SMatt Jacob return (tptr); 250d81ba9d5SMatt Jacob } 251d81ba9d5SMatt Jacob } while ((tptr = tptr->next) != NULL); 252f6e75de2SMatt Jacob ISP_UNLOCK(isp); 253d81ba9d5SMatt Jacob return (tptr); 254d81ba9d5SMatt Jacob } 255d81ba9d5SMatt Jacob 256d81ba9d5SMatt Jacob static __inline void 257d81ba9d5SMatt Jacob rls_lun_statep(struct ispsoftc *isp, tstate_t *tptr) 258d81ba9d5SMatt Jacob { 259d81ba9d5SMatt Jacob if (tptr->hold) 260d81ba9d5SMatt Jacob tptr->hold--; 261d81ba9d5SMatt Jacob } 262d81ba9d5SMatt Jacob 263d81ba9d5SMatt Jacob static __inline int 264d81ba9d5SMatt Jacob isp_psema_sig_rqe(struct ispsoftc *isp) 265d81ba9d5SMatt Jacob { 266f6e75de2SMatt Jacob ISP_LOCK(isp); 267d81ba9d5SMatt Jacob while (isp->isp_osinfo.tmflags & TM_BUSY) { 268d81ba9d5SMatt Jacob isp->isp_osinfo.tmflags |= TM_WANTED; 269d81ba9d5SMatt Jacob if (tsleep(&isp->isp_osinfo.tmflags, PRIBIO|PCATCH, "i0", 0)) { 270f6e75de2SMatt Jacob ISP_UNLOCK(isp); 271d81ba9d5SMatt Jacob return (-1); 272d81ba9d5SMatt Jacob } 273d81ba9d5SMatt Jacob isp->isp_osinfo.tmflags |= TM_BUSY; 274d81ba9d5SMatt Jacob } 275f6e75de2SMatt Jacob ISP_UNLOCK(isp); 276d81ba9d5SMatt Jacob return (0); 277d81ba9d5SMatt Jacob } 278d81ba9d5SMatt Jacob 279d81ba9d5SMatt Jacob static __inline int 280d81ba9d5SMatt Jacob isp_cv_wait_timed_rqe(struct ispsoftc *isp, int timo) 281d81ba9d5SMatt Jacob { 282f6e75de2SMatt Jacob ISP_LOCK(isp); 283d81ba9d5SMatt Jacob if (tsleep(&isp->isp_osinfo.rstatus, PRIBIO, "qt1", timo)) { 284f6e75de2SMatt Jacob ISP_UNLOCK(isp); 285d81ba9d5SMatt Jacob return (-1); 286d81ba9d5SMatt Jacob } 287f6e75de2SMatt Jacob ISP_UNLOCK(isp); 288d81ba9d5SMatt Jacob return (0); 289d81ba9d5SMatt Jacob } 290d81ba9d5SMatt Jacob 291d81ba9d5SMatt Jacob static __inline void 292d81ba9d5SMatt Jacob isp_cv_signal_rqe(struct ispsoftc *isp, int status) 293d81ba9d5SMatt Jacob { 294d81ba9d5SMatt Jacob isp->isp_osinfo.rstatus = status; 295d81ba9d5SMatt Jacob wakeup(&isp->isp_osinfo.rstatus); 296d81ba9d5SMatt Jacob } 297d81ba9d5SMatt Jacob 298d81ba9d5SMatt Jacob static __inline void 299d81ba9d5SMatt Jacob isp_vsema_rqe(struct ispsoftc *isp) 300d81ba9d5SMatt Jacob { 301f6e75de2SMatt Jacob ISP_LOCK(isp); 302d81ba9d5SMatt Jacob if (isp->isp_osinfo.tmflags & TM_WANTED) { 303d81ba9d5SMatt Jacob isp->isp_osinfo.tmflags &= ~TM_WANTED; 304d81ba9d5SMatt Jacob wakeup(&isp->isp_osinfo.tmflags); 305d81ba9d5SMatt Jacob } 306d81ba9d5SMatt Jacob isp->isp_osinfo.tmflags &= ~TM_BUSY; 307f6e75de2SMatt Jacob ISP_UNLOCK(isp); 308d81ba9d5SMatt Jacob } 309d81ba9d5SMatt Jacob 310d81ba9d5SMatt Jacob static cam_status 311d81ba9d5SMatt Jacob create_lun_state(struct ispsoftc *isp, struct cam_path *path, tstate_t **rslt) 312d81ba9d5SMatt Jacob { 313d81ba9d5SMatt Jacob cam_status status; 314d81ba9d5SMatt Jacob lun_id_t lun; 315d81ba9d5SMatt Jacob tstate_t *tptr, *new; 316d81ba9d5SMatt Jacob 317d81ba9d5SMatt Jacob lun = xpt_path_lun_id(path); 318d81ba9d5SMatt Jacob if (lun < 0) { 319d81ba9d5SMatt Jacob return (CAM_LUN_INVALID); 320d81ba9d5SMatt Jacob } 321d81ba9d5SMatt Jacob if (is_lun_enabled(isp, lun)) { 322d81ba9d5SMatt Jacob return (CAM_LUN_ALRDY_ENA); 323d81ba9d5SMatt Jacob } 324d81ba9d5SMatt Jacob new = (tstate_t *) malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT); 325d81ba9d5SMatt Jacob if (new == NULL) { 326d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 327d81ba9d5SMatt Jacob } 328d81ba9d5SMatt Jacob bzero(new, sizeof (tstate_t)); 329d81ba9d5SMatt Jacob 330d81ba9d5SMatt Jacob status = xpt_create_path(&new->owner, NULL, xpt_path_path_id(path), 331d81ba9d5SMatt Jacob xpt_path_target_id(path), xpt_path_lun_id(path)); 332d81ba9d5SMatt Jacob if (status != CAM_REQ_CMP) { 333d81ba9d5SMatt Jacob free(new, M_DEVBUF); 334d81ba9d5SMatt Jacob return (status); 335d81ba9d5SMatt Jacob } 336d81ba9d5SMatt Jacob new->lun = lun; 337d81ba9d5SMatt Jacob SLIST_INIT(&new->atios); 338d81ba9d5SMatt Jacob SLIST_INIT(&new->inots); 339d81ba9d5SMatt Jacob new->hold = 1; 340d81ba9d5SMatt Jacob 341f6e75de2SMatt Jacob ISP_LOCK(isp); 342d81ba9d5SMatt Jacob if ((tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(lun)]) == NULL) { 343d81ba9d5SMatt Jacob isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(lun)] = new; 344d81ba9d5SMatt Jacob } else { 345d81ba9d5SMatt Jacob while (tptr->next) 346d81ba9d5SMatt Jacob tptr = tptr->next; 347d81ba9d5SMatt Jacob tptr->next = new; 348d81ba9d5SMatt Jacob } 349f6e75de2SMatt Jacob ISP_UNLOCK(isp); 350d81ba9d5SMatt Jacob *rslt = new; 351d81ba9d5SMatt Jacob return (CAM_REQ_CMP); 352d81ba9d5SMatt Jacob } 353d81ba9d5SMatt Jacob 354d81ba9d5SMatt Jacob static __inline void 355d81ba9d5SMatt Jacob destroy_lun_state(struct ispsoftc *isp, tstate_t *tptr) 356d81ba9d5SMatt Jacob { 357d81ba9d5SMatt Jacob tstate_t *lw, *pw; 358d81ba9d5SMatt Jacob 359f6e75de2SMatt Jacob ISP_LOCK(isp); 360d81ba9d5SMatt Jacob if (tptr->hold) { 361f6e75de2SMatt Jacob ISP_UNLOCK(isp); 362d81ba9d5SMatt Jacob return; 363d81ba9d5SMatt Jacob } 364d81ba9d5SMatt Jacob pw = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(tptr->lun)]; 365d81ba9d5SMatt Jacob if (pw == NULL) { 366f6e75de2SMatt Jacob ISP_UNLOCK(isp); 367d81ba9d5SMatt Jacob return; 368d81ba9d5SMatt Jacob } else if (pw->lun == tptr->lun) { 369d81ba9d5SMatt Jacob isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(tptr->lun)] = pw->next; 370d81ba9d5SMatt Jacob } else { 371d81ba9d5SMatt Jacob lw = pw; 372d81ba9d5SMatt Jacob pw = lw->next; 373d81ba9d5SMatt Jacob while (pw) { 374d81ba9d5SMatt Jacob if (pw->lun == tptr->lun) { 375d81ba9d5SMatt Jacob lw->next = pw->next; 376d81ba9d5SMatt Jacob break; 377d81ba9d5SMatt Jacob } 378d81ba9d5SMatt Jacob lw = pw; 379d81ba9d5SMatt Jacob pw = pw->next; 380d81ba9d5SMatt Jacob } 381d81ba9d5SMatt Jacob if (pw == NULL) { 382f6e75de2SMatt Jacob ISP_UNLOCK(isp); 383d81ba9d5SMatt Jacob return; 384d81ba9d5SMatt Jacob } 385d81ba9d5SMatt Jacob } 386d81ba9d5SMatt Jacob free(tptr, M_DEVBUF); 387f6e75de2SMatt Jacob ISP_UNLOCK(isp); 388d81ba9d5SMatt Jacob } 389d81ba9d5SMatt Jacob 390d81ba9d5SMatt Jacob static void 391d81ba9d5SMatt Jacob isp_en_lun(struct ispsoftc *isp, union ccb *ccb) 392d81ba9d5SMatt Jacob { 393d81ba9d5SMatt Jacob const char *lfmt = "Lun now %sabled for target mode\n"; 394d81ba9d5SMatt Jacob struct ccb_en_lun *cel = &ccb->cel; 395d81ba9d5SMatt Jacob tstate_t *tptr; 396d81ba9d5SMatt Jacob u_int16_t rstat; 397b6b6ad2fSMatt Jacob int bus, frozen = 0; 398d81ba9d5SMatt Jacob lun_id_t lun; 399d81ba9d5SMatt Jacob target_id_t tgt; 400d81ba9d5SMatt Jacob 401d81ba9d5SMatt Jacob 402d81ba9d5SMatt Jacob bus = XS_CHANNEL(ccb); 403d81ba9d5SMatt Jacob tgt = ccb->ccb_h.target_id; 404d81ba9d5SMatt Jacob lun = ccb->ccb_h.target_lun; 405d81ba9d5SMatt Jacob 406d81ba9d5SMatt Jacob /* 407d81ba9d5SMatt Jacob * Do some sanity checking first. 408d81ba9d5SMatt Jacob */ 409d81ba9d5SMatt Jacob 4102ad50ca5SMatt Jacob if (lun < 0 || lun >= (lun_id_t) isp->isp_maxluns) { 411d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 412d81ba9d5SMatt Jacob return; 413d81ba9d5SMatt Jacob } 4142ad50ca5SMatt Jacob if (IS_SCSI(isp)) { 415d81ba9d5SMatt Jacob if (tgt != CAM_TARGET_WILDCARD && 416d81ba9d5SMatt Jacob tgt != ((sdparam *) isp->isp_param)->isp_initiator_id) { 417d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_TID_INVALID; 418d81ba9d5SMatt Jacob return; 419d81ba9d5SMatt Jacob } 420d81ba9d5SMatt Jacob } else { 421d81ba9d5SMatt Jacob if (tgt != CAM_TARGET_WILDCARD && 422d81ba9d5SMatt Jacob tgt != ((fcparam *) isp->isp_param)->isp_loopid) { 423d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_TID_INVALID; 424d81ba9d5SMatt Jacob return; 425d81ba9d5SMatt Jacob } 426d81ba9d5SMatt Jacob } 427d81ba9d5SMatt Jacob 428b6b6ad2fSMatt Jacob /* 429b6b6ad2fSMatt Jacob * If Fibre Channel, stop and drain all activity to this bus. 430b6b6ad2fSMatt Jacob */ 431b6b6ad2fSMatt Jacob if (IS_FC(isp)) { 432b6b6ad2fSMatt Jacob ISP_LOCK(isp); 433b6b6ad2fSMatt Jacob frozen = 1; 434b6b6ad2fSMatt Jacob xpt_freeze_simq(isp->isp_sim, 1); 435b6b6ad2fSMatt Jacob isp->isp_osinfo.drain = 1; 436b6b6ad2fSMatt Jacob /* ISP_UNLOCK(isp); XXX NEED CV_WAIT HERE XXX */ 437b6b6ad2fSMatt Jacob while (isp->isp_osinfo.drain) { 438b6b6ad2fSMatt Jacob tsleep(&isp->isp_osinfo.drain, PRIBIO, "ispdrain", 0); 439b6b6ad2fSMatt Jacob } 440b6b6ad2fSMatt Jacob ISP_UNLOCK(isp); 441b6b6ad2fSMatt Jacob } 442b6b6ad2fSMatt Jacob 443b6b6ad2fSMatt Jacob /* 444b6b6ad2fSMatt Jacob * Check to see if we're enabling on fibre channel and 445b6b6ad2fSMatt Jacob * don't yet have a notion of who the heck we are (no 446b6b6ad2fSMatt Jacob * loop yet). 447b6b6ad2fSMatt Jacob */ 448b6b6ad2fSMatt Jacob if (IS_FC(isp) && cel->enable && 449b6b6ad2fSMatt Jacob (isp->isp_osinfo.tmflags & TM_TMODE_ENABLED) == 0) { 450b6b6ad2fSMatt Jacob int rv= 2 * 1000000; 451b6b6ad2fSMatt Jacob fcparam *fcp = isp->isp_param; 452b6b6ad2fSMatt Jacob 453b6b6ad2fSMatt Jacob ISP_LOCK(isp); 454b6b6ad2fSMatt Jacob rv = isp_control(isp, ISPCTL_FCLINK_TEST, &rv); 455b6b6ad2fSMatt Jacob ISP_UNLOCK(isp); 456b6b6ad2fSMatt Jacob if (rv || fcp->isp_fwstate != FW_READY) { 457b6b6ad2fSMatt Jacob xpt_print_path(ccb->ccb_h.path); 458b6b6ad2fSMatt Jacob printf("link status not good yet\n"); 459b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 460b6b6ad2fSMatt Jacob if (frozen) 461b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 462b6b6ad2fSMatt Jacob return; 463b6b6ad2fSMatt Jacob } 464b6b6ad2fSMatt Jacob ISP_LOCK(isp); 465b6b6ad2fSMatt Jacob rv = isp_control(isp, ISPCTL_PDB_SYNC, NULL); 466b6b6ad2fSMatt Jacob ISP_UNLOCK(isp); 467b6b6ad2fSMatt Jacob if (rv || fcp->isp_fwstate != FW_READY) { 468b6b6ad2fSMatt Jacob xpt_print_path(ccb->ccb_h.path); 469b6b6ad2fSMatt Jacob printf("could not get a good port database read\n"); 470b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 471b6b6ad2fSMatt Jacob if (frozen) 472b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 473b6b6ad2fSMatt Jacob return; 474b6b6ad2fSMatt Jacob } 475b6b6ad2fSMatt Jacob } 476b6b6ad2fSMatt Jacob 477b6b6ad2fSMatt Jacob 478b6b6ad2fSMatt Jacob /* 479b6b6ad2fSMatt Jacob * Next check to see whether this is a target/lun wildcard action. 480b6b6ad2fSMatt Jacob * 481b6b6ad2fSMatt Jacob * If so, we enable/disable target mode but don't do any lun enabling. 482b6b6ad2fSMatt Jacob */ 483b6b6ad2fSMatt Jacob if (lun == CAM_LUN_WILDCARD && tgt == CAM_TARGET_WILDCARD) { 484b6b6ad2fSMatt Jacob int av; 485b6b6ad2fSMatt Jacob tptr = &isp->isp_osinfo.tsdflt; 486b6b6ad2fSMatt Jacob if (cel->enable) { 487b6b6ad2fSMatt Jacob if (isp->isp_osinfo.tmflags & TM_TMODE_ENABLED) { 488b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; 489b6b6ad2fSMatt Jacob if (frozen) 490b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 491b6b6ad2fSMatt Jacob return; 492b6b6ad2fSMatt Jacob } 493b6b6ad2fSMatt Jacob ccb->ccb_h.status = 494b6b6ad2fSMatt Jacob xpt_create_path(&tptr->owner, NULL, 495b6b6ad2fSMatt Jacob xpt_path_path_id(ccb->ccb_h.path), 496b6b6ad2fSMatt Jacob xpt_path_target_id(ccb->ccb_h.path), 497b6b6ad2fSMatt Jacob xpt_path_lun_id(ccb->ccb_h.path)); 498b6b6ad2fSMatt Jacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 499b6b6ad2fSMatt Jacob if (frozen) 500b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 501b6b6ad2fSMatt Jacob return; 502b6b6ad2fSMatt Jacob } 503b6b6ad2fSMatt Jacob SLIST_INIT(&tptr->atios); 504b6b6ad2fSMatt Jacob SLIST_INIT(&tptr->inots); 505b6b6ad2fSMatt Jacob av = 1; 506b6b6ad2fSMatt Jacob ISP_LOCK(isp); 507b6b6ad2fSMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 508b6b6ad2fSMatt Jacob if (av) { 509b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 510b6b6ad2fSMatt Jacob xpt_free_path(tptr->owner); 511b6b6ad2fSMatt Jacob ISP_UNLOCK(isp); 512b6b6ad2fSMatt Jacob if (frozen) 513b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 514b6b6ad2fSMatt Jacob return; 515b6b6ad2fSMatt Jacob } 516b6b6ad2fSMatt Jacob isp->isp_osinfo.tmflags |= TM_TMODE_ENABLED; 517b6b6ad2fSMatt Jacob ISP_UNLOCK(isp); 518b6b6ad2fSMatt Jacob } else { 519b6b6ad2fSMatt Jacob if ((isp->isp_osinfo.tmflags & TM_TMODE_ENABLED) == 0) { 520b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 521b6b6ad2fSMatt Jacob if (frozen) 522b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 523b6b6ad2fSMatt Jacob return; 524b6b6ad2fSMatt Jacob } 525b6b6ad2fSMatt Jacob if (are_any_luns_enabled(isp)) { 526b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_SCSI_BUSY; 527b6b6ad2fSMatt Jacob if (frozen) 528b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 529b6b6ad2fSMatt Jacob return; 530b6b6ad2fSMatt Jacob } 531b6b6ad2fSMatt Jacob av = 0; 532b6b6ad2fSMatt Jacob ISP_LOCK(isp); 533b6b6ad2fSMatt Jacob av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); 534b6b6ad2fSMatt Jacob if (av) { 535b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 536b6b6ad2fSMatt Jacob ISP_UNLOCK(isp); 537b6b6ad2fSMatt Jacob if (frozen) 538b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 539b6b6ad2fSMatt Jacob return; 540b6b6ad2fSMatt Jacob } 541b6b6ad2fSMatt Jacob isp->isp_osinfo.tmflags &= ~TM_TMODE_ENABLED; 542b6b6ad2fSMatt Jacob ISP_UNLOCK(isp); 543b6b6ad2fSMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 544b6b6ad2fSMatt Jacob } 545b6b6ad2fSMatt Jacob xpt_print_path(ccb->ccb_h.path); 546b6b6ad2fSMatt Jacob printf(lfmt, (cel->enable) ? "en" : "dis"); 547b6b6ad2fSMatt Jacob if (frozen) 548b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 549b6b6ad2fSMatt Jacob return; 550b6b6ad2fSMatt Jacob } 551b6b6ad2fSMatt Jacob 552b6b6ad2fSMatt Jacob /* 553b6b6ad2fSMatt Jacob * We can move along now... 554b6b6ad2fSMatt Jacob */ 555b6b6ad2fSMatt Jacob 556b6b6ad2fSMatt Jacob if (frozen) 557b6b6ad2fSMatt Jacob xpt_release_simq(isp->isp_sim, 1); 558b6b6ad2fSMatt Jacob 559d81ba9d5SMatt Jacob 560d81ba9d5SMatt Jacob if (cel->enable) { 561d81ba9d5SMatt Jacob ccb->ccb_h.status = 562d81ba9d5SMatt Jacob create_lun_state(isp, ccb->ccb_h.path, &tptr); 563d81ba9d5SMatt Jacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 564d81ba9d5SMatt Jacob return; 565d81ba9d5SMatt Jacob } 566d81ba9d5SMatt Jacob } else { 567d81ba9d5SMatt Jacob tptr = get_lun_statep(isp, lun); 568d81ba9d5SMatt Jacob if (tptr == NULL) { 569d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 570d81ba9d5SMatt Jacob return; 571d81ba9d5SMatt Jacob } 572d81ba9d5SMatt Jacob } 573d81ba9d5SMatt Jacob 574d81ba9d5SMatt Jacob if (isp_psema_sig_rqe(isp)) { 575d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 576d81ba9d5SMatt Jacob if (cel->enable) 577d81ba9d5SMatt Jacob destroy_lun_state(isp, tptr); 578d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 579d81ba9d5SMatt Jacob return; 580d81ba9d5SMatt Jacob } 581d81ba9d5SMatt Jacob 582f6e75de2SMatt Jacob ISP_LOCK(isp); 583d81ba9d5SMatt Jacob if (cel->enable) { 584d81ba9d5SMatt Jacob u_int32_t seq = isp->isp_osinfo.rollinfo++; 585d81ba9d5SMatt Jacob rstat = LUN_ERR; 586d81ba9d5SMatt Jacob if (isp_lun_cmd(isp, RQSTYPE_ENABLE_LUN, bus, tgt, lun, seq)) { 587d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 588d81ba9d5SMatt Jacob printf("isp_lun_cmd failed\n"); 589d81ba9d5SMatt Jacob goto out; 590d81ba9d5SMatt Jacob } 591d81ba9d5SMatt Jacob if (isp_cv_wait_timed_rqe(isp, 30 * hz)) { 592d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 593d81ba9d5SMatt Jacob printf("wait for ENABLE LUN timed out\n"); 594d81ba9d5SMatt Jacob goto out; 595d81ba9d5SMatt Jacob } 596d81ba9d5SMatt Jacob rstat = isp->isp_osinfo.rstatus; 597d81ba9d5SMatt Jacob if (rstat != LUN_OK) { 598d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 599d81ba9d5SMatt Jacob printf("ENABLE LUN returned 0x%x\n", rstat); 600d81ba9d5SMatt Jacob goto out; 601d81ba9d5SMatt Jacob } 602d81ba9d5SMatt Jacob } else { 603d81ba9d5SMatt Jacob u_int32_t seq; 604d81ba9d5SMatt Jacob 605d81ba9d5SMatt Jacob seq = isp->isp_osinfo.rollinfo++; 606d81ba9d5SMatt Jacob rstat = LUN_ERR; 607d81ba9d5SMatt Jacob 608d81ba9d5SMatt Jacob if (isp_lun_cmd(isp, -RQSTYPE_MODIFY_LUN, bus, tgt, lun, seq)) { 609d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 610d81ba9d5SMatt Jacob printf("isp_lun_cmd failed\n"); 611d81ba9d5SMatt Jacob goto out; 612d81ba9d5SMatt Jacob } 613d81ba9d5SMatt Jacob if (isp_cv_wait_timed_rqe(isp, 30 * hz)) { 614d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 615d81ba9d5SMatt Jacob printf("wait for MODIFY LUN timed out\n"); 616d81ba9d5SMatt Jacob goto out; 617d81ba9d5SMatt Jacob } 618d81ba9d5SMatt Jacob rstat = isp->isp_osinfo.rstatus; 619d81ba9d5SMatt Jacob if (rstat != LUN_OK) { 620d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 621d81ba9d5SMatt Jacob printf("MODIFY LUN returned 0x%x\n", rstat); 622d81ba9d5SMatt Jacob goto out; 623d81ba9d5SMatt Jacob } 624d81ba9d5SMatt Jacob rstat = LUN_ERR; 625d81ba9d5SMatt Jacob seq = isp->isp_osinfo.rollinfo++; 626d81ba9d5SMatt Jacob 627d81ba9d5SMatt Jacob if (isp_lun_cmd(isp, -RQSTYPE_ENABLE_LUN, bus, tgt, lun, seq)) { 628d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 629d81ba9d5SMatt Jacob printf("isp_lun_cmd failed\n"); 630d81ba9d5SMatt Jacob goto out; 631d81ba9d5SMatt Jacob } 632d81ba9d5SMatt Jacob if (isp_cv_wait_timed_rqe(isp, 30 * hz)) { 633d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 634d81ba9d5SMatt Jacob printf("wait for ENABLE LUN timed out\n"); 635d81ba9d5SMatt Jacob goto out; 636d81ba9d5SMatt Jacob } 637d81ba9d5SMatt Jacob rstat = isp->isp_osinfo.rstatus; 638d81ba9d5SMatt Jacob if (rstat != LUN_OK) { 639d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 640d81ba9d5SMatt Jacob printf("ENABLE LUN returned 0x%x\n", rstat); 641d81ba9d5SMatt Jacob goto out; 642d81ba9d5SMatt Jacob } 643d81ba9d5SMatt Jacob } 644d81ba9d5SMatt Jacob out: 645d81ba9d5SMatt Jacob isp_vsema_rqe(isp); 646f6e75de2SMatt Jacob ISP_UNLOCK(isp); 647d81ba9d5SMatt Jacob 648d81ba9d5SMatt Jacob if (rstat != LUN_OK) { 649d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 650d81ba9d5SMatt Jacob printf("lun %sable failed\n", (cel->enable) ? "en" : "dis"); 651d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 652d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 653d81ba9d5SMatt Jacob if (cel->enable) 654d81ba9d5SMatt Jacob destroy_lun_state(isp, tptr); 655d81ba9d5SMatt Jacob } else { 656d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 657d81ba9d5SMatt Jacob printf(lfmt, (cel->enable) ? "en" : "dis"); 658d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 659d81ba9d5SMatt Jacob if (cel->enable == 0) { 660d81ba9d5SMatt Jacob destroy_lun_state(isp, tptr); 661d81ba9d5SMatt Jacob } 662d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_CMP; 663d81ba9d5SMatt Jacob } 664d81ba9d5SMatt Jacob } 665d81ba9d5SMatt Jacob 666d81ba9d5SMatt Jacob static cam_status 667d81ba9d5SMatt Jacob isp_abort_tgt_ccb(struct ispsoftc *isp, union ccb *ccb) 668d81ba9d5SMatt Jacob { 669d81ba9d5SMatt Jacob tstate_t *tptr; 670d81ba9d5SMatt Jacob struct ccb_hdr_slist *lp; 671d81ba9d5SMatt Jacob struct ccb_hdr *curelm; 672d81ba9d5SMatt Jacob int found; 673d81ba9d5SMatt Jacob union ccb *accb = ccb->cab.abort_ccb; 674d81ba9d5SMatt Jacob 675d81ba9d5SMatt Jacob if (accb->ccb_h.target_id != CAM_TARGET_WILDCARD) { 676d81ba9d5SMatt Jacob if (IS_FC(isp) && (accb->ccb_h.target_id != 677d81ba9d5SMatt Jacob ((fcparam *) isp->isp_param)->isp_loopid)) { 678d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 679d81ba9d5SMatt Jacob } else if (IS_SCSI(isp) && (accb->ccb_h.target_id != 680d81ba9d5SMatt Jacob ((sdparam *) isp->isp_param)->isp_initiator_id)) { 681d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 682d81ba9d5SMatt Jacob } 683d81ba9d5SMatt Jacob } 684d81ba9d5SMatt Jacob tptr = get_lun_statep(isp, accb->ccb_h.target_lun); 685d81ba9d5SMatt Jacob if (tptr == NULL) { 686d81ba9d5SMatt Jacob return (CAM_PATH_INVALID); 687d81ba9d5SMatt Jacob } 688d81ba9d5SMatt Jacob if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 689d81ba9d5SMatt Jacob lp = &tptr->atios; 690d81ba9d5SMatt Jacob } else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY) { 691d81ba9d5SMatt Jacob lp = &tptr->inots; 692d81ba9d5SMatt Jacob } else { 693d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 694d81ba9d5SMatt Jacob return (CAM_UA_ABORT); 695d81ba9d5SMatt Jacob } 696d81ba9d5SMatt Jacob curelm = SLIST_FIRST(lp); 697d81ba9d5SMatt Jacob found = 0; 698d81ba9d5SMatt Jacob if (curelm == &accb->ccb_h) { 699d81ba9d5SMatt Jacob found = 1; 700d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(lp, sim_links.sle); 701d81ba9d5SMatt Jacob } else { 702d81ba9d5SMatt Jacob while(curelm != NULL) { 703d81ba9d5SMatt Jacob struct ccb_hdr *nextelm; 704d81ba9d5SMatt Jacob 705d81ba9d5SMatt Jacob nextelm = SLIST_NEXT(curelm, sim_links.sle); 706d81ba9d5SMatt Jacob if (nextelm == &accb->ccb_h) { 707d81ba9d5SMatt Jacob found = 1; 708d81ba9d5SMatt Jacob SLIST_NEXT(curelm, sim_links.sle) = 709d81ba9d5SMatt Jacob SLIST_NEXT(nextelm, sim_links.sle); 710d81ba9d5SMatt Jacob break; 711d81ba9d5SMatt Jacob } 712d81ba9d5SMatt Jacob curelm = nextelm; 713d81ba9d5SMatt Jacob } 714d81ba9d5SMatt Jacob } 715d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 716d81ba9d5SMatt Jacob if (found) { 717d81ba9d5SMatt Jacob accb->ccb_h.status = CAM_REQ_ABORTED; 718d81ba9d5SMatt Jacob return (CAM_REQ_CMP); 719d81ba9d5SMatt Jacob } 720d81ba9d5SMatt Jacob return(CAM_PATH_INVALID); 721d81ba9d5SMatt Jacob } 722d81ba9d5SMatt Jacob 723d81ba9d5SMatt Jacob static cam_status 724d81ba9d5SMatt Jacob isp_target_start_ctio(struct ispsoftc *isp, union ccb *ccb) 725d81ba9d5SMatt Jacob { 726d81ba9d5SMatt Jacob void *qe; 72700a8e174SMatt Jacob struct ccb_scsiio *cso = &ccb->csio; 728d81ba9d5SMatt Jacob u_int32_t *hp, save_handle; 729d81ba9d5SMatt Jacob u_int16_t iptr, optr; 730d81ba9d5SMatt Jacob 731f48ce188SMatt Jacob 732d81ba9d5SMatt Jacob if (isp_getrqentry(isp, &iptr, &optr, &qe)) { 73392a1e549SMatt Jacob xpt_print_path(ccb->ccb_h.path); 73492a1e549SMatt Jacob printf("Request Queue Overflow in isp_target_start_ctio\n"); 735d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 736d81ba9d5SMatt Jacob } 73792a1e549SMatt Jacob bzero(qe, QENTRY_LEN); 738d81ba9d5SMatt Jacob 739d81ba9d5SMatt Jacob /* 740d81ba9d5SMatt Jacob * We're either moving data or completing a command here. 741d81ba9d5SMatt Jacob */ 742d81ba9d5SMatt Jacob 743d81ba9d5SMatt Jacob if (IS_FC(isp)) { 744f48ce188SMatt Jacob struct ccb_accept_tio *atiop; 745d81ba9d5SMatt Jacob ct2_entry_t *cto = qe; 74600a8e174SMatt Jacob 747d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; 748d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_count = 1; 74900a8e174SMatt Jacob cto->ct_iid = cso->init_id; 7502ad50ca5SMatt Jacob if (isp->isp_maxluns <= 16) { 751d81ba9d5SMatt Jacob cto->ct_lun = ccb->ccb_h.target_lun; 7522ad50ca5SMatt Jacob } 753f48ce188SMatt Jacob /* 754f48ce188SMatt Jacob * Start with a residual based on what the original datalength 755f48ce188SMatt Jacob * was supposed to be. Basically, we ignore what CAM has set 756f48ce188SMatt Jacob * for residuals. The data transfer routines will knock off 757f48ce188SMatt Jacob * the residual for each byte actually moved- and also will 758f48ce188SMatt Jacob * be responsible for setting the underrun flag. 759f48ce188SMatt Jacob */ 760f48ce188SMatt Jacob /* HACK! HACK! */ 761f48ce188SMatt Jacob if ((atiop = ccb->ccb_h.periph_priv.entries[1].ptr) != NULL) { 762f48ce188SMatt Jacob cto->ct_resid = atiop->ccb_h.spriv_field0; 763f48ce188SMatt Jacob } 764f48ce188SMatt Jacob 765f48ce188SMatt Jacob /* 766f48ce188SMatt Jacob * We always have to use the tag_id- it has the RX_ID 767f48ce188SMatt Jacob * for this exchage. 768f48ce188SMatt Jacob */ 76900a8e174SMatt Jacob cto->ct_rxid = cso->tag_id; 77000a8e174SMatt Jacob if (cso->dxfer_len == 0) { 77100a8e174SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA; 772f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 77300a8e174SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 774f48ce188SMatt Jacob cto->rsp.m1.ct_scsi_status = cso->scsi_status; 775f48ce188SMatt Jacob } 77600a8e174SMatt Jacob if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) { 77700a8e174SMatt Jacob int m = min(cso->sense_len, MAXRESPLEN); 77800a8e174SMatt Jacob bcopy(&cso->sense_data, cto->rsp.m1.ct_resp, m); 77900a8e174SMatt Jacob cto->rsp.m1.ct_senselen = m; 78000a8e174SMatt Jacob cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID; 78100a8e174SMatt Jacob } 78200a8e174SMatt Jacob } else { 78300a8e174SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE0; 78400a8e174SMatt Jacob if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 78500a8e174SMatt Jacob cto->ct_flags |= CT2_DATA_IN; 78600a8e174SMatt Jacob } else { 78700a8e174SMatt Jacob cto->ct_flags |= CT2_DATA_OUT; 788d81ba9d5SMatt Jacob } 789d81ba9d5SMatt Jacob if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 790d81ba9d5SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 79100a8e174SMatt Jacob cto->rsp.m0.ct_scsi_status = cso->scsi_status; 792d81ba9d5SMatt Jacob } 793f48ce188SMatt Jacob /* 794f48ce188SMatt Jacob * If we're sending data and status back together, 795f48ce188SMatt Jacob * we can't also send back sense data as well. 796f48ce188SMatt Jacob */ 79700a8e174SMatt Jacob ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 79800a8e174SMatt Jacob } 799b09b0095SMatt Jacob if (cto->ct_flags & CAM_SEND_STATUS) { 800b09b0095SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG2, 801b09b0095SMatt Jacob "CTIO2 RX_ID 0x%x SCSI STATUS 0x%x datalength %u", 802b09b0095SMatt Jacob cto->ct_rxid, cso->scsi_status, cto->ct_resid); 803d81ba9d5SMatt Jacob } 804d81ba9d5SMatt Jacob hp = &cto->ct_reserved; 805d81ba9d5SMatt Jacob } else { 806d81ba9d5SMatt Jacob ct_entry_t *cto = qe; 80700a8e174SMatt Jacob 808d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 809d81ba9d5SMatt Jacob cto->ct_header.rqs_entry_count = 1; 81000a8e174SMatt Jacob cto->ct_iid = cso->init_id; 811d81ba9d5SMatt Jacob cto->ct_tgt = ccb->ccb_h.target_id; 812d81ba9d5SMatt Jacob cto->ct_lun = ccb->ccb_h.target_lun; 813f48ce188SMatt Jacob if (cso->tag_id && cso->tag_action) { 814f48ce188SMatt Jacob /* 815f48ce188SMatt Jacob * We don't specify a tag type for regular SCSI. 816f48ce188SMatt Jacob * Just the tag value and set the flag. 817f48ce188SMatt Jacob */ 81800a8e174SMatt Jacob cto->ct_tag_val = cso->tag_id; 819f48ce188SMatt Jacob cto->ct_flags |= CT_TQAE; 820f48ce188SMatt Jacob } 821f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) { 822f48ce188SMatt Jacob cto->ct_flags |= CT_NODISC; 823f48ce188SMatt Jacob } 824f48ce188SMatt Jacob if (cso->dxfer_len == 0) { 825d81ba9d5SMatt Jacob cto->ct_flags |= CT_NO_DATA; 82600a8e174SMatt Jacob } else if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 82700a8e174SMatt Jacob cto->ct_flags |= CT_DATA_IN; 82800a8e174SMatt Jacob } else { 82900a8e174SMatt Jacob cto->ct_flags |= CT_DATA_OUT; 830d81ba9d5SMatt Jacob } 831f48ce188SMatt Jacob if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 832d81ba9d5SMatt Jacob cto->ct_flags |= CT_SENDSTATUS; 83300a8e174SMatt Jacob cto->ct_scsi_status = cso->scsi_status; 83400a8e174SMatt Jacob cto->ct_resid = cso->resid; 835d81ba9d5SMatt Jacob } 836b09b0095SMatt Jacob if (cto->ct_flags & CAM_SEND_STATUS) { 837b09b0095SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG2, 838b09b0095SMatt Jacob "CTIO SCSI STATUS 0x%x resid %d", 839b09b0095SMatt Jacob cso->scsi_status, cso->resid); 84092a1e549SMatt Jacob } 841d81ba9d5SMatt Jacob hp = &cto->ct_reserved; 84200a8e174SMatt Jacob ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 843d81ba9d5SMatt Jacob } 844d81ba9d5SMatt Jacob 845b09b0095SMatt Jacob if (isp_save_xs(isp, (XS_T *)ccb, hp)) { 84692a1e549SMatt Jacob xpt_print_path(ccb->ccb_h.path); 84792a1e549SMatt Jacob printf("No XFLIST pointers for isp_target_start_ctio\n"); 848d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 849d81ba9d5SMatt Jacob } 850d81ba9d5SMatt Jacob 851d81ba9d5SMatt Jacob 852d81ba9d5SMatt Jacob /* 853d81ba9d5SMatt Jacob * Call the dma setup routines for this entry (and any subsequent 854d81ba9d5SMatt Jacob * CTIOs) if there's data to move, and then tell the f/w it's got 855b09b0095SMatt Jacob * new things to play with. As with isp_start's usage of DMA setup, 856d81ba9d5SMatt Jacob * any swizzling is done in the machine dependent layer. Because 857d81ba9d5SMatt Jacob * of this, we put the request onto the queue area first in native 858d81ba9d5SMatt Jacob * format. 859d81ba9d5SMatt Jacob */ 860d81ba9d5SMatt Jacob 861d81ba9d5SMatt Jacob save_handle = *hp; 86200a8e174SMatt Jacob switch (ISP_DMASETUP(isp, cso, qe, &iptr, optr)) { 863d81ba9d5SMatt Jacob case CMD_QUEUED: 864d81ba9d5SMatt Jacob ISP_ADD_REQUEST(isp, iptr); 865d81ba9d5SMatt Jacob return (CAM_REQ_INPROG); 866d81ba9d5SMatt Jacob 867d81ba9d5SMatt Jacob case CMD_EAGAIN: 868d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 869d81ba9d5SMatt Jacob isp_destroy_handle(isp, save_handle); 870d81ba9d5SMatt Jacob return (CAM_RESRC_UNAVAIL); 871d81ba9d5SMatt Jacob 872d81ba9d5SMatt Jacob default: 873d81ba9d5SMatt Jacob isp_destroy_handle(isp, save_handle); 874b85389e1SMatt Jacob return (XS_ERR(ccb)); 875d81ba9d5SMatt Jacob } 876d81ba9d5SMatt Jacob } 877d81ba9d5SMatt Jacob 878f48ce188SMatt Jacob static cam_status 879f48ce188SMatt Jacob isp_target_putback_atio(struct ispsoftc *isp, union ccb *ccb) 880f48ce188SMatt Jacob { 881f48ce188SMatt Jacob void *qe; 882f48ce188SMatt Jacob struct ccb_accept_tio *atiop; 883f48ce188SMatt Jacob u_int16_t iptr, optr; 884f48ce188SMatt Jacob 885f48ce188SMatt Jacob if (isp_getrqentry(isp, &iptr, &optr, &qe)) { 886f48ce188SMatt Jacob xpt_print_path(ccb->ccb_h.path); 887f48ce188SMatt Jacob printf("Request Queue Overflow in isp_target_putback_atio\n"); 888f48ce188SMatt Jacob return (CAM_RESRC_UNAVAIL); 889f48ce188SMatt Jacob } 890f48ce188SMatt Jacob bzero(qe, QENTRY_LEN); 891f48ce188SMatt Jacob atiop = (struct ccb_accept_tio *) ccb; 892f48ce188SMatt Jacob if (IS_FC(isp)) { 893f48ce188SMatt Jacob at2_entry_t *at = qe; 894f48ce188SMatt Jacob at->at_header.rqs_entry_type = RQSTYPE_ATIO2; 895f48ce188SMatt Jacob at->at_header.rqs_entry_count = 1; 896f48ce188SMatt Jacob if (isp->isp_maxluns > 16) { 897f48ce188SMatt Jacob at->at_scclun = (uint16_t) atiop->ccb_h.target_lun; 898f48ce188SMatt Jacob } else { 899f48ce188SMatt Jacob at->at_lun = (uint8_t) atiop->ccb_h.target_lun; 900f48ce188SMatt Jacob } 901f48ce188SMatt Jacob at->at_status = CT_OK; 902f48ce188SMatt Jacob at->at_rxid = atiop->tag_id; 903f48ce188SMatt Jacob ISP_SWIZ_ATIO2(isp, qe, qe); 904f48ce188SMatt Jacob } else { 905f48ce188SMatt Jacob at_entry_t *at = qe; 906f48ce188SMatt Jacob at->at_header.rqs_entry_type = RQSTYPE_ATIO; 907f48ce188SMatt Jacob at->at_header.rqs_entry_count = 1; 908f48ce188SMatt Jacob at->at_iid = atiop->init_id; 909f48ce188SMatt Jacob at->at_tgt = atiop->ccb_h.target_id; 910f48ce188SMatt Jacob at->at_lun = atiop->ccb_h.target_lun; 911f48ce188SMatt Jacob at->at_status = CT_OK; 912f48ce188SMatt Jacob if (atiop->ccb_h.status & CAM_TAG_ACTION_VALID) { 913f48ce188SMatt Jacob at->at_tag_type = atiop->tag_action; 914f48ce188SMatt Jacob } 915f48ce188SMatt Jacob at->at_tag_val = atiop->tag_id; 916f48ce188SMatt Jacob ISP_SWIZ_ATIO(isp, qe, qe); 917f48ce188SMatt Jacob } 918f48ce188SMatt Jacob ISP_TDQE(isp, "isp_target_putback_atio", (int) optr, qe); 919f48ce188SMatt Jacob ISP_ADD_REQUEST(isp, iptr); 920f48ce188SMatt Jacob return (CAM_REQ_CMP); 921f48ce188SMatt Jacob } 922f48ce188SMatt Jacob 923f48ce188SMatt Jacob static void 924f48ce188SMatt Jacob isp_refire_putback_atio(void *arg) 925f48ce188SMatt Jacob { 926f48ce188SMatt Jacob union ccb *ccb = arg; 927f48ce188SMatt Jacob int s = splcam(); 928f48ce188SMatt Jacob if (isp_target_putback_atio(XS_ISP(ccb), ccb) != CAM_REQ_CMP) { 929f48ce188SMatt Jacob (void) timeout(isp_refire_putback_atio, ccb, 10); 930f48ce188SMatt Jacob } else { 931f48ce188SMatt Jacob isp_handle_platform_ctio_part2(XS_ISP(ccb), ccb); 932f48ce188SMatt Jacob } 933f48ce188SMatt Jacob splx(s); 934f48ce188SMatt Jacob } 935f48ce188SMatt Jacob 936d81ba9d5SMatt Jacob /* 937d81ba9d5SMatt Jacob * Handle ATIO stuff that the generic code can't. 938d81ba9d5SMatt Jacob * This means handling CDBs. 939d81ba9d5SMatt Jacob */ 940d81ba9d5SMatt Jacob 941d81ba9d5SMatt Jacob static int 942d81ba9d5SMatt Jacob isp_handle_platform_atio(struct ispsoftc *isp, at_entry_t *aep) 943d81ba9d5SMatt Jacob { 944d81ba9d5SMatt Jacob tstate_t *tptr; 945d81ba9d5SMatt Jacob int status; 946d81ba9d5SMatt Jacob struct ccb_accept_tio *atiop; 947d81ba9d5SMatt Jacob 948d81ba9d5SMatt Jacob /* 949d81ba9d5SMatt Jacob * The firmware status (except for the QLTM_SVALID bit) 950d81ba9d5SMatt Jacob * indicates why this ATIO was sent to us. 951d81ba9d5SMatt Jacob * 952d81ba9d5SMatt Jacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 953d81ba9d5SMatt Jacob * 954d81ba9d5SMatt Jacob * If the DISCONNECTS DISABLED bit is set in the flags field, 955d81ba9d5SMatt Jacob * we're still connected on the SCSI bus - i.e. the initiator 956d81ba9d5SMatt Jacob * did not set DiscPriv in the identify message. We don't care 957d81ba9d5SMatt Jacob * about this so it's ignored. 958d81ba9d5SMatt Jacob */ 959d81ba9d5SMatt Jacob status = aep->at_status; 960d81ba9d5SMatt Jacob if ((status & ~QLTM_SVALID) == AT_PHASE_ERROR) { 961d81ba9d5SMatt Jacob /* 962d81ba9d5SMatt Jacob * Bus Phase Sequence error. We should have sense data 963d81ba9d5SMatt Jacob * suggested by the f/w. I'm not sure quite yet what 964d81ba9d5SMatt Jacob * to do about this for CAM. 965d81ba9d5SMatt Jacob */ 966d81ba9d5SMatt Jacob printf("%s: PHASE ERROR\n", isp->isp_name); 967d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 968d81ba9d5SMatt Jacob return (0); 969d81ba9d5SMatt Jacob } 970d81ba9d5SMatt Jacob if ((status & ~QLTM_SVALID) != AT_CDB) { 971d81ba9d5SMatt Jacob printf("%s: bogus atio (0x%x) leaked to platform\n", 972d81ba9d5SMatt Jacob isp->isp_name, status); 973d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 974d81ba9d5SMatt Jacob return (0); 975d81ba9d5SMatt Jacob } 976d81ba9d5SMatt Jacob 977d81ba9d5SMatt Jacob tptr = get_lun_statep(isp, aep->at_lun); 978d81ba9d5SMatt Jacob if (tptr == NULL) { 979d81ba9d5SMatt Jacob tptr = get_lun_statep(isp, CAM_LUN_WILDCARD); 980d81ba9d5SMatt Jacob } 981d81ba9d5SMatt Jacob 982d81ba9d5SMatt Jacob if (tptr == NULL) { 983d81ba9d5SMatt Jacob /* 984d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 985d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 986d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a BUSY status 987d81ba9d5SMatt Jacob * instead. This works out okay because the only 988d81ba9d5SMatt Jacob * time we should, in fact, get this, is in the 989d81ba9d5SMatt Jacob * case that somebody configured us without the 990d81ba9d5SMatt Jacob * blackhole driver, so they get what they deserve. 991d81ba9d5SMatt Jacob */ 992d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 993d81ba9d5SMatt Jacob return (0); 994d81ba9d5SMatt Jacob } 995d81ba9d5SMatt Jacob 996d81ba9d5SMatt Jacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 997d81ba9d5SMatt Jacob if (atiop == NULL) { 998d81ba9d5SMatt Jacob /* 999d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1000d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1001d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a QUEUE FULL status 1002d81ba9d5SMatt Jacob * instead. This works out okay because the only time we 1003d81ba9d5SMatt Jacob * should, in fact, get this, is in the case that we've 1004d81ba9d5SMatt Jacob * run out of ATIOS. 1005d81ba9d5SMatt Jacob */ 1006d81ba9d5SMatt Jacob xpt_print_path(tptr->owner); 1007d81ba9d5SMatt Jacob printf("no ATIOS for lun %d from initiator %d\n", 1008d81ba9d5SMatt Jacob aep->at_lun, aep->at_iid); 1009d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1010d81ba9d5SMatt Jacob if (aep->at_flags & AT_TQAE) 1011d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); 1012d81ba9d5SMatt Jacob else 1013d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1014d81ba9d5SMatt Jacob return (0); 1015d81ba9d5SMatt Jacob } 1016d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 1017d81ba9d5SMatt Jacob if (tptr == &isp->isp_osinfo.tsdflt) { 1018d81ba9d5SMatt Jacob atiop->ccb_h.target_id = aep->at_tgt; 1019d81ba9d5SMatt Jacob atiop->ccb_h.target_lun = aep->at_lun; 1020d81ba9d5SMatt Jacob } 1021d81ba9d5SMatt Jacob if (aep->at_flags & AT_NODISC) { 1022f48ce188SMatt Jacob atiop->ccb_h.flags = CAM_DIS_DISCONNECT; 1023f48ce188SMatt Jacob } else { 1024f48ce188SMatt Jacob atiop->ccb_h.flags = 0; 1025d81ba9d5SMatt Jacob } 1026d81ba9d5SMatt Jacob 1027f48ce188SMatt Jacob if (status & QLTM_SVALID) { 1028f48ce188SMatt Jacob size_t amt = imin(QLTM_SENSELEN, sizeof (atiop->sense_data)); 1029f48ce188SMatt Jacob atiop->sense_len = amt; 1030f48ce188SMatt Jacob MEMCPY(&atiop->sense_data, aep->at_sense, amt); 1031f48ce188SMatt Jacob } else { 1032f48ce188SMatt Jacob atiop->sense_len = 0; 1033f48ce188SMatt Jacob } 1034d81ba9d5SMatt Jacob 1035d81ba9d5SMatt Jacob atiop->init_id = aep->at_iid; 1036d81ba9d5SMatt Jacob atiop->cdb_len = aep->at_cdblen; 1037d81ba9d5SMatt Jacob MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen); 1038d81ba9d5SMatt Jacob atiop->ccb_h.status = CAM_CDB_RECVD; 1039d81ba9d5SMatt Jacob atiop->tag_id = aep->at_tag_val; 1040f48ce188SMatt Jacob if ((atiop->tag_action = aep->at_tag_type) != 0) { 1041d81ba9d5SMatt Jacob atiop->ccb_h.status |= CAM_TAG_ACTION_VALID; 1042d81ba9d5SMatt Jacob } 1043d81ba9d5SMatt Jacob xpt_done((union ccb*)atiop); 1044b09b0095SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG2, 1045b09b0095SMatt Jacob "ATIO CDB=0x%x iid%d->lun%d tag 0x%x ttype 0x%x %s", 1046b09b0095SMatt Jacob aep->at_cdb[0] & 0xff, aep->at_iid, aep->at_lun, 1047b09b0095SMatt Jacob aep->at_tag_val & 0xff, aep->at_tag_type, 1048b09b0095SMatt Jacob (aep->at_flags & AT_NODISC)? "nondisc" : "disconnecting"); 1049d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1050d81ba9d5SMatt Jacob return (0); 1051d81ba9d5SMatt Jacob } 1052d81ba9d5SMatt Jacob 1053d81ba9d5SMatt Jacob static int 1054d81ba9d5SMatt Jacob isp_handle_platform_atio2(struct ispsoftc *isp, at2_entry_t *aep) 1055d81ba9d5SMatt Jacob { 105692a1e549SMatt Jacob lun_id_t lun; 1057d81ba9d5SMatt Jacob tstate_t *tptr; 1058d81ba9d5SMatt Jacob struct ccb_accept_tio *atiop; 1059d81ba9d5SMatt Jacob 1060d81ba9d5SMatt Jacob /* 1061d81ba9d5SMatt Jacob * The firmware status (except for the QLTM_SVALID bit) 1062d81ba9d5SMatt Jacob * indicates why this ATIO was sent to us. 1063d81ba9d5SMatt Jacob * 1064d81ba9d5SMatt Jacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 1065d81ba9d5SMatt Jacob */ 1066d81ba9d5SMatt Jacob if ((aep->at_status & ~QLTM_SVALID) != AT_CDB) { 1067d81ba9d5SMatt Jacob printf("%s: bogus atio (0x%x) leaked to platform\n", 1068d81ba9d5SMatt Jacob isp->isp_name, aep->at_status); 1069d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1070d81ba9d5SMatt Jacob return (0); 1071d81ba9d5SMatt Jacob } 1072d81ba9d5SMatt Jacob 10732ad50ca5SMatt Jacob if (isp->isp_maxluns > 16) { 107492a1e549SMatt Jacob lun = aep->at_scclun; 10752ad50ca5SMatt Jacob } else { 107692a1e549SMatt Jacob lun = aep->at_lun; 10772ad50ca5SMatt Jacob } 107892a1e549SMatt Jacob tptr = get_lun_statep(isp, lun); 1079d81ba9d5SMatt Jacob if (tptr == NULL) { 1080d81ba9d5SMatt Jacob tptr = get_lun_statep(isp, CAM_LUN_WILDCARD); 1081d81ba9d5SMatt Jacob } 1082d81ba9d5SMatt Jacob 1083d81ba9d5SMatt Jacob if (tptr == NULL) { 108452df5dfdSMatt Jacob /* 108552df5dfdSMatt Jacob * What we'd like to know is whether or not we have a listener 108652df5dfdSMatt Jacob * upstream that really hasn't configured yet. If we do, then 108752df5dfdSMatt Jacob * we can give a more sensible reply here. If not, then we can 108852df5dfdSMatt Jacob * reject this out of hand. 108952df5dfdSMatt Jacob * 109052df5dfdSMatt Jacob * Choices for what to send were 109152df5dfdSMatt Jacob * 109252df5dfdSMatt Jacob * Not Ready, Unit Not Self-Configured Yet 109352df5dfdSMatt Jacob * (0x2,0x3e,0x00) 109452df5dfdSMatt Jacob * 109552df5dfdSMatt Jacob * for the former and 109652df5dfdSMatt Jacob * 109752df5dfdSMatt Jacob * Illegal Request, Logical Unit Not Supported 109852df5dfdSMatt Jacob * (0x5,0x25,0x00) 109952df5dfdSMatt Jacob * 110052df5dfdSMatt Jacob * for the latter. 110152df5dfdSMatt Jacob * 110252df5dfdSMatt Jacob * We used to decide whether there was at least one listener 110352df5dfdSMatt Jacob * based upon whether the black hole driver was configured. 110452df5dfdSMatt Jacob * However, recent config(8) changes have made this hard to do 110552df5dfdSMatt Jacob * at this time. 110652df5dfdSMatt Jacob * 110752df5dfdSMatt Jacob */ 1108d81ba9d5SMatt Jacob u_int32_t ccode = SCSI_STATUS_BUSY; 1109d81ba9d5SMatt Jacob 1110d81ba9d5SMatt Jacob /* 1111d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1112d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1113d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a BUSY status 1114d81ba9d5SMatt Jacob * instead. This works out okay because the only 1115d81ba9d5SMatt Jacob * time we should, in fact, get this, is in the 1116d81ba9d5SMatt Jacob * case that somebody configured us without the 1117d81ba9d5SMatt Jacob * blackhole driver, so they get what they deserve. 1118d81ba9d5SMatt Jacob */ 1119d81ba9d5SMatt Jacob isp_endcmd(isp, aep, ccode, 0); 1120d81ba9d5SMatt Jacob return (0); 1121d81ba9d5SMatt Jacob } 1122d81ba9d5SMatt Jacob 1123d81ba9d5SMatt Jacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 1124d81ba9d5SMatt Jacob if (atiop == NULL) { 1125d81ba9d5SMatt Jacob /* 1126d81ba9d5SMatt Jacob * Because we can't autofeed sense data back with 1127d81ba9d5SMatt Jacob * a command for parallel SCSI, we can't give back 1128d81ba9d5SMatt Jacob * a CHECK CONDITION. We'll give back a QUEUE FULL status 1129d81ba9d5SMatt Jacob * instead. This works out okay because the only time we 1130d81ba9d5SMatt Jacob * should, in fact, get this, is in the case that we've 1131d81ba9d5SMatt Jacob * run out of ATIOS. 1132d81ba9d5SMatt Jacob */ 1133d81ba9d5SMatt Jacob xpt_print_path(tptr->owner); 1134d81ba9d5SMatt Jacob printf("no ATIOS for lun %d from initiator %d\n", 113592a1e549SMatt Jacob lun, aep->at_iid); 1136d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1137d81ba9d5SMatt Jacob if (aep->at_flags & AT_TQAE) 1138d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); 1139d81ba9d5SMatt Jacob else 1140d81ba9d5SMatt Jacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 1141d81ba9d5SMatt Jacob return (0); 1142d81ba9d5SMatt Jacob } 1143d81ba9d5SMatt Jacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 1144f48ce188SMatt Jacob 1145d81ba9d5SMatt Jacob if (tptr == &isp->isp_osinfo.tsdflt) { 1146d81ba9d5SMatt Jacob atiop->ccb_h.target_id = 1147d81ba9d5SMatt Jacob ((fcparam *)isp->isp_param)->isp_loopid; 114892a1e549SMatt Jacob atiop->ccb_h.target_lun = lun; 1149d81ba9d5SMatt Jacob } 1150f48ce188SMatt Jacob if (aep->at_status & QLTM_SVALID) { 1151f48ce188SMatt Jacob size_t amt = imin(QLTM_SENSELEN, sizeof (atiop->sense_data)); 1152f48ce188SMatt Jacob atiop->sense_len = amt; 1153f48ce188SMatt Jacob MEMCPY(&atiop->sense_data, aep->at_sense, amt); 1154f48ce188SMatt Jacob } else { 1155f48ce188SMatt Jacob atiop->sense_len = 0; 1156f48ce188SMatt Jacob } 1157f48ce188SMatt Jacob 1158d81ba9d5SMatt Jacob atiop->init_id = aep->at_iid; 1159d81ba9d5SMatt Jacob atiop->cdb_len = ATIO2_CDBLEN; 1160d81ba9d5SMatt Jacob MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, ATIO2_CDBLEN); 1161d81ba9d5SMatt Jacob atiop->ccb_h.status = CAM_CDB_RECVD; 1162d81ba9d5SMatt Jacob atiop->tag_id = aep->at_rxid; 1163d81ba9d5SMatt Jacob switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) { 1164d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_SIMPLEQ: 1165d81ba9d5SMatt Jacob atiop->tag_action = MSG_SIMPLE_Q_TAG; 1166d81ba9d5SMatt Jacob break; 1167d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_HEADOFQ: 1168d81ba9d5SMatt Jacob atiop->tag_action = MSG_HEAD_OF_Q_TAG; 1169d81ba9d5SMatt Jacob break; 1170d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_ORDERED: 1171d81ba9d5SMatt Jacob atiop->tag_action = MSG_ORDERED_Q_TAG; 1172d81ba9d5SMatt Jacob break; 1173d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_ACAQ: /* ?? */ 1174d81ba9d5SMatt Jacob case ATIO2_TC_ATTR_UNTAGGED: 1175d81ba9d5SMatt Jacob default: 1176d81ba9d5SMatt Jacob atiop->tag_action = 0; 1177d81ba9d5SMatt Jacob break; 1178d81ba9d5SMatt Jacob } 1179d81ba9d5SMatt Jacob if (atiop->tag_action != 0) { 1180d81ba9d5SMatt Jacob atiop->ccb_h.status |= CAM_TAG_ACTION_VALID; 1181d81ba9d5SMatt Jacob } 1182f48ce188SMatt Jacob 1183f48ce188SMatt Jacob /* 1184f48ce188SMatt Jacob * Preserve overall command datalength in private field. 1185f48ce188SMatt Jacob */ 1186f48ce188SMatt Jacob atiop->ccb_h.spriv_field0 = aep->at_datalen; 1187f48ce188SMatt Jacob 1188d81ba9d5SMatt Jacob xpt_done((union ccb*)atiop); 1189b09b0095SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG2, 1190b09b0095SMatt Jacob "ATIO2 RX_ID 0x%x CDB=0x%x iid%d->lun%d tattr 0x%x datalen %u", 1191b09b0095SMatt Jacob aep->at_rxid & 0xffff, aep->at_cdb[0] & 0xff, aep->at_iid, 1192b09b0095SMatt Jacob lun, aep->at_taskflags, aep->at_datalen); 1193d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1194d81ba9d5SMatt Jacob return (0); 1195d81ba9d5SMatt Jacob } 1196d81ba9d5SMatt Jacob 1197d81ba9d5SMatt Jacob static int 1198d81ba9d5SMatt Jacob isp_handle_platform_ctio(struct ispsoftc *isp, void *arg) 1199d81ba9d5SMatt Jacob { 1200d81ba9d5SMatt Jacob union ccb *ccb; 1201f48ce188SMatt Jacob int sentstatus, ok, notify_cam; 1202d81ba9d5SMatt Jacob 1203d81ba9d5SMatt Jacob /* 1204d81ba9d5SMatt Jacob * CTIO and CTIO2 are close enough.... 1205d81ba9d5SMatt Jacob */ 1206d81ba9d5SMatt Jacob 1207d81ba9d5SMatt Jacob ccb = (union ccb *) isp_find_xs(isp, ((ct_entry_t *)arg)->ct_reserved); 1208d81ba9d5SMatt Jacob KASSERT((ccb != NULL), ("null ccb in isp_handle_platform_ctio")); 1209d81ba9d5SMatt Jacob isp_destroy_handle(isp, ((ct_entry_t *)arg)->ct_reserved); 1210d81ba9d5SMatt Jacob 1211d81ba9d5SMatt Jacob if (IS_FC(isp)) { 1212d81ba9d5SMatt Jacob ct2_entry_t *ct = arg; 1213d81ba9d5SMatt Jacob sentstatus = ct->ct_flags & CT2_SENDSTATUS; 1214d81ba9d5SMatt Jacob ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; 1215f48ce188SMatt Jacob if (ok && (ccb->ccb_h.flags & CAM_SEND_SENSE)) { 121600a8e174SMatt Jacob ccb->ccb_h.status |= CAM_SENT_SENSE; 121700a8e174SMatt Jacob } 1218b09b0095SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG2, 1219b09b0095SMatt Jacob "CTIO2 RX_ID 0x%x sts 0x%x flg 0x%x sns %d FIN", 1220b09b0095SMatt Jacob ct->ct_rxid, ct->ct_status, ct->ct_flags, 122100a8e174SMatt Jacob (ccb->ccb_h.status & CAM_SENT_SENSE) != 0); 1222f48ce188SMatt Jacob notify_cam = ct->ct_header.rqs_seqno; 1223d81ba9d5SMatt Jacob } else { 1224d81ba9d5SMatt Jacob ct_entry_t *ct = arg; 1225d81ba9d5SMatt Jacob sentstatus = ct->ct_flags & CT_SENDSTATUS; 1226d81ba9d5SMatt Jacob ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; 1227b09b0095SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG2, 1228b09b0095SMatt Jacob "CTIO tag 0x%x sts 0x%x flg 0x%x FIN", 1229b09b0095SMatt Jacob ct->ct_tag_val, ct->ct_status, ct->ct_flags); 1230f48ce188SMatt Jacob notify_cam = ct->ct_header.rqs_seqno; 1231d81ba9d5SMatt Jacob } 1232d81ba9d5SMatt Jacob 1233d81ba9d5SMatt Jacob /* 1234d81ba9d5SMatt Jacob * We're here either because data transfers are done (and 1235d81ba9d5SMatt Jacob * it's time to send a final status CTIO) or because the final 1236d81ba9d5SMatt Jacob * status CTIO is done. We don't get called for all intermediate 1237d81ba9d5SMatt Jacob * CTIOs that happen for a large data transfer. 1238d81ba9d5SMatt Jacob * 1239d81ba9d5SMatt Jacob * In any case, for this platform, the upper layers figure out 1240d81ba9d5SMatt Jacob * what to do next, so all we do here is collect status and 1241f48ce188SMatt Jacob * pass information along. The exception is that we clear 1242f48ce188SMatt Jacob * the notion of handling a non-disconnecting command here. 1243d81ba9d5SMatt Jacob */ 1244d81ba9d5SMatt Jacob 1245d81ba9d5SMatt Jacob if (sentstatus) { 1246d81ba9d5SMatt Jacob /* 1247d81ba9d5SMatt Jacob * Data transfer done. See if all went okay. 1248d81ba9d5SMatt Jacob */ 1249d81ba9d5SMatt Jacob if (ok) { 1250d81ba9d5SMatt Jacob ccb->csio.resid = 0; 1251d81ba9d5SMatt Jacob } else { 1252d81ba9d5SMatt Jacob ccb->csio.resid = ccb->csio.dxfer_len; 1253d81ba9d5SMatt Jacob } 1254d81ba9d5SMatt Jacob } 1255d81ba9d5SMatt Jacob 1256f48ce188SMatt Jacob if (notify_cam == 0) { 1257b09b0095SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, "Intermediate CTIO done"); 1258f48ce188SMatt Jacob return (0); 1259f48ce188SMatt Jacob } 1260b09b0095SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, "Final CTIO done"); 1261f48ce188SMatt Jacob if (isp_target_putback_atio(isp, ccb) != CAM_REQ_CMP) { 1262f48ce188SMatt Jacob (void) timeout(isp_refire_putback_atio, ccb, 10); 1263f48ce188SMatt Jacob } else { 1264f48ce188SMatt Jacob isp_handle_platform_ctio_part2(isp, ccb); 1265f48ce188SMatt Jacob } 1266f48ce188SMatt Jacob return (0); 1267f48ce188SMatt Jacob } 1268d81ba9d5SMatt Jacob 1269f48ce188SMatt Jacob static void 1270f48ce188SMatt Jacob isp_handle_platform_ctio_part2(struct ispsoftc *isp, union ccb *ccb) 1271f48ce188SMatt Jacob { 1272d81ba9d5SMatt Jacob if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { 1273d81ba9d5SMatt Jacob ccb->ccb_h.status |= CAM_REQ_CMP; 1274d81ba9d5SMatt Jacob } 1275d81ba9d5SMatt Jacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1276d81ba9d5SMatt Jacob if (isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE) { 1277d81ba9d5SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_RESOURCE; 1278d81ba9d5SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 1279d81ba9d5SMatt Jacob if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 1280b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "ctio->relsimq"); 1281d81ba9d5SMatt Jacob ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 1282d81ba9d5SMatt Jacob } else { 1283b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, "ctio->devqfrozen"); 1284d81ba9d5SMatt Jacob } 1285d81ba9d5SMatt Jacob } else { 1286b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1287b09b0095SMatt Jacob "ctio->simqfrozen(%x)", isp->isp_osinfo.simqfrozen); 1288d81ba9d5SMatt Jacob } 1289d81ba9d5SMatt Jacob } 1290d81ba9d5SMatt Jacob xpt_done(ccb); 1291d81ba9d5SMatt Jacob } 1292d81ba9d5SMatt Jacob #endif 1293d81ba9d5SMatt Jacob 1294478f8a96SJustin T. Gibbs static void 1295cbf57b47SMatt Jacob isp_cam_async(void *cbarg, u_int32_t code, struct cam_path *path, void *arg) 1296478f8a96SJustin T. Gibbs { 1297478f8a96SJustin T. Gibbs struct cam_sim *sim; 1298478f8a96SJustin T. Gibbs struct ispsoftc *isp; 1299478f8a96SJustin T. Gibbs 1300478f8a96SJustin T. Gibbs sim = (struct cam_sim *)cbarg; 1301478f8a96SJustin T. Gibbs isp = (struct ispsoftc *) cam_sim_softc(sim); 1302478f8a96SJustin T. Gibbs switch (code) { 1303478f8a96SJustin T. Gibbs case AC_LOST_DEVICE: 1304ab6c4b31SMatt Jacob if (IS_SCSI(isp)) { 1305478f8a96SJustin T. Gibbs u_int16_t oflags, nflags; 1306478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 1307f6e75de2SMatt Jacob int rvf, tgt; 1308478f8a96SJustin T. Gibbs 1309f9e908dcSMatt Jacob tgt = xpt_path_target_id(path); 1310f9e908dcSMatt Jacob rvf = ISP_FW_REVX(isp->isp_fwrev); 1311f6e75de2SMatt Jacob ISP_LOCK(isp); 1312ea6f23cdSMatt Jacob sdp += cam_sim_bus(sim); 1313ea6f23cdSMatt Jacob isp->isp_update |= (1 << cam_sim_bus(sim)); 1314478f8a96SJustin T. Gibbs nflags = DPARM_SAFE_DFLT; 1315f9e908dcSMatt Jacob if (rvf >= ISP_FW_REV(7, 55, 0) || 1316f9e908dcSMatt Jacob (ISP_FW_REV(4, 55, 0) <= rvf && 1317f9e908dcSMatt Jacob (rvf < ISP_FW_REV(5, 0, 0)))) { 1318478f8a96SJustin T. Gibbs nflags |= DPARM_NARROW | DPARM_ASYNC; 1319478f8a96SJustin T. Gibbs } 1320478f8a96SJustin T. Gibbs oflags = sdp->isp_devparam[tgt].dev_flags; 1321478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_flags = nflags; 1322478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_update = 1; 1323478f8a96SJustin T. Gibbs (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL); 1324478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_flags = oflags; 1325f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1326478f8a96SJustin T. Gibbs } 1327478f8a96SJustin T. Gibbs break; 1328478f8a96SJustin T. Gibbs default: 13290470d791SMatt Jacob printf("%s: isp_attach Async Code 0x%x\n", isp->isp_name, code); 1330478f8a96SJustin T. Gibbs break; 1331478f8a96SJustin T. Gibbs } 1332478f8a96SJustin T. Gibbs } 1333478f8a96SJustin T. Gibbs 1334478f8a96SJustin T. Gibbs static void 1335c3055363SMatt Jacob isp_poll(struct cam_sim *sim) 1336478f8a96SJustin T. Gibbs { 1337478f8a96SJustin T. Gibbs isp_intr((struct ispsoftc *) cam_sim_softc(sim)); 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) { 1490478f8a96SJustin T. Gibbs printf("%s: invalid tgt/lun (%d.%d) in XPT_SCSI_IO\n", 1491478f8a96SJustin T. Gibbs isp->isp_name, ccb->ccb_h.target_id, 1492478f8a96SJustin T. Gibbs 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: 15390470d791SMatt Jacob isp_done((struct ccb_scsiio *) ccb); 15400470d791SMatt Jacob break; 15410470d791SMatt Jacob default: 15420470d791SMatt Jacob printf("%s: What's this? 0x%x at %d in file %s\n", 15430470d791SMatt Jacob isp->isp_name, error, __LINE__, __FILE__); 1544b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQ_CMP_ERR); 15450470d791SMatt Jacob xpt_done(ccb); 1546478f8a96SJustin T. Gibbs } 1547478f8a96SJustin T. Gibbs break; 1548478f8a96SJustin T. Gibbs 1549d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 1550478f8a96SJustin T. Gibbs case XPT_EN_LUN: /* Enable LUN as a target */ 1551d81ba9d5SMatt Jacob isp_en_lun(isp, ccb); 1552478f8a96SJustin T. Gibbs xpt_done(ccb); 1553478f8a96SJustin T. Gibbs break; 1554478f8a96SJustin T. Gibbs 1555d81ba9d5SMatt Jacob case XPT_NOTIFY_ACK: /* recycle notify ack */ 1556d81ba9d5SMatt Jacob case XPT_IMMED_NOTIFY: /* Add Immediate Notify Resource */ 1557d81ba9d5SMatt Jacob case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */ 1558d81ba9d5SMatt Jacob { 1559d81ba9d5SMatt Jacob tstate_t *tptr = get_lun_statep(isp, ccb->ccb_h.target_lun); 1560d81ba9d5SMatt Jacob if (tptr == NULL) { 1561d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_LUN_INVALID; 1562d81ba9d5SMatt Jacob xpt_done(ccb); 1563d81ba9d5SMatt Jacob break; 1564d81ba9d5SMatt Jacob } 1565f48ce188SMatt Jacob ccb->ccb_h.sim_priv.entries[0].field = 0; 1566f48ce188SMatt Jacob ccb->ccb_h.sim_priv.entries[1].ptr = isp; 1567f6e75de2SMatt Jacob ISP_LOCK(isp); 1568d81ba9d5SMatt Jacob if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 1569f48ce188SMatt Jacob #if 0 1570f48ce188SMatt Jacob (void) isp_target_putback_atio(isp, ccb); 1571f48ce188SMatt Jacob #endif 1572d81ba9d5SMatt Jacob SLIST_INSERT_HEAD(&tptr->atios, 1573d81ba9d5SMatt Jacob &ccb->ccb_h, sim_links.sle); 1574d81ba9d5SMatt Jacob } else { 1575d81ba9d5SMatt Jacob SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, 1576d81ba9d5SMatt Jacob sim_links.sle); 1577d81ba9d5SMatt Jacob } 1578f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1579d81ba9d5SMatt Jacob rls_lun_statep(isp, tptr); 1580d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_INPROG; 1581d81ba9d5SMatt Jacob break; 1582d81ba9d5SMatt Jacob } 1583d81ba9d5SMatt Jacob case XPT_CONT_TARGET_IO: 1584d81ba9d5SMatt Jacob { 1585f6e75de2SMatt Jacob ISP_LOCK(isp); 1586d81ba9d5SMatt Jacob ccb->ccb_h.status = isp_target_start_ctio(isp, ccb); 1587d81ba9d5SMatt Jacob if (ccb->ccb_h.status != CAM_REQ_INPROG) { 1588d81ba9d5SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 1589d81ba9d5SMatt Jacob xpt_freeze_simq(sim, 1); 1590d81ba9d5SMatt Jacob xpt_print_path(ccb->ccb_h.path); 1591d81ba9d5SMatt Jacob printf("XPT_CONT_TARGET_IO freeze simq\n"); 1592d81ba9d5SMatt Jacob } 1593d81ba9d5SMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_RESOURCE; 1594b85389e1SMatt Jacob XS_SETERR(ccb, CAM_REQUEUE_REQ); 1595d81ba9d5SMatt Jacob xpt_done(ccb); 1596d81ba9d5SMatt Jacob } else { 1597d81ba9d5SMatt Jacob ccb->ccb_h.status |= CAM_SIM_QUEUED; 1598d81ba9d5SMatt Jacob } 1599f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1600d81ba9d5SMatt Jacob break; 1601d81ba9d5SMatt Jacob } 1602d81ba9d5SMatt Jacob #endif 1603478f8a96SJustin T. Gibbs case XPT_RESET_DEV: /* BDR the specified SCSI device */ 1604d81ba9d5SMatt Jacob 1605d81ba9d5SMatt Jacob bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path)); 1606d81ba9d5SMatt Jacob tgt = ccb->ccb_h.target_id; 1607d81ba9d5SMatt Jacob tgt |= (bus << 16); 1608d81ba9d5SMatt Jacob 1609f6e75de2SMatt Jacob ISP_LOCK(isp); 1610ea6f23cdSMatt Jacob error = isp_control(isp, ISPCTL_RESET_DEV, &tgt); 1611f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1612478f8a96SJustin T. Gibbs if (error) { 1613478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 1614478f8a96SJustin T. Gibbs } else { 1615478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 1616478f8a96SJustin T. Gibbs } 1617478f8a96SJustin T. Gibbs xpt_done(ccb); 1618478f8a96SJustin T. Gibbs break; 1619478f8a96SJustin T. Gibbs case XPT_ABORT: /* Abort the specified CCB */ 1620d81ba9d5SMatt Jacob { 1621d81ba9d5SMatt Jacob union ccb *accb = ccb->cab.abort_ccb; 1622d81ba9d5SMatt Jacob switch (accb->ccb_h.func_code) { 1623d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 1624d81ba9d5SMatt Jacob case XPT_ACCEPT_TARGET_IO: 1625d81ba9d5SMatt Jacob case XPT_IMMED_NOTIFY: 1626d81ba9d5SMatt Jacob ccb->ccb_h.status = isp_abort_tgt_ccb(isp, ccb); 1627d81ba9d5SMatt Jacob break; 1628d81ba9d5SMatt Jacob case XPT_CONT_TARGET_IO: 1629b09b0095SMatt Jacob isp_prt(isp, ISP_LOGERR, "cannot abort CTIOs yet"); 1630d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_UA_ABORT; 1631d81ba9d5SMatt Jacob break; 1632d81ba9d5SMatt Jacob #endif 1633d81ba9d5SMatt Jacob case XPT_SCSI_IO: 1634f6e75de2SMatt Jacob ISP_LOCK(isp); 1635478f8a96SJustin T. Gibbs error = isp_control(isp, ISPCTL_ABORT_CMD, ccb); 1636f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1637478f8a96SJustin T. Gibbs if (error) { 1638d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_UA_ABORT; 1639478f8a96SJustin T. Gibbs } else { 1640478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 1641478f8a96SJustin T. Gibbs } 1642d81ba9d5SMatt Jacob break; 1643d81ba9d5SMatt Jacob default: 1644d81ba9d5SMatt Jacob ccb->ccb_h.status = CAM_REQ_INVALID; 1645d81ba9d5SMatt Jacob break; 1646d81ba9d5SMatt Jacob } 1647478f8a96SJustin T. Gibbs xpt_done(ccb); 1648478f8a96SJustin T. Gibbs break; 1649d81ba9d5SMatt Jacob } 1650478f8a96SJustin T. Gibbs case XPT_SET_TRAN_SETTINGS: /* Nexus Settings */ 1651478f8a96SJustin T. Gibbs 1652478f8a96SJustin T. Gibbs cts = &ccb->cts; 1653478f8a96SJustin T. Gibbs tgt = cts->ccb_h.target_id; 1654f6e75de2SMatt Jacob ISP_LOCK(isp); 1655ab6c4b31SMatt Jacob if (IS_SCSI(isp)) { 1656478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 1657478f8a96SJustin T. Gibbs u_int16_t *dptr; 1658d81ba9d5SMatt Jacob 1659d81ba9d5SMatt Jacob bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 1660478f8a96SJustin T. Gibbs 1661ea6f23cdSMatt Jacob sdp += bus; 1662478f8a96SJustin T. Gibbs #if 0 1663478f8a96SJustin T. Gibbs if (cts->flags & CCB_TRANS_CURRENT_SETTINGS) 1664478f8a96SJustin T. Gibbs dptr = &sdp->isp_devparam[tgt].cur_dflags; 1665478f8a96SJustin T. Gibbs else 1666478f8a96SJustin T. Gibbs dptr = &sdp->isp_devparam[tgt].dev_flags; 1667478f8a96SJustin T. Gibbs #else 1668478f8a96SJustin T. Gibbs /* 1669478f8a96SJustin T. Gibbs * We always update (internally) from dev_flags 1670478f8a96SJustin T. Gibbs * so any request to change settings just gets 1671478f8a96SJustin T. Gibbs * vectored to that location. 1672478f8a96SJustin T. Gibbs */ 1673478f8a96SJustin T. Gibbs dptr = &sdp->isp_devparam[tgt].dev_flags; 1674478f8a96SJustin T. Gibbs #endif 1675478f8a96SJustin T. Gibbs 1676478f8a96SJustin T. Gibbs /* 1677478f8a96SJustin T. Gibbs * Note that these operations affect the 16784394c92fSMatt Jacob * the goal flags (dev_flags)- not 1679478f8a96SJustin T. Gibbs * the current state flags. Then we mark 1680478f8a96SJustin T. Gibbs * things so that the next operation to 1681478f8a96SJustin T. Gibbs * this HBA will cause the update to occur. 1682478f8a96SJustin T. Gibbs */ 1683478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_DISC_VALID) { 1684478f8a96SJustin T. Gibbs if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) { 1685478f8a96SJustin T. Gibbs *dptr |= DPARM_DISC; 1686478f8a96SJustin T. Gibbs } else { 1687478f8a96SJustin T. Gibbs *dptr &= ~DPARM_DISC; 1688478f8a96SJustin T. Gibbs } 1689478f8a96SJustin T. Gibbs } 1690478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_TQ_VALID) { 1691478f8a96SJustin T. Gibbs if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) { 1692478f8a96SJustin T. Gibbs *dptr |= DPARM_TQING; 1693478f8a96SJustin T. Gibbs } else { 1694478f8a96SJustin T. Gibbs *dptr &= ~DPARM_TQING; 1695478f8a96SJustin T. Gibbs } 1696478f8a96SJustin T. Gibbs } 1697478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) { 1698478f8a96SJustin T. Gibbs switch (cts->bus_width) { 1699478f8a96SJustin T. Gibbs case MSG_EXT_WDTR_BUS_16_BIT: 1700478f8a96SJustin T. Gibbs *dptr |= DPARM_WIDE; 1701478f8a96SJustin T. Gibbs break; 1702478f8a96SJustin T. Gibbs default: 1703478f8a96SJustin T. Gibbs *dptr &= ~DPARM_WIDE; 1704478f8a96SJustin T. Gibbs } 1705478f8a96SJustin T. Gibbs } 1706478f8a96SJustin T. Gibbs /* 1707478f8a96SJustin T. Gibbs * Any SYNC RATE of nonzero and SYNC_OFFSET 1708478f8a96SJustin T. Gibbs * of nonzero will cause us to go to the 1709478f8a96SJustin T. Gibbs * selected (from NVRAM) maximum value for 1710478f8a96SJustin T. Gibbs * this device. At a later point, we'll 1711478f8a96SJustin T. Gibbs * allow finer control. 1712478f8a96SJustin T. Gibbs */ 1713478f8a96SJustin T. Gibbs if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) && 1714478f8a96SJustin T. Gibbs (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) && 1715478f8a96SJustin T. Gibbs (cts->sync_offset > 0)) { 1716478f8a96SJustin T. Gibbs *dptr |= DPARM_SYNC; 1717478f8a96SJustin T. Gibbs } else { 1718478f8a96SJustin T. Gibbs *dptr &= ~DPARM_SYNC; 1719478f8a96SJustin T. Gibbs } 1720ab6c4b31SMatt Jacob *dptr |= DPARM_SAFE_DFLT; 172183ae4407SMatt Jacob if (bootverbose || isp->isp_dblev >= 3) 172283ae4407SMatt Jacob printf("%s: %d.%d set %s period 0x%x offset " 172383ae4407SMatt Jacob "0x%x flags 0x%x\n", isp->isp_name, bus, 172483ae4407SMatt Jacob tgt, 17254394c92fSMatt Jacob (cts->flags & CCB_TRANS_CURRENT_SETTINGS)? 17264394c92fSMatt Jacob "current" : "user", 17272b052931SMatt Jacob sdp->isp_devparam[tgt].sync_period, 17282b052931SMatt Jacob sdp->isp_devparam[tgt].sync_offset, 172983ae4407SMatt Jacob sdp->isp_devparam[tgt].dev_flags); 1730478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_update = 1; 1731ea6f23cdSMatt Jacob isp->isp_update |= (1 << bus); 1732478f8a96SJustin T. Gibbs } 1733f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1734478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 1735478f8a96SJustin T. Gibbs xpt_done(ccb); 1736478f8a96SJustin T. Gibbs break; 1737478f8a96SJustin T. Gibbs 1738478f8a96SJustin T. Gibbs case XPT_GET_TRAN_SETTINGS: 1739478f8a96SJustin T. Gibbs 1740478f8a96SJustin T. Gibbs cts = &ccb->cts; 1741478f8a96SJustin T. Gibbs tgt = cts->ccb_h.target_id; 1742ab6c4b31SMatt Jacob if (IS_FC(isp)) { 1743478f8a96SJustin T. Gibbs /* 1744478f8a96SJustin T. Gibbs * a lot of normal SCSI things don't make sense. 1745478f8a96SJustin T. Gibbs */ 1746478f8a96SJustin T. Gibbs cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB; 1747478f8a96SJustin T. Gibbs cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 1748478f8a96SJustin T. Gibbs /* 1749478f8a96SJustin T. Gibbs * How do you measure the width of a high 1750478f8a96SJustin T. Gibbs * speed serial bus? Well, in bytes. 1751478f8a96SJustin T. Gibbs * 1752478f8a96SJustin T. Gibbs * Offset and period make no sense, though, so we set 1753478f8a96SJustin T. Gibbs * (above) a 'base' transfer speed to be gigabit. 1754478f8a96SJustin T. Gibbs */ 1755478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 1756478f8a96SJustin T. Gibbs } else { 1757478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 17584394c92fSMatt Jacob u_int16_t dval, pval, oval; 1759ea6f23cdSMatt Jacob int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 1760478f8a96SJustin T. Gibbs 1761ea6f23cdSMatt Jacob sdp += bus; 17624394c92fSMatt Jacob if (cts->flags & CCB_TRANS_CURRENT_SETTINGS) { 1763f6e75de2SMatt Jacob ISP_LOCK(isp); 176483ae4407SMatt Jacob sdp->isp_devparam[tgt].dev_refresh = 1; 176583ae4407SMatt Jacob isp->isp_update |= (1 << bus); 176683ae4407SMatt Jacob (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, 176783ae4407SMatt Jacob NULL); 1768f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1769478f8a96SJustin T. Gibbs dval = sdp->isp_devparam[tgt].cur_dflags; 17704394c92fSMatt Jacob oval = sdp->isp_devparam[tgt].cur_offset; 17714394c92fSMatt Jacob pval = sdp->isp_devparam[tgt].cur_period; 17724394c92fSMatt Jacob } else { 1773478f8a96SJustin T. Gibbs dval = sdp->isp_devparam[tgt].dev_flags; 17744394c92fSMatt Jacob oval = sdp->isp_devparam[tgt].sync_offset; 17754394c92fSMatt Jacob pval = sdp->isp_devparam[tgt].sync_period; 17764394c92fSMatt Jacob } 1777478f8a96SJustin T. Gibbs 1778f6e75de2SMatt Jacob ISP_LOCK(isp); 1779478f8a96SJustin T. Gibbs cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); 1780478f8a96SJustin T. Gibbs 1781478f8a96SJustin T. Gibbs if (dval & DPARM_DISC) { 1782478f8a96SJustin T. Gibbs cts->flags |= CCB_TRANS_DISC_ENB; 1783478f8a96SJustin T. Gibbs } 1784478f8a96SJustin T. Gibbs if (dval & DPARM_TQING) { 1785478f8a96SJustin T. Gibbs cts->flags |= CCB_TRANS_TAG_ENB; 1786478f8a96SJustin T. Gibbs } 1787478f8a96SJustin T. Gibbs if (dval & DPARM_WIDE) { 1788478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 1789478f8a96SJustin T. Gibbs } else { 1790478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 1791478f8a96SJustin T. Gibbs } 1792478f8a96SJustin T. Gibbs cts->valid = CCB_TRANS_BUS_WIDTH_VALID | 1793478f8a96SJustin T. Gibbs CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 1794478f8a96SJustin T. Gibbs 17954394c92fSMatt Jacob if ((dval & DPARM_SYNC) && oval != 0) { 17964394c92fSMatt Jacob cts->sync_period = pval; 17974394c92fSMatt Jacob cts->sync_offset = oval; 1798478f8a96SJustin T. Gibbs cts->valid |= 1799478f8a96SJustin T. Gibbs CCB_TRANS_SYNC_RATE_VALID | 1800478f8a96SJustin T. Gibbs CCB_TRANS_SYNC_OFFSET_VALID; 1801478f8a96SJustin T. Gibbs } 1802f6e75de2SMatt Jacob ISP_UNLOCK(isp); 180383ae4407SMatt Jacob if (bootverbose || isp->isp_dblev >= 3) 180483ae4407SMatt Jacob printf("%s: %d.%d get %s period 0x%x offset " 180583ae4407SMatt Jacob "0x%x flags 0x%x\n", isp->isp_name, bus, 180683ae4407SMatt Jacob tgt, 18074394c92fSMatt Jacob (cts->flags & CCB_TRANS_CURRENT_SETTINGS)? 180883ae4407SMatt Jacob "current" : "user", pval, oval, dval); 1809478f8a96SJustin T. Gibbs } 1810478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 1811478f8a96SJustin T. Gibbs xpt_done(ccb); 1812478f8a96SJustin T. Gibbs break; 1813478f8a96SJustin T. Gibbs 1814478f8a96SJustin T. Gibbs case XPT_CALC_GEOMETRY: 1815478f8a96SJustin T. Gibbs { 1816478f8a96SJustin T. Gibbs struct ccb_calc_geometry *ccg; 1817478f8a96SJustin T. Gibbs u_int32_t secs_per_cylinder; 1818478f8a96SJustin T. Gibbs u_int32_t size_mb; 1819478f8a96SJustin T. Gibbs 1820478f8a96SJustin T. Gibbs ccg = &ccb->ccg; 1821478f8a96SJustin T. Gibbs if (ccg->block_size == 0) { 1822478f8a96SJustin T. Gibbs printf("%s: %d.%d XPT_CALC_GEOMETRY block size 0?\n", 1823478f8a96SJustin T. Gibbs isp->isp_name, ccg->ccb_h.target_id, 1824478f8a96SJustin T. Gibbs ccg->ccb_h.target_lun); 1825478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 1826478f8a96SJustin T. Gibbs xpt_done(ccb); 1827478f8a96SJustin T. Gibbs break; 1828478f8a96SJustin T. Gibbs } 1829478f8a96SJustin T. Gibbs size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size); 1830478f8a96SJustin T. Gibbs if (size_mb > 1024) { 1831478f8a96SJustin T. Gibbs ccg->heads = 255; 1832478f8a96SJustin T. Gibbs ccg->secs_per_track = 63; 1833478f8a96SJustin T. Gibbs } else { 1834478f8a96SJustin T. Gibbs ccg->heads = 64; 1835478f8a96SJustin T. Gibbs ccg->secs_per_track = 32; 1836478f8a96SJustin T. Gibbs } 1837478f8a96SJustin T. Gibbs secs_per_cylinder = ccg->heads * ccg->secs_per_track; 1838478f8a96SJustin T. Gibbs ccg->cylinders = ccg->volume_size / secs_per_cylinder; 1839478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 1840478f8a96SJustin T. Gibbs xpt_done(ccb); 1841478f8a96SJustin T. Gibbs break; 1842478f8a96SJustin T. Gibbs } 1843478f8a96SJustin T. Gibbs case XPT_RESET_BUS: /* Reset the specified bus */ 1844ab6c4b31SMatt Jacob bus = cam_sim_bus(sim); 1845f6e75de2SMatt Jacob ISP_LOCK(isp); 1846ab6c4b31SMatt Jacob error = isp_control(isp, ISPCTL_RESET_BUS, &bus); 1847f6e75de2SMatt Jacob ISP_UNLOCK(isp); 1848478f8a96SJustin T. Gibbs if (error) 1849478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 18502b052931SMatt Jacob else { 1851ea6f23cdSMatt Jacob if (cam_sim_bus(sim) && isp->isp_path2 != NULL) 1852ea6f23cdSMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); 1853ea6f23cdSMatt Jacob else if (isp->isp_path != NULL) 18542b052931SMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path, NULL); 1855478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 18562b052931SMatt Jacob } 1857478f8a96SJustin T. Gibbs xpt_done(ccb); 1858478f8a96SJustin T. Gibbs break; 1859478f8a96SJustin T. Gibbs 1860478f8a96SJustin T. Gibbs case XPT_TERM_IO: /* Terminate the I/O process */ 1861478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 1862478f8a96SJustin T. Gibbs xpt_done(ccb); 1863478f8a96SJustin T. Gibbs break; 1864478f8a96SJustin T. Gibbs 1865478f8a96SJustin T. Gibbs case XPT_PATH_INQ: /* Path routing inquiry */ 1866478f8a96SJustin T. Gibbs { 1867478f8a96SJustin T. Gibbs struct ccb_pathinq *cpi = &ccb->cpi; 1868478f8a96SJustin T. Gibbs 1869478f8a96SJustin T. Gibbs cpi->version_num = 1; 1870d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 1871d81ba9d5SMatt Jacob cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO; 1872d81ba9d5SMatt Jacob #else 1873478f8a96SJustin T. Gibbs cpi->target_sprt = 0; 1874d81ba9d5SMatt Jacob #endif 1875478f8a96SJustin T. Gibbs cpi->hba_eng_cnt = 0; 18760470d791SMatt Jacob cpi->max_target = ISP_MAX_TARGETS(isp) - 1; 18770470d791SMatt Jacob cpi->max_lun = ISP_MAX_LUNS(isp) - 1; 18780470d791SMatt Jacob cpi->bus_id = cam_sim_bus(sim); 18794394c92fSMatt Jacob if (IS_FC(isp)) { 18804394c92fSMatt Jacob cpi->hba_misc = PIM_NOBUSRESET; 18810470d791SMatt Jacob /* 18820470d791SMatt Jacob * Because our loop ID can shift from time to time, 18830470d791SMatt Jacob * make our initiator ID out of range of our bus. 18840470d791SMatt Jacob */ 18850470d791SMatt Jacob cpi->initiator_id = cpi->max_target + 1; 18860470d791SMatt Jacob 18879deea857SKenneth D. Merry /* 18889deea857SKenneth D. Merry * Set base transfer capabilities for Fibre Channel. 18899deea857SKenneth D. Merry * Technically not correct because we don't know 18909deea857SKenneth D. Merry * what media we're running on top of- but we'll 18919deea857SKenneth D. Merry * look good if we always say 100MB/s. 18929deea857SKenneth D. Merry */ 18939deea857SKenneth D. Merry cpi->base_transfer_speed = 100000; 18940470d791SMatt Jacob cpi->hba_inquiry = PI_TAG_ABLE; 1895478f8a96SJustin T. Gibbs } else { 1896ea6f23cdSMatt Jacob sdparam *sdp = isp->isp_param; 1897ea6f23cdSMatt Jacob sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path)); 18980470d791SMatt Jacob cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; 18994394c92fSMatt Jacob cpi->hba_misc = 0; 1900ea6f23cdSMatt Jacob cpi->initiator_id = sdp->isp_initiator_id; 19019deea857SKenneth D. Merry cpi->base_transfer_speed = 3300; 1902478f8a96SJustin T. Gibbs } 1903478f8a96SJustin T. Gibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 1904478f8a96SJustin T. Gibbs strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN); 1905478f8a96SJustin T. Gibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 1906478f8a96SJustin T. Gibbs cpi->unit_number = cam_sim_unit(sim); 1907478f8a96SJustin T. Gibbs cpi->ccb_h.status = CAM_REQ_CMP; 1908478f8a96SJustin T. Gibbs xpt_done(ccb); 1909478f8a96SJustin T. Gibbs break; 1910478f8a96SJustin T. Gibbs } 1911478f8a96SJustin T. Gibbs default: 1912478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 1913478f8a96SJustin T. Gibbs xpt_done(ccb); 1914478f8a96SJustin T. Gibbs break; 1915478f8a96SJustin T. Gibbs } 1916478f8a96SJustin T. Gibbs } 1917d3a9eb2eSMatt Jacob 1918d3a9eb2eSMatt Jacob #define ISPDDB (CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB) 1919d3a9eb2eSMatt Jacob void 1920c3055363SMatt Jacob isp_done(struct ccb_scsiio *sccb) 1921d3a9eb2eSMatt Jacob { 1922d3a9eb2eSMatt Jacob struct ispsoftc *isp = XS_ISP(sccb); 1923d3a9eb2eSMatt Jacob 1924d3a9eb2eSMatt Jacob if (XS_NOERR(sccb)) 1925d3a9eb2eSMatt Jacob XS_SETERR(sccb, CAM_REQ_CMP); 1926b85389e1SMatt Jacob 1927d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP && 1928d3a9eb2eSMatt Jacob (sccb->scsi_status != SCSI_STATUS_OK)) { 1929d3a9eb2eSMatt Jacob sccb->ccb_h.status &= ~CAM_STATUS_MASK; 193092a1e549SMatt Jacob if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) && 193192a1e549SMatt Jacob (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) { 193292a1e549SMatt Jacob sccb->ccb_h.status |= CAM_AUTOSENSE_FAIL; 193392a1e549SMatt Jacob } else { 1934d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 1935d3a9eb2eSMatt Jacob } 193692a1e549SMatt Jacob } 1937b85389e1SMatt Jacob 19380470d791SMatt Jacob sccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1939d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1940d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 1941d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_DEV_QFRZN; 19420470d791SMatt Jacob xpt_freeze_devq(sccb->ccb_h.path, 1); 19430470d791SMatt Jacob if (sccb->scsi_status != SCSI_STATUS_OK) 1944b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1945b09b0095SMatt Jacob "freeze devq %d.%d %x %x", 1946b09b0095SMatt Jacob sccb->ccb_h.target_id, 19470470d791SMatt Jacob sccb->ccb_h.target_lun, sccb->ccb_h.status, 1948b09b0095SMatt Jacob sccb->scsi_status); 1949d3a9eb2eSMatt Jacob } 1950d3a9eb2eSMatt Jacob } 1951b85389e1SMatt Jacob 19520470d791SMatt Jacob /* 19530470d791SMatt Jacob * If we were frozen waiting resources, clear that we were frozen 19540470d791SMatt Jacob * waiting for resources. If we are no longer frozen, and the devq 19550470d791SMatt Jacob * isn't frozen, mark the completing CCB to have the XPT layer 19560470d791SMatt Jacob * release the simq. 19570470d791SMatt Jacob */ 195857c801f5SMatt Jacob if (isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE) { 195957c801f5SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_RESOURCE; 19600470d791SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 19610470d791SMatt Jacob if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 1962b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1963b09b0095SMatt Jacob "isp_done->relsimq"); 1964d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_RELEASE_SIMQ; 19650470d791SMatt Jacob } else { 1966b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1967b09b0095SMatt Jacob "isp_done->devq frozen"); 1968d3a9eb2eSMatt Jacob } 19690470d791SMatt Jacob } else { 1970b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1971b09b0095SMatt Jacob "isp_done -> simqfrozen = %x", 1972b09b0095SMatt Jacob isp->isp_osinfo.simqfrozen); 19730470d791SMatt Jacob } 19740470d791SMatt Jacob } 1975b85389e1SMatt Jacob if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) && 1976d3a9eb2eSMatt Jacob (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1977d3a9eb2eSMatt Jacob xpt_print_path(sccb->ccb_h.path); 1978d3a9eb2eSMatt Jacob printf("cam completion status 0x%x\n", sccb->ccb_h.status); 1979d3a9eb2eSMatt Jacob } 1980b85389e1SMatt Jacob 1981b85389e1SMatt Jacob XS_CMD_S_DONE(sccb); 1982b85389e1SMatt Jacob if (XS_CMD_WDOG_P(sccb) == 0) { 1983b85389e1SMatt Jacob untimeout(isp_watchdog, (caddr_t)sccb, sccb->ccb_h.timeout_ch); 1984b85389e1SMatt Jacob if (XS_CMD_GRACE_P(sccb)) { 1985b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 1986b09b0095SMatt Jacob "finished command on borrowed time"); 1987b85389e1SMatt Jacob } 1988b85389e1SMatt Jacob XS_CMD_S_CLEAR(sccb); 1989d3a9eb2eSMatt Jacob xpt_done((union ccb *) sccb); 1990d3a9eb2eSMatt Jacob } 1991b85389e1SMatt Jacob } 1992d3a9eb2eSMatt Jacob 1993cbf57b47SMatt Jacob int 19940470d791SMatt Jacob isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg) 1995cbf57b47SMatt Jacob { 1996ea6f23cdSMatt Jacob int bus, rv = 0; 1997cbf57b47SMatt Jacob switch (cmd) { 1998cbf57b47SMatt Jacob case ISPASYNC_NEW_TGT_PARAMS: 19990470d791SMatt Jacob { 2000cbf57b47SMatt Jacob int flags, tgt; 2001cbf57b47SMatt Jacob sdparam *sdp = isp->isp_param; 2002cbf57b47SMatt Jacob struct ccb_trans_settings neg; 2003cbf57b47SMatt Jacob struct cam_path *tmppath; 2004cbf57b47SMatt Jacob 2005cbf57b47SMatt Jacob tgt = *((int *)arg); 2006ea6f23cdSMatt Jacob bus = (tgt >> 16) & 0xffff; 2007ea6f23cdSMatt Jacob tgt &= 0xffff; 2008ea6f23cdSMatt Jacob sdp += bus; 2009cbf57b47SMatt Jacob if (xpt_create_path(&tmppath, NULL, 2010ea6f23cdSMatt Jacob cam_sim_path(bus? isp->isp_sim2 : isp->isp_sim), 2011ea6f23cdSMatt Jacob tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 2012cbf57b47SMatt Jacob xpt_print_path(isp->isp_path); 2013cbf57b47SMatt Jacob printf("isp_async cannot make temp path for " 2014ea6f23cdSMatt Jacob "target %d bus %d\n", tgt, bus); 2015cbf57b47SMatt Jacob rv = -1; 2016cbf57b47SMatt Jacob break; 2017cbf57b47SMatt Jacob } 20184394c92fSMatt Jacob flags = sdp->isp_devparam[tgt].cur_dflags; 2019cbf57b47SMatt Jacob neg.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 2020cbf57b47SMatt Jacob if (flags & DPARM_DISC) { 2021cbf57b47SMatt Jacob neg.flags |= CCB_TRANS_DISC_ENB; 2022cbf57b47SMatt Jacob } 2023cbf57b47SMatt Jacob if (flags & DPARM_TQING) { 2024cbf57b47SMatt Jacob neg.flags |= CCB_TRANS_TAG_ENB; 2025cbf57b47SMatt Jacob } 2026cbf57b47SMatt Jacob neg.valid |= CCB_TRANS_BUS_WIDTH_VALID; 2027cbf57b47SMatt Jacob neg.bus_width = (flags & DPARM_WIDE)? 2028cbf57b47SMatt Jacob MSG_EXT_WDTR_BUS_8_BIT : MSG_EXT_WDTR_BUS_16_BIT; 20294394c92fSMatt Jacob neg.sync_period = sdp->isp_devparam[tgt].cur_period; 20304394c92fSMatt Jacob neg.sync_offset = sdp->isp_devparam[tgt].cur_offset; 2031cbf57b47SMatt Jacob if (flags & DPARM_SYNC) { 20324394c92fSMatt Jacob neg.valid |= 20334394c92fSMatt Jacob CCB_TRANS_SYNC_RATE_VALID | 2034cbf57b47SMatt Jacob CCB_TRANS_SYNC_OFFSET_VALID; 2035cbf57b47SMatt Jacob } 2036b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2037b09b0095SMatt Jacob "NEW_TGT_PARAMS bus %d tgt %d period %x offset %x flags %x", 2038b09b0095SMatt Jacob bus, tgt, neg.sync_period, neg.sync_offset, flags); 2039cbf57b47SMatt Jacob xpt_setup_ccb(&neg.ccb_h, tmppath, 1); 2040cbf57b47SMatt Jacob xpt_async(AC_TRANSFER_NEG, tmppath, &neg); 2041cbf57b47SMatt Jacob xpt_free_path(tmppath); 2042cbf57b47SMatt Jacob break; 20430470d791SMatt Jacob } 204457c801f5SMatt Jacob case ISPASYNC_BUS_RESET: 2045ea6f23cdSMatt Jacob bus = *((int *)arg); 2046b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected", 2047b09b0095SMatt Jacob bus); 2048ea6f23cdSMatt Jacob if (bus > 0 && isp->isp_path2) { 2049ea6f23cdSMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); 2050ea6f23cdSMatt Jacob } else if (isp->isp_path) { 205157c801f5SMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path, NULL); 205257c801f5SMatt Jacob } 205357c801f5SMatt Jacob break; 205457c801f5SMatt Jacob case ISPASYNC_LOOP_DOWN: 205557c801f5SMatt Jacob if (isp->isp_path) { 20560470d791SMatt Jacob if (isp->isp_osinfo.simqfrozen == 0) { 2057b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2058b09b0095SMatt Jacob "loop down freeze simq"); 205957c801f5SMatt Jacob xpt_freeze_simq(isp->isp_sim, 1); 20600470d791SMatt Jacob } 206157c801f5SMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; 206257c801f5SMatt Jacob } 2063b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop DOWN"); 206457c801f5SMatt Jacob break; 206557c801f5SMatt Jacob case ISPASYNC_LOOP_UP: 206657c801f5SMatt Jacob if (isp->isp_path) { 20670470d791SMatt Jacob int wasfrozen = 20680470d791SMatt Jacob isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN; 206957c801f5SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN; 20700470d791SMatt Jacob if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) { 20710470d791SMatt Jacob xpt_release_simq(isp->isp_sim, 1); 2072b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2073b09b0095SMatt Jacob "loop up release simq"); 207457c801f5SMatt Jacob } 207557c801f5SMatt Jacob } 2076b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Loop UP"); 207757c801f5SMatt Jacob break; 207802ab3379SMatt Jacob case ISPASYNC_PDB_CHANGED: 20790470d791SMatt Jacob { 2080b09b0095SMatt Jacob const char *fmt = "Target %d (Loop 0x%x) Port ID 0x%x " 2081b09b0095SMatt Jacob "role %s %s\n Port WWN 0x%08x%08x\n Node WWN 0x%08x%08x"; 208202ab3379SMatt Jacob const static char *roles[4] = { 20830470d791SMatt Jacob "(none)", "Target", "Initiator", "Target/Initiator" 208457c801f5SMatt Jacob }; 208502ab3379SMatt Jacob char *ptr; 208602ab3379SMatt Jacob fcparam *fcp = isp->isp_param; 208702ab3379SMatt Jacob int tgt = *((int *) arg); 208802ab3379SMatt Jacob struct lportdb *lp = &fcp->portdb[tgt]; 208902ab3379SMatt Jacob 209002ab3379SMatt Jacob if (lp->valid) { 209102ab3379SMatt Jacob ptr = "arrived"; 209202ab3379SMatt Jacob } else { 209302ab3379SMatt Jacob ptr = "disappeared"; 209402ab3379SMatt Jacob } 2095b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, fmt, tgt, lp->loopid, lp->portid, 209602ab3379SMatt Jacob roles[lp->roles & 0x3], ptr, 209702ab3379SMatt Jacob (u_int32_t) (lp->port_wwn >> 32), 209802ab3379SMatt Jacob (u_int32_t) (lp->port_wwn & 0xffffffffLL), 209902ab3379SMatt Jacob (u_int32_t) (lp->node_wwn >> 32), 210002ab3379SMatt Jacob (u_int32_t) (lp->node_wwn & 0xffffffffLL)); 21014394c92fSMatt Jacob break; 21024394c92fSMatt Jacob } 210357c801f5SMatt Jacob case ISPASYNC_CHANGE_NOTIFY: 2104b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, "Name Server Database Changed"); 210557c801f5SMatt Jacob break; 21060470d791SMatt Jacob #ifdef ISP2100_FABRIC 210702ab3379SMatt Jacob case ISPASYNC_FABRIC_DEV: 210802ab3379SMatt Jacob { 210902ab3379SMatt Jacob int target; 211002ab3379SMatt Jacob struct lportdb *lp; 211140cfc8feSMatt Jacob char *pt; 211240cfc8feSMatt Jacob sns_ganrsp_t *resp = (sns_ganrsp_t *) arg; 211302ab3379SMatt Jacob u_int32_t portid; 211440cfc8feSMatt Jacob u_int64_t wwpn, wwnn; 211502ab3379SMatt Jacob fcparam *fcp = isp->isp_param; 211602ab3379SMatt Jacob 211702ab3379SMatt Jacob rv = -1; 211802ab3379SMatt Jacob 211902ab3379SMatt Jacob portid = 212002ab3379SMatt Jacob (((u_int32_t) resp->snscb_port_id[0]) << 16) | 212102ab3379SMatt Jacob (((u_int32_t) resp->snscb_port_id[1]) << 8) | 212202ab3379SMatt Jacob (((u_int32_t) resp->snscb_port_id[2])); 212340cfc8feSMatt Jacob 212440cfc8feSMatt Jacob wwpn = 212502ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[0]) << 56) | 212602ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[1]) << 48) | 212702ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[2]) << 40) | 212802ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[3]) << 32) | 212902ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[4]) << 24) | 213002ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[5]) << 16) | 213102ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[6]) << 8) | 213202ab3379SMatt Jacob (((u_int64_t)resp->snscb_portname[7])); 213340cfc8feSMatt Jacob 213440cfc8feSMatt Jacob wwnn = 213540cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[0]) << 56) | 213640cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[1]) << 48) | 213740cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[2]) << 40) | 213840cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[3]) << 32) | 213940cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[4]) << 24) | 214040cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[5]) << 16) | 214140cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[6]) << 8) | 214240cfc8feSMatt Jacob (((u_int64_t)resp->snscb_nodename[7])); 214340cfc8feSMatt Jacob if (portid == 0 || wwpn == 0) { 214402ab3379SMatt Jacob rv = 0; 214502ab3379SMatt Jacob break; 214602ab3379SMatt Jacob } 214740cfc8feSMatt Jacob 214840cfc8feSMatt Jacob switch (resp->snscb_port_type) { 214940cfc8feSMatt Jacob case 1: 215040cfc8feSMatt Jacob pt = " N_Port"; 215140cfc8feSMatt Jacob break; 215240cfc8feSMatt Jacob case 2: 215340cfc8feSMatt Jacob pt = " NL_Port"; 215440cfc8feSMatt Jacob break; 215540cfc8feSMatt Jacob case 3: 215640cfc8feSMatt Jacob pt = "F/NL_Port"; 215740cfc8feSMatt Jacob break; 215840cfc8feSMatt Jacob case 0x7f: 215940cfc8feSMatt Jacob pt = " Nx_Port"; 216040cfc8feSMatt Jacob break; 216140cfc8feSMatt Jacob case 0x81: 216240cfc8feSMatt Jacob pt = " F_port"; 216340cfc8feSMatt Jacob break; 216440cfc8feSMatt Jacob case 0x82: 216540cfc8feSMatt Jacob pt = " FL_Port"; 216640cfc8feSMatt Jacob break; 216740cfc8feSMatt Jacob case 0x84: 216840cfc8feSMatt Jacob pt = " E_port"; 216940cfc8feSMatt Jacob break; 217040cfc8feSMatt Jacob default: 217140cfc8feSMatt Jacob pt = "?"; 217240cfc8feSMatt Jacob break; 217340cfc8feSMatt Jacob } 2174b09b0095SMatt Jacob isp_prt(isp, ISP_LOGINFO, 2175b09b0095SMatt Jacob "%s @ 0x%x, Node 0x%08x%08x Port %08x%08x", 2176b09b0095SMatt Jacob pt, portid, ((u_int32_t) (wwnn >> 32)), ((u_int32_t) wwnn), 217740cfc8feSMatt Jacob ((u_int32_t) (wwpn >> 32)), ((u_int32_t) wwpn)); 217802ab3379SMatt Jacob for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) { 217902ab3379SMatt Jacob lp = &fcp->portdb[target]; 218040cfc8feSMatt Jacob if (lp->port_wwn == wwpn && lp->node_wwn == wwnn) 218102ab3379SMatt Jacob break; 218202ab3379SMatt Jacob } 218302ab3379SMatt Jacob if (target < MAX_FC_TARG) { 218402ab3379SMatt Jacob rv = 0; 218502ab3379SMatt Jacob break; 218602ab3379SMatt Jacob } 218702ab3379SMatt Jacob for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) { 218802ab3379SMatt Jacob lp = &fcp->portdb[target]; 218902ab3379SMatt Jacob if (lp->port_wwn == 0) 219002ab3379SMatt Jacob break; 219102ab3379SMatt Jacob } 219202ab3379SMatt Jacob if (target == MAX_FC_TARG) { 219302ab3379SMatt Jacob printf("%s: no more space for fabric devices\n", 219402ab3379SMatt Jacob isp->isp_name); 219502ab3379SMatt Jacob break; 219602ab3379SMatt Jacob } 219740cfc8feSMatt Jacob lp->node_wwn = wwnn; 219840cfc8feSMatt Jacob lp->port_wwn = wwpn; 219902ab3379SMatt Jacob lp->portid = portid; 220002ab3379SMatt Jacob rv = 0; 220102ab3379SMatt Jacob break; 220202ab3379SMatt Jacob } 220302ab3379SMatt Jacob #endif 2204d81ba9d5SMatt Jacob #ifdef ISP_TARGET_MODE 2205d81ba9d5SMatt Jacob case ISPASYNC_TARGET_MESSAGE: 2206d81ba9d5SMatt Jacob { 2207d81ba9d5SMatt Jacob tmd_msg_t *mp = arg; 2208b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2209b09b0095SMatt Jacob "bus %d iid %d tgt %d lun %d ttype %x tval %x msg[0]=%x", 2210b09b0095SMatt Jacob mp->nt_bus, (int) mp->nt_iid, (int) mp->nt_tgt, 2211b09b0095SMatt Jacob (int) mp->nt_lun, mp->nt_tagtype, mp->nt_tagval, 2212b09b0095SMatt Jacob mp->nt_msg[0]); 2213d81ba9d5SMatt Jacob break; 2214d81ba9d5SMatt Jacob } 2215d81ba9d5SMatt Jacob case ISPASYNC_TARGET_EVENT: 2216d81ba9d5SMatt Jacob { 2217d81ba9d5SMatt Jacob tmd_event_t *ep = arg; 2218b09b0095SMatt Jacob isp_prt(isp, ISP_LOGDEBUG2, 2219b09b0095SMatt Jacob "bus %d event code 0x%x", ep->ev_bus, ep->ev_event); 2220d81ba9d5SMatt Jacob break; 2221d81ba9d5SMatt Jacob } 2222d81ba9d5SMatt Jacob case ISPASYNC_TARGET_ACTION: 2223d81ba9d5SMatt Jacob switch (((isphdr_t *)arg)->rqs_entry_type) { 2224cbf57b47SMatt Jacob default: 2225d81ba9d5SMatt Jacob printf("%s: event 0x%x for unhandled target action\n", 2226d81ba9d5SMatt Jacob isp->isp_name, ((isphdr_t *)arg)->rqs_entry_type); 2227d81ba9d5SMatt Jacob break; 2228d81ba9d5SMatt Jacob case RQSTYPE_ATIO: 2229d81ba9d5SMatt Jacob rv = isp_handle_platform_atio(isp, (at_entry_t *) arg); 2230d81ba9d5SMatt Jacob break; 2231d81ba9d5SMatt Jacob case RQSTYPE_ATIO2: 2232d81ba9d5SMatt Jacob rv = isp_handle_platform_atio2(isp, (at2_entry_t *)arg); 2233d81ba9d5SMatt Jacob break; 2234d81ba9d5SMatt Jacob case RQSTYPE_CTIO2: 2235d81ba9d5SMatt Jacob case RQSTYPE_CTIO: 2236d81ba9d5SMatt Jacob rv = isp_handle_platform_ctio(isp, arg); 2237d81ba9d5SMatt Jacob break; 2238d81ba9d5SMatt Jacob case RQSTYPE_ENABLE_LUN: 2239d81ba9d5SMatt Jacob case RQSTYPE_MODIFY_LUN: 2240d81ba9d5SMatt Jacob isp_cv_signal_rqe(isp, ((lun_entry_t *)arg)->le_status); 2241d81ba9d5SMatt Jacob break; 2242d81ba9d5SMatt Jacob } 2243d81ba9d5SMatt Jacob break; 2244d81ba9d5SMatt Jacob #endif 2245d81ba9d5SMatt Jacob default: 2246b09b0095SMatt Jacob isp_prt(isp, ISP_LOGERR, "unknown isp_async event %d", cmd); 224702ab3379SMatt Jacob rv = -1; 2248cbf57b47SMatt Jacob break; 2249cbf57b47SMatt Jacob } 2250cbf57b47SMatt Jacob return (rv); 2251cbf57b47SMatt Jacob } 2252cbf57b47SMatt Jacob 225392718a7fSMatt Jacob 225492718a7fSMatt Jacob /* 225592718a7fSMatt Jacob * Locks are held before coming here. 225692718a7fSMatt Jacob */ 225792718a7fSMatt Jacob void 225892718a7fSMatt Jacob isp_uninit(struct ispsoftc *isp) 225992718a7fSMatt Jacob { 2260ea6f23cdSMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_RESET); 226192718a7fSMatt Jacob DISABLE_INTS(isp); 226292718a7fSMatt Jacob } 2263b09b0095SMatt Jacob 2264b09b0095SMatt Jacob void 2265b09b0095SMatt Jacob isp_prt(struct ispsoftc *isp, int level, const char *fmt, ...) 2266b09b0095SMatt Jacob { 2267b09b0095SMatt Jacob va_list ap; 2268b09b0095SMatt Jacob if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) { 2269b09b0095SMatt Jacob return; 2270b09b0095SMatt Jacob } 2271b09b0095SMatt Jacob printf("%s: ", isp->isp_name); 2272b09b0095SMatt Jacob va_start(ap, fmt); 2273b09b0095SMatt Jacob vprintf(fmt, ap); 2274b09b0095SMatt Jacob va_end(ap); 2275b09b0095SMatt Jacob printf("\n"); 2276b09b0095SMatt Jacob } 2277