1139749Simp/*- 2196008Smjacob * Copyright (c) 1997-2009 by Matthew Jacob 3154704Smjacob * All rights reserved. 435388Smjacob * 535388Smjacob * Redistribution and use in source and binary forms, with or without 635388Smjacob * modification, are permitted provided that the following conditions 735388Smjacob * are met: 835388Smjacob * 1. Redistributions of source code must retain the above copyright 935388Smjacob * notice immediately at the beginning of the file, without modification, 1035388Smjacob * this list of conditions, and the following disclaimer. 1166189Smjacob * 2. The name of the author may not be used to endorse or promote products 1266189Smjacob * derived from this software without specific prior written permission. 1335388Smjacob * 1435388Smjacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1535388Smjacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1635388Smjacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1735388Smjacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 1835388Smjacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1935388Smjacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2035388Smjacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2135388Smjacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2235388Smjacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2335388Smjacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2435388Smjacob * SUCH DAMAGE. 2535388Smjacob */ 26119418Sobrien 27160410Smjacob/* 28160410Smjacob * Platform (FreeBSD) dependent common attachment code for Qlogic adapters. 29160410Smjacob */ 30119418Sobrien#include <sys/cdefs.h> 31119418Sobrien__FBSDID("$FreeBSD$"); 3235388Smjacob#include <dev/isp/isp_freebsd.h> 3377365Smjacob#include <sys/unistd.h> 3477365Smjacob#include <sys/kthread.h> 3577365Smjacob#include <sys/conf.h> 36100679Smjacob#include <sys/module.h> 3777365Smjacob#include <sys/ioccom.h> 3877365Smjacob#include <dev/isp/isp_ioctl.h> 39167473Smjacob#include <sys/devicestat.h> 40164272Smjacob#include <cam/cam_periph.h> 41166120Smjacob#include <cam/cam_xpt_periph.h> 4235388Smjacob 43196008Smjacob#if __FreeBSD_version < 800002 44196008Smjacob#define THREAD_CREATE kthread_create 45196008Smjacob#else 46196008Smjacob#define THREAD_CREATE kproc_create 47165337Smjacob#endif 4875200Smjacob 49100679SmjacobMODULE_VERSION(isp, 1); 50120088SmarkmMODULE_DEPEND(isp, cam, 1, 1, 1); 5199756Smjacobint isp_announced = 0; 52208119Smjacobint isp_fabric_hysteresis = 5; 53196008Smjacobint isp_loop_down_limit = 60; /* default loop down limit */ 54164272Smjacobint isp_change_is_bad = 0; /* "changed" devices are bad */ 55196008Smjacobint isp_quickboot_time = 7; /* don't wait more than N secs for loop up */ 56164272Smjacobint isp_gone_device_time = 30; /* grace time before reporting device lost */ 57196008Smjacobint isp_autoconfig = 1; /* automatically attach/detach devices */ 58196008Smjacobstatic const char prom3[] = "Chan %d PortID 0x%06x Departed from Target %u because of %s"; 59196008Smjacobstatic const char rqo[] = "%s: Request Queue Overflow\n"; 6099756Smjacob 61196008Smjacobstatic void isp_freeze_loopdown(ispsoftc_t *, int, char *); 6277365Smjacobstatic d_ioctl_t ispioctl; 6362498Smjacobstatic void isp_intr_enable(void *); 64155704Smjacobstatic void isp_cam_async(void *, uint32_t, struct cam_path *, void *); 6549915Smjacobstatic void isp_poll(struct cam_sim *); 6662173Smjacobstatic timeout_t isp_watchdog; 67224804Smjacobstatic timeout_t isp_gdt; 68224804Smjacobstatic task_fn_t isp_gdt_task; 69164272Smjacobstatic timeout_t isp_ldt; 70224804Smjacobstatic task_fn_t isp_ldt_task; 7177365Smjacobstatic void isp_kthread(void *); 7249915Smjacobstatic void isp_action(struct cam_sim *, union ccb *); 73196008Smjacob#ifdef ISP_INTERNAL_TARGET 74196008Smjacobstatic void isp_target_thread_pi(void *); 75196008Smjacobstatic void isp_target_thread_fc(void *); 76161792Smjacob#endif 77239143Smjacobstatic int isp_timer_count; 78196008Smjacobstatic void isp_timer(void *); 7960220Smjacob 8077365Smjacobstatic struct cdevsw isp_cdevsw = { 81126080Sphk .d_version = D_VERSION, 82111815Sphk .d_ioctl = ispioctl, 83111815Sphk .d_name = "isp", 8477365Smjacob}; 8577365Smjacob 86196008Smjacobstatic int 87196008Smjacobisp_attach_chan(ispsoftc_t *isp, struct cam_devq *devq, int chan) 8839235Sgibbs{ 8939235Sgibbs struct ccb_setasync csa; 9046972Smjacob struct cam_sim *sim; 9146972Smjacob struct cam_path *path; 9239235Sgibbs 9339235Sgibbs /* 94196008Smjacob * Construct our SIM entry. 9539235Sgibbs */ 96196008Smjacob sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp, device_get_unit(isp->isp_dev), &isp->isp_osinfo.lock, isp->isp_maxcmds, isp->isp_maxcmds, devq); 9746972Smjacob 9846972Smjacob if (sim == NULL) { 99196008Smjacob return (ENOMEM); 10039235Sgibbs } 10162498Smjacob 102169530Smjacob ISP_LOCK(isp); 103196008Smjacob if (xpt_bus_register(sim, isp->isp_dev, chan) != CAM_SUCCESS) { 104196008Smjacob ISP_UNLOCK(isp); 105196008Smjacob cam_sim_free(sim, FALSE); 106196008Smjacob return (EIO); 10739235Sgibbs } 108196008Smjacob ISP_UNLOCK(isp); 109224856Smjacob if (xpt_create_path_unlocked(&path, NULL, cam_sim_path(sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 110196008Smjacob ISP_LOCK(isp); 11146972Smjacob xpt_bus_deregister(cam_sim_path(sim)); 112196008Smjacob ISP_UNLOCK(isp); 113196008Smjacob cam_sim_free(sim, FALSE); 114196008Smjacob return (ENXIO); 11539235Sgibbs } 11646972Smjacob xpt_setup_ccb(&csa.ccb_h, path, 5); 11739235Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 11839235Sgibbs csa.event_enable = AC_LOST_DEVICE; 11943420Smjacob csa.callback = isp_cam_async; 12046972Smjacob csa.callback_arg = sim; 121238869Smjacob 122238869Smjacob ISP_LOCK(isp); 12339235Sgibbs xpt_action((union ccb *)&csa); 124238869Smjacob ISP_UNLOCK(isp); 12539235Sgibbs 126196008Smjacob if (IS_SCSI(isp)) { 127196008Smjacob struct isp_spi *spi = ISP_SPI_PC(isp, chan); 128196008Smjacob spi->sim = sim; 129196008Smjacob spi->path = path; 130196008Smjacob#ifdef ISP_INTERNAL_TARGET 131196008Smjacob ISP_SET_PC(isp, chan, proc_active, 1); 132196008Smjacob if (THREAD_CREATE(isp_target_thread_pi, spi, &spi->target_proc, 0, 0, "%s: isp_test_tgt%d", device_get_nameunit(isp->isp_osinfo.dev), chan)) { 133196008Smjacob ISP_SET_PC(isp, chan, proc_active, 0); 134196008Smjacob isp_prt(isp, ISP_LOGERR, "cannot create test target thread"); 13546972Smjacob } 136196008Smjacob#endif 137196008Smjacob } else { 138200089Smjacob fcparam *fcp = FCPARAM(isp, chan); 139196008Smjacob struct isp_fc *fc = ISP_FC_PC(isp, chan); 14046972Smjacob 141200089Smjacob ISP_LOCK(isp); 142196008Smjacob fc->sim = sim; 143196008Smjacob fc->path = path; 144196008Smjacob fc->isp = isp; 145200089Smjacob fc->ready = 1; 146224804Smjacob 147196008Smjacob callout_init_mtx(&fc->ldt, &isp->isp_osinfo.lock, 0); 148196008Smjacob callout_init_mtx(&fc->gdt, &isp->isp_osinfo.lock, 0); 149224804Smjacob TASK_INIT(&fc->ltask, 1, isp_ldt_task, fc); 150224804Smjacob TASK_INIT(&fc->gtask, 1, isp_gdt_task, fc); 151208119Smjacob 152196008Smjacob /* 153196008Smjacob * We start by being "loop down" if we have an initiator role 154196008Smjacob */ 155200089Smjacob if (fcp->role & ISP_ROLE_INITIATOR) { 156196008Smjacob isp_freeze_loopdown(isp, chan, "isp_attach"); 157196008Smjacob callout_reset(&fc->ldt, isp_quickboot_time * hz, isp_ldt, fc); 158238869Smjacob isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "Starting Initial Loop Down Timer @ %lu", (unsigned long) time_uptime); 159196008Smjacob } 160196008Smjacob ISP_UNLOCK(isp); 161200089Smjacob if (THREAD_CREATE(isp_kthread, fc, &fc->kproc, 0, 0, "%s: fc_thrd%d", device_get_nameunit(isp->isp_osinfo.dev), chan)) { 162200089Smjacob xpt_free_path(fc->path); 163200089Smjacob ISP_LOCK(isp); 164238869Smjacob if (callout_active(&fc->ldt)) 165200089Smjacob callout_stop(&fc->ldt); 166200089Smjacob xpt_bus_deregister(cam_sim_path(fc->sim)); 167200089Smjacob ISP_UNLOCK(isp); 168200089Smjacob cam_sim_free(fc->sim, FALSE); 169200089Smjacob return (ENOMEM); 170200089Smjacob } 171196008Smjacob#ifdef ISP_INTERNAL_TARGET 172196008Smjacob ISP_SET_PC(isp, chan, proc_active, 1); 173196008Smjacob if (THREAD_CREATE(isp_target_thread_fc, fc, &fc->target_proc, 0, 0, "%s: isp_test_tgt%d", device_get_nameunit(isp->isp_osinfo.dev), chan)) { 174196008Smjacob ISP_SET_PC(isp, chan, proc_active, 0); 175196008Smjacob isp_prt(isp, ISP_LOGERR, "cannot create test target thread"); 176196008Smjacob } 177196008Smjacob#endif 178227126Smjacob if (chan == 0) { 179227126Smjacob struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(isp->isp_osinfo.dev); 180227126Smjacob struct sysctl_oid *tree = device_get_sysctl_tree(isp->isp_osinfo.dev); 181227126Smjacob SYSCTL_ADD_QUAD(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "wwnn", CTLFLAG_RD, &FCPARAM(isp, 0)->isp_wwnn, "World Wide Node Name"); 182227126Smjacob SYSCTL_ADD_QUAD(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "wwpn", CTLFLAG_RD, &FCPARAM(isp, 0)->isp_wwpn, "World Wide Port Name"); 183227126Smjacob SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "loop_down_limit", CTLFLAG_RW, &ISP_FC_PC(isp, 0)->loop_down_limit, 0, "Loop Down Limit"); 184227126Smjacob SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "gone_device_time", CTLFLAG_RW, &ISP_FC_PC(isp, 0)->gone_device_time, 0, "Gone Device Time"); 185238869Smjacob#if defined(ISP_TARGET_MODE) && defined(DEBUG) 186238869Smjacob SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "inject_lost_data_frame", CTLFLAG_RW, &ISP_FC_PC(isp, 0)->inject_lost_data_frame, 0, "Cause a Lost Frame on a Read"); 187238869Smjacob#endif 188227126Smjacob } 189196008Smjacob } 190196008Smjacob return (0); 191196008Smjacob} 19246972Smjacob 193196008Smjacobint 194196008Smjacobisp_attach(ispsoftc_t *isp) 195196008Smjacob{ 196196008Smjacob const char *nu = device_get_nameunit(isp->isp_osinfo.dev); 197196008Smjacob int du = device_get_unit(isp->isp_dev); 198196008Smjacob int chan; 199196008Smjacob 200196008Smjacob isp->isp_osinfo.ehook.ich_func = isp_intr_enable; 201196008Smjacob isp->isp_osinfo.ehook.ich_arg = isp; 202224856Smjacob /* 203224856Smjacob * Haha. Set this first, because if we're loaded as a module isp_intr_enable 204224856Smjacob * will be called right awawy, which will clear isp_osinfo.ehook_active, 205224856Smjacob * which would be unwise to then set again later. 206224856Smjacob */ 207224856Smjacob isp->isp_osinfo.ehook_active = 1; 208196008Smjacob if (config_intrhook_establish(&isp->isp_osinfo.ehook) != 0) { 209196008Smjacob isp_prt(isp, ISP_LOGERR, "could not establish interrupt enable hook"); 210196008Smjacob return (-EIO); 21146972Smjacob } 21277365Smjacob 21377365Smjacob /* 214196008Smjacob * Create the device queue for our SIM(s). 21577365Smjacob */ 216196008Smjacob isp->isp_osinfo.devq = cam_simq_alloc(isp->isp_maxcmds); 217196008Smjacob if (isp->isp_osinfo.devq == NULL) { 218196008Smjacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 219196008Smjacob return (EIO); 220196008Smjacob } 22177365Smjacob 222196008Smjacob for (chan = 0; chan < isp->isp_nchan; chan++) { 223196008Smjacob if (isp_attach_chan(isp, isp->isp_osinfo.devq, chan)) { 224196008Smjacob goto unwind; 225196008Smjacob } 22672347Smjacob } 227196008Smjacob 228196008Smjacob callout_init_mtx(&isp->isp_osinfo.tmo, &isp->isp_osinfo.lock, 0); 229239143Smjacob isp_timer_count = hz >> 2; 230239143Smjacob callout_reset(&isp->isp_osinfo.tmo, isp_timer_count, isp_timer, isp); 231196008Smjacob isp->isp_osinfo.timer_active = 1; 232196008Smjacob 233196008Smjacob isp->isp_osinfo.cdev = make_dev(&isp_cdevsw, du, UID_ROOT, GID_OPERATOR, 0600, "%s", nu); 234196008Smjacob if (isp->isp_osinfo.cdev) { 235196008Smjacob isp->isp_osinfo.cdev->si_drv1 = isp; 236196008Smjacob } 237196008Smjacob return (0); 238196008Smjacob 239196008Smjacobunwind: 240196008Smjacob while (--chan >= 0) { 241196008Smjacob struct cam_sim *sim; 242196008Smjacob struct cam_path *path; 243196008Smjacob if (IS_FC(isp)) { 244196008Smjacob sim = ISP_FC_PC(isp, chan)->sim; 245196008Smjacob path = ISP_FC_PC(isp, chan)->path; 246196008Smjacob } else { 247196008Smjacob sim = ISP_SPI_PC(isp, chan)->sim; 248196008Smjacob path = ISP_SPI_PC(isp, chan)->path; 24955371Smjacob } 250196008Smjacob xpt_free_path(path); 251196008Smjacob ISP_LOCK(isp); 252196008Smjacob xpt_bus_deregister(cam_sim_path(sim)); 253196008Smjacob ISP_UNLOCK(isp); 254196008Smjacob cam_sim_free(sim, FALSE); 25549915Smjacob } 256196008Smjacob if (isp->isp_osinfo.ehook_active) { 257196008Smjacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 258196008Smjacob isp->isp_osinfo.ehook_active = 0; 259196008Smjacob } 260196008Smjacob if (isp->isp_osinfo.cdev) { 261196008Smjacob destroy_dev(isp->isp_osinfo.cdev); 262196008Smjacob isp->isp_osinfo.cdev = NULL; 263196008Smjacob } 264196008Smjacob cam_simq_free(isp->isp_osinfo.devq); 265196008Smjacob isp->isp_osinfo.devq = NULL; 266196008Smjacob return (-1); 267196008Smjacob} 268169292Smjacob 269224856Smjacobint 270196008Smjacobisp_detach(ispsoftc_t *isp) 271196008Smjacob{ 272224856Smjacob struct cam_sim *sim; 273224856Smjacob struct cam_path *path; 274224856Smjacob struct ccb_setasync csa; 275196008Smjacob int chan; 276196008Smjacob 277196008Smjacob ISP_LOCK(isp); 278224856Smjacob for (chan = isp->isp_nchan - 1; chan >= 0; chan -= 1) { 279224856Smjacob if (IS_FC(isp)) { 280224856Smjacob sim = ISP_FC_PC(isp, chan)->sim; 281224856Smjacob path = ISP_FC_PC(isp, chan)->path; 282224856Smjacob } else { 283224856Smjacob sim = ISP_SPI_PC(isp, chan)->sim; 284224856Smjacob path = ISP_SPI_PC(isp, chan)->path; 285224856Smjacob } 286224856Smjacob if (sim->refcount > 2) { 287224856Smjacob ISP_UNLOCK(isp); 288224856Smjacob return (EBUSY); 289224856Smjacob } 290224856Smjacob } 291196008Smjacob if (isp->isp_osinfo.timer_active) { 292196008Smjacob callout_stop(&isp->isp_osinfo.tmo); 293196008Smjacob isp->isp_osinfo.timer_active = 0; 294196008Smjacob } 295196008Smjacob for (chan = isp->isp_nchan - 1; chan >= 0; chan -= 1) { 296196008Smjacob if (IS_FC(isp)) { 297196008Smjacob sim = ISP_FC_PC(isp, chan)->sim; 298196008Smjacob path = ISP_FC_PC(isp, chan)->path; 299196008Smjacob } else { 300196008Smjacob sim = ISP_SPI_PC(isp, chan)->sim; 301196008Smjacob path = ISP_SPI_PC(isp, chan)->path; 302169292Smjacob } 303224856Smjacob xpt_setup_ccb(&csa.ccb_h, path, 5); 304224856Smjacob csa.ccb_h.func_code = XPT_SASYNC_CB; 305224856Smjacob csa.event_enable = 0; 306224856Smjacob csa.callback = isp_cam_async; 307224856Smjacob csa.callback_arg = sim; 308238869Smjacob ISP_LOCK(isp); 309224856Smjacob xpt_action((union ccb *)&csa); 310238869Smjacob ISP_UNLOCK(isp); 311196008Smjacob xpt_free_path(path); 312196008Smjacob xpt_bus_deregister(cam_sim_path(sim)); 313196008Smjacob cam_sim_free(sim, FALSE); 314169292Smjacob } 315224856Smjacob ISP_UNLOCK(isp); 316196008Smjacob if (isp->isp_osinfo.cdev) { 317196008Smjacob destroy_dev(isp->isp_osinfo.cdev); 318196008Smjacob isp->isp_osinfo.cdev = NULL; 319196008Smjacob } 320196008Smjacob if (isp->isp_osinfo.ehook_active) { 321196008Smjacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 322196008Smjacob isp->isp_osinfo.ehook_active = 0; 323196008Smjacob } 324208761Smjacob if (isp->isp_osinfo.devq != NULL) { 325196008Smjacob cam_simq_free(isp->isp_osinfo.devq); 326196008Smjacob isp->isp_osinfo.devq = NULL; 327196008Smjacob } 328224856Smjacob return (0); 32939235Sgibbs} 33039235Sgibbs 331164272Smjacobstatic void 332196008Smjacobisp_freeze_loopdown(ispsoftc_t *isp, int chan, char *msg) 33399598Smjacob{ 334196008Smjacob if (IS_FC(isp)) { 335196008Smjacob struct isp_fc *fc = ISP_FC_PC(isp, chan); 336196008Smjacob if (fc->simqfrozen == 0) { 337196008Smjacob isp_prt(isp, ISP_LOGDEBUG0, "%s: freeze simq (loopdown) chan %d", msg, chan); 338196008Smjacob fc->simqfrozen = SIMQFRZ_LOOPDOWN; 339196008Smjacob xpt_freeze_simq(fc->sim, 1); 340196008Smjacob } else { 341196008Smjacob isp_prt(isp, ISP_LOGDEBUG0, "%s: mark frozen (loopdown) chan %d", msg, chan); 342196008Smjacob fc->simqfrozen |= SIMQFRZ_LOOPDOWN; 343196008Smjacob } 34499598Smjacob } 34599598Smjacob} 34699598Smjacob 347224856Smjacobstatic void 348224856Smjacobisp_unfreeze_loopdown(ispsoftc_t *isp, int chan) 349224856Smjacob{ 350224856Smjacob if (IS_FC(isp)) { 351224856Smjacob struct isp_fc *fc = ISP_FC_PC(isp, chan); 352224856Smjacob int wasfrozen = fc->simqfrozen & SIMQFRZ_LOOPDOWN; 353224856Smjacob fc->simqfrozen &= ~SIMQFRZ_LOOPDOWN; 354224856Smjacob if (wasfrozen && fc->simqfrozen == 0) { 355238869Smjacob isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "%s: Chan %d releasing simq", __func__, chan); 356224856Smjacob xpt_release_simq(fc->sim, 1); 357224856Smjacob } 358224856Smjacob } 359224856Smjacob} 360157943Smjacob 361224856Smjacob 36277365Smjacobstatic int 363196008Smjacobispioctl(struct cdev *dev, u_long c, caddr_t addr, int flags, struct thread *td) 36477365Smjacob{ 365157943Smjacob ispsoftc_t *isp; 366196008Smjacob int nr, chan, retval = ENOTTY; 36777365Smjacob 368196008Smjacob isp = dev->si_drv1; 369238869Smjacob 370156236Smjacob switch (c) { 37177365Smjacob case ISP_SDBLEV: 37277365Smjacob { 37377365Smjacob int olddblev = isp->isp_dblev; 37477365Smjacob isp->isp_dblev = *(int *)addr; 37577365Smjacob *(int *)addr = olddblev; 37677365Smjacob retval = 0; 37777365Smjacob break; 37877365Smjacob } 379125549Smjacob case ISP_GETROLE: 380196008Smjacob chan = *(int *)addr; 381196008Smjacob if (chan < 0 || chan >= isp->isp_nchan) { 382196008Smjacob retval = -ENXIO; 383196008Smjacob break; 384196008Smjacob } 385196008Smjacob if (IS_FC(isp)) { 386196008Smjacob *(int *)addr = FCPARAM(isp, chan)->role; 387196008Smjacob } else { 388196008Smjacob *(int *)addr = SDPARAM(isp, chan)->role; 389196008Smjacob } 390125549Smjacob retval = 0; 391125549Smjacob break; 392125549Smjacob case ISP_SETROLE: 393125549Smjacob nr = *(int *)addr; 394196008Smjacob chan = nr >> 8; 395196008Smjacob if (chan < 0 || chan >= isp->isp_nchan) { 396196008Smjacob retval = -ENXIO; 397196008Smjacob break; 398196008Smjacob } 399196008Smjacob nr &= 0xff; 400125549Smjacob if (nr & ~(ISP_ROLE_INITIATOR|ISP_ROLE_TARGET)) { 401125549Smjacob retval = EINVAL; 402125549Smjacob break; 403125549Smjacob } 404196008Smjacob if (IS_FC(isp)) { 405197214Smjacob /* 406197214Smjacob * We don't really support dual role at present on FC cards. 407197214Smjacob * 408197214Smjacob * We should, but a bunch of things are currently broken, 409197214Smjacob * so don't allow it. 410197214Smjacob */ 411197214Smjacob if (nr == ISP_ROLE_BOTH) { 412197214Smjacob isp_prt(isp, ISP_LOGERR, "cannot support dual role at present"); 413197214Smjacob retval = EINVAL; 414197214Smjacob break; 415197214Smjacob } 416196008Smjacob *(int *)addr = FCPARAM(isp, chan)->role; 417196008Smjacob#ifdef ISP_INTERNAL_TARGET 418196008Smjacob ISP_LOCK(isp); 419196008Smjacob retval = isp_fc_change_role(isp, chan, nr); 420196008Smjacob ISP_UNLOCK(isp); 421196008Smjacob#else 422196008Smjacob FCPARAM(isp, chan)->role = nr; 423196008Smjacob#endif 424196008Smjacob } else { 425196008Smjacob *(int *)addr = SDPARAM(isp, chan)->role; 426196008Smjacob SDPARAM(isp, chan)->role = nr; 427196008Smjacob } 428196008Smjacob retval = 0; 429196008Smjacob break; 430196008Smjacob 43177365Smjacob case ISP_RESETHBA: 432170570Smjacob ISP_LOCK(isp); 433196008Smjacob#ifdef ISP_TARGET_MODE 434196008Smjacob isp_del_all_wwn_entries(isp, ISP_NOCHAN); 435196008Smjacob#endif 436196008Smjacob isp_reinit(isp, 0); 437170570Smjacob ISP_UNLOCK(isp); 43877365Smjacob retval = 0; 43977365Smjacob break; 440196008Smjacob 44191036Smjacob case ISP_RESCAN: 44277365Smjacob if (IS_FC(isp)) { 443196008Smjacob chan = *(int *)addr; 444196008Smjacob if (chan < 0 || chan >= isp->isp_nchan) { 445196008Smjacob retval = -ENXIO; 446196008Smjacob break; 447196008Smjacob } 448170570Smjacob ISP_LOCK(isp); 449196008Smjacob if (isp_fc_runstate(isp, chan, 5 * 1000000)) { 45077365Smjacob retval = EIO; 45177365Smjacob } else { 45277365Smjacob retval = 0; 45377365Smjacob } 454170570Smjacob ISP_UNLOCK(isp); 45577365Smjacob } 45677365Smjacob break; 457196008Smjacob 45877365Smjacob case ISP_FC_LIP: 45977365Smjacob if (IS_FC(isp)) { 460196008Smjacob chan = *(int *)addr; 461196008Smjacob if (chan < 0 || chan >= isp->isp_nchan) { 462196008Smjacob retval = -ENXIO; 463196008Smjacob break; 464196008Smjacob } 465170570Smjacob ISP_LOCK(isp); 466196008Smjacob if (isp_control(isp, ISPCTL_SEND_LIP, chan)) { 46777365Smjacob retval = EIO; 46877365Smjacob } else { 46977365Smjacob retval = 0; 47077365Smjacob } 471170570Smjacob ISP_UNLOCK(isp); 47277365Smjacob } 47377365Smjacob break; 47477365Smjacob case ISP_FC_GETDINFO: 47577365Smjacob { 47677365Smjacob struct isp_fc_device *ifc = (struct isp_fc_device *) addr; 477163899Smjacob fcportdb_t *lp; 47877365Smjacob 479160250Smjacob if (IS_SCSI(isp)) { 480160250Smjacob break; 481160250Smjacob } 482171337Smjacob if (ifc->loopid >= MAX_FC_TARG) { 48377365Smjacob retval = EINVAL; 48477365Smjacob break; 48577365Smjacob } 486196008Smjacob lp = &FCPARAM(isp, ifc->chan)->portdb[ifc->loopid]; 487196008Smjacob if (lp->state == FC_PORTDB_STATE_VALID || lp->target_mode) { 488238869Smjacob ifc->role = (lp->prli_word3 & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT; 489163899Smjacob ifc->loopid = lp->handle; 49077365Smjacob ifc->portid = lp->portid; 49177365Smjacob ifc->node_wwn = lp->node_wwn; 49277365Smjacob ifc->port_wwn = lp->port_wwn; 49377365Smjacob retval = 0; 49477365Smjacob } else { 49577365Smjacob retval = ENODEV; 49677365Smjacob } 49777365Smjacob break; 49877365Smjacob } 49988855Smjacob case ISP_GET_STATS: 50088855Smjacob { 50188855Smjacob isp_stats_t *sp = (isp_stats_t *) addr; 50288855Smjacob 503196008Smjacob ISP_MEMZERO(sp, sizeof (*sp)); 50488855Smjacob sp->isp_stat_version = ISP_STATS_VERSION; 50588855Smjacob sp->isp_type = isp->isp_type; 50688855Smjacob sp->isp_revision = isp->isp_revision; 507170570Smjacob ISP_LOCK(isp); 50888855Smjacob sp->isp_stats[ISP_INTCNT] = isp->isp_intcnt; 50988855Smjacob sp->isp_stats[ISP_INTBOGUS] = isp->isp_intbogus; 51088855Smjacob sp->isp_stats[ISP_INTMBOXC] = isp->isp_intmboxc; 51188855Smjacob sp->isp_stats[ISP_INGOASYNC] = isp->isp_intoasync; 51288855Smjacob sp->isp_stats[ISP_RSLTCCMPLT] = isp->isp_rsltccmplt; 51388855Smjacob sp->isp_stats[ISP_FPHCCMCPLT] = isp->isp_fphccmplt; 51488855Smjacob sp->isp_stats[ISP_RSCCHIWAT] = isp->isp_rscchiwater; 51588855Smjacob sp->isp_stats[ISP_FPCCHIWAT] = isp->isp_fpcchiwater; 516170570Smjacob ISP_UNLOCK(isp); 51788855Smjacob retval = 0; 51888855Smjacob break; 51988855Smjacob } 52088855Smjacob case ISP_CLR_STATS: 521170570Smjacob ISP_LOCK(isp); 52288855Smjacob isp->isp_intcnt = 0; 52388855Smjacob isp->isp_intbogus = 0; 52488855Smjacob isp->isp_intmboxc = 0; 52588855Smjacob isp->isp_intoasync = 0; 52688855Smjacob isp->isp_rsltccmplt = 0; 52788855Smjacob isp->isp_fphccmplt = 0; 52888855Smjacob isp->isp_rscchiwater = 0; 52988855Smjacob isp->isp_fpcchiwater = 0; 530170570Smjacob ISP_UNLOCK(isp); 53188855Smjacob retval = 0; 53288855Smjacob break; 53398289Smjacob case ISP_FC_GETHINFO: 53498289Smjacob { 53598289Smjacob struct isp_hba_device *hba = (struct isp_hba_device *) addr; 536196008Smjacob int chan = hba->fc_channel; 537160250Smjacob 538196008Smjacob if (chan < 0 || chan >= isp->isp_nchan) { 539196008Smjacob retval = ENXIO; 540196008Smjacob break; 541196008Smjacob } 542124892Smjacob hba->fc_fw_major = ISP_FW_MAJORX(isp->isp_fwrev); 543124892Smjacob hba->fc_fw_minor = ISP_FW_MINORX(isp->isp_fwrev); 544124892Smjacob hba->fc_fw_micro = ISP_FW_MICROX(isp->isp_fwrev); 545196008Smjacob hba->fc_nchannels = isp->isp_nchan; 546160250Smjacob if (IS_FC(isp)) { 547196008Smjacob hba->fc_nports = MAX_FC_TARG; 548196008Smjacob hba->fc_speed = FCPARAM(isp, hba->fc_channel)->isp_gbspeed; 549196008Smjacob hba->fc_topology = FCPARAM(isp, chan)->isp_topo + 1; 550196008Smjacob hba->fc_loopid = FCPARAM(isp, chan)->isp_loopid; 551196008Smjacob hba->nvram_node_wwn = FCPARAM(isp, chan)->isp_wwnn_nvram; 552196008Smjacob hba->nvram_port_wwn = FCPARAM(isp, chan)->isp_wwpn_nvram; 553196008Smjacob hba->active_node_wwn = FCPARAM(isp, chan)->isp_wwnn; 554196008Smjacob hba->active_port_wwn = FCPARAM(isp, chan)->isp_wwpn; 555196008Smjacob } else { 556196008Smjacob hba->fc_nports = MAX_TARGETS; 557196008Smjacob hba->fc_speed = 0; 558196008Smjacob hba->fc_topology = 0; 559196008Smjacob hba->nvram_node_wwn = 0ull; 560196008Smjacob hba->nvram_port_wwn = 0ull; 561196008Smjacob hba->active_node_wwn = 0ull; 562196008Smjacob hba->active_port_wwn = 0ull; 563160250Smjacob } 56498289Smjacob retval = 0; 56598289Smjacob break; 56698289Smjacob } 567151834Smjacob case ISP_TSK_MGMT: 568151834Smjacob { 569151834Smjacob int needmarker; 570151834Smjacob struct isp_fc_tsk_mgmt *fct = (struct isp_fc_tsk_mgmt *) addr; 571155704Smjacob uint16_t loopid; 572151834Smjacob mbreg_t mbs; 573151834Smjacob 574151834Smjacob if (IS_SCSI(isp)) { 575151834Smjacob break; 576151834Smjacob } 577151834Smjacob 578196008Smjacob chan = fct->chan; 579196008Smjacob if (chan < 0 || chan >= isp->isp_nchan) { 580196008Smjacob retval = -ENXIO; 581196008Smjacob break; 582196008Smjacob } 583196008Smjacob 584151834Smjacob needmarker = retval = 0; 585154704Smjacob loopid = fct->loopid; 586196008Smjacob ISP_LOCK(isp); 587196008Smjacob if (IS_24XX(isp)) { 588196008Smjacob uint8_t local[QENTRY_LEN]; 589196008Smjacob isp24xx_tmf_t *tmf; 590196008Smjacob isp24xx_statusreq_t *sp; 591196008Smjacob fcparam *fcp = FCPARAM(isp, chan); 592196008Smjacob fcportdb_t *lp; 593196008Smjacob int i; 594196008Smjacob 595196008Smjacob for (i = 0; i < MAX_FC_TARG; i++) { 596196008Smjacob lp = &fcp->portdb[i]; 597196008Smjacob if (lp->handle == loopid) { 598196008Smjacob break; 599196008Smjacob } 600151834Smjacob } 601196008Smjacob if (i == MAX_FC_TARG) { 602196008Smjacob retval = ENXIO; 603196008Smjacob ISP_UNLOCK(isp); 604196008Smjacob break; 605196008Smjacob } 606196008Smjacob /* XXX VALIDATE LP XXX */ 607196008Smjacob tmf = (isp24xx_tmf_t *) local; 608196008Smjacob ISP_MEMZERO(tmf, QENTRY_LEN); 609196008Smjacob tmf->tmf_header.rqs_entry_type = RQSTYPE_TSK_MGMT; 610196008Smjacob tmf->tmf_header.rqs_entry_count = 1; 611196008Smjacob tmf->tmf_nphdl = lp->handle; 612196008Smjacob tmf->tmf_delay = 2; 613196008Smjacob tmf->tmf_timeout = 2; 614196008Smjacob tmf->tmf_tidlo = lp->portid; 615196008Smjacob tmf->tmf_tidhi = lp->portid >> 16; 616196008Smjacob tmf->tmf_vpidx = ISP_GET_VPIDX(isp, chan); 617196008Smjacob tmf->tmf_lun[1] = fct->lun & 0xff; 618196008Smjacob if (fct->lun >= 256) { 619196008Smjacob tmf->tmf_lun[0] = 0x40 | (fct->lun >> 8); 620196008Smjacob } 621196008Smjacob switch (fct->action) { 622196008Smjacob case IPT_CLEAR_ACA: 623196008Smjacob tmf->tmf_flags = ISP24XX_TMF_CLEAR_ACA; 624196008Smjacob break; 625196008Smjacob case IPT_TARGET_RESET: 626196008Smjacob tmf->tmf_flags = ISP24XX_TMF_TARGET_RESET; 627196008Smjacob needmarker = 1; 628196008Smjacob break; 629196008Smjacob case IPT_LUN_RESET: 630196008Smjacob tmf->tmf_flags = ISP24XX_TMF_LUN_RESET; 631196008Smjacob needmarker = 1; 632196008Smjacob break; 633196008Smjacob case IPT_CLEAR_TASK_SET: 634196008Smjacob tmf->tmf_flags = ISP24XX_TMF_CLEAR_TASK_SET; 635196008Smjacob needmarker = 1; 636196008Smjacob break; 637196008Smjacob case IPT_ABORT_TASK_SET: 638196008Smjacob tmf->tmf_flags = ISP24XX_TMF_ABORT_TASK_SET; 639196008Smjacob needmarker = 1; 640196008Smjacob break; 641196008Smjacob default: 642196008Smjacob retval = EINVAL; 643196008Smjacob break; 644196008Smjacob } 645196008Smjacob if (retval) { 646196008Smjacob ISP_UNLOCK(isp); 647196008Smjacob break; 648196008Smjacob } 649196008Smjacob MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 5000000); 650196008Smjacob mbs.param[1] = QENTRY_LEN; 651196008Smjacob mbs.param[2] = DMA_WD1(fcp->isp_scdma); 652196008Smjacob mbs.param[3] = DMA_WD0(fcp->isp_scdma); 653196008Smjacob mbs.param[6] = DMA_WD3(fcp->isp_scdma); 654196008Smjacob mbs.param[7] = DMA_WD2(fcp->isp_scdma); 655196008Smjacob 656196008Smjacob if (FC_SCRATCH_ACQUIRE(isp, chan)) { 657196008Smjacob ISP_UNLOCK(isp); 658196008Smjacob retval = ENOMEM; 659196008Smjacob break; 660196008Smjacob } 661196008Smjacob isp_put_24xx_tmf(isp, tmf, fcp->isp_scratch); 662218691Smarius MEMORYBARRIER(isp, SYNC_SFORDEV, 0, QENTRY_LEN, chan); 663196008Smjacob sp = (isp24xx_statusreq_t *) local; 664196008Smjacob sp->req_completion_status = 1; 665151834Smjacob retval = isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); 666218691Smarius MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN, chan); 667196008Smjacob isp_get_24xx_response(isp, &((isp24xx_statusreq_t *)fcp->isp_scratch)[1], sp); 668196008Smjacob FC_SCRATCH_RELEASE(isp, chan); 669196008Smjacob if (retval || sp->req_completion_status != 0) { 670196008Smjacob FC_SCRATCH_RELEASE(isp, chan); 671151834Smjacob retval = EIO; 672196008Smjacob } 673196008Smjacob if (retval == 0) { 674196008Smjacob if (needmarker) { 675196008Smjacob fcp->sendmarker = 1; 676196008Smjacob } 677196008Smjacob } 678196008Smjacob } else { 679196008Smjacob MBSINIT(&mbs, 0, MBLOGALL, 0); 680196008Smjacob if (ISP_CAP_2KLOGIN(isp) == 0) { 681196008Smjacob loopid <<= 8; 682196008Smjacob } 683196008Smjacob switch (fct->action) { 684196008Smjacob case IPT_CLEAR_ACA: 685196008Smjacob mbs.param[0] = MBOX_CLEAR_ACA; 686196008Smjacob mbs.param[1] = loopid; 687196008Smjacob mbs.param[2] = fct->lun; 688196008Smjacob break; 689196008Smjacob case IPT_TARGET_RESET: 690196008Smjacob mbs.param[0] = MBOX_TARGET_RESET; 691196008Smjacob mbs.param[1] = loopid; 692196008Smjacob needmarker = 1; 693196008Smjacob break; 694196008Smjacob case IPT_LUN_RESET: 695196008Smjacob mbs.param[0] = MBOX_LUN_RESET; 696196008Smjacob mbs.param[1] = loopid; 697196008Smjacob mbs.param[2] = fct->lun; 698196008Smjacob needmarker = 1; 699196008Smjacob break; 700196008Smjacob case IPT_CLEAR_TASK_SET: 701196008Smjacob mbs.param[0] = MBOX_CLEAR_TASK_SET; 702196008Smjacob mbs.param[1] = loopid; 703196008Smjacob mbs.param[2] = fct->lun; 704196008Smjacob needmarker = 1; 705196008Smjacob break; 706196008Smjacob case IPT_ABORT_TASK_SET: 707196008Smjacob mbs.param[0] = MBOX_ABORT_TASK_SET; 708196008Smjacob mbs.param[1] = loopid; 709196008Smjacob mbs.param[2] = fct->lun; 710196008Smjacob needmarker = 1; 711196008Smjacob break; 712196008Smjacob default: 713196008Smjacob retval = EINVAL; 714196008Smjacob break; 715196008Smjacob } 716196008Smjacob if (retval == 0) { 717196008Smjacob if (needmarker) { 718196008Smjacob FCPARAM(isp, chan)->sendmarker = 1; 719196008Smjacob } 720196008Smjacob retval = isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); 721196008Smjacob if (retval) { 722196008Smjacob retval = EIO; 723196008Smjacob } 724196008Smjacob } 725151834Smjacob } 726196008Smjacob ISP_UNLOCK(isp); 727151834Smjacob break; 728151834Smjacob } 72977365Smjacob default: 73077365Smjacob break; 73177365Smjacob } 73277365Smjacob return (retval); 73377365Smjacob} 73477365Smjacob 73562498Smjacobstatic void 73662498Smjacobisp_intr_enable(void *arg) 73762498Smjacob{ 738196008Smjacob int chan; 739157943Smjacob ispsoftc_t *isp = arg; 740169292Smjacob ISP_LOCK(isp); 741196008Smjacob for (chan = 0; chan < isp->isp_nchan; chan++) { 742196008Smjacob if (IS_FC(isp)) { 743196008Smjacob if (FCPARAM(isp, chan)->role != ISP_ROLE_NONE) { 744196008Smjacob ISP_ENABLE_INTS(isp); 745196008Smjacob break; 746196008Smjacob } 747196008Smjacob } else { 748196008Smjacob if (SDPARAM(isp, chan)->role != ISP_ROLE_NONE) { 749196008Smjacob ISP_ENABLE_INTS(isp); 750196008Smjacob break; 751196008Smjacob } 752196008Smjacob } 75372347Smjacob } 754224856Smjacob isp->isp_osinfo.ehook_active = 0; 755169292Smjacob ISP_UNLOCK(isp); 75662498Smjacob /* Release our hook so that the boot can continue. */ 75762498Smjacob config_intrhook_disestablish(&isp->isp_osinfo.ehook); 75862498Smjacob} 75955371Smjacob 76055371Smjacob/* 761196008Smjacob * Local Inlines 762196008Smjacob */ 763196008Smjacob 764196008Smjacobstatic ISP_INLINE int isp_get_pcmd(ispsoftc_t *, union ccb *); 765196008Smjacobstatic ISP_INLINE void isp_free_pcmd(ispsoftc_t *, union ccb *); 766196008Smjacob 767196008Smjacobstatic ISP_INLINE int 768196008Smjacobisp_get_pcmd(ispsoftc_t *isp, union ccb *ccb) 769196008Smjacob{ 770196008Smjacob ISP_PCMD(ccb) = isp->isp_osinfo.pcmd_free; 771196008Smjacob if (ISP_PCMD(ccb) == NULL) { 772196008Smjacob return (-1); 773196008Smjacob } 774196008Smjacob isp->isp_osinfo.pcmd_free = ((struct isp_pcmd *)ISP_PCMD(ccb))->next; 775196008Smjacob return (0); 776196008Smjacob} 777196008Smjacob 778196008Smjacobstatic ISP_INLINE void 779196008Smjacobisp_free_pcmd(ispsoftc_t *isp, union ccb *ccb) 780196008Smjacob{ 781238869Smjacob if (ISP_PCMD(ccb)) { 782239218Smjacob#ifdef ISP_TARGET_MODE 783239218Smjacob PISP_PCMD(ccb)->datalen = 0; 784239218Smjacob PISP_PCMD(ccb)->totslen = 0; 785239218Smjacob PISP_PCMD(ccb)->cumslen = 0; 786239218Smjacob PISP_PCMD(ccb)->crn = 0; 787239218Smjacob#endif 788239218Smjacob PISP_PCMD(ccb)->next = isp->isp_osinfo.pcmd_free; 789238869Smjacob isp->isp_osinfo.pcmd_free = ISP_PCMD(ccb); 790238869Smjacob ISP_PCMD(ccb) = NULL; 791238869Smjacob } 792196008Smjacob} 793238869Smjacob 794196008Smjacob/* 79555371Smjacob * Put the target mode functions here, because some are inlines 79655371Smjacob */ 79755371Smjacob#ifdef ISP_TARGET_MODE 798236427Smjacobstatic ISP_INLINE void isp_tmlock(ispsoftc_t *, const char *); 799236427Smjacobstatic ISP_INLINE void isp_tmunlk(ispsoftc_t *); 800236427Smjacobstatic ISP_INLINE int is_any_lun_enabled(ispsoftc_t *, int); 801196008Smjacobstatic ISP_INLINE int is_lun_enabled(ispsoftc_t *, int, lun_id_t); 802196008Smjacobstatic ISP_INLINE tstate_t *get_lun_statep(ispsoftc_t *, int, lun_id_t); 803196008Smjacobstatic ISP_INLINE tstate_t *get_lun_statep_from_tag(ispsoftc_t *, int, uint32_t); 804196008Smjacobstatic ISP_INLINE void rls_lun_statep(ispsoftc_t *, tstate_t *); 805196008Smjacobstatic ISP_INLINE inot_private_data_t *get_ntp_from_tagdata(ispsoftc_t *, uint32_t, uint32_t, tstate_t **); 806196008Smjacobstatic ISP_INLINE atio_private_data_t *isp_get_atpd(ispsoftc_t *, tstate_t *, uint32_t); 807196008Smjacobstatic ISP_INLINE void isp_put_atpd(ispsoftc_t *, tstate_t *, atio_private_data_t *); 808196008Smjacobstatic ISP_INLINE inot_private_data_t *isp_get_ntpd(ispsoftc_t *, tstate_t *); 809196008Smjacobstatic ISP_INLINE inot_private_data_t *isp_find_ntpd(ispsoftc_t *, tstate_t *, uint32_t, uint32_t); 810196008Smjacobstatic ISP_INLINE void isp_put_ntpd(ispsoftc_t *, tstate_t *, inot_private_data_t *); 811196008Smjacobstatic cam_status create_lun_state(ispsoftc_t *, int, struct cam_path *, tstate_t **); 812157943Smjacobstatic void destroy_lun_state(ispsoftc_t *, tstate_t *); 813196008Smjacobstatic void isp_enable_lun(ispsoftc_t *, union ccb *); 814236427Smjacobstatic cam_status isp_enable_deferred_luns(ispsoftc_t *, int); 815196008Smjacobstatic cam_status isp_enable_deferred(ispsoftc_t *, int, lun_id_t); 816196008Smjacobstatic void isp_disable_lun(ispsoftc_t *, union ccb *); 817196008Smjacobstatic int isp_enable_target_mode(ispsoftc_t *, int); 818236427Smjacobstatic int isp_disable_target_mode(ispsoftc_t *, int); 819157943Smjacobstatic void isp_ledone(ispsoftc_t *, lun_entry_t *); 82075200Smjacobstatic timeout_t isp_refire_putback_atio; 821238869Smjacobstatic timeout_t isp_refire_notify_ack; 82275200Smjacobstatic void isp_complete_ctio(union ccb *); 82375200Smjacobstatic void isp_target_putback_atio(union ccb *); 824239143Smjacobenum Start_Ctio_How { FROM_CAM, FROM_TIMER, FROM_SRR, FROM_CTIO_DONE }; 825238869Smjacobstatic void isp_target_start_ctio(ispsoftc_t *, union ccb *, enum Start_Ctio_How); 826196008Smjacobstatic void isp_handle_platform_atio(ispsoftc_t *, at_entry_t *); 827196008Smjacobstatic void isp_handle_platform_atio2(ispsoftc_t *, at2_entry_t *); 828196008Smjacobstatic void isp_handle_platform_atio7(ispsoftc_t *, at7_entry_t *); 829196008Smjacobstatic void isp_handle_platform_ctio(ispsoftc_t *, void *); 830196008Smjacobstatic void isp_handle_platform_notify_scsi(ispsoftc_t *, in_entry_t *); 831196008Smjacobstatic void isp_handle_platform_notify_fc(ispsoftc_t *, in_fcentry_t *); 832196008Smjacobstatic void isp_handle_platform_notify_24xx(ispsoftc_t *, in_fcentry_24xx_t *); 833196008Smjacobstatic int isp_handle_platform_target_notify_ack(ispsoftc_t *, isp_notify_t *); 834196008Smjacobstatic void isp_handle_platform_target_tmf(ispsoftc_t *, isp_notify_t *); 835196008Smjacobstatic void isp_target_mark_aborted(ispsoftc_t *, union ccb *); 836196008Smjacobstatic void isp_target_mark_aborted_early(ispsoftc_t *, tstate_t *, uint32_t); 83755371Smjacob 838236427Smjacobstatic ISP_INLINE void 839236427Smjacobisp_tmlock(ispsoftc_t *isp, const char *msg) 840236427Smjacob{ 841236427Smjacob while (isp->isp_osinfo.tmbusy) { 842236427Smjacob isp->isp_osinfo.tmwanted = 1; 843236427Smjacob mtx_sleep(isp, &isp->isp_lock, PRIBIO, msg, 0); 844236427Smjacob } 845236427Smjacob isp->isp_osinfo.tmbusy = 1; 846236427Smjacob} 847236427Smjacob 848236427Smjacobstatic ISP_INLINE void 849236427Smjacobisp_tmunlk(ispsoftc_t *isp) 850236427Smjacob{ 851236427Smjacob isp->isp_osinfo.tmbusy = 0; 852236427Smjacob if (isp->isp_osinfo.tmwanted) { 853236427Smjacob isp->isp_osinfo.tmwanted = 0; 854236427Smjacob wakeup(isp); 855236427Smjacob } 856236427Smjacob} 857236427Smjacob 858196008Smjacobstatic ISP_INLINE int 859236427Smjacobis_any_lun_enabled(ispsoftc_t *isp, int bus) 860236427Smjacob{ 861236427Smjacob struct tslist *lhp; 862236427Smjacob int i; 863236427Smjacob 864236427Smjacob for (i = 0; i < LUN_HASH_SIZE; i++) { 865236427Smjacob ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp); 866236427Smjacob if (SLIST_FIRST(lhp)) 867236427Smjacob return (1); 868236427Smjacob } 869236427Smjacob return (0); 870236427Smjacob} 871236427Smjacob 872236427Smjacobstatic ISP_INLINE int 873157943Smjacobis_lun_enabled(ispsoftc_t *isp, int bus, lun_id_t lun) 87455371Smjacob{ 87555371Smjacob tstate_t *tptr; 876196008Smjacob struct tslist *lhp; 877196008Smjacob 878196008Smjacob ISP_GET_PC_ADDR(isp, bus, lun_hash[LUN_HASH_FUNC(lun)], lhp); 879196008Smjacob SLIST_FOREACH(tptr, lhp, next) { 880196008Smjacob if (xpt_path_lun_id(tptr->owner) == lun) { 88155371Smjacob return (1); 88255371Smjacob } 883196008Smjacob } 88455371Smjacob return (0); 88555371Smjacob} 88655371Smjacob 887196008Smjacobstatic void 888196008Smjacobdump_tstates(ispsoftc_t *isp, int bus) 88955371Smjacob{ 890196008Smjacob int i, j; 891196008Smjacob struct tslist *lhp; 892196008Smjacob tstate_t *tptr = NULL; 893196008Smjacob 894196008Smjacob if (bus >= isp->isp_nchan) { 895196008Smjacob return; 89675200Smjacob } 897196008Smjacob for (i = 0; i < LUN_HASH_SIZE; i++) { 898196008Smjacob ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp); 899196008Smjacob j = 0; 900196008Smjacob SLIST_FOREACH(tptr, lhp, next) { 901196008Smjacob xpt_print(tptr->owner, "[%d, %d] atio_cnt=%d inot_cnt=%d\n", i, j, tptr->atio_count, tptr->inot_count); 902196008Smjacob j++; 90355371Smjacob } 90455371Smjacob } 90555371Smjacob} 90655371Smjacob 907196008Smjacobstatic ISP_INLINE tstate_t * 908157943Smjacobget_lun_statep(ispsoftc_t *isp, int bus, lun_id_t lun) 90955371Smjacob{ 91083028Smjacob tstate_t *tptr = NULL; 911196008Smjacob struct tslist *lhp; 912196008Smjacob int i; 91355371Smjacob 914196008Smjacob if (bus < isp->isp_nchan) { 915196008Smjacob for (i = 0; i < LUN_HASH_SIZE; i++) { 916196008Smjacob ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp); 917196008Smjacob SLIST_FOREACH(tptr, lhp, next) { 918196008Smjacob if (xpt_path_lun_id(tptr->owner) == lun) { 919196008Smjacob tptr->hold++; 920196008Smjacob return (tptr); 921196008Smjacob } 922196008Smjacob } 92382689Smjacob } 924196008Smjacob } 925196008Smjacob return (NULL); 926196008Smjacob} 927196008Smjacob 928196008Smjacobstatic ISP_INLINE tstate_t * 929196008Smjacobget_lun_statep_from_tag(ispsoftc_t *isp, int bus, uint32_t tagval) 930196008Smjacob{ 931196008Smjacob tstate_t *tptr = NULL; 932196008Smjacob atio_private_data_t *atp; 933196008Smjacob struct tslist *lhp; 934196008Smjacob int i; 935196008Smjacob 936196008Smjacob if (bus < isp->isp_nchan && tagval != 0) { 937196008Smjacob for (i = 0; i < LUN_HASH_SIZE; i++) { 938196008Smjacob ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp); 939196008Smjacob SLIST_FOREACH(tptr, lhp, next) { 940196008Smjacob atp = isp_get_atpd(isp, tptr, tagval); 941196008Smjacob if (atp && atp->tag == tagval) { 942196008Smjacob tptr->hold++; 943196008Smjacob return (tptr); 944196008Smjacob } 945196008Smjacob } 94683028Smjacob } 94755371Smjacob } 948196008Smjacob return (NULL); 949196008Smjacob} 95055371Smjacob 951196008Smjacobstatic ISP_INLINE inot_private_data_t * 952196008Smjacobget_ntp_from_tagdata(ispsoftc_t *isp, uint32_t tag_id, uint32_t seq_id, tstate_t **rslt) 953196008Smjacob{ 954196008Smjacob inot_private_data_t *ntp; 955196008Smjacob tstate_t *tptr; 956196008Smjacob struct tslist *lhp; 957196008Smjacob int bus, i; 958196008Smjacob 959196008Smjacob for (bus = 0; bus < isp->isp_nchan; bus++) { 960196008Smjacob for (i = 0; i < LUN_HASH_SIZE; i++) { 961196008Smjacob ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp); 962196008Smjacob SLIST_FOREACH(tptr, lhp, next) { 963196008Smjacob ntp = isp_find_ntpd(isp, tptr, tag_id, seq_id); 964196008Smjacob if (ntp) { 965196008Smjacob *rslt = tptr; 966196008Smjacob tptr->hold++; 967196008Smjacob return (ntp); 968196008Smjacob } 969196008Smjacob } 97055371Smjacob } 971196008Smjacob } 972196008Smjacob return (NULL); 97355371Smjacob} 974236427Smjacob 975196008Smjacobstatic ISP_INLINE void 976157943Smjacobrls_lun_statep(ispsoftc_t *isp, tstate_t *tptr) 97755371Smjacob{ 978196008Smjacob KASSERT((tptr->hold), ("tptr not held")); 979196008Smjacob tptr->hold--; 98055371Smjacob} 98155371Smjacob 982196008Smjacobstatic void 983196008Smjacobisp_tmcmd_restart(ispsoftc_t *isp) 98484242Smjacob{ 985196008Smjacob inot_private_data_t *ntp; 986239143Smjacob inot_private_data_t *restart_queue; 987196008Smjacob tstate_t *tptr; 988239143Smjacob union ccb *ccb; 989196008Smjacob struct tslist *lhp; 990196008Smjacob int bus, i; 991196008Smjacob 992196008Smjacob for (bus = 0; bus < isp->isp_nchan; bus++) { 993196008Smjacob for (i = 0; i < LUN_HASH_SIZE; i++) { 994196008Smjacob ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp); 995196008Smjacob SLIST_FOREACH(tptr, lhp, next) { 996239143Smjacob if ((restart_queue = tptr->restart_queue) != NULL) 997239143Smjacob tptr->restart_queue = NULL; 998196008Smjacob while (restart_queue) { 999196008Smjacob ntp = restart_queue; 1000196008Smjacob restart_queue = ntp->rd.nt.nt_hba; 1001196008Smjacob if (IS_24XX(isp)) { 1002196008Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: restarting resrc deprived %x", __func__, ((at7_entry_t *)ntp->rd.data)->at_rxid); 1003196008Smjacob isp_handle_platform_atio7(isp, (at7_entry_t *) ntp->rd.data); 1004196008Smjacob } else { 1005196008Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: restarting resrc deprived %x", __func__, ((at2_entry_t *)ntp->rd.data)->at_rxid); 1006196008Smjacob isp_handle_platform_atio2(isp, (at2_entry_t *) ntp->rd.data); 1007196008Smjacob } 1008196008Smjacob isp_put_ntpd(isp, tptr, ntp); 1009196008Smjacob if (tptr->restart_queue && restart_queue != NULL) { 1010196008Smjacob ntp = tptr->restart_queue; 1011196008Smjacob tptr->restart_queue = restart_queue; 1012196008Smjacob while (restart_queue->rd.nt.nt_hba) { 1013196008Smjacob restart_queue = restart_queue->rd.nt.nt_hba; 1014196008Smjacob } 1015196008Smjacob restart_queue->rd.nt.nt_hba = ntp; 1016196008Smjacob break; 1017196008Smjacob } 1018196008Smjacob } 1019239143Smjacob /* 1020239143Smjacob * We only need to do this once per tptr 1021239143Smjacob */ 1022239143Smjacob if (!TAILQ_EMPTY(&tptr->waitq)) { 1023239143Smjacob ccb = (union ccb *)TAILQ_LAST(&tptr->waitq, isp_ccbq); 1024239143Smjacob TAILQ_REMOVE(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); 1025239143Smjacob isp_target_start_ctio(isp, ccb, FROM_TIMER); 1026239143Smjacob } 1027196008Smjacob } 1028196008Smjacob } 1029196008Smjacob } 1030196008Smjacob} 1031196008Smjacob 1032196008Smjacobstatic ISP_INLINE atio_private_data_t * 1033196008Smjacobisp_get_atpd(ispsoftc_t *isp, tstate_t *tptr, uint32_t tag) 1034196008Smjacob{ 103584242Smjacob atio_private_data_t *atp; 1036196008Smjacob 1037196008Smjacob if (tag == 0) { 1038196008Smjacob atp = tptr->atfree; 1039196008Smjacob if (atp) { 1040196008Smjacob tptr->atfree = atp->next; 1041196008Smjacob } 1042196008Smjacob return (atp); 1043196008Smjacob } 1044196008Smjacob for (atp = tptr->atpool; atp < &tptr->atpool[ATPDPSIZE]; atp++) { 1045196008Smjacob if (atp->tag == tag) { 104684242Smjacob return (atp); 1047196008Smjacob } 104884242Smjacob } 104984242Smjacob return (NULL); 105084242Smjacob} 105184242Smjacob 1052196008Smjacobstatic ISP_INLINE void 1053196008Smjacobisp_put_atpd(ispsoftc_t *isp, tstate_t *tptr, atio_private_data_t *atp) 1054196008Smjacob{ 1055238869Smjacob if (atp->ests) { 1056238869Smjacob isp_put_ecmd(isp, atp->ests); 1057238869Smjacob } 1058238869Smjacob memset(atp, 0, sizeof (*atp)); 1059196008Smjacob atp->next = tptr->atfree; 1060196008Smjacob tptr->atfree = atp; 1061196008Smjacob} 1062196008Smjacob 1063196008Smjacobstatic void 1064196008Smjacobisp_dump_atpd(ispsoftc_t *isp, tstate_t *tptr) 1065196008Smjacob{ 1066196008Smjacob atio_private_data_t *atp; 1067196008Smjacob const char *states[8] = { "Free", "ATIO", "CAM", "CTIO", "LAST_CTIO", "PDON", "?6", "7" }; 1068196008Smjacob 1069196008Smjacob for (atp = tptr->atpool; atp < &tptr->atpool[ATPDPSIZE]; atp++) { 1070196008Smjacob if (atp->tag == 0) { 1071196008Smjacob continue; 1072196008Smjacob } 1073239143Smjacob xpt_print(tptr->owner, "ATP: [0x%x] origdlen %u bytes_xfrd %u lun %u nphdl 0x%04x s_id 0x%06x d_id 0x%06x oxid 0x%04x state %s\n", 1074239143Smjacob atp->tag, atp->orig_datalen, atp->bytes_xfered, atp->lun, atp->nphdl, atp->sid, atp->portid, atp->oxid, states[atp->state & 0x7]); 1075196008Smjacob } 1076196008Smjacob} 1077196008Smjacob 1078196008Smjacob 1079196008Smjacobstatic ISP_INLINE inot_private_data_t * 1080196008Smjacobisp_get_ntpd(ispsoftc_t *isp, tstate_t *tptr) 1081196008Smjacob{ 1082196008Smjacob inot_private_data_t *ntp; 1083196008Smjacob ntp = tptr->ntfree; 1084196008Smjacob if (ntp) { 1085196008Smjacob tptr->ntfree = ntp->next; 1086196008Smjacob } 1087196008Smjacob return (ntp); 1088196008Smjacob} 1089196008Smjacob 1090196008Smjacobstatic ISP_INLINE inot_private_data_t * 1091196008Smjacobisp_find_ntpd(ispsoftc_t *isp, tstate_t *tptr, uint32_t tag_id, uint32_t seq_id) 1092196008Smjacob{ 1093196008Smjacob inot_private_data_t *ntp; 1094196008Smjacob for (ntp = tptr->ntpool; ntp < &tptr->ntpool[ATPDPSIZE]; ntp++) { 1095196008Smjacob if (ntp->rd.tag_id == tag_id && ntp->rd.seq_id == seq_id) { 1096196008Smjacob return (ntp); 1097196008Smjacob } 1098196008Smjacob } 1099196008Smjacob return (NULL); 1100196008Smjacob} 1101196008Smjacob 1102196008Smjacobstatic ISP_INLINE void 1103196008Smjacobisp_put_ntpd(ispsoftc_t *isp, tstate_t *tptr, inot_private_data_t *ntp) 1104196008Smjacob{ 1105196008Smjacob ntp->rd.tag_id = ntp->rd.seq_id = 0; 1106196008Smjacob ntp->next = tptr->ntfree; 1107196008Smjacob tptr->ntfree = ntp; 1108196008Smjacob} 1109196008Smjacob 111055371Smjacobstatic cam_status 1111196008Smjacobcreate_lun_state(ispsoftc_t *isp, int bus, struct cam_path *path, tstate_t **rslt) 111255371Smjacob{ 111355371Smjacob cam_status status; 111455371Smjacob lun_id_t lun; 1115196008Smjacob struct tslist *lhp; 1116196008Smjacob tstate_t *tptr; 1117196008Smjacob int i; 111855371Smjacob 111955371Smjacob lun = xpt_path_lun_id(path); 1120196008Smjacob if (lun != CAM_LUN_WILDCARD) { 1121196008Smjacob if (lun >= ISP_MAX_LUNS(isp)) { 1122196008Smjacob return (CAM_LUN_INVALID); 1123196008Smjacob } 112455371Smjacob } 112575200Smjacob if (is_lun_enabled(isp, bus, lun)) { 112655371Smjacob return (CAM_LUN_ALRDY_ENA); 112755371Smjacob } 1128236427Smjacob tptr = malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO); 1129196008Smjacob if (tptr == NULL) { 113055371Smjacob return (CAM_RESRC_UNAVAIL); 113155371Smjacob } 1132196008Smjacob status = xpt_create_path(&tptr->owner, NULL, xpt_path_path_id(path), xpt_path_target_id(path), lun); 113355371Smjacob if (status != CAM_REQ_CMP) { 1134196008Smjacob free(tptr, M_DEVBUF); 113555371Smjacob return (status); 113655371Smjacob } 1137196008Smjacob SLIST_INIT(&tptr->atios); 1138196008Smjacob SLIST_INIT(&tptr->inots); 1139239143Smjacob TAILQ_INIT(&tptr->waitq); 1140196008Smjacob for (i = 0; i < ATPDPSIZE-1; i++) { 1141196008Smjacob tptr->atpool[i].next = &tptr->atpool[i+1]; 1142196008Smjacob tptr->ntpool[i].next = &tptr->ntpool[i+1]; 114355371Smjacob } 1144196008Smjacob tptr->atfree = tptr->atpool; 1145196008Smjacob tptr->ntfree = tptr->ntpool; 1146196008Smjacob tptr->hold = 1; 1147196008Smjacob ISP_GET_PC_ADDR(isp, bus, lun_hash[LUN_HASH_FUNC(xpt_path_lun_id(tptr->owner))], lhp); 1148196008Smjacob SLIST_INSERT_HEAD(lhp, tptr, next); 1149196008Smjacob *rslt = tptr; 1150196008Smjacob ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, path, "created tstate\n"); 115155371Smjacob return (CAM_REQ_CMP); 115255371Smjacob} 115355371Smjacob 1154196008Smjacobstatic ISP_INLINE void 1155157943Smjacobdestroy_lun_state(ispsoftc_t *isp, tstate_t *tptr) 115655371Smjacob{ 1157239330Smjacob union ccb *ccb; 1158196008Smjacob struct tslist *lhp; 1159236427Smjacob 1160228461Smav KASSERT((tptr->hold != 0), ("tptr is not held")); 1161228461Smav KASSERT((tptr->hold == 1), ("tptr still held (%d)", tptr->hold)); 1162239330Smjacob do { 1163239330Smjacob ccb = (union ccb *)SLIST_FIRST(&tptr->atios); 1164239330Smjacob if (ccb) { 1165239330Smjacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 1166239330Smjacob ccb->ccb_h.status = CAM_REQ_ABORTED; 1167239330Smjacob xpt_done(ccb); 1168239330Smjacob } 1169239330Smjacob } while (ccb); 1170239330Smjacob do { 1171239330Smjacob ccb = (union ccb *)SLIST_FIRST(&tptr->inots); 1172239330Smjacob if (ccb) { 1173239330Smjacob SLIST_REMOVE_HEAD(&tptr->inots, sim_links.sle); 1174239330Smjacob ccb->ccb_h.status = CAM_REQ_ABORTED; 1175239330Smjacob xpt_done(ccb); 1176239330Smjacob } 1177239330Smjacob } while (ccb); 1178228461Smav ISP_GET_PC_ADDR(isp, cam_sim_bus(xpt_path_sim(tptr->owner)), lun_hash[LUN_HASH_FUNC(xpt_path_lun_id(tptr->owner))], lhp); 1179196008Smjacob SLIST_REMOVE(lhp, tptr, tstate, next); 1180236427Smjacob ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, tptr->owner, "destroyed tstate\n"); 1181196008Smjacob xpt_free_path(tptr->owner); 118255371Smjacob free(tptr, M_DEVBUF); 118355371Smjacob} 118455371Smjacob 118577365Smjacob/* 1186196008Smjacob * Enable a lun. 118777365Smjacob */ 1188196008Smjacobstatic void 1189196008Smjacobisp_enable_lun(ispsoftc_t *isp, union ccb *ccb) 119055371Smjacob{ 1191170412Smjacob tstate_t *tptr = NULL; 1192196008Smjacob int bus, tm_enabled, target_role; 1193196008Smjacob target_id_t target; 119455371Smjacob lun_id_t lun; 119555371Smjacob 1196236427Smjacob 1197196008Smjacob /* 1198196008Smjacob * We only support either a wildcard target/lun or a target ID of zero and a non-wildcard lun 1199196008Smjacob */ 1200125597Smjacob bus = XS_CHANNEL(ccb); 1201196008Smjacob target = ccb->ccb_h.target_id; 1202196008Smjacob lun = ccb->ccb_h.target_lun; 1203236427Smjacob ISP_PATH_PRT(isp, ISP_LOGTDEBUG0|ISP_LOGCONFIG, ccb->ccb_h.path, "enabling lun %u\n", lun); 1204196008Smjacob if (target != CAM_TARGET_WILDCARD && target != 0) { 1205196008Smjacob ccb->ccb_h.status = CAM_TID_INVALID; 1206196008Smjacob xpt_done(ccb); 1207196008Smjacob return; 1208125597Smjacob } 1209196008Smjacob if (target == CAM_TARGET_WILDCARD && lun != CAM_LUN_WILDCARD) { 1210196008Smjacob ccb->ccb_h.status = CAM_LUN_INVALID; 1211196008Smjacob xpt_done(ccb); 1212196008Smjacob return; 1213196008Smjacob } 121455371Smjacob 1215196008Smjacob if (target != CAM_TARGET_WILDCARD && lun == CAM_LUN_WILDCARD) { 1216196008Smjacob ccb->ccb_h.status = CAM_LUN_INVALID; 1217196008Smjacob xpt_done(ccb); 1218196008Smjacob return; 1219196008Smjacob } 1220164909Smjacob if (isp->isp_dblev & ISP_LOGTDEBUG0) { 1221196008Smjacob xpt_print(ccb->ccb_h.path, "enabling lun 0x%x on channel %d\n", lun, bus); 1222164909Smjacob } 122365140Smjacob 1224196008Smjacob /* 1225196008Smjacob * Wait until we're not busy with the lun enables subsystem 1226196008Smjacob */ 1227236427Smjacob isp_tmlock(isp, "isp_enable_lun"); 122883028Smjacob 1229196008Smjacob /* 1230196008Smjacob * This is as a good a place as any to check f/w capabilities. 1231196008Smjacob */ 1232196008Smjacob 1233196008Smjacob if (IS_FC(isp)) { 1234196008Smjacob if (ISP_CAP_TMODE(isp) == 0) { 1235196008Smjacob xpt_print(ccb->ccb_h.path, "firmware does not support target mode\n"); 123683028Smjacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 1237196008Smjacob goto done; 123872347Smjacob } 123983028Smjacob /* 1240196008Smjacob * We *could* handle non-SCCLUN f/w, but we'd have to 1241196008Smjacob * dork with our already fragile enable/disable code. 124283028Smjacob */ 1243196008Smjacob if (ISP_CAP_SCCFW(isp) == 0) { 1244196008Smjacob xpt_print(ccb->ccb_h.path, "firmware not SCCLUN capable\n"); 1245125549Smjacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 1246196008Smjacob goto done; 124765140Smjacob } 124865140Smjacob 1249196008Smjacob target_role = (FCPARAM(isp, bus)->role & ISP_ROLE_TARGET) != 0; 1250196008Smjacob 125182689Smjacob } else { 1252196008Smjacob target_role = (SDPARAM(isp, bus)->role & ISP_ROLE_TARGET) != 0; 125382689Smjacob } 125455371Smjacob 1255196008Smjacob /* 1256196008Smjacob * Create the state pointer. 1257196008Smjacob * It should not already exist. 1258196008Smjacob */ 1259196008Smjacob tptr = get_lun_statep(isp, bus, lun); 1260196008Smjacob if (tptr) { 1261196008Smjacob ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; 1262196008Smjacob goto done; 1263196008Smjacob } 1264196008Smjacob ccb->ccb_h.status = create_lun_state(isp, bus, ccb->ccb_h.path, &tptr); 1265196008Smjacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 1266196008Smjacob goto done; 1267196008Smjacob } 1268125549Smjacob 126955371Smjacob /* 1270196008Smjacob * We have a tricky maneuver to perform here. 127183028Smjacob * 1272196008Smjacob * If target mode isn't already enabled here, 1273196008Smjacob * *and* our current role includes target mode, 1274196008Smjacob * we enable target mode here. 1275196008Smjacob * 127655371Smjacob */ 1277196008Smjacob ISP_GET_PC(isp, bus, tm_enabled, tm_enabled); 1278196008Smjacob if (tm_enabled == 0 && target_role != 0) { 1279196008Smjacob if (isp_enable_target_mode(isp, bus)) { 1280196008Smjacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 1281196008Smjacob destroy_lun_state(isp, tptr); 1282196008Smjacob tptr = NULL; 1283196008Smjacob goto done; 128482689Smjacob } 1285196008Smjacob tm_enabled = 1; 128682689Smjacob } 128782689Smjacob 128882689Smjacob /* 1289196008Smjacob * Now check to see whether this bus is in target mode already. 1290196008Smjacob * 1291196008Smjacob * If not, a later role change into target mode will finish the job. 129282689Smjacob */ 1293196008Smjacob if (tm_enabled == 0) { 1294196008Smjacob ISP_SET_PC(isp, bus, tm_enable_defer, 1); 129583028Smjacob ccb->ccb_h.status = CAM_REQ_CMP; 1296236427Smjacob xpt_print(ccb->ccb_h.path, "Target Mode not enabled yet- lun enable deferred\n"); 1297238869Smjacob goto done1; 129855371Smjacob } 129955371Smjacob 1300125597Smjacob /* 1301196008Smjacob * Enable the lun. 1302125597Smjacob */ 1303196008Smjacob ccb->ccb_h.status = isp_enable_deferred(isp, bus, lun); 1304196008Smjacob 1305196008Smjacobdone: 1306236427Smjacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 1307236427Smjacob if (tptr) { 1308236427Smjacob destroy_lun_state(isp, tptr); 1309236427Smjacob tptr = NULL; 1310236427Smjacob } 1311236427Smjacob } else { 1312236427Smjacob tptr->enabled = 1; 1313125597Smjacob } 1314238869Smjacobdone1: 1315196008Smjacob if (tptr) { 1316196008Smjacob rls_lun_statep(isp, tptr); 1317125597Smjacob } 1318236427Smjacob 1319236427Smjacob /* 1320236427Smjacob * And we're outta here.... 1321236427Smjacob */ 1322236427Smjacob isp_tmunlk(isp); 1323196008Smjacob xpt_done(ccb); 1324196008Smjacob} 132555371Smjacob 1326236427Smjacobstatic cam_status 1327196008Smjacobisp_enable_deferred_luns(ispsoftc_t *isp, int bus) 1328196008Smjacob{ 1329236427Smjacob tstate_t *tptr = NULL; 1330236427Smjacob struct tslist *lhp; 1331236427Smjacob int i, n; 1332236427Smjacob 1333238869Smjacob 1334236427Smjacob ISP_GET_PC(isp, bus, tm_enabled, i); 1335236427Smjacob if (i == 1) { 1336236427Smjacob return (CAM_REQ_CMP); 1337236427Smjacob } 1338236427Smjacob ISP_GET_PC(isp, bus, tm_enable_defer, i); 1339236427Smjacob if (i == 0) { 1340236427Smjacob return (CAM_REQ_CMP); 1341236427Smjacob } 1342196008Smjacob /* 1343236427Smjacob * If this succeeds, it will set tm_enable 1344196008Smjacob */ 1345236427Smjacob if (isp_enable_target_mode(isp, bus)) { 1346236427Smjacob return (CAM_REQ_CMP_ERR); 1347236427Smjacob } 1348236427Smjacob isp_tmlock(isp, "isp_enable_deferred_luns"); 1349236427Smjacob for (n = i = 0; i < LUN_HASH_SIZE; i++) { 1350236427Smjacob ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp); 1351236427Smjacob SLIST_FOREACH(tptr, lhp, next) { 1352236427Smjacob tptr->hold++; 1353236427Smjacob if (tptr->enabled == 0) { 1354238869Smjacob if (isp_enable_deferred(isp, bus, xpt_path_lun_id(tptr->owner)) == CAM_REQ_CMP) { 1355236427Smjacob tptr->enabled = 1; 1356236427Smjacob n++; 1357236427Smjacob } 1358236427Smjacob } else { 1359236427Smjacob n++; 1360236427Smjacob } 1361236427Smjacob tptr->hold--; 1362236427Smjacob } 1363236427Smjacob } 1364236427Smjacob isp_tmunlk(isp); 1365236427Smjacob if (n == 0) { 1366236427Smjacob return (CAM_REQ_CMP_ERR); 1367236427Smjacob } 1368236427Smjacob ISP_SET_PC(isp, bus, tm_enable_defer, 0); 1369236427Smjacob return (CAM_REQ_CMP); 1370196008Smjacob} 137177365Smjacob 1372236427Smjacobstatic cam_status 1373196008Smjacobisp_enable_deferred(ispsoftc_t *isp, int bus, lun_id_t lun) 1374196008Smjacob{ 1375196008Smjacob cam_status status; 1376238869Smjacob int luns_already_enabled; 1377196008Smjacob 1378238869Smjacob ISP_GET_PC(isp, bus, tm_luns_enabled, luns_already_enabled); 1379238869Smjacob isp_prt(isp, ISP_LOGTINFO, "%s: bus %d lun %u luns_enabled %d", __func__, bus, lun, luns_already_enabled); 1380236427Smjacob if (IS_24XX(isp) || (IS_FC(isp) && luns_already_enabled)) { 1381196008Smjacob status = CAM_REQ_CMP; 138255371Smjacob } else { 1383196008Smjacob int cmd_cnt, not_cnt; 138455371Smjacob 1385196008Smjacob if (IS_23XX(isp)) { 1386196008Smjacob cmd_cnt = DFLT_CMND_CNT; 1387196008Smjacob not_cnt = DFLT_INOT_CNT; 1388196008Smjacob } else { 1389196008Smjacob cmd_cnt = 64; 1390196008Smjacob not_cnt = 8; 139177365Smjacob } 1392196008Smjacob status = CAM_REQ_INPROG; 1393196008Smjacob isp->isp_osinfo.rptr = &status; 1394238869Smjacob if (isp_lun_cmd(isp, RQSTYPE_ENABLE_LUN, bus, lun == CAM_LUN_WILDCARD? 0 : lun, cmd_cnt, not_cnt)) { 1395196008Smjacob status = CAM_RESRC_UNAVAIL; 1396196008Smjacob } else { 1397196008Smjacob mtx_sleep(&status, &isp->isp_lock, PRIBIO, "isp_enable_deferred", 0); 139855371Smjacob } 1399196008Smjacob isp->isp_osinfo.rptr = NULL; 1400125597Smjacob } 1401196008Smjacob if (status == CAM_REQ_CMP) { 1402196008Smjacob ISP_SET_PC(isp, bus, tm_luns_enabled, 1); 1403236427Smjacob isp_prt(isp, ISP_LOGCONFIG|ISP_LOGTINFO, "bus %d lun %u now enabled for target mode", bus, lun); 1404196008Smjacob } 1405196008Smjacob return (status); 1406125597Smjacob} 140777365Smjacob 1408125597Smjacobstatic void 1409196008Smjacobisp_disable_lun(ispsoftc_t *isp, union ccb *ccb) 1410125597Smjacob{ 1411196008Smjacob tstate_t *tptr = NULL; 1412196008Smjacob int bus; 1413196008Smjacob cam_status status; 1414196008Smjacob target_id_t target; 1415196008Smjacob lun_id_t lun; 141655371Smjacob 1417196008Smjacob bus = XS_CHANNEL(ccb); 1418196008Smjacob target = ccb->ccb_h.target_id; 1419196008Smjacob lun = ccb->ccb_h.target_lun; 1420236427Smjacob ISP_PATH_PRT(isp, ISP_LOGTDEBUG0|ISP_LOGCONFIG, ccb->ccb_h.path, "disabling lun %u\n", lun); 1421196008Smjacob if (target != CAM_TARGET_WILDCARD && target != 0) { 1422196008Smjacob ccb->ccb_h.status = CAM_TID_INVALID; 1423196008Smjacob xpt_done(ccb); 1424125597Smjacob return; 142555371Smjacob } 1426236427Smjacob 1427196008Smjacob if (target == CAM_TARGET_WILDCARD && lun != CAM_LUN_WILDCARD) { 1428196008Smjacob ccb->ccb_h.status = CAM_LUN_INVALID; 1429196008Smjacob xpt_done(ccb); 1430125597Smjacob return; 1431125597Smjacob } 143282689Smjacob 1433196008Smjacob if (target != CAM_TARGET_WILDCARD && lun == CAM_LUN_WILDCARD) { 1434196008Smjacob ccb->ccb_h.status = CAM_LUN_INVALID; 1435125597Smjacob xpt_done(ccb); 1436125597Smjacob return; 1437125597Smjacob } 1438125597Smjacob 1439196008Smjacob /* 1440196008Smjacob * See if we're busy disabling a lun now. 1441196008Smjacob */ 1442236427Smjacob isp_tmlock(isp, "isp_disable_lun"); 1443228461Smav status = CAM_REQ_INPROG; 1444125597Smjacob 1445196008Smjacob /* 1446196008Smjacob * Find the state pointer. 1447196008Smjacob */ 1448196008Smjacob if ((tptr = get_lun_statep(isp, bus, lun)) == NULL) { 1449228461Smav status = CAM_PATH_INVALID; 1450196008Smjacob goto done; 1451125597Smjacob } 1452125597Smjacob 1453196008Smjacob /* 1454196008Smjacob * If we're a 24XX card, we're done. 1455196008Smjacob */ 1456196008Smjacob if (IS_24XX(isp)) { 1457196008Smjacob status = CAM_REQ_CMP; 1458196008Smjacob goto done; 1459196008Smjacob } 1460196008Smjacob 1461196008Smjacob /* 1462196008Smjacob * For SCC FW, we only deal with lun zero. 1463196008Smjacob */ 1464238869Smjacob if (IS_FC(isp) && lun > 0) { 1465238869Smjacob status = CAM_REQ_CMP; 1466238869Smjacob goto done; 1467196008Smjacob } 1468196008Smjacob isp->isp_osinfo.rptr = &status; 1469196008Smjacob if (isp_lun_cmd(isp, RQSTYPE_ENABLE_LUN, bus, lun, 0, 0)) { 1470196008Smjacob status = CAM_RESRC_UNAVAIL; 1471196008Smjacob } else { 1472196008Smjacob mtx_sleep(ccb, &isp->isp_lock, PRIBIO, "isp_disable_lun", 0); 1473196008Smjacob } 1474236427Smjacob isp->isp_osinfo.rptr = NULL; 1475196008Smjacobdone: 1476236427Smjacob if (status == CAM_REQ_CMP) { 1477236427Smjacob tptr->enabled = 0; 1478236427Smjacob /* 1479238869Smjacob * If we have no more luns enabled for this bus, 1480238869Smjacob * delete all tracked wwns for it (if we are FC), 1481236427Smjacob * and disable target mode. 1482236427Smjacob */ 1483236427Smjacob if (is_any_lun_enabled(isp, bus) == 0) { 1484236427Smjacob isp_del_all_wwn_entries(isp, bus); 1485236427Smjacob if (isp_disable_target_mode(isp, bus)) { 1486236427Smjacob status = CAM_REQ_CMP_ERR; 1487236427Smjacob } 1488236427Smjacob } 1489236427Smjacob } 1490228461Smav ccb->ccb_h.status = status; 1491196008Smjacob if (status == CAM_REQ_CMP) { 1492239330Smjacob destroy_lun_state(isp, tptr); 1493236427Smjacob xpt_print(ccb->ccb_h.path, "lun now disabled for target mode\n"); 1494236427Smjacob } else { 1495236427Smjacob if (tptr) 1496236427Smjacob rls_lun_statep(isp, tptr); 149755371Smjacob } 1498236427Smjacob isp_tmunlk(isp); 1499196008Smjacob xpt_done(ccb); 1500196008Smjacob} 1501125597Smjacob 1502196008Smjacobstatic int 1503196008Smjacobisp_enable_target_mode(ispsoftc_t *isp, int bus) 1504196008Smjacob{ 1505236427Smjacob int tm_enabled; 1506196008Smjacob 1507236427Smjacob ISP_GET_PC(isp, bus, tm_enabled, tm_enabled); 1508236427Smjacob if (tm_enabled != 0) { 1509196008Smjacob return (0); 1510196008Smjacob } 1511196008Smjacob if (IS_SCSI(isp)) { 1512196008Smjacob mbreg_t mbs; 1513196008Smjacob MBSINIT(&mbs, MBOX_ENABLE_TARGET_MODE, MBLOGALL, 0); 1514196008Smjacob mbs.param[0] = MBOX_ENABLE_TARGET_MODE; 1515196008Smjacob mbs.param[1] = ENABLE_TARGET_FLAG|ENABLE_TQING_FLAG; 1516196008Smjacob mbs.param[2] = bus << 7; 1517196008Smjacob if (isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs) < 0 || mbs.param[0] != MBOX_COMMAND_COMPLETE) { 1518236427Smjacob isp_prt(isp, ISP_LOGERR, "Unable to enable Target Role on Bus %d", bus); 1519196008Smjacob return (EIO); 1520125597Smjacob } 1521125597Smjacob } 1522196008Smjacob ISP_SET_PC(isp, bus, tm_enabled, 1); 1523236427Smjacob isp_prt(isp, ISP_LOGINFO, "Target Role enabled on Bus %d", bus); 1524196008Smjacob return (0); 152555371Smjacob} 152655371Smjacob 1527196008Smjacobstatic int 1528196008Smjacobisp_disable_target_mode(ispsoftc_t *isp, int bus) 152955371Smjacob{ 1530236427Smjacob int tm_enabled; 153155371Smjacob 1532236427Smjacob ISP_GET_PC(isp, bus, tm_enabled, tm_enabled); 1533236427Smjacob if (tm_enabled == 0) { 1534196008Smjacob return (0); 1535196008Smjacob } 1536196008Smjacob if (IS_SCSI(isp)) { 1537196008Smjacob mbreg_t mbs; 1538196008Smjacob MBSINIT(&mbs, MBOX_ENABLE_TARGET_MODE, MBLOGALL, 0); 1539196008Smjacob mbs.param[2] = bus << 7; 1540196008Smjacob if (isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs) < 0 || mbs.param[0] != MBOX_COMMAND_COMPLETE) { 1541236427Smjacob isp_prt(isp, ISP_LOGERR, "Unable to disable Target Role on Bus %d", bus); 1542196008Smjacob return (EIO); 1543125549Smjacob } 1544196008Smjacob } 1545196008Smjacob ISP_SET_PC(isp, bus, tm_enabled, 0); 1546238869Smjacob isp_prt(isp, ISP_LOGINFO, "Target Role disabled on Bus %d", bus); 1547196008Smjacob return (0); 1548196008Smjacob} 1549196008Smjacob 1550196008Smjacobstatic void 1551196008Smjacobisp_ledone(ispsoftc_t *isp, lun_entry_t *lep) 1552196008Smjacob{ 1553196008Smjacob uint32_t *rptr; 1554196008Smjacob 1555196008Smjacob rptr = isp->isp_osinfo.rptr; 1556196008Smjacob if (lep->le_status != LUN_OK) { 1557196008Smjacob isp_prt(isp, ISP_LOGERR, "ENABLE/MODIFY LUN returned 0x%x", lep->le_status); 1558196008Smjacob if (rptr) { 1559196008Smjacob *rptr = CAM_REQ_CMP_ERR; 1560196008Smjacob wakeup_one(rptr); 156155371Smjacob } 156255371Smjacob } else { 1563196008Smjacob if (rptr) { 1564196008Smjacob *rptr = CAM_REQ_CMP; 1565196008Smjacob wakeup_one(rptr); 156655371Smjacob } 156755371Smjacob } 156855371Smjacob} 156955371Smjacob 1570157943Smjacobstatic void 1571238869Smjacobisp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb, enum Start_Ctio_How how) 157255371Smjacob{ 1573239143Smjacob int fctape, sendstatus, resid; 1574196008Smjacob tstate_t *tptr; 1575238869Smjacob fcparam *fcp; 1576196008Smjacob atio_private_data_t *atp; 1577239143Smjacob struct ccb_scsiio *cso; 1578239143Smjacob uint32_t dmaresult, handle, xfrlen, sense_length, tmp; 1579155704Smjacob uint8_t local[QENTRY_LEN]; 158055371Smjacob 1581196008Smjacob tptr = get_lun_statep(isp, XS_CHANNEL(ccb), XS_LUN(ccb)); 1582196008Smjacob if (tptr == NULL) { 1583196008Smjacob tptr = get_lun_statep(isp, XS_CHANNEL(ccb), CAM_LUN_WILDCARD); 1584196008Smjacob if (tptr == NULL) { 1585239143Smjacob isp_prt(isp, ISP_LOGERR, "%s: [0x%x] cannot find tstate pointer", __func__, ccb->csio.tag_id); 1586196008Smjacob ccb->ccb_h.status = CAM_DEV_NOT_THERE; 1587196008Smjacob xpt_done(ccb); 1588196008Smjacob return; 1589196008Smjacob } 1590196008Smjacob } 1591239143Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: ENTRY[0x%x] how %u xfrlen %u sendstatus %d sense_len %u", __func__, ccb->csio.tag_id, how, ccb->csio.dxfer_len, 1592239143Smjacob (ccb->ccb_h.flags & CAM_SEND_STATUS) != 0, ((ccb->ccb_h.flags & CAM_SEND_SENSE)? ccb->csio.sense_len : 0)); 1593196008Smjacob 1594239143Smjacob switch (how) { 1595239143Smjacob case FROM_TIMER: 1596239143Smjacob case FROM_CAM: 1597239143Smjacob /* 1598239143Smjacob * Insert at the tail of the list, if any, waiting CTIO CCBs 1599239143Smjacob */ 1600239143Smjacob TAILQ_INSERT_TAIL(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); 1601239143Smjacob break; 1602239143Smjacob case FROM_SRR: 1603239143Smjacob case FROM_CTIO_DONE: 1604239143Smjacob TAILQ_INSERT_HEAD(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); 1605239143Smjacob break; 1606196008Smjacob } 1607238869Smjacob 1608239143Smjacob while (TAILQ_FIRST(&tptr->waitq) != NULL) { 1609239143Smjacob ccb = (union ccb *) TAILQ_FIRST(&tptr->waitq); 1610239143Smjacob TAILQ_REMOVE(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); 1611196008Smjacob 1612239143Smjacob cso = &ccb->csio; 1613239143Smjacob xfrlen = cso->dxfer_len; 1614239143Smjacob if (xfrlen == 0) { 1615239143Smjacob if ((ccb->ccb_h.flags & CAM_SEND_STATUS) == 0) { 1616239143Smjacob ISP_PATH_PRT(isp, ISP_LOGERR, ccb->ccb_h.path, "a data transfer length of zero but no status to send is wrong\n"); 1617239143Smjacob ccb->ccb_h.status = CAM_REQ_INVALID; 1618239143Smjacob xpt_done(ccb); 1619239143Smjacob continue; 1620239143Smjacob } 1621239143Smjacob } 1622196008Smjacob 1623239143Smjacob atp = isp_get_atpd(isp, tptr, cso->tag_id); 1624239143Smjacob if (atp == NULL) { 1625239143Smjacob isp_prt(isp, ISP_LOGERR, "%s: [0x%x] cannot find private data adjunct in %s", __func__, cso->tag_id, __func__); 1626239143Smjacob isp_dump_atpd(isp, tptr); 1627239143Smjacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 1628239143Smjacob xpt_done(ccb); 1629239143Smjacob continue; 1630239143Smjacob } 1631238869Smjacob 1632239143Smjacob /* 1633239143Smjacob * Is this command a dead duck? 1634239143Smjacob */ 1635239143Smjacob if (atp->dead) { 1636239143Smjacob isp_prt(isp, ISP_LOGERR, "%s: [0x%x] not sending a CTIO for a dead command", __func__, cso->tag_id); 1637239143Smjacob ccb->ccb_h.status = CAM_REQ_ABORTED; 1638239143Smjacob xpt_done(ccb); 1639239143Smjacob continue; 1640239143Smjacob } 1641238869Smjacob 1642239143Smjacob /* 1643239143Smjacob * Check to make sure we're still in target mode. 1644239143Smjacob */ 1645239143Smjacob fcp = FCPARAM(isp, XS_CHANNEL(ccb)); 1646239143Smjacob if ((fcp->role & ISP_ROLE_TARGET) == 0) { 1647239143Smjacob isp_prt(isp, ISP_LOGERR, "%s: [0x%x] stopping sending a CTIO because we're no longer in target mode", __func__, cso->tag_id); 1648239143Smjacob ccb->ccb_h.status = CAM_PROVIDE_FAIL; 1649239143Smjacob xpt_done(ccb); 1650239143Smjacob continue; 1651239143Smjacob } 165255371Smjacob 1653239143Smjacob /* 1654239143Smjacob * We're only handling ATPD_CCB_OUTSTANDING outstanding CCB at a time (one of which 1655239143Smjacob * could be split into two CTIOs to split data and status). 1656239143Smjacob */ 1657239143Smjacob if (atp->ctcnt >= ATPD_CCB_OUTSTANDING) { 1658239143Smjacob isp_prt(isp, ISP_LOGTINFO, "[0x%x] handling only %d CCBs at a time (flags for this ccb: 0x%x)", cso->tag_id, ATPD_CCB_OUTSTANDING, ccb->ccb_h.flags); 1659239143Smjacob TAILQ_INSERT_HEAD(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); 1660239143Smjacob break; 1661239143Smjacob } 1662238869Smjacob 1663238869Smjacob /* 1664239143Smjacob * Does the initiator expect FC-Tape style responses? 1665238869Smjacob */ 1666239143Smjacob if ((atp->word3 & PRLI_WD3_RETRY) && fcp->fctape_enabled) { 1667239143Smjacob fctape = 1; 1668239143Smjacob } else { 1669239143Smjacob fctape = 0; 1670239143Smjacob } 1671238869Smjacob 1672238869Smjacob /* 1673239143Smjacob * If we already did the data xfer portion of a CTIO that sends data 1674239143Smjacob * and status, don't do it again and do the status portion now. 1675238869Smjacob */ 1676239143Smjacob if (atp->sendst) { 1677239143Smjacob isp_prt(isp, ISP_LOGTINFO, "[0x%x] now sending synthesized status orig_dl=%u xfered=%u bit=%u", 1678239143Smjacob cso->tag_id, atp->orig_datalen, atp->bytes_xfered, atp->bytes_in_transit); 1679239143Smjacob xfrlen = 0; /* we already did the data transfer */ 1680239143Smjacob atp->sendst = 0; 1681238869Smjacob } 1682239143Smjacob if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 1683239143Smjacob sendstatus = 1; 1684239143Smjacob } else { 1685239143Smjacob sendstatus = 0; 1686239143Smjacob } 1687238869Smjacob 1688239143Smjacob if (ccb->ccb_h.flags & CAM_SEND_SENSE) { 1689239143Smjacob KASSERT((sendstatus != 0), ("how can you have CAM_SEND_SENSE w/o CAM_SEND_STATUS?")); 1690239143Smjacob /* 1691239143Smjacob * Sense length is not the entire sense data structure size. Periph 1692239143Smjacob * drivers don't seem to be setting sense_len to reflect the actual 1693239143Smjacob * size. We'll peek inside to get the right amount. 1694239143Smjacob */ 1695239143Smjacob sense_length = cso->sense_len; 1696238869Smjacob 1697239143Smjacob /* 1698239143Smjacob * This 'cannot' happen 1699239143Smjacob */ 1700239143Smjacob if (sense_length > (XCMD_SIZE - MIN_FCP_RESPONSE_SIZE)) { 1701239143Smjacob sense_length = XCMD_SIZE - MIN_FCP_RESPONSE_SIZE; 1702239143Smjacob } 1703239143Smjacob } else { 1704239143Smjacob sense_length = 0; 1705239143Smjacob } 170655371Smjacob 1707239143Smjacob memset(local, 0, QENTRY_LEN); 1708238869Smjacob 1709238869Smjacob /* 1710239143Smjacob * Check for overflow 1711238869Smjacob */ 1712239143Smjacob tmp = atp->bytes_xfered + atp->bytes_in_transit + xfrlen; 1713239143Smjacob if (tmp > atp->orig_datalen) { 1714239143Smjacob isp_prt(isp, ISP_LOGERR, "%s: [0x%x] data overflow by %u bytes", __func__, cso->tag_id, tmp - atp->orig_datalen); 1715239143Smjacob ccb->ccb_h.status = CAM_DATA_RUN_ERR; 1716239143Smjacob xpt_done(ccb); 1717239143Smjacob continue; 1718239143Smjacob } 1719238869Smjacob 1720239143Smjacob if (IS_24XX(isp)) { 1721239143Smjacob ct7_entry_t *cto = (ct7_entry_t *) local; 1722239143Smjacob 1723239143Smjacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7; 1724239143Smjacob cto->ct_header.rqs_entry_count = 1; 1725239143Smjacob cto->ct_header.rqs_seqno |= ATPD_SEQ_NOTIFY_CAM; 1726239143Smjacob ATPD_SET_SEQNO(cto, atp); 1727239143Smjacob cto->ct_nphdl = atp->nphdl; 1728239143Smjacob cto->ct_rxid = atp->tag; 1729239143Smjacob cto->ct_iid_lo = atp->portid; 1730239143Smjacob cto->ct_iid_hi = atp->portid >> 16; 1731239143Smjacob cto->ct_oxid = atp->oxid; 1732239143Smjacob cto->ct_vpidx = ISP_GET_VPIDX(isp, XS_CHANNEL(ccb)); 1733239143Smjacob cto->ct_timeout = 120; 1734239143Smjacob cto->ct_flags = atp->tattr << CT7_TASK_ATTR_SHIFT; 1735239143Smjacob 1736239143Smjacob /* 1737239143Smjacob * Mode 1, status, no data. Only possible when we are sending status, have 1738240590Smjacob * no data to transfer, and any sense data can fit into a ct7_entry_t. 1739239143Smjacob * 1740240589Smjacob * Mode 2, status, no data. We have to use this in the case that 1741240589Smjacob * the sense data won't fit into a ct7_entry_t. 1742239143Smjacob * 1743239143Smjacob */ 1744239143Smjacob if (sendstatus && xfrlen == 0) { 1745239143Smjacob cto->ct_flags |= CT7_SENDSTATUS | CT7_NO_DATA; 1746239143Smjacob resid = atp->orig_datalen - atp->bytes_xfered - atp->bytes_in_transit; 1747239143Smjacob if (sense_length <= MAXRESPLEN_24XX) { 1748239143Smjacob if (resid < 0) { 1749239143Smjacob cto->ct_resid = -resid; 1750239143Smjacob } else if (resid > 0) { 1751239143Smjacob cto->ct_resid = resid; 1752239143Smjacob } 1753239143Smjacob cto->ct_flags |= CT7_FLAG_MODE1; 1754239143Smjacob cto->ct_scsi_status = cso->scsi_status; 1755239143Smjacob if (resid < 0) { 1756239143Smjacob cto->ct_scsi_status |= (FCP_RESID_OVERFLOW << 8); 1757239143Smjacob } else if (resid > 0) { 1758239143Smjacob cto->ct_scsi_status |= (FCP_RESID_UNDERFLOW << 8); 1759239143Smjacob } 1760239143Smjacob if (fctape) { 1761239143Smjacob cto->ct_flags |= CT7_CONFIRM|CT7_EXPLCT_CONF; 1762239143Smjacob } 1763239143Smjacob if (sense_length) { 1764239143Smjacob cto->ct_scsi_status |= (FCP_SNSLEN_VALID << 8); 1765239143Smjacob cto->rsp.m1.ct_resplen = cto->ct_senselen = sense_length; 1766239143Smjacob memcpy(cto->rsp.m1.ct_resp, &cso->sense_data, sense_length); 1767239143Smjacob } 1768239143Smjacob } else { 1769239143Smjacob bus_addr_t addr; 1770239143Smjacob char buf[XCMD_SIZE]; 1771239143Smjacob fcp_rsp_iu_t *rp; 1772239143Smjacob 1773238869Smjacob if (atp->ests == NULL) { 1774239143Smjacob atp->ests = isp_get_ecmd(isp); 1775239143Smjacob if (atp->ests == NULL) { 1776239143Smjacob TAILQ_INSERT_HEAD(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); 1777239143Smjacob break; 1778239143Smjacob } 1779238869Smjacob } 1780239143Smjacob memset(buf, 0, sizeof (buf)); 1781239143Smjacob rp = (fcp_rsp_iu_t *)buf; 1782239143Smjacob if (fctape) { 1783239143Smjacob cto->ct_flags |= CT7_CONFIRM|CT7_EXPLCT_CONF; 1784239143Smjacob rp->fcp_rsp_bits |= FCP_CONF_REQ; 1785239143Smjacob } 1786239143Smjacob cto->ct_flags |= CT7_FLAG_MODE2; 1787239143Smjacob rp->fcp_rsp_scsi_status = cso->scsi_status; 1788239143Smjacob if (resid < 0) { 1789239143Smjacob rp->fcp_rsp_resid = -resid; 1790239143Smjacob rp->fcp_rsp_bits |= FCP_RESID_OVERFLOW; 1791239143Smjacob } else if (resid > 0) { 1792239143Smjacob rp->fcp_rsp_resid = resid; 1793239143Smjacob rp->fcp_rsp_bits |= FCP_RESID_UNDERFLOW; 1794239143Smjacob } 1795239143Smjacob if (sense_length) { 1796239143Smjacob rp->fcp_rsp_snslen = sense_length; 1797239143Smjacob cto->ct_senselen = sense_length; 1798239143Smjacob rp->fcp_rsp_bits |= FCP_SNSLEN_VALID; 1799239143Smjacob isp_put_fcp_rsp_iu(isp, rp, atp->ests); 1800239143Smjacob memcpy(((fcp_rsp_iu_t *)atp->ests)->fcp_rsp_extra, &cso->sense_data, sense_length); 1801239143Smjacob } else { 1802239143Smjacob isp_put_fcp_rsp_iu(isp, rp, atp->ests); 1803239143Smjacob } 1804239143Smjacob if (isp->isp_dblev & ISP_LOGTDEBUG1) { 1805239143Smjacob isp_print_bytes(isp, "FCP Response Frame After Swizzling", MIN_FCP_RESPONSE_SIZE + sense_length, atp->ests); 1806239143Smjacob } 1807239143Smjacob addr = isp->isp_osinfo.ecmd_dma; 1808239143Smjacob addr += ((((isp_ecmd_t *)atp->ests) - isp->isp_osinfo.ecmd_base) * XCMD_SIZE); 1809239143Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: ests base %p vaddr %p ecmd_dma %jx addr %jx len %u", __func__, isp->isp_osinfo.ecmd_base, atp->ests, 1810239143Smjacob (uintmax_t) isp->isp_osinfo.ecmd_dma, (uintmax_t)addr, MIN_FCP_RESPONSE_SIZE + sense_length); 1811239143Smjacob cto->rsp.m2.ct_datalen = MIN_FCP_RESPONSE_SIZE + sense_length; 1812239143Smjacob cto->rsp.m2.ct_fcp_rsp_iudata.ds_base = DMA_LO32(addr); 1813239143Smjacob cto->rsp.m2.ct_fcp_rsp_iudata.ds_basehi = DMA_HI32(addr); 1814239143Smjacob cto->rsp.m2.ct_fcp_rsp_iudata.ds_count = MIN_FCP_RESPONSE_SIZE + sense_length; 1815238869Smjacob } 1816238869Smjacob if (sense_length) { 1817239143Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO7[0x%x] seq %u nc %d CDB0=%x sstatus=0x%x flags=0x%x resid=%d slen %u sense: %x %x/%x/%x", __func__, 1818239143Smjacob cto->ct_rxid, ATPD_GET_SEQNO(cto), ATPD_GET_NCAM(cto), atp->cdb0, cto->ct_scsi_status, cto->ct_flags, cto->ct_resid, sense_length, 1819239143Smjacob cso->sense_data.error_code, cso->sense_data.sense_buf[1], cso->sense_data.sense_buf[11], cso->sense_data.sense_buf[12]); 1820238869Smjacob } else { 1821239143Smjacob isp_prt(isp, ISP_LOGDEBUG0, "%s: CTIO7[0x%x] seq %u nc %d CDB0=%x sstatus=0x%x flags=0x%x resid=%d", __func__, 1822239143Smjacob cto->ct_rxid, ATPD_GET_SEQNO(cto), ATPD_GET_NCAM(cto), atp->cdb0, cto->ct_scsi_status, cto->ct_flags, cto->ct_resid); 1823238869Smjacob } 1824239143Smjacob atp->state = ATPD_STATE_LAST_CTIO; 1825238869Smjacob } 1826238869Smjacob 1827196008Smjacob /* 1828239143Smjacob * Mode 0 data transfers, *possibly* with status. 1829196008Smjacob */ 1830239143Smjacob if (xfrlen != 0) { 1831239143Smjacob cto->ct_flags |= CT7_FLAG_MODE0; 1832239143Smjacob if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1833239143Smjacob cto->ct_flags |= CT7_DATA_IN; 1834239143Smjacob } else { 1835239143Smjacob cto->ct_flags |= CT7_DATA_OUT; 1836239143Smjacob } 1837238869Smjacob 1838239143Smjacob cto->rsp.m0.reloff = atp->bytes_xfered + atp->bytes_in_transit; 1839239143Smjacob cto->rsp.m0.ct_xfrlen = xfrlen; 1840239143Smjacob 1841238869Smjacob#ifdef DEBUG 1842239143Smjacob if (ISP_FC_PC(isp, XS_CHANNEL(ccb))->inject_lost_data_frame && xfrlen > ISP_FC_PC(isp, XS_CHANNEL(ccb))->inject_lost_data_frame) { 1843239143Smjacob isp_prt(isp, ISP_LOGWARN, "%s: truncating data frame with xfrlen %d to %d", __func__, xfrlen, xfrlen - (xfrlen >> 2)); 1844239143Smjacob ISP_FC_PC(isp, XS_CHANNEL(ccb))->inject_lost_data_frame = 0; 1845239143Smjacob cto->rsp.m0.ct_xfrlen -= xfrlen >> 2; 1846239143Smjacob } 1847238869Smjacob#endif 1848239143Smjacob if (sendstatus) { 1849239143Smjacob resid = atp->orig_datalen - atp->bytes_xfered - xfrlen; 1850239143Smjacob if (cso->scsi_status == SCSI_STATUS_OK && resid == 0 /* && fctape == 0 */) { 1851239143Smjacob cto->ct_flags |= CT7_SENDSTATUS; 1852239143Smjacob atp->state = ATPD_STATE_LAST_CTIO; 1853239143Smjacob if (fctape) { 1854239143Smjacob cto->ct_flags |= CT7_CONFIRM|CT7_EXPLCT_CONF; 1855239143Smjacob } 1856239143Smjacob } else { 1857239143Smjacob atp->sendst = 1; /* send status later */ 1858239143Smjacob cto->ct_header.rqs_seqno &= ~ATPD_SEQ_NOTIFY_CAM; 1859239143Smjacob atp->state = ATPD_STATE_CTIO; 1860239143Smjacob } 1861238869Smjacob } else { 1862238869Smjacob atp->state = ATPD_STATE_CTIO; 1863238869Smjacob } 1864239143Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO7[0x%x] seq %u nc %d CDB0=%x sstatus=0x%x flags=0x%x xfrlen=%u off=%u", __func__, 1865239143Smjacob cto->ct_rxid, ATPD_GET_SEQNO(cto), ATPD_GET_NCAM(cto), atp->cdb0, cto->ct_scsi_status, cto->ct_flags, xfrlen, atp->bytes_xfered); 1866238869Smjacob } 1867239143Smjacob } else if (IS_FC(isp)) { 1868239143Smjacob ct2_entry_t *cto = (ct2_entry_t *) local; 186956007Smjacob 1870239143Smjacob if (isp->isp_osinfo.sixtyfourbit) 1871239143Smjacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO3; 1872239143Smjacob else 1873239143Smjacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; 1874239143Smjacob cto->ct_header.rqs_entry_count = 1; 1875239143Smjacob cto->ct_header.rqs_seqno |= ATPD_SEQ_NOTIFY_CAM; 1876239143Smjacob ATPD_SET_SEQNO(cto, atp); 1877239143Smjacob if (ISP_CAP_2KLOGIN(isp) == 0) { 1878239143Smjacob ((ct2e_entry_t *)cto)->ct_iid = cso->init_id; 1879239143Smjacob } else { 1880239143Smjacob cto->ct_iid = cso->init_id; 1881239143Smjacob if (ISP_CAP_SCCFW(isp) == 0) { 1882239143Smjacob cto->ct_lun = ccb->ccb_h.target_lun; 1883239143Smjacob } 1884158816Smjacob } 1885239143Smjacob cto->ct_timeout = 10; 1886239143Smjacob cto->ct_rxid = cso->tag_id; 188763385Smjacob 1888239143Smjacob /* 1889239143Smjacob * Mode 1, status, no data. Only possible when we are sending status, have 1890239143Smjacob * no data to transfer, and the sense length can fit in the ct7_entry. 1891239143Smjacob * 1892240518Seadler * Mode 2, status, no data. We have to use this in the case the response 1893239143Smjacob * length won't fit into a ct2_entry_t. 1894239143Smjacob * 1895239143Smjacob * We'll fill out this structure with information as if this were a 1896239143Smjacob * Mode 1. The hardware layer will create the Mode 2 FCP RSP IU as 1897239143Smjacob * needed based upon this. 1898239143Smjacob */ 1899239143Smjacob if (sendstatus && xfrlen == 0) { 1900239143Smjacob cto->ct_flags |= CT2_SENDSTATUS | CT2_NO_DATA; 1901239143Smjacob resid = atp->orig_datalen - atp->bytes_xfered - atp->bytes_in_transit; 1902239143Smjacob if (sense_length <= MAXRESPLEN) { 1903239143Smjacob if (resid < 0) { 1904239143Smjacob cto->ct_resid = -resid; 1905239143Smjacob } else if (resid > 0) { 1906239143Smjacob cto->ct_resid = resid; 1907239143Smjacob } 1908239143Smjacob cto->ct_flags |= CT2_FLAG_MODE1; 1909239143Smjacob cto->rsp.m1.ct_scsi_status = cso->scsi_status; 1910239143Smjacob if (resid < 0) { 1911239143Smjacob cto->rsp.m1.ct_scsi_status |= CT2_DATA_OVER; 1912239143Smjacob } else if (resid > 0) { 1913239143Smjacob cto->rsp.m1.ct_scsi_status |= CT2_DATA_UNDER; 1914239143Smjacob } 1915239143Smjacob if (fctape) { 1916239143Smjacob cto->ct_flags |= CT2_CONFIRM; 1917239143Smjacob } 1918239143Smjacob if (sense_length) { 1919239143Smjacob cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID; 1920239143Smjacob cto->rsp.m1.ct_resplen = cto->rsp.m1.ct_senselen = sense_length; 1921239143Smjacob memcpy(cto->rsp.m1.ct_resp, &cso->sense_data, sense_length); 1922239143Smjacob } 1923239143Smjacob } else { 1924239143Smjacob bus_addr_t addr; 1925239143Smjacob char buf[XCMD_SIZE]; 1926239143Smjacob fcp_rsp_iu_t *rp; 192784242Smjacob 1928238869Smjacob if (atp->ests == NULL) { 1929239143Smjacob atp->ests = isp_get_ecmd(isp); 1930239143Smjacob if (atp->ests == NULL) { 1931239143Smjacob TAILQ_INSERT_HEAD(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); 1932239143Smjacob break; 1933239143Smjacob } 1934238869Smjacob } 1935239143Smjacob memset(buf, 0, sizeof (buf)); 1936239143Smjacob rp = (fcp_rsp_iu_t *)buf; 1937239143Smjacob if (fctape) { 1938239143Smjacob cto->ct_flags |= CT2_CONFIRM; 1939239143Smjacob rp->fcp_rsp_bits |= FCP_CONF_REQ; 1940239143Smjacob } 1941239143Smjacob cto->ct_flags |= CT2_FLAG_MODE2; 1942239143Smjacob rp->fcp_rsp_scsi_status = cso->scsi_status; 1943239143Smjacob if (resid < 0) { 1944239143Smjacob rp->fcp_rsp_resid = -resid; 1945239143Smjacob rp->fcp_rsp_bits |= FCP_RESID_OVERFLOW; 1946239143Smjacob } else if (resid > 0) { 1947239143Smjacob rp->fcp_rsp_resid = resid; 1948239143Smjacob rp->fcp_rsp_bits |= FCP_RESID_UNDERFLOW; 1949239143Smjacob } 1950239143Smjacob if (sense_length) { 1951239143Smjacob rp->fcp_rsp_snslen = sense_length; 1952239143Smjacob rp->fcp_rsp_bits |= FCP_SNSLEN_VALID; 1953239143Smjacob isp_put_fcp_rsp_iu(isp, rp, atp->ests); 1954239143Smjacob memcpy(((fcp_rsp_iu_t *)atp->ests)->fcp_rsp_extra, &cso->sense_data, sense_length); 1955239143Smjacob } else { 1956239143Smjacob isp_put_fcp_rsp_iu(isp, rp, atp->ests); 1957239143Smjacob } 1958239143Smjacob if (isp->isp_dblev & ISP_LOGTDEBUG1) { 1959239143Smjacob isp_print_bytes(isp, "FCP Response Frame After Swizzling", MIN_FCP_RESPONSE_SIZE + sense_length, atp->ests); 1960239143Smjacob } 1961239143Smjacob addr = isp->isp_osinfo.ecmd_dma; 1962239143Smjacob addr += ((((isp_ecmd_t *)atp->ests) - isp->isp_osinfo.ecmd_base) * XCMD_SIZE); 1963239143Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: ests base %p vaddr %p ecmd_dma %jx addr %jx len %u", __func__, isp->isp_osinfo.ecmd_base, atp->ests, 1964239143Smjacob (uintmax_t) isp->isp_osinfo.ecmd_dma, (uintmax_t)addr, MIN_FCP_RESPONSE_SIZE + sense_length); 1965239143Smjacob cto->rsp.m2.ct_datalen = MIN_FCP_RESPONSE_SIZE + sense_length; 1966239143Smjacob if (isp->isp_osinfo.sixtyfourbit) { 1967239143Smjacob cto->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_base = DMA_LO32(addr); 1968239143Smjacob cto->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_basehi = DMA_HI32(addr); 1969239143Smjacob cto->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_count = MIN_FCP_RESPONSE_SIZE + sense_length; 1970239143Smjacob } else { 1971239143Smjacob cto->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_base = DMA_LO32(addr); 1972239143Smjacob cto->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_count = MIN_FCP_RESPONSE_SIZE + sense_length; 1973239143Smjacob } 1974238869Smjacob } 1975238869Smjacob if (sense_length) { 1976239143Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO2[0x%x] seq %u nc %d CDB0=%x sstatus=0x%x flags=0x%x resid=%d sense: %x %x/%x/%x", __func__, 1977239143Smjacob cto->ct_rxid, ATPD_GET_SEQNO(cto), ATPD_GET_NCAM(cto), atp->cdb0, cso->scsi_status, cto->ct_flags, cto->ct_resid, 1978239143Smjacob cso->sense_data.error_code, cso->sense_data.sense_buf[1], cso->sense_data.sense_buf[11], cso->sense_data.sense_buf[12]); 1979238869Smjacob } else { 1980239143Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO2[0x%x] seq %u nc %d CDB0=%x sstatus=0x%x flags=0x%x resid=%d", __func__, cto->ct_rxid, 1981239143Smjacob ATPD_GET_SEQNO(cto), ATPD_GET_NCAM(cto), atp->cdb0, cso->scsi_status, cto->ct_flags, cto->ct_resid); 1982238869Smjacob } 1983239143Smjacob atp->state = ATPD_STATE_LAST_CTIO; 1984239143Smjacob } 1985239143Smjacob 1986239143Smjacob if (xfrlen != 0) { 1987239143Smjacob cto->ct_flags |= CT2_FLAG_MODE0; 1988239143Smjacob if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1989239143Smjacob cto->ct_flags |= CT2_DATA_IN; 1990239143Smjacob } else { 1991239143Smjacob cto->ct_flags |= CT2_DATA_OUT; 1992238869Smjacob } 1993239143Smjacob 1994239143Smjacob cto->ct_reloff = atp->bytes_xfered + atp->bytes_in_transit; 1995239143Smjacob cto->rsp.m0.ct_xfrlen = xfrlen; 1996239143Smjacob 1997239143Smjacob if (sendstatus) { 1998239143Smjacob resid = atp->orig_datalen - atp->bytes_xfered - xfrlen; 1999239143Smjacob if (cso->scsi_status == SCSI_STATUS_OK && resid == 0 /*&& fctape == 0*/) { 2000239143Smjacob cto->ct_flags |= CT2_SENDSTATUS; 2001239143Smjacob atp->state = ATPD_STATE_LAST_CTIO; 2002239143Smjacob if (fctape) { 2003239143Smjacob cto->ct_flags |= CT2_CONFIRM; 2004239143Smjacob } 2005239143Smjacob } else { 2006239143Smjacob atp->sendst = 1; /* send status later */ 2007239143Smjacob cto->ct_header.rqs_seqno &= ~ATPD_SEQ_NOTIFY_CAM; 2008239143Smjacob atp->state = ATPD_STATE_CTIO; 2009239143Smjacob } 2010238869Smjacob } else { 2011239143Smjacob atp->state = ATPD_STATE_CTIO; 2012238869Smjacob } 201363385Smjacob } 2014239143Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO2[%x] seq %u nc %d CDB0=%x scsi status %x flags %x resid %d xfrlen %u offset %u", __func__, cto->ct_rxid, 2015239143Smjacob ATPD_GET_SEQNO(cto), ATPD_GET_NCAM(cto), atp->cdb0, cso->scsi_status, cto->ct_flags, cto->ct_resid, cso->dxfer_len, atp->bytes_xfered); 2016239143Smjacob } else { 2017239143Smjacob ct_entry_t *cto = (ct_entry_t *) local; 2018238869Smjacob 2019239143Smjacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 2020239143Smjacob cto->ct_header.rqs_entry_count = 1; 2021239143Smjacob cto->ct_header.rqs_seqno |= ATPD_SEQ_NOTIFY_CAM; 2022239143Smjacob ATPD_SET_SEQNO(cto, atp); 2023239143Smjacob cto->ct_iid = cso->init_id; 2024239143Smjacob cto->ct_iid |= XS_CHANNEL(ccb) << 7; 2025239143Smjacob cto->ct_tgt = ccb->ccb_h.target_id; 2026239143Smjacob cto->ct_lun = ccb->ccb_h.target_lun; 2027239143Smjacob cto->ct_fwhandle = cso->tag_id; 2028239143Smjacob if (atp->rxid) { 2029239143Smjacob cto->ct_tag_val = atp->rxid; 2030239143Smjacob cto->ct_flags |= CT_TQAE; 203155387Smjacob } 2032239143Smjacob if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) { 2033239143Smjacob cto->ct_flags |= CT_NODISC; 2034196008Smjacob } 2035239143Smjacob if (cso->dxfer_len == 0) { 2036239143Smjacob cto->ct_flags |= CT_NO_DATA; 2037239143Smjacob } else if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 2038239143Smjacob cto->ct_flags |= CT_DATA_IN; 203984242Smjacob } else { 2040239143Smjacob cto->ct_flags |= CT_DATA_OUT; 204156007Smjacob } 2042239143Smjacob if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 2043239143Smjacob cto->ct_flags |= CT_SENDSTATUS|CT_CCINCR; 2044239143Smjacob cto->ct_scsi_status = cso->scsi_status; 2045239143Smjacob cto->ct_resid = atp->orig_datalen - atp->bytes_xfered - atp->bytes_in_transit - xfrlen; 2046239143Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO[%x] seq %u nc %d scsi status %x resid %d tag_id %x", __func__, 2047239143Smjacob cto->ct_fwhandle, ATPD_GET_SEQNO(cto), ATPD_GET_NCAM(cto), cso->scsi_status, cso->resid, cso->tag_id); 2048239143Smjacob } 2049239143Smjacob ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 2050239143Smjacob cto->ct_timeout = 10; 205155371Smjacob } 205256007Smjacob 2053239143Smjacob if (isp_get_pcmd(isp, ccb)) { 2054239143Smjacob ISP_PATH_PRT(isp, ISP_LOGWARN, ccb->ccb_h.path, "out of PCMDs\n"); 2055239143Smjacob TAILQ_INSERT_HEAD(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); 2056239143Smjacob break; 205763385Smjacob } 2058239143Smjacob if (isp_allocate_xs_tgt(isp, ccb, &handle)) { 2059239143Smjacob ISP_PATH_PRT(isp, ISP_LOGWARN, ccb->ccb_h.path, "No XFLIST pointers for %s\n", __func__); 2060239143Smjacob TAILQ_INSERT_HEAD(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); 2061239143Smjacob isp_free_pcmd(isp, ccb); 2062239143Smjacob break; 206363385Smjacob } 2064239143Smjacob atp->bytes_in_transit += xfrlen; 2065239143Smjacob PISP_PCMD(ccb)->datalen = xfrlen; 206655371Smjacob 206755371Smjacob 2068239143Smjacob /* 2069239143Smjacob * Call the dma setup routines for this entry (and any subsequent 2070239143Smjacob * CTIOs) if there's data to move, and then tell the f/w it's got 2071239143Smjacob * new things to play with. As with isp_start's usage of DMA setup, 2072239143Smjacob * any swizzling is done in the machine dependent layer. Because 2073239143Smjacob * of this, we put the request onto the queue area first in native 2074239143Smjacob * format. 2075239143Smjacob */ 207655371Smjacob 2077239143Smjacob if (IS_24XX(isp)) { 2078239143Smjacob ct7_entry_t *cto = (ct7_entry_t *) local; 2079239143Smjacob cto->ct_syshandle = handle; 2080239143Smjacob } else if (IS_FC(isp)) { 2081239143Smjacob ct2_entry_t *cto = (ct2_entry_t *) local; 2082239143Smjacob cto->ct_syshandle = handle; 2083239143Smjacob } else { 2084239143Smjacob ct_entry_t *cto = (ct_entry_t *) local; 2085239143Smjacob cto->ct_syshandle = handle; 2086239143Smjacob } 208775200Smjacob 2088239143Smjacob dmaresult = ISP_DMASETUP(isp, cso, (ispreq_t *) local); 2089239143Smjacob if (dmaresult != CMD_QUEUED) { 2090239143Smjacob isp_destroy_tgt_handle(isp, handle); 2091239143Smjacob isp_free_pcmd(isp, ccb); 2092239143Smjacob if (dmaresult == CMD_EAGAIN) { 2093239143Smjacob TAILQ_INSERT_HEAD(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); 2094239143Smjacob break; 2095239143Smjacob } 2096239143Smjacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2097239143Smjacob xpt_done(ccb); 2098239143Smjacob continue; 2099239143Smjacob } 2100196008Smjacob isp->isp_nactive++; 2101239143Smjacob ccb->ccb_h.status = CAM_REQ_INPROG | CAM_SIM_QUEUED; 2102238869Smjacob if (xfrlen) { 2103238869Smjacob ccb->ccb_h.spriv_field0 = atp->bytes_xfered; 2104238869Smjacob } else { 2105238869Smjacob ccb->ccb_h.spriv_field0 = ~0; 2106238869Smjacob } 2107238869Smjacob atp->ctcnt++; 2108239143Smjacob atp->seqno++; 210955371Smjacob } 2110196008Smjacob rls_lun_statep(isp, tptr); 211155371Smjacob} 211255371Smjacob 211375200Smjacobstatic void 211475200Smjacobisp_refire_putback_atio(void *arg) 211563385Smjacob{ 2116196008Smjacob union ccb *ccb = arg; 2117196008Smjacob ispsoftc_t *isp = XS_ISP(ccb); 2118196008Smjacob ISP_LOCK(isp); 2119196008Smjacob isp_target_putback_atio(ccb); 2120196008Smjacob ISP_UNLOCK(isp); 212175200Smjacob} 212275200Smjacob 212375200Smjacobstatic void 2124238869Smjacobisp_refire_notify_ack(void *arg) 2125238869Smjacob{ 2126238869Smjacob isp_tna_t *tp = arg; 2127238869Smjacob ispsoftc_t *isp = tp->isp; 2128238869Smjacob ISP_LOCK(isp); 2129238869Smjacob if (isp_notify_ack(isp, tp->not)) { 2130238869Smjacob (void) timeout(isp_refire_notify_ack, tp, 5); 2131238869Smjacob } else { 2132238869Smjacob free(tp, M_DEVBUF); 2133238869Smjacob } 2134238869Smjacob ISP_UNLOCK(isp); 2135238869Smjacob} 2136238869Smjacob 2137238869Smjacob 2138238869Smjacobstatic void 213975200Smjacobisp_target_putback_atio(union ccb *ccb) 214075200Smjacob{ 2141157943Smjacob ispsoftc_t *isp; 214275200Smjacob struct ccb_scsiio *cso; 214363385Smjacob void *qe; 214463385Smjacob 214575200Smjacob isp = XS_ISP(ccb); 214675200Smjacob 2147196008Smjacob qe = isp_getrqentry(isp); 2148196008Smjacob if (qe == NULL) { 2149196008Smjacob xpt_print(ccb->ccb_h.path, rqo, __func__); 215075200Smjacob (void) timeout(isp_refire_putback_atio, ccb, 10); 215175200Smjacob return; 215263385Smjacob } 2153158816Smjacob memset(qe, 0, QENTRY_LEN); 215475200Smjacob cso = &ccb->csio; 215563385Smjacob if (IS_FC(isp)) { 215687635Smjacob at2_entry_t local, *at = &local; 2157196008Smjacob ISP_MEMZERO(at, sizeof (at2_entry_t)); 215863385Smjacob at->at_header.rqs_entry_type = RQSTYPE_ATIO2; 215963385Smjacob at->at_header.rqs_entry_count = 1; 2160196008Smjacob if (ISP_CAP_SCCFW(isp)) { 216175200Smjacob at->at_scclun = (uint16_t) ccb->ccb_h.target_lun; 216263385Smjacob } else { 216375200Smjacob at->at_lun = (uint8_t) ccb->ccb_h.target_lun; 216463385Smjacob } 216563385Smjacob at->at_status = CT_OK; 216675200Smjacob at->at_rxid = cso->tag_id; 216798289Smjacob at->at_iid = cso->ccb_h.target_id; 216887635Smjacob isp_put_atio2(isp, at, qe); 216963385Smjacob } else { 217087635Smjacob at_entry_t local, *at = &local; 2171196008Smjacob ISP_MEMZERO(at, sizeof (at_entry_t)); 217263385Smjacob at->at_header.rqs_entry_type = RQSTYPE_ATIO; 217363385Smjacob at->at_header.rqs_entry_count = 1; 217475200Smjacob at->at_iid = cso->init_id; 217575200Smjacob at->at_iid |= XS_CHANNEL(ccb) << 7; 217675200Smjacob at->at_tgt = cso->ccb_h.target_id; 217775200Smjacob at->at_lun = cso->ccb_h.target_lun; 217863385Smjacob at->at_status = CT_OK; 217975200Smjacob at->at_tag_val = AT_GET_TAG(cso->tag_id); 218075200Smjacob at->at_handle = AT_GET_HANDLE(cso->tag_id); 218187635Smjacob isp_put_atio(isp, at, qe); 218263385Smjacob } 2183196008Smjacob ISP_TDQE(isp, "isp_target_putback_atio", isp->isp_reqidx, qe); 2184196008Smjacob ISP_SYNC_REQUEST(isp); 218575200Smjacob isp_complete_ctio(ccb); 218663385Smjacob} 218763385Smjacob 218863385Smjacobstatic void 218975200Smjacobisp_complete_ctio(union ccb *ccb) 219063385Smjacob{ 2191238869Smjacob if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { 2192238869Smjacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 2193238869Smjacob xpt_done(ccb); 219463385Smjacob } 219563385Smjacob} 219663385Smjacob 219755371Smjacob/* 219855371Smjacob * Handle ATIO stuff that the generic code can't. 219955371Smjacob * This means handling CDBs. 220055371Smjacob */ 220155371Smjacob 2202196008Smjacobstatic void 2203157943Smjacobisp_handle_platform_atio(ispsoftc_t *isp, at_entry_t *aep) 220455371Smjacob{ 220555371Smjacob tstate_t *tptr; 2206196008Smjacob int status, bus; 220755371Smjacob struct ccb_accept_tio *atiop; 2208196008Smjacob atio_private_data_t *atp; 220955371Smjacob 221055371Smjacob /* 221155371Smjacob * The firmware status (except for the QLTM_SVALID bit) 221255371Smjacob * indicates why this ATIO was sent to us. 221355371Smjacob * 2214215034Sbrucec * If QLTM_SVALID is set, the firmware has recommended Sense Data. 221555371Smjacob * 221655371Smjacob * If the DISCONNECTS DISABLED bit is set in the flags field, 221777365Smjacob * we're still connected on the SCSI bus. 221855371Smjacob */ 221955371Smjacob status = aep->at_status; 222055371Smjacob if ((status & ~QLTM_SVALID) == AT_PHASE_ERROR) { 222155371Smjacob /* 222255371Smjacob * Bus Phase Sequence error. We should have sense data 222355371Smjacob * suggested by the f/w. I'm not sure quite yet what 222455371Smjacob * to do about this for CAM. 222555371Smjacob */ 222673245Smjacob isp_prt(isp, ISP_LOGWARN, "PHASE ERROR"); 222755371Smjacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 2228196008Smjacob return; 222955371Smjacob } 223055371Smjacob if ((status & ~QLTM_SVALID) != AT_CDB) { 2231196008Smjacob isp_prt(isp, ISP_LOGWARN, "bad atio (0x%x) leaked to platform", status); 223255371Smjacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 2233196008Smjacob return; 223455371Smjacob } 223555371Smjacob 223677365Smjacob bus = GET_BUS_VAL(aep->at_iid); 223775200Smjacob tptr = get_lun_statep(isp, bus, aep->at_lun); 223855371Smjacob if (tptr == NULL) { 223975200Smjacob tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD); 2240125549Smjacob if (tptr == NULL) { 2241157945Smjacob /* 2242157945Smjacob * Because we can't autofeed sense data back with 2243157945Smjacob * a command for parallel SCSI, we can't give back 2244157945Smjacob * a CHECK CONDITION. We'll give back a BUSY status 2245157945Smjacob * instead. This works out okay because the only 2246157945Smjacob * time we should, in fact, get this, is in the 2247157945Smjacob * case that somebody configured us without the 2248157945Smjacob * blackhole driver, so they get what they deserve. 2249157945Smjacob */ 2250157945Smjacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 2251196008Smjacob return; 2252125549Smjacob } 225355371Smjacob } 225455371Smjacob 2255196008Smjacob atp = isp_get_atpd(isp, tptr, 0); 225655371Smjacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 2257196008Smjacob if (atiop == NULL || atp == NULL) { 225855371Smjacob /* 225955371Smjacob * Because we can't autofeed sense data back with 226055371Smjacob * a command for parallel SCSI, we can't give back 226155371Smjacob * a CHECK CONDITION. We'll give back a QUEUE FULL status 226255371Smjacob * instead. This works out okay because the only time we 226355371Smjacob * should, in fact, get this, is in the case that we've 226455371Smjacob * run out of ATIOS. 226555371Smjacob */ 2266196008Smjacob xpt_print(tptr->owner, "no %s for lun %d from initiator %d\n", (atp == NULL && atiop == NULL)? "ATIOs *or* ATPS" : 2267196008Smjacob ((atp == NULL)? "ATPs" : "ATIOs"), aep->at_lun, aep->at_iid); 2268196008Smjacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 2269196008Smjacob if (atp) { 2270196008Smjacob isp_put_atpd(isp, tptr, atp); 2271196008Smjacob } 227283028Smjacob rls_lun_statep(isp, tptr); 2273196008Smjacob return; 227455371Smjacob } 2275238869Smjacob atp->tag = aep->at_handle; 2276238869Smjacob atp->rxid = aep->at_tag_val; 2277196008Smjacob atp->state = ATPD_STATE_ATIO; 227855371Smjacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 2279125549Smjacob tptr->atio_count--; 2280238869Smjacob ISP_PATH_PRT(isp, ISP_LOGTDEBUG2, atiop->ccb_h.path, "Take FREE ATIO count now %d\n", tptr->atio_count); 2281196008Smjacob atiop->ccb_h.target_id = aep->at_tgt; 2282196008Smjacob atiop->ccb_h.target_lun = aep->at_lun; 228355371Smjacob if (aep->at_flags & AT_NODISC) { 228463385Smjacob atiop->ccb_h.flags = CAM_DIS_DISCONNECT; 228563385Smjacob } else { 228663385Smjacob atiop->ccb_h.flags = 0; 228755371Smjacob } 228855371Smjacob 228963385Smjacob if (status & QLTM_SVALID) { 2290219098Smjacob size_t amt = ISP_MIN(QLTM_SENSELEN, sizeof (atiop->sense_data)); 229163385Smjacob atiop->sense_len = amt; 2292196008Smjacob ISP_MEMCPY(&atiop->sense_data, aep->at_sense, amt); 229363385Smjacob } else { 229463385Smjacob atiop->sense_len = 0; 229563385Smjacob } 229655371Smjacob 229777365Smjacob atiop->init_id = GET_IID_VAL(aep->at_iid); 229855371Smjacob atiop->cdb_len = aep->at_cdblen; 2299196008Smjacob ISP_MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen); 230055371Smjacob atiop->ccb_h.status = CAM_CDB_RECVD; 230175200Smjacob /* 230275200Smjacob * Construct a tag 'id' based upon tag value (which may be 0..255) 230375200Smjacob * and the handle (which we have to preserve). 230475200Smjacob */ 2305196008Smjacob atiop->tag_id = atp->tag; 230675200Smjacob if (aep->at_flags & AT_TQAE) { 230775200Smjacob atiop->tag_action = aep->at_tag_type; 230855371Smjacob atiop->ccb_h.status |= CAM_TAG_ACTION_VALID; 230955371Smjacob } 2310196008Smjacob atp->orig_datalen = 0; 2311196008Smjacob atp->bytes_xfered = 0; 2312196008Smjacob atp->lun = aep->at_lun; 2313196008Smjacob atp->nphdl = aep->at_iid; 2314196008Smjacob atp->portid = PORT_NONE; 2315196008Smjacob atp->oxid = 0; 2316196008Smjacob atp->cdb0 = atiop->cdb_io.cdb_bytes[0]; 2317196008Smjacob atp->tattr = aep->at_tag_type; 2318196008Smjacob atp->state = ATPD_STATE_CAM; 2319238869Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "ATIO[0x%x] CDB=0x%x lun %d", aep->at_tag_val, atp->cdb0, atp->lun); 232055371Smjacob rls_lun_statep(isp, tptr); 232155371Smjacob} 232255371Smjacob 2323196008Smjacobstatic void 2324157943Smjacobisp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep) 232555371Smjacob{ 232655387Smjacob lun_id_t lun; 2327196008Smjacob fcportdb_t *lp; 232855371Smjacob tstate_t *tptr; 232955371Smjacob struct ccb_accept_tio *atiop; 2330196008Smjacob uint16_t nphdl; 2331208761Smjacob atio_private_data_t *atp; 2332196008Smjacob inot_private_data_t *ntp; 233355371Smjacob 233455371Smjacob /* 233555371Smjacob * The firmware status (except for the QLTM_SVALID bit) 233655371Smjacob * indicates why this ATIO was sent to us. 233755371Smjacob * 2338215034Sbrucec * If QLTM_SVALID is set, the firmware has recommended Sense Data. 233955371Smjacob */ 234055371Smjacob if ((aep->at_status & ~QLTM_SVALID) != AT_CDB) { 2341196008Smjacob isp_prt(isp, ISP_LOGWARN, "bogus atio (0x%x) leaked to platform", aep->at_status); 234255371Smjacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 2343196008Smjacob return; 234455371Smjacob } 234555371Smjacob 2346196008Smjacob if (ISP_CAP_SCCFW(isp)) { 234761775Smjacob lun = aep->at_scclun; 234861775Smjacob } else { 234961775Smjacob lun = aep->at_lun; 235061775Smjacob } 2351196008Smjacob if (ISP_CAP_2KLOGIN(isp)) { 2352196008Smjacob nphdl = ((at2e_entry_t *)aep)->at_iid; 2353196008Smjacob } else { 2354196008Smjacob nphdl = aep->at_iid; 2355196008Smjacob } 235675200Smjacob tptr = get_lun_statep(isp, 0, lun); 235755371Smjacob if (tptr == NULL) { 235875200Smjacob tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD); 2359125549Smjacob if (tptr == NULL) { 2360238869Smjacob isp_prt(isp, ISP_LOGWARN, "%s: [0x%x] no state pointer for lun %d or wildcard", __func__, aep->at_rxid, lun); 2361238869Smjacob if (lun == 0) { 2362238869Smjacob isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); 2363238869Smjacob } else { 2364238869Smjacob isp_endcmd(isp, aep, SCSI_STATUS_CHECK_COND | ECMD_SVALID | (0x5 << 12) | (0x25 << 16), 0); 2365238869Smjacob } 2366196008Smjacob return; 2367125549Smjacob } 236855371Smjacob } 236955371Smjacob 2370196008Smjacob /* 2371196008Smjacob * Start any commands pending resources first. 2372196008Smjacob */ 2373196008Smjacob if (tptr->restart_queue) { 2374196008Smjacob inot_private_data_t *restart_queue = tptr->restart_queue; 2375196008Smjacob tptr->restart_queue = NULL; 2376196008Smjacob while (restart_queue) { 2377196008Smjacob ntp = restart_queue; 2378196008Smjacob restart_queue = ntp->rd.nt.nt_hba; 2379196008Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: restarting resrc deprived %x", __func__, ((at2_entry_t *)ntp->rd.data)->at_rxid); 2380196008Smjacob isp_handle_platform_atio2(isp, (at2_entry_t *) ntp->rd.data); 2381196008Smjacob isp_put_ntpd(isp, tptr, ntp); 2382196008Smjacob /* 2383196008Smjacob * If a recursion caused the restart queue to start to fill again, 2384196008Smjacob * stop and splice the new list on top of the old list and restore 2385196008Smjacob * it and go to noresrc. 2386196008Smjacob */ 2387196008Smjacob if (tptr->restart_queue) { 2388196008Smjacob ntp = tptr->restart_queue; 2389196008Smjacob tptr->restart_queue = restart_queue; 2390196008Smjacob while (restart_queue->rd.nt.nt_hba) { 2391196008Smjacob restart_queue = restart_queue->rd.nt.nt_hba; 2392196008Smjacob } 2393196008Smjacob restart_queue->rd.nt.nt_hba = ntp; 2394196008Smjacob goto noresrc; 2395196008Smjacob } 2396196008Smjacob } 2397196008Smjacob } 2398196008Smjacob 239955371Smjacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 2400196008Smjacob if (atiop == NULL) { 2401196008Smjacob goto noresrc; 2402196008Smjacob } 2403125549Smjacob 2404196008Smjacob atp = isp_get_atpd(isp, tptr, 0); 2405196008Smjacob if (atp == NULL) { 2406196008Smjacob goto noresrc; 240755371Smjacob } 2408196008Smjacob 2409196008Smjacob atp->tag = aep->at_rxid; 241098289Smjacob atp->state = ATPD_STATE_ATIO; 241155371Smjacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 241298289Smjacob tptr->atio_count--; 2413238869Smjacob isp_prt(isp, ISP_LOGTDEBUG2, "Take FREE ATIO count now %d", tptr->atio_count); 2414196008Smjacob atiop->ccb_h.target_id = FCPARAM(isp, 0)->isp_loopid; 2415196008Smjacob atiop->ccb_h.target_lun = lun; 241663385Smjacob 241773115Smjacob /* 241873115Smjacob * We don't get 'suggested' sense data as we do with SCSI cards. 241973115Smjacob */ 242073115Smjacob atiop->sense_len = 0; 2421196008Smjacob if (ISP_CAP_2KLOGIN(isp)) { 2422196008Smjacob /* 2423196008Smjacob * NB: We could not possibly have 2K logins if we 2424196008Smjacob * NB: also did not have SCC FW. 2425196008Smjacob */ 2426196008Smjacob atiop->init_id = ((at2e_entry_t *)aep)->at_iid; 2427196008Smjacob } else { 2428196008Smjacob atiop->init_id = aep->at_iid; 2429196008Smjacob } 243063385Smjacob 2431196008Smjacob /* 2432196008Smjacob * If we're not in the port database, add ourselves. 2433196008Smjacob */ 2434196008Smjacob if (!IS_2100(isp) && isp_find_pdb_by_loopid(isp, 0, atiop->init_id, &lp) == 0) { 2435196008Smjacob uint64_t iid = 2436196008Smjacob (((uint64_t) aep->at_wwpn[0]) << 48) | 2437196008Smjacob (((uint64_t) aep->at_wwpn[1]) << 32) | 2438196008Smjacob (((uint64_t) aep->at_wwpn[2]) << 16) | 2439196008Smjacob (((uint64_t) aep->at_wwpn[3]) << 0); 2440196008Smjacob /* 2441196008Smjacob * However, make sure we delete ourselves if otherwise 2442196008Smjacob * we were there but at a different loop id. 2443196008Smjacob */ 2444196008Smjacob if (isp_find_pdb_by_wwn(isp, 0, iid, &lp)) { 2445196008Smjacob isp_del_wwn_entry(isp, 0, iid, lp->handle, lp->portid); 2446196008Smjacob } 2447238869Smjacob isp_add_wwn_entry(isp, 0, iid, atiop->init_id, PORT_ANY, 0); 2448196008Smjacob } 244955371Smjacob atiop->cdb_len = ATIO2_CDBLEN; 2450196008Smjacob ISP_MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, ATIO2_CDBLEN); 245155371Smjacob atiop->ccb_h.status = CAM_CDB_RECVD; 2452196008Smjacob atiop->tag_id = atp->tag; 245355371Smjacob switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) { 245455371Smjacob case ATIO2_TC_ATTR_SIMPLEQ: 2455196008Smjacob atiop->ccb_h.flags = CAM_TAG_ACTION_VALID; 245655371Smjacob atiop->tag_action = MSG_SIMPLE_Q_TAG; 245755371Smjacob break; 2458196008Smjacob case ATIO2_TC_ATTR_HEADOFQ: 2459196008Smjacob atiop->ccb_h.flags = CAM_TAG_ACTION_VALID; 246055371Smjacob atiop->tag_action = MSG_HEAD_OF_Q_TAG; 246155371Smjacob break; 2462196008Smjacob case ATIO2_TC_ATTR_ORDERED: 2463196008Smjacob atiop->ccb_h.flags = CAM_TAG_ACTION_VALID; 246455371Smjacob atiop->tag_action = MSG_ORDERED_Q_TAG; 246555371Smjacob break; 2466196008Smjacob case ATIO2_TC_ATTR_ACAQ: /* ?? */ 246755371Smjacob case ATIO2_TC_ATTR_UNTAGGED: 246855371Smjacob default: 246955371Smjacob atiop->tag_action = 0; 247055371Smjacob break; 247155371Smjacob } 247263385Smjacob 247384242Smjacob atp->orig_datalen = aep->at_datalen; 2474196008Smjacob atp->bytes_xfered = 0; 2475196008Smjacob atp->lun = lun; 2476196008Smjacob atp->nphdl = atiop->init_id; 2477196008Smjacob atp->sid = PORT_ANY; 2478196008Smjacob atp->oxid = aep->at_oxid; 2479196008Smjacob atp->cdb0 = aep->at_cdb[0]; 2480196008Smjacob atp->tattr = aep->at_taskflags & ATIO2_TC_ATTR_MASK; 2481196008Smjacob atp->state = ATPD_STATE_CAM; 2482196008Smjacob xpt_done((union ccb *)atiop); 2483238869Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "ATIO2[0x%x] CDB=0x%x lun %d datalen %u", aep->at_rxid, atp->cdb0, lun, atp->orig_datalen); 2484196008Smjacob rls_lun_statep(isp, tptr); 2485196008Smjacob return; 2486196008Smjacobnoresrc: 2487196008Smjacob ntp = isp_get_ntpd(isp, tptr); 2488196008Smjacob if (ntp == NULL) { 2489196008Smjacob rls_lun_statep(isp, tptr); 2490196008Smjacob isp_endcmd(isp, aep, nphdl, 0, SCSI_STATUS_BUSY, 0); 2491196008Smjacob return; 2492196008Smjacob } 2493196008Smjacob memcpy(ntp->rd.data, aep, QENTRY_LEN); 2494196008Smjacob ntp->rd.nt.nt_hba = tptr->restart_queue; 2495196008Smjacob tptr->restart_queue = ntp; 2496196008Smjacob rls_lun_statep(isp, tptr); 2497196008Smjacob} 2498196008Smjacob 2499196008Smjacobstatic void 2500196008Smjacobisp_handle_platform_atio7(ispsoftc_t *isp, at7_entry_t *aep) 2501196008Smjacob{ 2502196008Smjacob int cdbxlen; 2503196008Smjacob uint16_t lun, chan, nphdl = NIL_HANDLE; 2504196008Smjacob uint32_t did, sid; 2505196008Smjacob uint64_t wwn = INI_NONE; 2506196008Smjacob fcportdb_t *lp; 2507196008Smjacob tstate_t *tptr; 2508196008Smjacob struct ccb_accept_tio *atiop; 2509196008Smjacob atio_private_data_t *atp = NULL; 2510237537Smjacob atio_private_data_t *oatp; 2511196008Smjacob inot_private_data_t *ntp; 2512196008Smjacob 2513196008Smjacob did = (aep->at_hdr.d_id[0] << 16) | (aep->at_hdr.d_id[1] << 8) | aep->at_hdr.d_id[2]; 2514196008Smjacob sid = (aep->at_hdr.s_id[0] << 16) | (aep->at_hdr.s_id[1] << 8) | aep->at_hdr.s_id[2]; 2515196008Smjacob lun = (aep->at_cmnd.fcp_cmnd_lun[0] << 8) | aep->at_cmnd.fcp_cmnd_lun[1]; 2516196008Smjacob 2517196008Smjacob /* 2518196008Smjacob * Find the N-port handle, and Virtual Port Index for this command. 2519196008Smjacob * 2520196008Smjacob * If we can't, we're somewhat in trouble because we can't actually respond w/o that information. 2521196008Smjacob * We also, as a matter of course, need to know the WWN of the initiator too. 2522196008Smjacob */ 2523196008Smjacob if (ISP_CAP_MULTI_ID(isp)) { 2524196008Smjacob /* 2525196008Smjacob * Find the right channel based upon D_ID 2526196008Smjacob */ 2527196008Smjacob isp_find_chan_by_did(isp, did, &chan); 2528196008Smjacob 2529196008Smjacob if (chan == ISP_NOCHAN) { 2530196008Smjacob NANOTIME_T now; 2531196008Smjacob 2532196008Smjacob /* 2533196008Smjacob * If we don't recognizer our own D_DID, terminate the exchange, unless we're within 2 seconds of startup 2534196008Smjacob * It's a bit tricky here as we need to stash this command *somewhere*. 2535196008Smjacob */ 2536196008Smjacob GET_NANOTIME(&now); 2537196008Smjacob if (NANOTIME_SUB(&isp->isp_init_time, &now) > 2000000000ULL) { 2538196008Smjacob isp_prt(isp, ISP_LOGWARN, "%s: [RX_ID 0x%x] D_ID %x not found on any channel- dropping", __func__, aep->at_rxid, did); 2539196008Smjacob isp_endcmd(isp, aep, NIL_HANDLE, ISP_NOCHAN, ECMD_TERMINATE, 0); 2540196008Smjacob return; 2541196008Smjacob } 2542196008Smjacob tptr = get_lun_statep(isp, 0, 0); 2543196008Smjacob if (tptr == NULL) { 2544196008Smjacob tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD); 2545196008Smjacob if (tptr == NULL) { 2546196008Smjacob isp_prt(isp, ISP_LOGWARN, "%s: [RX_ID 0x%x] D_ID %x not found on any channel and no tptr- dropping", __func__, aep->at_rxid, did); 2547196008Smjacob isp_endcmd(isp, aep, NIL_HANDLE, ISP_NOCHAN, ECMD_TERMINATE, 0); 2548196008Smjacob return; 2549196008Smjacob } 2550196008Smjacob } 2551196008Smjacob isp_prt(isp, ISP_LOGWARN, "%s: [RX_ID 0x%x] D_ID %x not found on any channel- deferring", __func__, aep->at_rxid, did); 2552196008Smjacob goto noresrc; 2553196008Smjacob } 2554196008Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: [RX_ID 0x%x] D_ID 0x%06x found on Chan %d for S_ID 0x%06x", __func__, aep->at_rxid, did, chan, sid); 2555196008Smjacob } else { 2556196008Smjacob chan = 0; 2557196008Smjacob } 2558196008Smjacob 2559196008Smjacob /* 2560196008Smjacob * Find the PDB entry for this initiator 2561196008Smjacob */ 2562196008Smjacob if (isp_find_pdb_by_sid(isp, chan, sid, &lp) == 0) { 2563196008Smjacob /* 2564196008Smjacob * If we're not in the port database terminate the exchange. 2565196008Smjacob */ 2566196008Smjacob isp_prt(isp, ISP_LOGTINFO, "%s: [RX_ID 0x%x] D_ID 0x%06x found on Chan %d for S_ID 0x%06x wasn't in PDB already", 2567196008Smjacob __func__, aep->at_rxid, did, chan, sid); 2568196008Smjacob isp_endcmd(isp, aep, NIL_HANDLE, chan, ECMD_TERMINATE, 0); 2569196008Smjacob return; 2570196008Smjacob } 2571196008Smjacob nphdl = lp->handle; 2572196008Smjacob wwn = lp->port_wwn; 2573196008Smjacob 2574196008Smjacob /* 2575196008Smjacob * Get the tstate pointer 2576196008Smjacob */ 2577196008Smjacob tptr = get_lun_statep(isp, chan, lun); 2578196008Smjacob if (tptr == NULL) { 2579196008Smjacob tptr = get_lun_statep(isp, chan, CAM_LUN_WILDCARD); 2580196008Smjacob if (tptr == NULL) { 2581238869Smjacob isp_prt(isp, ISP_LOGWARN, "%s: [0x%x] no state pointer for lun %d or wildcard", __func__, aep->at_rxid, lun); 2582238869Smjacob if (lun == 0) { 2583238869Smjacob isp_endcmd(isp, aep, nphdl, SCSI_STATUS_BUSY, 0); 2584238869Smjacob } else { 2585238869Smjacob isp_endcmd(isp, aep, nphdl, chan, SCSI_STATUS_CHECK_COND | ECMD_SVALID | (0x5 << 12) | (0x25 << 16), 0); 2586238869Smjacob } 2587196008Smjacob return; 2588196008Smjacob } 2589196008Smjacob } 2590196008Smjacob 2591196008Smjacob /* 2592196008Smjacob * Start any commands pending resources first. 2593196008Smjacob */ 2594196008Smjacob if (tptr->restart_queue) { 2595196008Smjacob inot_private_data_t *restart_queue = tptr->restart_queue; 2596196008Smjacob tptr->restart_queue = NULL; 2597196008Smjacob while (restart_queue) { 2598196008Smjacob ntp = restart_queue; 2599196008Smjacob restart_queue = ntp->rd.nt.nt_hba; 2600196008Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: restarting resrc deprived %x", __func__, ((at7_entry_t *)ntp->rd.data)->at_rxid); 2601196008Smjacob isp_handle_platform_atio7(isp, (at7_entry_t *) ntp->rd.data); 2602196008Smjacob isp_put_ntpd(isp, tptr, ntp); 2603196008Smjacob /* 2604196008Smjacob * If a recursion caused the restart queue to start to fill again, 2605196008Smjacob * stop and splice the new list on top of the old list and restore 2606196008Smjacob * it and go to noresrc. 2607196008Smjacob */ 2608196008Smjacob if (tptr->restart_queue) { 2609237537Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: restart queue refilling", __func__); 2610196008Smjacob if (restart_queue) { 2611196008Smjacob ntp = tptr->restart_queue; 2612196008Smjacob tptr->restart_queue = restart_queue; 2613196008Smjacob while (restart_queue->rd.nt.nt_hba) { 2614196008Smjacob restart_queue = restart_queue->rd.nt.nt_hba; 2615196008Smjacob } 2616196008Smjacob restart_queue->rd.nt.nt_hba = ntp; 2617196008Smjacob } 2618196008Smjacob goto noresrc; 2619196008Smjacob } 2620196008Smjacob } 2621196008Smjacob } 2622196008Smjacob 2623196008Smjacob /* 2624196008Smjacob * If the f/w is out of resources, just send a BUSY status back. 2625196008Smjacob */ 2626196008Smjacob if (aep->at_rxid == AT7_NORESRC_RXID) { 2627196008Smjacob rls_lun_statep(isp, tptr); 2628196008Smjacob isp_endcmd(isp, aep, nphdl, chan, SCSI_BUSY, 0); 2629196008Smjacob return; 2630196008Smjacob } 2631196008Smjacob 2632196008Smjacob /* 2633196008Smjacob * If we're out of resources, just send a BUSY status back. 2634196008Smjacob */ 2635196008Smjacob atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); 2636196008Smjacob if (atiop == NULL) { 2637196008Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] out of atios", aep->at_rxid); 2638196008Smjacob goto noresrc; 2639196008Smjacob } 2640196008Smjacob 2641196008Smjacob atp = isp_get_atpd(isp, tptr, 0); 2642196008Smjacob if (atp == NULL) { 2643196008Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] out of atps", aep->at_rxid); 2644196008Smjacob goto noresrc; 2645196008Smjacob } 2646237537Smjacob oatp = isp_get_atpd(isp, tptr, aep->at_rxid); 2647237537Smjacob if (oatp) { 2648238869Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] tag wraparound in isp_handle_platforms_atio7 (N-Port Handle 0x%04x S_ID 0x%04x OX_ID 0x%04x) oatp state %d", 2649237537Smjacob aep->at_rxid, nphdl, sid, aep->at_hdr.ox_id, oatp->state); 2650196008Smjacob /* 2651196008Smjacob * It's not a "no resource" condition- but we can treat it like one 2652196008Smjacob */ 2653196008Smjacob goto noresrc; 2654196008Smjacob } 2655238869Smjacob atp->word3 = lp->prli_word3; 2656196008Smjacob atp->tag = aep->at_rxid; 2657196008Smjacob atp->state = ATPD_STATE_ATIO; 2658196008Smjacob SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); 2659196008Smjacob tptr->atio_count--; 2660238869Smjacob ISP_PATH_PRT(isp, ISP_LOGTDEBUG2, atiop->ccb_h.path, "Take FREE ATIO count now %d\n", tptr->atio_count); 2661196008Smjacob atiop->init_id = nphdl; 2662196008Smjacob atiop->ccb_h.target_id = FCPARAM(isp, chan)->isp_loopid; 2663196008Smjacob atiop->ccb_h.target_lun = lun; 2664196008Smjacob atiop->sense_len = 0; 2665196008Smjacob cdbxlen = aep->at_cmnd.fcp_cmnd_alen_datadir >> FCP_CMND_ADDTL_CDBLEN_SHIFT; 2666196008Smjacob if (cdbxlen) { 2667196008Smjacob isp_prt(isp, ISP_LOGWARN, "additional CDBLEN ignored"); 2668196008Smjacob } 2669196008Smjacob cdbxlen = sizeof (aep->at_cmnd.cdb_dl.sf.fcp_cmnd_cdb); 2670196008Smjacob ISP_MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cmnd.cdb_dl.sf.fcp_cmnd_cdb, cdbxlen); 2671196008Smjacob atiop->cdb_len = cdbxlen; 2672196008Smjacob atiop->ccb_h.status = CAM_CDB_RECVD; 2673196008Smjacob atiop->tag_id = atp->tag; 2674196008Smjacob switch (aep->at_cmnd.fcp_cmnd_task_attribute & FCP_CMND_TASK_ATTR_MASK) { 2675196008Smjacob case FCP_CMND_TASK_ATTR_SIMPLE: 2676196008Smjacob atiop->ccb_h.flags = CAM_TAG_ACTION_VALID; 2677196008Smjacob atiop->tag_action = MSG_SIMPLE_Q_TAG; 2678196008Smjacob break; 2679196008Smjacob case FCP_CMND_TASK_ATTR_HEAD: 2680196008Smjacob atiop->ccb_h.flags = CAM_TAG_ACTION_VALID; 2681196008Smjacob atiop->tag_action = MSG_HEAD_OF_Q_TAG; 2682196008Smjacob break; 2683196008Smjacob case FCP_CMND_TASK_ATTR_ORDERED: 2684196008Smjacob atiop->ccb_h.flags = CAM_TAG_ACTION_VALID; 2685196008Smjacob atiop->tag_action = MSG_ORDERED_Q_TAG; 2686196008Smjacob break; 2687196008Smjacob default: 2688196008Smjacob /* FALLTHROUGH */ 2689196008Smjacob case FCP_CMND_TASK_ATTR_ACA: 2690196008Smjacob case FCP_CMND_TASK_ATTR_UNTAGGED: 2691196008Smjacob atiop->tag_action = 0; 2692196008Smjacob break; 2693196008Smjacob } 2694196008Smjacob atp->orig_datalen = aep->at_cmnd.cdb_dl.sf.fcp_cmnd_dl; 269584242Smjacob atp->bytes_xfered = 0; 2696196008Smjacob atp->lun = lun; 2697196008Smjacob atp->nphdl = nphdl; 2698196008Smjacob atp->portid = sid; 2699196008Smjacob atp->oxid = aep->at_hdr.ox_id; 2700237537Smjacob atp->rxid = aep->at_hdr.rx_id; 2701196008Smjacob atp->cdb0 = atiop->cdb_io.cdb_bytes[0]; 2702196008Smjacob atp->tattr = aep->at_cmnd.fcp_cmnd_task_attribute & FCP_CMND_TASK_ATTR_MASK; 270398289Smjacob atp->state = ATPD_STATE_CAM; 2704238869Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "ATIO7[0x%x] CDB=0x%x lun %d datalen %u", aep->at_rxid, atp->cdb0, lun, atp->orig_datalen); 2705196008Smjacob xpt_done((union ccb *)atiop); 270655371Smjacob rls_lun_statep(isp, tptr); 2707196008Smjacob return; 2708196008Smjacobnoresrc: 2709196008Smjacob if (atp) { 2710196008Smjacob isp_put_atpd(isp, tptr, atp); 2711196008Smjacob } 2712196008Smjacob ntp = isp_get_ntpd(isp, tptr); 2713196008Smjacob if (ntp == NULL) { 2714196008Smjacob rls_lun_statep(isp, tptr); 2715196008Smjacob isp_endcmd(isp, aep, nphdl, chan, SCSI_STATUS_BUSY, 0); 2716196008Smjacob return; 2717196008Smjacob } 2718196008Smjacob memcpy(ntp->rd.data, aep, QENTRY_LEN); 2719196008Smjacob ntp->rd.nt.nt_hba = tptr->restart_queue; 2720196008Smjacob tptr->restart_queue = ntp; 2721196008Smjacob rls_lun_statep(isp, tptr); 272255371Smjacob} 272355371Smjacob 2724238869Smjacob 2725238869Smjacob/* 2726238869Smjacob * Handle starting an SRR (sequence retransmit request) 2727238869Smjacob * We get here when we've gotten the immediate notify 2728238869Smjacob * and the return of all outstanding CTIOs for this 2729238869Smjacob * transaction. 2730238869Smjacob */ 2731196008Smjacobstatic void 2732238869Smjacobisp_handle_srr_start(ispsoftc_t *isp, tstate_t *tptr, atio_private_data_t *atp) 2733238869Smjacob{ 2734238869Smjacob in_fcentry_24xx_t *inot; 2735238869Smjacob uint32_t srr_off, ccb_off, ccb_len, ccb_end; 2736238869Smjacob union ccb *ccb; 2737238869Smjacob 2738238869Smjacob inot = (in_fcentry_24xx_t *)atp->srr; 2739238869Smjacob srr_off = inot->in_srr_reloff_lo | (inot->in_srr_reloff_hi << 16); 2740238869Smjacob ccb = atp->srr_ccb; 2741238869Smjacob atp->srr_ccb = NULL; 2742238869Smjacob atp->nsrr++; 2743238869Smjacob if (ccb == NULL) { 2744239143Smjacob isp_prt(isp, ISP_LOGWARN, "SRR[0x%x] null ccb", atp->tag); 2745238869Smjacob goto fail; 2746238869Smjacob } 2747238869Smjacob 2748238869Smjacob ccb_off = ccb->ccb_h.spriv_field0; 2749238869Smjacob ccb_len = ccb->csio.dxfer_len; 2750238869Smjacob ccb_end = (ccb_off == ~0)? ~0 : ccb_off + ccb_len; 2751238869Smjacob 2752238869Smjacob switch (inot->in_srr_iu) { 2753238869Smjacob case R_CTL_INFO_SOLICITED_DATA: 2754238869Smjacob /* 2755238869Smjacob * We have to restart a FCP_DATA data out transaction 2756238869Smjacob */ 2757238869Smjacob atp->sendst = 0; 2758238869Smjacob atp->bytes_xfered = srr_off; 2759238869Smjacob if (ccb_len == 0) { 2760239143Smjacob isp_prt(isp, ISP_LOGWARN, "SRR[0x%x] SRR offset 0x%x but current CCB doesn't transfer data", atp->tag, srr_off); 2761238869Smjacob goto mdp; 2762238869Smjacob } 2763238869Smjacob if (srr_off < ccb_off || ccb_off > srr_off + ccb_len) { 2764239143Smjacob isp_prt(isp, ISP_LOGWARN, "SRR[0x%x] SRR offset 0x%x not covered by current CCB data range [0x%x..0x%x]", atp->tag, srr_off, ccb_off, ccb_end); 2765238869Smjacob goto mdp; 2766238869Smjacob } 2767239143Smjacob isp_prt(isp, ISP_LOGWARN, "SRR[0x%x] SRR offset 0x%x covered by current CCB data range [0x%x..0x%x]", atp->tag, srr_off, ccb_off, ccb_end); 2768238869Smjacob break; 2769238869Smjacob case R_CTL_INFO_COMMAND_STATUS: 2770239143Smjacob isp_prt(isp, ISP_LOGTINFO, "SRR[0x%x] Got an FCP RSP SRR- resending status", atp->tag); 2771238869Smjacob atp->sendst = 1; 2772238869Smjacob /* 2773238869Smjacob * We have to restart a FCP_RSP IU transaction 2774238869Smjacob */ 2775238869Smjacob break; 2776238869Smjacob case R_CTL_INFO_DATA_DESCRIPTOR: 2777238869Smjacob /* 2778238869Smjacob * We have to restart an FCP DATA in transaction 2779238869Smjacob */ 2780238869Smjacob isp_prt(isp, ISP_LOGWARN, "Got an FCP DATA IN SRR- dropping"); 2781238869Smjacob goto fail; 2782238869Smjacob 2783238869Smjacob default: 2784238869Smjacob isp_prt(isp, ISP_LOGWARN, "Got an unknown information (%x) SRR- dropping", inot->in_srr_iu); 2785238869Smjacob goto fail; 2786238869Smjacob } 2787238869Smjacob 2788238869Smjacob /* 2789238869Smjacob * We can't do anything until this is acked, so we might as well start it now. 2790238869Smjacob * We aren't going to do the usual asynchronous ack issue because we need 2791238869Smjacob * to make sure this gets on the wire first. 2792238869Smjacob */ 2793238869Smjacob if (isp_notify_ack(isp, inot)) { 2794238869Smjacob isp_prt(isp, ISP_LOGWARN, "could not push positive ack for SRR- you lose"); 2795238869Smjacob goto fail; 2796238869Smjacob } 2797238869Smjacob isp_target_start_ctio(isp, ccb, FROM_SRR); 2798238869Smjacob return; 2799238869Smjacobfail: 2800238869Smjacob inot->in_reserved = 1; 2801238869Smjacob isp_async(isp, ISPASYNC_TARGET_NOTIFY_ACK, inot); 2802238869Smjacob ccb->ccb_h.status &= ~CAM_STATUS_MASK; 2803238869Smjacob ccb->ccb_h.status |= CAM_REQ_CMP_ERR; 2804238869Smjacob isp_complete_ctio(ccb); 2805238869Smjacob return; 2806238869Smjacobmdp: 2807238869Smjacob if (isp_notify_ack(isp, inot)) { 2808238869Smjacob isp_prt(isp, ISP_LOGWARN, "could not push positive ack for SRR- you lose"); 2809238869Smjacob goto fail; 2810238869Smjacob } 2811238869Smjacob ccb->ccb_h.status &= ~CAM_STATUS_MASK; 2812238869Smjacob ccb->ccb_h.status = CAM_MESSAGE_RECV; 2813238869Smjacob /* 2814238869Smjacob * This is not a strict interpretation of MDP, but it's close 2815238869Smjacob */ 2816238869Smjacob ccb->csio.msg_ptr = &ccb->csio.sense_data.sense_buf[SSD_FULL_SIZE - 16]; 2817238869Smjacob ccb->csio.msg_len = 7; 2818238869Smjacob ccb->csio.msg_ptr[0] = MSG_EXTENDED; 2819238869Smjacob ccb->csio.msg_ptr[1] = 5; 2820238869Smjacob ccb->csio.msg_ptr[2] = 0; /* modify data pointer */ 2821238869Smjacob ccb->csio.msg_ptr[3] = srr_off >> 24; 2822238869Smjacob ccb->csio.msg_ptr[4] = srr_off >> 16; 2823238869Smjacob ccb->csio.msg_ptr[5] = srr_off >> 8; 2824238869Smjacob ccb->csio.msg_ptr[6] = srr_off; 2825238869Smjacob isp_complete_ctio(ccb); 2826238869Smjacob} 2827238869Smjacob 2828238869Smjacob 2829238869Smjacobstatic void 2830238869Smjacobisp_handle_srr_notify(ispsoftc_t *isp, void *inot_raw) 2831238869Smjacob{ 2832238869Smjacob tstate_t *tptr; 2833238869Smjacob in_fcentry_24xx_t *inot = inot_raw; 2834238869Smjacob atio_private_data_t *atp; 2835238869Smjacob uint32_t tag = inot->in_rxid; 2836238869Smjacob uint32_t bus = inot->in_vpidx; 2837238869Smjacob 2838238869Smjacob if (!IS_24XX(isp)) { 2839238869Smjacob isp_async(isp, ISPASYNC_TARGET_NOTIFY_ACK, inot_raw); 2840238869Smjacob return; 2841238869Smjacob } 2842238869Smjacob 2843238869Smjacob tptr = get_lun_statep_from_tag(isp, bus, tag); 2844238869Smjacob if (tptr == NULL) { 2845238869Smjacob isp_prt(isp, ISP_LOGERR, "%s: cannot find tptr for tag %x in SRR Notify", __func__, tag); 2846238869Smjacob isp_async(isp, ISPASYNC_TARGET_NOTIFY_ACK, inot); 2847238869Smjacob return; 2848238869Smjacob } 2849238869Smjacob atp = isp_get_atpd(isp, tptr, tag); 2850238869Smjacob if (atp == NULL) { 2851238869Smjacob rls_lun_statep(isp, tptr); 2852238869Smjacob isp_prt(isp, ISP_LOGERR, "%s: cannot find adjunct for %x in SRR Notify", __func__, tag); 2853238869Smjacob isp_async(isp, ISPASYNC_TARGET_NOTIFY_ACK, inot); 2854238869Smjacob return; 2855238869Smjacob } 2856238869Smjacob atp->srr_notify_rcvd = 1; 2857238869Smjacob memcpy(atp->srr, inot, sizeof (atp->srr)); 2858239143Smjacob isp_prt(isp, ISP_LOGTINFO /* ISP_LOGTDEBUG0 */, "SRR[0x%x] inot->in_rxid flags 0x%x srr_iu=%x reloff 0x%x", inot->in_rxid, inot->in_flags, inot->in_srr_iu, 2859238869Smjacob inot->in_srr_reloff_lo | (inot->in_srr_reloff_hi << 16)); 2860238869Smjacob if (atp->srr_ccb) 2861238869Smjacob isp_handle_srr_start(isp, tptr, atp); 2862238869Smjacob rls_lun_statep(isp, tptr); 2863238869Smjacob} 2864238869Smjacob 2865238869Smjacobstatic void 2866157943Smjacobisp_handle_platform_ctio(ispsoftc_t *isp, void *arg) 286755371Smjacob{ 286855371Smjacob union ccb *ccb; 2869239143Smjacob int sentstatus = 0, ok = 0, notify_cam = 0, resid = 0, failure = 0; 2870196008Smjacob tstate_t *tptr = NULL; 2871196008Smjacob atio_private_data_t *atp = NULL; 2872196008Smjacob int bus; 2873239143Smjacob uint32_t handle, moved_data = 0, data_requested; 287455371Smjacob 287555371Smjacob /* 2876204397Smjacob * CTIO handles are 16 bits. 2877204397Smjacob * CTIO2 and CTIO7 are 32 bits. 287855371Smjacob */ 287955371Smjacob 2880196008Smjacob if (IS_SCSI(isp)) { 2881196008Smjacob handle = ((ct_entry_t *)arg)->ct_syshandle; 2882196008Smjacob } else { 2883196008Smjacob handle = ((ct2_entry_t *)arg)->ct_syshandle; 2884196008Smjacob } 2885196008Smjacob ccb = isp_find_xs_tgt(isp, handle); 2886196008Smjacob if (ccb == NULL) { 2887196008Smjacob isp_print_bytes(isp, "null ccb in isp_handle_platform_ctio", QENTRY_LEN, arg); 2888196008Smjacob return; 2889196008Smjacob } 2890196008Smjacob isp_destroy_tgt_handle(isp, handle); 2891239143Smjacob data_requested = PISP_PCMD(ccb)->datalen; 2892238869Smjacob isp_free_pcmd(isp, ccb); 2893238869Smjacob if (isp->isp_nactive) { 2894238869Smjacob isp->isp_nactive--; 2895238869Smjacob } 2896238869Smjacob 2897196008Smjacob bus = XS_CHANNEL(ccb); 2898196008Smjacob tptr = get_lun_statep(isp, bus, XS_LUN(ccb)); 2899196008Smjacob if (tptr == NULL) { 2900196008Smjacob tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD); 2901196008Smjacob } 2902238869Smjacob if (tptr == NULL) { 2903238869Smjacob isp_prt(isp, ISP_LOGERR, "%s: cannot find tptr for tag %x after I/O", __func__, ccb->csio.tag_id); 2904238869Smjacob return; 2905196008Smjacob } 2906238869Smjacob 2907196008Smjacob if (IS_24XX(isp)) { 2908238869Smjacob atp = isp_get_atpd(isp, tptr, ((ct7_entry_t *)arg)->ct_rxid); 2909238869Smjacob } else if (IS_FC(isp)) { 2910238869Smjacob atp = isp_get_atpd(isp, tptr, ((ct2_entry_t *)arg)->ct_rxid); 2911238869Smjacob } else { 2912238869Smjacob atp = isp_get_atpd(isp, tptr, ((ct_entry_t *)arg)->ct_fwhandle); 2913238869Smjacob } 2914238869Smjacob if (atp == NULL) { 2915238869Smjacob rls_lun_statep(isp, tptr); 2916238869Smjacob isp_prt(isp, ISP_LOGERR, "%s: cannot find adjunct for %x after I/O", __func__, ccb->csio.tag_id); 2917238869Smjacob return; 2918238869Smjacob } 2919238869Smjacob KASSERT((atp->ctcnt > 0), ("ctio count not greater than zero")); 2920239143Smjacob atp->bytes_in_transit -= data_requested; 2921238869Smjacob atp->ctcnt -= 1; 2922238869Smjacob ccb->ccb_h.status &= ~CAM_STATUS_MASK; 2923238869Smjacob 2924238869Smjacob if (IS_24XX(isp)) { 2925196008Smjacob ct7_entry_t *ct = arg; 292655371Smjacob 2927238869Smjacob if (ct->ct_nphdl == CT7_SRR) { 2928238869Smjacob atp->srr_ccb = ccb; 2929238869Smjacob if (atp->srr_notify_rcvd) 2930238869Smjacob isp_handle_srr_start(isp, tptr, atp); 2931196008Smjacob rls_lun_statep(isp, tptr); 2932196008Smjacob return; 2933196008Smjacob } 2934196008Smjacob if (ct->ct_nphdl == CT_HBA_RESET) { 2935238869Smjacob failure = CAM_UNREC_HBA_ERROR; 2936238869Smjacob } else { 2937238869Smjacob sentstatus = ct->ct_flags & CT7_SENDSTATUS; 2938238869Smjacob ok = (ct->ct_nphdl == CT7_OK); 2939239143Smjacob notify_cam = (ct->ct_header.rqs_seqno & ATPD_SEQ_NOTIFY_CAM) != 0; 2940238869Smjacob if ((ct->ct_flags & CT7_DATAMASK) != CT7_NO_DATA) { 2941238869Smjacob resid = ct->ct_resid; 2942239143Smjacob moved_data = data_requested - resid; 2943238869Smjacob } 2944196008Smjacob } 2945239143Smjacob isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, "%s: CTIO7[%x] seq %u nc %d sts 0x%x flg 0x%x sns %d resid %d %s", __func__, ct->ct_rxid, ATPD_GET_SEQNO(ct), 2946239143Smjacob notify_cam, ct->ct_nphdl, ct->ct_flags, (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, resid, sentstatus? "FIN" : "MID"); 2947196008Smjacob } else if (IS_FC(isp)) { 294855371Smjacob ct2_entry_t *ct = arg; 2949238869Smjacob if (ct->ct_status == CT_SRR) { 2950238869Smjacob atp->srr_ccb = ccb; 2951238869Smjacob if (atp->srr_notify_rcvd) 2952238869Smjacob isp_handle_srr_start(isp, tptr, atp); 2953196008Smjacob rls_lun_statep(isp, tptr); 2954238869Smjacob isp_target_putback_atio(ccb); 2955196008Smjacob return; 295698289Smjacob } 2957196008Smjacob if (ct->ct_status == CT_HBA_RESET) { 2958238869Smjacob failure = CAM_UNREC_HBA_ERROR; 2959238869Smjacob } else { 2960238869Smjacob sentstatus = ct->ct_flags & CT2_SENDSTATUS; 2961238869Smjacob ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; 2962239143Smjacob notify_cam = (ct->ct_header.rqs_seqno & ATPD_SEQ_NOTIFY_CAM) != 0; 2963238869Smjacob if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) { 2964238869Smjacob resid = ct->ct_resid; 2965239143Smjacob moved_data = data_requested - resid; 2966238869Smjacob } 296798289Smjacob } 2968239143Smjacob isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, "%s: CTIO2[%x] seq %u nc %d sts 0x%x flg 0x%x sns %d resid %d %s", __func__, ct->ct_rxid, ATPD_GET_SEQNO(ct), 2969239143Smjacob notify_cam, ct->ct_status, ct->ct_flags, (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, resid, sentstatus? "FIN" : "MID"); 297055371Smjacob } else { 297155371Smjacob ct_entry_t *ct = arg; 2972238869Smjacob 2973196008Smjacob if (ct->ct_status == (CT_HBA_RESET & 0xff)) { 2974238869Smjacob failure = CAM_UNREC_HBA_ERROR; 2975238869Smjacob } else { 2976238869Smjacob sentstatus = ct->ct_flags & CT_SENDSTATUS; 2977238869Smjacob ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; 2978239143Smjacob notify_cam = (ct->ct_header.rqs_seqno & ATPD_SEQ_NOTIFY_CAM) != 0; 297975200Smjacob } 298077365Smjacob if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) { 298175200Smjacob resid = ct->ct_resid; 2982239143Smjacob moved_data = data_requested - resid; 298377365Smjacob } 2984239143Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO[%x] seq %u nc %d tag %x S_ID 0x%x lun %d sts %x flg %x resid %d %s", __func__, ct->ct_fwhandle, ATPD_GET_SEQNO(ct), 2985239143Smjacob notify_cam, ct->ct_tag_val, ct->ct_iid, ct->ct_lun, ct->ct_status, ct->ct_flags, resid, sentstatus? "FIN" : "MID"); 298655371Smjacob } 2987238869Smjacob if (ok) { 2988238869Smjacob if (moved_data) { 2989239143Smjacob atp->bytes_xfered += moved_data; 2990239143Smjacob ccb->csio.resid = atp->orig_datalen - atp->bytes_xfered - atp->bytes_in_transit; 2991238869Smjacob } 2992238869Smjacob if (sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) { 2993238869Smjacob ccb->ccb_h.status |= CAM_SENT_SENSE; 2994238869Smjacob } 2995238869Smjacob ccb->ccb_h.status |= CAM_REQ_CMP; 2996238869Smjacob } else { 2997238869Smjacob notify_cam = 1; 2998238869Smjacob if (failure == CAM_UNREC_HBA_ERROR) 2999238869Smjacob ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR; 3000238869Smjacob else 3001238869Smjacob ccb->ccb_h.status |= CAM_REQ_CMP_ERR; 3002238869Smjacob } 3003238869Smjacob atp->state = ATPD_STATE_PDON; 3004238869Smjacob rls_lun_statep(isp, tptr); 300555371Smjacob 300655371Smjacob /* 3007238869Smjacob * We never *not* notify CAM when there has been any error (ok == 0), 3008238869Smjacob * so we never need to do an ATIO putback if we're not notifying CAM. 300955371Smjacob */ 3010239143Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO[0x%x] done (ok=%d nc=%d nowsendstatus=%d ccb ss=%d)", 3011239143Smjacob (sentstatus)? " FINAL " : "MIDTERM ", atp->tag, ok, notify_cam, atp->sendst, (ccb->ccb_h.flags & CAM_SEND_STATUS) != 0); 301263385Smjacob if (notify_cam == 0) { 3013238869Smjacob if (atp->sendst) { 3014238869Smjacob isp_target_start_ctio(isp, ccb, FROM_CTIO_DONE); 3015238869Smjacob } 3016196008Smjacob return; 301763385Smjacob } 301875200Smjacob 3019238869Smjacob /* 3020238869Smjacob * We're telling CAM we're done with this CTIO transaction. 3021238869Smjacob * 3022238869Smjacob * 24XX cards never need an ATIO put back. 3023238869Smjacob * 3024238869Smjacob * Other cards need one put back only on error. 3025238869Smjacob * In the latter case, a timeout will re-fire 3026238869Smjacob * and try again in case we didn't have 3027238869Smjacob * queue resources to do so at first. In any case, 3028238869Smjacob * once the putback is done we do the completion 3029238869Smjacob * call. 3030238869Smjacob */ 3031238869Smjacob if (ok || IS_24XX(isp)) { 3032238869Smjacob isp_complete_ctio(ccb); 3033238869Smjacob } else { 303475200Smjacob isp_target_putback_atio(ccb); 303563385Smjacob } 303663385Smjacob} 303798289Smjacob 3038196008Smjacobstatic void 3039196008Smjacobisp_handle_platform_notify_scsi(ispsoftc_t *isp, in_entry_t *inot) 304098289Smjacob{ 3041238869Smjacob isp_async(isp, ISPASYNC_TARGET_NOTIFY_ACK, inot); 304298289Smjacob} 304398289Smjacob 3044196008Smjacobstatic void 3045157943Smjacobisp_handle_platform_notify_fc(ispsoftc_t *isp, in_fcentry_t *inp) 304698289Smjacob{ 3047196008Smjacob int needack = 1; 304898289Smjacob switch (inp->in_status) { 304998289Smjacob case IN_PORT_LOGOUT: 3050196008Smjacob /* 3051196008Smjacob * XXX: Need to delete this initiator's WWN from the database 3052196008Smjacob * XXX: Need to send this LOGOUT upstream 3053196008Smjacob */ 3054196008Smjacob isp_prt(isp, ISP_LOGWARN, "port logout of S_ID 0x%x", inp->in_iid); 305598289Smjacob break; 305698289Smjacob case IN_PORT_CHANGED: 3057196008Smjacob isp_prt(isp, ISP_LOGWARN, "port changed for S_ID 0x%x", inp->in_iid); 305898289Smjacob break; 305998289Smjacob case IN_GLOBAL_LOGO: 3060196008Smjacob isp_del_all_wwn_entries(isp, 0); 306198289Smjacob isp_prt(isp, ISP_LOGINFO, "all ports logged out"); 306298289Smjacob break; 306398289Smjacob case IN_ABORT_TASK: 306498289Smjacob { 3065196008Smjacob tstate_t *tptr; 3066196008Smjacob uint16_t lun; 3067196008Smjacob uint32_t loopid; 3068196008Smjacob uint64_t wwn; 3069196008Smjacob atio_private_data_t *atp; 3070196008Smjacob fcportdb_t *lp; 3071196008Smjacob struct ccb_immediate_notify *inot = NULL; 307298289Smjacob 3073196008Smjacob if (ISP_CAP_SCCFW(isp)) { 3074196008Smjacob lun = inp->in_scclun; 3075196008Smjacob } else { 3076196008Smjacob lun = inp->in_lun; 3077196008Smjacob } 3078196008Smjacob if (ISP_CAP_2KLOGIN(isp)) { 3079208761Smjacob loopid = ((in_fcentry_e_t *)inp)->in_iid; 3080196008Smjacob } else { 3081196008Smjacob loopid = inp->in_iid; 3082196008Smjacob } 3083196008Smjacob if (isp_find_pdb_by_loopid(isp, 0, loopid, &lp)) { 3084196008Smjacob wwn = lp->port_wwn; 3085196008Smjacob } else { 3086196008Smjacob wwn = INI_ANY; 3087196008Smjacob } 3088196008Smjacob tptr = get_lun_statep(isp, 0, lun); 3089196008Smjacob if (tptr == NULL) { 3090196008Smjacob tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD); 3091196008Smjacob if (tptr == NULL) { 3092196008Smjacob isp_prt(isp, ISP_LOGWARN, "ABORT TASK for lun %u- but no tstate", lun); 3093196008Smjacob return; 3094196008Smjacob } 3095196008Smjacob } 3096196008Smjacob atp = isp_get_atpd(isp, tptr, inp->in_seqid); 3097196008Smjacob 309898289Smjacob if (atp) { 3099196008Smjacob inot = (struct ccb_immediate_notify *) SLIST_FIRST(&tptr->inots); 3100196008Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "ABORT TASK RX_ID %x WWN 0x%016llx state %d", inp->in_seqid, (unsigned long long) wwn, atp->state); 3101196008Smjacob if (inot) { 3102196008Smjacob tptr->inot_count--; 3103196008Smjacob SLIST_REMOVE_HEAD(&tptr->inots, sim_links.sle); 3104238869Smjacob ISP_PATH_PRT(isp, ISP_LOGTDEBUG2, inot->ccb_h.path, "%s: Take FREE INOT count now %d\n", __func__, tptr->inot_count); 3105196008Smjacob } else { 3106238869Smjacob ISP_PATH_PRT(isp, ISP_LOGWARN, tptr->owner, "out of INOT structures\n"); 310798289Smjacob } 310898289Smjacob } else { 3109196008Smjacob ISP_PATH_PRT(isp, ISP_LOGWARN, tptr->owner, "abort task RX_ID %x from wwn 0x%016llx, state unknown\n", inp->in_seqid, wwn); 311098289Smjacob } 311198289Smjacob if (inot) { 3112196008Smjacob isp_notify_t tmp, *nt = &tmp; 3113196008Smjacob ISP_MEMZERO(nt, sizeof (isp_notify_t)); 3114196008Smjacob nt->nt_hba = isp; 3115196008Smjacob nt->nt_tgt = FCPARAM(isp, 0)->isp_wwpn; 3116196008Smjacob nt->nt_wwn = wwn; 3117196008Smjacob nt->nt_nphdl = loopid; 3118196008Smjacob nt->nt_sid = PORT_ANY; 3119196008Smjacob nt->nt_did = PORT_ANY; 3120196008Smjacob nt->nt_lun = lun; 3121196008Smjacob nt->nt_need_ack = 1; 3122196008Smjacob nt->nt_channel = 0; 3123196008Smjacob nt->nt_ncode = NT_ABORT_TASK; 3124196008Smjacob nt->nt_lreserved = inot; 3125196008Smjacob isp_handle_platform_target_tmf(isp, nt); 3126196008Smjacob needack = 0; 312798289Smjacob } 3128196008Smjacob rls_lun_statep(isp, tptr); 312998289Smjacob break; 313098289Smjacob } 313198289Smjacob default: 313298289Smjacob break; 313398289Smjacob } 3134196008Smjacob if (needack) { 3135238869Smjacob isp_async(isp, ISPASYNC_TARGET_NOTIFY_ACK, inp); 3136196008Smjacob } 3137196008Smjacob} 3138196008Smjacob 3139196008Smjacobstatic void 3140196008Smjacobisp_handle_platform_notify_24xx(ispsoftc_t *isp, in_fcentry_24xx_t *inot) 3141196008Smjacob{ 3142196008Smjacob uint16_t nphdl; 3143238869Smjacob uint16_t prli_options = 0; 3144196008Smjacob uint32_t portid; 3145196008Smjacob fcportdb_t *lp; 3146196008Smjacob uint8_t *ptr = NULL; 3147196008Smjacob uint64_t wwn; 3148196008Smjacob 3149196008Smjacob nphdl = inot->in_nphdl; 3150196008Smjacob if (nphdl != NIL_HANDLE) { 3151196008Smjacob portid = inot->in_portid_hi << 16 | inot->in_portid_lo; 3152196008Smjacob } else { 3153196008Smjacob portid = PORT_ANY; 3154196008Smjacob } 3155196008Smjacob 3156196008Smjacob switch (inot->in_status) { 3157196008Smjacob case IN24XX_ELS_RCVD: 3158196008Smjacob { 3159196008Smjacob char buf[16], *msg; 3160196008Smjacob int chan = ISP_GET_VPIDX(isp, inot->in_vpidx); 3161196008Smjacob 3162196008Smjacob /* 3163196008Smjacob * Note that we're just getting notification that an ELS was received 3164215034Sbrucec * (possibly with some associated information sent upstream). This is 3165196008Smjacob * *not* the same as being given the ELS frame to accept or reject. 3166196008Smjacob */ 3167196008Smjacob switch (inot->in_status_subcode) { 3168196008Smjacob case LOGO: 3169196008Smjacob msg = "LOGO"; 3170196008Smjacob if (ISP_FW_NEWER_THAN(isp, 4, 0, 25)) { 3171196008Smjacob ptr = (uint8_t *)inot; /* point to unswizzled entry! */ 3172196008Smjacob wwn = (((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF]) << 56) | 3173196008Smjacob (((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+1]) << 48) | 3174196008Smjacob (((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+2]) << 40) | 3175196008Smjacob (((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+3]) << 32) | 3176196008Smjacob (((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+4]) << 24) | 3177196008Smjacob (((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+5]) << 16) | 3178196008Smjacob (((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+6]) << 8) | 3179196008Smjacob (((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+7])); 3180196008Smjacob } else { 3181196008Smjacob wwn = INI_ANY; 3182196008Smjacob } 3183196008Smjacob isp_del_wwn_entry(isp, chan, wwn, nphdl, portid); 3184196008Smjacob break; 3185196008Smjacob case PRLO: 3186196008Smjacob msg = "PRLO"; 3187196008Smjacob break; 3188196008Smjacob case PLOGI: 3189208542Smjacob case PRLI: 3190208542Smjacob /* 3191208542Smjacob * Treat PRLI the same as PLOGI and make a database entry for it. 3192208542Smjacob */ 3193238869Smjacob if (inot->in_status_subcode == PLOGI) { 3194208542Smjacob msg = "PLOGI"; 3195238869Smjacob } else { 3196238869Smjacob prli_options = inot->in_prli_options; 3197208542Smjacob msg = "PRLI"; 3198238869Smjacob } 3199196008Smjacob if (ISP_FW_NEWER_THAN(isp, 4, 0, 25)) { 3200196008Smjacob ptr = (uint8_t *)inot; /* point to unswizzled entry! */ 3201196008Smjacob wwn = (((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF]) << 56) | 3202196008Smjacob (((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+1]) << 48) | 3203196008Smjacob (((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+2]) << 40) | 3204196008Smjacob (((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+3]) << 32) | 3205196008Smjacob (((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+4]) << 24) | 3206196008Smjacob (((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+5]) << 16) | 3207196008Smjacob (((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+6]) << 8) | 3208196008Smjacob (((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+7])); 3209196008Smjacob } else { 3210196008Smjacob wwn = INI_NONE; 3211196008Smjacob } 3212238869Smjacob isp_add_wwn_entry(isp, chan, wwn, nphdl, portid, prli_options); 3213196008Smjacob break; 3214196008Smjacob case PDISC: 3215196008Smjacob msg = "PDISC"; 3216196008Smjacob break; 3217196008Smjacob case ADISC: 3218196008Smjacob msg = "ADISC"; 3219196008Smjacob break; 3220196008Smjacob default: 3221196008Smjacob ISP_SNPRINTF(buf, sizeof (buf), "ELS 0x%x", inot->in_status_subcode); 3222196008Smjacob msg = buf; 3223196008Smjacob break; 3224196008Smjacob } 3225196008Smjacob if (inot->in_flags & IN24XX_FLAG_PUREX_IOCB) { 3226196008Smjacob isp_prt(isp, ISP_LOGERR, "%s Chan %d ELS N-port handle %x PortID 0x%06x marked as needing a PUREX response", msg, chan, nphdl, portid); 3227196008Smjacob break; 3228196008Smjacob } 3229196008Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "%s Chan %d ELS N-port handle %x PortID 0x%06x RX_ID 0x%x OX_ID 0x%x", msg, chan, nphdl, portid, 3230196008Smjacob inot->in_rxid, inot->in_oxid); 3231238869Smjacob isp_async(isp, ISPASYNC_TARGET_NOTIFY_ACK, inot); 3232196008Smjacob break; 3233196008Smjacob } 3234196008Smjacob 3235196008Smjacob case IN24XX_PORT_LOGOUT: 3236196008Smjacob ptr = "PORT LOGOUT"; 3237196008Smjacob if (isp_find_pdb_by_loopid(isp, ISP_GET_VPIDX(isp, inot->in_vpidx), nphdl, &lp)) { 3238196008Smjacob isp_del_wwn_entry(isp, ISP_GET_VPIDX(isp, inot->in_vpidx), lp->port_wwn, nphdl, lp->portid); 3239196008Smjacob } 3240196008Smjacob /* FALLTHROUGH */ 3241196008Smjacob case IN24XX_PORT_CHANGED: 3242196008Smjacob if (ptr == NULL) { 3243196008Smjacob ptr = "PORT CHANGED"; 3244196008Smjacob } 3245196008Smjacob /* FALLTHROUGH */ 3246196008Smjacob case IN24XX_LIP_RESET: 3247196008Smjacob if (ptr == NULL) { 3248196008Smjacob ptr = "LIP RESET"; 3249196008Smjacob } 3250196008Smjacob isp_prt(isp, ISP_LOGINFO, "Chan %d %s (sub-status 0x%x) for N-port handle 0x%x", ISP_GET_VPIDX(isp, inot->in_vpidx), ptr, inot->in_status_subcode, nphdl); 3251196008Smjacob 3252196008Smjacob /* 3253196008Smjacob * All subcodes here are irrelevant. What is relevant 3254196008Smjacob * is that we need to terminate all active commands from 3255196008Smjacob * this initiator (known by N-port handle). 3256196008Smjacob */ 3257196008Smjacob /* XXX IMPLEMENT XXX */ 3258238869Smjacob isp_async(isp, ISPASYNC_TARGET_NOTIFY_ACK, inot); 3259196008Smjacob break; 3260196008Smjacob 3261238869Smjacob case IN24XX_SRR_RCVD: 3262238869Smjacob#ifdef ISP_TARGET_MODE 3263238869Smjacob isp_handle_srr_notify(isp, inot); 3264238869Smjacob break; 3265238869Smjacob#else 3266238869Smjacob if (ptr == NULL) { 3267238869Smjacob ptr = "SRR RCVD"; 3268238869Smjacob } 3269238869Smjacob /* FALLTHROUGH */ 3270238869Smjacob#endif 3271196008Smjacob case IN24XX_LINK_RESET: 3272238869Smjacob if (ptr == NULL) { 3273238869Smjacob ptr = "LINK RESET"; 3274238869Smjacob } 3275196008Smjacob case IN24XX_LINK_FAILED: 3276238869Smjacob if (ptr == NULL) { 3277238869Smjacob ptr = "LINK FAILED"; 3278238869Smjacob } 3279196008Smjacob default: 3280238869Smjacob isp_prt(isp, ISP_LOGWARN, "Chan %d %s", ISP_GET_VPIDX(isp, inot->in_vpidx), ptr); 3281238869Smjacob isp_async(isp, ISPASYNC_TARGET_NOTIFY_ACK, inot); 3282196008Smjacob break; 3283196008Smjacob } 3284196008Smjacob} 3285196008Smjacob 3286196008Smjacobstatic int 3287196008Smjacobisp_handle_platform_target_notify_ack(ispsoftc_t *isp, isp_notify_t *mp) 3288196008Smjacob{ 3289196008Smjacob 3290196008Smjacob if (isp->isp_state != ISP_RUNSTATE) { 3291196008Smjacob isp_prt(isp, ISP_LOGTINFO, "Notify Code 0x%x (qevalid=%d) acked- h/w not ready (dropping)", mp->nt_ncode, mp->nt_lreserved != NULL); 3292196008Smjacob return (0); 3293196008Smjacob } 3294196008Smjacob 3295196008Smjacob /* 3296196008Smjacob * This case is for a Task Management Function, which shows up as an ATIO7 entry. 3297196008Smjacob */ 3298196008Smjacob if (IS_24XX(isp) && mp->nt_lreserved && ((isphdr_t *)mp->nt_lreserved)->rqs_entry_type == RQSTYPE_ATIO) { 3299196008Smjacob ct7_entry_t local, *cto = &local; 3300196008Smjacob at7_entry_t *aep = (at7_entry_t *)mp->nt_lreserved; 3301196008Smjacob fcportdb_t *lp; 3302196008Smjacob uint32_t sid; 3303196008Smjacob uint16_t nphdl; 3304196008Smjacob 3305196008Smjacob sid = (aep->at_hdr.s_id[0] << 16) | (aep->at_hdr.s_id[1] << 8) | aep->at_hdr.s_id[2]; 3306196008Smjacob if (isp_find_pdb_by_sid(isp, mp->nt_channel, sid, &lp)) { 3307196008Smjacob nphdl = lp->handle; 3308196008Smjacob } else { 3309196008Smjacob nphdl = NIL_HANDLE; 3310196008Smjacob } 3311196008Smjacob ISP_MEMZERO(&local, sizeof (local)); 3312196008Smjacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7; 3313196008Smjacob cto->ct_header.rqs_entry_count = 1; 3314196008Smjacob cto->ct_nphdl = nphdl; 3315196008Smjacob cto->ct_rxid = aep->at_rxid; 3316196008Smjacob cto->ct_vpidx = mp->nt_channel; 3317196008Smjacob cto->ct_iid_lo = sid; 3318196008Smjacob cto->ct_iid_hi = sid >> 16; 3319196008Smjacob cto->ct_oxid = aep->at_hdr.ox_id; 3320196008Smjacob cto->ct_flags = CT7_SENDSTATUS|CT7_NOACK|CT7_NO_DATA|CT7_FLAG_MODE1; 3321196008Smjacob cto->ct_flags |= (aep->at_ta_len >> 12) << CT7_TASK_ATTR_SHIFT; 3322196008Smjacob return (isp_target_put_entry(isp, &local)); 3323196008Smjacob } 3324196008Smjacob 3325196008Smjacob /* 3326196008Smjacob * This case is for a responding to an ABTS frame 3327196008Smjacob */ 3328196008Smjacob if (IS_24XX(isp) && mp->nt_lreserved && ((isphdr_t *)mp->nt_lreserved)->rqs_entry_type == RQSTYPE_ABTS_RCVD) { 3329196008Smjacob 3330196008Smjacob /* 3331196008Smjacob * Overload nt_need_ack here to mark whether we've terminated the associated command. 3332196008Smjacob */ 3333196008Smjacob if (mp->nt_need_ack) { 3334196008Smjacob uint8_t storage[QENTRY_LEN]; 3335196008Smjacob ct7_entry_t *cto = (ct7_entry_t *) storage; 3336196008Smjacob abts_t *abts = (abts_t *)mp->nt_lreserved; 3337196008Smjacob 3338196008Smjacob ISP_MEMZERO(cto, sizeof (ct7_entry_t)); 3339196008Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: [%x] terminating after ABTS received", __func__, abts->abts_rxid_task); 3340196008Smjacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7; 3341196008Smjacob cto->ct_header.rqs_entry_count = 1; 3342196008Smjacob cto->ct_nphdl = mp->nt_nphdl; 3343196008Smjacob cto->ct_rxid = abts->abts_rxid_task; 3344196008Smjacob cto->ct_iid_lo = mp->nt_sid; 3345196008Smjacob cto->ct_iid_hi = mp->nt_sid >> 16; 3346196008Smjacob cto->ct_oxid = abts->abts_ox_id; 3347196008Smjacob cto->ct_vpidx = mp->nt_channel; 3348196008Smjacob cto->ct_flags = CT7_NOACK|CT7_TERMINATE; 3349196008Smjacob if (isp_target_put_entry(isp, cto)) { 3350196008Smjacob return (ENOMEM); 3351196008Smjacob } 3352196008Smjacob mp->nt_need_ack = 0; 3353196008Smjacob } 3354196008Smjacob if (isp_acknak_abts(isp, mp->nt_lreserved, 0) == ENOMEM) { 3355196008Smjacob return (ENOMEM); 3356196008Smjacob } else { 3357196008Smjacob return (0); 3358196008Smjacob } 3359196008Smjacob } 3360196008Smjacob 3361196008Smjacob /* 3362196008Smjacob * Handle logout cases here 3363196008Smjacob */ 3364196008Smjacob if (mp->nt_ncode == NT_GLOBAL_LOGOUT) { 3365196008Smjacob isp_del_all_wwn_entries(isp, mp->nt_channel); 3366196008Smjacob } 3367196008Smjacob 3368196008Smjacob if (mp->nt_ncode == NT_LOGOUT) { 3369196008Smjacob if (!IS_2100(isp) && IS_FC(isp)) { 3370196008Smjacob isp_del_wwn_entries(isp, mp); 3371196008Smjacob } 3372196008Smjacob } 3373196008Smjacob 3374196008Smjacob /* 3375196008Smjacob * General purpose acknowledgement 3376196008Smjacob */ 3377196008Smjacob if (mp->nt_need_ack) { 3378196008Smjacob isp_prt(isp, ISP_LOGTINFO, "Notify Code 0x%x (qevalid=%d) being acked", mp->nt_ncode, mp->nt_lreserved != NULL); 3379238869Smjacob /* 3380238869Smjacob * Don't need to use the guaranteed send because the caller can retry 3381238869Smjacob */ 3382196008Smjacob return (isp_notify_ack(isp, mp->nt_lreserved)); 3383196008Smjacob } 338498289Smjacob return (0); 338598289Smjacob} 3386196008Smjacob 3387196008Smjacob/* 3388215034Sbrucec * Handle task management functions. 3389196008Smjacob * 3390196008Smjacob * We show up here with a notify structure filled out. 3391196008Smjacob * 3392196008Smjacob * The nt_lreserved tag points to the original queue entry 3393196008Smjacob */ 3394196008Smjacobstatic void 3395196008Smjacobisp_handle_platform_target_tmf(ispsoftc_t *isp, isp_notify_t *notify) 3396196008Smjacob{ 3397196008Smjacob tstate_t *tptr; 3398196008Smjacob fcportdb_t *lp; 3399196008Smjacob struct ccb_immediate_notify *inot; 3400196008Smjacob inot_private_data_t *ntp = NULL; 3401196008Smjacob lun_id_t lun; 3402196008Smjacob 3403196008Smjacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: code 0x%x sid 0x%x tagval 0x%016llx chan %d lun 0x%x", __func__, notify->nt_ncode, 3404196008Smjacob notify->nt_sid, (unsigned long long) notify->nt_tagval, notify->nt_channel, notify->nt_lun); 3405196008Smjacob /* 3406196008Smjacob * NB: This assignment is necessary because of tricky type conversion. 3407196008Smjacob * XXX: This is tricky and I need to check this. If the lun isn't known 3408196008Smjacob * XXX: for the task management function, it does not of necessity follow 3409196008Smjacob * XXX: that it should go up stream to the wildcard listener. 3410196008Smjacob */ 3411196008Smjacob if (notify->nt_lun == LUN_ANY) { 3412196008Smjacob lun = CAM_LUN_WILDCARD; 3413196008Smjacob } else { 3414196008Smjacob lun = notify->nt_lun; 3415196008Smjacob } 3416196008Smjacob tptr = get_lun_statep(isp, notify->nt_channel, lun); 3417196008Smjacob if (tptr == NULL) { 3418196008Smjacob tptr = get_lun_statep(isp, notify->nt_channel, CAM_LUN_WILDCARD); 3419196008Smjacob if (tptr == NULL) { 3420196008Smjacob isp_prt(isp, ISP_LOGWARN, "%s: no state pointer found for chan %d lun 0x%x", __func__, notify->nt_channel, lun); 3421196008Smjacob goto bad; 3422196008Smjacob } 3423196008Smjacob } 3424196008Smjacob inot = (struct ccb_immediate_notify *) SLIST_FIRST(&tptr->inots); 3425196008Smjacob if (inot == NULL) { 3426196008Smjacob isp_prt(isp, ISP_LOGWARN, "%s: out of immediate notify structures for chan %d lun 0x%x", __func__, notify->nt_channel, lun); 3427196008Smjacob goto bad; 3428196008Smjacob } 3429196008Smjacob 3430196008Smjacob if (isp_find_pdb_by_sid(isp, notify->nt_channel, notify->nt_sid, &lp) == 0) { 3431196008Smjacob inot->initiator_id = CAM_TARGET_WILDCARD; 3432196008Smjacob } else { 3433196008Smjacob inot->initiator_id = lp->handle; 3434196008Smjacob } 3435196008Smjacob inot->seq_id = notify->nt_tagval; 3436196008Smjacob inot->tag_id = notify->nt_tagval >> 32; 3437196008Smjacob 3438196008Smjacob switch (notify->nt_ncode) { 3439196008Smjacob case NT_ABORT_TASK: 3440196008Smjacob isp_target_mark_aborted_early(isp, tptr, inot->tag_id); 3441196008Smjacob inot->arg = MSG_ABORT_TASK; 3442196008Smjacob break; 3443196008Smjacob case NT_ABORT_TASK_SET: 3444196008Smjacob isp_target_mark_aborted_early(isp, tptr, TAG_ANY); 3445196008Smjacob inot->arg = MSG_ABORT_TASK_SET; 3446196008Smjacob break; 3447196008Smjacob case NT_CLEAR_ACA: 3448196008Smjacob inot->arg = MSG_CLEAR_ACA; 3449196008Smjacob break; 3450196008Smjacob case NT_CLEAR_TASK_SET: 3451196008Smjacob inot->arg = MSG_CLEAR_TASK_SET; 3452196008Smjacob break; 3453196008Smjacob case NT_LUN_RESET: 3454196008Smjacob inot->arg = MSG_LOGICAL_UNIT_RESET; 3455196008Smjacob break; 3456196008Smjacob case NT_TARGET_RESET: 3457196008Smjacob inot->arg = MSG_TARGET_RESET; 3458196008Smjacob break; 3459196008Smjacob default: 3460196008Smjacob isp_prt(isp, ISP_LOGWARN, "%s: unknown TMF code 0x%x for chan %d lun 0x%x", __func__, notify->nt_ncode, notify->nt_channel, lun); 3461196008Smjacob goto bad; 3462196008Smjacob } 3463196008Smjacob 3464196008Smjacob ntp = isp_get_ntpd(isp, tptr); 3465196008Smjacob if (ntp == NULL) { 3466196008Smjacob isp_prt(isp, ISP_LOGWARN, "%s: out of inotify private structures", __func__); 3467196008Smjacob goto bad; 3468196008Smjacob } 3469196008Smjacob ISP_MEMCPY(&ntp->rd.nt, notify, sizeof (isp_notify_t)); 3470196008Smjacob if (notify->nt_lreserved) { 3471196008Smjacob ISP_MEMCPY(&ntp->rd.data, notify->nt_lreserved, QENTRY_LEN); 3472196008Smjacob ntp->rd.nt.nt_lreserved = &ntp->rd.data; 3473196008Smjacob } 3474196008Smjacob ntp->rd.seq_id = notify->nt_tagval; 3475196008Smjacob ntp->rd.tag_id = notify->nt_tagval >> 32; 3476196008Smjacob 3477196008Smjacob tptr->inot_count--; 3478196008Smjacob SLIST_REMOVE_HEAD(&tptr->inots, sim_links.sle); 3479196008Smjacob rls_lun_statep(isp, tptr); 3480238869Smjacob ISP_PATH_PRT(isp, ISP_LOGTDEBUG2, inot->ccb_h.path, "%s: Take FREE INOT count now %d\n", __func__, tptr->inot_count); 3481196008Smjacob inot->ccb_h.status = CAM_MESSAGE_RECV; 3482196008Smjacob xpt_done((union ccb *)inot); 3483196008Smjacob return; 3484196008Smjacobbad: 3485196008Smjacob if (tptr) { 3486196008Smjacob rls_lun_statep(isp, tptr); 3487196008Smjacob } 3488196008Smjacob if (notify->nt_need_ack && notify->nt_lreserved) { 3489196008Smjacob if (((isphdr_t *)notify->nt_lreserved)->rqs_entry_type == RQSTYPE_ABTS_RCVD) { 3490238869Smjacob if (isp_acknak_abts(isp, notify->nt_lreserved, ENOMEM)) { 3491238869Smjacob isp_prt(isp, ISP_LOGWARN, "you lose- unable to send an ACKNAK"); 3492238869Smjacob } 3493196008Smjacob } else { 3494238869Smjacob isp_async(isp, ISPASYNC_TARGET_NOTIFY_ACK, notify->nt_lreserved); 3495196008Smjacob } 3496196008Smjacob } 3497196008Smjacob} 3498196008Smjacob 3499196008Smjacob/* 3500215034Sbrucec * Find the associated private data and mark it as dead so 3501196008Smjacob * we don't try to work on it any further. 3502196008Smjacob */ 3503196008Smjacobstatic void 3504196008Smjacobisp_target_mark_aborted(ispsoftc_t *isp, union ccb *ccb) 3505196008Smjacob{ 3506196008Smjacob tstate_t *tptr; 3507196008Smjacob atio_private_data_t *atp; 3508228461Smav union ccb *accb = ccb->cab.abort_ccb; 3509196008Smjacob 3510228461Smav tptr = get_lun_statep(isp, XS_CHANNEL(accb), XS_LUN(accb)); 3511196008Smjacob if (tptr == NULL) { 3512228461Smav tptr = get_lun_statep(isp, XS_CHANNEL(accb), CAM_LUN_WILDCARD); 3513196008Smjacob if (tptr == NULL) { 3514196008Smjacob ccb->ccb_h.status = CAM_REQ_INVALID; 3515196008Smjacob return; 3516196008Smjacob } 3517196008Smjacob } 3518196008Smjacob 3519228461Smav atp = isp_get_atpd(isp, tptr, accb->atio.tag_id); 3520196008Smjacob if (atp == NULL) { 3521196008Smjacob ccb->ccb_h.status = CAM_REQ_INVALID; 3522228461Smav } else { 3523228461Smav atp->dead = 1; 3524228461Smav ccb->ccb_h.status = CAM_REQ_CMP; 3525196008Smjacob } 3526228461Smav rls_lun_statep(isp, tptr); 3527196008Smjacob} 3528196008Smjacob 3529196008Smjacobstatic void 3530196008Smjacobisp_target_mark_aborted_early(ispsoftc_t *isp, tstate_t *tptr, uint32_t tag_id) 3531196008Smjacob{ 3532196008Smjacob atio_private_data_t *atp; 3533196008Smjacob inot_private_data_t *restart_queue = tptr->restart_queue; 3534196008Smjacob 3535196008Smjacob /* 3536196008Smjacob * First, clean any commands pending restart 3537196008Smjacob */ 3538196008Smjacob tptr->restart_queue = NULL; 3539196008Smjacob while (restart_queue) { 3540196008Smjacob uint32_t this_tag_id; 3541196008Smjacob inot_private_data_t *ntp = restart_queue; 3542196008Smjacob 3543196008Smjacob restart_queue = ntp->rd.nt.nt_hba; 3544196008Smjacob 3545196008Smjacob if (IS_24XX(isp)) { 3546196008Smjacob this_tag_id = ((at7_entry_t *)ntp->rd.data)->at_rxid; 3547196008Smjacob } else { 3548196008Smjacob this_tag_id = ((at2_entry_t *)ntp->rd.data)->at_rxid; 3549196008Smjacob } 3550196008Smjacob if ((uint64_t)tag_id == TAG_ANY || tag_id == this_tag_id) { 3551196008Smjacob isp_put_ntpd(isp, tptr, ntp); 3552196008Smjacob } else { 3553196008Smjacob ntp->rd.nt.nt_hba = tptr->restart_queue; 3554196008Smjacob tptr->restart_queue = ntp; 3555196008Smjacob } 3556196008Smjacob } 3557196008Smjacob 3558196008Smjacob /* 3559196008Smjacob * Now mark other ones dead as well. 3560196008Smjacob */ 3561196008Smjacob for (atp = tptr->atpool; atp < &tptr->atpool[ATPDPSIZE]; atp++) { 3562196008Smjacob if ((uint64_t)tag_id == TAG_ANY || atp->tag == tag_id) { 3563196008Smjacob atp->dead = 1; 3564196008Smjacob } 3565196008Smjacob } 3566196008Smjacob} 3567196008Smjacob 3568196008Smjacob 3569196008Smjacob#ifdef ISP_INTERNAL_TARGET 3570239143Smjacob//#define ISP_SEPARATE_STATUS 1 3571239143Smjacob#define ISP_MULTI_CCBS 1 3572239143Smjacob#if defined(ISP_MULTI_CCBS) && !defined(ISP_SEPARATE_STATUS) 3573239143Smjacob#define ISP_SEPARATE_STATUS 1 3574239143Smjacob#endif 3575196008Smjacob 3576239143Smjacobtypedef struct periph_private_data_t { 3577239143Smjacob union ccb *ccb; /* original ATIO or Immediate Notify */ 3578239143Smjacob unsigned long offset; /* current offset */ 3579239143Smjacob int sequence; /* current CTIO sequence */ 3580239143Smjacob int ctio_cnt; /* current # of ctio's outstanding */ 3581239143Smjacob int 3582239143Smjacob status_sent : 1, 3583239143Smjacob on_queue : 1; /* on restart queue */ 3584239143Smjacob} ppd_t; 3585239143Smjacob/* 3586239143Smjacob * Each ATIO we allocate will have periph private data associated with it 3587239143Smjacob * that maintains per-command state. This private to each ATIO. 3588239143Smjacob */ 3589239143Smjacob#define ATIO_PPD(ccb) ((ppd_t *)(((struct ccb_hdr *)ccb)->ppriv_ptr0)) 3590239143Smjacob/* 3591239143Smjacob * Each CTIO we send downstream will get a pointer to the ATIO itself 3592239143Smjacob * so that on completion we can retrieve that pointer. 3593239143Smjacob */ 3594196008Smjacob#define ccb_atio ppriv_ptr1 3595196008Smjacob#define ccb_inot ppriv_ptr1 3596196008Smjacob 3597239143Smjacob/* 3598239143Smjacob * Each CTIO we send downstream will contain a sequence number 3599239143Smjacob */ 3600239143Smjacob#define CTIO_SEQ(ccb) ccb->ccb_h.ppriv_field0 3601239143Smjacob 3602196008Smjacob#define MAX_ISP_TARG_TRANSFER (2 << 20) 3603239143Smjacob#define NISP_TARG_CMDS 64 3604239143Smjacob#define NISP_TARG_NOTIFIES 64 3605196008Smjacob#define DISK_SHIFT 9 3606196008Smjacob#define JUNK_SIZE 256 3607239143Smjacob#define MULTI_CCB_DATA_LIM 8192 3608239143Smjacob//#define MULTI_CCB_DATA_CNT 64 3609239143Smjacob#define MULTI_CCB_DATA_CNT 8 3610196008Smjacob 3611196008Smjacobextern u_int vm_kmem_size; 3612196008Smjacobstatic int ca; 3613196008Smjacobstatic uint32_t disk_size; 3614196008Smjacobstatic uint8_t *disk_data = NULL; 3615196008Smjacobstatic uint8_t *junk_data; 3616196008Smjacobstatic MALLOC_DEFINE(M_ISPTARG, "ISPTARG", "ISP TARGET data"); 3617196008Smjacobstruct isptarg_softc { 3618196008Smjacob /* CCBs (CTIOs, ATIOs, INOTs) pending on the controller */ 3619239143Smjacob struct isp_ccbq work_queue; 3620239143Smjacob struct isp_ccbq rework_queue; 3621239143Smjacob struct isp_ccbq running_queue; 3622239143Smjacob struct isp_ccbq inot_queue; 3623196008Smjacob struct cam_periph *periph; 3624196008Smjacob struct cam_path *path; 3625196008Smjacob ispsoftc_t *isp; 3626196008Smjacob}; 3627196008Smjacobstatic periph_ctor_t isptargctor; 3628196008Smjacobstatic periph_dtor_t isptargdtor; 3629196008Smjacobstatic periph_start_t isptargstart; 3630196008Smjacobstatic periph_init_t isptarginit; 3631196008Smjacobstatic void isptarg_done(struct cam_periph *, union ccb *); 3632196008Smjacobstatic void isptargasync(void *, u_int32_t, struct cam_path *, void *); 3633196008Smjacob 3634196008Smjacob 3635196008Smjacobstatic int isptarg_rwparm(uint8_t *, uint8_t *, uint64_t, uint32_t, uint8_t **, uint32_t *, int *); 3636196008Smjacob 3637196008Smjacobstatic struct periph_driver isptargdriver = 3638196008Smjacob{ 3639239143Smjacob isptarginit, "isptarg", TAILQ_HEAD_INITIALIZER(isptargdriver.units), 0 3640196008Smjacob}; 3641196008Smjacob 364255371Smjacobstatic void 3643196008Smjacobisptarginit(void) 3644196008Smjacob{ 3645196008Smjacob} 3646196008Smjacob 3647196008Smjacobstatic void 3648196008Smjacobisptargnotify(ispsoftc_t *isp, union ccb *iccb, struct ccb_immediate_notify *inot) 3649196008Smjacob{ 3650196008Smjacob struct ccb_notify_acknowledge *ack = &iccb->cna2; 3651196008Smjacob 3652196008Smjacob ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, inot->ccb_h.path, "%s: [0x%x] immediate notify for 0x%x from 0x%x status 0x%x arg 0x%x\n", __func__, 3653196008Smjacob inot->tag_id, inot->initiator_id, inot->seq_id, inot->ccb_h.status, inot->arg); 3654196008Smjacob ack->ccb_h.func_code = XPT_NOTIFY_ACKNOWLEDGE; 3655196008Smjacob ack->ccb_h.flags = 0; 3656196008Smjacob ack->ccb_h.retry_count = 0; 3657196008Smjacob ack->ccb_h.cbfcnp = isptarg_done; 3658196008Smjacob ack->ccb_h.timeout = 0; 3659196008Smjacob ack->ccb_h.ccb_inot = inot; 3660196008Smjacob ack->tag_id = inot->tag_id; 3661196008Smjacob ack->seq_id = inot->seq_id; 3662196008Smjacob ack->initiator_id = inot->initiator_id; 3663196008Smjacob xpt_action(iccb); 3664196008Smjacob} 3665196008Smjacob 3666196008Smjacobstatic void 3667196008Smjacobisptargstart(struct cam_periph *periph, union ccb *iccb) 3668196008Smjacob{ 3669208809Smjacob const uint8_t niliqd[SHORT_INQUIRY_LENGTH] = { 3670208809Smjacob 0x7f, 0x0, 0x5, 0x2, 32, 0, 0, 0x32, 3671208809Smjacob 'F', 'R', 'E', 'E', 'B', 'S', 'D', ' ', 3672208809Smjacob 'S', 'C', 'S', 'I', ' ', 'N', 'U', 'L', 3673208809Smjacob 'L', ' ', 'D', 'E', 'V', 'I', 'C', 'E', 3674208809Smjacob '0', '0', '0', '1' 3675208809Smjacob }; 3676196008Smjacob const uint8_t iqd[SHORT_INQUIRY_LENGTH] = { 3677208809Smjacob 0, 0x0, 0x5, 0x2, 32, 0, 0, 0x32, 3678196008Smjacob 'F', 'R', 'E', 'E', 'B', 'S', 'D', ' ', 3679196008Smjacob 'S', 'C', 'S', 'I', ' ', 'M', 'E', 'M', 3680196008Smjacob 'O', 'R', 'Y', ' ', 'D', 'I', 'S', 'K', 3681196008Smjacob '0', '0', '0', '1' 3682196008Smjacob }; 3683239143Smjacob int r, i, more = 0, last, is_data_cmd = 0, is_write; 3684239143Smjacob char *queue; 3685196008Smjacob struct isptarg_softc *softc = periph->softc; 3686196008Smjacob struct ccb_scsiio *csio; 3687196008Smjacob lun_id_t return_lun; 3688196008Smjacob struct ccb_accept_tio *atio; 3689196008Smjacob uint8_t *cdb, *ptr, status; 3690196008Smjacob uint8_t *data_ptr; 3691196008Smjacob uint32_t data_len, flags; 3692196008Smjacob struct ccb_hdr *ccbh; 3693196008Smjacob 3694196008Smjacob mtx_assert(periph->sim->mtx, MA_OWNED); 3695238869Smjacob ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG1, iccb->ccb_h.path, "%s: function code 0x%x INOTQ=%c WORKQ=%c REWORKQ=%c\n", __func__, iccb->ccb_h.func_code, 3696196008Smjacob TAILQ_FIRST(&softc->inot_queue)? 'y' : 'n', TAILQ_FIRST(&softc->work_queue)? 'y' : 'n', TAILQ_FIRST(&softc->rework_queue)? 'y' : 'n'); 3697196008Smjacob /* 3698196008Smjacob * Check for immediate notifies first 3699196008Smjacob */ 3700196008Smjacob ccbh = TAILQ_FIRST(&softc->inot_queue); 3701196008Smjacob if (ccbh) { 3702196008Smjacob TAILQ_REMOVE(&softc->inot_queue, ccbh, periph_links.tqe); 3703196008Smjacob if (TAILQ_FIRST(&softc->inot_queue) || TAILQ_FIRST(&softc->work_queue) || TAILQ_FIRST(&softc->rework_queue)) { 3704196008Smjacob xpt_schedule(periph, 1); 3705196008Smjacob } 3706196008Smjacob isptargnotify(softc->isp, iccb, (struct ccb_immediate_notify *)ccbh); 3707196008Smjacob return; 3708196008Smjacob } 3709196008Smjacob 3710196008Smjacob /* 3711196008Smjacob * Check the rework (continuation) work queue first. 3712196008Smjacob */ 3713196008Smjacob ccbh = TAILQ_FIRST(&softc->rework_queue); 3714196008Smjacob if (ccbh) { 3715196008Smjacob atio = (struct ccb_accept_tio *)ccbh; 3716196008Smjacob TAILQ_REMOVE(&softc->rework_queue, ccbh, periph_links.tqe); 3717196008Smjacob more = TAILQ_FIRST(&softc->work_queue) || TAILQ_FIRST(&softc->rework_queue); 3718239143Smjacob queue = "rework"; 3719196008Smjacob } else { 3720196008Smjacob ccbh = TAILQ_FIRST(&softc->work_queue); 3721196008Smjacob if (ccbh == NULL) { 3722196008Smjacob xpt_release_ccb(iccb); 3723196008Smjacob return; 3724196008Smjacob } 3725196008Smjacob atio = (struct ccb_accept_tio *)ccbh; 3726196008Smjacob TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe); 3727196008Smjacob more = TAILQ_FIRST(&softc->work_queue) != NULL; 3728239143Smjacob queue = "work"; 3729196008Smjacob } 3730239143Smjacob ATIO_PPD(atio)->on_queue = 0; 3731196008Smjacob 3732196008Smjacob if (atio->tag_id == 0xffffffff || atio->ccb_h.func_code != XPT_ACCEPT_TARGET_IO) { 3733196008Smjacob panic("BAD ATIO"); 3734196008Smjacob } 3735196008Smjacob 3736239143Smjacob data_len = is_write = 0; 3737196008Smjacob data_ptr = NULL; 3738196008Smjacob csio = &iccb->csio; 3739196008Smjacob status = SCSI_STATUS_OK; 3740196008Smjacob flags = CAM_SEND_STATUS; 3741196008Smjacob memset(&atio->sense_data, 0, sizeof (atio->sense_data)); 3742196008Smjacob cdb = atio->cdb_io.cdb_bytes; 3743239143Smjacob ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, ccbh->path, "%s: [0x%x] processing ATIO from %s queue initiator 0x%x CDB=0x%x data_offset=%u\n", __func__, atio->tag_id, 3744239143Smjacob queue, atio->init_id, cdb[0], ATIO_PPD(atio)->offset); 3745196008Smjacob 3746196008Smjacob return_lun = XS_LUN(atio); 3747196008Smjacob if (return_lun != 0) { 3748196008Smjacob xpt_print(atio->ccb_h.path, "[0x%x] Non-Zero Lun %d: cdb0=0x%x\n", atio->tag_id, return_lun, cdb[0]); 3749196008Smjacob if (cdb[0] != INQUIRY && cdb[0] != REPORT_LUNS && cdb[0] != REQUEST_SENSE) { 3750196008Smjacob status = SCSI_STATUS_CHECK_COND; 3751238869Smjacob SDFIXED(atio->sense_data)->error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR; 3752238869Smjacob SDFIXED(atio->sense_data)->flags = SSD_KEY_ILLEGAL_REQUEST; 3753238869Smjacob SDFIXED(atio->sense_data)->add_sense_code = 0x25; /* LOGICAL UNIT NOT SUPPORTED */ 3754228914Smjacob atio->sense_len = SSD_MIN_SIZE; 3755196008Smjacob } 3756196008Smjacob return_lun = CAM_LUN_WILDCARD; 3757196008Smjacob } 3758196008Smjacob 3759196008Smjacob switch (cdb[0]) { 3760196008Smjacob case REQUEST_SENSE: 3761196008Smjacob flags |= CAM_DIR_IN; 3762196008Smjacob data_len = sizeof (atio->sense_data); 3763196008Smjacob junk_data[0] = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_NO_SENSE; 3764196008Smjacob memset(junk_data+1, 0, data_len-1); 3765196008Smjacob if (data_len > cdb[4]) { 3766196008Smjacob data_len = cdb[4]; 3767196008Smjacob } 3768196008Smjacob if (data_len) { 3769196008Smjacob data_ptr = junk_data; 3770196008Smjacob } 3771196008Smjacob break; 3772239143Smjacob case WRITE_6: 3773239143Smjacob case WRITE_10: 3774239143Smjacob case WRITE_12: 3775239143Smjacob case WRITE_16: 3776239143Smjacob is_write = 1; 3777239143Smjacob /* FALLTHROUGH */ 3778196008Smjacob case READ_6: 3779196008Smjacob case READ_10: 3780196008Smjacob case READ_12: 3781196008Smjacob case READ_16: 3782239143Smjacob is_data_cmd = 1; 3783239143Smjacob r = isptarg_rwparm(cdb, disk_data, disk_size, ATIO_PPD(atio)->offset, &data_ptr, &data_len, &last); 3784238869Smjacob if (r != 0) { 3785196008Smjacob status = SCSI_STATUS_CHECK_COND; 3786238869Smjacob SDFIXED(atio->sense_data)->error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR; 3787238869Smjacob SDFIXED(atio->sense_data)->flags = SSD_KEY_ILLEGAL_REQUEST; 3788238869Smjacob if (r == -1) { 3789238869Smjacob SDFIXED(atio->sense_data)->add_sense_code = 0x21; /* LOGICAL BLOCK ADDRESS OUT OF RANGE */ 3790238869Smjacob } else { 3791238869Smjacob SDFIXED(atio->sense_data)->add_sense_code = 0x20; /* INVALID COMMAND OPERATION CODE */ 3792238869Smjacob } 3793228914Smjacob atio->sense_len = SSD_MIN_SIZE; 3794196008Smjacob } else { 3795239143Smjacob#ifdef ISP_SEPARATE_STATUS 3796196008Smjacob if (last && data_len) { 3797196008Smjacob last = 0; 3798196008Smjacob } 3799196008Smjacob#endif 3800196008Smjacob if (last == 0) { 3801196008Smjacob flags &= ~CAM_SEND_STATUS; 3802196008Smjacob } 3803196008Smjacob if (data_len) { 3804239143Smjacob ATIO_PPD(atio)->offset += data_len; 3805239143Smjacob if (is_write) 3806239143Smjacob flags |= CAM_DIR_OUT; 3807239143Smjacob else 3808239143Smjacob flags |= CAM_DIR_IN; 3809196008Smjacob } else { 3810196008Smjacob flags |= CAM_DIR_NONE; 3811196008Smjacob } 3812196008Smjacob } 3813196008Smjacob break; 3814196008Smjacob case INQUIRY: 3815196008Smjacob flags |= CAM_DIR_IN; 3816196008Smjacob if (cdb[1] || cdb[2] || cdb[3]) { 3817196008Smjacob status = SCSI_STATUS_CHECK_COND; 3818238869Smjacob SDFIXED(atio->sense_data)->error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR; 3819238869Smjacob SDFIXED(atio->sense_data)->flags = SSD_KEY_UNIT_ATTENTION; 3820238869Smjacob SDFIXED(atio->sense_data)->add_sense_code = 0x24; /* INVALID FIELD IN CDB */ 3821228914Smjacob atio->sense_len = SSD_MIN_SIZE; 3822196008Smjacob break; 3823196008Smjacob } 3824196008Smjacob data_len = sizeof (iqd); 3825196008Smjacob if (data_len > cdb[4]) { 3826196008Smjacob data_len = cdb[4]; 3827196008Smjacob } 3828196008Smjacob if (data_len) { 3829196008Smjacob if (XS_LUN(iccb) != 0) { 3830196008Smjacob memcpy(junk_data, niliqd, sizeof (iqd)); 3831196008Smjacob } else { 3832196008Smjacob memcpy(junk_data, iqd, sizeof (iqd)); 3833196008Smjacob } 3834196008Smjacob data_ptr = junk_data; 3835196008Smjacob } 3836196008Smjacob break; 3837196008Smjacob case TEST_UNIT_READY: 3838196008Smjacob flags |= CAM_DIR_NONE; 3839196008Smjacob if (ca) { 3840196008Smjacob ca = 0; 3841196008Smjacob status = SCSI_STATUS_CHECK_COND; 3842238869Smjacob SDFIXED(atio->sense_data)->error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR; 3843238869Smjacob SDFIXED(atio->sense_data)->flags = SSD_KEY_UNIT_ATTENTION; 3844238869Smjacob SDFIXED(atio->sense_data)->add_sense_code = 0x29; /* POWER ON, RESET, OR BUS DEVICE RESET OCCURRED */ 3845228914Smjacob atio->sense_len = SSD_MIN_SIZE; 3846196008Smjacob } 3847196008Smjacob break; 3848196008Smjacob case SYNCHRONIZE_CACHE: 3849196008Smjacob case START_STOP: 3850196008Smjacob case RESERVE: 3851196008Smjacob case RELEASE: 3852196008Smjacob case VERIFY_10: 3853196008Smjacob flags |= CAM_DIR_NONE; 3854196008Smjacob break; 3855196008Smjacob 3856196008Smjacob case READ_CAPACITY: 3857196008Smjacob flags |= CAM_DIR_IN; 3858196008Smjacob if (cdb[2] || cdb[3] || cdb[4] || cdb[5]) { 3859196008Smjacob status = SCSI_STATUS_CHECK_COND; 3860238869Smjacob SDFIXED(atio->sense_data)->error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR; 3861238869Smjacob SDFIXED(atio->sense_data)->flags = SSD_KEY_ILLEGAL_REQUEST; 3862238869Smjacob SDFIXED(atio->sense_data)->add_sense_code = 0x24; /* INVALID FIELD IN CDB */ 3863228914Smjacob atio->sense_len = SSD_MIN_SIZE; 3864196008Smjacob break; 3865196008Smjacob } 3866196008Smjacob if (cdb[8] & 0x1) { /* PMI */ 3867196008Smjacob junk_data[0] = 0xff; 3868196008Smjacob junk_data[1] = 0xff; 3869196008Smjacob junk_data[2] = 0xff; 3870196008Smjacob junk_data[3] = 0xff; 3871196008Smjacob } else { 3872196008Smjacob uint64_t last_blk = (disk_size >> DISK_SHIFT) - 1; 3873196008Smjacob if (last_blk < 0xffffffffULL) { 3874196008Smjacob junk_data[0] = (last_blk >> 24) & 0xff; 3875196008Smjacob junk_data[1] = (last_blk >> 16) & 0xff; 3876196008Smjacob junk_data[2] = (last_blk >> 8) & 0xff; 3877196008Smjacob junk_data[3] = (last_blk) & 0xff; 3878196008Smjacob } else { 3879196008Smjacob junk_data[0] = 0xff; 3880196008Smjacob junk_data[1] = 0xff; 3881196008Smjacob junk_data[2] = 0xff; 3882196008Smjacob junk_data[3] = 0xff; 3883196008Smjacob } 3884196008Smjacob } 3885196008Smjacob junk_data[4] = ((1 << DISK_SHIFT) >> 24) & 0xff; 3886196008Smjacob junk_data[5] = ((1 << DISK_SHIFT) >> 16) & 0xff; 3887196008Smjacob junk_data[6] = ((1 << DISK_SHIFT) >> 8) & 0xff; 3888196008Smjacob junk_data[7] = ((1 << DISK_SHIFT)) & 0xff; 3889196008Smjacob data_ptr = junk_data; 3890196008Smjacob data_len = 8; 3891196008Smjacob break; 3892196008Smjacob case REPORT_LUNS: 3893196008Smjacob flags |= CAM_DIR_IN; 3894196008Smjacob memset(junk_data, 0, JUNK_SIZE); 3895196008Smjacob junk_data[0] = (1 << 3) >> 24; 3896196008Smjacob junk_data[1] = (1 << 3) >> 16; 3897196008Smjacob junk_data[2] = (1 << 3) >> 8; 3898196008Smjacob junk_data[3] = (1 << 3); 3899196008Smjacob ptr = NULL; 3900196008Smjacob for (i = 0; i < 1; i++) { 3901239143Smjacob ptr = &junk_data[8 + (i << 3)]; 3902196008Smjacob if (i >= 256) { 3903196008Smjacob ptr[0] = 0x40 | ((i >> 8) & 0x3f); 3904196008Smjacob } 3905196008Smjacob ptr[1] = i; 3906196008Smjacob } 3907196008Smjacob data_ptr = junk_data; 3908196008Smjacob data_len = (ptr + 8) - junk_data; 3909196008Smjacob break; 3910196008Smjacob 3911196008Smjacob default: 3912196008Smjacob flags |= CAM_DIR_NONE; 3913196008Smjacob status = SCSI_STATUS_CHECK_COND; 3914238869Smjacob SDFIXED(atio->sense_data)->error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR; 3915238869Smjacob SDFIXED(atio->sense_data)->flags = SSD_KEY_ILLEGAL_REQUEST; 3916238869Smjacob SDFIXED(atio->sense_data)->add_sense_code = 0x20; /* INVALID COMMAND OPERATION CODE */ 3917228914Smjacob atio->sense_len = SSD_MIN_SIZE; 3918196008Smjacob break; 3919196008Smjacob } 3920196008Smjacob 3921196008Smjacob /* 3922196008Smjacob * If we are done with the transaction, tell the 3923196008Smjacob * controller to send status and perform a CMD_CMPLT. 3924196008Smjacob * If we have associated sense data, see if we can 3925196008Smjacob * send that too. 3926196008Smjacob */ 3927196008Smjacob if (status == SCSI_STATUS_CHECK_COND) { 3928196008Smjacob flags |= CAM_SEND_SENSE; 3929196008Smjacob csio->sense_len = atio->sense_len; 3930196008Smjacob csio->sense_data = atio->sense_data; 3931196008Smjacob flags &= ~CAM_DIR_MASK; 3932196008Smjacob data_len = 0; 3933196008Smjacob data_ptr = NULL; 3934196008Smjacob } 3935239143Smjacob cam_fill_ctio(csio, 0, isptarg_done, flags, MSG_SIMPLE_Q_TAG, atio->tag_id, atio->init_id, status, data_ptr, data_len, 30 * hz); 3936196008Smjacob iccb->ccb_h.target_id = atio->ccb_h.target_id; 3937196008Smjacob iccb->ccb_h.target_lun = return_lun; 3938196008Smjacob iccb->ccb_h.ccb_atio = atio; 3939239143Smjacob CTIO_SEQ(iccb) = ATIO_PPD(atio)->sequence++; 3940239143Smjacob ATIO_PPD(atio)->ctio_cnt++; 3941239143Smjacob if (flags & CAM_SEND_STATUS) { 3942239143Smjacob KASSERT((ATIO_PPD(atio)->status_sent == 0), ("we have already sent status for 0x%x in %s", atio->tag_id, __func__)); 3943239143Smjacob ATIO_PPD(atio)->status_sent = 1; 3944239143Smjacob } 3945239143Smjacob ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, atio->ccb_h.path, "%s: sending downstream for 0x%x sequence %u len %u flags %x\n", __func__, atio->tag_id, CTIO_SEQ(iccb), data_len, flags); 3946196008Smjacob xpt_action(iccb); 3947196008Smjacob 3948196008Smjacob if ((atio->ccb_h.status & CAM_DEV_QFRZN) != 0) { 3949196008Smjacob cam_release_devq(periph->path, 0, 0, 0, 0); 3950196008Smjacob atio->ccb_h.status &= ~CAM_DEV_QFRZN; 3951196008Smjacob } 3952239143Smjacob#ifdef ISP_MULTI_CCBS 3953239143Smjacob if (is_data_cmd && ATIO_PPD(atio)->status_sent == 0 && ATIO_PPD(atio)->ctio_cnt < MULTI_CCB_DATA_CNT && ATIO_PPD(atio)->on_queue == 0) { 3954239143Smjacob ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, atio->ccb_h.path, "%s: more still to do for 0x%x\n", __func__, atio->tag_id); 3955239143Smjacob TAILQ_INSERT_TAIL(&softc->rework_queue, &atio->ccb_h, periph_links.tqe); 3956239143Smjacob ATIO_PPD(atio)->on_queue = 1; 3957239143Smjacob more = 1; 3958239143Smjacob } 3959239143Smjacob#endif 3960196008Smjacob if (more) { 3961196008Smjacob xpt_schedule(periph, 1); 3962196008Smjacob } 3963196008Smjacob} 3964196008Smjacob 3965196008Smjacobstatic cam_status 3966196008Smjacobisptargctor(struct cam_periph *periph, void *arg) 3967196008Smjacob{ 3968196008Smjacob struct isptarg_softc *softc; 3969196008Smjacob 3970196008Smjacob softc = (struct isptarg_softc *)arg; 3971196008Smjacob periph->softc = softc; 3972196008Smjacob softc->periph = periph; 3973196008Smjacob softc->path = periph->path; 3974238869Smjacob ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG1, periph->path, "%s called\n", __func__); 3975196008Smjacob return (CAM_REQ_CMP); 3976196008Smjacob} 3977196008Smjacob 3978196008Smjacobstatic void 3979196008Smjacobisptargdtor(struct cam_periph *periph) 3980196008Smjacob{ 3981196008Smjacob struct isptarg_softc *softc; 3982196008Smjacob softc = (struct isptarg_softc *)periph->softc; 3983238869Smjacob ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG1, periph->path, "%s called\n", __func__); 3984196008Smjacob softc->periph = NULL; 3985196008Smjacob softc->path = NULL; 3986196008Smjacob periph->softc = NULL; 3987196008Smjacob} 3988196008Smjacob 3989196008Smjacobstatic void 3990196008Smjacobisptarg_done(struct cam_periph *periph, union ccb *ccb) 3991196008Smjacob{ 3992196008Smjacob struct isptarg_softc *softc; 3993196008Smjacob ispsoftc_t *isp; 3994239143Smjacob uint32_t newoff; 3995196008Smjacob struct ccb_accept_tio *atio; 3996196008Smjacob struct ccb_immediate_notify *inot; 3997196008Smjacob cam_status status; 3998196008Smjacob 3999196008Smjacob softc = (struct isptarg_softc *)periph->softc; 4000196008Smjacob isp = softc->isp; 4001196008Smjacob status = ccb->ccb_h.status & CAM_STATUS_MASK; 4002196008Smjacob 4003196008Smjacob switch (ccb->ccb_h.func_code) { 4004196008Smjacob case XPT_ACCEPT_TARGET_IO: 4005196008Smjacob atio = (struct ccb_accept_tio *) ccb; 4006239143Smjacob ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] ATIO seen in %s\n", atio->tag_id, __func__); 4007239143Smjacob memset(ATIO_PPD(atio), 0, sizeof (ppd_t)); 4008196008Smjacob TAILQ_INSERT_TAIL(&softc->work_queue, &ccb->ccb_h, periph_links.tqe); 4009239143Smjacob ATIO_PPD(atio)->on_queue = 1; 4010196008Smjacob xpt_schedule(periph, 1); 4011196008Smjacob break; 4012196008Smjacob case XPT_IMMEDIATE_NOTIFY: 4013196008Smjacob inot = (struct ccb_immediate_notify *) ccb; 4014239143Smjacob ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] INOT for 0x%x seen in %s\n", inot->tag_id, inot->seq_id, __func__); 4015196008Smjacob TAILQ_INSERT_TAIL(&softc->inot_queue, &ccb->ccb_h, periph_links.tqe); 4016196008Smjacob xpt_schedule(periph, 1); 4017196008Smjacob break; 4018196008Smjacob case XPT_CONT_TARGET_IO: 4019196008Smjacob atio = ccb->ccb_h.ccb_atio; 4020239143Smjacob KASSERT((ATIO_PPD(atio)->ctio_cnt != 0), ("ctio zero when finishing a CTIO")); 4021239143Smjacob ATIO_PPD(atio)->ctio_cnt--; 4022196008Smjacob if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 4023239143Smjacob switch (ccb->ccb_h.status & CAM_STATUS_MASK) { 4024239143Smjacob case CAM_MESSAGE_RECV: 4025239143Smjacob newoff = (ccb->csio.msg_ptr[3] << 24) | (ccb->csio.msg_ptr[4] << 16) | (ccb->csio.msg_ptr[5] << 8) | (ccb->csio.msg_ptr[6]); 4026239143Smjacob ISP_PATH_PRT(isp, ISP_LOGWARN, ccb->ccb_h.path, "[0x%x] got message to return to reset offset to 0x%x at sequence %u\n", atio->tag_id, newoff, CTIO_SEQ(ccb)); 4027239143Smjacob ATIO_PPD(atio)->offset = newoff; 4028239143Smjacob ATIO_PPD(atio)->status_sent = 0; 4029239143Smjacob if (ATIO_PPD(atio)->on_queue == 0) { 4030239143Smjacob TAILQ_INSERT_TAIL(&softc->rework_queue, &atio->ccb_h, periph_links.tqe); 4031239143Smjacob ATIO_PPD(atio)->on_queue = 1; 4032239143Smjacob } 4033238869Smjacob xpt_schedule(periph, 1); 4034239143Smjacob break; 4035239143Smjacob default: 4036238869Smjacob cam_error_print(ccb, CAM_ESF_ALL, CAM_EPF_ALL); 4037238869Smjacob xpt_action((union ccb *)atio); 4038239143Smjacob break; 4039238869Smjacob } 4040196008Smjacob } else if ((ccb->ccb_h.flags & CAM_SEND_STATUS) == 0) { 4041239143Smjacob ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] MID CTIO sequence %u seen in %s\n", atio->tag_id, CTIO_SEQ(ccb), __func__); 4042239143Smjacob if (ATIO_PPD(atio)->status_sent == 0 && ATIO_PPD(atio)->on_queue == 0) { 4043239143Smjacob TAILQ_INSERT_TAIL(&softc->rework_queue, &atio->ccb_h, periph_links.tqe); 4044239143Smjacob ATIO_PPD(atio)->on_queue = 1; 4045239143Smjacob } 4046196008Smjacob xpt_schedule(periph, 1); 4047196008Smjacob } else { 4048239143Smjacob KASSERT((ATIO_PPD(atio)->ctio_cnt == 0), ("ctio count still %d when we think we've sent the STATUS ctio", ATIO_PPD(atio)->ctio_cnt)); 4049239143Smjacob ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] FINAL CTIO sequence %u seen in %s\n", atio->tag_id, CTIO_SEQ(ccb), __func__); 4050196008Smjacob xpt_action((union ccb *)atio); 4051196008Smjacob } 4052239143Smjacob if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 4053239143Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0); 4054239143Smjacob ccb->ccb_h.status &= ~CAM_DEV_QFRZN; 4055239143Smjacob } 4056196008Smjacob xpt_release_ccb(ccb); 4057196008Smjacob break; 4058196008Smjacob case XPT_NOTIFY_ACKNOWLEDGE: 4059196008Smjacob if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 4060196008Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0); 4061196008Smjacob ccb->ccb_h.status &= ~CAM_DEV_QFRZN; 4062196008Smjacob } 4063196008Smjacob inot = ccb->ccb_h.ccb_inot; 4064238869Smjacob ISP_PATH_PRT(isp, ISP_LOGTDEBUG1, inot->ccb_h.path, "[0x%x] recycle notify for tag 0x%x\n", inot->tag_id, inot->seq_id); 4065196008Smjacob xpt_release_ccb(ccb); 4066196008Smjacob xpt_action((union ccb *)inot); 4067196008Smjacob break; 4068196008Smjacob default: 4069196008Smjacob xpt_print(ccb->ccb_h.path, "unexpected code 0x%x\n", ccb->ccb_h.func_code); 4070196008Smjacob break; 4071196008Smjacob } 4072196008Smjacob} 4073196008Smjacob 4074196008Smjacobstatic void 4075196008Smjacobisptargasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) 4076196008Smjacob{ 4077196008Smjacob struct ac_contract *acp = arg; 4078196008Smjacob struct ac_device_changed *fc = (struct ac_device_changed *) acp->contract_data; 4079196008Smjacob 4080196008Smjacob if (code != AC_CONTRACT) { 4081196008Smjacob return; 4082196008Smjacob } 4083196008Smjacob xpt_print(path, "0x%016llx Port ID 0x%06x %s\n", (unsigned long long) fc->wwpn, fc->port, fc->arrived? "arrived" : "departed"); 4084196008Smjacob} 4085196008Smjacob 4086196008Smjacobstatic void 4087196008Smjacobisp_target_thread(ispsoftc_t *isp, int chan) 4088196008Smjacob{ 4089196008Smjacob union ccb *ccb = NULL; 4090196008Smjacob int i; 4091196008Smjacob void *wchan; 4092196008Smjacob cam_status status; 4093196008Smjacob struct isptarg_softc *softc = NULL; 4094196008Smjacob struct cam_periph *periph = NULL, *wperiph = NULL; 4095196008Smjacob struct cam_path *path, *wpath; 4096196008Smjacob struct cam_sim *sim; 4097196008Smjacob 4098196008Smjacob if (disk_data == NULL) { 4099196008Smjacob disk_size = roundup2(vm_kmem_size >> 1, (1ULL << 20)); 4100196008Smjacob if (disk_size < (50 << 20)) { 4101196008Smjacob disk_size = 50 << 20; 4102196008Smjacob } 4103196008Smjacob disk_data = malloc(disk_size, M_ISPTARG, M_WAITOK | M_ZERO); 4104196008Smjacob if (disk_data == NULL) { 4105196008Smjacob isp_prt(isp, ISP_LOGERR, "%s: could not allocate disk data", __func__); 4106196008Smjacob goto out; 4107196008Smjacob } 4108196008Smjacob isp_prt(isp, ISP_LOGINFO, "allocated a %ju MiB disk", (uintmax_t) (disk_size >> 20)); 4109196008Smjacob } 4110196008Smjacob junk_data = malloc(JUNK_SIZE, M_ISPTARG, M_WAITOK | M_ZERO); 4111196008Smjacob if (junk_data == NULL) { 4112196008Smjacob isp_prt(isp, ISP_LOGERR, "%s: could not allocate junk", __func__); 4113196008Smjacob goto out; 4114196008Smjacob } 4115196008Smjacob 4116196008Smjacob 4117196008Smjacob softc = malloc(sizeof (*softc), M_ISPTARG, M_WAITOK | M_ZERO); 4118196008Smjacob if (softc == NULL) { 4119196008Smjacob isp_prt(isp, ISP_LOGERR, "%s: could not allocate softc", __func__); 4120196008Smjacob goto out; 4121196008Smjacob } 4122196008Smjacob TAILQ_INIT(&softc->work_queue); 4123196008Smjacob TAILQ_INIT(&softc->rework_queue); 4124196008Smjacob TAILQ_INIT(&softc->running_queue); 4125196008Smjacob TAILQ_INIT(&softc->inot_queue); 4126196008Smjacob softc->isp = isp; 4127196008Smjacob 4128196008Smjacob periphdriver_register(&isptargdriver); 4129196008Smjacob ISP_GET_PC(isp, chan, sim, sim); 4130196008Smjacob ISP_GET_PC(isp, chan, path, path); 4131196008Smjacob status = xpt_create_path_unlocked(&wpath, NULL, cam_sim_path(sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 4132196008Smjacob if (status != CAM_REQ_CMP) { 4133196008Smjacob isp_prt(isp, ISP_LOGERR, "%s: could not allocate wildcard path", __func__); 4134196008Smjacob return; 4135196008Smjacob } 4136196008Smjacob status = xpt_create_path_unlocked(&path, NULL, cam_sim_path(sim), 0, 0); 4137196008Smjacob if (status != CAM_REQ_CMP) { 4138196008Smjacob xpt_free_path(wpath); 4139196008Smjacob isp_prt(isp, ISP_LOGERR, "%s: could not allocate path", __func__); 4140196008Smjacob return; 4141196008Smjacob } 4142196008Smjacob 4143196008Smjacob ISP_LOCK(isp); 4144196008Smjacob status = cam_periph_alloc(isptargctor, NULL, isptargdtor, isptargstart, "isptarg", CAM_PERIPH_BIO, wpath, NULL, 0, softc); 4145196008Smjacob if (status != CAM_REQ_CMP) { 4146196008Smjacob ISP_UNLOCK(isp); 4147196008Smjacob isp_prt(isp, ISP_LOGERR, "%s: cam_periph_alloc for wildcard failed", __func__); 4148196008Smjacob goto out; 4149196008Smjacob } 4150196008Smjacob wperiph = cam_periph_find(wpath, "isptarg"); 4151196008Smjacob if (wperiph == NULL) { 4152196008Smjacob ISP_UNLOCK(isp); 4153196008Smjacob isp_prt(isp, ISP_LOGERR, "%s: wildcard periph already allocated but doesn't exist", __func__); 4154196008Smjacob goto out; 4155196008Smjacob } 4156196008Smjacob 4157196008Smjacob status = cam_periph_alloc(isptargctor, NULL, isptargdtor, isptargstart, "isptarg", CAM_PERIPH_BIO, path, NULL, 0, softc); 4158196008Smjacob if (status != CAM_REQ_CMP) { 4159196008Smjacob ISP_UNLOCK(isp); 4160196008Smjacob isp_prt(isp, ISP_LOGERR, "%s: cam_periph_alloc failed", __func__); 4161196008Smjacob goto out; 4162196008Smjacob } 4163196008Smjacob 4164196008Smjacob periph = cam_periph_find(path, "isptarg"); 4165196008Smjacob if (periph == NULL) { 4166196008Smjacob ISP_UNLOCK(isp); 4167196008Smjacob isp_prt(isp, ISP_LOGERR, "%s: periph already allocated but doesn't exist", __func__); 4168196008Smjacob goto out; 4169196008Smjacob } 4170196008Smjacob 4171196008Smjacob status = xpt_register_async(AC_CONTRACT, isptargasync, isp, wpath); 4172196008Smjacob if (status != CAM_REQ_CMP) { 4173196008Smjacob ISP_UNLOCK(isp); 4174196008Smjacob isp_prt(isp, ISP_LOGERR, "%s: xpt_register_async failed", __func__); 4175196008Smjacob goto out; 4176196008Smjacob } 4177196008Smjacob 4178196008Smjacob ISP_UNLOCK(isp); 4179196008Smjacob 4180196008Smjacob ccb = xpt_alloc_ccb(); 4181196008Smjacob 4182196008Smjacob /* 4183196008Smjacob * Make sure role is none. 4184196008Smjacob */ 4185196008Smjacob xpt_setup_ccb(&ccb->ccb_h, periph->path, 10); 4186196008Smjacob ccb->ccb_h.func_code = XPT_SET_SIM_KNOB; 4187196008Smjacob ccb->knob.xport_specific.fc.role = KNOB_ROLE_NONE; 4188196008Smjacob ccb->knob.xport_specific.fc.valid = KNOB_VALID_ROLE; 4189196008Smjacob 4190196008Smjacob ISP_LOCK(isp); 4191196008Smjacob xpt_action(ccb); 4192196008Smjacob ISP_UNLOCK(isp); 4193196008Smjacob 4194196008Smjacob /* 4195196008Smjacob * Now enable luns 4196196008Smjacob */ 4197196008Smjacob xpt_setup_ccb(&ccb->ccb_h, periph->path, 10); 4198196008Smjacob ccb->ccb_h.func_code = XPT_EN_LUN; 4199196008Smjacob ccb->cel.enable = 1; 4200196008Smjacob ISP_LOCK(isp); 4201196008Smjacob xpt_action(ccb); 4202196008Smjacob ISP_UNLOCK(isp); 4203196008Smjacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 4204196008Smjacob xpt_free_ccb(ccb); 4205196008Smjacob xpt_print(periph->path, "failed to enable lun (0x%x)\n", ccb->ccb_h.status); 4206196008Smjacob goto out; 4207196008Smjacob } 4208196008Smjacob 4209196008Smjacob xpt_setup_ccb(&ccb->ccb_h, wperiph->path, 10); 4210196008Smjacob ccb->ccb_h.func_code = XPT_EN_LUN; 4211196008Smjacob ccb->cel.enable = 1; 4212196008Smjacob ISP_LOCK(isp); 4213196008Smjacob xpt_action(ccb); 4214196008Smjacob ISP_UNLOCK(isp); 4215196008Smjacob if (ccb->ccb_h.status != CAM_REQ_CMP) { 4216196008Smjacob xpt_free_ccb(ccb); 4217196008Smjacob xpt_print(wperiph->path, "failed to enable lun (0x%x)\n", ccb->ccb_h.status); 4218196008Smjacob goto out; 4219196008Smjacob } 4220196008Smjacob xpt_free_ccb(ccb); 4221196008Smjacob 4222196008Smjacob /* 4223196008Smjacob * Add resources 4224196008Smjacob */ 4225196008Smjacob ISP_GET_PC_ADDR(isp, chan, target_proc, wchan); 4226196008Smjacob for (i = 0; i < 4; i++) { 4227196008Smjacob ccb = malloc(sizeof (*ccb), M_ISPTARG, M_WAITOK | M_ZERO); 4228196008Smjacob xpt_setup_ccb(&ccb->ccb_h, wperiph->path, 1); 4229196008Smjacob ccb->ccb_h.func_code = XPT_ACCEPT_TARGET_IO; 4230196008Smjacob ccb->ccb_h.cbfcnp = isptarg_done; 4231239143Smjacob ccb->ccb_h.ppriv_ptr0 = malloc(sizeof (ppd_t), M_ISPTARG, M_WAITOK | M_ZERO); 4232196008Smjacob ISP_LOCK(isp); 4233196008Smjacob xpt_action(ccb); 4234196008Smjacob ISP_UNLOCK(isp); 4235196008Smjacob } 4236196008Smjacob for (i = 0; i < NISP_TARG_CMDS; i++) { 4237196008Smjacob ccb = malloc(sizeof (*ccb), M_ISPTARG, M_WAITOK | M_ZERO); 4238196008Smjacob xpt_setup_ccb(&ccb->ccb_h, periph->path, 1); 4239196008Smjacob ccb->ccb_h.func_code = XPT_ACCEPT_TARGET_IO; 4240196008Smjacob ccb->ccb_h.cbfcnp = isptarg_done; 4241239143Smjacob ccb->ccb_h.ppriv_ptr0 = malloc(sizeof (ppd_t), M_ISPTARG, M_WAITOK | M_ZERO); 4242196008Smjacob ISP_LOCK(isp); 4243196008Smjacob xpt_action(ccb); 4244196008Smjacob ISP_UNLOCK(isp); 4245196008Smjacob } 4246196008Smjacob for (i = 0; i < 4; i++) { 4247196008Smjacob ccb = malloc(sizeof (*ccb), M_ISPTARG, M_WAITOK | M_ZERO); 4248196008Smjacob xpt_setup_ccb(&ccb->ccb_h, wperiph->path, 1); 4249196008Smjacob ccb->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY; 4250196008Smjacob ccb->ccb_h.cbfcnp = isptarg_done; 4251196008Smjacob ISP_LOCK(isp); 4252196008Smjacob xpt_action(ccb); 4253196008Smjacob ISP_UNLOCK(isp); 4254196008Smjacob } 4255196008Smjacob for (i = 0; i < NISP_TARG_NOTIFIES; i++) { 4256196008Smjacob ccb = malloc(sizeof (*ccb), M_ISPTARG, M_WAITOK | M_ZERO); 4257196008Smjacob xpt_setup_ccb(&ccb->ccb_h, periph->path, 1); 4258196008Smjacob ccb->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY; 4259196008Smjacob ccb->ccb_h.cbfcnp = isptarg_done; 4260196008Smjacob ISP_LOCK(isp); 4261196008Smjacob xpt_action(ccb); 4262196008Smjacob ISP_UNLOCK(isp); 4263196008Smjacob } 4264196008Smjacob 4265196008Smjacob /* 4266196008Smjacob * Now turn it all back on 4267196008Smjacob */ 4268196008Smjacob xpt_setup_ccb(&ccb->ccb_h, periph->path, 10); 4269196008Smjacob ccb->ccb_h.func_code = XPT_SET_SIM_KNOB; 4270196008Smjacob ccb->knob.xport_specific.fc.valid = KNOB_VALID_ROLE; 4271196008Smjacob ccb->knob.xport_specific.fc.role = KNOB_ROLE_TARGET; 4272196008Smjacob ISP_LOCK(isp); 4273196008Smjacob xpt_action(ccb); 4274196008Smjacob ISP_UNLOCK(isp); 4275196008Smjacob 4276196008Smjacob /* 4277196008Smjacob * Okay, while things are still active, sleep... 4278196008Smjacob */ 4279196008Smjacob ISP_LOCK(isp); 4280196008Smjacob for (;;) { 4281196008Smjacob ISP_GET_PC(isp, chan, proc_active, i); 4282196008Smjacob if (i == 0) { 4283196008Smjacob break; 4284196008Smjacob } 4285196008Smjacob msleep(wchan, &isp->isp_lock, PUSER, "tsnooze", 0); 4286196008Smjacob } 4287196008Smjacob ISP_UNLOCK(isp); 4288196008Smjacob 4289196008Smjacobout: 4290196008Smjacob if (wperiph) { 4291196008Smjacob cam_periph_invalidate(wperiph); 4292196008Smjacob } 4293196008Smjacob if (periph) { 4294196008Smjacob cam_periph_invalidate(periph); 4295196008Smjacob } 4296196008Smjacob if (junk_data) { 4297196008Smjacob free(junk_data, M_ISPTARG); 4298196008Smjacob } 4299196008Smjacob if (disk_data) { 4300196008Smjacob free(disk_data, M_ISPTARG); 4301196008Smjacob } 4302196008Smjacob if (softc) { 4303196008Smjacob free(softc, M_ISPTARG); 4304196008Smjacob } 4305196008Smjacob xpt_free_path(path); 4306196008Smjacob xpt_free_path(wpath); 4307196008Smjacob} 4308196008Smjacob 4309196008Smjacobstatic void 4310196008Smjacobisp_target_thread_pi(void *arg) 4311196008Smjacob{ 4312196008Smjacob struct isp_spi *pi = arg; 4313196008Smjacob isp_target_thread(cam_sim_softc(pi->sim), cam_sim_bus(pi->sim)); 4314196008Smjacob} 4315196008Smjacob 4316196008Smjacobstatic void 4317196008Smjacobisp_target_thread_fc(void *arg) 4318196008Smjacob{ 4319196008Smjacob struct isp_fc *fc = arg; 4320196008Smjacob isp_target_thread(cam_sim_softc(fc->sim), cam_sim_bus(fc->sim)); 4321196008Smjacob} 4322196008Smjacob 4323196008Smjacobstatic int 4324196008Smjacobisptarg_rwparm(uint8_t *cdb, uint8_t *dp, uint64_t dl, uint32_t offset, uint8_t **kp, uint32_t *tl, int *lp) 4325196008Smjacob{ 4326196008Smjacob uint32_t cnt, curcnt; 4327196008Smjacob uint64_t lba; 4328196008Smjacob 4329196008Smjacob switch (cdb[0]) { 4330196008Smjacob case WRITE_16: 4331196008Smjacob case READ_16: 4332196008Smjacob cnt = (((uint32_t)cdb[10]) << 24) | 4333196008Smjacob (((uint32_t)cdb[11]) << 16) | 4334196008Smjacob (((uint32_t)cdb[12]) << 8) | 4335196008Smjacob ((uint32_t)cdb[13]); 4336196008Smjacob 4337196008Smjacob lba = (((uint64_t)cdb[2]) << 56) | 4338196008Smjacob (((uint64_t)cdb[3]) << 48) | 4339196008Smjacob (((uint64_t)cdb[4]) << 40) | 4340196008Smjacob (((uint64_t)cdb[5]) << 32) | 4341196008Smjacob (((uint64_t)cdb[6]) << 24) | 4342196008Smjacob (((uint64_t)cdb[7]) << 16) | 4343196008Smjacob (((uint64_t)cdb[8]) << 8) | 4344196008Smjacob ((uint64_t)cdb[9]); 4345196008Smjacob break; 4346196008Smjacob case WRITE_12: 4347196008Smjacob case READ_12: 4348196008Smjacob cnt = (((uint32_t)cdb[6]) << 16) | 4349196008Smjacob (((uint32_t)cdb[7]) << 8) | 4350196008Smjacob ((u_int32_t)cdb[8]); 4351196008Smjacob 4352196008Smjacob lba = (((uint32_t)cdb[2]) << 24) | 4353196008Smjacob (((uint32_t)cdb[3]) << 16) | 4354196008Smjacob (((uint32_t)cdb[4]) << 8) | 4355196008Smjacob ((uint32_t)cdb[5]); 4356196008Smjacob break; 4357196008Smjacob case WRITE_10: 4358196008Smjacob case READ_10: 4359196008Smjacob cnt = (((uint32_t)cdb[7]) << 8) | 4360196008Smjacob ((u_int32_t)cdb[8]); 4361196008Smjacob 4362196008Smjacob lba = (((uint32_t)cdb[2]) << 24) | 4363196008Smjacob (((uint32_t)cdb[3]) << 16) | 4364196008Smjacob (((uint32_t)cdb[4]) << 8) | 4365196008Smjacob ((uint32_t)cdb[5]); 4366196008Smjacob break; 4367196008Smjacob case WRITE_6: 4368196008Smjacob case READ_6: 4369196008Smjacob cnt = cdb[4]; 4370196008Smjacob if (cnt == 0) { 4371196008Smjacob cnt = 256; 4372196008Smjacob } 4373196008Smjacob lba = (((uint32_t)cdb[1] & 0x1f) << 16) | 4374196008Smjacob (((uint32_t)cdb[2]) << 8) | 4375196008Smjacob ((uint32_t)cdb[3]); 4376196008Smjacob break; 4377196008Smjacob default: 4378196008Smjacob return (-1); 4379196008Smjacob } 4380196008Smjacob 4381196008Smjacob cnt <<= DISK_SHIFT; 4382196008Smjacob lba <<= DISK_SHIFT; 4383196008Smjacob 4384196008Smjacob if (offset == cnt) { 4385196008Smjacob *lp = 1; 4386196008Smjacob return (0); 4387196008Smjacob } 4388196008Smjacob 4389196008Smjacob if (lba + cnt > dl) { 4390238869Smjacob return (-2); 4391196008Smjacob } 4392196008Smjacob 4393196008Smjacob curcnt = MAX_ISP_TARG_TRANSFER; 4394196008Smjacob if (offset + curcnt >= cnt) { 4395196008Smjacob curcnt = cnt - offset; 4396196008Smjacob *lp = 1; 4397196008Smjacob } else { 4398196008Smjacob *lp = 0; 4399196008Smjacob } 4400239143Smjacob#ifdef ISP_MULTI_CCBS 4401239143Smjacob if (curcnt > MULTI_CCB_DATA_LIM) 4402239143Smjacob curcnt = MULTI_CCB_DATA_LIM; 4403239143Smjacob#endif 4404196008Smjacob *tl = curcnt; 4405196008Smjacob *kp = &dp[lba + offset]; 4406196008Smjacob return (0); 4407196008Smjacob} 4408196008Smjacob 4409196008Smjacob#endif 4410196008Smjacob#endif 4411196008Smjacob 4412196008Smjacobstatic void 4413155704Smjacobisp_cam_async(void *cbarg, uint32_t code, struct cam_path *path, void *arg) 441439235Sgibbs{ 441539235Sgibbs struct cam_sim *sim; 4416224856Smjacob int bus, tgt; 4417157943Smjacob ispsoftc_t *isp; 441839235Sgibbs 441939235Sgibbs sim = (struct cam_sim *)cbarg; 4420157943Smjacob isp = (ispsoftc_t *) cam_sim_softc(sim); 4421224856Smjacob bus = cam_sim_bus(sim); 4422224856Smjacob tgt = xpt_path_target_id(path); 4423224856Smjacob 442439235Sgibbs switch (code) { 442539235Sgibbs case AC_LOST_DEVICE: 442652349Smjacob if (IS_SCSI(isp)) { 4427155704Smjacob uint16_t oflags, nflags; 4428196008Smjacob sdparam *sdp = SDPARAM(isp, bus); 442939235Sgibbs 4430104806Smjacob if (tgt >= 0) { 4431104806Smjacob nflags = sdp->isp_devparam[tgt].nvrm_flags; 443275200Smjacob#ifndef ISP_TARGET_MODE 4433104806Smjacob nflags &= DPARM_SAFE_DFLT; 4434104806Smjacob if (isp->isp_loaded_fw) { 4435104806Smjacob nflags |= DPARM_NARROW | DPARM_ASYNC; 4436104806Smjacob } 443775200Smjacob#else 4438104806Smjacob nflags = DPARM_DEFAULT; 443975200Smjacob#endif 4440104806Smjacob oflags = sdp->isp_devparam[tgt].goal_flags; 4441104806Smjacob sdp->isp_devparam[tgt].goal_flags = nflags; 4442104806Smjacob sdp->isp_devparam[tgt].dev_update = 1; 4443196008Smjacob sdp->update = 1; 4444196008Smjacob (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, bus); 4445104806Smjacob sdp->isp_devparam[tgt].goal_flags = oflags; 4446104806Smjacob } 444739235Sgibbs } 444839235Sgibbs break; 444939235Sgibbs default: 445073245Smjacob isp_prt(isp, ISP_LOGWARN, "isp_cam_async: Code 0x%x", code); 445139235Sgibbs break; 445239235Sgibbs } 445339235Sgibbs} 445439235Sgibbs 445539235Sgibbsstatic void 445642131Smjacobisp_poll(struct cam_sim *sim) 445739235Sgibbs{ 4458157943Smjacob ispsoftc_t *isp = cam_sim_softc(sim); 4459163899Smjacob uint32_t isr; 4460163899Smjacob uint16_t sema, mbox; 446182689Smjacob 446283028Smjacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 446382689Smjacob isp_intr(isp, isr, sema, mbox); 446483028Smjacob } 446539235Sgibbs} 446639235Sgibbs 446752349Smjacob 4468196008Smjacobstatic void 4469196008Smjacobisp_watchdog(void *arg) 447060220Smjacob{ 4471196008Smjacob struct ccb_scsiio *xs = arg; 4472196008Smjacob ispsoftc_t *isp; 4473224856Smjacob uint32_t ohandle = ISP_HANDLE_FREE, handle; 447462173Smjacob 4475196008Smjacob isp = XS_ISP(xs); 4476196008Smjacob 447760220Smjacob handle = isp_find_handle(isp, xs); 4478224856Smjacob 4479224856Smjacob /* 4480224856Smjacob * Hand crank the interrupt code just to be sure the command isn't stuck somewhere. 4481224856Smjacob */ 4482203444Smjacob if (handle != ISP_HANDLE_FREE) { 4483224856Smjacob uint32_t isr; 4484224856Smjacob uint16_t sema, mbox; 4485224856Smjacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox) != 0) { 4486224856Smjacob isp_intr(isp, isr, sema, mbox); 4487224856Smjacob } 4488224856Smjacob ohandle = handle; 4489224856Smjacob handle = isp_find_handle(isp, xs); 4490224856Smjacob } 4491224856Smjacob if (handle != ISP_HANDLE_FREE) { 4492196008Smjacob /* 4493203444Smjacob * Try and make sure the command is really dead before 4494203444Smjacob * we release the handle (and DMA resources) for reuse. 4495203444Smjacob * 4496203444Smjacob * If we are successful in aborting the command then 4497203444Smjacob * we're done here because we'll get the command returned 4498203444Smjacob * back separately. 4499196008Smjacob */ 4500203444Smjacob if (isp_control(isp, ISPCTL_ABORT_CMD, xs) == 0) { 4501203444Smjacob return; 4502203444Smjacob } 450362173Smjacob 4504196008Smjacob /* 4505203444Smjacob * Note that after calling the above, the command may in 4506203444Smjacob * fact have been completed. 4507196008Smjacob */ 4508203444Smjacob xs = isp_find_xs(isp, handle); 4509203444Smjacob 4510203444Smjacob /* 4511203444Smjacob * If the command no longer exists, then we won't 4512203444Smjacob * be able to find the xs again with this handle. 4513203444Smjacob */ 4514203444Smjacob if (xs == NULL) { 4515203444Smjacob return; 4516203444Smjacob } 4517203444Smjacob 4518203444Smjacob /* 4519203444Smjacob * After this point, the command is really dead. 4520203444Smjacob */ 4521196008Smjacob if (XS_XFRLEN(xs)) { 4522196008Smjacob ISP_DMAFREE(isp, xs, handle); 4523196008Smjacob } 4524196008Smjacob isp_destroy_handle(isp, handle); 4525203444Smjacob isp_prt(isp, ISP_LOGERR, "%s: timeout for handle 0x%x", __func__, handle); 4526238869Smjacob xs->ccb_h.status &= ~CAM_STATUS_MASK; 4527238869Smjacob xs->ccb_h.status |= CAM_CMD_TIMEOUT; 4528224856Smjacob isp_prt_endcmd(isp, xs); 4529196008Smjacob isp_done(xs); 4530224856Smjacob } else { 4531224856Smjacob if (ohandle != ISP_HANDLE_FREE) { 4532224856Smjacob isp_prt(isp, ISP_LOGWARN, "%s: timeout for handle 0x%x, recovered during interrupt", __func__, ohandle); 4533224856Smjacob } else { 4534224856Smjacob isp_prt(isp, ISP_LOGWARN, "%s: timeout for handle already free", __func__); 4535224856Smjacob } 4536164272Smjacob } 4537164272Smjacob} 4538164272Smjacob 4539164272Smjacobstatic void 4540196008Smjacobisp_make_here(ispsoftc_t *isp, int chan, int tgt) 4541164272Smjacob{ 4542196008Smjacob union ccb *ccb; 4543196008Smjacob struct isp_fc *fc = ISP_FC_PC(isp, chan); 4544169292Smjacob 4545196008Smjacob if (isp_autoconfig == 0) { 4546196008Smjacob return; 4547164272Smjacob } 4548164272Smjacob 4549166897Smjacob /* 4550208582Smjacob * Allocate a CCB, create a wildcard path for this target and schedule a rescan. 4551166897Smjacob */ 4552168831Sscottl ccb = xpt_alloc_ccb_nowait(); 4553166897Smjacob if (ccb == NULL) { 4554196008Smjacob isp_prt(isp, ISP_LOGWARN, "Chan %d unable to alloc CCB for rescan", chan); 4555166897Smjacob return; 4556166897Smjacob } 4557249468Smav if (xpt_create_path(&ccb->ccb_h.path, NULL, cam_sim_path(fc->sim), 4558249468Smav tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 4559166897Smjacob isp_prt(isp, ISP_LOGWARN, "unable to create path for rescan"); 4560166897Smjacob xpt_free_ccb(ccb); 4561166897Smjacob return; 4562166897Smjacob } 4563166897Smjacob xpt_rescan(ccb); 4564166897Smjacob} 4565166897Smjacob 4566166897Smjacobstatic void 4567196008Smjacobisp_make_gone(ispsoftc_t *isp, int chan, int tgt) 4568166897Smjacob{ 4569166897Smjacob struct cam_path *tp; 4570196008Smjacob struct isp_fc *fc = ISP_FC_PC(isp, chan); 4571196008Smjacob 4572196008Smjacob if (isp_autoconfig == 0) { 4573196008Smjacob return; 4574196008Smjacob } 4575196008Smjacob if (xpt_create_path(&tp, NULL, cam_sim_path(fc->sim), tgt, CAM_LUN_WILDCARD) == CAM_REQ_CMP) { 4576166897Smjacob xpt_async(AC_LOST_DEVICE, tp, NULL); 4577166897Smjacob xpt_free_path(tp); 4578164272Smjacob } 4579164272Smjacob} 4580164272Smjacob 4581164272Smjacob/* 4582164272Smjacob * Gone Device Timer Function- when we have decided that a device has gone 4583164272Smjacob * away, we wait a specific period of time prior to telling the OS it has 4584164272Smjacob * gone away. 4585164272Smjacob * 4586164272Smjacob * This timer function fires once a second and then scans the port database 4587164272Smjacob * for devices that are marked dead but still have a virtual target assigned. 4588164272Smjacob * We decrement a counter for that port database entry, and when it hits zero, 4589164272Smjacob * we tell the OS the device has gone away. 4590164272Smjacob */ 4591164272Smjacobstatic void 4592164272Smjacobisp_gdt(void *arg) 4593164272Smjacob{ 4594196008Smjacob struct isp_fc *fc = arg; 4595224804Smjacob taskqueue_enqueue(taskqueue_thread, &fc->gtask); 4596224804Smjacob} 4597224804Smjacob 4598224804Smjacobstatic void 4599224804Smjacobisp_gdt_task(void *arg, int pending) 4600224804Smjacob{ 4601224804Smjacob struct isp_fc *fc = arg; 4602196008Smjacob ispsoftc_t *isp = fc->isp; 4603196008Smjacob int chan = fc - isp->isp_osinfo.pc.fc; 4604164272Smjacob fcportdb_t *lp; 4605164272Smjacob int dbidx, tgt, more_to_do = 0; 4606164272Smjacob 4607224804Smjacob ISP_LOCK(isp); 4608224804Smjacob isp_prt(isp, ISP_LOGDEBUG0, "Chan %d GDT timer expired", chan); 4609164272Smjacob for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { 4610196008Smjacob lp = &FCPARAM(isp, chan)->portdb[dbidx]; 4611164272Smjacob 4612164272Smjacob if (lp->state != FC_PORTDB_STATE_ZOMBIE) { 4613164272Smjacob continue; 4614164272Smjacob } 4615196008Smjacob if (lp->dev_map_idx == 0 || lp->target_mode) { 4616164272Smjacob continue; 4617164272Smjacob } 4618208119Smjacob if (lp->gone_timer != 0) { 4619238869Smjacob isp_prt(isp, ISP_LOG_SANCFG, "%s: Chan %d more to do for target %u (timer=%u)", __func__, chan, lp->dev_map_idx - 1, lp->gone_timer); 4620208119Smjacob lp->gone_timer -= 1; 4621164272Smjacob more_to_do++; 4622164272Smjacob continue; 4623164272Smjacob } 4624196008Smjacob tgt = lp->dev_map_idx - 1; 4625196008Smjacob FCPARAM(isp, chan)->isp_dev_map[tgt] = 0; 4626196008Smjacob lp->dev_map_idx = 0; 4627164272Smjacob lp->state = FC_PORTDB_STATE_NIL; 4628196008Smjacob isp_prt(isp, ISP_LOGCONFIG, prom3, chan, lp->portid, tgt, "Gone Device Timeout"); 4629196008Smjacob isp_make_gone(isp, chan, tgt); 4630164272Smjacob } 4631200089Smjacob if (fc->ready) { 4632200089Smjacob if (more_to_do) { 4633200089Smjacob callout_reset(&fc->gdt, hz, isp_gdt, fc); 4634200089Smjacob } else { 4635224804Smjacob callout_deactivate(&fc->gdt); 4636238869Smjacob isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Stopping Gone Device Timer @ %lu", chan, (unsigned long) time_uptime); 4637200089Smjacob } 463860220Smjacob } 4639224804Smjacob ISP_UNLOCK(isp); 464060220Smjacob} 464160220Smjacob 4642164272Smjacob/* 4643164272Smjacob * Loop Down Timer Function- when loop goes down, a timer is started and 4644164272Smjacob * and after it expires we come here and take all probational devices that 4645164272Smjacob * the OS knows about and the tell the OS that they've gone away. 4646164272Smjacob * 4647164272Smjacob * We don't clear the devices out of our port database because, when loop 4648164272Smjacob * come back up, we have to do some actual cleanup with the chip at that 4649164272Smjacob * point (implicit PLOGO, e.g., to get the chip's port database state right). 4650164272Smjacob */ 465160220Smjacobstatic void 4652164272Smjacobisp_ldt(void *arg) 465377365Smjacob{ 4654196008Smjacob struct isp_fc *fc = arg; 4655224804Smjacob taskqueue_enqueue(taskqueue_thread, &fc->ltask); 4656224804Smjacob} 4657224804Smjacob 4658224804Smjacobstatic void 4659224804Smjacobisp_ldt_task(void *arg, int pending) 4660224804Smjacob{ 4661224804Smjacob struct isp_fc *fc = arg; 4662196008Smjacob ispsoftc_t *isp = fc->isp; 4663196008Smjacob int chan = fc - isp->isp_osinfo.pc.fc; 4664164272Smjacob fcportdb_t *lp; 4665224856Smjacob int dbidx, tgt, i; 466677365Smjacob 4667224804Smjacob ISP_LOCK(isp); 4668238869Smjacob isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "Chan %d Loop Down Timer expired @ %lu", chan, (unsigned long) time_uptime); 4669224804Smjacob callout_deactivate(&fc->ldt); 4670157943Smjacob 4671164272Smjacob /* 4672164272Smjacob * Notify to the OS all targets who we now consider have departed. 4673164272Smjacob */ 4674164272Smjacob for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { 4675196008Smjacob lp = &FCPARAM(isp, chan)->portdb[dbidx]; 4676164272Smjacob 4677164272Smjacob if (lp->state != FC_PORTDB_STATE_PROBATIONAL) { 4678164272Smjacob continue; 4679164272Smjacob } 4680196008Smjacob if (lp->dev_map_idx == 0 || lp->target_mode) { 4681164272Smjacob continue; 4682164272Smjacob } 4683164272Smjacob 4684164272Smjacob /* 4685164272Smjacob * XXX: CLEAN UP AND COMPLETE ANY PENDING COMMANDS FIRST! 4686164272Smjacob */ 4687164272Smjacob 4688238869Smjacob 4689224856Smjacob for (i = 0; i < isp->isp_maxcmds; i++) { 4690224856Smjacob struct ccb_scsiio *xs; 4691224856Smjacob 4692224856Smjacob if (!ISP_VALID_HANDLE(isp, isp->isp_xflist[i].handle)) { 4693224856Smjacob continue; 4694224856Smjacob } 4695224856Smjacob if ((xs = isp->isp_xflist[i].cmd) == NULL) { 4696224856Smjacob continue; 4697224856Smjacob } 4698224856Smjacob if (dbidx != (FCPARAM(isp, chan)->isp_dev_map[XS_TGT(xs)] - 1)) { 4699224856Smjacob continue; 4700224856Smjacob } 4701239143Smjacob isp_prt(isp, ISP_LOGWARN, "command handle 0x%x for %d.%d.%d orphaned by loop down timeout", 4702224856Smjacob isp->isp_xflist[i].handle, chan, XS_TGT(xs), XS_LUN(xs)); 4703224856Smjacob } 4704224856Smjacob 4705164272Smjacob /* 4706164272Smjacob * Mark that we've announced that this device is gone.... 4707164272Smjacob */ 4708238869Smjacob lp->announced = 1; 4709164272Smjacob 4710164272Smjacob /* 4711164272Smjacob * but *don't* change the state of the entry. Just clear 4712164272Smjacob * any target id stuff and announce to CAM that the 4713164272Smjacob * device is gone. This way any necessary PLOGO stuff 4714164272Smjacob * will happen when loop comes back up. 4715164272Smjacob */ 4716164272Smjacob 4717196008Smjacob tgt = lp->dev_map_idx - 1; 4718196008Smjacob FCPARAM(isp, chan)->isp_dev_map[tgt] = 0; 4719196008Smjacob lp->dev_map_idx = 0; 4720196008Smjacob lp->state = FC_PORTDB_STATE_NIL; 4721196008Smjacob isp_prt(isp, ISP_LOGCONFIG, prom3, chan, lp->portid, tgt, "Loop Down Timeout"); 4722196008Smjacob isp_make_gone(isp, chan, tgt); 4723164272Smjacob } 4724164272Smjacob 4725224856Smjacob if (FCPARAM(isp, chan)->role & ISP_ROLE_INITIATOR) { 4726224856Smjacob isp_unfreeze_loopdown(isp, chan); 4727224856Smjacob } 4728164272Smjacob /* 4729164272Smjacob * The loop down timer has expired. Wake up the kthread 4730164272Smjacob * to notice that fact (or make it false). 4731164272Smjacob */ 4732196008Smjacob fc->loop_dead = 1; 4733196008Smjacob fc->loop_down_time = fc->loop_down_limit+1; 4734196008Smjacob wakeup(fc); 4735224856Smjacob ISP_UNLOCK(isp); 4736164272Smjacob} 4737164272Smjacob 4738164272Smjacobstatic void 4739164272Smjacobisp_kthread(void *arg) 4740164272Smjacob{ 4741196008Smjacob struct isp_fc *fc = arg; 4742196008Smjacob ispsoftc_t *isp = fc->isp; 4743196008Smjacob int chan = fc - isp->isp_osinfo.pc.fc; 4744164272Smjacob int slp = 0; 4745200089Smjacob 4746169292Smjacob mtx_lock(&isp->isp_osinfo.lock); 4747196008Smjacob 474877365Smjacob for (;;) { 4749224856Smjacob int lb, lim; 475099598Smjacob 4751238869Smjacob isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "%s: Chan %d checking FC state", __func__, chan); 4752196008Smjacob lb = isp_fc_runstate(isp, chan, 250000); 4753196008Smjacob 4754196008Smjacob /* 4755196008Smjacob * Our action is different based upon whether we're supporting 4756196008Smjacob * Initiator mode or not. If we are, we might freeze the simq 4757196008Smjacob * when loop is down and set all sorts of different delays to 4758196008Smjacob * check again. 4759196008Smjacob * 4760196008Smjacob * If not, we simply just wait for loop to come up. 4761196008Smjacob */ 4762205236Smjacob if (lb && (FCPARAM(isp, chan)->role & ISP_ROLE_INITIATOR)) { 4763164272Smjacob /* 4764164272Smjacob * Increment loop down time by the last sleep interval 4765164272Smjacob */ 4766196008Smjacob fc->loop_down_time += slp; 4767163899Smjacob 4768163899Smjacob if (lb < 0) { 4769238869Smjacob isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC loop not up (down count %d)", __func__, chan, fc->loop_down_time); 4770163899Smjacob } else { 4771238869Smjacob isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC got to %d (down count %d)", __func__, chan, lb, fc->loop_down_time); 477280314Smjacob } 4773163899Smjacob 4774163899Smjacob /* 4775163899Smjacob * If we've never seen loop up and we've waited longer 4776164272Smjacob * than quickboot time, or we've seen loop up but we've 4777164272Smjacob * waited longer than loop_down_limit, give up and go 4778164272Smjacob * to sleep until loop comes up. 4779163899Smjacob */ 4780196008Smjacob if (FCPARAM(isp, chan)->loop_seen_once == 0) { 4781164272Smjacob lim = isp_quickboot_time; 4782164272Smjacob } else { 4783196008Smjacob lim = fc->loop_down_limit; 4784164272Smjacob } 4785196008Smjacob if (fc->loop_down_time >= lim) { 4786196008Smjacob isp_freeze_loopdown(isp, chan, "loop limit hit"); 4787163899Smjacob slp = 0; 4788196008Smjacob } else if (fc->loop_down_time < 10) { 4789164272Smjacob slp = 1; 4790196008Smjacob } else if (fc->loop_down_time < 30) { 4791164272Smjacob slp = 5; 4792196008Smjacob } else if (fc->loop_down_time < 60) { 4793164272Smjacob slp = 10; 4794196008Smjacob } else if (fc->loop_down_time < 120) { 4795164272Smjacob slp = 20; 4796163899Smjacob } else { 4797164272Smjacob slp = 30; 4798163899Smjacob } 4799163899Smjacob 4800196008Smjacob } else if (lb) { 4801238869Smjacob isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC Loop Down", __func__, chan); 4802196008Smjacob fc->loop_down_time += slp; 4803238869Smjacob if (fc->loop_down_time > 300) 4804238869Smjacob slp = 0; 4805238869Smjacob else 4806238869Smjacob slp = 60; 4807163899Smjacob } else { 4808238869Smjacob isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC state OK", __func__, chan); 4809196008Smjacob fc->loop_down_time = 0; 4810163899Smjacob slp = 0; 481177365Smjacob } 481299598Smjacob 4813196008Smjacob 481480314Smjacob /* 4815196008Smjacob * If this is past the first loop up or the loop is dead and if we'd frozen the simq, unfreeze it 4816196008Smjacob * now so that CAM can start sending us commands. 4817196008Smjacob * 4818196008Smjacob * If the FC state isn't okay yet, they'll hit that in isp_start which will freeze the queue again 4819196008Smjacob * or kill the commands, as appropriate. 482080314Smjacob */ 4821196008Smjacob 4822196008Smjacob if (FCPARAM(isp, chan)->loop_seen_once || fc->loop_dead) { 4823224856Smjacob isp_unfreeze_loopdown(isp, chan); 482477365Smjacob } 4825196008Smjacob 4826238869Smjacob isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "%s: Chan %d sleep time %d", __func__, chan, slp); 4827196008Smjacob 4828196008Smjacob msleep(fc, &isp->isp_osinfo.lock, PRIBIO, "ispf", slp * hz); 4829196008Smjacob 4830163899Smjacob /* 4831163899Smjacob * If slp is zero, we're waking up for the first time after 4832163899Smjacob * things have been okay. In this case, we set a deferral state 4833163899Smjacob * for all commands and delay hysteresis seconds before starting 4834163899Smjacob * the FC state evaluation. This gives the loop/fabric a chance 4835163899Smjacob * to settle. 4836163899Smjacob */ 4837196008Smjacob if (slp == 0 && fc->hysteresis) { 4838238869Smjacob isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "%s: Chan %d sleep hysteresis ticks %d", __func__, chan, fc->hysteresis * hz); 4839208808Smjacob mtx_unlock(&isp->isp_osinfo.lock); 4840208808Smjacob pause("ispt", fc->hysteresis * hz); 4841208808Smjacob mtx_lock(&isp->isp_osinfo.lock); 4842163899Smjacob } 484377365Smjacob } 4844169292Smjacob mtx_unlock(&isp->isp_osinfo.lock); 484577365Smjacob} 484677365Smjacob 484777365Smjacobstatic void 484842131Smjacobisp_action(struct cam_sim *sim, union ccb *ccb) 484939235Sgibbs{ 4850169292Smjacob int bus, tgt, ts, error, lim; 4851157943Smjacob ispsoftc_t *isp; 485240419Sgibbs struct ccb_trans_settings *cts; 485339235Sgibbs 485439235Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n")); 4855238869Smjacob 4856157943Smjacob isp = (ispsoftc_t *)cam_sim_softc(sim); 4857196008Smjacob mtx_assert(&isp->isp_lock, MA_OWNED); 4858196008Smjacob 4859196008Smjacob if (isp->isp_state != ISP_RUNSTATE && ccb->ccb_h.func_code == XPT_SCSI_IO) { 486044819Smjacob isp_init(isp); 486144819Smjacob if (isp->isp_state != ISP_INITSTATE) { 486244819Smjacob /* 486344819Smjacob * Lie. Say it was a selection timeout. 486444819Smjacob */ 486562173Smjacob ccb->ccb_h.status = CAM_SEL_TIMEOUT | CAM_DEV_QFRZN; 486649915Smjacob xpt_freeze_devq(ccb->ccb_h.path, 1); 486744819Smjacob xpt_done(ccb); 486844819Smjacob return; 486944819Smjacob } 487044819Smjacob isp->isp_state = ISP_RUNSTATE; 487144819Smjacob } 487264093Smjacob isp_prt(isp, ISP_LOGDEBUG2, "isp_action code %x", ccb->ccb_h.func_code); 4873169292Smjacob ISP_PCMD(ccb) = NULL; 487439235Sgibbs 487539235Sgibbs switch (ccb->ccb_h.func_code) { 487639235Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 4877196008Smjacob bus = XS_CHANNEL(ccb); 487839235Sgibbs /* 487939235Sgibbs * Do a couple of preliminary checks... 488039235Sgibbs */ 488139235Sgibbs if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { 488239235Sgibbs if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) { 488339235Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 488439235Sgibbs xpt_done(ccb); 488539235Sgibbs break; 488639235Sgibbs } 488739235Sgibbs } 4888238869Smjacob ccb->csio.req_map = NULL; 488949915Smjacob#ifdef DIAGNOSTIC 489049915Smjacob if (ccb->ccb_h.target_id > (ISP_MAX_TARGETS(isp) - 1)) { 4891164909Smjacob xpt_print(ccb->ccb_h.path, "invalid target\n"); 489249915Smjacob ccb->ccb_h.status = CAM_PATH_INVALID; 489349915Smjacob } else if (ccb->ccb_h.target_lun > (ISP_MAX_LUNS(isp) - 1)) { 4894164909Smjacob xpt_print(ccb->ccb_h.path, "invalid lun\n"); 489549915Smjacob ccb->ccb_h.status = CAM_PATH_INVALID; 489639235Sgibbs } 489739235Sgibbs if (ccb->ccb_h.status == CAM_PATH_INVALID) { 489839235Sgibbs xpt_done(ccb); 489939235Sgibbs break; 490039235Sgibbs } 490149915Smjacob#endif 4902169292Smjacob ccb->csio.scsi_status = SCSI_STATUS_OK; 4903169292Smjacob if (isp_get_pcmd(isp, ccb)) { 4904169292Smjacob isp_prt(isp, ISP_LOGWARN, "out of PCMDs"); 4905169292Smjacob cam_freeze_devq(ccb->ccb_h.path); 4906196008Smjacob cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 250, 0); 4907169292Smjacob xpt_done(ccb); 4908169292Smjacob break; 4909169292Smjacob } 491064093Smjacob error = isp_start((XS_T *) ccb); 491149915Smjacob switch (error) { 491239235Sgibbs case CMD_QUEUED: 491339235Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 4914169292Smjacob if (ccb->ccb_h.timeout == CAM_TIME_INFINITY) { 4915169292Smjacob break; 491660220Smjacob } 4917169292Smjacob ts = ccb->ccb_h.timeout; 4918169292Smjacob if (ts == CAM_TIME_DEFAULT) { 4919169292Smjacob ts = 60*1000; 4920169292Smjacob } 4921169292Smjacob ts = isp_mstohz(ts); 4922196008Smjacob callout_reset(&PISP_PCMD(ccb)->wdog, ts, isp_watchdog, ccb); 492339235Sgibbs break; 492449915Smjacob case CMD_RQLATER: 492580314Smjacob /* 4926196008Smjacob * We get this result for FC devices if the loop state isn't ready yet 4927196008Smjacob * or if the device in question has gone zombie on us. 4928196008Smjacob * 4929196008Smjacob * If we've never seen Loop UP at all, we requeue this request and wait 4930196008Smjacob * for the initial loop up delay to expire. 4931163899Smjacob */ 4932196008Smjacob lim = ISP_FC_PC(isp, bus)->loop_down_limit; 4933196008Smjacob if (FCPARAM(isp, bus)->loop_seen_once == 0 || ISP_FC_PC(isp, bus)->loop_down_time >= lim) { 4934196008Smjacob if (FCPARAM(isp, bus)->loop_seen_once == 0) { 4935196008Smjacob isp_prt(isp, ISP_LOGDEBUG0, "%d.%d loop not seen yet @ %lu", XS_TGT(ccb), XS_LUN(ccb), (unsigned long) time_uptime); 4936196008Smjacob } else { 4937196008Smjacob isp_prt(isp, ISP_LOGDEBUG0, "%d.%d downtime (%d) > lim (%d)", XS_TGT(ccb), XS_LUN(ccb), ISP_FC_PC(isp, bus)->loop_down_time, lim); 4938196008Smjacob } 4939196008Smjacob ccb->ccb_h.status = CAM_SEL_TIMEOUT|CAM_DEV_QFRZN; 4940164272Smjacob xpt_freeze_devq(ccb->ccb_h.path, 1); 4941169292Smjacob isp_free_pcmd(isp, ccb); 494280314Smjacob xpt_done(ccb); 494380314Smjacob break; 494480314Smjacob } 4945196008Smjacob isp_prt(isp, ISP_LOGDEBUG0, "%d.%d retry later", XS_TGT(ccb), XS_LUN(ccb)); 4946164272Smjacob cam_freeze_devq(ccb->ccb_h.path); 4947196008Smjacob cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 1000, 0); 4948238869Smjacob ccb->ccb_h.status = CAM_REQUEUE_REQ; 4949169292Smjacob isp_free_pcmd(isp, ccb); 495049915Smjacob xpt_done(ccb); 495149915Smjacob break; 495239235Sgibbs case CMD_EAGAIN: 4953196008Smjacob isp_free_pcmd(isp, ccb); 4954196008Smjacob cam_freeze_devq(ccb->ccb_h.path); 4955196008Smjacob cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 100, 0); 4956238869Smjacob ccb->ccb_h.status = CAM_REQUEUE_REQ; 495739235Sgibbs xpt_done(ccb); 495839235Sgibbs break; 495939235Sgibbs case CMD_COMPLETE: 496049915Smjacob isp_done((struct ccb_scsiio *) ccb); 496149915Smjacob break; 496249915Smjacob default: 4963196008Smjacob isp_prt(isp, ISP_LOGERR, "What's this? 0x%x at %d in file %s", error, __LINE__, __FILE__); 4964238869Smjacob ccb->ccb_h.status = CAM_REQUEUE_REQ; 4965169292Smjacob isp_free_pcmd(isp, ccb); 496639235Sgibbs xpt_done(ccb); 496739235Sgibbs } 496839235Sgibbs break; 496939235Sgibbs 497055371Smjacob#ifdef ISP_TARGET_MODE 4971196008Smjacob case XPT_EN_LUN: /* Enable/Disable LUN as a target */ 4972196008Smjacob if (ccb->cel.enable) { 4973196008Smjacob isp_enable_lun(isp, ccb); 4974196008Smjacob } else { 4975196008Smjacob isp_disable_lun(isp, ccb); 4976125597Smjacob } 497739235Sgibbs break; 4978197214Smjacob case XPT_IMMED_NOTIFY: 4979196008Smjacob case XPT_IMMEDIATE_NOTIFY: /* Add Immediate Notify Resource */ 498055371Smjacob case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */ 498155371Smjacob { 4982196008Smjacob tstate_t *tptr = get_lun_statep(isp, XS_CHANNEL(ccb), ccb->ccb_h.target_lun); 498355371Smjacob if (tptr == NULL) { 4984196008Smjacob tptr = get_lun_statep(isp, XS_CHANNEL(ccb), CAM_LUN_WILDCARD); 4985196008Smjacob } 4986196008Smjacob if (tptr == NULL) { 4987196008Smjacob const char *str; 4988196008Smjacob uint32_t tag; 4989196008Smjacob 4990196008Smjacob if (ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) { 4991196008Smjacob str = "XPT_IMMEDIATE_NOTIFY"; 4992196008Smjacob tag = ccb->cin1.seq_id; 4993196008Smjacob } else { 4994196008Smjacob tag = ccb->atio.tag_id; 4995196008Smjacob str = "XPT_ACCEPT_TARGET_IO"; 4996196008Smjacob } 4997196008Smjacob ISP_PATH_PRT(isp, ISP_LOGWARN, ccb->ccb_h.path, "%s: [0x%x] no state pointer found for %s\n", __func__, tag, str); 4998196008Smjacob dump_tstates(isp, XS_CHANNEL(ccb)); 4999196008Smjacob ccb->ccb_h.status = CAM_DEV_NOT_THERE; 500055371Smjacob break; 500155371Smjacob } 5002238869Smjacob ccb->ccb_h.spriv_field0 = 0; 5003238869Smjacob ccb->ccb_h.spriv_ptr1 = isp; 500498289Smjacob ccb->ccb_h.flags = 0; 500598289Smjacob 500655371Smjacob if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 5007196008Smjacob if (ccb->atio.tag_id) { 5008196008Smjacob atio_private_data_t *atp = isp_get_atpd(isp, tptr, ccb->atio.tag_id); 5009196008Smjacob if (atp) { 5010196008Smjacob isp_put_atpd(isp, tptr, atp); 5011196008Smjacob } 5012196008Smjacob } 501398289Smjacob tptr->atio_count++; 5014196008Smjacob SLIST_INSERT_HEAD(&tptr->atios, &ccb->ccb_h, sim_links.sle); 5015238869Smjacob ISP_PATH_PRT(isp, ISP_LOGTDEBUG2, ccb->ccb_h.path, "Put FREE ATIO (tag id 0x%x), count now %d\n", 5016236427Smjacob ccb->atio.tag_id, tptr->atio_count); 5017239143Smjacob ccb->atio.tag_id = 0; 5018196008Smjacob } else if (ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) { 5019196008Smjacob if (ccb->cin1.tag_id) { 5020196008Smjacob inot_private_data_t *ntp = isp_find_ntpd(isp, tptr, ccb->cin1.tag_id, ccb->cin1.seq_id); 5021196008Smjacob if (ntp) { 5022196008Smjacob isp_put_ntpd(isp, tptr, ntp); 5023196008Smjacob } 5024196008Smjacob } 5025125549Smjacob tptr->inot_count++; 5026196008Smjacob SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, sim_links.sle); 5027238869Smjacob ISP_PATH_PRT(isp, ISP_LOGTDEBUG2, ccb->ccb_h.path, "Put FREE INOT, (seq id 0x%x) count now %d\n", 5028236427Smjacob ccb->cin1.seq_id, tptr->inot_count); 5029239143Smjacob ccb->cin1.seq_id = 0; 5030197214Smjacob } else if (ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) { 5031197214Smjacob tptr->inot_count++; 5032197214Smjacob SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, sim_links.sle); 5033238869Smjacob ISP_PATH_PRT(isp, ISP_LOGTDEBUG2, ccb->ccb_h.path, "Put FREE INOT, (seq id 0x%x) count now %d\n", 5034236427Smjacob ccb->cin1.seq_id, tptr->inot_count); 5035239143Smjacob ccb->cin1.seq_id = 0; 503655371Smjacob } 503755371Smjacob rls_lun_statep(isp, tptr); 503855371Smjacob ccb->ccb_h.status = CAM_REQ_INPROG; 503955371Smjacob break; 504055371Smjacob } 5041197214Smjacob case XPT_NOTIFY_ACK: 5042197214Smjacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 5043197214Smjacob break; 5044196008Smjacob case XPT_NOTIFY_ACKNOWLEDGE: /* notify ack */ 5045196008Smjacob { 5046196008Smjacob tstate_t *tptr; 5047196008Smjacob inot_private_data_t *ntp; 5048196008Smjacob 5049196008Smjacob /* 5050196008Smjacob * XXX: Because we cannot guarantee that the path information in the notify acknowledge ccb 5051196008Smjacob * XXX: matches that for the immediate notify, we have to *search* for the notify structure 5052196008Smjacob */ 5053196008Smjacob /* 5054196008Smjacob * All the relevant path information is in the associated immediate notify 5055196008Smjacob */ 5056196008Smjacob ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "%s: [0x%x] NOTIFY ACKNOWLEDGE for 0x%x seen\n", __func__, ccb->cna2.tag_id, ccb->cna2.seq_id); 5057196008Smjacob ntp = get_ntp_from_tagdata(isp, ccb->cna2.tag_id, ccb->cna2.seq_id, &tptr); 5058196008Smjacob if (ntp == NULL) { 5059196008Smjacob ISP_PATH_PRT(isp, ISP_LOGWARN, ccb->ccb_h.path, "%s: [0x%x] XPT_NOTIFY_ACKNOWLEDGE of 0x%x cannot find ntp private data\n", __func__, 5060196008Smjacob ccb->cna2.tag_id, ccb->cna2.seq_id); 5061196008Smjacob ccb->ccb_h.status = CAM_DEV_NOT_THERE; 5062196008Smjacob xpt_done(ccb); 5063196008Smjacob break; 5064196008Smjacob } 5065196008Smjacob if (isp_handle_platform_target_notify_ack(isp, &ntp->rd.nt)) { 5066196008Smjacob rls_lun_statep(isp, tptr); 5067196008Smjacob cam_freeze_devq(ccb->ccb_h.path); 5068196008Smjacob cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 1000, 0); 5069238869Smjacob ccb->ccb_h.status &= ~CAM_STATUS_MASK; 5070238869Smjacob ccb->ccb_h.status |= CAM_REQUEUE_REQ; 5071196008Smjacob break; 5072196008Smjacob } 5073196008Smjacob isp_put_ntpd(isp, tptr, ntp); 5074196008Smjacob rls_lun_statep(isp, tptr); 5075196008Smjacob ccb->ccb_h.status = CAM_REQ_CMP; 5076196008Smjacob ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "%s: [0x%x] calling xpt_done for tag 0x%x\n", __func__, ccb->cna2.tag_id, ccb->cna2.seq_id); 5077196008Smjacob xpt_done(ccb); 5078196008Smjacob break; 5079196008Smjacob } 508055371Smjacob case XPT_CONT_TARGET_IO: 5081238869Smjacob isp_target_start_ctio(isp, ccb, FROM_CAM); 508255371Smjacob break; 508355371Smjacob#endif 508439235Sgibbs case XPT_RESET_DEV: /* BDR the specified SCSI device */ 508555371Smjacob 508655371Smjacob bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path)); 508755371Smjacob tgt = ccb->ccb_h.target_id; 508855371Smjacob tgt |= (bus << 16); 508955371Smjacob 5090196008Smjacob error = isp_control(isp, ISPCTL_RESET_DEV, bus, tgt); 509139235Sgibbs if (error) { 509239235Sgibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 509339235Sgibbs } else { 509439235Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 509539235Sgibbs } 509639235Sgibbs xpt_done(ccb); 509739235Sgibbs break; 509839235Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 509955371Smjacob { 510055371Smjacob union ccb *accb = ccb->cab.abort_ccb; 510155371Smjacob switch (accb->ccb_h.func_code) { 510255371Smjacob#ifdef ISP_TARGET_MODE 510355371Smjacob case XPT_ACCEPT_TARGET_IO: 5104228461Smav isp_target_mark_aborted(isp, ccb); 510555371Smjacob break; 510655371Smjacob#endif 510755371Smjacob case XPT_SCSI_IO: 510855371Smjacob error = isp_control(isp, ISPCTL_ABORT_CMD, ccb); 510955371Smjacob if (error) { 511055371Smjacob ccb->ccb_h.status = CAM_UA_ABORT; 511155371Smjacob } else { 511255371Smjacob ccb->ccb_h.status = CAM_REQ_CMP; 511355371Smjacob } 511455371Smjacob break; 511555371Smjacob default: 511655371Smjacob ccb->ccb_h.status = CAM_REQ_INVALID; 511755371Smjacob break; 511839235Sgibbs } 5119208548Smjacob /* 5120208548Smjacob * This is not a queued CCB, so the caller expects it to be 5121208548Smjacob * complete when control is returned. 5122208548Smjacob */ 512339235Sgibbs break; 512455371Smjacob } 512579241Smjacob#define IS_CURRENT_SETTINGS(c) (c->type == CTS_TYPE_CURRENT_SETTINGS) 512639235Sgibbs case XPT_SET_TRAN_SETTINGS: /* Nexus Settings */ 512739235Sgibbs cts = &ccb->cts; 512880583Smjacob if (!IS_CURRENT_SETTINGS(cts)) { 512980583Smjacob ccb->ccb_h.status = CAM_REQ_INVALID; 513080583Smjacob xpt_done(ccb); 513180583Smjacob break; 513280583Smjacob } 513339235Sgibbs tgt = cts->ccb_h.target_id; 5134196008Smjacob bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 513552349Smjacob if (IS_SCSI(isp)) { 5136196008Smjacob struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi; 5137196008Smjacob struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi; 5138196008Smjacob sdparam *sdp = SDPARAM(isp, bus); 5139165337Smjacob uint16_t *dptr; 5140165337Smjacob 5141164845Smjacob if (spi->valid == 0 && scsi->valid == 0) { 5142164845Smjacob ccb->ccb_h.status = CAM_REQ_CMP; 5143164845Smjacob xpt_done(ccb); 5144164845Smjacob break; 5145164845Smjacob } 5146196008Smjacob 514779241Smjacob /* 514880583Smjacob * We always update (internally) from goal_flags 514979241Smjacob * so any request to change settings just gets 515079241Smjacob * vectored to that location. 515179241Smjacob */ 515280583Smjacob dptr = &sdp->isp_devparam[tgt].goal_flags; 515379241Smjacob 515479241Smjacob if ((spi->valid & CTS_SPI_VALID_DISC) != 0) { 515579241Smjacob if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) 515679241Smjacob *dptr |= DPARM_DISC; 515779241Smjacob else 515879241Smjacob *dptr &= ~DPARM_DISC; 515979241Smjacob } 516079241Smjacob 516179241Smjacob if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 516279241Smjacob if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) 516379241Smjacob *dptr |= DPARM_TQING; 516479241Smjacob else 516579241Smjacob *dptr &= ~DPARM_TQING; 516679241Smjacob } 516779241Smjacob 516879241Smjacob if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 516979241Smjacob if (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT) 517079241Smjacob *dptr |= DPARM_WIDE; 517179241Smjacob else 517279241Smjacob *dptr &= ~DPARM_WIDE; 517379241Smjacob } 517479241Smjacob 517579241Smjacob /* 517679241Smjacob * XXX: FIX ME 517779241Smjacob */ 5178196008Smjacob if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) && (spi->valid & CTS_SPI_VALID_SYNC_RATE) && (spi->sync_period && spi->sync_offset)) { 517979241Smjacob *dptr |= DPARM_SYNC; 518080583Smjacob /* 518180583Smjacob * XXX: CHECK FOR LEGALITY 518280583Smjacob */ 5183196008Smjacob sdp->isp_devparam[tgt].goal_period = spi->sync_period; 5184196008Smjacob sdp->isp_devparam[tgt].goal_offset = spi->sync_offset; 518579241Smjacob } else { 518679241Smjacob *dptr &= ~DPARM_SYNC; 518779241Smjacob } 5188196008Smjacob isp_prt(isp, ISP_LOGDEBUG0, "SET (%d.%d.%d) to flags %x off %x per %x", bus, tgt, cts->ccb_h.target_lun, sdp->isp_devparam[tgt].goal_flags, 5189196008Smjacob sdp->isp_devparam[tgt].goal_offset, sdp->isp_devparam[tgt].goal_period); 519039235Sgibbs sdp->isp_devparam[tgt].dev_update = 1; 5191196008Smjacob sdp->update = 1; 519239235Sgibbs } 519339235Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 519439235Sgibbs xpt_done(ccb); 519539235Sgibbs break; 519639235Sgibbs case XPT_GET_TRAN_SETTINGS: 519739235Sgibbs cts = &ccb->cts; 519839235Sgibbs tgt = cts->ccb_h.target_id; 5199196008Smjacob bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 520052349Smjacob if (IS_FC(isp)) { 5201196008Smjacob fcparam *fcp = FCPARAM(isp, bus); 5202196008Smjacob struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi; 5203196008Smjacob struct ccb_trans_settings_fc *fc = &cts->xport_specific.fc; 5204208895Smjacob unsigned int hdlidx; 520579241Smjacob 520679241Smjacob cts->protocol = PROTO_SCSI; 520779241Smjacob cts->protocol_version = SCSI_REV_2; 520879241Smjacob cts->transport = XPORT_FC; 520979241Smjacob cts->transport_version = 0; 521079241Smjacob 5211165020Smjacob scsi->valid = CTS_SCSI_VALID_TQ; 5212165020Smjacob scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; 521379241Smjacob fc->valid = CTS_FC_VALID_SPEED; 5214171936Sjkim fc->bitrate = 100000; 5215196008Smjacob fc->bitrate *= fcp->isp_gbspeed; 5216208895Smjacob hdlidx = fcp->isp_dev_map[tgt] - 1; 5217208895Smjacob if (hdlidx < MAX_FC_TARG) { 5218208895Smjacob fcportdb_t *lp = &fcp->portdb[hdlidx]; 521979241Smjacob fc->wwnn = lp->node_wwn; 522079241Smjacob fc->wwpn = lp->port_wwn; 522179241Smjacob fc->port = lp->portid; 5222196008Smjacob fc->valid |= CTS_FC_VALID_WWNN | CTS_FC_VALID_WWPN | CTS_FC_VALID_PORT; 522379241Smjacob } 522439235Sgibbs } else { 5225196008Smjacob struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi; 5226196008Smjacob struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi; 5227196008Smjacob sdparam *sdp = SDPARAM(isp, bus); 5228155704Smjacob uint16_t dval, pval, oval; 522939235Sgibbs 523079241Smjacob if (IS_CURRENT_SETTINGS(cts)) { 523147073Smjacob sdp->isp_devparam[tgt].dev_refresh = 1; 5232196008Smjacob sdp->update = 1; 5233196008Smjacob (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, bus); 523480583Smjacob dval = sdp->isp_devparam[tgt].actv_flags; 523580583Smjacob oval = sdp->isp_devparam[tgt].actv_offset; 523680583Smjacob pval = sdp->isp_devparam[tgt].actv_period; 523745040Smjacob } else { 523880583Smjacob dval = sdp->isp_devparam[tgt].nvrm_flags; 523980583Smjacob oval = sdp->isp_devparam[tgt].nvrm_offset; 524080583Smjacob pval = sdp->isp_devparam[tgt].nvrm_period; 524145040Smjacob } 524239235Sgibbs 524379241Smjacob cts->protocol = PROTO_SCSI; 524479241Smjacob cts->protocol_version = SCSI_REV_2; 524579241Smjacob cts->transport = XPORT_SPI; 524679241Smjacob cts->transport_version = 2; 524779241Smjacob 5248164845Smjacob spi->valid = 0; 5249164845Smjacob scsi->valid = 0; 5250164845Smjacob spi->flags = 0; 5251164845Smjacob scsi->flags = 0; 525279241Smjacob if (dval & DPARM_DISC) { 525379241Smjacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 525479241Smjacob } 525580583Smjacob if ((dval & DPARM_SYNC) && oval && pval) { 525679241Smjacob spi->sync_offset = oval; 525779241Smjacob spi->sync_period = pval; 5258164845Smjacob } else { 5259164845Smjacob spi->sync_offset = 0; 5260164845Smjacob spi->sync_period = 0; 526179241Smjacob } 5262164845Smjacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 5263164845Smjacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 526479241Smjacob spi->valid |= CTS_SPI_VALID_BUS_WIDTH; 526579241Smjacob if (dval & DPARM_WIDE) { 526679241Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 526779241Smjacob } else { 526879241Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 526979241Smjacob } 527079241Smjacob if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { 527179241Smjacob scsi->valid = CTS_SCSI_VALID_TQ; 5272164845Smjacob if (dval & DPARM_TQING) { 5273164845Smjacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 5274164845Smjacob } 527579241Smjacob spi->valid |= CTS_SPI_VALID_DISC; 527679241Smjacob } 5277196008Smjacob isp_prt(isp, ISP_LOGDEBUG0, "GET %s (%d.%d.%d) to flags %x off %x per %x", IS_CURRENT_SETTINGS(cts)? "ACTIVE" : "NVRAM", 5278164845Smjacob bus, tgt, cts->ccb_h.target_lun, dval, oval, pval); 527939235Sgibbs } 528039235Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 528139235Sgibbs xpt_done(ccb); 528239235Sgibbs break; 528339235Sgibbs 528439235Sgibbs case XPT_CALC_GEOMETRY: 5285196008Smjacob cam_calc_geometry(&ccb->ccg, 1); 5286196008Smjacob xpt_done(ccb); 5287196008Smjacob break; 528839235Sgibbs 5289196008Smjacob case XPT_RESET_BUS: /* Reset the specified bus */ 5290196008Smjacob bus = cam_sim_bus(sim); 5291196008Smjacob error = isp_control(isp, ISPCTL_RESET_BUS, bus); 5292196008Smjacob if (error) { 5293196008Smjacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 529439235Sgibbs xpt_done(ccb); 529539235Sgibbs break; 529639235Sgibbs } 5297196008Smjacob if (bootverbose) { 5298196008Smjacob xpt_print(ccb->ccb_h.path, "reset bus on channel %d\n", bus); 5299196008Smjacob } 5300196008Smjacob if (IS_FC(isp)) { 5301196008Smjacob xpt_async(AC_BUS_RESET, ISP_FC_PC(isp, bus)->path, 0); 5302157943Smjacob } else { 5303196008Smjacob xpt_async(AC_BUS_RESET, ISP_SPI_PC(isp, bus)->path, 0); 5304157943Smjacob } 5305157943Smjacob ccb->ccb_h.status = CAM_REQ_CMP; 530639235Sgibbs xpt_done(ccb); 530739235Sgibbs break; 5308196008Smjacob 5309196008Smjacob case XPT_TERM_IO: /* Terminate the I/O process */ 5310196008Smjacob ccb->ccb_h.status = CAM_REQ_INVALID; 5311157943Smjacob xpt_done(ccb); 5312157943Smjacob break; 5313196008Smjacob 5314196008Smjacob case XPT_SET_SIM_KNOB: /* Set SIM knobs */ 5315196008Smjacob { 5316196008Smjacob struct ccb_sim_knob *kp = &ccb->knob; 5317196008Smjacob fcparam *fcp; 5318196008Smjacob 5319196008Smjacob if (!IS_FC(isp)) { 5320196008Smjacob ccb->ccb_h.status = CAM_REQ_INVALID; 5321196008Smjacob xpt_done(ccb); 5322196008Smjacob break; 5323196008Smjacob } 5324196008Smjacob 5325196008Smjacob bus = cam_sim_bus(xpt_path_sim(kp->ccb_h.path)); 5326196008Smjacob fcp = FCPARAM(isp, bus); 5327196008Smjacob 5328196008Smjacob if (kp->xport_specific.fc.valid & KNOB_VALID_ADDRESS) { 5329196008Smjacob fcp->isp_wwnn = ISP_FC_PC(isp, bus)->def_wwnn = kp->xport_specific.fc.wwnn; 5330196008Smjacob fcp->isp_wwpn = ISP_FC_PC(isp, bus)->def_wwpn = kp->xport_specific.fc.wwpn; 5331224804Smjacob isp_prt(isp, ISP_LOGALL, "Setting Channel %d wwns to 0x%jx 0x%jx", bus, fcp->isp_wwnn, fcp->isp_wwpn); 5332196008Smjacob } 5333196008Smjacob ccb->ccb_h.status = CAM_REQ_CMP; 5334196008Smjacob if (kp->xport_specific.fc.valid & KNOB_VALID_ROLE) { 5335196008Smjacob int rchange = 0; 5336196008Smjacob int newrole = 0; 5337196008Smjacob 5338196008Smjacob switch (kp->xport_specific.fc.role) { 5339196008Smjacob case KNOB_ROLE_NONE: 5340196008Smjacob if (fcp->role != ISP_ROLE_NONE) { 5341196008Smjacob rchange = 1; 5342196008Smjacob newrole = ISP_ROLE_NONE; 5343196008Smjacob } 5344196008Smjacob break; 5345196008Smjacob case KNOB_ROLE_TARGET: 5346196008Smjacob if (fcp->role != ISP_ROLE_TARGET) { 5347196008Smjacob rchange = 1; 5348196008Smjacob newrole = ISP_ROLE_TARGET; 5349196008Smjacob } 5350196008Smjacob break; 5351196008Smjacob case KNOB_ROLE_INITIATOR: 5352196008Smjacob if (fcp->role != ISP_ROLE_INITIATOR) { 5353196008Smjacob rchange = 1; 5354196008Smjacob newrole = ISP_ROLE_INITIATOR; 5355196008Smjacob } 5356196008Smjacob break; 5357196008Smjacob case KNOB_ROLE_BOTH: 5358197214Smjacob#if 0 5359196008Smjacob if (fcp->role != ISP_ROLE_BOTH) { 5360196008Smjacob rchange = 1; 5361196008Smjacob newrole = ISP_ROLE_BOTH; 5362196008Smjacob } 5363197214Smjacob#else 5364197214Smjacob /* 5365197214Smjacob * We don't really support dual role at present on FC cards. 5366197214Smjacob * 5367197214Smjacob * We should, but a bunch of things are currently broken, 5368197214Smjacob * so don't allow it. 5369197214Smjacob */ 5370197214Smjacob isp_prt(isp, ISP_LOGERR, "cannot support dual role at present"); 5371197214Smjacob ccb->ccb_h.status = CAM_REQ_INVALID; 5372197214Smjacob#endif 5373196008Smjacob break; 5374196008Smjacob } 5375196008Smjacob if (rchange) { 5376236427Smjacob ISP_PATH_PRT(isp, ISP_LOGCONFIG, ccb->ccb_h.path, "changing role on from %d to %d\n", fcp->role, newrole); 5377238869Smjacob#ifdef ISP_TARGET_MODE 5378238869Smjacob ISP_SET_PC(isp, bus, tm_enabled, 0); 5379238869Smjacob ISP_SET_PC(isp, bus, tm_luns_enabled, 0); 5380238869Smjacob#endif 5381196008Smjacob if (isp_fc_change_role(isp, bus, newrole) != 0) { 5382196008Smjacob ccb->ccb_h.status = CAM_REQ_CMP_ERR; 5383238869Smjacob xpt_done(ccb); 5384238869Smjacob break; 5385238869Smjacob } 5386196008Smjacob#ifdef ISP_TARGET_MODE 5387238869Smjacob if (newrole == ISP_ROLE_TARGET || newrole == ISP_ROLE_BOTH) { 5388238869Smjacob /* 5389238869Smjacob * Give the new role a chance to complain and settle 5390238869Smjacob */ 5391238869Smjacob msleep(isp, &isp->isp_lock, PRIBIO, "taking a breather", 2); 5392236427Smjacob ccb->ccb_h.status = isp_enable_deferred_luns(isp, bus); 5393238869Smjacob } 5394157943Smjacob#endif 5395169292Smjacob } 539643790Smjacob } 539739235Sgibbs xpt_done(ccb); 539839235Sgibbs break; 5399196008Smjacob } 5400236427Smjacob case XPT_GET_SIM_KNOB: /* Get SIM knobs */ 5401196008Smjacob { 5402196008Smjacob struct ccb_sim_knob *kp = &ccb->knob; 540339235Sgibbs 5404196008Smjacob if (IS_FC(isp)) { 5405196008Smjacob fcparam *fcp; 5406196008Smjacob 5407196008Smjacob bus = cam_sim_bus(xpt_path_sim(kp->ccb_h.path)); 5408196008Smjacob fcp = FCPARAM(isp, bus); 5409196008Smjacob 5410196008Smjacob kp->xport_specific.fc.wwnn = fcp->isp_wwnn; 5411196008Smjacob kp->xport_specific.fc.wwpn = fcp->isp_wwpn; 5412196008Smjacob switch (fcp->role) { 5413196008Smjacob case ISP_ROLE_NONE: 5414196008Smjacob kp->xport_specific.fc.role = KNOB_ROLE_NONE; 5415196008Smjacob break; 5416196008Smjacob case ISP_ROLE_TARGET: 5417196008Smjacob kp->xport_specific.fc.role = KNOB_ROLE_TARGET; 5418196008Smjacob break; 5419196008Smjacob case ISP_ROLE_INITIATOR: 5420196008Smjacob kp->xport_specific.fc.role = KNOB_ROLE_INITIATOR; 5421196008Smjacob break; 5422196008Smjacob case ISP_ROLE_BOTH: 5423196008Smjacob kp->xport_specific.fc.role = KNOB_ROLE_BOTH; 5424196008Smjacob break; 5425196008Smjacob } 5426196008Smjacob kp->xport_specific.fc.valid = KNOB_VALID_ADDRESS | KNOB_VALID_ROLE; 5427196008Smjacob ccb->ccb_h.status = CAM_REQ_CMP; 5428196008Smjacob } else { 5429196008Smjacob ccb->ccb_h.status = CAM_REQ_INVALID; 5430196008Smjacob } 543139235Sgibbs xpt_done(ccb); 543239235Sgibbs break; 5433196008Smjacob } 543439235Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 543539235Sgibbs { 543639235Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 543739235Sgibbs 543839235Sgibbs cpi->version_num = 1; 543955371Smjacob#ifdef ISP_TARGET_MODE 544075200Smjacob cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO; 544155371Smjacob#else 544239235Sgibbs cpi->target_sprt = 0; 544355371Smjacob#endif 544439235Sgibbs cpi->hba_eng_cnt = 0; 544549915Smjacob cpi->max_target = ISP_MAX_TARGETS(isp) - 1; 544649915Smjacob cpi->max_lun = ISP_MAX_LUNS(isp) - 1; 544749915Smjacob cpi->bus_id = cam_sim_bus(sim); 5448254372Sken if (isp->isp_osinfo.sixtyfourbit) 5449254372Sken cpi->maxio = (ISP_NSEG64_MAX - 1) * PAGE_SIZE; 5450254372Sken else 5451254372Sken cpi->maxio = (ISP_NSEG_MAX - 1) * PAGE_SIZE; 5452254372Sken 5453196008Smjacob bus = cam_sim_bus(xpt_path_sim(cpi->ccb_h.path)); 545445040Smjacob if (IS_FC(isp)) { 5455196008Smjacob fcparam *fcp = FCPARAM(isp, bus); 5456196008Smjacob 5457251373Smarius cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED; 5458196008Smjacob 545946581Sken /* 546049915Smjacob * Because our loop ID can shift from time to time, 546149915Smjacob * make our initiator ID out of range of our bus. 546249915Smjacob */ 546349915Smjacob cpi->initiator_id = cpi->max_target + 1; 546449915Smjacob 546549915Smjacob /* 5466196008Smjacob * Set base transfer capabilities for Fibre Channel, for this HBA. 546746581Sken */ 5468224856Smjacob if (IS_25XX(isp)) { 5469224856Smjacob cpi->base_transfer_speed = 8000000; 5470224856Smjacob } else if (IS_24XX(isp)) { 5471196008Smjacob cpi->base_transfer_speed = 4000000; 5472196008Smjacob } else if (IS_23XX(isp)) { 5473196008Smjacob cpi->base_transfer_speed = 2000000; 5474196008Smjacob } else { 5475196008Smjacob cpi->base_transfer_speed = 1000000; 5476196008Smjacob } 547749915Smjacob cpi->hba_inquiry = PI_TAG_ABLE; 547879241Smjacob cpi->transport = XPORT_FC; 5479165337Smjacob cpi->transport_version = 0; 5480196008Smjacob cpi->xport_specific.fc.wwnn = fcp->isp_wwnn; 5481196008Smjacob cpi->xport_specific.fc.wwpn = fcp->isp_wwpn; 5482196008Smjacob cpi->xport_specific.fc.port = fcp->isp_portid; 5483196008Smjacob cpi->xport_specific.fc.bitrate = fcp->isp_gbspeed * 1000; 548439235Sgibbs } else { 5485196008Smjacob sdparam *sdp = SDPARAM(isp, bus); 548649915Smjacob cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; 5487251373Smarius cpi->hba_misc = PIM_UNMAPPED; 548846972Smjacob cpi->initiator_id = sdp->isp_initiator_id; 548946581Sken cpi->base_transfer_speed = 3300; 549079241Smjacob cpi->transport = XPORT_SPI; 5491165337Smjacob cpi->transport_version = 2; 549239235Sgibbs } 549379241Smjacob cpi->protocol = PROTO_SCSI; 549479241Smjacob cpi->protocol_version = SCSI_REV_2; 549539235Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 549639235Sgibbs strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN); 549739235Sgibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 549839235Sgibbs cpi->unit_number = cam_sim_unit(sim); 549939235Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 550039235Sgibbs xpt_done(ccb); 550139235Sgibbs break; 550239235Sgibbs } 550339235Sgibbs default: 550439235Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 550539235Sgibbs xpt_done(ccb); 550639235Sgibbs break; 550739235Sgibbs } 550839235Sgibbs} 550941523Smjacob 551041523Smjacob#define ISPDDB (CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB) 5511164272Smjacob 551241523Smjacobvoid 5513196008Smjacobisp_done(XS_T *sccb) 551441523Smjacob{ 5515157943Smjacob ispsoftc_t *isp = XS_ISP(sccb); 5516224856Smjacob uint32_t status; 551741523Smjacob 551841523Smjacob if (XS_NOERR(sccb)) 551941523Smjacob XS_SETERR(sccb, CAM_REQ_CMP); 552062173Smjacob 5521196008Smjacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP && (sccb->scsi_status != SCSI_STATUS_OK)) { 552241523Smjacob sccb->ccb_h.status &= ~CAM_STATUS_MASK; 5523196008Smjacob if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) && (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) { 552455387Smjacob sccb->ccb_h.status |= CAM_AUTOSENSE_FAIL; 552555387Smjacob } else { 552655387Smjacob sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 552755387Smjacob } 552841523Smjacob } 552962173Smjacob 553049915Smjacob sccb->ccb_h.status &= ~CAM_SIM_QUEUED; 5531224856Smjacob status = sccb->ccb_h.status & CAM_STATUS_MASK; 5532224856Smjacob if (status != CAM_REQ_CMP) { 5533224856Smjacob if (status != CAM_SEL_TIMEOUT) 5534224856Smjacob isp_prt(isp, ISP_LOGDEBUG0, "target %d lun %d CAM status 0x%x SCSI status 0x%x", XS_TGT(sccb), XS_LUN(sccb), sccb->ccb_h.status, sccb->scsi_status); 553541523Smjacob if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 553649915Smjacob sccb->ccb_h.status |= CAM_DEV_QFRZN; 553741523Smjacob xpt_freeze_devq(sccb->ccb_h.path, 1); 553841523Smjacob } 553941523Smjacob } 554062173Smjacob 5541196008Smjacob if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) && (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 5542196008Smjacob xpt_print(sccb->ccb_h.path, "cam completion status 0x%x\n", sccb->ccb_h.status); 554341523Smjacob } 554462173Smjacob 5545238869Smjacob if (callout_active(&PISP_PCMD(sccb)->wdog)) 5546224856Smjacob callout_stop(&PISP_PCMD(sccb)->wdog); 5547196008Smjacob isp_free_pcmd(isp, (union ccb *) sccb); 5548196008Smjacob xpt_done((union ccb *) sccb); 554941523Smjacob} 555041523Smjacob 5551196008Smjacobvoid 5552196008Smjacobisp_async(ispsoftc_t *isp, ispasync_t cmd, ...) 555343420Smjacob{ 5554196008Smjacob int bus; 5555238869Smjacob static const char prom0[] = "Chan %d PortID 0x%06x handle 0x%x %s %s WWPN 0x%08x%08x"; 5556238869Smjacob static const char prom2[] = "Chan %d PortID 0x%06x handle 0x%x %s %s tgt %u WWPN 0x%08x%08x"; 5557238869Smjacob char buf[64]; 5558164272Smjacob char *msg = NULL; 5559163899Smjacob target_id_t tgt; 5560163899Smjacob fcportdb_t *lp; 5561200089Smjacob struct isp_fc *fc; 5562163899Smjacob struct cam_path *tmppath; 5563196008Smjacob va_list ap; 5564163899Smjacob 556543420Smjacob switch (cmd) { 556643420Smjacob case ISPASYNC_NEW_TGT_PARAMS: 556749915Smjacob { 556879241Smjacob struct ccb_trans_settings_scsi *scsi; 556979241Smjacob struct ccb_trans_settings_spi *spi; 557049915Smjacob int flags, tgt; 5571196008Smjacob sdparam *sdp; 557279241Smjacob struct ccb_trans_settings cts; 557343420Smjacob 5574158816Smjacob memset(&cts, 0, sizeof (struct ccb_trans_settings)); 557579241Smjacob 5576196008Smjacob va_start(ap, cmd); 5577196008Smjacob bus = va_arg(ap, int); 5578196008Smjacob tgt = va_arg(ap, int); 5579196008Smjacob va_end(ap); 5580196008Smjacob sdp = SDPARAM(isp, bus); 5581196008Smjacob 5582196008Smjacob if (xpt_create_path(&tmppath, NULL, cam_sim_path(ISP_SPI_PC(isp, bus)->sim), tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 5583196008Smjacob isp_prt(isp, ISP_LOGWARN, "isp_async cannot make temp path for %d.%d", tgt, bus); 558449915Smjacob break; 558543420Smjacob } 558680583Smjacob flags = sdp->isp_devparam[tgt].actv_flags; 558779241Smjacob cts.type = CTS_TYPE_CURRENT_SETTINGS; 558879241Smjacob cts.protocol = PROTO_SCSI; 558979241Smjacob cts.transport = XPORT_SPI; 559079241Smjacob 559179241Smjacob scsi = &cts.proto_specific.scsi; 559279241Smjacob spi = &cts.xport_specific.spi; 559379241Smjacob 559479241Smjacob if (flags & DPARM_TQING) { 559579241Smjacob scsi->valid |= CTS_SCSI_VALID_TQ; 559679241Smjacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 559779241Smjacob } 559879241Smjacob 559949915Smjacob if (flags & DPARM_DISC) { 560079241Smjacob spi->valid |= CTS_SPI_VALID_DISC; 560179241Smjacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 560249915Smjacob } 560379241Smjacob spi->flags |= CTS_SPI_VALID_BUS_WIDTH; 560479241Smjacob if (flags & DPARM_WIDE) { 560579241Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 560679241Smjacob } else { 560779241Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 560879241Smjacob } 560979241Smjacob if (flags & DPARM_SYNC) { 561079241Smjacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 561179241Smjacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 561280583Smjacob spi->sync_period = sdp->isp_devparam[tgt].actv_period; 561380583Smjacob spi->sync_offset = sdp->isp_devparam[tgt].actv_offset; 561479241Smjacob } 5615196008Smjacob isp_prt(isp, ISP_LOGDEBUG2, "NEW_TGT_PARAMS bus %d tgt %d period %x offset %x flags %x", bus, tgt, sdp->isp_devparam[tgt].actv_period, sdp->isp_devparam[tgt].actv_offset, flags); 561679241Smjacob xpt_setup_ccb(&cts.ccb_h, tmppath, 1); 561779241Smjacob xpt_async(AC_TRANSFER_NEG, tmppath, &cts); 561880314Smjacob xpt_free_path(tmppath); 561943420Smjacob break; 562049915Smjacob } 562144819Smjacob case ISPASYNC_BUS_RESET: 5622196008Smjacob { 5623196008Smjacob va_start(ap, cmd); 5624196008Smjacob bus = va_arg(ap, int); 5625196008Smjacob va_end(ap); 5626196008Smjacob isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected", bus); 5627196008Smjacob if (IS_FC(isp)) { 5628196008Smjacob xpt_async(AC_BUS_RESET, ISP_FC_PC(isp, bus)->path, NULL); 5629196008Smjacob } else { 5630196008Smjacob xpt_async(AC_BUS_RESET, ISP_SPI_PC(isp, bus)->path, NULL); 563144819Smjacob } 563244819Smjacob break; 5633196008Smjacob } 563477365Smjacob case ISPASYNC_LIP: 5635164272Smjacob if (msg == NULL) { 5636164272Smjacob msg = "LIP Received"; 563777365Smjacob } 5638164272Smjacob /* FALLTHROUGH */ 563977365Smjacob case ISPASYNC_LOOP_RESET: 5640164272Smjacob if (msg == NULL) { 5641164272Smjacob msg = "LOOP Reset"; 564277365Smjacob } 5643164272Smjacob /* FALLTHROUGH */ 564444819Smjacob case ISPASYNC_LOOP_DOWN: 5645196008Smjacob { 5646164272Smjacob if (msg == NULL) { 5647164272Smjacob msg = "LOOP Down"; 5648164272Smjacob } 5649196008Smjacob va_start(ap, cmd); 5650196008Smjacob bus = va_arg(ap, int); 5651196008Smjacob va_end(ap); 5652196008Smjacob 5653200089Smjacob FCPARAM(isp, bus)->link_active = 0; 5654196008Smjacob 5655196008Smjacob fc = ISP_FC_PC(isp, bus); 5656200089Smjacob if (cmd == ISPASYNC_LOOP_DOWN && fc->ready) { 5657200089Smjacob /* 5658200089Smjacob * We don't do any simq freezing if we are only in target mode 5659200089Smjacob */ 5660205236Smjacob if (FCPARAM(isp, bus)->role & ISP_ROLE_INITIATOR) { 5661200089Smjacob if (fc->path) { 5662200089Smjacob isp_freeze_loopdown(isp, bus, msg); 5663200089Smjacob } 5664200089Smjacob if (!callout_active(&fc->ldt)) { 5665200089Smjacob callout_reset(&fc->ldt, fc->loop_down_limit * hz, isp_ldt, fc); 5666238869Smjacob isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "Starting Loop Down Timer @ %lu", (unsigned long) time_uptime); 5667200089Smjacob } 5668196008Smjacob } 566944819Smjacob } 5670196008Smjacob isp_prt(isp, ISP_LOGINFO, "Chan %d: %s", bus, msg); 567144819Smjacob break; 5672196008Smjacob } 567344819Smjacob case ISPASYNC_LOOP_UP: 5674196008Smjacob va_start(ap, cmd); 5675196008Smjacob bus = va_arg(ap, int); 5676196008Smjacob va_end(ap); 5677200089Smjacob fc = ISP_FC_PC(isp, bus); 567877365Smjacob /* 567977365Smjacob * Now we just note that Loop has come up. We don't 568077365Smjacob * actually do anything because we're waiting for a 568177365Smjacob * Change Notify before activating the FC cleanup 568277365Smjacob * thread to look at the state of the loop again. 568377365Smjacob */ 5684196008Smjacob FCPARAM(isp, bus)->link_active = 1; 5685200089Smjacob fc->loop_dead = 0; 5686200089Smjacob fc->loop_down_time = 0; 5687196008Smjacob isp_prt(isp, ISP_LOGINFO, "Chan %d Loop UP", bus); 568844819Smjacob break; 5689163899Smjacob case ISPASYNC_DEV_ARRIVED: 5690196008Smjacob va_start(ap, cmd); 5691196008Smjacob bus = va_arg(ap, int); 5692196008Smjacob lp = va_arg(ap, fcportdb_t *); 5693196008Smjacob va_end(ap); 5694200089Smjacob fc = ISP_FC_PC(isp, bus); 5695238869Smjacob lp->announced = 0; 5696208119Smjacob lp->gone_timer = 0; 5697238869Smjacob if ((FCPARAM(isp, bus)->role & ISP_ROLE_INITIATOR) && (lp->prli_word3 & PRLI_WD3_TARGET_FUNCTION)) { 5698196008Smjacob int dbidx = lp - FCPARAM(isp, bus)->portdb; 5699164272Smjacob int i; 5700163899Smjacob 5701164272Smjacob for (i = 0; i < MAX_FC_TARG; i++) { 5702164272Smjacob if (i >= FL_ID && i <= SNS_ID) { 5703164272Smjacob continue; 5704164272Smjacob } 5705196008Smjacob if (FCPARAM(isp, bus)->isp_dev_map[i] == 0) { 5706164272Smjacob break; 5707164272Smjacob } 5708164272Smjacob } 5709164272Smjacob if (i < MAX_FC_TARG) { 5710196008Smjacob FCPARAM(isp, bus)->isp_dev_map[i] = dbidx + 1; 5711196008Smjacob lp->dev_map_idx = i + 1; 5712164272Smjacob } else { 5713164272Smjacob isp_prt(isp, ISP_LOGWARN, "out of target ids"); 5714196008Smjacob isp_dump_portdb(isp, bus); 5715164272Smjacob } 5716164272Smjacob } 5717238869Smjacob isp_gen_role_str(buf, sizeof (buf), lp->prli_word3); 5718196008Smjacob if (lp->dev_map_idx) { 5719196008Smjacob tgt = lp->dev_map_idx - 1; 5720238869Smjacob isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, buf, "arrived at", tgt, (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn); 5721196008Smjacob isp_make_here(isp, bus, tgt); 5722163899Smjacob } else { 5723238869Smjacob isp_prt(isp, ISP_LOGCONFIG, prom0, bus, lp->portid, lp->handle, buf, "arrived", (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn); 5724163899Smjacob } 5725163899Smjacob break; 5726163899Smjacob case ISPASYNC_DEV_CHANGED: 5727196008Smjacob va_start(ap, cmd); 5728196008Smjacob bus = va_arg(ap, int); 5729196008Smjacob lp = va_arg(ap, fcportdb_t *); 5730196008Smjacob va_end(ap); 5731200089Smjacob fc = ISP_FC_PC(isp, bus); 5732238869Smjacob lp->announced = 0; 5733208119Smjacob lp->gone_timer = 0; 5734164272Smjacob if (isp_change_is_bad) { 5735164272Smjacob lp->state = FC_PORTDB_STATE_NIL; 5736196008Smjacob if (lp->dev_map_idx) { 5737196008Smjacob tgt = lp->dev_map_idx - 1; 5738196008Smjacob FCPARAM(isp, bus)->isp_dev_map[tgt] = 0; 5739196008Smjacob lp->dev_map_idx = 0; 5740196008Smjacob isp_prt(isp, ISP_LOGCONFIG, prom3, bus, lp->portid, tgt, "change is bad"); 5741196008Smjacob isp_make_gone(isp, bus, tgt); 5742164272Smjacob } else { 5743238869Smjacob isp_gen_role_str(buf, sizeof (buf), lp->prli_word3); 5744238869Smjacob isp_prt(isp, ISP_LOGCONFIG, prom0, bus, lp->portid, lp->handle, buf, "changed and departed", 5745196008Smjacob (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn); 5746164272Smjacob } 5747163899Smjacob } else { 5748164272Smjacob lp->portid = lp->new_portid; 5749238869Smjacob lp->prli_word3 = lp->new_prli_word3; 5750238869Smjacob isp_gen_role_str(buf, sizeof (buf), lp->prli_word3); 5751196008Smjacob if (lp->dev_map_idx) { 5752196008Smjacob int t = lp->dev_map_idx - 1; 5753196008Smjacob FCPARAM(isp, bus)->isp_dev_map[t] = (lp - FCPARAM(isp, bus)->portdb) + 1; 5754196008Smjacob tgt = lp->dev_map_idx - 1; 5755238869Smjacob isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, buf, "changed at", tgt, 5756196008Smjacob (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn); 5757164272Smjacob } else { 5758238869Smjacob isp_prt(isp, ISP_LOGCONFIG, prom0, bus, lp->portid, lp->handle, buf, "changed", (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn); 5759164272Smjacob } 5760163899Smjacob } 5761163899Smjacob break; 5762163899Smjacob case ISPASYNC_DEV_STAYED: 5763196008Smjacob va_start(ap, cmd); 5764196008Smjacob bus = va_arg(ap, int); 5765196008Smjacob lp = va_arg(ap, fcportdb_t *); 5766196008Smjacob va_end(ap); 5767238869Smjacob isp_gen_role_str(buf, sizeof (buf), lp->prli_word3); 5768196008Smjacob if (lp->dev_map_idx) { 5769196008Smjacob tgt = lp->dev_map_idx - 1; 5770238869Smjacob isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, buf, "stayed at", tgt, 5771196008Smjacob (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn); 5772163899Smjacob } else { 5773238869Smjacob isp_prt(isp, ISP_LOGCONFIG, prom0, bus, lp->portid, lp->handle, buf, "stayed", 5774196008Smjacob (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn); 5775163899Smjacob } 5776163899Smjacob break; 5777163899Smjacob case ISPASYNC_DEV_GONE: 5778196008Smjacob va_start(ap, cmd); 5779196008Smjacob bus = va_arg(ap, int); 5780196008Smjacob lp = va_arg(ap, fcportdb_t *); 5781196008Smjacob va_end(ap); 5782200089Smjacob fc = ISP_FC_PC(isp, bus); 5783164272Smjacob /* 5784164272Smjacob * If this has a virtual target and we haven't marked it 5785164272Smjacob * that we're going to have isp_gdt tell the OS it's gone, 5786164272Smjacob * set the isp_gdt timer running on it. 5787164272Smjacob * 5788164272Smjacob * If it isn't marked that isp_gdt is going to get rid of it, 5789164272Smjacob * announce that it's gone. 5790205236Smjacob * 5791164272Smjacob */ 5792238869Smjacob isp_gen_role_str(buf, sizeof (buf), lp->prli_word3); 5793238869Smjacob if (lp->dev_map_idx && lp->announced == 0) { 5794238869Smjacob lp->announced = 1; 5795164272Smjacob lp->state = FC_PORTDB_STATE_ZOMBIE; 5796208119Smjacob lp->gone_timer = ISP_FC_PC(isp, bus)->gone_device_time; 5797200089Smjacob if (fc->ready && !callout_active(&fc->gdt)) { 5798238869Smjacob isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "Chan %d Starting Gone Device Timer with %u seconds time now %lu", bus, lp->gone_timer, (unsigned long)time_uptime); 5799200089Smjacob callout_reset(&fc->gdt, hz, isp_gdt, fc); 5800164272Smjacob } 5801196008Smjacob tgt = lp->dev_map_idx - 1; 5802238869Smjacob isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, buf, "gone zombie at", tgt, (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn); 5803238869Smjacob } else if (lp->announced == 0) { 5804238869Smjacob isp_prt(isp, ISP_LOGCONFIG, prom0, bus, lp->portid, lp->handle, buf, "departed", (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn); 580579241Smjacob } 580644819Smjacob break; 580744819Smjacob case ISPASYNC_CHANGE_NOTIFY: 5808163899Smjacob { 5809163899Smjacob char *msg; 5810196008Smjacob int evt, nphdl, nlstate, reason; 5811196008Smjacob 5812196008Smjacob va_start(ap, cmd); 5813196008Smjacob bus = va_arg(ap, int); 5814196008Smjacob evt = va_arg(ap, int); 5815196008Smjacob if (IS_24XX(isp) && evt == ISPASYNC_CHANGE_PDB) { 5816196008Smjacob nphdl = va_arg(ap, int); 5817196008Smjacob nlstate = va_arg(ap, int); 5818196008Smjacob reason = va_arg(ap, int); 5819163899Smjacob } else { 5820196008Smjacob nphdl = NIL_HANDLE; 5821196008Smjacob nlstate = reason = 0; 582270822Smjacob } 5823196008Smjacob va_end(ap); 5824200089Smjacob fc = ISP_FC_PC(isp, bus); 5825196008Smjacob 5826196008Smjacob if (evt == ISPASYNC_CHANGE_PDB) { 5827196008Smjacob msg = "Chan %d Port Database Changed"; 5828196008Smjacob } else if (evt == ISPASYNC_CHANGE_SNS) { 5829196008Smjacob msg = "Chan %d Name Server Database Changed"; 5830196008Smjacob } else { 5831196008Smjacob msg = "Chan %d Other Change Notify"; 5832196008Smjacob } 5833196008Smjacob 5834164272Smjacob /* 5835164272Smjacob * If the loop down timer is running, cancel it. 5836164272Smjacob */ 5837200089Smjacob if (fc->ready && callout_active(&fc->ldt)) { 5838238869Smjacob isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "Stopping Loop Down Timer @ %lu", (unsigned long) time_uptime); 5839200089Smjacob callout_stop(&fc->ldt); 5840164272Smjacob } 5841196008Smjacob isp_prt(isp, ISP_LOGINFO, msg, bus); 5842205236Smjacob if (FCPARAM(isp, bus)->role & ISP_ROLE_INITIATOR) { 5843196008Smjacob isp_freeze_loopdown(isp, bus, msg); 5844196008Smjacob } 5845200089Smjacob wakeup(fc); 584644819Smjacob break; 584744819Smjacob } 584855371Smjacob#ifdef ISP_TARGET_MODE 5849154704Smjacob case ISPASYNC_TARGET_NOTIFY: 585055371Smjacob { 5851196008Smjacob isp_notify_t *notify; 5852196008Smjacob va_start(ap, cmd); 5853196008Smjacob notify = va_arg(ap, isp_notify_t *); 5854196008Smjacob va_end(ap); 5855196008Smjacob switch (notify->nt_ncode) { 5856196008Smjacob case NT_ABORT_TASK: 5857196008Smjacob case NT_ABORT_TASK_SET: 5858196008Smjacob case NT_CLEAR_ACA: 5859196008Smjacob case NT_CLEAR_TASK_SET: 5860196008Smjacob case NT_LUN_RESET: 5861196008Smjacob case NT_TARGET_RESET: 5862196008Smjacob /* 5863196008Smjacob * These are task management functions. 5864196008Smjacob */ 5865196008Smjacob isp_handle_platform_target_tmf(isp, notify); 5866196008Smjacob break; 5867196008Smjacob case NT_BUS_RESET: 5868196008Smjacob case NT_LIP_RESET: 5869196008Smjacob case NT_LINK_UP: 5870196008Smjacob case NT_LINK_DOWN: 5871196008Smjacob /* 5872196008Smjacob * No action need be taken here. 5873196008Smjacob */ 5874196008Smjacob break; 5875196008Smjacob case NT_HBA_RESET: 5876196008Smjacob isp_del_all_wwn_entries(isp, ISP_NOCHAN); 5877196008Smjacob break; 5878238869Smjacob case NT_GLOBAL_LOGOUT: 5879196008Smjacob case NT_LOGOUT: 5880196008Smjacob /* 5881196008Smjacob * This is device arrival/departure notification 5882196008Smjacob */ 5883196008Smjacob isp_handle_platform_target_notify_ack(isp, notify); 5884196008Smjacob break; 5885196008Smjacob case NT_ARRIVED: 5886196008Smjacob { 5887196008Smjacob struct ac_contract ac; 5888196008Smjacob struct ac_device_changed *fc; 5889196008Smjacob 5890196008Smjacob ac.contract_number = AC_CONTRACT_DEV_CHG; 5891196008Smjacob fc = (struct ac_device_changed *) ac.contract_data; 5892196008Smjacob fc->wwpn = notify->nt_wwn; 5893196008Smjacob fc->port = notify->nt_sid; 5894196008Smjacob fc->target = notify->nt_nphdl; 5895196008Smjacob fc->arrived = 1; 5896196008Smjacob xpt_async(AC_CONTRACT, ISP_FC_PC(isp, notify->nt_channel)->path, &ac); 5897196008Smjacob break; 5898196008Smjacob } 5899196008Smjacob case NT_DEPARTED: 5900196008Smjacob { 5901196008Smjacob struct ac_contract ac; 5902196008Smjacob struct ac_device_changed *fc; 5903196008Smjacob 5904196008Smjacob ac.contract_number = AC_CONTRACT_DEV_CHG; 5905196008Smjacob fc = (struct ac_device_changed *) ac.contract_data; 5906196008Smjacob fc->wwpn = notify->nt_wwn; 5907196008Smjacob fc->port = notify->nt_sid; 5908196008Smjacob fc->target = notify->nt_nphdl; 5909196008Smjacob fc->arrived = 0; 5910196008Smjacob xpt_async(AC_CONTRACT, ISP_FC_PC(isp, notify->nt_channel)->path, &ac); 5911196008Smjacob break; 5912196008Smjacob } 5913196008Smjacob default: 5914196008Smjacob isp_prt(isp, ISP_LOGALL, "target notify code 0x%x", notify->nt_ncode); 5915196008Smjacob isp_handle_platform_target_notify_ack(isp, notify); 5916196008Smjacob break; 5917196008Smjacob } 591855371Smjacob break; 591955371Smjacob } 5920238869Smjacob case ISPASYNC_TARGET_NOTIFY_ACK: 5921238869Smjacob { 5922238869Smjacob void *inot; 5923238869Smjacob va_start(ap, cmd); 5924238869Smjacob inot = va_arg(ap, void *); 5925238869Smjacob va_end(ap); 5926238869Smjacob if (isp_notify_ack(isp, inot)) { 5927238869Smjacob isp_tna_t *tp = malloc(sizeof (*tp), M_DEVBUF, M_NOWAIT); 5928238869Smjacob if (tp) { 5929238869Smjacob tp->isp = isp; 5930238869Smjacob if (inot) { 5931238869Smjacob memcpy(tp->data, inot, sizeof (tp->data)); 5932238869Smjacob tp->not = tp->data; 5933238869Smjacob } else { 5934238869Smjacob tp->not = NULL; 5935238869Smjacob } 5936238869Smjacob (void) timeout(isp_refire_notify_ack, tp, 5); 5937238869Smjacob } else { 5938238869Smjacob isp_prt(isp, ISP_LOGERR, "you lose- cannot allocate a notify refire"); 5939238869Smjacob } 5940238869Smjacob } 5941238869Smjacob break; 5942238869Smjacob } 594355371Smjacob case ISPASYNC_TARGET_ACTION: 5944196008Smjacob { 5945196008Smjacob isphdr_t *hp; 5946196008Smjacob 5947196008Smjacob va_start(ap, cmd); 5948196008Smjacob hp = va_arg(ap, isphdr_t *); 5949196008Smjacob va_end(ap); 5950196008Smjacob switch (hp->rqs_entry_type) { 595155371Smjacob default: 5952196008Smjacob isp_prt(isp, ISP_LOGWARN, "%s: unhandled target action 0x%x", __func__, hp->rqs_entry_type); 595355371Smjacob break; 595498289Smjacob case RQSTYPE_NOTIFY: 595598289Smjacob if (IS_SCSI(isp)) { 5956196008Smjacob isp_handle_platform_notify_scsi(isp, (in_entry_t *) hp); 5957196008Smjacob } else if (IS_24XX(isp)) { 5958196008Smjacob isp_handle_platform_notify_24xx(isp, (in_fcentry_24xx_t *) hp); 595998289Smjacob } else { 5960196008Smjacob isp_handle_platform_notify_fc(isp, (in_fcentry_t *) hp); 596198289Smjacob } 596298289Smjacob break; 596355371Smjacob case RQSTYPE_ATIO: 5964196008Smjacob if (IS_24XX(isp)) { 5965196008Smjacob isp_handle_platform_atio7(isp, (at7_entry_t *) hp); 5966196008Smjacob } else { 5967196008Smjacob isp_handle_platform_atio(isp, (at_entry_t *) hp); 5968196008Smjacob } 596955371Smjacob break; 597055371Smjacob case RQSTYPE_ATIO2: 5971196008Smjacob isp_handle_platform_atio2(isp, (at2_entry_t *) hp); 597255371Smjacob break; 5973196008Smjacob case RQSTYPE_CTIO7: 5974158819Smjacob case RQSTYPE_CTIO3: 597555371Smjacob case RQSTYPE_CTIO2: 597655371Smjacob case RQSTYPE_CTIO: 5977196008Smjacob isp_handle_platform_ctio(isp, hp); 597855371Smjacob break; 5979196008Smjacob case RQSTYPE_ABTS_RCVD: 5980196008Smjacob { 5981196008Smjacob abts_t *abts = (abts_t *)hp; 5982196008Smjacob isp_notify_t notify, *nt = ¬ify; 5983196008Smjacob tstate_t *tptr; 5984196008Smjacob fcportdb_t *lp; 5985196008Smjacob uint16_t chan; 5986196008Smjacob uint32_t sid, did; 5987196008Smjacob 5988196008Smjacob did = (abts->abts_did_hi << 16) | abts->abts_did_lo; 5989196008Smjacob sid = (abts->abts_sid_hi << 16) | abts->abts_sid_lo; 5990196008Smjacob ISP_MEMZERO(nt, sizeof (isp_notify_t)); 5991196008Smjacob 5992196008Smjacob nt->nt_hba = isp; 5993196008Smjacob nt->nt_did = did; 5994196008Smjacob nt->nt_nphdl = abts->abts_nphdl; 5995196008Smjacob nt->nt_sid = sid; 5996196008Smjacob isp_find_chan_by_did(isp, did, &chan); 5997196008Smjacob if (chan == ISP_NOCHAN) { 5998196008Smjacob nt->nt_tgt = TGT_ANY; 5999196008Smjacob } else { 6000196008Smjacob nt->nt_tgt = FCPARAM(isp, chan)->isp_wwpn; 6001196008Smjacob if (isp_find_pdb_by_loopid(isp, chan, abts->abts_nphdl, &lp)) { 6002196008Smjacob nt->nt_wwn = lp->port_wwn; 6003196008Smjacob } else { 6004196008Smjacob nt->nt_wwn = INI_ANY; 6005196008Smjacob } 6006196008Smjacob } 6007196008Smjacob /* 6008196008Smjacob * Try hard to find the lun for this command. 6009196008Smjacob */ 6010196008Smjacob tptr = get_lun_statep_from_tag(isp, chan, abts->abts_rxid_task); 6011196008Smjacob if (tptr) { 6012196008Smjacob nt->nt_lun = xpt_path_lun_id(tptr->owner); 6013196008Smjacob rls_lun_statep(isp, tptr); 6014196008Smjacob } else { 6015196008Smjacob nt->nt_lun = LUN_ANY; 6016196008Smjacob } 6017196008Smjacob nt->nt_need_ack = 1; 6018196008Smjacob nt->nt_tagval = abts->abts_rxid_task; 6019196008Smjacob nt->nt_tagval |= (((uint64_t) abts->abts_rxid_abts) << 32); 6020196008Smjacob if (abts->abts_rxid_task == ISP24XX_NO_TASK) { 6021196008Smjacob isp_prt(isp, ISP_LOGTINFO, "[0x%x] ABTS from N-Port handle 0x%x Port 0x%06x has no task id (rx_id 0x%04x ox_id 0x%04x)", 6022196008Smjacob abts->abts_rxid_abts, abts->abts_nphdl, sid, abts->abts_rx_id, abts->abts_ox_id); 6023196008Smjacob } else { 6024196008Smjacob isp_prt(isp, ISP_LOGTINFO, "[0x%x] ABTS from N-Port handle 0x%x Port 0x%06x for task 0x%x (rx_id 0x%04x ox_id 0x%04x)", 6025196008Smjacob abts->abts_rxid_abts, abts->abts_nphdl, sid, abts->abts_rxid_task, abts->abts_rx_id, abts->abts_ox_id); 6026196008Smjacob } 6027196008Smjacob nt->nt_channel = chan; 6028196008Smjacob nt->nt_ncode = NT_ABORT_TASK; 6029196008Smjacob nt->nt_lreserved = hp; 6030196008Smjacob isp_handle_platform_target_tmf(isp, nt); 6031196008Smjacob break; 6032196008Smjacob } 603355371Smjacob case RQSTYPE_ENABLE_LUN: 603455371Smjacob case RQSTYPE_MODIFY_LUN: 6035196008Smjacob isp_ledone(isp, (lun_entry_t *) hp); 603655371Smjacob break; 603755371Smjacob } 603855371Smjacob break; 6039196008Smjacob } 604055371Smjacob#endif 604179241Smjacob case ISPASYNC_FW_CRASH: 604279241Smjacob { 6043155704Smjacob uint16_t mbox1, mbox6; 604479241Smjacob mbox1 = ISP_READ(isp, OUTMAILBOX1); 604579241Smjacob if (IS_DUALBUS(isp)) { 604679241Smjacob mbox6 = ISP_READ(isp, OUTMAILBOX6); 604779241Smjacob } else { 604879241Smjacob mbox6 = 0; 604979241Smjacob } 6050196008Smjacob isp_prt(isp, ISP_LOGERR, "Internal Firmware Error on bus %d @ RISC Address 0x%x", mbox6, mbox1); 6051169292Smjacob mbox1 = isp->isp_osinfo.mbox_sleep_ok; 6052169292Smjacob isp->isp_osinfo.mbox_sleep_ok = 0; 6053196008Smjacob isp_reinit(isp, 1); 6054169292Smjacob isp->isp_osinfo.mbox_sleep_ok = mbox1; 6055102015Smjacob isp_async(isp, ISPASYNC_FW_RESTARTED, NULL); 605679241Smjacob break; 605779241Smjacob } 605843420Smjacob default: 605964093Smjacob isp_prt(isp, ISP_LOGERR, "unknown isp_async event %d", cmd); 606043420Smjacob break; 606143420Smjacob } 606243420Smjacob} 606342131Smjacob 606448488Smjacob 606542131Smjacob/* 606642131Smjacob * Locks are held before coming here. 606742131Smjacob */ 606842131Smjacobvoid 6069157943Smjacobisp_uninit(ispsoftc_t *isp) 607042131Smjacob{ 6071163899Smjacob if (IS_24XX(isp)) { 6072163899Smjacob ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_RESET); 6073163899Smjacob } else { 6074163899Smjacob ISP_WRITE(isp, HCCR, HCCR_CMD_RESET); 6075163899Smjacob } 6076163899Smjacob ISP_DISABLE_INTS(isp); 607742131Smjacob} 607864093Smjacob 6079196008Smjacob/* 6080196008Smjacob * When we want to get the 'default' WWNs (when lacking NVRAM), we pick them 6081196008Smjacob * up from our platform default (defww{p|n}n) and morph them based upon 6082196008Smjacob * channel. 6083196008Smjacob * 6084196008Smjacob * When we want to get the 'active' WWNs, we get NVRAM WWNs and then morph them 6085196008Smjacob * based upon channel. 6086196008Smjacob */ 6087196008Smjacob 6088196008Smjacobuint64_t 6089196008Smjacobisp_default_wwn(ispsoftc_t * isp, int chan, int isactive, int iswwnn) 6090196008Smjacob{ 6091196008Smjacob uint64_t seed; 6092196008Smjacob struct isp_fc *fc = ISP_FC_PC(isp, chan); 6093196008Smjacob 6094196008Smjacob /* 6095196008Smjacob * If we're asking for a active WWN, the default overrides get 6096196008Smjacob * returned, otherwise the NVRAM value is picked. 6097196008Smjacob * 6098196008Smjacob * If we're asking for a default WWN, we just pick the default override. 6099196008Smjacob */ 6100196008Smjacob if (isactive) { 6101196008Smjacob seed = iswwnn ? fc->def_wwnn : fc->def_wwpn; 6102196008Smjacob if (seed) { 6103196008Smjacob return (seed); 6104196008Smjacob } 6105196008Smjacob seed = iswwnn ? FCPARAM(isp, chan)->isp_wwnn_nvram : FCPARAM(isp, chan)->isp_wwpn_nvram; 6106196162Smjacob if (seed) { 6107196162Smjacob return (seed); 6108196162Smjacob } 6109196162Smjacob return (0x400000007F000009ull); 6110196008Smjacob } else { 6111196008Smjacob seed = iswwnn ? fc->def_wwnn : fc->def_wwpn; 6112196008Smjacob } 6113196008Smjacob 6114196008Smjacob 6115196008Smjacob /* 6116215034Sbrucec * For channel zero just return what we have. For either ACTIVE or 6117196008Smjacob * DEFAULT cases, we depend on default override of NVRAM values for 6118196008Smjacob * channel zero. 6119196008Smjacob */ 6120196008Smjacob if (chan == 0) { 6121196008Smjacob return (seed); 6122196008Smjacob } 6123196008Smjacob 6124196008Smjacob /* 6125196008Smjacob * For other channels, we are doing one of three things: 6126196008Smjacob * 6127196008Smjacob * 1. If what we have now is non-zero, return it. Otherwise we morph 6128196008Smjacob * values from channel 0. 2. If we're here for a WWPN we synthesize 6129196008Smjacob * it if Channel 0's wwpn has a type 2 NAA. 3. If we're here for a 6130196008Smjacob * WWNN we synthesize it if Channel 0's wwnn has a type 2 NAA. 6131196008Smjacob */ 6132196008Smjacob 6133196008Smjacob if (seed) { 6134196008Smjacob return (seed); 6135196008Smjacob } 6136196008Smjacob if (isactive) { 6137196008Smjacob seed = iswwnn ? FCPARAM(isp, 0)->isp_wwnn_nvram : FCPARAM(isp, 0)->isp_wwpn_nvram; 6138196008Smjacob } else { 6139196008Smjacob seed = iswwnn ? ISP_FC_PC(isp, 0)->def_wwnn : ISP_FC_PC(isp, 0)->def_wwpn; 6140196008Smjacob } 6141196008Smjacob 6142196008Smjacob if (((seed >> 60) & 0xf) == 2) { 6143196008Smjacob /* 6144196008Smjacob * The type 2 NAA fields for QLogic cards appear be laid out 6145196008Smjacob * thusly: 6146196008Smjacob * 6147196008Smjacob * bits 63..60 NAA == 2 bits 59..57 unused/zero bit 56 6148196008Smjacob * port (1) or node (0) WWN distinguishor bit 48 6149196008Smjacob * physical port on dual-port chips (23XX/24XX) 6150196008Smjacob * 6151196008Smjacob * This is somewhat nutty, particularly since bit 48 is 6152215034Sbrucec * irrelevant as they assign separate serial numbers to 6153196008Smjacob * different physical ports anyway. 6154196008Smjacob * 6155196008Smjacob * We'll stick our channel number plus one first into bits 6156196008Smjacob * 57..59 and thence into bits 52..55 which allows for 8 bits 6157196008Smjacob * of channel which is comfortably more than our maximum 6158196008Smjacob * (126) now. 6159196008Smjacob */ 6160196008Smjacob seed &= ~0x0FF0000000000000ULL; 6161196008Smjacob if (iswwnn == 0) { 6162196008Smjacob seed |= ((uint64_t) (chan + 1) & 0xf) << 56; 6163196008Smjacob seed |= ((uint64_t) ((chan + 1) >> 4) & 0xf) << 52; 6164196008Smjacob } 6165196008Smjacob } else { 6166196008Smjacob seed = 0; 6167196008Smjacob } 6168196008Smjacob return (seed); 6169196008Smjacob} 6170196008Smjacob 617164093Smjacobvoid 6172157943Smjacobisp_prt(ispsoftc_t *isp, int level, const char *fmt, ...) 617364093Smjacob{ 6174224804Smjacob int loc; 6175238869Smjacob char lbuf[200]; 617664093Smjacob va_list ap; 6177224804Smjacob 617864093Smjacob if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) { 617964093Smjacob return; 618064093Smjacob } 6181238869Smjacob snprintf(lbuf, sizeof (lbuf), "%s: ", device_get_nameunit(isp->isp_dev)); 6182224804Smjacob loc = strlen(lbuf); 618364093Smjacob va_start(ap, fmt); 6184224804Smjacob vsnprintf(&lbuf[loc], sizeof (lbuf) - loc - 1, fmt, ap); 618564093Smjacob va_end(ap); 6186224804Smjacob printf("%s\n", lbuf); 618764093Smjacob} 6188164272Smjacob 6189205698Smjacobvoid 6190205698Smjacobisp_xs_prt(ispsoftc_t *isp, XS_T *xs, int level, const char *fmt, ...) 6191205698Smjacob{ 6192205698Smjacob va_list ap; 6193205698Smjacob if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) { 6194205698Smjacob return; 6195205698Smjacob } 6196205698Smjacob xpt_print_path(xs->ccb_h.path); 6197205698Smjacob va_start(ap, fmt); 6198205698Smjacob vprintf(fmt, ap); 6199205698Smjacob va_end(ap); 6200205698Smjacob printf("\n"); 6201205698Smjacob} 6202205698Smjacob 6203164272Smjacobuint64_t 6204164272Smjacobisp_nanotime_sub(struct timespec *b, struct timespec *a) 6205164272Smjacob{ 6206164272Smjacob uint64_t elapsed; 6207164272Smjacob struct timespec x = *b; 6208164272Smjacob timespecsub(&x, a); 6209164272Smjacob elapsed = GET_NANOSEC(&x); 6210164272Smjacob if (elapsed == 0) 6211164272Smjacob elapsed++; 6212164272Smjacob return (elapsed); 6213164272Smjacob} 6214164272Smjacob 6215164272Smjacobint 6216164272Smjacobisp_mbox_acquire(ispsoftc_t *isp) 6217164272Smjacob{ 6218164272Smjacob if (isp->isp_osinfo.mboxbsy) { 6219164272Smjacob return (1); 6220164272Smjacob } else { 6221164272Smjacob isp->isp_osinfo.mboxcmd_done = 0; 6222164272Smjacob isp->isp_osinfo.mboxbsy = 1; 6223164272Smjacob return (0); 6224164272Smjacob } 6225164272Smjacob} 6226164272Smjacob 6227164272Smjacobvoid 6228164272Smjacobisp_mbox_wait_complete(ispsoftc_t *isp, mbreg_t *mbp) 6229164272Smjacob{ 6230165308Smjacob unsigned int usecs = mbp->timeout; 6231165308Smjacob unsigned int max, olim, ilim; 6232164272Smjacob 6233164272Smjacob if (usecs == 0) { 6234164272Smjacob usecs = MBCMD_DEFAULT_TIMEOUT; 6235164272Smjacob } 6236165308Smjacob max = isp->isp_mbxwrk0 + 1; 6237165308Smjacob 6238164272Smjacob if (isp->isp_osinfo.mbox_sleep_ok) { 6239165308Smjacob unsigned int ms = (usecs + 999) / 1000; 6240165308Smjacob 6241164272Smjacob isp->isp_osinfo.mbox_sleep_ok = 0; 6242164272Smjacob isp->isp_osinfo.mbox_sleeping = 1; 6243165308Smjacob for (olim = 0; olim < max; olim++) { 6244196008Smjacob msleep(&isp->isp_mbxworkp, &isp->isp_osinfo.lock, PRIBIO, "ispmbx_sleep", isp_mstohz(ms)); 6245165308Smjacob if (isp->isp_osinfo.mboxcmd_done) { 6246165308Smjacob break; 6247165308Smjacob } 6248165308Smjacob } 6249164272Smjacob isp->isp_osinfo.mbox_sleep_ok = 1; 6250164272Smjacob isp->isp_osinfo.mbox_sleeping = 0; 6251164272Smjacob } else { 6252165308Smjacob for (olim = 0; olim < max; olim++) { 6253165308Smjacob for (ilim = 0; ilim < usecs; ilim += 100) { 6254165308Smjacob uint32_t isr; 6255165308Smjacob uint16_t sema, mbox; 6256164272Smjacob if (isp->isp_osinfo.mboxcmd_done) { 6257164272Smjacob break; 6258164272Smjacob } 6259165308Smjacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { 6260165308Smjacob isp_intr(isp, isr, sema, mbox); 6261165308Smjacob if (isp->isp_osinfo.mboxcmd_done) { 6262165308Smjacob break; 6263165308Smjacob } 6264165308Smjacob } 6265196008Smjacob ISP_DELAY(100); 6266164272Smjacob } 6267165308Smjacob if (isp->isp_osinfo.mboxcmd_done) { 6268165308Smjacob break; 6269165308Smjacob } 6270164272Smjacob } 6271164272Smjacob } 6272164272Smjacob if (isp->isp_osinfo.mboxcmd_done == 0) { 6273196008Smjacob isp_prt(isp, ISP_LOGWARN, "%s Mailbox Command (0x%x) Timeout (%uus) (started @ %s:%d)", 6274196008Smjacob isp->isp_osinfo.mbox_sleep_ok? "Interrupting" : "Polled", isp->isp_lastmbxcmd, usecs, mbp->func, mbp->lineno); 6275164272Smjacob mbp->param[0] = MBOX_TIMEOUT; 6276164272Smjacob isp->isp_osinfo.mboxcmd_done = 1; 6277164272Smjacob } 6278164272Smjacob} 6279164272Smjacob 6280164272Smjacobvoid 6281164272Smjacobisp_mbox_notify_done(ispsoftc_t *isp) 6282164272Smjacob{ 6283164272Smjacob if (isp->isp_osinfo.mbox_sleeping) { 6284164272Smjacob wakeup(&isp->isp_mbxworkp); 6285164272Smjacob } 6286164272Smjacob isp->isp_osinfo.mboxcmd_done = 1; 6287164272Smjacob} 6288164272Smjacob 6289164272Smjacobvoid 6290164272Smjacobisp_mbox_release(ispsoftc_t *isp) 6291164272Smjacob{ 6292164272Smjacob isp->isp_osinfo.mboxbsy = 0; 6293164272Smjacob} 6294164272Smjacob 6295164272Smjacobint 6296196008Smjacobisp_fc_scratch_acquire(ispsoftc_t *isp, int chan) 6297196008Smjacob{ 6298196008Smjacob int ret = 0; 6299196008Smjacob if (isp->isp_osinfo.pc.fc[chan].fcbsy) { 6300196008Smjacob ret = -1; 6301196008Smjacob } else { 6302196008Smjacob isp->isp_osinfo.pc.fc[chan].fcbsy = 1; 6303196008Smjacob } 6304196008Smjacob return (ret); 6305196008Smjacob} 6306196008Smjacob 6307196008Smjacobint 6308164272Smjacobisp_mstohz(int ms) 6309164272Smjacob{ 6310165308Smjacob int hz; 6311164272Smjacob struct timeval t; 6312164272Smjacob t.tv_sec = ms / 1000; 6313164272Smjacob t.tv_usec = (ms % 1000) * 1000; 6314165308Smjacob hz = tvtohz(&t); 6315165308Smjacob if (hz < 0) { 6316165308Smjacob hz = 0x7fffffff; 6317164272Smjacob } 6318165308Smjacob if (hz == 0) { 6319165308Smjacob hz = 1; 6320165308Smjacob } 6321165308Smjacob return (hz); 6322164272Smjacob} 6323169292Smjacob 6324169292Smjacobvoid 6325169292Smjacobisp_platform_intr(void *arg) 6326169292Smjacob{ 6327169292Smjacob ispsoftc_t *isp = arg; 6328169292Smjacob uint32_t isr; 6329169292Smjacob uint16_t sema, mbox; 6330169292Smjacob 6331169292Smjacob ISP_LOCK(isp); 6332169292Smjacob isp->isp_intcnt++; 6333169292Smjacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox) == 0) { 6334169292Smjacob isp->isp_intbogus++; 6335169292Smjacob } else { 6336169292Smjacob isp_intr(isp, isr, sema, mbox); 6337169292Smjacob } 6338169292Smjacob ISP_UNLOCK(isp); 6339169292Smjacob} 6340169292Smjacob 6341169292Smjacobvoid 6342169292Smjacobisp_common_dmateardown(ispsoftc_t *isp, struct ccb_scsiio *csio, uint32_t hdl) 6343169292Smjacob{ 6344169292Smjacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 6345196008Smjacob bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_POSTREAD); 6346169292Smjacob } else { 6347196008Smjacob bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_POSTWRITE); 6348169292Smjacob } 6349169292Smjacob bus_dmamap_unload(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap); 6350169292Smjacob} 6351196008Smjacob 6352238869Smjacobint 6353238869Smjacobisp_fcp_next_crn(ispsoftc_t *isp, uint8_t *crnp, XS_T *cmd) 6354238869Smjacob{ 6355239218Smjacob uint32_t chan, tgt, lun; 6356239218Smjacob struct isp_fc *fc; 6357239218Smjacob struct isp_nexus *nxp; 6358239218Smjacob int idx; 6359238869Smjacob 6360239218Smjacob if (isp->isp_type < ISP_HA_FC_2300) 6361239218Smjacob return (0); 6362239218Smjacob 6363239218Smjacob chan = XS_CHANNEL(cmd); 6364239218Smjacob tgt = XS_TGT(cmd); 6365239218Smjacob lun = XS_LUN(cmd); 6366239218Smjacob fc = &isp->isp_osinfo.pc.fc[chan]; 6367239218Smjacob idx = NEXUS_HASH(tgt, lun); 6368239218Smjacob nxp = fc->nexus_hash[idx]; 6369239218Smjacob 6370238869Smjacob while (nxp) { 6371238869Smjacob if (nxp->tgt == tgt && nxp->lun == lun) 6372238869Smjacob break; 6373238869Smjacob nxp = nxp->next; 6374238869Smjacob } 6375238869Smjacob if (nxp == NULL) { 6376238869Smjacob nxp = fc->nexus_free_list; 6377238869Smjacob if (nxp == NULL) { 6378238869Smjacob nxp = malloc(sizeof (struct isp_nexus), M_DEVBUF, M_ZERO|M_NOWAIT); 6379238869Smjacob if (nxp == NULL) { 6380238869Smjacob return (-1); 6381238869Smjacob } 6382238869Smjacob } else { 6383238869Smjacob fc->nexus_free_list = nxp->next; 6384238869Smjacob } 6385238869Smjacob nxp->tgt = tgt; 6386238869Smjacob nxp->lun = lun; 6387238869Smjacob nxp->next = fc->nexus_hash[idx]; 6388238869Smjacob fc->nexus_hash[idx] = nxp; 6389238869Smjacob } 6390238869Smjacob if (nxp) { 6391238869Smjacob if (nxp->crnseed == 0) 6392238869Smjacob nxp->crnseed = 1; 6393238869Smjacob if (cmd) 6394238869Smjacob PISP_PCMD(cmd)->crn = nxp->crnseed; 6395238869Smjacob *crnp = nxp->crnseed++; 6396238869Smjacob return (0); 6397238869Smjacob } 6398238869Smjacob return (-1); 6399238869Smjacob} 6400238869Smjacob 6401239143Smjacob/* 6402239143Smjacob * We enter with the lock held 6403239143Smjacob */ 6404196008Smjacobvoid 6405196008Smjacobisp_timer(void *arg) 6406196008Smjacob{ 6407196008Smjacob ispsoftc_t *isp = arg; 6408196008Smjacob#ifdef ISP_TARGET_MODE 6409196008Smjacob isp_tmcmd_restart(isp); 6410196008Smjacob#endif 6411239143Smjacob callout_reset(&isp->isp_osinfo.tmo, isp_timer_count, isp_timer, isp); 6412196008Smjacob} 6413238869Smjacob 6414238869Smjacobisp_ecmd_t * 6415238869Smjacobisp_get_ecmd(ispsoftc_t *isp) 6416238869Smjacob{ 6417238869Smjacob isp_ecmd_t *ecmd = isp->isp_osinfo.ecmd_free; 6418238869Smjacob if (ecmd) { 6419238869Smjacob isp->isp_osinfo.ecmd_free = ecmd->next; 6420238869Smjacob } 6421238869Smjacob return (ecmd); 6422238869Smjacob} 6423238869Smjacob 6424238869Smjacobvoid 6425238869Smjacobisp_put_ecmd(ispsoftc_t *isp, isp_ecmd_t *ecmd) 6426238869Smjacob{ 6427238869Smjacob ecmd->next = isp->isp_osinfo.ecmd_free; 6428238869Smjacob isp->isp_osinfo.ecmd_free = ecmd; 6429238869Smjacob} 6430