1147883Sscottl/*- 2147883Sscottl * FreeBSD/CAM specific routines for LSI '909 FC adapters. 3147883Sscottl * FreeBSD Version. 4147883Sscottl * 5147883Sscottl * Copyright (c) 2000, 2001 by Greg Ansley 6147883Sscottl * 7147883Sscottl * Redistribution and use in source and binary forms, with or without 8147883Sscottl * modification, are permitted provided that the following conditions 9147883Sscottl * are met: 10147883Sscottl * 1. Redistributions of source code must retain the above copyright 11147883Sscottl * notice immediately at the beginning of the file, without modification, 12147883Sscottl * this list of conditions, and the following disclaimer. 13147883Sscottl * 2. The name of the author may not be used to endorse or promote products 14147883Sscottl * derived from this software without specific prior written permission. 15147883Sscottl * 16147883Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17147883Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18147883Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19147883Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 20147883Sscottl * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21147883Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22147883Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23147883Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24147883Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25147883Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26147883Sscottl * SUCH DAMAGE. 27156000Smjacob */ 28156000Smjacob/*- 29156000Smjacob * Copyright (c) 2002, 2006 by Matthew Jacob 30156000Smjacob * All rights reserved. 31156000Smjacob * 32156000Smjacob * Redistribution and use in source and binary forms, with or without 33156000Smjacob * modification, are permitted provided that the following conditions are 34156000Smjacob * met: 35156000Smjacob * 1. Redistributions of source code must retain the above copyright 36156000Smjacob * notice, this list of conditions and the following disclaimer. 37156000Smjacob * 2. Redistributions in binary form must reproduce at minimum a disclaimer 38156000Smjacob * substantially similar to the "NO WARRANTY" disclaimer below 39156000Smjacob * ("Disclaimer") and any redistribution must be conditioned upon including 40156000Smjacob * a substantially similar Disclaimer requirement for further binary 41156000Smjacob * redistribution. 42156000Smjacob * 3. Neither the names of the above listed copyright holders nor the names 43156000Smjacob * of any contributors may be used to endorse or promote products derived 44156000Smjacob * from this software without specific prior written permission. 45156000Smjacob * 46156000Smjacob * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 47156000Smjacob * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48156000Smjacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 49156000Smjacob * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 50156000Smjacob * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 51156000Smjacob * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 52156000Smjacob * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 53156000Smjacob * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 54156000Smjacob * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 55156000Smjacob * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT 56156000Smjacob * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 57147883Sscottl * 58156000Smjacob * Support from Chris Ellsworth in order to make SAS adapters work 59156000Smjacob * is gratefully acknowledged. 60159052Smjacob * 61159052Smjacob * Support from LSI-Logic has also gone a great deal toward making this a 62159052Smjacob * workable subsystem and is gratefully acknowledged. 63147883Sscottl */ 64147883Sscottl/*- 65147883Sscottl * Copyright (c) 2004, Avid Technology, Inc. and its contributors. 66147883Sscottl * Copyright (c) 2005, WHEEL Sp. z o.o. 67147883Sscottl * Copyright (c) 2004, 2005 Justin T. Gibbs 68147883Sscottl * All rights reserved. 69147883Sscottl * 70147883Sscottl * Redistribution and use in source and binary forms, with or without 71147883Sscottl * modification, are permitted provided that the following conditions are 72147883Sscottl * met: 73147883Sscottl * 1. Redistributions of source code must retain the above copyright 74147883Sscottl * notice, this list of conditions and the following disclaimer. 75147883Sscottl * 2. Redistributions in binary form must reproduce at minimum a disclaimer 76147883Sscottl * substantially similar to the "NO WARRANTY" disclaimer below 77147883Sscottl * ("Disclaimer") and any redistribution must be conditioned upon including 78147883Sscottl * a substantially similar Disclaimer requirement for further binary 79147883Sscottl * redistribution. 80148679Sgibbs * 3. Neither the names of the above listed copyright holders nor the names 81148679Sgibbs * of any contributors may be used to endorse or promote products derived 82148679Sgibbs * from this software without specific prior written permission. 83147883Sscottl * 84147883Sscottl * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 85147883Sscottl * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 86147883Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 87147883Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 88147883Sscottl * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 89147883Sscottl * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 90147883Sscottl * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 91147883Sscottl * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 92147883Sscottl * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 93147883Sscottl * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT 94147883Sscottl * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 95147883Sscottl */ 96147883Sscottl#include <sys/cdefs.h> 97147883Sscottl__FBSDID("$FreeBSD$"); 98147883Sscottl 99147883Sscottl#include <dev/mpt/mpt.h> 100147883Sscottl#include <dev/mpt/mpt_cam.h> 101147883Sscottl#include <dev/mpt/mpt_raid.h> 102147883Sscottl 103147883Sscottl#include "dev/mpt/mpilib/mpi_ioc.h" /* XXX Fix Event Handling!!! */ 104147883Sscottl#include "dev/mpt/mpilib/mpi_init.h" 105147883Sscottl#include "dev/mpt/mpilib/mpi_targ.h" 106157117Smjacob#include "dev/mpt/mpilib/mpi_fc.h" 107170252Sscottl#include "dev/mpt/mpilib/mpi_sas.h" 108245983Smarius 109147883Sscottl#include <sys/callout.h> 110147883Sscottl#include <sys/kthread.h> 111245983Smarius#include <sys/sysctl.h> 112147883Sscottl 113147883Sscottlstatic void mpt_poll(struct cam_sim *); 114147883Sscottlstatic timeout_t mpt_timeout; 115147883Sscottlstatic void mpt_action(struct cam_sim *, union ccb *); 116157662Smjacobstatic int 117157662Smjacobmpt_get_spi_settings(struct mpt_softc *, struct ccb_trans_settings *); 118157662Smjacobstatic void mpt_setwidth(struct mpt_softc *, int, int); 119157662Smjacobstatic void mpt_setsync(struct mpt_softc *, int, int, int); 120157662Smjacobstatic int mpt_update_spi_config(struct mpt_softc *, int); 121159312Smjacob 122147883Sscottlstatic mpt_reply_handler_t mpt_scsi_reply_handler; 123147883Sscottlstatic mpt_reply_handler_t mpt_scsi_tmf_reply_handler; 124157117Smjacobstatic mpt_reply_handler_t mpt_fc_els_reply_handler; 125157354Smjacobstatic int mpt_scsi_reply_frame_handler(struct mpt_softc *, request_t *, 126157354Smjacob MSG_DEFAULT_REPLY *); 127159471Sjkimstatic int mpt_bus_reset(struct mpt_softc *, target_id_t, lun_id_t, int); 128157117Smjacobstatic int mpt_fc_reset_link(struct mpt_softc *, int); 129147883Sscottl 130147883Sscottlstatic int mpt_spawn_recovery_thread(struct mpt_softc *mpt); 131147883Sscottlstatic void mpt_terminate_recovery_thread(struct mpt_softc *mpt); 132147883Sscottlstatic void mpt_recovery_thread(void *arg); 133157354Smjacobstatic void mpt_recover_commands(struct mpt_softc *mpt); 134157117Smjacob 135157354Smjacobstatic int mpt_scsi_send_tmf(struct mpt_softc *, u_int, u_int, u_int, 136157354Smjacob u_int, u_int, u_int, int); 137157354Smjacob 138157662Smjacobstatic void mpt_fc_post_els(struct mpt_softc *mpt, request_t *, int); 139157117Smjacobstatic void mpt_post_target_command(struct mpt_softc *, request_t *, int); 140157662Smjacobstatic int mpt_add_els_buffers(struct mpt_softc *mpt); 141157662Smjacobstatic int mpt_add_target_commands(struct mpt_softc *mpt); 142157117Smjacobstatic int mpt_enable_lun(struct mpt_softc *, target_id_t, lun_id_t); 143157117Smjacobstatic int mpt_disable_lun(struct mpt_softc *, target_id_t, lun_id_t); 144157117Smjacobstatic void mpt_target_start_io(struct mpt_softc *, union ccb *); 145157117Smjacobstatic cam_status mpt_abort_target_ccb(struct mpt_softc *, union ccb *); 146157354Smjacobstatic int mpt_abort_target_cmd(struct mpt_softc *, request_t *); 147157354Smjacobstatic void mpt_scsi_tgt_status(struct mpt_softc *, union ccb *, request_t *, 148157354Smjacob uint8_t, uint8_t const *); 149157354Smjacobstatic void 150157354Smjacobmpt_scsi_tgt_tsk_mgmt(struct mpt_softc *, request_t *, mpt_task_mgmt_t, 151157354Smjacob tgt_resource_t *, int); 152157354Smjacobstatic void mpt_tgt_dump_tgt_state(struct mpt_softc *, request_t *); 153157354Smjacobstatic void mpt_tgt_dump_req_state(struct mpt_softc *, request_t *); 154157354Smjacobstatic mpt_reply_handler_t mpt_scsi_tgt_reply_handler; 155170252Sscottlstatic mpt_reply_handler_t mpt_sata_pass_reply_handler; 156157117Smjacob 157147883Sscottlstatic uint32_t scsi_io_handler_id = MPT_HANDLER_ID_NONE; 158147883Sscottlstatic uint32_t scsi_tmf_handler_id = MPT_HANDLER_ID_NONE; 159157117Smjacobstatic uint32_t fc_els_handler_id = MPT_HANDLER_ID_NONE; 160170252Sscottlstatic uint32_t sata_pass_handler_id = MPT_HANDLER_ID_NONE; 161147883Sscottl 162147883Sscottlstatic mpt_probe_handler_t mpt_cam_probe; 163147883Sscottlstatic mpt_attach_handler_t mpt_cam_attach; 164157117Smjacobstatic mpt_enable_handler_t mpt_cam_enable; 165162133Smjacobstatic mpt_ready_handler_t mpt_cam_ready; 166147883Sscottlstatic mpt_event_handler_t mpt_cam_event; 167147883Sscottlstatic mpt_reset_handler_t mpt_cam_ioc_reset; 168147883Sscottlstatic mpt_detach_handler_t mpt_cam_detach; 169147883Sscottl 170147883Sscottlstatic struct mpt_personality mpt_cam_personality = 171147883Sscottl{ 172147883Sscottl .name = "mpt_cam", 173147883Sscottl .probe = mpt_cam_probe, 174147883Sscottl .attach = mpt_cam_attach, 175157117Smjacob .enable = mpt_cam_enable, 176162133Smjacob .ready = mpt_cam_ready, 177147883Sscottl .event = mpt_cam_event, 178147883Sscottl .reset = mpt_cam_ioc_reset, 179147883Sscottl .detach = mpt_cam_detach, 180147883Sscottl}; 181147883Sscottl 182147883SscottlDECLARE_MPT_PERSONALITY(mpt_cam, SI_ORDER_SECOND); 183165058SmjacobMODULE_DEPEND(mpt_cam, cam, 1, 1, 1); 184147883Sscottl 185170252Sscottlint mpt_enable_sata_wc = -1; 186170252SscottlTUNABLE_INT("hw.mpt.enable_sata_wc", &mpt_enable_sata_wc); 187170252Sscottl 188224493Smariusstatic int 189147883Sscottlmpt_cam_probe(struct mpt_softc *mpt) 190147883Sscottl{ 191160649Smjacob int role; 192160649Smjacob 193147883Sscottl /* 194160649Smjacob * Only attach to nodes that support the initiator or target role 195160649Smjacob * (or want to) or have RAID physical devices that need CAM pass-thru 196160649Smjacob * support. 197147883Sscottl */ 198160649Smjacob if (mpt->do_cfg_role) { 199160649Smjacob role = mpt->cfg_role; 200160649Smjacob } else { 201160649Smjacob role = mpt->role; 202160649Smjacob } 203160649Smjacob if ((role & (MPT_ROLE_TARGET|MPT_ROLE_INITIATOR)) != 0 || 204160649Smjacob (mpt->ioc_page2 != NULL && mpt->ioc_page2->MaxPhysDisks != 0)) { 205147883Sscottl return (0); 206157117Smjacob } 207147883Sscottl return (ENODEV); 208147883Sscottl} 209147883Sscottl 210224493Smariusstatic int 211147883Sscottlmpt_cam_attach(struct mpt_softc *mpt) 212147883Sscottl{ 213147883Sscottl struct cam_devq *devq; 214147883Sscottl mpt_handler_t handler; 215147883Sscottl int maxq; 216147883Sscottl int error; 217147883Sscottl 218169293Smjacob MPT_LOCK(mpt); 219147883Sscottl TAILQ_INIT(&mpt->request_timeout_list); 220164990Smjacob maxq = (mpt->ioc_facts.GlobalCredits < MPT_MAX_REQUESTS(mpt))? 221164990Smjacob mpt->ioc_facts.GlobalCredits : MPT_MAX_REQUESTS(mpt); 222147883Sscottl 223147883Sscottl handler.reply_handler = mpt_scsi_reply_handler; 224147883Sscottl error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler, 225147883Sscottl &scsi_io_handler_id); 226157117Smjacob if (error != 0) { 227169293Smjacob MPT_UNLOCK(mpt); 228169293Smjacob goto cleanup; 229157117Smjacob } 230157117Smjacob 231147883Sscottl handler.reply_handler = mpt_scsi_tmf_reply_handler; 232147883Sscottl error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler, 233147883Sscottl &scsi_tmf_handler_id); 234157117Smjacob if (error != 0) { 235169293Smjacob MPT_UNLOCK(mpt); 236169293Smjacob goto cleanup; 237157117Smjacob } 238147883Sscottl 239147883Sscottl /* 240157662Smjacob * If we're fibre channel and could support target mode, we register 241157662Smjacob * an ELS reply handler and give it resources. 242157117Smjacob */ 243157117Smjacob if (mpt->is_fc && (mpt->role & MPT_ROLE_TARGET) != 0) { 244157117Smjacob handler.reply_handler = mpt_fc_els_reply_handler; 245157117Smjacob error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler, 246157117Smjacob &fc_els_handler_id); 247157117Smjacob if (error != 0) { 248169293Smjacob MPT_UNLOCK(mpt); 249169293Smjacob goto cleanup; 250157117Smjacob } 251157662Smjacob if (mpt_add_els_buffers(mpt) == FALSE) { 252157662Smjacob error = ENOMEM; 253169293Smjacob MPT_UNLOCK(mpt); 254169293Smjacob goto cleanup; 255157117Smjacob } 256157662Smjacob maxq -= mpt->els_cmds_allocated; 257157117Smjacob } 258157117Smjacob 259157117Smjacob /* 260157662Smjacob * If we support target mode, we register a reply handler for it, 261162133Smjacob * but don't add command resources until we actually enable target 262162133Smjacob * mode. 263157117Smjacob */ 264162059Smjacob if (mpt->is_fc && (mpt->role & MPT_ROLE_TARGET) != 0) { 265157117Smjacob handler.reply_handler = mpt_scsi_tgt_reply_handler; 266157117Smjacob error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler, 267157117Smjacob &mpt->scsi_tgt_handler_id); 268157117Smjacob if (error != 0) { 269169293Smjacob MPT_UNLOCK(mpt); 270169293Smjacob goto cleanup; 271157117Smjacob } 272157117Smjacob } 273157117Smjacob 274170252Sscottl if (mpt->is_sas) { 275170252Sscottl handler.reply_handler = mpt_sata_pass_reply_handler; 276170252Sscottl error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler, 277170252Sscottl &sata_pass_handler_id); 278170252Sscottl if (error != 0) { 279170252Sscottl MPT_UNLOCK(mpt); 280170252Sscottl goto cleanup; 281170252Sscottl } 282170252Sscottl } 283170252Sscottl 284157117Smjacob /* 285147883Sscottl * We keep one request reserved for timeout TMF requests. 286147883Sscottl */ 287157354Smjacob mpt->tmf_req = mpt_get_request(mpt, FALSE); 288147883Sscottl if (mpt->tmf_req == NULL) { 289147883Sscottl mpt_prt(mpt, "Unable to allocate dedicated TMF request!\n"); 290147883Sscottl error = ENOMEM; 291169293Smjacob MPT_UNLOCK(mpt); 292169293Smjacob goto cleanup; 293147883Sscottl } 294147883Sscottl 295147883Sscottl /* 296147883Sscottl * Mark the request as free even though not on the free list. 297147883Sscottl * There is only one TMF request allowed to be outstanding at 298147883Sscottl * a time and the TMF routines perform their own allocation 299147883Sscottl * tracking using the standard state flags. 300147883Sscottl */ 301147883Sscottl mpt->tmf_req->state = REQ_STATE_FREE; 302147883Sscottl maxq--; 303147883Sscottl 304169293Smjacob /* 305169293Smjacob * The rest of this is CAM foo, for which we need to drop our lock 306169293Smjacob */ 307169293Smjacob MPT_UNLOCK(mpt); 308169293Smjacob 309147883Sscottl if (mpt_spawn_recovery_thread(mpt) != 0) { 310147883Sscottl mpt_prt(mpt, "Unable to spawn recovery thread!\n"); 311147883Sscottl error = ENOMEM; 312169293Smjacob goto cleanup; 313147883Sscottl } 314147883Sscottl 315147883Sscottl /* 316147883Sscottl * Create the device queue for our SIM(s). 317147883Sscottl */ 318170924Sscottl devq = cam_simq_alloc(maxq); 319147883Sscottl if (devq == NULL) { 320147883Sscottl mpt_prt(mpt, "Unable to allocate CAM SIMQ!\n"); 321147883Sscottl error = ENOMEM; 322147883Sscottl goto cleanup; 323147883Sscottl } 324147883Sscottl 325147883Sscottl /* 326147883Sscottl * Construct our SIM entry. 327147883Sscottl */ 328169293Smjacob mpt->sim = 329170924Sscottl mpt_sim_alloc(mpt_action, mpt_poll, "mpt", mpt, 1, maxq, devq); 330147883Sscottl if (mpt->sim == NULL) { 331147883Sscottl mpt_prt(mpt, "Unable to allocate CAM SIM!\n"); 332147883Sscottl cam_simq_free(devq); 333147883Sscottl error = ENOMEM; 334147883Sscottl goto cleanup; 335147883Sscottl } 336147883Sscottl 337147883Sscottl /* 338158935Smjacob * Register exactly this bus. 339147883Sscottl */ 340169293Smjacob MPT_LOCK(mpt); 341264950Smarius if (xpt_bus_register(mpt->sim, mpt->dev, 0) != CAM_SUCCESS) { 342147883Sscottl mpt_prt(mpt, "Bus registration Failed!\n"); 343147883Sscottl error = ENOMEM; 344169293Smjacob MPT_UNLOCK(mpt); 345147883Sscottl goto cleanup; 346147883Sscottl } 347147883Sscottl 348147883Sscottl if (xpt_create_path(&mpt->path, NULL, cam_sim_path(mpt->sim), 349147883Sscottl CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 350147883Sscottl mpt_prt(mpt, "Unable to allocate Path!\n"); 351147883Sscottl error = ENOMEM; 352169293Smjacob MPT_UNLOCK(mpt); 353147883Sscottl goto cleanup; 354147883Sscottl } 355169293Smjacob MPT_UNLOCK(mpt); 356147883Sscottl 357147883Sscottl /* 358147883Sscottl * Only register a second bus for RAID physical 359147883Sscottl * devices if the controller supports RAID. 360147883Sscottl */ 361157117Smjacob if (mpt->ioc_page2 == NULL || mpt->ioc_page2->MaxPhysDisks == 0) { 362147883Sscottl return (0); 363157117Smjacob } 364147883Sscottl 365147883Sscottl /* 366147883Sscottl * Create a "bus" to export all hidden disks to CAM. 367147883Sscottl */ 368169293Smjacob mpt->phydisk_sim = 369170924Sscottl mpt_sim_alloc(mpt_action, mpt_poll, "mpt", mpt, 1, maxq, devq); 370147883Sscottl if (mpt->phydisk_sim == NULL) { 371147883Sscottl mpt_prt(mpt, "Unable to allocate Physical Disk CAM SIM!\n"); 372147883Sscottl error = ENOMEM; 373147883Sscottl goto cleanup; 374147883Sscottl } 375147883Sscottl 376147883Sscottl /* 377158935Smjacob * Register this bus. 378147883Sscottl */ 379169293Smjacob MPT_LOCK(mpt); 380264950Smarius if (xpt_bus_register(mpt->phydisk_sim, mpt->dev, 1) != 381178725Sjkim CAM_SUCCESS) { 382147883Sscottl mpt_prt(mpt, "Physical Disk Bus registration Failed!\n"); 383147883Sscottl error = ENOMEM; 384169293Smjacob MPT_UNLOCK(mpt); 385147883Sscottl goto cleanup; 386147883Sscottl } 387147883Sscottl 388147883Sscottl if (xpt_create_path(&mpt->phydisk_path, NULL, 389147883Sscottl cam_sim_path(mpt->phydisk_sim), 390147883Sscottl CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 391147883Sscottl mpt_prt(mpt, "Unable to allocate Physical Disk Path!\n"); 392147883Sscottl error = ENOMEM; 393169293Smjacob MPT_UNLOCK(mpt); 394147883Sscottl goto cleanup; 395147883Sscottl } 396169293Smjacob MPT_UNLOCK(mpt); 397160649Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, "attached cam\n"); 398147883Sscottl return (0); 399157662Smjacob 400147883Sscottlcleanup: 401147883Sscottl mpt_cam_detach(mpt); 402147883Sscottl return (error); 403147883Sscottl} 404147883Sscottl 405157117Smjacob/* 406157117Smjacob * Read FC configuration information 407157117Smjacob */ 408157117Smjacobstatic int 409157117Smjacobmpt_read_config_info_fc(struct mpt_softc *mpt) 410157117Smjacob{ 411245983Smarius struct sysctl_ctx_list *ctx; 412245983Smarius struct sysctl_oid *tree; 413157117Smjacob char *topology = NULL; 414159919Smjacob int rv; 415157117Smjacob 416157117Smjacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_FC_PORT, 0, 417157117Smjacob 0, &mpt->mpt_fcport_page0.Header, FALSE, 5000); 418157117Smjacob if (rv) { 419157117Smjacob return (-1); 420157117Smjacob } 421157117Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, "FC Port Page 0 Header: %x %x %x %x\n", 422157117Smjacob mpt->mpt_fcport_page0.Header.PageVersion, 423157117Smjacob mpt->mpt_fcport_page0.Header.PageLength, 424157117Smjacob mpt->mpt_fcport_page0.Header.PageNumber, 425157117Smjacob mpt->mpt_fcport_page0.Header.PageType); 426157117Smjacob 427157117Smjacob 428157117Smjacob rv = mpt_read_cur_cfg_page(mpt, 0, &mpt->mpt_fcport_page0.Header, 429157117Smjacob sizeof(mpt->mpt_fcport_page0), FALSE, 5000); 430157117Smjacob if (rv) { 431157117Smjacob mpt_prt(mpt, "failed to read FC Port Page 0\n"); 432157117Smjacob return (-1); 433157117Smjacob } 434186878Smarius mpt2host_config_page_fc_port_0(&mpt->mpt_fcport_page0); 435157117Smjacob 436159919Smjacob mpt->mpt_fcport_speed = mpt->mpt_fcport_page0.CurrentSpeed; 437157117Smjacob 438157117Smjacob switch (mpt->mpt_fcport_page0.Flags & 439157117Smjacob MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK) { 440157117Smjacob case MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT: 441159919Smjacob mpt->mpt_fcport_speed = 0; 442157117Smjacob topology = "<NO LOOP>"; 443157117Smjacob break; 444157117Smjacob case MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT: 445157117Smjacob topology = "N-Port"; 446157117Smjacob break; 447157117Smjacob case MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP: 448157117Smjacob topology = "NL-Port"; 449157117Smjacob break; 450157117Smjacob case MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT: 451157117Smjacob topology = "F-Port"; 452157117Smjacob break; 453157117Smjacob case MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP: 454157117Smjacob topology = "FL-Port"; 455157117Smjacob break; 456157117Smjacob default: 457159919Smjacob mpt->mpt_fcport_speed = 0; 458157117Smjacob topology = "?"; 459157117Smjacob break; 460157117Smjacob } 461157117Smjacob 462157117Smjacob mpt_lprt(mpt, MPT_PRT_INFO, 463157117Smjacob "FC Port Page 0: Topology <%s> WWNN 0x%08x%08x WWPN 0x%08x%08x " 464157117Smjacob "Speed %u-Gbit\n", topology, 465157117Smjacob mpt->mpt_fcport_page0.WWNN.High, 466157117Smjacob mpt->mpt_fcport_page0.WWNN.Low, 467157117Smjacob mpt->mpt_fcport_page0.WWPN.High, 468157117Smjacob mpt->mpt_fcport_page0.WWPN.Low, 469159919Smjacob mpt->mpt_fcport_speed); 470169293Smjacob MPT_UNLOCK(mpt); 471245983Smarius ctx = device_get_sysctl_ctx(mpt->dev); 472245983Smarius tree = device_get_sysctl_tree(mpt->dev); 473157117Smjacob 474245983Smarius snprintf(mpt->scinfo.fc.wwnn, sizeof (mpt->scinfo.fc.wwnn), 475245983Smarius "0x%08x%08x", mpt->mpt_fcport_page0.WWNN.High, 476245983Smarius mpt->mpt_fcport_page0.WWNN.Low); 477160397Smjacob 478245983Smarius snprintf(mpt->scinfo.fc.wwpn, sizeof (mpt->scinfo.fc.wwpn), 479245983Smarius "0x%08x%08x", mpt->mpt_fcport_page0.WWPN.High, 480245983Smarius mpt->mpt_fcport_page0.WWPN.Low); 481160397Smjacob 482245983Smarius SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 483245983Smarius "wwnn", CTLFLAG_RD, mpt->scinfo.fc.wwnn, 0, 484245983Smarius "World Wide Node Name"); 485160397Smjacob 486245983Smarius SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 487245983Smarius "wwpn", CTLFLAG_RD, mpt->scinfo.fc.wwpn, 0, 488245983Smarius "World Wide Port Name"); 489160397Smjacob 490169293Smjacob MPT_LOCK(mpt); 491157117Smjacob return (0); 492157117Smjacob} 493157117Smjacob 494157117Smjacob/* 495157117Smjacob * Set FC configuration information. 496157117Smjacob */ 497157117Smjacobstatic int 498157117Smjacobmpt_set_initial_config_fc(struct mpt_softc *mpt) 499157117Smjacob{ 500157117Smjacob CONFIG_PAGE_FC_PORT_1 fc; 501157117Smjacob U32 fl; 502157117Smjacob int r, doit = 0; 503160290Smjacob int role; 504157117Smjacob 505157117Smjacob r = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, 506157117Smjacob &fc.Header, FALSE, 5000); 507157117Smjacob if (r) { 508160290Smjacob mpt_prt(mpt, "failed to read FC page 1 header\n"); 509157117Smjacob return (mpt_fc_reset_link(mpt, 1)); 510157117Smjacob } 511157117Smjacob 512160290Smjacob r = mpt_read_cfg_page(mpt, MPI_CONFIG_ACTION_PAGE_READ_NVRAM, 0, 513157117Smjacob &fc.Header, sizeof (fc), FALSE, 5000); 514157117Smjacob if (r) { 515160290Smjacob mpt_prt(mpt, "failed to read FC page 1\n"); 516157117Smjacob return (mpt_fc_reset_link(mpt, 1)); 517157117Smjacob } 518186878Smarius mpt2host_config_page_fc_port_1(&fc); 519157117Smjacob 520160290Smjacob /* 521160290Smjacob * Check our flags to make sure we support the role we want. 522160290Smjacob */ 523160290Smjacob doit = 0; 524160290Smjacob role = 0; 525186878Smarius fl = fc.Flags; 526160290Smjacob 527160290Smjacob if (fl & MPI_FCPORTPAGE1_FLAGS_PROT_FCP_INIT) { 528160290Smjacob role |= MPT_ROLE_INITIATOR; 529157117Smjacob } 530160290Smjacob if (fl & MPI_FCPORTPAGE1_FLAGS_PROT_FCP_TARG) { 531160290Smjacob role |= MPT_ROLE_TARGET; 532160290Smjacob } 533160290Smjacob 534160290Smjacob fl &= ~MPI_FCPORTPAGE1_FLAGS_PROT_MASK; 535160290Smjacob 536160290Smjacob if (mpt->do_cfg_role == 0) { 537160290Smjacob role = mpt->cfg_role; 538160290Smjacob } else { 539160290Smjacob mpt->do_cfg_role = 0; 540160290Smjacob } 541160290Smjacob 542160290Smjacob if (role != mpt->cfg_role) { 543160290Smjacob if (mpt->cfg_role & MPT_ROLE_INITIATOR) { 544160290Smjacob if ((role & MPT_ROLE_INITIATOR) == 0) { 545160290Smjacob mpt_prt(mpt, "adding initiator role\n"); 546160290Smjacob fl |= MPI_FCPORTPAGE1_FLAGS_PROT_FCP_INIT; 547160290Smjacob doit++; 548160290Smjacob } else { 549160290Smjacob mpt_prt(mpt, "keeping initiator role\n"); 550160290Smjacob } 551160290Smjacob } else if (role & MPT_ROLE_INITIATOR) { 552160290Smjacob mpt_prt(mpt, "removing initiator role\n"); 553160290Smjacob doit++; 554160290Smjacob } 555160290Smjacob if (mpt->cfg_role & MPT_ROLE_TARGET) { 556160290Smjacob if ((role & MPT_ROLE_TARGET) == 0) { 557160290Smjacob mpt_prt(mpt, "adding target role\n"); 558160290Smjacob fl |= MPI_FCPORTPAGE1_FLAGS_PROT_FCP_TARG; 559160290Smjacob doit++; 560160290Smjacob } else { 561160290Smjacob mpt_prt(mpt, "keeping target role\n"); 562160290Smjacob } 563160290Smjacob } else if (role & MPT_ROLE_TARGET) { 564160290Smjacob mpt_prt(mpt, "removing target role\n"); 565160290Smjacob doit++; 566160290Smjacob } 567160290Smjacob mpt->role = mpt->cfg_role; 568160290Smjacob } 569160290Smjacob 570160290Smjacob if (fl & MPI_FCPORTPAGE1_FLAGS_PROT_FCP_TARG) { 571160290Smjacob if ((fl & MPI_FCPORTPAGE1_FLAGS_TARGET_MODE_OXID) == 0) { 572160290Smjacob mpt_prt(mpt, "adding OXID option\n"); 573160290Smjacob fl |= MPI_FCPORTPAGE1_FLAGS_TARGET_MODE_OXID; 574160290Smjacob doit++; 575160290Smjacob } 576160290Smjacob } 577160290Smjacob 578157117Smjacob if (doit) { 579186878Smarius fc.Flags = fl; 580186878Smarius host2mpt_config_page_fc_port_1(&fc); 581157117Smjacob r = mpt_write_cfg_page(mpt, 582160290Smjacob MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM, 0, &fc.Header, 583157117Smjacob sizeof(fc), FALSE, 5000); 584157117Smjacob if (r != 0) { 585160290Smjacob mpt_prt(mpt, "failed to update NVRAM with changes\n"); 586160290Smjacob return (0); 587157117Smjacob } 588160290Smjacob mpt_prt(mpt, "NOTE: NVRAM changes will not take " 589160290Smjacob "effect until next reboot or IOC reset\n"); 590157117Smjacob } 591157662Smjacob return (0); 592157117Smjacob} 593157117Smjacob 594170252Sscottlstatic int 595170252Sscottlmptsas_sas_io_unit_pg0(struct mpt_softc *mpt, struct mptsas_portinfo *portinfo) 596170252Sscottl{ 597170252Sscottl ConfigExtendedPageHeader_t hdr; 598170252Sscottl struct mptsas_phyinfo *phyinfo; 599170252Sscottl SasIOUnitPage0_t *buffer; 600170252Sscottl int error, len, i; 601170252Sscottl 602170252Sscottl error = mpt_read_extcfg_header(mpt, MPI_SASIOUNITPAGE0_PAGEVERSION, 603170252Sscottl 0, 0, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 604170252Sscottl &hdr, 0, 10000); 605170252Sscottl if (error) 606170252Sscottl goto out; 607170252Sscottl if (hdr.ExtPageLength == 0) { 608170252Sscottl error = ENXIO; 609170252Sscottl goto out; 610170252Sscottl } 611170252Sscottl 612170252Sscottl len = hdr.ExtPageLength * 4; 613170252Sscottl buffer = malloc(len, M_DEVBUF, M_NOWAIT|M_ZERO); 614170252Sscottl if (buffer == NULL) { 615170252Sscottl error = ENOMEM; 616170252Sscottl goto out; 617170252Sscottl } 618170252Sscottl 619170252Sscottl error = mpt_read_extcfg_page(mpt, MPI_CONFIG_ACTION_PAGE_READ_CURRENT, 620170252Sscottl 0, &hdr, buffer, len, 0, 10000); 621170252Sscottl if (error) { 622170252Sscottl free(buffer, M_DEVBUF); 623170252Sscottl goto out; 624170252Sscottl } 625170252Sscottl 626170252Sscottl portinfo->num_phys = buffer->NumPhys; 627170252Sscottl portinfo->phy_info = malloc(sizeof(*portinfo->phy_info) * 628170252Sscottl portinfo->num_phys, M_DEVBUF, M_NOWAIT|M_ZERO); 629170252Sscottl if (portinfo->phy_info == NULL) { 630170252Sscottl free(buffer, M_DEVBUF); 631170252Sscottl error = ENOMEM; 632170252Sscottl goto out; 633170252Sscottl } 634170252Sscottl 635170252Sscottl for (i = 0; i < portinfo->num_phys; i++) { 636170252Sscottl phyinfo = &portinfo->phy_info[i]; 637170252Sscottl phyinfo->phy_num = i; 638170252Sscottl phyinfo->port_id = buffer->PhyData[i].Port; 639170252Sscottl phyinfo->negotiated_link_rate = 640170252Sscottl buffer->PhyData[i].NegotiatedLinkRate; 641170252Sscottl phyinfo->handle = 642170252Sscottl le16toh(buffer->PhyData[i].ControllerDevHandle); 643170252Sscottl } 644170252Sscottl 645170252Sscottl free(buffer, M_DEVBUF); 646170252Sscottlout: 647170252Sscottl return (error); 648170252Sscottl} 649170252Sscottl 650170252Sscottlstatic int 651170252Sscottlmptsas_sas_phy_pg0(struct mpt_softc *mpt, struct mptsas_phyinfo *phy_info, 652170252Sscottl uint32_t form, uint32_t form_specific) 653170252Sscottl{ 654170252Sscottl ConfigExtendedPageHeader_t hdr; 655170252Sscottl SasPhyPage0_t *buffer; 656170252Sscottl int error; 657170252Sscottl 658170252Sscottl error = mpt_read_extcfg_header(mpt, MPI_SASPHY0_PAGEVERSION, 0, 0, 659170252Sscottl MPI_CONFIG_EXTPAGETYPE_SAS_PHY, &hdr, 660170252Sscottl 0, 10000); 661170252Sscottl if (error) 662170252Sscottl goto out; 663170252Sscottl if (hdr.ExtPageLength == 0) { 664170252Sscottl error = ENXIO; 665170252Sscottl goto out; 666170252Sscottl } 667170252Sscottl 668170252Sscottl buffer = malloc(sizeof(SasPhyPage0_t), M_DEVBUF, M_NOWAIT|M_ZERO); 669170252Sscottl if (buffer == NULL) { 670170252Sscottl error = ENOMEM; 671170252Sscottl goto out; 672170252Sscottl } 673170252Sscottl 674170252Sscottl error = mpt_read_extcfg_page(mpt, MPI_CONFIG_ACTION_PAGE_READ_CURRENT, 675170252Sscottl form + form_specific, &hdr, buffer, 676170252Sscottl sizeof(SasPhyPage0_t), 0, 10000); 677170252Sscottl if (error) { 678170252Sscottl free(buffer, M_DEVBUF); 679170252Sscottl goto out; 680170252Sscottl } 681170252Sscottl 682170252Sscottl phy_info->hw_link_rate = buffer->HwLinkRate; 683170252Sscottl phy_info->programmed_link_rate = buffer->ProgrammedLinkRate; 684170252Sscottl phy_info->identify.dev_handle = le16toh(buffer->OwnerDevHandle); 685170252Sscottl phy_info->attached.dev_handle = le16toh(buffer->AttachedDevHandle); 686170252Sscottl 687170252Sscottl free(buffer, M_DEVBUF); 688170252Sscottlout: 689170252Sscottl return (error); 690170252Sscottl} 691170252Sscottl 692170252Sscottlstatic int 693170252Sscottlmptsas_sas_device_pg0(struct mpt_softc *mpt, struct mptsas_devinfo *device_info, 694170252Sscottl uint32_t form, uint32_t form_specific) 695170252Sscottl{ 696170252Sscottl ConfigExtendedPageHeader_t hdr; 697170252Sscottl SasDevicePage0_t *buffer; 698170252Sscottl uint64_t sas_address; 699170252Sscottl int error = 0; 700170252Sscottl 701170252Sscottl bzero(device_info, sizeof(*device_info)); 702170252Sscottl error = mpt_read_extcfg_header(mpt, MPI_SASDEVICE0_PAGEVERSION, 0, 0, 703170252Sscottl MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 704170252Sscottl &hdr, 0, 10000); 705170252Sscottl if (error) 706170252Sscottl goto out; 707170252Sscottl if (hdr.ExtPageLength == 0) { 708170252Sscottl error = ENXIO; 709170252Sscottl goto out; 710170252Sscottl } 711170252Sscottl 712170252Sscottl buffer = malloc(sizeof(SasDevicePage0_t), M_DEVBUF, M_NOWAIT|M_ZERO); 713170252Sscottl if (buffer == NULL) { 714170252Sscottl error = ENOMEM; 715170252Sscottl goto out; 716170252Sscottl } 717170252Sscottl 718170252Sscottl error = mpt_read_extcfg_page(mpt, MPI_CONFIG_ACTION_PAGE_READ_CURRENT, 719170252Sscottl form + form_specific, &hdr, buffer, 720170252Sscottl sizeof(SasDevicePage0_t), 0, 10000); 721170252Sscottl if (error) { 722170252Sscottl free(buffer, M_DEVBUF); 723170252Sscottl goto out; 724170252Sscottl } 725170252Sscottl 726170252Sscottl device_info->dev_handle = le16toh(buffer->DevHandle); 727170252Sscottl device_info->parent_dev_handle = le16toh(buffer->ParentDevHandle); 728170252Sscottl device_info->enclosure_handle = le16toh(buffer->EnclosureHandle); 729170252Sscottl device_info->slot = le16toh(buffer->Slot); 730170252Sscottl device_info->phy_num = buffer->PhyNum; 731170252Sscottl device_info->physical_port = buffer->PhysicalPort; 732170252Sscottl device_info->target_id = buffer->TargetID; 733170252Sscottl device_info->bus = buffer->Bus; 734170252Sscottl bcopy(&buffer->SASAddress, &sas_address, sizeof(uint64_t)); 735170252Sscottl device_info->sas_address = le64toh(sas_address); 736170252Sscottl device_info->device_info = le32toh(buffer->DeviceInfo); 737170252Sscottl 738170252Sscottl free(buffer, M_DEVBUF); 739170252Sscottlout: 740170252Sscottl return (error); 741170252Sscottl} 742170252Sscottl 743157117Smjacob/* 744157117Smjacob * Read SAS configuration information. Nothing to do yet. 745157117Smjacob */ 746157117Smjacobstatic int 747157117Smjacobmpt_read_config_info_sas(struct mpt_softc *mpt) 748157117Smjacob{ 749170252Sscottl struct mptsas_portinfo *portinfo; 750170252Sscottl struct mptsas_phyinfo *phyinfo; 751170252Sscottl int error, i; 752170252Sscottl 753170252Sscottl portinfo = malloc(sizeof(*portinfo), M_DEVBUF, M_NOWAIT|M_ZERO); 754170252Sscottl if (portinfo == NULL) 755170252Sscottl return (ENOMEM); 756170252Sscottl 757170252Sscottl error = mptsas_sas_io_unit_pg0(mpt, portinfo); 758170252Sscottl if (error) { 759170252Sscottl free(portinfo, M_DEVBUF); 760170252Sscottl return (0); 761170252Sscottl } 762170252Sscottl 763170252Sscottl for (i = 0; i < portinfo->num_phys; i++) { 764170252Sscottl phyinfo = &portinfo->phy_info[i]; 765170252Sscottl error = mptsas_sas_phy_pg0(mpt, phyinfo, 766170252Sscottl (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER << 767170252Sscottl MPI_SAS_PHY_PGAD_FORM_SHIFT), i); 768170252Sscottl if (error) 769170252Sscottl break; 770170252Sscottl error = mptsas_sas_device_pg0(mpt, &phyinfo->identify, 771170252Sscottl (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << 772170252Sscottl MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 773170252Sscottl phyinfo->handle); 774170252Sscottl if (error) 775170252Sscottl break; 776170252Sscottl phyinfo->identify.phy_num = phyinfo->phy_num = i; 777170252Sscottl if (phyinfo->attached.dev_handle) 778170252Sscottl error = mptsas_sas_device_pg0(mpt, 779170252Sscottl &phyinfo->attached, 780170252Sscottl (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << 781170252Sscottl MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 782170252Sscottl phyinfo->attached.dev_handle); 783170252Sscottl if (error) 784170252Sscottl break; 785170252Sscottl } 786170252Sscottl mpt->sas_portinfo = portinfo; 787157117Smjacob return (0); 788157117Smjacob} 789157117Smjacob 790170252Sscottlstatic void 791170252Sscottlmptsas_set_sata_wc(struct mpt_softc *mpt, struct mptsas_devinfo *devinfo, 792170252Sscottl int enabled) 793170252Sscottl{ 794170252Sscottl SataPassthroughRequest_t *pass; 795170252Sscottl request_t *req; 796170252Sscottl int error, status; 797170252Sscottl 798170252Sscottl req = mpt_get_request(mpt, 0); 799170252Sscottl if (req == NULL) 800170252Sscottl return; 801170252Sscottl 802170252Sscottl pass = req->req_vbuf; 803170252Sscottl bzero(pass, sizeof(SataPassthroughRequest_t)); 804170252Sscottl pass->Function = MPI_FUNCTION_SATA_PASSTHROUGH; 805170252Sscottl pass->TargetID = devinfo->target_id; 806170252Sscottl pass->Bus = devinfo->bus; 807170252Sscottl pass->PassthroughFlags = 0; 808170252Sscottl pass->ConnectionRate = MPI_SATA_PT_REQ_CONNECT_RATE_NEGOTIATED; 809170252Sscottl pass->DataLength = 0; 810170252Sscottl pass->MsgContext = htole32(req->index | sata_pass_handler_id); 811170252Sscottl pass->CommandFIS[0] = 0x27; 812170252Sscottl pass->CommandFIS[1] = 0x80; 813170252Sscottl pass->CommandFIS[2] = 0xef; 814170252Sscottl pass->CommandFIS[3] = (enabled) ? 0x02 : 0x82; 815170252Sscottl pass->CommandFIS[7] = 0x40; 816170252Sscottl pass->CommandFIS[15] = 0x08; 817170252Sscottl 818170252Sscottl mpt_check_doorbell(mpt); 819170252Sscottl mpt_send_cmd(mpt, req); 820170252Sscottl error = mpt_wait_req(mpt, req, REQ_STATE_DONE, REQ_STATE_DONE, 0, 821170252Sscottl 10 * 1000); 822170252Sscottl if (error) { 823170252Sscottl mpt_free_request(mpt, req); 824170252Sscottl printf("error %d sending passthrough\n", error); 825170252Sscottl return; 826170252Sscottl } 827170252Sscottl 828170252Sscottl status = le16toh(req->IOCStatus); 829170252Sscottl if (status != MPI_IOCSTATUS_SUCCESS) { 830170252Sscottl mpt_free_request(mpt, req); 831170252Sscottl printf("IOCSTATUS %d\n", status); 832170252Sscottl return; 833170252Sscottl } 834170252Sscottl 835170252Sscottl mpt_free_request(mpt, req); 836170252Sscottl} 837170252Sscottl 838157117Smjacob/* 839157117Smjacob * Set SAS configuration information. Nothing to do yet. 840157117Smjacob */ 841157117Smjacobstatic int 842157117Smjacobmpt_set_initial_config_sas(struct mpt_softc *mpt) 843157117Smjacob{ 844170252Sscottl struct mptsas_phyinfo *phyinfo; 845170252Sscottl int i; 846170252Sscottl 847170252Sscottl if ((mpt_enable_sata_wc != -1) && (mpt->sas_portinfo != NULL)) { 848170252Sscottl for (i = 0; i < mpt->sas_portinfo->num_phys; i++) { 849170252Sscottl phyinfo = &mpt->sas_portinfo->phy_info[i]; 850170252Sscottl if (phyinfo->attached.dev_handle == 0) 851170252Sscottl continue; 852170252Sscottl if ((phyinfo->attached.device_info & 853170252Sscottl MPI_SAS_DEVICE_INFO_SATA_DEVICE) == 0) 854170252Sscottl continue; 855170252Sscottl if (bootverbose) 856170252Sscottl device_printf(mpt->dev, 857170252Sscottl "%sabling SATA WC on phy %d\n", 858170252Sscottl (mpt_enable_sata_wc) ? "En" : "Dis", i); 859170252Sscottl mptsas_set_sata_wc(mpt, &phyinfo->attached, 860170252Sscottl mpt_enable_sata_wc); 861170252Sscottl } 862170252Sscottl } 863170252Sscottl 864157117Smjacob return (0); 865157117Smjacob} 866157117Smjacob 867170252Sscottlstatic int 868170252Sscottlmpt_sata_pass_reply_handler(struct mpt_softc *mpt, request_t *req, 869170252Sscottl uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) 870170252Sscottl{ 871224493Smarius 872170252Sscottl if (req != NULL) { 873170252Sscottl if (reply_frame != NULL) { 874170252Sscottl req->IOCStatus = le16toh(reply_frame->IOCStatus); 875170252Sscottl } 876170252Sscottl req->state &= ~REQ_STATE_QUEUED; 877170252Sscottl req->state |= REQ_STATE_DONE; 878170252Sscottl TAILQ_REMOVE(&mpt->request_pending_list, req, links); 879170252Sscottl if ((req->state & REQ_STATE_NEED_WAKEUP) != 0) { 880170252Sscottl wakeup(req); 881170252Sscottl } else if ((req->state & REQ_STATE_TIMEDOUT) != 0) { 882170252Sscottl /* 883170252Sscottl * Whew- we can free this request (late completion) 884170252Sscottl */ 885170252Sscottl mpt_free_request(mpt, req); 886170252Sscottl } 887170252Sscottl } 888170252Sscottl 889170252Sscottl return (TRUE); 890170252Sscottl} 891170252Sscottl 892157117Smjacob/* 893157117Smjacob * Read SCSI configuration information 894157117Smjacob */ 895157117Smjacobstatic int 896157117Smjacobmpt_read_config_info_spi(struct mpt_softc *mpt) 897157117Smjacob{ 898157117Smjacob int rv, i; 899157117Smjacob 900157662Smjacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 0, 0, 901157662Smjacob &mpt->mpt_port_page0.Header, FALSE, 5000); 902157662Smjacob if (rv) { 903157117Smjacob return (-1); 904157662Smjacob } 905157662Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, "SPI Port Page 0 Header: %x %x %x %x\n", 906157662Smjacob mpt->mpt_port_page0.Header.PageVersion, 907157662Smjacob mpt->mpt_port_page0.Header.PageLength, 908157662Smjacob mpt->mpt_port_page0.Header.PageNumber, 909157662Smjacob mpt->mpt_port_page0.Header.PageType); 910157117Smjacob 911157662Smjacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1, 0, 912157662Smjacob &mpt->mpt_port_page1.Header, FALSE, 5000); 913157662Smjacob if (rv) { 914157117Smjacob return (-1); 915157662Smjacob } 916157117Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, "SPI Port Page 1 Header: %x %x %x %x\n", 917157662Smjacob mpt->mpt_port_page1.Header.PageVersion, 918157662Smjacob mpt->mpt_port_page1.Header.PageLength, 919157662Smjacob mpt->mpt_port_page1.Header.PageNumber, 920157662Smjacob mpt->mpt_port_page1.Header.PageType); 921157117Smjacob 922157662Smjacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2, 0, 923157662Smjacob &mpt->mpt_port_page2.Header, FALSE, 5000); 924157662Smjacob if (rv) { 925157117Smjacob return (-1); 926157662Smjacob } 927157662Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, "SPI Port Page 2 Header: %x %x %x %x\n", 928157662Smjacob mpt->mpt_port_page2.Header.PageVersion, 929157662Smjacob mpt->mpt_port_page2.Header.PageLength, 930157662Smjacob mpt->mpt_port_page2.Header.PageNumber, 931157662Smjacob mpt->mpt_port_page2.Header.PageType); 932157117Smjacob 933157117Smjacob for (i = 0; i < 16; i++) { 934157117Smjacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 935157662Smjacob 0, i, &mpt->mpt_dev_page0[i].Header, FALSE, 5000); 936157662Smjacob if (rv) { 937157117Smjacob return (-1); 938157662Smjacob } 939157117Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 940157662Smjacob "SPI Target %d Device Page 0 Header: %x %x %x %x\n", i, 941157662Smjacob mpt->mpt_dev_page0[i].Header.PageVersion, 942157662Smjacob mpt->mpt_dev_page0[i].Header.PageLength, 943157662Smjacob mpt->mpt_dev_page0[i].Header.PageNumber, 944157662Smjacob mpt->mpt_dev_page0[i].Header.PageType); 945157117Smjacob 946157117Smjacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 947157662Smjacob 1, i, &mpt->mpt_dev_page1[i].Header, FALSE, 5000); 948157662Smjacob if (rv) { 949157117Smjacob return (-1); 950157662Smjacob } 951157117Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 952157662Smjacob "SPI Target %d Device Page 1 Header: %x %x %x %x\n", i, 953157662Smjacob mpt->mpt_dev_page1[i].Header.PageVersion, 954157662Smjacob mpt->mpt_dev_page1[i].Header.PageLength, 955157662Smjacob mpt->mpt_dev_page1[i].Header.PageNumber, 956157662Smjacob mpt->mpt_dev_page1[i].Header.PageType); 957157117Smjacob } 958157117Smjacob 959157117Smjacob /* 960157117Smjacob * At this point, we don't *have* to fail. As long as we have 961157117Smjacob * valid config header information, we can (barely) lurch 962157117Smjacob * along. 963157117Smjacob */ 964157117Smjacob 965157662Smjacob rv = mpt_read_cur_cfg_page(mpt, 0, &mpt->mpt_port_page0.Header, 966157662Smjacob sizeof(mpt->mpt_port_page0), FALSE, 5000); 967157117Smjacob if (rv) { 968157117Smjacob mpt_prt(mpt, "failed to read SPI Port Page 0\n"); 969157117Smjacob } else { 970186878Smarius mpt2host_config_page_scsi_port_0(&mpt->mpt_port_page0); 971164846Smjacob mpt_lprt(mpt, MPT_PRT_NEGOTIATION, 972157117Smjacob "SPI Port Page 0: Capabilities %x PhysicalInterface %x\n", 973157117Smjacob mpt->mpt_port_page0.Capabilities, 974157117Smjacob mpt->mpt_port_page0.PhysicalInterface); 975157117Smjacob } 976157117Smjacob 977157662Smjacob rv = mpt_read_cur_cfg_page(mpt, 0, &mpt->mpt_port_page1.Header, 978157662Smjacob sizeof(mpt->mpt_port_page1), FALSE, 5000); 979157117Smjacob if (rv) { 980157117Smjacob mpt_prt(mpt, "failed to read SPI Port Page 1\n"); 981157117Smjacob } else { 982186878Smarius mpt2host_config_page_scsi_port_1(&mpt->mpt_port_page1); 983157117Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 984157117Smjacob "SPI Port Page 1: Configuration %x OnBusTimerValue %x\n", 985157117Smjacob mpt->mpt_port_page1.Configuration, 986157117Smjacob mpt->mpt_port_page1.OnBusTimerValue); 987157117Smjacob } 988157117Smjacob 989157662Smjacob rv = mpt_read_cur_cfg_page(mpt, 0, &mpt->mpt_port_page2.Header, 990157662Smjacob sizeof(mpt->mpt_port_page2), FALSE, 5000); 991157117Smjacob if (rv) { 992157117Smjacob mpt_prt(mpt, "failed to read SPI Port Page 2\n"); 993157117Smjacob } else { 994159178Smjacob mpt_lprt(mpt, MPT_PRT_NEGOTIATION, 995159178Smjacob "Port Page 2: Flags %x Settings %x\n", 996157117Smjacob mpt->mpt_port_page2.PortFlags, 997157117Smjacob mpt->mpt_port_page2.PortSettings); 998186878Smarius mpt2host_config_page_scsi_port_2(&mpt->mpt_port_page2); 999157117Smjacob for (i = 0; i < 16; i++) { 1000159178Smjacob mpt_lprt(mpt, MPT_PRT_NEGOTIATION, 1001159178Smjacob " Port Page 2 Tgt %d: timo %x SF %x Flags %x\n", 1002157117Smjacob i, mpt->mpt_port_page2.DeviceSettings[i].Timeout, 1003157117Smjacob mpt->mpt_port_page2.DeviceSettings[i].SyncFactor, 1004157117Smjacob mpt->mpt_port_page2.DeviceSettings[i].DeviceFlags); 1005157117Smjacob } 1006157117Smjacob } 1007157117Smjacob 1008157117Smjacob for (i = 0; i < 16; i++) { 1009157662Smjacob rv = mpt_read_cur_cfg_page(mpt, i, 1010157662Smjacob &mpt->mpt_dev_page0[i].Header, sizeof(*mpt->mpt_dev_page0), 1011157662Smjacob FALSE, 5000); 1012157117Smjacob if (rv) { 1013157117Smjacob mpt_prt(mpt, 1014157662Smjacob "cannot read SPI Target %d Device Page 0\n", i); 1015157117Smjacob continue; 1016157117Smjacob } 1017186878Smarius mpt2host_config_page_scsi_device_0(&mpt->mpt_dev_page0[i]); 1018159178Smjacob mpt_lprt(mpt, MPT_PRT_NEGOTIATION, 1019159178Smjacob "target %d page 0: Negotiated Params %x Information %x\n", 1020159178Smjacob i, mpt->mpt_dev_page0[i].NegotiatedParameters, 1021157662Smjacob mpt->mpt_dev_page0[i].Information); 1022157117Smjacob 1023157662Smjacob rv = mpt_read_cur_cfg_page(mpt, i, 1024157662Smjacob &mpt->mpt_dev_page1[i].Header, sizeof(*mpt->mpt_dev_page1), 1025157662Smjacob FALSE, 5000); 1026157117Smjacob if (rv) { 1027157117Smjacob mpt_prt(mpt, 1028157662Smjacob "cannot read SPI Target %d Device Page 1\n", i); 1029157117Smjacob continue; 1030157117Smjacob } 1031186878Smarius mpt2host_config_page_scsi_device_1(&mpt->mpt_dev_page1[i]); 1032159178Smjacob mpt_lprt(mpt, MPT_PRT_NEGOTIATION, 1033159178Smjacob "target %d page 1: Requested Params %x Configuration %x\n", 1034159178Smjacob i, mpt->mpt_dev_page1[i].RequestedParameters, 1035157662Smjacob mpt->mpt_dev_page1[i].Configuration); 1036157117Smjacob } 1037157117Smjacob return (0); 1038157117Smjacob} 1039157117Smjacob 1040157117Smjacob/* 1041157117Smjacob * Validate SPI configuration information. 1042157117Smjacob * 1043157117Smjacob * In particular, validate SPI Port Page 1. 1044157117Smjacob */ 1045157117Smjacobstatic int 1046157117Smjacobmpt_set_initial_config_spi(struct mpt_softc *mpt) 1047157117Smjacob{ 1048207286Smarius int error, i, pp1val; 1049157117Smjacob 1050157117Smjacob mpt->mpt_disc_enable = 0xff; 1051157117Smjacob mpt->mpt_tag_enable = 0; 1052157117Smjacob 1053207286Smarius pp1val = ((1 << mpt->mpt_ini_id) << 1054207286Smarius MPI_SCSIPORTPAGE1_CFG_SHIFT_PORT_RESPONSE_ID) | mpt->mpt_ini_id; 1055157117Smjacob if (mpt->mpt_port_page1.Configuration != pp1val) { 1056157117Smjacob CONFIG_PAGE_SCSI_PORT_1 tmp; 1057157117Smjacob 1058157662Smjacob mpt_prt(mpt, "SPI Port Page 1 Config value bad (%x)- should " 1059157662Smjacob "be %x\n", mpt->mpt_port_page1.Configuration, pp1val); 1060157117Smjacob tmp = mpt->mpt_port_page1; 1061157117Smjacob tmp.Configuration = pp1val; 1062186878Smarius host2mpt_config_page_scsi_port_1(&tmp); 1063157662Smjacob error = mpt_write_cur_cfg_page(mpt, 0, 1064157662Smjacob &tmp.Header, sizeof(tmp), FALSE, 5000); 1065157662Smjacob if (error) { 1066157117Smjacob return (-1); 1067157662Smjacob } 1068157662Smjacob error = mpt_read_cur_cfg_page(mpt, 0, 1069157662Smjacob &tmp.Header, sizeof(tmp), FALSE, 5000); 1070157662Smjacob if (error) { 1071157117Smjacob return (-1); 1072157662Smjacob } 1073186878Smarius mpt2host_config_page_scsi_port_1(&tmp); 1074157117Smjacob if (tmp.Configuration != pp1val) { 1075157117Smjacob mpt_prt(mpt, 1076157117Smjacob "failed to reset SPI Port Page 1 Config value\n"); 1077157117Smjacob return (-1); 1078157117Smjacob } 1079157117Smjacob mpt->mpt_port_page1 = tmp; 1080157117Smjacob } 1081157117Smjacob 1082157662Smjacob /* 1083157662Smjacob * The purpose of this exercise is to get 1084157662Smjacob * all targets back to async/narrow. 1085157662Smjacob * 1086159051Smjacob * We skip this step if the BIOS has already negotiated 1087194903Smarius * speeds with the targets. 1088157662Smjacob */ 1089157662Smjacob i = mpt->mpt_port_page2.PortSettings & 1090157662Smjacob MPI_SCSIPORTPAGE2_PORT_MASK_NEGO_MASTER_SETTINGS; 1091194903Smarius if (i == MPI_SCSIPORTPAGE2_PORT_ALL_MASTER_SETTINGS) { 1092159051Smjacob mpt_lprt(mpt, MPT_PRT_NEGOTIATION, 1093158935Smjacob "honoring BIOS transfer negotiations\n"); 1094159178Smjacob } else { 1095159178Smjacob for (i = 0; i < 16; i++) { 1096159178Smjacob mpt->mpt_dev_page1[i].RequestedParameters = 0; 1097159178Smjacob mpt->mpt_dev_page1[i].Configuration = 0; 1098159178Smjacob (void) mpt_update_spi_config(mpt, i); 1099159178Smjacob } 1100157662Smjacob } 1101157117Smjacob return (0); 1102157117Smjacob} 1103157117Smjacob 1104224493Smariusstatic int 1105157117Smjacobmpt_cam_enable(struct mpt_softc *mpt) 1106157117Smjacob{ 1107169293Smjacob int error; 1108169293Smjacob 1109169293Smjacob MPT_LOCK(mpt); 1110169293Smjacob 1111169293Smjacob error = EIO; 1112157117Smjacob if (mpt->is_fc) { 1113157117Smjacob if (mpt_read_config_info_fc(mpt)) { 1114169293Smjacob goto out; 1115157117Smjacob } 1116157117Smjacob if (mpt_set_initial_config_fc(mpt)) { 1117169293Smjacob goto out; 1118157117Smjacob } 1119157117Smjacob } else if (mpt->is_sas) { 1120157117Smjacob if (mpt_read_config_info_sas(mpt)) { 1121169293Smjacob goto out; 1122157117Smjacob } 1123157117Smjacob if (mpt_set_initial_config_sas(mpt)) { 1124169293Smjacob goto out; 1125157117Smjacob } 1126159178Smjacob } else if (mpt->is_spi) { 1127157117Smjacob if (mpt_read_config_info_spi(mpt)) { 1128169293Smjacob goto out; 1129157117Smjacob } 1130157117Smjacob if (mpt_set_initial_config_spi(mpt)) { 1131169293Smjacob goto out; 1132157117Smjacob } 1133157117Smjacob } 1134169293Smjacob error = 0; 1135169293Smjacob 1136169293Smjacobout: 1137169293Smjacob MPT_UNLOCK(mpt); 1138169293Smjacob return (error); 1139162133Smjacob} 1140162133Smjacob 1141224493Smariusstatic void 1142162133Smjacobmpt_cam_ready(struct mpt_softc *mpt) 1143162133Smjacob{ 1144224493Smarius 1145160391Smjacob /* 1146160391Smjacob * If we're in target mode, hang out resources now 1147160391Smjacob * so we don't cause the world to hang talking to us. 1148160391Smjacob */ 1149162059Smjacob if (mpt->is_fc && (mpt->role & MPT_ROLE_TARGET)) { 1150160391Smjacob /* 1151160391Smjacob * Try to add some target command resources 1152160391Smjacob */ 1153162133Smjacob MPT_LOCK(mpt); 1154160391Smjacob if (mpt_add_target_commands(mpt) == FALSE) { 1155162133Smjacob mpt_prt(mpt, "failed to add target commands\n"); 1156160391Smjacob } 1157162133Smjacob MPT_UNLOCK(mpt); 1158160391Smjacob } 1159165814Smjacob mpt->ready = 1; 1160157117Smjacob} 1161157117Smjacob 1162224493Smariusstatic void 1163147883Sscottlmpt_cam_detach(struct mpt_softc *mpt) 1164147883Sscottl{ 1165147883Sscottl mpt_handler_t handler; 1166147883Sscottl 1167169293Smjacob MPT_LOCK(mpt); 1168165814Smjacob mpt->ready = 0; 1169147883Sscottl mpt_terminate_recovery_thread(mpt); 1170147883Sscottl 1171147883Sscottl handler.reply_handler = mpt_scsi_reply_handler; 1172147883Sscottl mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler, 1173147883Sscottl scsi_io_handler_id); 1174147883Sscottl handler.reply_handler = mpt_scsi_tmf_reply_handler; 1175147883Sscottl mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler, 1176147883Sscottl scsi_tmf_handler_id); 1177157117Smjacob handler.reply_handler = mpt_fc_els_reply_handler; 1178157117Smjacob mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler, 1179157117Smjacob fc_els_handler_id); 1180157117Smjacob handler.reply_handler = mpt_scsi_tgt_reply_handler; 1181157117Smjacob mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler, 1182157117Smjacob mpt->scsi_tgt_handler_id); 1183170252Sscottl handler.reply_handler = mpt_sata_pass_reply_handler; 1184170252Sscottl mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler, 1185170252Sscottl sata_pass_handler_id); 1186147883Sscottl 1187147883Sscottl if (mpt->tmf_req != NULL) { 1188157662Smjacob mpt->tmf_req->state = REQ_STATE_ALLOCATED; 1189147883Sscottl mpt_free_request(mpt, mpt->tmf_req); 1190147883Sscottl mpt->tmf_req = NULL; 1191147883Sscottl } 1192170271Sscottl if (mpt->sas_portinfo != NULL) { 1193170271Sscottl free(mpt->sas_portinfo, M_DEVBUF); 1194170271Sscottl mpt->sas_portinfo = NULL; 1195170271Sscottl } 1196147883Sscottl 1197147883Sscottl if (mpt->sim != NULL) { 1198147883Sscottl xpt_free_path(mpt->path); 1199147883Sscottl xpt_bus_deregister(cam_sim_path(mpt->sim)); 1200147883Sscottl cam_sim_free(mpt->sim, TRUE); 1201147883Sscottl mpt->sim = NULL; 1202147883Sscottl } 1203147883Sscottl 1204147883Sscottl if (mpt->phydisk_sim != NULL) { 1205147883Sscottl xpt_free_path(mpt->phydisk_path); 1206147883Sscottl xpt_bus_deregister(cam_sim_path(mpt->phydisk_sim)); 1207147883Sscottl cam_sim_free(mpt->phydisk_sim, TRUE); 1208147883Sscottl mpt->phydisk_sim = NULL; 1209147883Sscottl } 1210209599Sken MPT_UNLOCK(mpt); 1211147883Sscottl} 1212147883Sscottl 1213157117Smjacob/* This routine is used after a system crash to dump core onto the swap device. 1214147883Sscottl */ 1215147883Sscottlstatic void 1216147883Sscottlmpt_poll(struct cam_sim *sim) 1217147883Sscottl{ 1218147883Sscottl struct mpt_softc *mpt; 1219147883Sscottl 1220147883Sscottl mpt = (struct mpt_softc *)cam_sim_softc(sim); 1221147883Sscottl mpt_intr(mpt); 1222147883Sscottl} 1223147883Sscottl 1224147883Sscottl/* 1225147883Sscottl * Watchdog timeout routine for SCSI requests. 1226147883Sscottl */ 1227147883Sscottlstatic void 1228147883Sscottlmpt_timeout(void *arg) 1229147883Sscottl{ 1230147883Sscottl union ccb *ccb; 1231147883Sscottl struct mpt_softc *mpt; 1232147883Sscottl request_t *req; 1233147883Sscottl 1234147883Sscottl ccb = (union ccb *)arg; 1235147883Sscottl mpt = ccb->ccb_h.ccb_mpt_ptr; 1236147883Sscottl 1237198262Skan MPT_LOCK_ASSERT(mpt); 1238147883Sscottl req = ccb->ccb_h.ccb_req_ptr; 1239157354Smjacob mpt_prt(mpt, "request %p:%u timed out for ccb %p (req->ccb %p)\n", req, 1240157354Smjacob req->serno, ccb, req->ccb); 1241157662Smjacob/* XXX: WHAT ARE WE TRYING TO DO HERE? */ 1242147883Sscottl if ((req->state & REQ_STATE_QUEUED) == REQ_STATE_QUEUED) { 1243147883Sscottl TAILQ_REMOVE(&mpt->request_pending_list, req, links); 1244147883Sscottl TAILQ_INSERT_TAIL(&mpt->request_timeout_list, req, links); 1245147883Sscottl req->state |= REQ_STATE_TIMEDOUT; 1246147883Sscottl mpt_wakeup_recovery_thread(mpt); 1247147883Sscottl } 1248147883Sscottl} 1249147883Sscottl 1250147883Sscottl/* 1251252301Smarius * Callback routine from bus_dmamap_load_ccb(9) or, in simple cases, called 1252252301Smarius * directly. 1253147883Sscottl * 1254147883Sscottl * Takes a list of physical segments and builds the SGL for SCSI IO command 1255147883Sscottl * and forwards the commard to the IOC after one last check that CAM has not 1256147883Sscottl * aborted the transaction. 1257147883Sscottl */ 1258147883Sscottlstatic void 1259157117Smjacobmpt_execute_req_a64(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 1260147883Sscottl{ 1261155521Smjacob request_t *req, *trq; 1262155521Smjacob char *mpt_off; 1263147883Sscottl union ccb *ccb; 1264147883Sscottl struct mpt_softc *mpt; 1265231623Smarius bus_addr_t chain_list_addr; 1266231623Smarius int first_lim, seg, this_seg_lim; 1267231623Smarius uint32_t addr, cur_off, flags, nxt_off, tf; 1268158935Smjacob void *sglp = NULL; 1269157117Smjacob MSG_REQUEST_HEADER *hdrp; 1270155521Smjacob SGE_SIMPLE64 *se; 1271155521Smjacob SGE_CHAIN64 *ce; 1272158935Smjacob int istgt = 0; 1273147883Sscottl 1274147883Sscottl req = (request_t *)arg; 1275147883Sscottl ccb = req->ccb; 1276147883Sscottl 1277147883Sscottl mpt = ccb->ccb_h.ccb_mpt_ptr; 1278147883Sscottl req = ccb->ccb_h.ccb_req_ptr; 1279157117Smjacob 1280157117Smjacob hdrp = req->req_vbuf; 1281155521Smjacob mpt_off = req->req_vbuf; 1282147883Sscottl 1283155521Smjacob if (error == 0 && ((uint32_t)nseg) >= mpt->max_seg_cnt) { 1284147883Sscottl error = EFBIG; 1285147883Sscottl } 1286147883Sscottl 1287158935Smjacob if (error == 0) { 1288158935Smjacob switch (hdrp->Function) { 1289158935Smjacob case MPI_FUNCTION_SCSI_IO_REQUEST: 1290158935Smjacob case MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: 1291158935Smjacob istgt = 0; 1292158935Smjacob sglp = &((PTR_MSG_SCSI_IO_REQUEST)hdrp)->SGL; 1293158935Smjacob break; 1294158935Smjacob case MPI_FUNCTION_TARGET_ASSIST: 1295158935Smjacob istgt = 1; 1296158935Smjacob sglp = &((PTR_MSG_TARGET_ASSIST_REQUEST)hdrp)->SGL; 1297158935Smjacob break; 1298158935Smjacob default: 1299158935Smjacob mpt_prt(mpt, "bad fct 0x%x in mpt_execute_req_a64\n", 1300158935Smjacob hdrp->Function); 1301158935Smjacob error = EINVAL; 1302158935Smjacob break; 1303158935Smjacob } 1304158935Smjacob } 1305159178Smjacob 1306159178Smjacob if (error == 0 && ((uint32_t)nseg) >= mpt->max_seg_cnt) { 1307159178Smjacob error = EFBIG; 1308159178Smjacob mpt_prt(mpt, "segment count %d too large (max %u)\n", 1309159178Smjacob nseg, mpt->max_seg_cnt); 1310159178Smjacob } 1311159178Smjacob 1312155521Smjacobbad: 1313147883Sscottl if (error != 0) { 1314157117Smjacob if (error != EFBIG && error != ENOMEM) { 1315159178Smjacob mpt_prt(mpt, "mpt_execute_req_a64: err %d\n", error); 1316157117Smjacob } 1317157117Smjacob if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { 1318157117Smjacob cam_status status; 1319157117Smjacob mpt_freeze_ccb(ccb); 1320155521Smjacob if (error == EFBIG) { 1321157117Smjacob status = CAM_REQ_TOO_BIG; 1322155521Smjacob } else if (error == ENOMEM) { 1323155521Smjacob if (mpt->outofbeer == 0) { 1324155521Smjacob mpt->outofbeer = 1; 1325155521Smjacob xpt_freeze_simq(mpt->sim, 1); 1326155521Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 1327155521Smjacob "FREEZEQ\n"); 1328155521Smjacob } 1329157117Smjacob status = CAM_REQUEUE_REQ; 1330157117Smjacob } else { 1331157117Smjacob status = CAM_REQ_CMP_ERR; 1332157117Smjacob } 1333157117Smjacob mpt_set_ccb_status(ccb, status); 1334147883Sscottl } 1335157117Smjacob if (hdrp->Function == MPI_FUNCTION_TARGET_ASSIST) { 1336157117Smjacob request_t *cmd_req = 1337157117Smjacob MPT_TAG_2_REQ(mpt, ccb->csio.tag_id); 1338157117Smjacob MPT_TGT_STATE(mpt, cmd_req)->state = TGT_STATE_IN_CAM; 1339157117Smjacob MPT_TGT_STATE(mpt, cmd_req)->ccb = NULL; 1340157117Smjacob MPT_TGT_STATE(mpt, cmd_req)->req = NULL; 1341157117Smjacob } 1342147883Sscottl ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1343231629Smarius KASSERT(ccb->ccb_h.status, ("zero ccb sts at %d", __LINE__)); 1344147883Sscottl xpt_done(ccb); 1345147883Sscottl mpt_free_request(mpt, req); 1346147883Sscottl return; 1347147883Sscottl } 1348147883Sscottl 1349155521Smjacob /* 1350155521Smjacob * No data to transfer? 1351155521Smjacob * Just make a single simple SGL with zero length. 1352155521Smjacob */ 1353147883Sscottl 1354155521Smjacob if (mpt->verbose >= MPT_PRT_DEBUG) { 1355157117Smjacob int tidx = ((char *)sglp) - mpt_off; 1356155521Smjacob memset(&mpt_off[tidx], 0xff, MPT_REQUEST_AREA - tidx); 1357155521Smjacob } 1358147883Sscottl 1359155521Smjacob if (nseg == 0) { 1360157117Smjacob SGE_SIMPLE32 *se1 = (SGE_SIMPLE32 *) sglp; 1361155521Smjacob MPI_pSGE_SET_FLAGS(se1, 1362155521Smjacob (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 1363155521Smjacob MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST)); 1364164315Sjb se1->FlagsLength = htole32(se1->FlagsLength); 1365155521Smjacob goto out; 1366155521Smjacob } 1367155521Smjacob 1368157117Smjacob 1369155521Smjacob flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_64_BIT_ADDRESSING; 1370158935Smjacob if (istgt == 0) { 1371157117Smjacob if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { 1372157117Smjacob flags |= MPI_SGE_FLAGS_HOST_TO_IOC; 1373157117Smjacob } 1374155521Smjacob } else { 1375157117Smjacob if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1376157117Smjacob flags |= MPI_SGE_FLAGS_HOST_TO_IOC; 1377157117Smjacob } 1378155521Smjacob } 1379157117Smjacob 1380251874Sscottl if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 1381157117Smjacob bus_dmasync_op_t op; 1382158935Smjacob if (istgt == 0) { 1383157117Smjacob if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1384157117Smjacob op = BUS_DMASYNC_PREREAD; 1385157117Smjacob } else { 1386157117Smjacob op = BUS_DMASYNC_PREWRITE; 1387157117Smjacob } 1388157117Smjacob } else { 1389157117Smjacob if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1390157117Smjacob op = BUS_DMASYNC_PREWRITE; 1391157117Smjacob } else { 1392157117Smjacob op = BUS_DMASYNC_PREREAD; 1393157117Smjacob } 1394157117Smjacob } 1395155521Smjacob bus_dmamap_sync(mpt->buffer_dmat, req->dmap, op); 1396155521Smjacob } 1397155521Smjacob 1398155521Smjacob /* 1399155521Smjacob * Okay, fill in what we can at the end of the command frame. 1400155521Smjacob * If we have up to MPT_NSGL_FIRST, we can fit them all into 1401155521Smjacob * the command frame. 1402155521Smjacob * 1403155521Smjacob * Otherwise, we fill up through MPT_NSGL_FIRST less one 1404155521Smjacob * SIMPLE64 pointers and start doing CHAIN64 entries after 1405155521Smjacob * that. 1406155521Smjacob */ 1407155521Smjacob 1408155521Smjacob if (nseg < MPT_NSGL_FIRST(mpt)) { 1409155521Smjacob first_lim = nseg; 1410155521Smjacob } else { 1411155521Smjacob /* 1412155521Smjacob * Leave room for CHAIN element 1413155521Smjacob */ 1414155521Smjacob first_lim = MPT_NSGL_FIRST(mpt) - 1; 1415155521Smjacob } 1416155521Smjacob 1417157117Smjacob se = (SGE_SIMPLE64 *) sglp; 1418155521Smjacob for (seg = 0; seg < first_lim; seg++, se++, dm_segs++) { 1419231623Smarius tf = flags; 1420157354Smjacob memset(se, 0, sizeof (*se)); 1421231623Smarius MPI_pSGE_SET_LENGTH(se, dm_segs->ds_len); 1422164315Sjb se->Address.Low = htole32(dm_segs->ds_addr & 0xffffffff); 1423155521Smjacob if (sizeof(bus_addr_t) > 4) { 1424231623Smarius addr = ((uint64_t)dm_segs->ds_addr) >> 32; 1425231623Smarius /* SAS1078 36GB limitation WAR */ 1426231623Smarius if (mpt->is_1078 && (((uint64_t)dm_segs->ds_addr + 1427231623Smarius MPI_SGE_LENGTH(se->FlagsLength)) >> 32) == 9) { 1428231623Smarius addr |= (1 << 31); 1429231623Smarius tf |= MPI_SGE_FLAGS_LOCAL_ADDRESS; 1430231623Smarius } 1431231623Smarius se->Address.High = htole32(addr); 1432147883Sscottl } 1433155521Smjacob if (seg == first_lim - 1) { 1434155521Smjacob tf |= MPI_SGE_FLAGS_LAST_ELEMENT; 1435155521Smjacob } 1436155521Smjacob if (seg == nseg - 1) { 1437155521Smjacob tf |= MPI_SGE_FLAGS_END_OF_LIST | 1438155521Smjacob MPI_SGE_FLAGS_END_OF_BUFFER; 1439155521Smjacob } 1440155521Smjacob MPI_pSGE_SET_FLAGS(se, tf); 1441164315Sjb se->FlagsLength = htole32(se->FlagsLength); 1442155521Smjacob } 1443147883Sscottl 1444155521Smjacob if (seg == nseg) { 1445155521Smjacob goto out; 1446155521Smjacob } 1447155521Smjacob 1448155521Smjacob /* 1449155521Smjacob * Tell the IOC where to find the first chain element. 1450155521Smjacob */ 1451157117Smjacob hdrp->ChainOffset = ((char *)se - (char *)hdrp) >> 2; 1452155521Smjacob nxt_off = MPT_RQSL(mpt); 1453155521Smjacob trq = req; 1454155521Smjacob 1455155521Smjacob /* 1456155521Smjacob * Make up the rest of the data segments out of a chain element 1457231623Smarius * (contained in the current request frame) which points to 1458155521Smjacob * SIMPLE64 elements in the next request frame, possibly ending 1459155521Smjacob * with *another* chain element (if there's more). 1460155521Smjacob */ 1461155521Smjacob while (seg < nseg) { 1462147883Sscottl /* 1463155521Smjacob * Point to the chain descriptor. Note that the chain 1464155521Smjacob * descriptor is at the end of the *previous* list (whether 1465155521Smjacob * chain or simple). 1466147883Sscottl */ 1467155521Smjacob ce = (SGE_CHAIN64 *) se; 1468147883Sscottl 1469147883Sscottl /* 1470155521Smjacob * Before we change our current pointer, make sure we won't 1471155521Smjacob * overflow the request area with this frame. Note that we 1472155521Smjacob * test against 'greater than' here as it's okay in this case 1473155521Smjacob * to have next offset be just outside the request area. 1474147883Sscottl */ 1475155521Smjacob if ((nxt_off + MPT_RQSL(mpt)) > MPT_REQUEST_AREA) { 1476155521Smjacob nxt_off = MPT_REQUEST_AREA; 1477155521Smjacob goto next_chain; 1478155521Smjacob } 1479147883Sscottl 1480155521Smjacob /* 1481155521Smjacob * Set our SGE element pointer to the beginning of the chain 1482155521Smjacob * list and update our next chain list offset. 1483155521Smjacob */ 1484155521Smjacob se = (SGE_SIMPLE64 *) &mpt_off[nxt_off]; 1485155521Smjacob cur_off = nxt_off; 1486155521Smjacob nxt_off += MPT_RQSL(mpt); 1487147883Sscottl 1488155521Smjacob /* 1489231623Smarius * Now initialize the chain descriptor. 1490155521Smjacob */ 1491157354Smjacob memset(ce, 0, sizeof (*ce)); 1492155521Smjacob 1493155521Smjacob /* 1494155521Smjacob * Get the physical address of the chain list. 1495155521Smjacob */ 1496155521Smjacob chain_list_addr = trq->req_pbuf; 1497155521Smjacob chain_list_addr += cur_off; 1498155521Smjacob if (sizeof (bus_addr_t) > 4) { 1499155521Smjacob ce->Address.High = 1500186878Smarius htole32(((uint64_t)chain_list_addr) >> 32); 1501147883Sscottl } 1502186878Smarius ce->Address.Low = htole32(chain_list_addr & 0xffffffff); 1503155521Smjacob ce->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | 1504155521Smjacob MPI_SGE_FLAGS_64_BIT_ADDRESSING; 1505147883Sscottl 1506155521Smjacob /* 1507155521Smjacob * If we have more than a frame's worth of segments left, 1508155521Smjacob * set up the chain list to have the last element be another 1509155521Smjacob * chain descriptor. 1510155521Smjacob */ 1511155521Smjacob if ((nseg - seg) > MPT_NSGL(mpt)) { 1512155521Smjacob this_seg_lim = seg + MPT_NSGL(mpt) - 1; 1513155521Smjacob /* 1514155521Smjacob * The length of the chain is the length in bytes of the 1515155521Smjacob * number of segments plus the next chain element. 1516155521Smjacob * 1517155521Smjacob * The next chain descriptor offset is the length, 1518155521Smjacob * in words, of the number of segments. 1519155521Smjacob */ 1520155521Smjacob ce->Length = (this_seg_lim - seg) * 1521155521Smjacob sizeof (SGE_SIMPLE64); 1522155521Smjacob ce->NextChainOffset = ce->Length >> 2; 1523155521Smjacob ce->Length += sizeof (SGE_CHAIN64); 1524155521Smjacob } else { 1525155521Smjacob this_seg_lim = nseg; 1526155521Smjacob ce->Length = (this_seg_lim - seg) * 1527155521Smjacob sizeof (SGE_SIMPLE64); 1528147883Sscottl } 1529186878Smarius ce->Length = htole16(ce->Length); 1530147883Sscottl 1531155521Smjacob /* 1532155521Smjacob * Fill in the chain list SGE elements with our segment data. 1533155521Smjacob * 1534155521Smjacob * If we're the last element in this chain list, set the last 1535155521Smjacob * element flag. If we're the completely last element period, 1536155521Smjacob * set the end of list and end of buffer flags. 1537155521Smjacob */ 1538155521Smjacob while (seg < this_seg_lim) { 1539231623Smarius tf = flags; 1540157354Smjacob memset(se, 0, sizeof (*se)); 1541231623Smarius MPI_pSGE_SET_LENGTH(se, dm_segs->ds_len); 1542186878Smarius se->Address.Low = htole32(dm_segs->ds_addr & 1543186878Smarius 0xffffffff); 1544155521Smjacob if (sizeof (bus_addr_t) > 4) { 1545231623Smarius addr = ((uint64_t)dm_segs->ds_addr) >> 32; 1546231623Smarius /* SAS1078 36GB limitation WAR */ 1547231623Smarius if (mpt->is_1078 && 1548231623Smarius (((uint64_t)dm_segs->ds_addr + 1549231623Smarius MPI_SGE_LENGTH(se->FlagsLength)) >> 1550231623Smarius 32) == 9) { 1551231623Smarius addr |= (1 << 31); 1552231623Smarius tf |= MPI_SGE_FLAGS_LOCAL_ADDRESS; 1553231623Smarius } 1554231623Smarius se->Address.High = htole32(addr); 1555155521Smjacob } 1556231623Smarius if (seg == this_seg_lim - 1) { 1557155521Smjacob tf |= MPI_SGE_FLAGS_LAST_ELEMENT; 1558147883Sscottl } 1559155521Smjacob if (seg == nseg - 1) { 1560155521Smjacob tf |= MPI_SGE_FLAGS_END_OF_LIST | 1561155521Smjacob MPI_SGE_FLAGS_END_OF_BUFFER; 1562155521Smjacob } 1563147883Sscottl MPI_pSGE_SET_FLAGS(se, tf); 1564164315Sjb se->FlagsLength = htole32(se->FlagsLength); 1565155521Smjacob se++; 1566155521Smjacob seg++; 1567155521Smjacob dm_segs++; 1568147883Sscottl } 1569147883Sscottl 1570155521Smjacob next_chain: 1571147883Sscottl /* 1572155521Smjacob * If we have more segments to do and we've used up all of 1573155521Smjacob * the space in a request area, go allocate another one 1574155521Smjacob * and chain to that. 1575147883Sscottl */ 1576155521Smjacob if (seg < nseg && nxt_off >= MPT_REQUEST_AREA) { 1577157662Smjacob request_t *nrq; 1578155521Smjacob 1579157662Smjacob nrq = mpt_get_request(mpt, FALSE); 1580157662Smjacob 1581155521Smjacob if (nrq == NULL) { 1582155521Smjacob error = ENOMEM; 1583155521Smjacob goto bad; 1584155521Smjacob } 1585155521Smjacob 1586155521Smjacob /* 1587155521Smjacob * Append the new request area on the tail of our list. 1588155521Smjacob */ 1589155521Smjacob if ((trq = req->chain) == NULL) { 1590155521Smjacob req->chain = nrq; 1591155521Smjacob } else { 1592155521Smjacob while (trq->chain != NULL) { 1593155521Smjacob trq = trq->chain; 1594155521Smjacob } 1595155521Smjacob trq->chain = nrq; 1596155521Smjacob } 1597155521Smjacob trq = nrq; 1598155521Smjacob mpt_off = trq->req_vbuf; 1599155521Smjacob if (mpt->verbose >= MPT_PRT_DEBUG) { 1600155521Smjacob memset(mpt_off, 0xff, MPT_REQUEST_AREA); 1601155521Smjacob } 1602155521Smjacob nxt_off = 0; 1603155521Smjacob } 1604147883Sscottl } 1605155521Smjacobout: 1606147883Sscottl 1607147883Sscottl /* 1608147883Sscottl * Last time we need to check if this CCB needs to be aborted. 1609147883Sscottl */ 1610157117Smjacob if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { 1611157117Smjacob if (hdrp->Function == MPI_FUNCTION_TARGET_ASSIST) { 1612157117Smjacob request_t *cmd_req = 1613157117Smjacob MPT_TAG_2_REQ(mpt, ccb->csio.tag_id); 1614157117Smjacob MPT_TGT_STATE(mpt, cmd_req)->state = TGT_STATE_IN_CAM; 1615157117Smjacob MPT_TGT_STATE(mpt, cmd_req)->ccb = NULL; 1616157117Smjacob MPT_TGT_STATE(mpt, cmd_req)->req = NULL; 1617157117Smjacob } 1618157117Smjacob mpt_prt(mpt, 1619157117Smjacob "mpt_execute_req_a64: I/O cancelled (status 0x%x)\n", 1620157117Smjacob ccb->ccb_h.status & CAM_STATUS_MASK); 1621251874Sscottl if (nseg) { 1622147883Sscottl bus_dmamap_unload(mpt->buffer_dmat, req->dmap); 1623157117Smjacob } 1624157117Smjacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1625231629Smarius KASSERT(ccb->ccb_h.status, ("zero ccb sts at %d", __LINE__)); 1626157117Smjacob xpt_done(ccb); 1627147883Sscottl mpt_free_request(mpt, req); 1628157117Smjacob return; 1629157117Smjacob } 1630157117Smjacob 1631157117Smjacob ccb->ccb_h.status |= CAM_SIM_QUEUED; 1632157117Smjacob if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { 1633169293Smjacob mpt_req_timeout(req, (ccb->ccb_h.timeout * hz) / 1000, 1634169293Smjacob mpt_timeout, ccb); 1635157117Smjacob } 1636158982Smjacob if (mpt->verbose > MPT_PRT_DEBUG) { 1637157117Smjacob int nc = 0; 1638157117Smjacob mpt_print_request(req->req_vbuf); 1639157117Smjacob for (trq = req->chain; trq; trq = trq->chain) { 1640157117Smjacob printf(" Additional Chain Area %d\n", nc++); 1641157117Smjacob mpt_dump_sgl(trq->req_vbuf, 0); 1642157117Smjacob } 1643157117Smjacob } 1644158982Smjacob 1645157117Smjacob if (hdrp->Function == MPI_FUNCTION_TARGET_ASSIST) { 1646157117Smjacob request_t *cmd_req = MPT_TAG_2_REQ(mpt, ccb->csio.tag_id); 1647157117Smjacob mpt_tgt_state_t *tgt = MPT_TGT_STATE(mpt, cmd_req); 1648157117Smjacob#ifdef WE_TRUST_AUTO_GOOD_STATUS 1649157117Smjacob if ((ccb->ccb_h.flags & CAM_SEND_STATUS) && 1650157117Smjacob csio->scsi_status == SCSI_STATUS_OK && tgt->resid == 0) { 1651157117Smjacob tgt->state = TGT_STATE_MOVING_DATA_AND_STATUS; 1652157117Smjacob } else { 1653157117Smjacob tgt->state = TGT_STATE_MOVING_DATA; 1654157117Smjacob } 1655157117Smjacob#else 1656157117Smjacob tgt->state = TGT_STATE_MOVING_DATA; 1657157117Smjacob#endif 1658157117Smjacob } 1659157117Smjacob mpt_send_cmd(mpt, req); 1660157117Smjacob} 1661157117Smjacob 1662157117Smjacobstatic void 1663157117Smjacobmpt_execute_req(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 1664157117Smjacob{ 1665157117Smjacob request_t *req, *trq; 1666157117Smjacob char *mpt_off; 1667157117Smjacob union ccb *ccb; 1668157117Smjacob struct mpt_softc *mpt; 1669157117Smjacob int seg, first_lim; 1670157117Smjacob uint32_t flags, nxt_off; 1671158935Smjacob void *sglp = NULL; 1672157117Smjacob MSG_REQUEST_HEADER *hdrp; 1673157117Smjacob SGE_SIMPLE32 *se; 1674157117Smjacob SGE_CHAIN32 *ce; 1675158935Smjacob int istgt = 0; 1676157117Smjacob 1677157117Smjacob req = (request_t *)arg; 1678157117Smjacob ccb = req->ccb; 1679157117Smjacob 1680157117Smjacob mpt = ccb->ccb_h.ccb_mpt_ptr; 1681157117Smjacob req = ccb->ccb_h.ccb_req_ptr; 1682157117Smjacob 1683157117Smjacob hdrp = req->req_vbuf; 1684157117Smjacob mpt_off = req->req_vbuf; 1685157117Smjacob 1686158935Smjacob if (error == 0 && ((uint32_t)nseg) >= mpt->max_seg_cnt) { 1687158935Smjacob error = EFBIG; 1688157117Smjacob } 1689157117Smjacob 1690158935Smjacob if (error == 0) { 1691158935Smjacob switch (hdrp->Function) { 1692158935Smjacob case MPI_FUNCTION_SCSI_IO_REQUEST: 1693158935Smjacob case MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: 1694158935Smjacob sglp = &((PTR_MSG_SCSI_IO_REQUEST)hdrp)->SGL; 1695158935Smjacob break; 1696158935Smjacob case MPI_FUNCTION_TARGET_ASSIST: 1697158935Smjacob istgt = 1; 1698158935Smjacob sglp = &((PTR_MSG_TARGET_ASSIST_REQUEST)hdrp)->SGL; 1699158935Smjacob break; 1700158935Smjacob default: 1701158935Smjacob mpt_prt(mpt, "bad fct 0x%x in mpt_execute_req\n", 1702158935Smjacob hdrp->Function); 1703158935Smjacob error = EINVAL; 1704158935Smjacob break; 1705158935Smjacob } 1706158935Smjacob } 1707157117Smjacob 1708157117Smjacob if (error == 0 && ((uint32_t)nseg) >= mpt->max_seg_cnt) { 1709157117Smjacob error = EFBIG; 1710157117Smjacob mpt_prt(mpt, "segment count %d too large (max %u)\n", 1711157117Smjacob nseg, mpt->max_seg_cnt); 1712157117Smjacob } 1713157117Smjacob 1714157117Smjacobbad: 1715157117Smjacob if (error != 0) { 1716159178Smjacob if (error != EFBIG && error != ENOMEM) { 1717159178Smjacob mpt_prt(mpt, "mpt_execute_req: err %d\n", error); 1718157117Smjacob } 1719157117Smjacob if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { 1720157117Smjacob cam_status status; 1721157117Smjacob mpt_freeze_ccb(ccb); 1722157117Smjacob if (error == EFBIG) { 1723157117Smjacob status = CAM_REQ_TOO_BIG; 1724157117Smjacob } else if (error == ENOMEM) { 1725157117Smjacob if (mpt->outofbeer == 0) { 1726157117Smjacob mpt->outofbeer = 1; 1727157117Smjacob xpt_freeze_simq(mpt->sim, 1); 1728157117Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 1729157117Smjacob "FREEZEQ\n"); 1730157117Smjacob } 1731157117Smjacob status = CAM_REQUEUE_REQ; 1732157117Smjacob } else { 1733157117Smjacob status = CAM_REQ_CMP_ERR; 1734157117Smjacob } 1735157117Smjacob mpt_set_ccb_status(ccb, status); 1736157117Smjacob } 1737159178Smjacob if (hdrp->Function == MPI_FUNCTION_TARGET_ASSIST) { 1738159178Smjacob request_t *cmd_req = 1739159178Smjacob MPT_TAG_2_REQ(mpt, ccb->csio.tag_id); 1740159178Smjacob MPT_TGT_STATE(mpt, cmd_req)->state = TGT_STATE_IN_CAM; 1741159178Smjacob MPT_TGT_STATE(mpt, cmd_req)->ccb = NULL; 1742159178Smjacob MPT_TGT_STATE(mpt, cmd_req)->req = NULL; 1743159178Smjacob } 1744157117Smjacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1745231629Smarius KASSERT(ccb->ccb_h.status, ("zero ccb sts at %d", __LINE__)); 1746147883Sscottl xpt_done(ccb); 1747157117Smjacob mpt_free_request(mpt, req); 1748147883Sscottl return; 1749147883Sscottl } 1750147883Sscottl 1751157117Smjacob /* 1752157117Smjacob * No data to transfer? 1753157117Smjacob * Just make a single simple SGL with zero length. 1754157117Smjacob */ 1755157117Smjacob 1756157117Smjacob if (mpt->verbose >= MPT_PRT_DEBUG) { 1757157117Smjacob int tidx = ((char *)sglp) - mpt_off; 1758157117Smjacob memset(&mpt_off[tidx], 0xff, MPT_REQUEST_AREA - tidx); 1759157117Smjacob } 1760157117Smjacob 1761157117Smjacob if (nseg == 0) { 1762157117Smjacob SGE_SIMPLE32 *se1 = (SGE_SIMPLE32 *) sglp; 1763157117Smjacob MPI_pSGE_SET_FLAGS(se1, 1764157117Smjacob (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 1765157117Smjacob MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST)); 1766164315Sjb se1->FlagsLength = htole32(se1->FlagsLength); 1767157117Smjacob goto out; 1768157117Smjacob } 1769157117Smjacob 1770157117Smjacob 1771157117Smjacob flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT; 1772159178Smjacob if (istgt == 0) { 1773157117Smjacob if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { 1774157117Smjacob flags |= MPI_SGE_FLAGS_HOST_TO_IOC; 1775157117Smjacob } 1776157117Smjacob } else { 1777157117Smjacob if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1778157117Smjacob flags |= MPI_SGE_FLAGS_HOST_TO_IOC; 1779157117Smjacob } 1780157117Smjacob } 1781157117Smjacob 1782251874Sscottl if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 1783157117Smjacob bus_dmasync_op_t op; 1784158935Smjacob if (istgt) { 1785157117Smjacob if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1786157117Smjacob op = BUS_DMASYNC_PREREAD; 1787157117Smjacob } else { 1788157117Smjacob op = BUS_DMASYNC_PREWRITE; 1789157117Smjacob } 1790157117Smjacob } else { 1791157117Smjacob if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1792157117Smjacob op = BUS_DMASYNC_PREWRITE; 1793157117Smjacob } else { 1794157117Smjacob op = BUS_DMASYNC_PREREAD; 1795157117Smjacob } 1796157117Smjacob } 1797157117Smjacob bus_dmamap_sync(mpt->buffer_dmat, req->dmap, op); 1798157117Smjacob } 1799157117Smjacob 1800157117Smjacob /* 1801157117Smjacob * Okay, fill in what we can at the end of the command frame. 1802157117Smjacob * If we have up to MPT_NSGL_FIRST, we can fit them all into 1803157117Smjacob * the command frame. 1804157117Smjacob * 1805157117Smjacob * Otherwise, we fill up through MPT_NSGL_FIRST less one 1806157117Smjacob * SIMPLE32 pointers and start doing CHAIN32 entries after 1807157117Smjacob * that. 1808157117Smjacob */ 1809157117Smjacob 1810157117Smjacob if (nseg < MPT_NSGL_FIRST(mpt)) { 1811157117Smjacob first_lim = nseg; 1812157117Smjacob } else { 1813157117Smjacob /* 1814157117Smjacob * Leave room for CHAIN element 1815157117Smjacob */ 1816157117Smjacob first_lim = MPT_NSGL_FIRST(mpt) - 1; 1817157117Smjacob } 1818157117Smjacob 1819157117Smjacob se = (SGE_SIMPLE32 *) sglp; 1820157117Smjacob for (seg = 0; seg < first_lim; seg++, se++, dm_segs++) { 1821157117Smjacob uint32_t tf; 1822157117Smjacob 1823157354Smjacob memset(se, 0,sizeof (*se)); 1824186878Smarius se->Address = htole32(dm_segs->ds_addr); 1825159178Smjacob 1826157117Smjacob MPI_pSGE_SET_LENGTH(se, dm_segs->ds_len); 1827157117Smjacob tf = flags; 1828157117Smjacob if (seg == first_lim - 1) { 1829157117Smjacob tf |= MPI_SGE_FLAGS_LAST_ELEMENT; 1830157117Smjacob } 1831157117Smjacob if (seg == nseg - 1) { 1832157117Smjacob tf |= MPI_SGE_FLAGS_END_OF_LIST | 1833157117Smjacob MPI_SGE_FLAGS_END_OF_BUFFER; 1834157117Smjacob } 1835157117Smjacob MPI_pSGE_SET_FLAGS(se, tf); 1836164315Sjb se->FlagsLength = htole32(se->FlagsLength); 1837157117Smjacob } 1838157117Smjacob 1839157117Smjacob if (seg == nseg) { 1840157117Smjacob goto out; 1841157117Smjacob } 1842157117Smjacob 1843157117Smjacob /* 1844157117Smjacob * Tell the IOC where to find the first chain element. 1845157117Smjacob */ 1846157117Smjacob hdrp->ChainOffset = ((char *)se - (char *)hdrp) >> 2; 1847157117Smjacob nxt_off = MPT_RQSL(mpt); 1848157117Smjacob trq = req; 1849157117Smjacob 1850157117Smjacob /* 1851157117Smjacob * Make up the rest of the data segments out of a chain element 1852231623Smarius * (contained in the current request frame) which points to 1853157117Smjacob * SIMPLE32 elements in the next request frame, possibly ending 1854157117Smjacob * with *another* chain element (if there's more). 1855157117Smjacob */ 1856157117Smjacob while (seg < nseg) { 1857157117Smjacob int this_seg_lim; 1858157117Smjacob uint32_t tf, cur_off; 1859157117Smjacob bus_addr_t chain_list_addr; 1860157117Smjacob 1861157117Smjacob /* 1862157117Smjacob * Point to the chain descriptor. Note that the chain 1863157117Smjacob * descriptor is at the end of the *previous* list (whether 1864157117Smjacob * chain or simple). 1865157117Smjacob */ 1866157117Smjacob ce = (SGE_CHAIN32 *) se; 1867157117Smjacob 1868157117Smjacob /* 1869157117Smjacob * Before we change our current pointer, make sure we won't 1870157117Smjacob * overflow the request area with this frame. Note that we 1871157117Smjacob * test against 'greater than' here as it's okay in this case 1872157117Smjacob * to have next offset be just outside the request area. 1873157117Smjacob */ 1874157117Smjacob if ((nxt_off + MPT_RQSL(mpt)) > MPT_REQUEST_AREA) { 1875157117Smjacob nxt_off = MPT_REQUEST_AREA; 1876157117Smjacob goto next_chain; 1877157117Smjacob } 1878157117Smjacob 1879157117Smjacob /* 1880157117Smjacob * Set our SGE element pointer to the beginning of the chain 1881157117Smjacob * list and update our next chain list offset. 1882157117Smjacob */ 1883157117Smjacob se = (SGE_SIMPLE32 *) &mpt_off[nxt_off]; 1884157117Smjacob cur_off = nxt_off; 1885157117Smjacob nxt_off += MPT_RQSL(mpt); 1886157117Smjacob 1887157117Smjacob /* 1888231623Smarius * Now initialize the chain descriptor. 1889157117Smjacob */ 1890157354Smjacob memset(ce, 0, sizeof (*ce)); 1891157117Smjacob 1892157117Smjacob /* 1893157117Smjacob * Get the physical address of the chain list. 1894157117Smjacob */ 1895157117Smjacob chain_list_addr = trq->req_pbuf; 1896157117Smjacob chain_list_addr += cur_off; 1897159178Smjacob 1898159178Smjacob 1899159178Smjacob 1900186878Smarius ce->Address = htole32(chain_list_addr); 1901157117Smjacob ce->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT; 1902157117Smjacob 1903159178Smjacob 1904157117Smjacob /* 1905157117Smjacob * If we have more than a frame's worth of segments left, 1906157117Smjacob * set up the chain list to have the last element be another 1907157117Smjacob * chain descriptor. 1908157117Smjacob */ 1909157117Smjacob if ((nseg - seg) > MPT_NSGL(mpt)) { 1910157117Smjacob this_seg_lim = seg + MPT_NSGL(mpt) - 1; 1911157117Smjacob /* 1912157117Smjacob * The length of the chain is the length in bytes of the 1913157117Smjacob * number of segments plus the next chain element. 1914157117Smjacob * 1915157117Smjacob * The next chain descriptor offset is the length, 1916157117Smjacob * in words, of the number of segments. 1917157117Smjacob */ 1918157117Smjacob ce->Length = (this_seg_lim - seg) * 1919157117Smjacob sizeof (SGE_SIMPLE32); 1920157117Smjacob ce->NextChainOffset = ce->Length >> 2; 1921157117Smjacob ce->Length += sizeof (SGE_CHAIN32); 1922157117Smjacob } else { 1923157117Smjacob this_seg_lim = nseg; 1924157117Smjacob ce->Length = (this_seg_lim - seg) * 1925157117Smjacob sizeof (SGE_SIMPLE32); 1926157117Smjacob } 1927186878Smarius ce->Length = htole16(ce->Length); 1928157117Smjacob 1929157117Smjacob /* 1930157117Smjacob * Fill in the chain list SGE elements with our segment data. 1931157117Smjacob * 1932157117Smjacob * If we're the last element in this chain list, set the last 1933157117Smjacob * element flag. If we're the completely last element period, 1934157117Smjacob * set the end of list and end of buffer flags. 1935157117Smjacob */ 1936157117Smjacob while (seg < this_seg_lim) { 1937157354Smjacob memset(se, 0, sizeof (*se)); 1938186878Smarius se->Address = htole32(dm_segs->ds_addr); 1939159178Smjacob 1940157117Smjacob MPI_pSGE_SET_LENGTH(se, dm_segs->ds_len); 1941157117Smjacob tf = flags; 1942231623Smarius if (seg == this_seg_lim - 1) { 1943157117Smjacob tf |= MPI_SGE_FLAGS_LAST_ELEMENT; 1944157117Smjacob } 1945157117Smjacob if (seg == nseg - 1) { 1946157117Smjacob tf |= MPI_SGE_FLAGS_END_OF_LIST | 1947157117Smjacob MPI_SGE_FLAGS_END_OF_BUFFER; 1948157117Smjacob } 1949157117Smjacob MPI_pSGE_SET_FLAGS(se, tf); 1950164315Sjb se->FlagsLength = htole32(se->FlagsLength); 1951157117Smjacob se++; 1952157117Smjacob seg++; 1953157117Smjacob dm_segs++; 1954157117Smjacob } 1955157117Smjacob 1956157117Smjacob next_chain: 1957157117Smjacob /* 1958157117Smjacob * If we have more segments to do and we've used up all of 1959157117Smjacob * the space in a request area, go allocate another one 1960157117Smjacob * and chain to that. 1961157117Smjacob */ 1962157117Smjacob if (seg < nseg && nxt_off >= MPT_REQUEST_AREA) { 1963157662Smjacob request_t *nrq; 1964157117Smjacob 1965157662Smjacob nrq = mpt_get_request(mpt, FALSE); 1966157662Smjacob 1967157117Smjacob if (nrq == NULL) { 1968157117Smjacob error = ENOMEM; 1969157117Smjacob goto bad; 1970157117Smjacob } 1971157117Smjacob 1972157117Smjacob /* 1973157117Smjacob * Append the new request area on the tail of our list. 1974157117Smjacob */ 1975157117Smjacob if ((trq = req->chain) == NULL) { 1976157117Smjacob req->chain = nrq; 1977157117Smjacob } else { 1978157117Smjacob while (trq->chain != NULL) { 1979157117Smjacob trq = trq->chain; 1980157117Smjacob } 1981157117Smjacob trq->chain = nrq; 1982157117Smjacob } 1983157117Smjacob trq = nrq; 1984157117Smjacob mpt_off = trq->req_vbuf; 1985157117Smjacob if (mpt->verbose >= MPT_PRT_DEBUG) { 1986157117Smjacob memset(mpt_off, 0xff, MPT_REQUEST_AREA); 1987157117Smjacob } 1988157117Smjacob nxt_off = 0; 1989157117Smjacob } 1990157117Smjacob } 1991157117Smjacobout: 1992157117Smjacob 1993157117Smjacob /* 1994157117Smjacob * Last time we need to check if this CCB needs to be aborted. 1995157117Smjacob */ 1996157117Smjacob if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { 1997157117Smjacob if (hdrp->Function == MPI_FUNCTION_TARGET_ASSIST) { 1998157117Smjacob request_t *cmd_req = 1999157117Smjacob MPT_TAG_2_REQ(mpt, ccb->csio.tag_id); 2000157117Smjacob MPT_TGT_STATE(mpt, cmd_req)->state = TGT_STATE_IN_CAM; 2001157117Smjacob MPT_TGT_STATE(mpt, cmd_req)->ccb = NULL; 2002157117Smjacob MPT_TGT_STATE(mpt, cmd_req)->req = NULL; 2003157117Smjacob } 2004159178Smjacob mpt_prt(mpt, 2005159178Smjacob "mpt_execute_req: I/O cancelled (status 0x%x)\n", 2006157117Smjacob ccb->ccb_h.status & CAM_STATUS_MASK); 2007251874Sscottl if (nseg) { 2008157117Smjacob bus_dmamap_unload(mpt->buffer_dmat, req->dmap); 2009157117Smjacob } 2010157117Smjacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 2011231629Smarius KASSERT(ccb->ccb_h.status, ("zero ccb sts at %d", __LINE__)); 2012157117Smjacob xpt_done(ccb); 2013157117Smjacob mpt_free_request(mpt, req); 2014157117Smjacob return; 2015157117Smjacob } 2016157117Smjacob 2017147883Sscottl ccb->ccb_h.status |= CAM_SIM_QUEUED; 2018147883Sscottl if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { 2019169293Smjacob mpt_req_timeout(req, (ccb->ccb_h.timeout * hz) / 1000, 2020169293Smjacob mpt_timeout, ccb); 2021147883Sscottl } 2022158982Smjacob if (mpt->verbose > MPT_PRT_DEBUG) { 2023155521Smjacob int nc = 0; 2024157117Smjacob mpt_print_request(req->req_vbuf); 2025155521Smjacob for (trq = req->chain; trq; trq = trq->chain) { 2026155521Smjacob printf(" Additional Chain Area %d\n", nc++); 2027155521Smjacob mpt_dump_sgl(trq->req_vbuf, 0); 2028155521Smjacob } 2029155521Smjacob } 2030159178Smjacob 2031157117Smjacob if (hdrp->Function == MPI_FUNCTION_TARGET_ASSIST) { 2032157117Smjacob request_t *cmd_req = MPT_TAG_2_REQ(mpt, ccb->csio.tag_id); 2033157117Smjacob mpt_tgt_state_t *tgt = MPT_TGT_STATE(mpt, cmd_req); 2034157117Smjacob#ifdef WE_TRUST_AUTO_GOOD_STATUS 2035157117Smjacob if ((ccb->ccb_h.flags & CAM_SEND_STATUS) && 2036157117Smjacob csio->scsi_status == SCSI_STATUS_OK && tgt->resid == 0) { 2037157117Smjacob tgt->state = TGT_STATE_MOVING_DATA_AND_STATUS; 2038157117Smjacob } else { 2039157117Smjacob tgt->state = TGT_STATE_MOVING_DATA; 2040157117Smjacob } 2041157117Smjacob#else 2042157117Smjacob tgt->state = TGT_STATE_MOVING_DATA; 2043157117Smjacob#endif 2044157117Smjacob } 2045147883Sscottl mpt_send_cmd(mpt, req); 2046147883Sscottl} 2047147883Sscottl 2048147883Sscottlstatic void 2049147883Sscottlmpt_start(struct cam_sim *sim, union ccb *ccb) 2050147883Sscottl{ 2051147883Sscottl request_t *req; 2052147883Sscottl struct mpt_softc *mpt; 2053147883Sscottl MSG_SCSI_IO_REQUEST *mpt_req; 2054147883Sscottl struct ccb_scsiio *csio = &ccb->csio; 2055147883Sscottl struct ccb_hdr *ccbh = &ccb->ccb_h; 2056157117Smjacob bus_dmamap_callback_t *cb; 2057158982Smjacob target_id_t tgt; 2058147883Sscottl int raid_passthru; 2059251874Sscottl int error; 2060147883Sscottl 2061147883Sscottl /* Get the pointer for the physical addapter */ 2062147883Sscottl mpt = ccb->ccb_h.ccb_mpt_ptr; 2063147883Sscottl raid_passthru = (sim == mpt->phydisk_sim); 2064147883Sscottl 2065157354Smjacob if ((req = mpt_get_request(mpt, FALSE)) == NULL) { 2066147883Sscottl if (mpt->outofbeer == 0) { 2067147883Sscottl mpt->outofbeer = 1; 2068147883Sscottl xpt_freeze_simq(mpt->sim, 1); 2069147883Sscottl mpt_lprt(mpt, MPT_PRT_DEBUG, "FREEZEQ\n"); 2070147883Sscottl } 2071157117Smjacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 2072157117Smjacob mpt_set_ccb_status(ccb, CAM_REQUEUE_REQ); 2073147883Sscottl xpt_done(ccb); 2074147883Sscottl return; 2075147883Sscottl } 2076157662Smjacob#ifdef INVARIANTS 2077157662Smjacob mpt_req_not_spcl(mpt, req, "mpt_start", __LINE__); 2078157662Smjacob#endif 2079147883Sscottl 2080157117Smjacob if (sizeof (bus_addr_t) > 4) { 2081157117Smjacob cb = mpt_execute_req_a64; 2082157117Smjacob } else { 2083157117Smjacob cb = mpt_execute_req; 2084157117Smjacob } 2085157117Smjacob 2086147883Sscottl /* 2087147883Sscottl * Link the ccb and the request structure so we can find 2088147883Sscottl * the other knowing either the request or the ccb 2089147883Sscottl */ 2090147883Sscottl req->ccb = ccb; 2091147883Sscottl ccb->ccb_h.ccb_req_ptr = req; 2092147883Sscottl 2093147883Sscottl /* Now we build the command for the IOC */ 2094147883Sscottl mpt_req = req->req_vbuf; 2095157354Smjacob memset(mpt_req, 0, sizeof (MSG_SCSI_IO_REQUEST)); 2096147883Sscottl 2097147883Sscottl mpt_req->Function = MPI_FUNCTION_SCSI_IO_REQUEST; 2098157117Smjacob if (raid_passthru) { 2099147883Sscottl mpt_req->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH; 2100158982Smjacob if (mpt_map_physdisk(mpt, ccb, &tgt) != 0) { 2101158982Smjacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 2102158982Smjacob mpt_set_ccb_status(ccb, CAM_DEV_NOT_THERE); 2103158982Smjacob xpt_done(ccb); 2104158982Smjacob return; 2105158982Smjacob } 2106158982Smjacob mpt_req->Bus = 0; /* we never set bus here */ 2107158982Smjacob } else { 2108158982Smjacob tgt = ccb->ccb_h.target_id; 2109158982Smjacob mpt_req->Bus = 0; /* XXX */ 2110158982Smjacob 2111157117Smjacob } 2112147883Sscottl mpt_req->SenseBufferLength = 2113147883Sscottl (csio->sense_len < MPT_SENSE_SIZE) ? 2114147883Sscottl csio->sense_len : MPT_SENSE_SIZE; 2115147883Sscottl 2116147883Sscottl /* 2117147883Sscottl * We use the message context to find the request structure when we 2118147883Sscottl * Get the command completion interrupt from the IOC. 2119147883Sscottl */ 2120147883Sscottl mpt_req->MsgContext = htole32(req->index | scsi_io_handler_id); 2121147883Sscottl 2122147883Sscottl /* Which physical device to do the I/O on */ 2123158982Smjacob mpt_req->TargetID = tgt; 2124147883Sscottl 2125157117Smjacob /* We assume a single level LUN type */ 2126195274Sdelphij if (ccb->ccb_h.target_lun >= MPT_MAX_LUNS) { 2127157117Smjacob mpt_req->LUN[0] = 0x40 | ((ccb->ccb_h.target_lun >> 8) & 0x3f); 2128157117Smjacob mpt_req->LUN[1] = ccb->ccb_h.target_lun & 0xff; 2129157117Smjacob } else { 2130157117Smjacob mpt_req->LUN[1] = ccb->ccb_h.target_lun; 2131157117Smjacob } 2132157117Smjacob 2133147883Sscottl /* Set the direction of the transfer */ 2134157354Smjacob if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 2135147883Sscottl mpt_req->Control = MPI_SCSIIO_CONTROL_READ; 2136157354Smjacob } else if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { 2137147883Sscottl mpt_req->Control = MPI_SCSIIO_CONTROL_WRITE; 2138157354Smjacob } else { 2139147883Sscottl mpt_req->Control = MPI_SCSIIO_CONTROL_NODATATRANSFER; 2140157354Smjacob } 2141147883Sscottl 2142147883Sscottl if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) { 2143147883Sscottl switch(ccb->csio.tag_action) { 2144147883Sscottl case MSG_HEAD_OF_Q_TAG: 2145147883Sscottl mpt_req->Control |= MPI_SCSIIO_CONTROL_HEADOFQ; 2146147883Sscottl break; 2147147883Sscottl case MSG_ACA_TASK: 2148147883Sscottl mpt_req->Control |= MPI_SCSIIO_CONTROL_ACAQ; 2149147883Sscottl break; 2150147883Sscottl case MSG_ORDERED_Q_TAG: 2151147883Sscottl mpt_req->Control |= MPI_SCSIIO_CONTROL_ORDEREDQ; 2152147883Sscottl break; 2153147883Sscottl case MSG_SIMPLE_Q_TAG: 2154147883Sscottl default: 2155147883Sscottl mpt_req->Control |= MPI_SCSIIO_CONTROL_SIMPLEQ; 2156147883Sscottl break; 2157147883Sscottl } 2158147883Sscottl } else { 2159157354Smjacob if (mpt->is_fc || mpt->is_sas) { 2160147883Sscottl mpt_req->Control |= MPI_SCSIIO_CONTROL_SIMPLEQ; 2161157354Smjacob } else { 2162147883Sscottl /* XXX No such thing for a target doing packetized. */ 2163147883Sscottl mpt_req->Control |= MPI_SCSIIO_CONTROL_UNTAGGED; 2164157354Smjacob } 2165147883Sscottl } 2166147883Sscottl 2167159178Smjacob if (mpt->is_spi) { 2168147883Sscottl if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) { 2169147883Sscottl mpt_req->Control |= MPI_SCSIIO_CONTROL_NO_DISCONNECT; 2170147883Sscottl } 2171147883Sscottl } 2172186878Smarius mpt_req->Control = htole32(mpt_req->Control); 2173147883Sscottl 2174147883Sscottl /* Copy the scsi command block into place */ 2175157354Smjacob if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { 2176147883Sscottl bcopy(csio->cdb_io.cdb_ptr, mpt_req->CDB, csio->cdb_len); 2177157354Smjacob } else { 2178147883Sscottl bcopy(csio->cdb_io.cdb_bytes, mpt_req->CDB, csio->cdb_len); 2179157354Smjacob } 2180147883Sscottl 2181147883Sscottl mpt_req->CDBLength = csio->cdb_len; 2182164315Sjb mpt_req->DataLength = htole32(csio->dxfer_len); 2183164315Sjb mpt_req->SenseBufferLowAddr = htole32(req->sense_pbuf); 2184147883Sscottl 2185147883Sscottl /* 2186158982Smjacob * Do a *short* print here if we're set to MPT_PRT_DEBUG 2187158982Smjacob */ 2188158982Smjacob if (mpt->verbose == MPT_PRT_DEBUG) { 2189164837Smjacob U32 df; 2190158982Smjacob mpt_prt(mpt, "mpt_start: %s op 0x%x ", 2191158982Smjacob (mpt_req->Function == MPI_FUNCTION_SCSI_IO_REQUEST)? 2192158982Smjacob "SCSI_IO_REQUEST" : "SCSI_IO_PASSTHRU", mpt_req->CDB[0]); 2193164837Smjacob df = mpt_req->Control & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK; 2194164837Smjacob if (df != MPI_SCSIIO_CONTROL_NODATATRANSFER) { 2195158982Smjacob mpt_prtc(mpt, "(%s %u byte%s ", 2196164837Smjacob (df == MPI_SCSIIO_CONTROL_READ)? 2197158982Smjacob "read" : "write", csio->dxfer_len, 2198158982Smjacob (csio->dxfer_len == 1)? ")" : "s)"); 2199158982Smjacob } 2200158982Smjacob mpt_prtc(mpt, "tgt %u lun %u req %p:%u\n", tgt, 2201158982Smjacob ccb->ccb_h.target_lun, req, req->serno); 2202158982Smjacob } 2203158982Smjacob 2204251874Sscottl error = bus_dmamap_load_ccb(mpt->buffer_dmat, req->dmap, ccb, cb, 2205251874Sscottl req, 0); 2206251874Sscottl if (error == EINPROGRESS) { 2207251874Sscottl /* 2208251874Sscottl * So as to maintain ordering, freeze the controller queue 2209251874Sscottl * until our mapping is returned. 2210251874Sscottl */ 2211251874Sscottl xpt_freeze_simq(mpt->sim, 1); 2212251874Sscottl ccbh->status |= CAM_RELEASE_SIMQ; 2213147883Sscottl } 2214147883Sscottl} 2215147883Sscottl 2216147883Sscottlstatic int 2217159471Sjkimmpt_bus_reset(struct mpt_softc *mpt, target_id_t tgt, lun_id_t lun, 2218159471Sjkim int sleep_ok) 2219147883Sscottl{ 2220147883Sscottl int error; 2221157662Smjacob uint16_t status; 2222157662Smjacob uint8_t response; 2223147883Sscottl 2224159471Sjkim error = mpt_scsi_send_tmf(mpt, 2225159471Sjkim (tgt != CAM_TARGET_WILDCARD || lun != CAM_LUN_WILDCARD) ? 2226159471Sjkim MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET : 2227159471Sjkim MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, 2228147883Sscottl mpt->is_fc ? MPI_SCSITASKMGMT_MSGFLAGS_LIP_RESET_OPTION : 0, 2229159471Sjkim 0, /* XXX How do I get the channel ID? */ 2230159471Sjkim tgt != CAM_TARGET_WILDCARD ? tgt : 0, 2231159471Sjkim lun != CAM_LUN_WILDCARD ? lun : 0, 2232159471Sjkim 0, sleep_ok); 2233147883Sscottl 2234147883Sscottl if (error != 0) { 2235147883Sscottl /* 2236147883Sscottl * mpt_scsi_send_tmf hard resets on failure, so no 2237147883Sscottl * need to do so here. 2238147883Sscottl */ 2239147883Sscottl mpt_prt(mpt, 2240147883Sscottl "mpt_bus_reset: mpt_scsi_send_tmf returned %d\n", error); 2241147883Sscottl return (EIO); 2242147883Sscottl } 2243147883Sscottl 2244147883Sscottl /* Wait for bus reset to be processed by the IOC. */ 2245147883Sscottl error = mpt_wait_req(mpt, mpt->tmf_req, REQ_STATE_DONE, 2246157354Smjacob REQ_STATE_DONE, sleep_ok, 5000); 2247147883Sscottl 2248186878Smarius status = le16toh(mpt->tmf_req->IOCStatus); 2249157662Smjacob response = mpt->tmf_req->ResponseCode; 2250147883Sscottl mpt->tmf_req->state = REQ_STATE_FREE; 2251157662Smjacob 2252147883Sscottl if (error) { 2253157662Smjacob mpt_prt(mpt, "mpt_bus_reset: Reset timed-out. " 2254157662Smjacob "Resetting controller.\n"); 2255157662Smjacob mpt_reset(mpt, TRUE); 2256147883Sscottl return (ETIMEDOUT); 2257157662Smjacob } 2258157662Smjacob 2259157662Smjacob if ((status & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 2260157662Smjacob mpt_prt(mpt, "mpt_bus_reset: TMF IOC Status 0x%x. " 2261157662Smjacob "Resetting controller.\n", status); 2262157662Smjacob mpt_reset(mpt, TRUE); 2263147883Sscottl return (EIO); 2264147883Sscottl } 2265157662Smjacob 2266157662Smjacob if (response != MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED && 2267157662Smjacob response != MPI_SCSITASKMGMT_RSP_TM_COMPLETE) { 2268157662Smjacob mpt_prt(mpt, "mpt_bus_reset: TMF Response 0x%x. " 2269157662Smjacob "Resetting controller.\n", response); 2270157662Smjacob mpt_reset(mpt, TRUE); 2271157662Smjacob return (EIO); 2272157662Smjacob } 2273147883Sscottl return (0); 2274147883Sscottl} 2275147883Sscottl 2276147883Sscottlstatic int 2277157117Smjacobmpt_fc_reset_link(struct mpt_softc *mpt, int dowait) 2278157117Smjacob{ 2279157117Smjacob int r = 0; 2280157117Smjacob request_t *req; 2281157117Smjacob PTR_MSG_FC_PRIMITIVE_SEND_REQUEST fc; 2282157117Smjacob 2283157117Smjacob req = mpt_get_request(mpt, FALSE); 2284157117Smjacob if (req == NULL) { 2285157117Smjacob return (ENOMEM); 2286157117Smjacob } 2287157117Smjacob fc = req->req_vbuf; 2288157117Smjacob memset(fc, 0, sizeof(*fc)); 2289157117Smjacob fc->SendFlags = MPI_FC_PRIM_SEND_FLAGS_RESET_LINK; 2290157117Smjacob fc->Function = MPI_FUNCTION_FC_PRIMITIVE_SEND; 2291157117Smjacob fc->MsgContext = htole32(req->index | fc_els_handler_id); 2292157117Smjacob mpt_send_cmd(mpt, req); 2293157117Smjacob if (dowait) { 2294157117Smjacob r = mpt_wait_req(mpt, req, REQ_STATE_DONE, 2295157117Smjacob REQ_STATE_DONE, FALSE, 60 * 1000); 2296157354Smjacob if (r == 0) { 2297157354Smjacob mpt_free_request(mpt, req); 2298157354Smjacob } 2299157117Smjacob } 2300157117Smjacob return (r); 2301157117Smjacob} 2302157117Smjacob 2303157117Smjacobstatic int 2304147883Sscottlmpt_cam_event(struct mpt_softc *mpt, request_t *req, 2305147883Sscottl MSG_EVENT_NOTIFY_REPLY *msg) 2306147883Sscottl{ 2307164315Sjb uint32_t data0, data1; 2308162133Smjacob 2309164315Sjb data0 = le32toh(msg->Data[0]); 2310164315Sjb data1 = le32toh(msg->Data[1]); 2311147883Sscottl switch(msg->Event & 0xFF) { 2312147883Sscottl case MPI_EVENT_UNIT_ATTENTION: 2313162133Smjacob mpt_prt(mpt, "UNIT ATTENTION: Bus: 0x%02x TargetID: 0x%02x\n", 2314164315Sjb (data0 >> 8) & 0xff, data0 & 0xff); 2315147883Sscottl break; 2316147883Sscottl 2317147883Sscottl case MPI_EVENT_IOC_BUS_RESET: 2318147883Sscottl /* We generated a bus reset */ 2319162133Smjacob mpt_prt(mpt, "IOC Generated Bus Reset Port: %d\n", 2320164315Sjb (data0 >> 8) & 0xff); 2321147883Sscottl xpt_async(AC_BUS_RESET, mpt->path, NULL); 2322147883Sscottl break; 2323147883Sscottl 2324147883Sscottl case MPI_EVENT_EXT_BUS_RESET: 2325147883Sscottl /* Someone else generated a bus reset */ 2326157117Smjacob mpt_prt(mpt, "External Bus Reset Detected\n"); 2327147883Sscottl /* 2328147883Sscottl * These replies don't return EventData like the MPI 2329147883Sscottl * spec says they do 2330147883Sscottl */ 2331147883Sscottl xpt_async(AC_BUS_RESET, mpt->path, NULL); 2332147883Sscottl break; 2333147883Sscottl 2334147883Sscottl case MPI_EVENT_RESCAN: 2335166897Smjacob { 2336166897Smjacob union ccb *ccb; 2337166897Smjacob uint32_t pathid; 2338147883Sscottl /* 2339157662Smjacob * In general this means a device has been added to the loop. 2340147883Sscottl */ 2341164315Sjb mpt_prt(mpt, "Rescan Port: %d\n", (data0 >> 8) & 0xff); 2342166897Smjacob if (mpt->ready == 0) { 2343166897Smjacob break; 2344166897Smjacob } 2345166897Smjacob if (mpt->phydisk_sim) { 2346168831Sscottl pathid = cam_sim_path(mpt->phydisk_sim); 2347166897Smjacob } else { 2348168831Sscottl pathid = cam_sim_path(mpt->sim); 2349166897Smjacob } 2350166897Smjacob /* 2351166897Smjacob * Allocate a CCB, create a wildcard path for this bus, 2352166897Smjacob * and schedule a rescan. 2353166897Smjacob */ 2354168831Sscottl ccb = xpt_alloc_ccb_nowait(); 2355166897Smjacob if (ccb == NULL) { 2356166897Smjacob mpt_prt(mpt, "unable to alloc CCB for rescan\n"); 2357166897Smjacob break; 2358166897Smjacob } 2359166897Smjacob 2360253037Smav if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid, 2361166897Smjacob CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 2362166897Smjacob mpt_prt(mpt, "unable to create path for rescan\n"); 2363166897Smjacob xpt_free_ccb(ccb); 2364166897Smjacob break; 2365166897Smjacob } 2366166897Smjacob xpt_rescan(ccb); 2367147883Sscottl break; 2368166897Smjacob } 2369264950Smarius 2370147883Sscottl case MPI_EVENT_LINK_STATUS_CHANGE: 2371147883Sscottl mpt_prt(mpt, "Port %d: LinkState: %s\n", 2372164315Sjb (data1 >> 8) & 0xff, 2373164315Sjb ((data0 & 0xff) == 0)? "Failed" : "Active"); 2374147883Sscottl break; 2375147883Sscottl 2376147883Sscottl case MPI_EVENT_LOOP_STATE_CHANGE: 2377164315Sjb switch ((data0 >> 16) & 0xff) { 2378147883Sscottl case 0x01: 2379147883Sscottl mpt_prt(mpt, 2380147883Sscottl "Port 0x%x: FC LinkEvent: LIP(%02x,%02x) " 2381147883Sscottl "(Loop Initialization)\n", 2382164315Sjb (data1 >> 8) & 0xff, 2383164315Sjb (data0 >> 8) & 0xff, 2384164315Sjb (data0 ) & 0xff); 2385164315Sjb switch ((data0 >> 8) & 0xff) { 2386147883Sscottl case 0xF7: 2387164315Sjb if ((data0 & 0xff) == 0xF7) { 2388157117Smjacob mpt_prt(mpt, "Device needs AL_PA\n"); 2389147883Sscottl } else { 2390157117Smjacob mpt_prt(mpt, "Device %02x doesn't like " 2391147883Sscottl "FC performance\n", 2392164315Sjb data0 & 0xFF); 2393147883Sscottl } 2394147883Sscottl break; 2395147883Sscottl case 0xF8: 2396164315Sjb if ((data0 & 0xff) == 0xF7) { 2397157117Smjacob mpt_prt(mpt, "Device had loop failure " 2398157117Smjacob "at its receiver prior to acquiring" 2399157117Smjacob " AL_PA\n"); 2400147883Sscottl } else { 2401157117Smjacob mpt_prt(mpt, "Device %02x detected loop" 2402157117Smjacob " failure at its receiver\n", 2403164315Sjb data0 & 0xFF); 2404147883Sscottl } 2405147883Sscottl break; 2406147883Sscottl default: 2407157117Smjacob mpt_prt(mpt, "Device %02x requests that device " 2408156041Smjacob "%02x reset itself\n", 2409164315Sjb data0 & 0xFF, 2410164315Sjb (data0 >> 8) & 0xFF); 2411147883Sscottl break; 2412147883Sscottl } 2413147883Sscottl break; 2414147883Sscottl case 0x02: 2415147883Sscottl mpt_prt(mpt, "Port 0x%x: FC LinkEvent: " 2416147883Sscottl "LPE(%02x,%02x) (Loop Port Enable)\n", 2417164315Sjb (data1 >> 8) & 0xff, /* Port */ 2418164315Sjb (data0 >> 8) & 0xff, /* Character 3 */ 2419164315Sjb (data0 ) & 0xff /* Character 4 */); 2420147883Sscottl break; 2421147883Sscottl case 0x03: 2422147883Sscottl mpt_prt(mpt, "Port 0x%x: FC LinkEvent: " 2423147883Sscottl "LPB(%02x,%02x) (Loop Port Bypass)\n", 2424164315Sjb (data1 >> 8) & 0xff, /* Port */ 2425164315Sjb (data0 >> 8) & 0xff, /* Character 3 */ 2426164315Sjb (data0 ) & 0xff /* Character 4 */); 2427147883Sscottl break; 2428147883Sscottl default: 2429147883Sscottl mpt_prt(mpt, "Port 0x%x: FC LinkEvent: Unknown " 2430147883Sscottl "FC event (%02x %02x %02x)\n", 2431164315Sjb (data1 >> 8) & 0xff, /* Port */ 2432164315Sjb (data0 >> 16) & 0xff, /* Event */ 2433164315Sjb (data0 >> 8) & 0xff, /* Character 3 */ 2434164315Sjb (data0 ) & 0xff /* Character 4 */); 2435147883Sscottl } 2436147883Sscottl break; 2437147883Sscottl 2438147883Sscottl case MPI_EVENT_LOGOUT: 2439147883Sscottl mpt_prt(mpt, "FC Logout Port: %d N_PortID: %02x\n", 2440164315Sjb (data1 >> 8) & 0xff, data0); 2441147883Sscottl break; 2442162133Smjacob case MPI_EVENT_QUEUE_FULL: 2443162133Smjacob { 2444162534Smjacob struct cam_sim *sim; 2445162534Smjacob struct cam_path *tmppath; 2446162534Smjacob struct ccb_relsim crs; 2447186878Smarius PTR_EVENT_DATA_QUEUE_FULL pqf; 2448162534Smjacob lun_id_t lun_id; 2449162534Smjacob 2450186878Smarius pqf = (PTR_EVENT_DATA_QUEUE_FULL)msg->Data; 2451186878Smarius pqf->CurrentDepth = le16toh(pqf->CurrentDepth); 2452162534Smjacob mpt_prt(mpt, "QUEUE FULL EVENT: Bus 0x%02x Target 0x%02x Depth " 2453162534Smjacob "%d\n", pqf->Bus, pqf->TargetID, pqf->CurrentDepth); 2454224494Smarius if (mpt->phydisk_sim && mpt_is_raid_member(mpt, 2455224494Smarius pqf->TargetID) != 0) { 2456162534Smjacob sim = mpt->phydisk_sim; 2457162534Smjacob } else { 2458162534Smjacob sim = mpt->sim; 2459162534Smjacob } 2460162534Smjacob for (lun_id = 0; lun_id < MPT_MAX_LUNS; lun_id++) { 2461162534Smjacob if (xpt_create_path(&tmppath, NULL, cam_sim_path(sim), 2462162534Smjacob pqf->TargetID, lun_id) != CAM_REQ_CMP) { 2463162534Smjacob mpt_prt(mpt, "unable to create a path to send " 2464162534Smjacob "XPT_REL_SIMQ"); 2465162534Smjacob break; 2466162534Smjacob } 2467162534Smjacob xpt_setup_ccb(&crs.ccb_h, tmppath, 5); 2468162534Smjacob crs.ccb_h.func_code = XPT_REL_SIMQ; 2469203484Smav crs.ccb_h.flags = CAM_DEV_QFREEZE; 2470162534Smjacob crs.release_flags = RELSIM_ADJUST_OPENINGS; 2471162534Smjacob crs.openings = pqf->CurrentDepth - 1; 2472162534Smjacob xpt_action((union ccb *)&crs); 2473162534Smjacob if (crs.ccb_h.status != CAM_REQ_CMP) { 2474162534Smjacob mpt_prt(mpt, "XPT_REL_SIMQ failed\n"); 2475162534Smjacob } 2476162534Smjacob xpt_free_path(tmppath); 2477162534Smjacob } 2478162133Smjacob break; 2479162133Smjacob } 2480207543Smjacob case MPI_EVENT_IR_RESYNC_UPDATE: 2481207543Smjacob mpt_prt(mpt, "IR resync update %d completed\n", 2482207543Smjacob (data0 >> 16) & 0xff); 2483207543Smjacob break; 2484224494Smarius case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: 2485224494Smarius { 2486224494Smarius union ccb *ccb; 2487224494Smarius struct cam_sim *sim; 2488224494Smarius struct cam_path *tmppath; 2489224494Smarius PTR_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE psdsc; 2490224494Smarius 2491224494Smarius psdsc = (PTR_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE)msg->Data; 2492224494Smarius if (mpt->phydisk_sim && mpt_is_raid_member(mpt, 2493224494Smarius psdsc->TargetID) != 0) 2494224494Smarius sim = mpt->phydisk_sim; 2495224494Smarius else 2496224494Smarius sim = mpt->sim; 2497224494Smarius switch(psdsc->ReasonCode) { 2498224494Smarius case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: 2499224494Smarius ccb = xpt_alloc_ccb_nowait(); 2500224494Smarius if (ccb == NULL) { 2501224494Smarius mpt_prt(mpt, 2502224494Smarius "unable to alloc CCB for rescan\n"); 2503224494Smarius break; 2504224494Smarius } 2505253037Smav if (xpt_create_path(&ccb->ccb_h.path, NULL, 2506224494Smarius cam_sim_path(sim), psdsc->TargetID, 2507224494Smarius CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 2508224494Smarius mpt_prt(mpt, 2509224494Smarius "unable to create path for rescan\n"); 2510224494Smarius xpt_free_ccb(ccb); 2511224494Smarius break; 2512224494Smarius } 2513224494Smarius xpt_rescan(ccb); 2514224494Smarius break; 2515224494Smarius case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: 2516224494Smarius if (xpt_create_path(&tmppath, NULL, cam_sim_path(sim), 2517224494Smarius psdsc->TargetID, CAM_LUN_WILDCARD) != 2518224494Smarius CAM_REQ_CMP) { 2519224494Smarius mpt_prt(mpt, 2520224494Smarius "unable to create path for async event"); 2521224494Smarius break; 2522224494Smarius } 2523224494Smarius xpt_async(AC_LOST_DEVICE, tmppath, NULL); 2524224494Smarius xpt_free_path(tmppath); 2525224494Smarius break; 2526224761Smarius case MPI_EVENT_SAS_DEV_STAT_RC_CMPL_INTERNAL_DEV_RESET: 2527224761Smarius case MPI_EVENT_SAS_DEV_STAT_RC_CMPL_TASK_ABORT_INTERNAL: 2528224494Smarius case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: 2529224494Smarius break; 2530224494Smarius default: 2531224494Smarius mpt_lprt(mpt, MPT_PRT_WARN, 2532224494Smarius "SAS device status change: Bus: 0x%02x TargetID: " 2533224761Smarius "0x%02x ReasonCode: 0x%02x\n", psdsc->Bus, 2534224761Smarius psdsc->TargetID, psdsc->ReasonCode); 2535224494Smarius break; 2536224494Smarius } 2537224494Smarius break; 2538224494Smarius } 2539224761Smarius case MPI_EVENT_SAS_DISCOVERY_ERROR: 2540224761Smarius { 2541224761Smarius PTR_EVENT_DATA_DISCOVERY_ERROR pde; 2542224761Smarius 2543224761Smarius pde = (PTR_EVENT_DATA_DISCOVERY_ERROR)msg->Data; 2544224761Smarius pde->DiscoveryStatus = le32toh(pde->DiscoveryStatus); 2545224761Smarius mpt_lprt(mpt, MPT_PRT_WARN, 2546224761Smarius "SAS discovery error: Port: 0x%02x Status: 0x%08x\n", 2547224761Smarius pde->Port, pde->DiscoveryStatus); 2548224761Smarius break; 2549224761Smarius } 2550164837Smjacob case MPI_EVENT_EVENT_CHANGE: 2551164837Smjacob case MPI_EVENT_INTEGRATED_RAID: 2552224494Smarius case MPI_EVENT_IR2: 2553224494Smarius case MPI_EVENT_LOG_ENTRY_ADDED: 2554224494Smarius case MPI_EVENT_SAS_DISCOVERY: 2555224494Smarius case MPI_EVENT_SAS_PHY_LINK_STATUS: 2556162133Smjacob case MPI_EVENT_SAS_SES: 2557162133Smjacob break; 2558147883Sscottl default: 2559157117Smjacob mpt_lprt(mpt, MPT_PRT_WARN, "mpt_cam_event: 0x%x\n", 2560157117Smjacob msg->Event & 0xFF); 2561157354Smjacob return (0); 2562147883Sscottl } 2563157354Smjacob return (1); 2564147883Sscottl} 2565147883Sscottl 2566147883Sscottl/* 2567147883Sscottl * Reply path for all SCSI I/O requests, called from our 2568147883Sscottl * interrupt handler by extracting our handler index from 2569147883Sscottl * the MsgContext field of the reply from the IOC. 2570147883Sscottl * 2571147883Sscottl * This routine is optimized for the common case of a 2572147883Sscottl * completion without error. All exception handling is 2573147883Sscottl * offloaded to non-inlined helper routines to minimize 2574147883Sscottl * cache footprint. 2575147883Sscottl */ 2576147883Sscottlstatic int 2577147883Sscottlmpt_scsi_reply_handler(struct mpt_softc *mpt, request_t *req, 2578157117Smjacob uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) 2579147883Sscottl{ 2580147883Sscottl MSG_SCSI_IO_REQUEST *scsi_req; 2581147883Sscottl union ccb *ccb; 2582157354Smjacob 2583157354Smjacob if (req->state == REQ_STATE_FREE) { 2584157354Smjacob mpt_prt(mpt, "mpt_scsi_reply_handler: req already free\n"); 2585157354Smjacob return (TRUE); 2586157354Smjacob } 2587157354Smjacob 2588147883Sscottl scsi_req = (MSG_SCSI_IO_REQUEST *)req->req_vbuf; 2589147883Sscottl ccb = req->ccb; 2590147883Sscottl if (ccb == NULL) { 2591159312Smjacob mpt_prt(mpt, "mpt_scsi_reply_handler: req %p:%u with no ccb\n", 2592159312Smjacob req, req->serno); 2593157354Smjacob return (TRUE); 2594147883Sscottl } 2595159312Smjacob 2596169293Smjacob mpt_req_untimeout(req, mpt_timeout, ccb); 2597159178Smjacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 2598147883Sscottl 2599147883Sscottl if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 2600147883Sscottl bus_dmasync_op_t op; 2601147883Sscottl 2602147883Sscottl if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 2603147883Sscottl op = BUS_DMASYNC_POSTREAD; 2604147883Sscottl else 2605147883Sscottl op = BUS_DMASYNC_POSTWRITE; 2606147883Sscottl bus_dmamap_sync(mpt->buffer_dmat, req->dmap, op); 2607147883Sscottl bus_dmamap_unload(mpt->buffer_dmat, req->dmap); 2608147883Sscottl } 2609147883Sscottl 2610147883Sscottl if (reply_frame == NULL) { 2611147883Sscottl /* 2612157117Smjacob * Context only reply, completion without error status. 2613147883Sscottl */ 2614147883Sscottl ccb->csio.resid = 0; 2615147883Sscottl mpt_set_ccb_status(ccb, CAM_REQ_CMP); 2616147883Sscottl ccb->csio.scsi_status = SCSI_STATUS_OK; 2617147883Sscottl } else { 2618147883Sscottl mpt_scsi_reply_frame_handler(mpt, req, reply_frame); 2619147883Sscottl } 2620147883Sscottl 2621147883Sscottl if (mpt->outofbeer) { 2622147883Sscottl ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 2623147883Sscottl mpt->outofbeer = 0; 2624159178Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, "THAWQ\n"); 2625147883Sscottl } 2626159178Smjacob if (scsi_req->CDB[0] == INQUIRY && (scsi_req->CDB[1] & SI_EVPD) == 0) { 2627159178Smjacob struct scsi_inquiry_data *iq = 2628159178Smjacob (struct scsi_inquiry_data *)ccb->csio.data_ptr; 2629159178Smjacob if (scsi_req->Function == 2630159178Smjacob MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { 2631159178Smjacob /* 2632159178Smjacob * Fake out the device type so that only the 2633159178Smjacob * pass-thru device will attach. 2634159178Smjacob */ 2635159178Smjacob iq->device &= ~0x1F; 2636159178Smjacob iq->device |= T_NODEVICE; 2637159178Smjacob } 2638147883Sscottl } 2639158982Smjacob if (mpt->verbose == MPT_PRT_DEBUG) { 2640158982Smjacob mpt_prt(mpt, "mpt_scsi_reply_handler: %p:%u complete\n", 2641158982Smjacob req, req->serno); 2642158982Smjacob } 2643231629Smarius KASSERT(ccb->ccb_h.status, ("zero ccb sts at %d", __LINE__)); 2644147883Sscottl xpt_done(ccb); 2645157117Smjacob if ((req->state & REQ_STATE_TIMEDOUT) == 0) { 2646147883Sscottl TAILQ_REMOVE(&mpt->request_pending_list, req, links); 2647157117Smjacob } else { 2648157662Smjacob mpt_prt(mpt, "completing timedout/aborted req %p:%u\n", 2649157662Smjacob req, req->serno); 2650147883Sscottl TAILQ_REMOVE(&mpt->request_timeout_list, req, links); 2651157117Smjacob } 2652159178Smjacob KASSERT((req->state & REQ_STATE_NEED_WAKEUP) == 0, 2653159178Smjacob ("CCB req needed wakeup")); 2654157662Smjacob#ifdef INVARIANTS 2655159178Smjacob mpt_req_not_spcl(mpt, req, "mpt_scsi_reply_handler", __LINE__); 2656157662Smjacob#endif 2657159178Smjacob mpt_free_request(mpt, req); 2658157662Smjacob return (TRUE); 2659147883Sscottl} 2660147883Sscottl 2661147883Sscottlstatic int 2662147883Sscottlmpt_scsi_tmf_reply_handler(struct mpt_softc *mpt, request_t *req, 2663157117Smjacob uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) 2664147883Sscottl{ 2665147883Sscottl MSG_SCSI_TASK_MGMT_REPLY *tmf_reply; 2666147883Sscottl 2667147883Sscottl KASSERT(req == mpt->tmf_req, ("TMF Reply not using mpt->tmf_req")); 2668157662Smjacob#ifdef INVARIANTS 2669157662Smjacob mpt_req_not_spcl(mpt, req, "mpt_scsi_tmf_reply_handler", __LINE__); 2670157662Smjacob#endif 2671147883Sscottl tmf_reply = (MSG_SCSI_TASK_MGMT_REPLY *)reply_frame; 2672157662Smjacob /* Record IOC Status and Response Code of TMF for any waiters. */ 2673157662Smjacob req->IOCStatus = le16toh(tmf_reply->IOCStatus); 2674157662Smjacob req->ResponseCode = tmf_reply->ResponseCode; 2675147883Sscottl 2676164415Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, "TMF complete: req %p:%u status 0x%x\n", 2677157662Smjacob req, req->serno, le16toh(tmf_reply->IOCStatus)); 2678147883Sscottl TAILQ_REMOVE(&mpt->request_pending_list, req, links); 2679147883Sscottl if ((req->state & REQ_STATE_NEED_WAKEUP) != 0) { 2680147883Sscottl req->state |= REQ_STATE_DONE; 2681147883Sscottl wakeup(req); 2682157354Smjacob } else { 2683147883Sscottl mpt->tmf_req->state = REQ_STATE_FREE; 2684157354Smjacob } 2685157354Smjacob return (TRUE); 2686147883Sscottl} 2687147883Sscottl 2688147883Sscottl/* 2689157117Smjacob * XXX: Move to definitions file 2690157117Smjacob */ 2691157117Smjacob#define ELS 0x22 2692157117Smjacob#define FC4LS 0x32 2693157117Smjacob#define ABTS 0x81 2694157117Smjacob#define BA_ACC 0x84 2695157117Smjacob 2696157117Smjacob#define LS_RJT 0x01 2697157117Smjacob#define LS_ACC 0x02 2698157117Smjacob#define PLOGI 0x03 2699157117Smjacob#define LOGO 0x05 2700157117Smjacob#define SRR 0x14 2701157117Smjacob#define PRLI 0x20 2702157117Smjacob#define PRLO 0x21 2703157117Smjacob#define ADISC 0x52 2704157117Smjacob#define RSCN 0x61 2705157117Smjacob 2706157117Smjacobstatic void 2707157117Smjacobmpt_fc_els_send_response(struct mpt_softc *mpt, request_t *req, 2708157117Smjacob PTR_MSG_LINK_SERVICE_BUFFER_POST_REPLY rp, U8 length) 2709157117Smjacob{ 2710164315Sjb uint32_t fl; 2711157117Smjacob MSG_LINK_SERVICE_RSP_REQUEST tmp; 2712157117Smjacob PTR_MSG_LINK_SERVICE_RSP_REQUEST rsp; 2713157117Smjacob 2714157117Smjacob /* 2715157117Smjacob * We are going to reuse the ELS request to send this response back. 2716157117Smjacob */ 2717157117Smjacob rsp = &tmp; 2718157117Smjacob memset(rsp, 0, sizeof(*rsp)); 2719157117Smjacob 2720157117Smjacob#ifdef USE_IMMEDIATE_LINK_DATA 2721157117Smjacob /* 2722157117Smjacob * Apparently the IMMEDIATE stuff doesn't seem to work. 2723157117Smjacob */ 2724157117Smjacob rsp->RspFlags = LINK_SERVICE_RSP_FLAGS_IMMEDIATE; 2725157117Smjacob#endif 2726157117Smjacob rsp->RspLength = length; 2727157117Smjacob rsp->Function = MPI_FUNCTION_FC_LINK_SRVC_RSP; 2728157117Smjacob rsp->MsgContext = htole32(req->index | fc_els_handler_id); 2729157117Smjacob 2730157117Smjacob /* 2731157117Smjacob * Copy over information from the original reply frame to 2732157117Smjacob * it's correct place in the response. 2733157117Smjacob */ 2734157117Smjacob memcpy((U8 *)rsp + 0x0c, (U8 *)rp + 0x1c, 24); 2735157117Smjacob 2736157117Smjacob /* 2737157117Smjacob * And now copy back the temporary area to the original frame. 2738157117Smjacob */ 2739157117Smjacob memcpy(req->req_vbuf, rsp, sizeof (MSG_LINK_SERVICE_RSP_REQUEST)); 2740157117Smjacob rsp = req->req_vbuf; 2741157117Smjacob 2742157117Smjacob#ifdef USE_IMMEDIATE_LINK_DATA 2743157117Smjacob memcpy((U8 *)&rsp->SGL, &((U8 *)req->req_vbuf)[MPT_RQSL(mpt)], length); 2744157117Smjacob#else 2745157117Smjacob{ 2746157117Smjacob PTR_SGE_SIMPLE32 se = (PTR_SGE_SIMPLE32) &rsp->SGL; 2747157117Smjacob bus_addr_t paddr = req->req_pbuf; 2748157117Smjacob paddr += MPT_RQSL(mpt); 2749157117Smjacob 2750164315Sjb fl = 2751157117Smjacob MPI_SGE_FLAGS_HOST_TO_IOC | 2752157117Smjacob MPI_SGE_FLAGS_SIMPLE_ELEMENT | 2753157117Smjacob MPI_SGE_FLAGS_LAST_ELEMENT | 2754157117Smjacob MPI_SGE_FLAGS_END_OF_LIST | 2755157117Smjacob MPI_SGE_FLAGS_END_OF_BUFFER; 2756164315Sjb fl <<= MPI_SGE_FLAGS_SHIFT; 2757164315Sjb fl |= (length); 2758164315Sjb se->FlagsLength = htole32(fl); 2759164315Sjb se->Address = htole32((uint32_t) paddr); 2760157117Smjacob} 2761157117Smjacob#endif 2762157117Smjacob 2763157117Smjacob /* 2764157117Smjacob * Send it on... 2765157117Smjacob */ 2766157117Smjacob mpt_send_cmd(mpt, req); 2767157117Smjacob} 2768157117Smjacob 2769157117Smjacobstatic int 2770157117Smjacobmpt_fc_els_reply_handler(struct mpt_softc *mpt, request_t *req, 2771157117Smjacob uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) 2772157117Smjacob{ 2773157117Smjacob PTR_MSG_LINK_SERVICE_BUFFER_POST_REPLY rp = 2774157117Smjacob (PTR_MSG_LINK_SERVICE_BUFFER_POST_REPLY) reply_frame; 2775157117Smjacob U8 rctl; 2776157117Smjacob U8 type; 2777157117Smjacob U8 cmd; 2778157117Smjacob U16 status = le16toh(reply_frame->IOCStatus); 2779157117Smjacob U32 *elsbuf; 2780157662Smjacob int ioindex; 2781157117Smjacob int do_refresh = TRUE; 2782157117Smjacob 2783157662Smjacob#ifdef INVARIANTS 2784157662Smjacob KASSERT(mpt_req_on_free_list(mpt, req) == 0, 2785157662Smjacob ("fc_els_reply_handler: req %p:%u for function %x on freelist!", 2786157662Smjacob req, req->serno, rp->Function)); 2787157662Smjacob if (rp->Function != MPI_FUNCTION_FC_PRIMITIVE_SEND) { 2788157662Smjacob mpt_req_spcl(mpt, req, "fc_els_reply_handler", __LINE__); 2789157662Smjacob } else { 2790157662Smjacob mpt_req_not_spcl(mpt, req, "fc_els_reply_handler", __LINE__); 2791157662Smjacob } 2792157662Smjacob#endif 2793158278Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 2794157662Smjacob "FC_ELS Complete: req %p:%u, reply %p function %x\n", 2795157662Smjacob req, req->serno, reply_frame, reply_frame->Function); 2796157117Smjacob 2797157117Smjacob if (status != MPI_IOCSTATUS_SUCCESS) { 2798157117Smjacob mpt_prt(mpt, "ELS REPLY STATUS 0x%x for Function %x\n", 2799157117Smjacob status, reply_frame->Function); 2800157117Smjacob if (status == MPI_IOCSTATUS_INVALID_STATE) { 2801157117Smjacob /* 2802157117Smjacob * XXX: to get around shutdown issue 2803157117Smjacob */ 2804157117Smjacob mpt->disabled = 1; 2805157117Smjacob return (TRUE); 2806157117Smjacob } 2807157117Smjacob return (TRUE); 2808157117Smjacob } 2809157117Smjacob 2810157117Smjacob /* 2811157117Smjacob * If the function of a link service response, we recycle the 2812157117Smjacob * response to be a refresh for a new link service request. 2813157662Smjacob * 2814157662Smjacob * The request pointer is bogus in this case and we have to fetch 2815157662Smjacob * it based upon the TransactionContext. 2816157117Smjacob */ 2817157117Smjacob if (rp->Function == MPI_FUNCTION_FC_LINK_SRVC_RSP) { 2818157662Smjacob /* Freddie Uncle Charlie Katie */ 2819157662Smjacob /* We don't get the IOINDEX as part of the Link Svc Rsp */ 2820157662Smjacob for (ioindex = 0; ioindex < mpt->els_cmds_allocated; ioindex++) 2821157662Smjacob if (mpt->els_cmd_ptrs[ioindex] == req) { 2822157662Smjacob break; 2823157662Smjacob } 2824157662Smjacob 2825157662Smjacob KASSERT(ioindex < mpt->els_cmds_allocated, 2826157662Smjacob ("can't find my mommie!")); 2827157662Smjacob 2828157662Smjacob /* remove from active list as we're going to re-post it */ 2829157662Smjacob TAILQ_REMOVE(&mpt->request_pending_list, req, links); 2830157662Smjacob req->state &= ~REQ_STATE_QUEUED; 2831157662Smjacob req->state |= REQ_STATE_DONE; 2832157662Smjacob mpt_fc_post_els(mpt, req, ioindex); 2833157117Smjacob return (TRUE); 2834157117Smjacob } 2835157117Smjacob 2836157117Smjacob if (rp->Function == MPI_FUNCTION_FC_PRIMITIVE_SEND) { 2837157662Smjacob /* remove from active list as we're done */ 2838157662Smjacob TAILQ_REMOVE(&mpt->request_pending_list, req, links); 2839157117Smjacob req->state &= ~REQ_STATE_QUEUED; 2840157117Smjacob req->state |= REQ_STATE_DONE; 2841160396Smjacob if (req->state & REQ_STATE_TIMEDOUT) { 2842157117Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 2843160396Smjacob "Sync Primitive Send Completed After Timeout\n"); 2844160396Smjacob mpt_free_request(mpt, req); 2845160396Smjacob } else if ((req->state & REQ_STATE_NEED_WAKEUP) == 0) { 2846160396Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 2847157117Smjacob "Async Primitive Send Complete\n"); 2848157117Smjacob mpt_free_request(mpt, req); 2849157117Smjacob } else { 2850157117Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 2851160396Smjacob "Sync Primitive Send Complete- Waking Waiter\n"); 2852157117Smjacob wakeup(req); 2853157117Smjacob } 2854157117Smjacob return (TRUE); 2855157117Smjacob } 2856157117Smjacob 2857157117Smjacob if (rp->Function != MPI_FUNCTION_FC_LINK_SRVC_BUF_POST) { 2858157117Smjacob mpt_prt(mpt, "unexpected ELS_REPLY: Function 0x%x Flags %x " 2859157117Smjacob "Length %d Message Flags %x\n", rp->Function, rp->Flags, 2860157117Smjacob rp->MsgLength, rp->MsgFlags); 2861157117Smjacob return (TRUE); 2862157117Smjacob } 2863157117Smjacob 2864157117Smjacob if (rp->MsgLength <= 5) { 2865157117Smjacob /* 2866157117Smjacob * This is just a ack of an original ELS buffer post 2867157117Smjacob */ 2868158278Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 2869157662Smjacob "RECV'd ACK of FC_ELS buf post %p:%u\n", req, req->serno); 2870157117Smjacob return (TRUE); 2871157117Smjacob } 2872157117Smjacob 2873157117Smjacob 2874157117Smjacob rctl = (le32toh(rp->Rctl_Did) & MPI_FC_RCTL_MASK) >> MPI_FC_RCTL_SHIFT; 2875157117Smjacob type = (le32toh(rp->Type_Fctl) & MPI_FC_TYPE_MASK) >> MPI_FC_TYPE_SHIFT; 2876157117Smjacob 2877157117Smjacob elsbuf = &((U32 *)req->req_vbuf)[MPT_RQSL(mpt)/sizeof (U32)]; 2878157117Smjacob cmd = be32toh(elsbuf[0]) >> 24; 2879157117Smjacob 2880157117Smjacob if (rp->Flags & MPI_LS_BUF_POST_REPLY_FLAG_NO_RSP_NEEDED) { 2881157117Smjacob mpt_lprt(mpt, MPT_PRT_ALWAYS, "ELS_REPLY: response unneeded\n"); 2882157117Smjacob return (TRUE); 2883157117Smjacob } 2884157117Smjacob 2885157662Smjacob ioindex = le32toh(rp->TransactionContext); 2886157662Smjacob req = mpt->els_cmd_ptrs[ioindex]; 2887157117Smjacob 2888157117Smjacob if (rctl == ELS && type == 1) { 2889157117Smjacob switch (cmd) { 2890157117Smjacob case PRLI: 2891157117Smjacob /* 2892157117Smjacob * Send back a PRLI ACC 2893157117Smjacob */ 2894157117Smjacob mpt_prt(mpt, "PRLI from 0x%08x%08x\n", 2895157117Smjacob le32toh(rp->Wwn.PortNameHigh), 2896157117Smjacob le32toh(rp->Wwn.PortNameLow)); 2897157117Smjacob elsbuf[0] = htobe32(0x02100014); 2898157117Smjacob elsbuf[1] |= htobe32(0x00000100); 2899157117Smjacob elsbuf[4] = htobe32(0x00000002); 2900157117Smjacob if (mpt->role & MPT_ROLE_TARGET) 2901157117Smjacob elsbuf[4] |= htobe32(0x00000010); 2902157117Smjacob if (mpt->role & MPT_ROLE_INITIATOR) 2903157117Smjacob elsbuf[4] |= htobe32(0x00000020); 2904157662Smjacob /* remove from active list as we're done */ 2905157662Smjacob TAILQ_REMOVE(&mpt->request_pending_list, req, links); 2906157662Smjacob req->state &= ~REQ_STATE_QUEUED; 2907157662Smjacob req->state |= REQ_STATE_DONE; 2908157117Smjacob mpt_fc_els_send_response(mpt, req, rp, 20); 2909157117Smjacob do_refresh = FALSE; 2910157117Smjacob break; 2911157117Smjacob case PRLO: 2912157117Smjacob memset(elsbuf, 0, 5 * (sizeof (U32))); 2913157117Smjacob elsbuf[0] = htobe32(0x02100014); 2914157117Smjacob elsbuf[1] = htobe32(0x08000100); 2915157117Smjacob mpt_prt(mpt, "PRLO from 0x%08x%08x\n", 2916157117Smjacob le32toh(rp->Wwn.PortNameHigh), 2917157117Smjacob le32toh(rp->Wwn.PortNameLow)); 2918157662Smjacob /* remove from active list as we're done */ 2919157662Smjacob TAILQ_REMOVE(&mpt->request_pending_list, req, links); 2920157662Smjacob req->state &= ~REQ_STATE_QUEUED; 2921157662Smjacob req->state |= REQ_STATE_DONE; 2922157117Smjacob mpt_fc_els_send_response(mpt, req, rp, 20); 2923157117Smjacob do_refresh = FALSE; 2924157117Smjacob break; 2925157117Smjacob default: 2926157117Smjacob mpt_prt(mpt, "ELS TYPE 1 COMMAND: %x\n", cmd); 2927157117Smjacob break; 2928157117Smjacob } 2929157117Smjacob } else if (rctl == ABTS && type == 0) { 2930157117Smjacob uint16_t rx_id = le16toh(rp->Rxid); 2931157117Smjacob uint16_t ox_id = le16toh(rp->Oxid); 2932157117Smjacob request_t *tgt_req = NULL; 2933157117Smjacob 2934157117Smjacob mpt_prt(mpt, 2935157117Smjacob "ELS: ABTS OX_ID 0x%x RX_ID 0x%x from 0x%08x%08x\n", 2936157117Smjacob ox_id, rx_id, le32toh(rp->Wwn.PortNameHigh), 2937157117Smjacob le32toh(rp->Wwn.PortNameLow)); 2938157117Smjacob if (rx_id >= mpt->mpt_max_tgtcmds) { 2939157117Smjacob mpt_prt(mpt, "Bad RX_ID 0x%x\n", rx_id); 2940157117Smjacob } else if (mpt->tgt_cmd_ptrs == NULL) { 2941157117Smjacob mpt_prt(mpt, "No TGT CMD PTRS\n"); 2942157117Smjacob } else { 2943157117Smjacob tgt_req = mpt->tgt_cmd_ptrs[rx_id]; 2944157117Smjacob } 2945157117Smjacob if (tgt_req) { 2946157117Smjacob mpt_tgt_state_t *tgt = MPT_TGT_STATE(mpt, tgt_req); 2947217009Smarius union ccb *ccb; 2948157117Smjacob uint32_t ct_id; 2949157117Smjacob 2950157117Smjacob /* 2951157117Smjacob * Check to make sure we have the correct command 2952157117Smjacob * The reply descriptor in the target state should 2953157117Smjacob * should contain an IoIndex that should match the 2954157117Smjacob * RX_ID. 2955157117Smjacob * 2956157117Smjacob * It'd be nice to have OX_ID to crosscheck with 2957157117Smjacob * as well. 2958157117Smjacob */ 2959157117Smjacob ct_id = GET_IO_INDEX(tgt->reply_desc); 2960157117Smjacob 2961157117Smjacob if (ct_id != rx_id) { 2962157117Smjacob mpt_lprt(mpt, MPT_PRT_ERROR, "ABORT Mismatch: " 2963157117Smjacob "RX_ID received=0x%x; RX_ID in cmd=0x%x\n", 2964157117Smjacob rx_id, ct_id); 2965157117Smjacob goto skip; 2966157117Smjacob } 2967157117Smjacob 2968157117Smjacob ccb = tgt->ccb; 2969157117Smjacob if (ccb) { 2970157117Smjacob mpt_prt(mpt, 2971157117Smjacob "CCB (%p): lun %u flags %x status %x\n", 2972157117Smjacob ccb, ccb->ccb_h.target_lun, 2973157117Smjacob ccb->ccb_h.flags, ccb->ccb_h.status); 2974157117Smjacob } 2975157117Smjacob mpt_prt(mpt, "target state 0x%x resid %u xfrd %u rpwrd " 2976157354Smjacob "%x nxfers %x\n", tgt->state, 2977157117Smjacob tgt->resid, tgt->bytes_xfered, tgt->reply_desc, 2978157354Smjacob tgt->nxfers); 2979157117Smjacob skip: 2980157354Smjacob if (mpt_abort_target_cmd(mpt, tgt_req)) { 2981157354Smjacob mpt_prt(mpt, "unable to start TargetAbort\n"); 2982157117Smjacob } 2983157117Smjacob } else { 2984157117Smjacob mpt_prt(mpt, "no back pointer for RX_ID 0x%x\n", rx_id); 2985157117Smjacob } 2986157117Smjacob memset(elsbuf, 0, 5 * (sizeof (U32))); 2987157117Smjacob elsbuf[0] = htobe32(0); 2988157117Smjacob elsbuf[1] = htobe32((ox_id << 16) | rx_id); 2989157117Smjacob elsbuf[2] = htobe32(0x000ffff); 2990157117Smjacob /* 2991220945Smarius * Dork with the reply frame so that the response to it 2992157117Smjacob * will be correct. 2993157117Smjacob */ 2994157117Smjacob rp->Rctl_Did += ((BA_ACC - ABTS) << MPI_FC_RCTL_SHIFT); 2995157662Smjacob /* remove from active list as we're done */ 2996157662Smjacob TAILQ_REMOVE(&mpt->request_pending_list, req, links); 2997157662Smjacob req->state &= ~REQ_STATE_QUEUED; 2998157662Smjacob req->state |= REQ_STATE_DONE; 2999157117Smjacob mpt_fc_els_send_response(mpt, req, rp, 12); 3000157117Smjacob do_refresh = FALSE; 3001157117Smjacob } else { 3002157117Smjacob mpt_prt(mpt, "ELS: RCTL %x TYPE %x CMD %x\n", rctl, type, cmd); 3003157117Smjacob } 3004157117Smjacob if (do_refresh == TRUE) { 3005157662Smjacob /* remove from active list as we're done */ 3006157662Smjacob TAILQ_REMOVE(&mpt->request_pending_list, req, links); 3007157662Smjacob req->state &= ~REQ_STATE_QUEUED; 3008157662Smjacob req->state |= REQ_STATE_DONE; 3009157662Smjacob mpt_fc_post_els(mpt, req, ioindex); 3010157117Smjacob } 3011157117Smjacob return (TRUE); 3012157117Smjacob} 3013157117Smjacob 3014157117Smjacob/* 3015147883Sscottl * Clean up all SCSI Initiator personality state in response 3016147883Sscottl * to a controller reset. 3017147883Sscottl */ 3018147883Sscottlstatic void 3019147883Sscottlmpt_cam_ioc_reset(struct mpt_softc *mpt, int type) 3020147883Sscottl{ 3021224493Smarius 3022147883Sscottl /* 3023147883Sscottl * The pending list is already run down by 3024147883Sscottl * the generic handler. Perform the same 3025147883Sscottl * operation on the timed out request list. 3026147883Sscottl */ 3027147883Sscottl mpt_complete_request_chain(mpt, &mpt->request_timeout_list, 3028147883Sscottl MPI_IOCSTATUS_INVALID_STATE); 3029147883Sscottl 3030147883Sscottl /* 3031157662Smjacob * XXX: We need to repost ELS and Target Command Buffers? 3032157662Smjacob */ 3033157662Smjacob 3034157662Smjacob /* 3035147883Sscottl * Inform the XPT that a bus reset has occurred. 3036147883Sscottl */ 3037147883Sscottl xpt_async(AC_BUS_RESET, mpt->path, NULL); 3038147883Sscottl} 3039147883Sscottl 3040147883Sscottl/* 3041147883Sscottl * Parse additional completion information in the reply 3042147883Sscottl * frame for SCSI I/O requests. 3043147883Sscottl */ 3044147883Sscottlstatic int 3045147883Sscottlmpt_scsi_reply_frame_handler(struct mpt_softc *mpt, request_t *req, 3046147883Sscottl MSG_DEFAULT_REPLY *reply_frame) 3047147883Sscottl{ 3048147883Sscottl union ccb *ccb; 3049147883Sscottl MSG_SCSI_IO_REPLY *scsi_io_reply; 3050147883Sscottl u_int ioc_status; 3051147883Sscottl u_int sstate; 3052147883Sscottl 3053147883Sscottl MPT_DUMP_REPLY_FRAME(mpt, reply_frame); 3054147883Sscottl KASSERT(reply_frame->Function == MPI_FUNCTION_SCSI_IO_REQUEST 3055147883Sscottl || reply_frame->Function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH, 3056147883Sscottl ("MPT SCSI I/O Handler called with incorrect reply type")); 3057147883Sscottl KASSERT((reply_frame->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) == 0, 3058147883Sscottl ("MPT SCSI I/O Handler called with continuation reply")); 3059147883Sscottl 3060147883Sscottl scsi_io_reply = (MSG_SCSI_IO_REPLY *)reply_frame; 3061147883Sscottl ioc_status = le16toh(scsi_io_reply->IOCStatus); 3062147883Sscottl ioc_status &= MPI_IOCSTATUS_MASK; 3063147883Sscottl sstate = scsi_io_reply->SCSIState; 3064147883Sscottl 3065147883Sscottl ccb = req->ccb; 3066147883Sscottl ccb->csio.resid = 3067147883Sscottl ccb->csio.dxfer_len - le32toh(scsi_io_reply->TransferCount); 3068147883Sscottl 3069147883Sscottl if ((sstate & MPI_SCSI_STATE_AUTOSENSE_VALID) != 0 3070147883Sscottl && (ccb->ccb_h.flags & (CAM_SENSE_PHYS | CAM_SENSE_PTR)) == 0) { 3071226067Sken uint32_t sense_returned; 3072226067Sken 3073147883Sscottl ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 3074226067Sken 3075226067Sken sense_returned = le32toh(scsi_io_reply->SenseCount); 3076226067Sken if (sense_returned < ccb->csio.sense_len) 3077226067Sken ccb->csio.sense_resid = ccb->csio.sense_len - 3078226067Sken sense_returned; 3079226067Sken else 3080226067Sken ccb->csio.sense_resid = 0; 3081226067Sken 3082238013Smarius bzero(&ccb->csio.sense_data, sizeof(ccb->csio.sense_data)); 3083147883Sscottl bcopy(req->sense_vbuf, &ccb->csio.sense_data, 3084226067Sken min(ccb->csio.sense_len, sense_returned)); 3085147883Sscottl } 3086147883Sscottl 3087147883Sscottl if ((sstate & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) != 0) { 3088147883Sscottl /* 3089147883Sscottl * Tag messages rejected, but non-tagged retry 3090147883Sscottl * was successful. 3091147883SscottlXXXX 3092147883Sscottl mpt_set_tags(mpt, devinfo, MPT_QUEUE_NONE); 3093147883Sscottl */ 3094147883Sscottl } 3095147883Sscottl 3096147883Sscottl switch(ioc_status) { 3097147883Sscottl case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: 3098147883Sscottl /* 3099147883Sscottl * XXX 3100147883Sscottl * Linux driver indicates that a zero 3101147883Sscottl * transfer length with this error code 3102147883Sscottl * indicates a CRC error. 3103147883Sscottl * 3104147883Sscottl * No need to swap the bytes for checking 3105147883Sscottl * against zero. 3106147883Sscottl */ 3107147883Sscottl if (scsi_io_reply->TransferCount == 0) { 3108147883Sscottl mpt_set_ccb_status(ccb, CAM_UNCOR_PARITY); 3109147883Sscottl break; 3110147883Sscottl } 3111147883Sscottl /* FALLTHROUGH */ 3112147883Sscottl case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: 3113147883Sscottl case MPI_IOCSTATUS_SUCCESS: 3114147883Sscottl case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: 3115147883Sscottl if ((sstate & MPI_SCSI_STATE_NO_SCSI_STATUS) != 0) { 3116147883Sscottl /* 3117147883Sscottl * Status was never returned for this transaction. 3118147883Sscottl */ 3119147883Sscottl mpt_set_ccb_status(ccb, CAM_UNEXP_BUSFREE); 3120147883Sscottl } else if (scsi_io_reply->SCSIStatus != SCSI_STATUS_OK) { 3121147883Sscottl ccb->csio.scsi_status = scsi_io_reply->SCSIStatus; 3122147883Sscottl mpt_set_ccb_status(ccb, CAM_SCSI_STATUS_ERROR); 3123147883Sscottl if ((sstate & MPI_SCSI_STATE_AUTOSENSE_FAILED) != 0) 3124147883Sscottl mpt_set_ccb_status(ccb, CAM_AUTOSENSE_FAIL); 3125147883Sscottl } else if ((sstate & MPI_SCSI_STATE_RESPONSE_INFO_VALID) != 0) { 3126147883Sscottl 3127220945Smarius /* XXX Handle SPI-Packet and FCP-2 response info. */ 3128147883Sscottl mpt_set_ccb_status(ccb, CAM_REQ_CMP_ERR); 3129147883Sscottl } else 3130147883Sscottl mpt_set_ccb_status(ccb, CAM_REQ_CMP); 3131147883Sscottl break; 3132147883Sscottl case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: 3133147883Sscottl mpt_set_ccb_status(ccb, CAM_DATA_RUN_ERR); 3134147883Sscottl break; 3135147883Sscottl case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: 3136147883Sscottl mpt_set_ccb_status(ccb, CAM_UNCOR_PARITY); 3137147883Sscottl break; 3138147883Sscottl case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: 3139147883Sscottl /* 3140147883Sscottl * Since selection timeouts and "device really not 3141147883Sscottl * there" are grouped into this error code, report 3142147883Sscottl * selection timeout. Selection timeouts are 3143147883Sscottl * typically retried before giving up on the device 3144147883Sscottl * whereas "device not there" errors are considered 3145147883Sscottl * unretryable. 3146147883Sscottl */ 3147147883Sscottl mpt_set_ccb_status(ccb, CAM_SEL_TIMEOUT); 3148147883Sscottl break; 3149147883Sscottl case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: 3150147883Sscottl mpt_set_ccb_status(ccb, CAM_SEQUENCE_FAIL); 3151147883Sscottl break; 3152147883Sscottl case MPI_IOCSTATUS_SCSI_INVALID_BUS: 3153147883Sscottl mpt_set_ccb_status(ccb, CAM_PATH_INVALID); 3154147883Sscottl break; 3155147883Sscottl case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: 3156147883Sscottl mpt_set_ccb_status(ccb, CAM_TID_INVALID); 3157147883Sscottl break; 3158147883Sscottl case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: 3159147883Sscottl ccb->ccb_h.status = CAM_UA_TERMIO; 3160147883Sscottl break; 3161147883Sscottl case MPI_IOCSTATUS_INVALID_STATE: 3162147883Sscottl /* 3163147883Sscottl * The IOC has been reset. Emulate a bus reset. 3164147883Sscottl */ 3165147883Sscottl /* FALLTHROUGH */ 3166147883Sscottl case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: 3167147883Sscottl ccb->ccb_h.status = CAM_SCSI_BUS_RESET; 3168147883Sscottl break; 3169147883Sscottl case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: 3170147883Sscottl case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: 3171147883Sscottl /* 3172147883Sscottl * Don't clobber any timeout status that has 3173147883Sscottl * already been set for this transaction. We 3174147883Sscottl * want the SCSI layer to be able to differentiate 3175147883Sscottl * between the command we aborted due to timeout 3176147883Sscottl * and any innocent bystanders. 3177147883Sscottl */ 3178147883Sscottl if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) 3179147883Sscottl break; 3180147883Sscottl mpt_set_ccb_status(ccb, CAM_REQ_TERMIO); 3181147883Sscottl break; 3182147883Sscottl 3183147883Sscottl case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: 3184147883Sscottl mpt_set_ccb_status(ccb, CAM_RESRC_UNAVAIL); 3185147883Sscottl break; 3186147883Sscottl case MPI_IOCSTATUS_BUSY: 3187147883Sscottl mpt_set_ccb_status(ccb, CAM_BUSY); 3188147883Sscottl break; 3189147883Sscottl case MPI_IOCSTATUS_INVALID_FUNCTION: 3190147883Sscottl case MPI_IOCSTATUS_INVALID_SGL: 3191147883Sscottl case MPI_IOCSTATUS_INTERNAL_ERROR: 3192147883Sscottl case MPI_IOCSTATUS_INVALID_FIELD: 3193147883Sscottl default: 3194147883Sscottl /* XXX 3195147883Sscottl * Some of the above may need to kick 3196147883Sscottl * of a recovery action!!!! 3197147883Sscottl */ 3198147883Sscottl ccb->ccb_h.status = CAM_UNREC_HBA_ERROR; 3199147883Sscottl break; 3200147883Sscottl } 3201147883Sscottl 3202157354Smjacob if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 3203147883Sscottl mpt_freeze_ccb(ccb); 3204157354Smjacob } 3205147883Sscottl 3206157354Smjacob return (TRUE); 3207147883Sscottl} 3208147883Sscottl 3209147883Sscottlstatic void 3210147883Sscottlmpt_action(struct cam_sim *sim, union ccb *ccb) 3211147883Sscottl{ 3212159312Smjacob struct mpt_softc *mpt; 3213159312Smjacob struct ccb_trans_settings *cts; 3214158982Smjacob target_id_t tgt; 3215159471Sjkim lun_id_t lun; 3216159312Smjacob int raid_passthru; 3217147883Sscottl 3218147883Sscottl CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("mpt_action\n")); 3219147883Sscottl 3220147883Sscottl mpt = (struct mpt_softc *)cam_sim_softc(sim); 3221147883Sscottl raid_passthru = (sim == mpt->phydisk_sim); 3222169293Smjacob MPT_LOCK_ASSERT(mpt); 3223147883Sscottl 3224147883Sscottl tgt = ccb->ccb_h.target_id; 3225159471Sjkim lun = ccb->ccb_h.target_lun; 3226164837Smjacob if (raid_passthru && 3227164837Smjacob ccb->ccb_h.func_code != XPT_PATH_INQ && 3228159471Sjkim ccb->ccb_h.func_code != XPT_RESET_BUS && 3229159471Sjkim ccb->ccb_h.func_code != XPT_RESET_DEV) { 3230147883Sscottl if (mpt_map_physdisk(mpt, ccb, &tgt) != 0) { 3231157117Smjacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 3232157117Smjacob mpt_set_ccb_status(ccb, CAM_DEV_NOT_THERE); 3233147883Sscottl xpt_done(ccb); 3234147883Sscottl return; 3235147883Sscottl } 3236147883Sscottl } 3237147883Sscottl ccb->ccb_h.ccb_mpt_ptr = mpt; 3238147883Sscottl 3239147883Sscottl switch (ccb->ccb_h.func_code) { 3240147883Sscottl case XPT_SCSI_IO: /* Execute the requested I/O operation */ 3241147883Sscottl /* 3242147883Sscottl * Do a couple of preliminary checks... 3243147883Sscottl */ 3244147883Sscottl if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { 3245147883Sscottl if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) { 3246157117Smjacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 3247157117Smjacob mpt_set_ccb_status(ccb, CAM_REQ_INVALID); 3248147883Sscottl break; 3249147883Sscottl } 3250147883Sscottl } 3251147883Sscottl /* Max supported CDB length is 16 bytes */ 3252147883Sscottl /* XXX Unless we implement the new 32byte message type */ 3253147883Sscottl if (ccb->csio.cdb_len > 3254147883Sscottl sizeof (((PTR_MSG_SCSI_IO_REQUEST)0)->CDB)) { 3255157117Smjacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 3256157117Smjacob mpt_set_ccb_status(ccb, CAM_REQ_INVALID); 3257158935Smjacob break; 3258147883Sscottl } 3259166897Smjacob#ifdef MPT_TEST_MULTIPATH 3260166897Smjacob if (mpt->failure_id == ccb->ccb_h.target_id) { 3261166897Smjacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 3262166897Smjacob mpt_set_ccb_status(ccb, CAM_SEL_TIMEOUT); 3263166897Smjacob break; 3264166897Smjacob } 3265166897Smjacob#endif 3266147883Sscottl ccb->csio.scsi_status = SCSI_STATUS_OK; 3267147883Sscottl mpt_start(sim, ccb); 3268158935Smjacob return; 3269147883Sscottl 3270147883Sscottl case XPT_RESET_BUS: 3271164837Smjacob if (raid_passthru) { 3272164837Smjacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 3273164837Smjacob mpt_set_ccb_status(ccb, CAM_REQ_CMP); 3274164837Smjacob break; 3275164837Smjacob } 3276159471Sjkim case XPT_RESET_DEV: 3277168470Smjacob if (ccb->ccb_h.func_code == XPT_RESET_BUS) { 3278168470Smjacob if (bootverbose) { 3279168470Smjacob xpt_print(ccb->ccb_h.path, "reset bus\n"); 3280168470Smjacob } 3281168470Smjacob } else { 3282168470Smjacob xpt_print(ccb->ccb_h.path, "reset device\n"); 3283168470Smjacob } 3284159471Sjkim (void) mpt_bus_reset(mpt, tgt, lun, FALSE); 3285158982Smjacob 3286147883Sscottl /* 3287147883Sscottl * mpt_bus_reset is always successful in that it 3288147883Sscottl * will fall back to a hard reset should a bus 3289147883Sscottl * reset attempt fail. 3290147883Sscottl */ 3291157117Smjacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 3292147883Sscottl mpt_set_ccb_status(ccb, CAM_REQ_CMP); 3293147883Sscottl break; 3294147883Sscottl 3295147883Sscottl case XPT_ABORT: 3296157117Smjacob { 3297157117Smjacob union ccb *accb = ccb->cab.abort_ccb; 3298157117Smjacob switch (accb->ccb_h.func_code) { 3299157117Smjacob case XPT_ACCEPT_TARGET_IO: 3300237825Sken case XPT_IMMEDIATE_NOTIFY: 3301157853Smjacob ccb->ccb_h.status = mpt_abort_target_ccb(mpt, ccb); 3302157117Smjacob break; 3303157117Smjacob case XPT_CONT_TARGET_IO: 3304157117Smjacob mpt_prt(mpt, "cannot abort active CTIOs yet\n"); 3305157117Smjacob ccb->ccb_h.status = CAM_UA_ABORT; 3306157117Smjacob break; 3307157117Smjacob case XPT_SCSI_IO: 3308157117Smjacob ccb->ccb_h.status = CAM_UA_ABORT; 3309157117Smjacob break; 3310157117Smjacob default: 3311157117Smjacob ccb->ccb_h.status = CAM_REQ_INVALID; 3312157117Smjacob break; 3313157117Smjacob } 3314147883Sscottl break; 3315157117Smjacob } 3316147883Sscottl 3317159471Sjkim#define IS_CURRENT_SETTINGS(c) ((c)->type == CTS_TYPE_CURRENT_SETTINGS) 3318264950Smarius 3319147883Sscottl#define DP_DISC_ENABLE 0x1 3320147883Sscottl#define DP_DISC_DISABL 0x2 3321147883Sscottl#define DP_DISC (DP_DISC_ENABLE|DP_DISC_DISABL) 3322147883Sscottl 3323147883Sscottl#define DP_TQING_ENABLE 0x4 3324147883Sscottl#define DP_TQING_DISABL 0x8 3325147883Sscottl#define DP_TQING (DP_TQING_ENABLE|DP_TQING_DISABL) 3326147883Sscottl 3327147883Sscottl#define DP_WIDE 0x10 3328147883Sscottl#define DP_NARROW 0x20 3329147883Sscottl#define DP_WIDTH (DP_WIDE|DP_NARROW) 3330147883Sscottl 3331147883Sscottl#define DP_SYNC 0x40 3332147883Sscottl 3333147883Sscottl case XPT_SET_TRAN_SETTINGS: /* Nexus Settings */ 3334157662Smjacob { 3335157662Smjacob struct ccb_trans_settings_scsi *scsi; 3336157662Smjacob struct ccb_trans_settings_spi *spi; 3337157662Smjacob uint8_t dval; 3338157662Smjacob u_int period; 3339157662Smjacob u_int offset; 3340159051Smjacob int i, j; 3341157662Smjacob 3342147883Sscottl cts = &ccb->cts; 3343159051Smjacob 3344157662Smjacob if (mpt->is_fc || mpt->is_sas) { 3345157662Smjacob mpt_set_ccb_status(ccb, CAM_REQ_CMP); 3346157662Smjacob break; 3347157662Smjacob } 3348157662Smjacob 3349164837Smjacob scsi = &cts->proto_specific.scsi; 3350164837Smjacob spi = &cts->xport_specific.spi; 3351164837Smjacob 3352159051Smjacob /* 3353164837Smjacob * We can be called just to valid transport and proto versions 3354164837Smjacob */ 3355164837Smjacob if (scsi->valid == 0 && spi->valid == 0) { 3356164837Smjacob mpt_set_ccb_status(ccb, CAM_REQ_CMP); 3357164837Smjacob break; 3358164837Smjacob } 3359164837Smjacob 3360164837Smjacob /* 3361159051Smjacob * Skip attempting settings on RAID volume disks. 3362159051Smjacob * Other devices on the bus get the normal treatment. 3363159051Smjacob */ 3364159051Smjacob if (mpt->phydisk_sim && raid_passthru == 0 && 3365159051Smjacob mpt_is_raid_volume(mpt, tgt) != 0) { 3366159312Smjacob mpt_lprt(mpt, MPT_PRT_NEGOTIATION, 3367164837Smjacob "no transfer settings for RAID vols\n"); 3368158982Smjacob mpt_set_ccb_status(ccb, CAM_REQ_CMP); 3369158982Smjacob break; 3370158982Smjacob } 3371158982Smjacob 3372159051Smjacob i = mpt->mpt_port_page2.PortSettings & 3373159051Smjacob MPI_SCSIPORTPAGE2_PORT_MASK_NEGO_MASTER_SETTINGS; 3374159051Smjacob j = mpt->mpt_port_page2.PortFlags & 3375159051Smjacob MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK; 3376159051Smjacob if (i == MPI_SCSIPORTPAGE2_PORT_ALL_MASTER_SETTINGS && 3377159051Smjacob j == MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV) { 3378159051Smjacob mpt_lprt(mpt, MPT_PRT_ALWAYS, 3379159051Smjacob "honoring BIOS transfer negotiations\n"); 3380157662Smjacob mpt_set_ccb_status(ccb, CAM_REQ_CMP); 3381157662Smjacob break; 3382157662Smjacob } 3383157662Smjacob 3384157662Smjacob dval = 0; 3385157662Smjacob period = 0; 3386157662Smjacob offset = 0; 3387157662Smjacob 3388157662Smjacob if ((spi->valid & CTS_SPI_VALID_DISC) != 0) { 3389163816Smjacob dval |= ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) ? 3390159471Sjkim DP_DISC_ENABLE : DP_DISC_DISABL; 3391157662Smjacob } 3392147883Sscottl 3393157662Smjacob if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 3394163816Smjacob dval |= ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) ? 3395159471Sjkim DP_TQING_ENABLE : DP_TQING_DISABL; 3396157662Smjacob } 3397147883Sscottl 3398157662Smjacob if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 3399159471Sjkim dval |= (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT) ? 3400159471Sjkim DP_WIDE : DP_NARROW; 3401157662Smjacob } 3402147883Sscottl 3403163925Smjacob if (spi->valid & CTS_SPI_VALID_SYNC_OFFSET) { 3404157662Smjacob dval |= DP_SYNC; 3405157662Smjacob offset = spi->sync_offset; 3406163925Smjacob } else { 3407163925Smjacob PTR_CONFIG_PAGE_SCSI_DEVICE_1 ptr = 3408163925Smjacob &mpt->mpt_dev_page1[tgt]; 3409163925Smjacob offset = ptr->RequestedParameters; 3410163925Smjacob offset &= MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK; 3411163925Smjacob offset >>= MPI_SCSIDEVPAGE1_RP_SHIFT_MAX_SYNC_OFFSET; 3412157662Smjacob } 3413163925Smjacob if (spi->valid & CTS_SPI_VALID_SYNC_RATE) { 3414163925Smjacob dval |= DP_SYNC; 3415163925Smjacob period = spi->sync_period; 3416163925Smjacob } else { 3417163925Smjacob PTR_CONFIG_PAGE_SCSI_DEVICE_1 ptr = 3418163925Smjacob &mpt->mpt_dev_page1[tgt]; 3419163925Smjacob period = ptr->RequestedParameters; 3420163925Smjacob period &= MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK; 3421163925Smjacob period >>= MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD; 3422163925Smjacob } 3423264950Smarius 3424157662Smjacob if (dval & DP_DISC_ENABLE) { 3425157662Smjacob mpt->mpt_disc_enable |= (1 << tgt); 3426157662Smjacob } else if (dval & DP_DISC_DISABL) { 3427157662Smjacob mpt->mpt_disc_enable &= ~(1 << tgt); 3428147883Sscottl } 3429157662Smjacob if (dval & DP_TQING_ENABLE) { 3430157662Smjacob mpt->mpt_tag_enable |= (1 << tgt); 3431157662Smjacob } else if (dval & DP_TQING_DISABL) { 3432157662Smjacob mpt->mpt_tag_enable &= ~(1 << tgt); 3433157662Smjacob } 3434157662Smjacob if (dval & DP_WIDTH) { 3435157662Smjacob mpt_setwidth(mpt, tgt, 1); 3436157662Smjacob } 3437157662Smjacob if (dval & DP_SYNC) { 3438157662Smjacob mpt_setsync(mpt, tgt, period, offset); 3439157662Smjacob } 3440163925Smjacob if (dval == 0) { 3441163925Smjacob mpt_set_ccb_status(ccb, CAM_REQ_CMP); 3442163925Smjacob break; 3443163925Smjacob } 3444163816Smjacob mpt_lprt(mpt, MPT_PRT_NEGOTIATION, 3445164837Smjacob "set [%d]: 0x%x period 0x%x offset %d\n", 3446164837Smjacob tgt, dval, period, offset); 3447159051Smjacob if (mpt_update_spi_config(mpt, tgt)) { 3448159051Smjacob mpt_set_ccb_status(ccb, CAM_REQ_CMP_ERR); 3449159178Smjacob } else { 3450159178Smjacob mpt_set_ccb_status(ccb, CAM_REQ_CMP); 3451159051Smjacob } 3452147883Sscottl break; 3453157662Smjacob } 3454147883Sscottl case XPT_GET_TRAN_SETTINGS: 3455164990Smjacob { 3456165274Smjacob struct ccb_trans_settings_scsi *scsi; 3457147883Sscottl cts = &ccb->cts; 3458165274Smjacob cts->protocol = PROTO_SCSI; 3459147883Sscottl if (mpt->is_fc) { 3460147883Sscottl struct ccb_trans_settings_fc *fc = 3461147883Sscottl &cts->xport_specific.fc; 3462163816Smjacob cts->protocol_version = SCSI_REV_SPC; 3463147883Sscottl cts->transport = XPORT_FC; 3464147883Sscottl cts->transport_version = 0; 3465147883Sscottl fc->valid = CTS_FC_VALID_SPEED; 3466164837Smjacob fc->bitrate = 100000; 3467155521Smjacob } else if (mpt->is_sas) { 3468155521Smjacob struct ccb_trans_settings_sas *sas = 3469155521Smjacob &cts->xport_specific.sas; 3470163816Smjacob cts->protocol_version = SCSI_REV_SPC2; 3471155521Smjacob cts->transport = XPORT_SAS; 3472155521Smjacob cts->transport_version = 0; 3473155521Smjacob sas->valid = CTS_SAS_VALID_SPEED; 3474164837Smjacob sas->bitrate = 300000; 3475164990Smjacob } else { 3476165274Smjacob cts->protocol_version = SCSI_REV_2; 3477165274Smjacob cts->transport = XPORT_SPI; 3478165274Smjacob cts->transport_version = 2; 3479164990Smjacob if (mpt_get_spi_settings(mpt, cts) != 0) { 3480164990Smjacob mpt_set_ccb_status(ccb, CAM_REQ_CMP_ERR); 3481165274Smjacob break; 3482164990Smjacob } 3483147883Sscottl } 3484164990Smjacob scsi = &cts->proto_specific.scsi; 3485164990Smjacob scsi->valid = CTS_SCSI_VALID_TQ; 3486164990Smjacob scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; 3487157117Smjacob mpt_set_ccb_status(ccb, CAM_REQ_CMP); 3488147883Sscottl break; 3489164990Smjacob } 3490147883Sscottl case XPT_CALC_GEOMETRY: 3491147883Sscottl { 3492147883Sscottl struct ccb_calc_geometry *ccg; 3493147883Sscottl 3494147883Sscottl ccg = &ccb->ccg; 3495147883Sscottl if (ccg->block_size == 0) { 3496157117Smjacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 3497157117Smjacob mpt_set_ccb_status(ccb, CAM_REQ_INVALID); 3498147883Sscottl break; 3499147883Sscottl } 3500245983Smarius cam_calc_geometry(ccg, /* extended */ 1); 3501231629Smarius KASSERT(ccb->ccb_h.status, ("zero ccb sts at %d", __LINE__)); 3502147883Sscottl break; 3503147883Sscottl } 3504147883Sscottl case XPT_PATH_INQ: /* Path routing inquiry */ 3505147883Sscottl { 3506147883Sscottl struct ccb_pathinq *cpi = &ccb->cpi; 3507147883Sscottl 3508147883Sscottl cpi->version_num = 1; 3509147883Sscottl cpi->target_sprt = 0; 3510147883Sscottl cpi->hba_eng_cnt = 0; 3511164990Smjacob cpi->max_target = mpt->port_facts[0].MaxDevices - 1; 3512209599Sken cpi->maxio = (mpt->max_cam_seg_cnt - 1) * PAGE_SIZE; 3513159919Smjacob /* 3514164837Smjacob * FC cards report MAX_DEVICES of 512, but 3515164837Smjacob * the MSG_SCSI_IO_REQUEST target id field 3516164837Smjacob * is only 8 bits. Until we fix the driver 3517164837Smjacob * to support 'channels' for bus overflow, 3518164837Smjacob * just limit it. 3519159919Smjacob */ 3520164348Smjacob if (cpi->max_target > 255) { 3521159919Smjacob cpi->max_target = 255; 3522164348Smjacob } 3523164837Smjacob 3524159943Smjacob /* 3525164837Smjacob * VMware ESX reports > 16 devices and then dies when we probe. 3526159943Smjacob */ 3527164348Smjacob if (mpt->is_spi && cpi->max_target > 15) { 3528159943Smjacob cpi->max_target = 15; 3529164348Smjacob } 3530195275Sdelphij if (mpt->is_spi) 3531195275Sdelphij cpi->max_lun = 7; 3532195275Sdelphij else 3533195275Sdelphij cpi->max_lun = MPT_MAX_LUNS; 3534159919Smjacob cpi->initiator_id = mpt->mpt_ini_id; 3535164837Smjacob cpi->bus_id = cam_sim_bus(sim); 3536159919Smjacob 3537159919Smjacob /* 3538159919Smjacob * The base speed is the speed of the underlying connection. 3539159919Smjacob */ 3540164837Smjacob cpi->protocol = PROTO_SCSI; 3541158935Smjacob if (mpt->is_fc) { 3542252301Smarius cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED; 3543164348Smjacob cpi->base_transfer_speed = 100000; 3544147883Sscottl cpi->hba_inquiry = PI_TAG_ABLE; 3545164837Smjacob cpi->transport = XPORT_FC; 3546164837Smjacob cpi->transport_version = 0; 3547164837Smjacob cpi->protocol_version = SCSI_REV_SPC; 3548155521Smjacob } else if (mpt->is_sas) { 3549252301Smarius cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED; 3550155521Smjacob cpi->base_transfer_speed = 300000; 3551155521Smjacob cpi->hba_inquiry = PI_TAG_ABLE; 3552164837Smjacob cpi->transport = XPORT_SAS; 3553164837Smjacob cpi->transport_version = 0; 3554164837Smjacob cpi->protocol_version = SCSI_REV_SPC2; 3555147883Sscottl } else { 3556252301Smarius cpi->hba_misc = PIM_SEQSCAN | PIM_UNMAPPED; 3557147883Sscottl cpi->base_transfer_speed = 3300; 3558147883Sscottl cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; 3559164837Smjacob cpi->transport = XPORT_SPI; 3560164837Smjacob cpi->transport_version = 2; 3561164837Smjacob cpi->protocol_version = SCSI_REV_2; 3562147883Sscottl } 3563159051Smjacob 3564159051Smjacob /* 3565159051Smjacob * We give our fake RAID passhtru bus a width that is MaxVolumes 3566164837Smjacob * wide and restrict it to one lun. 3567159051Smjacob */ 3568158935Smjacob if (raid_passthru) { 3569159051Smjacob cpi->max_target = mpt->ioc_page2->MaxPhysDisks - 1; 3570159312Smjacob cpi->initiator_id = cpi->max_target + 1; 3571158982Smjacob cpi->max_lun = 0; 3572158935Smjacob } 3573147883Sscottl 3574157117Smjacob if ((mpt->role & MPT_ROLE_INITIATOR) == 0) { 3575157117Smjacob cpi->hba_misc |= PIM_NOINITIATOR; 3576157117Smjacob } 3577162059Smjacob if (mpt->is_fc && (mpt->role & MPT_ROLE_TARGET)) { 3578157117Smjacob cpi->target_sprt = 3579157117Smjacob PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO; 3580157117Smjacob } else { 3581157117Smjacob cpi->target_sprt = 0; 3582157117Smjacob } 3583147883Sscottl strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 3584147883Sscottl strncpy(cpi->hba_vid, "LSI", HBA_IDLEN); 3585147883Sscottl strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 3586147883Sscottl cpi->unit_number = cam_sim_unit(sim); 3587147883Sscottl cpi->ccb_h.status = CAM_REQ_CMP; 3588147883Sscottl break; 3589147883Sscottl } 3590157117Smjacob case XPT_EN_LUN: /* Enable LUN as a target */ 3591157117Smjacob { 3592157117Smjacob int result; 3593157117Smjacob 3594157117Smjacob if (ccb->cel.enable) 3595157117Smjacob result = mpt_enable_lun(mpt, 3596157117Smjacob ccb->ccb_h.target_id, ccb->ccb_h.target_lun); 3597157117Smjacob else 3598157117Smjacob result = mpt_disable_lun(mpt, 3599157117Smjacob ccb->ccb_h.target_id, ccb->ccb_h.target_lun); 3600157117Smjacob if (result == 0) { 3601157117Smjacob mpt_set_ccb_status(ccb, CAM_REQ_CMP); 3602157117Smjacob } else { 3603157117Smjacob mpt_set_ccb_status(ccb, CAM_REQ_CMP_ERR); 3604157117Smjacob } 3605157117Smjacob break; 3606157117Smjacob } 3607237825Sken case XPT_NOTIFY_ACKNOWLEDGE: /* recycle notify ack */ 3608237825Sken case XPT_IMMEDIATE_NOTIFY: /* Add Immediate Notify Resource */ 3609157117Smjacob case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */ 3610157117Smjacob { 3611157117Smjacob tgt_resource_t *trtp; 3612157117Smjacob lun_id_t lun = ccb->ccb_h.target_lun; 3613157117Smjacob ccb->ccb_h.sim_priv.entries[0].field = 0; 3614157117Smjacob ccb->ccb_h.sim_priv.entries[1].ptr = mpt; 3615157117Smjacob ccb->ccb_h.flags = 0; 3616157117Smjacob 3617157117Smjacob if (lun == CAM_LUN_WILDCARD) { 3618157117Smjacob if (ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) { 3619157117Smjacob mpt_set_ccb_status(ccb, CAM_REQ_INVALID); 3620157117Smjacob break; 3621157117Smjacob } 3622157117Smjacob trtp = &mpt->trt_wildcard; 3623157117Smjacob } else if (lun >= MPT_MAX_LUNS) { 3624157117Smjacob mpt_set_ccb_status(ccb, CAM_REQ_INVALID); 3625157117Smjacob break; 3626157117Smjacob } else { 3627157117Smjacob trtp = &mpt->trt[lun]; 3628157117Smjacob } 3629157117Smjacob if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 3630157117Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG1, 3631157117Smjacob "Put FREE ATIO %p lun %d\n", ccb, lun); 3632157117Smjacob STAILQ_INSERT_TAIL(&trtp->atios, &ccb->ccb_h, 3633157117Smjacob sim_links.stqe); 3634237825Sken } else if (ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) { 3635157117Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG1, 3636157117Smjacob "Put FREE INOT lun %d\n", lun); 3637157117Smjacob STAILQ_INSERT_TAIL(&trtp->inots, &ccb->ccb_h, 3638157117Smjacob sim_links.stqe); 3639157117Smjacob } else { 3640157117Smjacob mpt_lprt(mpt, MPT_PRT_ALWAYS, "Got Notify ACK\n"); 3641157117Smjacob } 3642157117Smjacob mpt_set_ccb_status(ccb, CAM_REQ_INPROG); 3643159919Smjacob return; 3644157117Smjacob } 3645157117Smjacob case XPT_CONT_TARGET_IO: 3646157117Smjacob mpt_target_start_io(mpt, ccb); 3647159919Smjacob return; 3648159919Smjacob 3649147883Sscottl default: 3650147883Sscottl ccb->ccb_h.status = CAM_REQ_INVALID; 3651147883Sscottl break; 3652147883Sscottl } 3653158935Smjacob xpt_done(ccb); 3654147883Sscottl} 3655147883Sscottl 3656147883Sscottlstatic int 3657157662Smjacobmpt_get_spi_settings(struct mpt_softc *mpt, struct ccb_trans_settings *cts) 3658147883Sscottl{ 3659158982Smjacob struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi; 3660158982Smjacob struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi; 3661158982Smjacob target_id_t tgt; 3662164846Smjacob uint32_t dval, pval, oval; 3663147883Sscottl int rv; 3664147883Sscottl 3665165274Smjacob if (IS_CURRENT_SETTINGS(cts) == 0) { 3666164837Smjacob tgt = cts->ccb_h.target_id; 3667164837Smjacob } else if (xpt_path_sim(cts->ccb_h.path) == mpt->phydisk_sim) { 3668159051Smjacob if (mpt_map_physdisk(mpt, (union ccb *)cts, &tgt)) { 3669159051Smjacob return (-1); 3670158982Smjacob } 3671159051Smjacob } else { 3672159051Smjacob tgt = cts->ccb_h.target_id; 3673158982Smjacob } 3674157662Smjacob 3675157662Smjacob /* 3676164837Smjacob * We aren't looking at Port Page 2 BIOS settings here- 3677164837Smjacob * sometimes these have been known to be bogus XXX. 3678164837Smjacob * 3679164837Smjacob * For user settings, we pick the max from port page 0 3680159178Smjacob * 3681159178Smjacob * For current settings we read the current settings out from 3682159178Smjacob * device page 0 for that target. 3683157662Smjacob */ 3684157662Smjacob if (IS_CURRENT_SETTINGS(cts)) { 3685157662Smjacob CONFIG_PAGE_SCSI_DEVICE_0 tmp; 3686157662Smjacob dval = 0; 3687157662Smjacob 3688157662Smjacob tmp = mpt->mpt_dev_page0[tgt]; 3689157662Smjacob rv = mpt_read_cur_cfg_page(mpt, tgt, &tmp.Header, 3690157662Smjacob sizeof(tmp), FALSE, 5000); 3691157662Smjacob if (rv) { 3692157662Smjacob mpt_prt(mpt, "can't get tgt %d config page 0\n", tgt); 3693157662Smjacob return (rv); 3694157662Smjacob } 3695186878Smarius mpt2host_config_page_scsi_device_0(&tmp); 3696186878Smarius 3697164837Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 3698164837Smjacob "mpt_get_spi_settings[%d]: current NP %x Info %x\n", tgt, 3699164837Smjacob tmp.NegotiatedParameters, tmp.Information); 3700159471Sjkim dval |= (tmp.NegotiatedParameters & MPI_SCSIDEVPAGE0_NP_WIDE) ? 3701159471Sjkim DP_WIDE : DP_NARROW; 3702159471Sjkim dval |= (mpt->mpt_disc_enable & (1 << tgt)) ? 3703159471Sjkim DP_DISC_ENABLE : DP_DISC_DISABL; 3704159471Sjkim dval |= (mpt->mpt_tag_enable & (1 << tgt)) ? 3705159471Sjkim DP_TQING_ENABLE : DP_TQING_DISABL; 3706164837Smjacob oval = tmp.NegotiatedParameters; 3707164837Smjacob oval &= MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK; 3708164837Smjacob oval >>= MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_OFFSET; 3709164837Smjacob pval = tmp.NegotiatedParameters; 3710164837Smjacob pval &= MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK; 3711164837Smjacob pval >>= MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_PERIOD; 3712159178Smjacob mpt->mpt_dev_page0[tgt] = tmp; 3713147883Sscottl } else { 3714164846Smjacob dval = DP_WIDE|DP_DISC_ENABLE|DP_TQING_ENABLE|DP_SYNC; 3715164837Smjacob oval = mpt->mpt_port_page0.Capabilities; 3716164837Smjacob oval = MPI_SCSIPORTPAGE0_CAP_GET_MAX_SYNC_OFFSET(oval); 3717164837Smjacob pval = mpt->mpt_port_page0.Capabilities; 3718164837Smjacob pval = MPI_SCSIPORTPAGE0_CAP_GET_MIN_SYNC_PERIOD(pval); 3719147883Sscottl } 3720157662Smjacob 3721164837Smjacob spi->valid = 0; 3722164837Smjacob scsi->valid = 0; 3723164837Smjacob spi->flags = 0; 3724164837Smjacob scsi->flags = 0; 3725164846Smjacob spi->sync_offset = oval; 3726164846Smjacob spi->sync_period = pval; 3727164846Smjacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 3728164846Smjacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 3729157662Smjacob spi->valid |= CTS_SPI_VALID_BUS_WIDTH; 3730157662Smjacob if (dval & DP_WIDE) { 3731157662Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 3732157662Smjacob } else { 3733157662Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 3734157662Smjacob } 3735157662Smjacob if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { 3736157662Smjacob scsi->valid = CTS_SCSI_VALID_TQ; 3737164846Smjacob if (dval & DP_TQING_ENABLE) { 3738164846Smjacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 3739164846Smjacob } 3740157662Smjacob spi->valid |= CTS_SPI_VALID_DISC; 3741164846Smjacob if (dval & DP_DISC_ENABLE) { 3742164846Smjacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 3743164846Smjacob } 3744157662Smjacob } 3745264950Smarius 3746159051Smjacob mpt_lprt(mpt, MPT_PRT_NEGOTIATION, 3747164846Smjacob "mpt_get_spi_settings[%d]: %s flags 0x%x per 0x%x off=%d\n", tgt, 3748264950Smarius IS_CURRENT_SETTINGS(cts) ? "ACTIVE" : "NVRAM ", dval, pval, oval); 3749147883Sscottl return (0); 3750147883Sscottl} 3751147883Sscottl 3752157662Smjacobstatic void 3753157662Smjacobmpt_setwidth(struct mpt_softc *mpt, int tgt, int onoff) 3754157662Smjacob{ 3755159051Smjacob PTR_CONFIG_PAGE_SCSI_DEVICE_1 ptr; 3756157662Smjacob 3757159051Smjacob ptr = &mpt->mpt_dev_page1[tgt]; 3758157662Smjacob if (onoff) { 3759159051Smjacob ptr->RequestedParameters |= MPI_SCSIDEVPAGE1_RP_WIDE; 3760157662Smjacob } else { 3761159051Smjacob ptr->RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_WIDE; 3762157662Smjacob } 3763157662Smjacob} 3764157662Smjacob 3765157662Smjacobstatic void 3766147883Sscottlmpt_setsync(struct mpt_softc *mpt, int tgt, int period, int offset) 3767147883Sscottl{ 3768159051Smjacob PTR_CONFIG_PAGE_SCSI_DEVICE_1 ptr; 3769147883Sscottl 3770159051Smjacob ptr = &mpt->mpt_dev_page1[tgt]; 3771159051Smjacob ptr->RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK; 3772159051Smjacob ptr->RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK; 3773159051Smjacob ptr->RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_DT; 3774159051Smjacob ptr->RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_QAS; 3775159051Smjacob ptr->RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_IU; 3776163925Smjacob if (period == 0) { 3777163925Smjacob return; 3778163925Smjacob } 3779163925Smjacob ptr->RequestedParameters |= 3780163925Smjacob period << MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD; 3781163925Smjacob ptr->RequestedParameters |= 3782163925Smjacob offset << MPI_SCSIDEVPAGE1_RP_SHIFT_MAX_SYNC_OFFSET; 3783159178Smjacob if (period < 0xa) { 3784159178Smjacob ptr->RequestedParameters |= MPI_SCSIDEVPAGE1_RP_DT; 3785147883Sscottl } 3786159178Smjacob if (period < 0x9) { 3787159178Smjacob ptr->RequestedParameters |= MPI_SCSIDEVPAGE1_RP_QAS; 3788159178Smjacob ptr->RequestedParameters |= MPI_SCSIDEVPAGE1_RP_IU; 3789159178Smjacob } 3790157662Smjacob} 3791157662Smjacob 3792157662Smjacobstatic int 3793157662Smjacobmpt_update_spi_config(struct mpt_softc *mpt, int tgt) 3794157662Smjacob{ 3795157662Smjacob CONFIG_PAGE_SCSI_DEVICE_1 tmp; 3796157662Smjacob int rv; 3797157662Smjacob 3798159178Smjacob mpt_lprt(mpt, MPT_PRT_NEGOTIATION, 3799159178Smjacob "mpt_update_spi_config[%d].page1: Requested Params 0x%08x\n", 3800159178Smjacob tgt, mpt->mpt_dev_page1[tgt].RequestedParameters); 3801157662Smjacob tmp = mpt->mpt_dev_page1[tgt]; 3802186878Smarius host2mpt_config_page_scsi_device_1(&tmp); 3803157662Smjacob rv = mpt_write_cur_cfg_page(mpt, tgt, 3804157662Smjacob &tmp.Header, sizeof(tmp), FALSE, 5000); 3805147883Sscottl if (rv) { 3806157662Smjacob mpt_prt(mpt, "mpt_update_spi_config: write cur page failed\n"); 3807147883Sscottl return (-1); 3808147883Sscottl } 3809147883Sscottl return (0); 3810147883Sscottl} 3811147883Sscottl 3812147883Sscottl/****************************** Timeout Recovery ******************************/ 3813147883Sscottlstatic int 3814147883Sscottlmpt_spawn_recovery_thread(struct mpt_softc *mpt) 3815147883Sscottl{ 3816147883Sscottl int error; 3817147883Sscottl 3818264950Smarius error = kproc_create(mpt_recovery_thread, mpt, 3819147883Sscottl &mpt->recovery_thread, /*flags*/0, 3820147883Sscottl /*altstack*/0, "mpt_recovery%d", mpt->unit); 3821147883Sscottl return (error); 3822147883Sscottl} 3823147883Sscottl 3824147883Sscottlstatic void 3825147883Sscottlmpt_terminate_recovery_thread(struct mpt_softc *mpt) 3826147883Sscottl{ 3827224493Smarius 3828147883Sscottl if (mpt->recovery_thread == NULL) { 3829147883Sscottl return; 3830147883Sscottl } 3831147883Sscottl mpt->shutdwn_recovery = 1; 3832147883Sscottl wakeup(mpt); 3833147883Sscottl /* 3834147883Sscottl * Sleep on a slightly different location 3835147883Sscottl * for this interlock just for added safety. 3836147883Sscottl */ 3837147883Sscottl mpt_sleep(mpt, &mpt->recovery_thread, PUSER, "thtrm", 0); 3838147883Sscottl} 3839147883Sscottl 3840147883Sscottlstatic void 3841147883Sscottlmpt_recovery_thread(void *arg) 3842147883Sscottl{ 3843147883Sscottl struct mpt_softc *mpt; 3844147883Sscottl 3845147883Sscottl mpt = (struct mpt_softc *)arg; 3846147883Sscottl MPT_LOCK(mpt); 3847147883Sscottl for (;;) { 3848157662Smjacob if (TAILQ_EMPTY(&mpt->request_timeout_list) != 0) { 3849157662Smjacob if (mpt->shutdwn_recovery == 0) { 3850157662Smjacob mpt_sleep(mpt, mpt, PUSER, "idle", 0); 3851157662Smjacob } 3852157662Smjacob } 3853157117Smjacob if (mpt->shutdwn_recovery != 0) { 3854147883Sscottl break; 3855157117Smjacob } 3856147883Sscottl mpt_recover_commands(mpt); 3857147883Sscottl } 3858147883Sscottl mpt->recovery_thread = NULL; 3859147883Sscottl wakeup(&mpt->recovery_thread); 3860147883Sscottl MPT_UNLOCK(mpt); 3861264950Smarius kproc_exit(0); 3862147883Sscottl} 3863147883Sscottl 3864147883Sscottlstatic int 3865157354Smjacobmpt_scsi_send_tmf(struct mpt_softc *mpt, u_int type, u_int flags, 3866157354Smjacob u_int channel, u_int target, u_int lun, u_int abort_ctx, int sleep_ok) 3867147883Sscottl{ 3868147883Sscottl MSG_SCSI_TASK_MGMT *tmf_req; 3869147883Sscottl int error; 3870147883Sscottl 3871147883Sscottl /* 3872147883Sscottl * Wait for any current TMF request to complete. 3873147883Sscottl * We're only allowed to issue one TMF at a time. 3874147883Sscottl */ 3875157662Smjacob error = mpt_wait_req(mpt, mpt->tmf_req, REQ_STATE_FREE, REQ_STATE_FREE, 3876147883Sscottl sleep_ok, MPT_TMF_MAX_TIMEOUT); 3877147883Sscottl if (error != 0) { 3878157354Smjacob mpt_reset(mpt, TRUE); 3879147883Sscottl return (ETIMEDOUT); 3880147883Sscottl } 3881147883Sscottl 3882157662Smjacob mpt_assign_serno(mpt, mpt->tmf_req); 3883147883Sscottl mpt->tmf_req->state = REQ_STATE_ALLOCATED|REQ_STATE_QUEUED; 3884147883Sscottl 3885147883Sscottl tmf_req = (MSG_SCSI_TASK_MGMT *)mpt->tmf_req->req_vbuf; 3886157354Smjacob memset(tmf_req, 0, sizeof(*tmf_req)); 3887147883Sscottl tmf_req->TargetID = target; 3888147883Sscottl tmf_req->Bus = channel; 3889147883Sscottl tmf_req->Function = MPI_FUNCTION_SCSI_TASK_MGMT; 3890147883Sscottl tmf_req->TaskType = type; 3891147883Sscottl tmf_req->MsgFlags = flags; 3892147883Sscottl tmf_req->MsgContext = 3893147883Sscottl htole32(mpt->tmf_req->index | scsi_tmf_handler_id); 3894195274Sdelphij if (lun > MPT_MAX_LUNS) { 3895157354Smjacob tmf_req->LUN[0] = 0x40 | ((lun >> 8) & 0x3f); 3896157354Smjacob tmf_req->LUN[1] = lun & 0xff; 3897157354Smjacob } else { 3898157354Smjacob tmf_req->LUN[1] = lun; 3899157354Smjacob } 3900147883Sscottl tmf_req->TaskMsgContext = abort_ctx; 3901147883Sscottl 3902164415Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 3903157354Smjacob "Issuing TMF %p:%u with MsgContext of 0x%x\n", mpt->tmf_req, 3904157354Smjacob mpt->tmf_req->serno, tmf_req->MsgContext); 3905157662Smjacob if (mpt->verbose > MPT_PRT_DEBUG) { 3906147883Sscottl mpt_print_request(tmf_req); 3907157662Smjacob } 3908147883Sscottl 3909157662Smjacob KASSERT(mpt_req_on_pending_list(mpt, mpt->tmf_req) == 0, 3910157662Smjacob ("mpt_scsi_send_tmf: tmf_req already on pending list")); 3911157662Smjacob TAILQ_INSERT_HEAD(&mpt->request_pending_list, mpt->tmf_req, links); 3912157662Smjacob error = mpt_send_handshake_cmd(mpt, sizeof(*tmf_req), tmf_req); 3913157117Smjacob if (error != MPT_OK) { 3914164415Smjacob TAILQ_REMOVE(&mpt->request_pending_list, mpt->tmf_req, links); 3915164415Smjacob mpt->tmf_req->state = REQ_STATE_FREE; 3916157354Smjacob mpt_reset(mpt, TRUE); 3917157117Smjacob } 3918147883Sscottl return (error); 3919147883Sscottl} 3920147883Sscottl 3921157354Smjacob/* 3922157354Smjacob * When a command times out, it is placed on the requeust_timeout_list 3923157354Smjacob * and we wake our recovery thread. The MPT-Fusion architecture supports 3924157354Smjacob * only a single TMF operation at a time, so we serially abort/bdr, etc, 3925157354Smjacob * the timedout transactions. The next TMF is issued either by the 3926157354Smjacob * completion handler of the current TMF waking our recovery thread, 3927157354Smjacob * or the TMF timeout handler causing a hard reset sequence. 3928157354Smjacob */ 3929157117Smjacobstatic void 3930157354Smjacobmpt_recover_commands(struct mpt_softc *mpt) 3931157354Smjacob{ 3932157354Smjacob request_t *req; 3933157354Smjacob union ccb *ccb; 3934157354Smjacob int error; 3935157354Smjacob 3936157354Smjacob if (TAILQ_EMPTY(&mpt->request_timeout_list) != 0) { 3937157354Smjacob /* 3938157354Smjacob * No work to do- leave. 3939157354Smjacob */ 3940157354Smjacob mpt_prt(mpt, "mpt_recover_commands: no requests.\n"); 3941157354Smjacob return; 3942157354Smjacob } 3943157354Smjacob 3944157354Smjacob /* 3945157354Smjacob * Flush any commands whose completion coincides with their timeout. 3946157354Smjacob */ 3947157354Smjacob mpt_intr(mpt); 3948157354Smjacob 3949157354Smjacob if (TAILQ_EMPTY(&mpt->request_timeout_list) != 0) { 3950157354Smjacob /* 3951157354Smjacob * The timedout commands have already 3952157354Smjacob * completed. This typically means 3953157354Smjacob * that either the timeout value was on 3954157354Smjacob * the hairy edge of what the device 3955157354Smjacob * requires or - more likely - interrupts 3956157354Smjacob * are not happening. 3957157354Smjacob */ 3958157354Smjacob mpt_prt(mpt, "Timedout requests already complete. " 3959157853Smjacob "Interrupts may not be functioning.\n"); 3960157853Smjacob mpt_enable_ints(mpt); 3961157853Smjacob return; 3962157354Smjacob } 3963157354Smjacob 3964157354Smjacob /* 3965157354Smjacob * We have no visibility into the current state of the 3966157354Smjacob * controller, so attempt to abort the commands in the 3967157662Smjacob * order they timed-out. For initiator commands, we 3968157662Smjacob * depend on the reply handler pulling requests off 3969157662Smjacob * the timeout list. 3970157354Smjacob */ 3971157354Smjacob while ((req = TAILQ_FIRST(&mpt->request_timeout_list)) != NULL) { 3972157662Smjacob uint16_t status; 3973157662Smjacob uint8_t response; 3974157662Smjacob MSG_REQUEST_HEADER *hdrp = req->req_vbuf; 3975157354Smjacob 3976157662Smjacob mpt_prt(mpt, "attempting to abort req %p:%u function %x\n", 3977157662Smjacob req, req->serno, hdrp->Function); 3978157354Smjacob ccb = req->ccb; 3979157662Smjacob if (ccb == NULL) { 3980157662Smjacob mpt_prt(mpt, "null ccb in timed out request. " 3981157662Smjacob "Resetting Controller.\n"); 3982157662Smjacob mpt_reset(mpt, TRUE); 3983157662Smjacob continue; 3984157662Smjacob } 3985157354Smjacob mpt_set_ccb_status(ccb, CAM_CMD_TIMEOUT); 3986157662Smjacob 3987157662Smjacob /* 3988157662Smjacob * Check to see if this is not an initiator command and 3989157662Smjacob * deal with it differently if it is. 3990157662Smjacob */ 3991157662Smjacob switch (hdrp->Function) { 3992157662Smjacob case MPI_FUNCTION_SCSI_IO_REQUEST: 3993158935Smjacob case MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: 3994157662Smjacob break; 3995157662Smjacob default: 3996157662Smjacob /* 3997157662Smjacob * XXX: FIX ME: need to abort target assists... 3998157662Smjacob */ 3999157662Smjacob mpt_prt(mpt, "just putting it back on the pend q\n"); 4000157662Smjacob TAILQ_REMOVE(&mpt->request_timeout_list, req, links); 4001157662Smjacob TAILQ_INSERT_HEAD(&mpt->request_pending_list, req, 4002157662Smjacob links); 4003157662Smjacob continue; 4004157662Smjacob } 4005157662Smjacob 4006157354Smjacob error = mpt_scsi_send_tmf(mpt, 4007157354Smjacob MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, 4008157354Smjacob 0, 0, ccb->ccb_h.target_id, ccb->ccb_h.target_lun, 4009157354Smjacob htole32(req->index | scsi_io_handler_id), TRUE); 4010157354Smjacob 4011157354Smjacob if (error != 0) { 4012157354Smjacob /* 4013157354Smjacob * mpt_scsi_send_tmf hard resets on failure, so no 4014157354Smjacob * need to do so here. Our queue should be emptied 4015157354Smjacob * by the hard reset. 4016157354Smjacob */ 4017157354Smjacob continue; 4018157354Smjacob } 4019157354Smjacob 4020157354Smjacob error = mpt_wait_req(mpt, mpt->tmf_req, REQ_STATE_DONE, 4021157354Smjacob REQ_STATE_DONE, TRUE, 500); 4022157354Smjacob 4023186878Smarius status = le16toh(mpt->tmf_req->IOCStatus); 4024157662Smjacob response = mpt->tmf_req->ResponseCode; 4025157662Smjacob mpt->tmf_req->state = REQ_STATE_FREE; 4026157662Smjacob 4027157354Smjacob if (error != 0) { 4028157354Smjacob /* 4029157662Smjacob * If we've errored out,, reset the controller. 4030157354Smjacob */ 4031157354Smjacob mpt_prt(mpt, "mpt_recover_commands: abort timed-out. " 4032157662Smjacob "Resetting controller\n"); 4033157354Smjacob mpt_reset(mpt, TRUE); 4034157354Smjacob continue; 4035157354Smjacob } 4036157354Smjacob 4037157662Smjacob if ((status & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 4038157662Smjacob mpt_prt(mpt, "mpt_recover_commands: IOC Status 0x%x. " 4039157662Smjacob "Resetting controller.\n", status); 4040157662Smjacob mpt_reset(mpt, TRUE); 4041157662Smjacob continue; 4042157662Smjacob } 4043157354Smjacob 4044157662Smjacob if (response != MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED && 4045157662Smjacob response != MPI_SCSITASKMGMT_RSP_TM_COMPLETE) { 4046157662Smjacob mpt_prt(mpt, "mpt_recover_commands: TMF Response 0x%x. " 4047157662Smjacob "Resetting controller.\n", response); 4048157662Smjacob mpt_reset(mpt, TRUE); 4049157354Smjacob continue; 4050157354Smjacob } 4051157662Smjacob mpt_prt(mpt, "abort of req %p:%u completed\n", req, req->serno); 4052157354Smjacob } 4053157354Smjacob} 4054157354Smjacob 4055157354Smjacob/************************ Target Mode Support ****************************/ 4056157354Smjacobstatic void 4057157662Smjacobmpt_fc_post_els(struct mpt_softc *mpt, request_t *req, int ioindex) 4058157117Smjacob{ 4059157117Smjacob MSG_LINK_SERVICE_BUFFER_POST_REQUEST *fc; 4060157117Smjacob PTR_SGE_TRANSACTION32 tep; 4061157117Smjacob PTR_SGE_SIMPLE32 se; 4062157117Smjacob bus_addr_t paddr; 4063164315Sjb uint32_t fl; 4064157117Smjacob 4065157117Smjacob paddr = req->req_pbuf; 4066157117Smjacob paddr += MPT_RQSL(mpt); 4067157117Smjacob 4068157117Smjacob fc = req->req_vbuf; 4069157117Smjacob memset(fc, 0, MPT_REQUEST_AREA); 4070157117Smjacob fc->BufferCount = 1; 4071157117Smjacob fc->Function = MPI_FUNCTION_FC_LINK_SRVC_BUF_POST; 4072157117Smjacob fc->MsgContext = htole32(req->index | fc_els_handler_id); 4073157117Smjacob 4074157117Smjacob /* 4075157117Smjacob * Okay, set up ELS buffer pointers. ELS buffer pointers 4076157117Smjacob * consist of a TE SGL element (with details length of zero) 4077209599Sken * followed by a SIMPLE SGL element which holds the address 4078157117Smjacob * of the buffer. 4079157117Smjacob */ 4080157117Smjacob 4081157117Smjacob tep = (PTR_SGE_TRANSACTION32) &fc->SGL; 4082157117Smjacob 4083157117Smjacob tep->ContextSize = 4; 4084157117Smjacob tep->Flags = 0; 4085157662Smjacob tep->TransactionContext[0] = htole32(ioindex); 4086157117Smjacob 4087157117Smjacob se = (PTR_SGE_SIMPLE32) &tep->TransactionDetails[0]; 4088164315Sjb fl = 4089157117Smjacob MPI_SGE_FLAGS_HOST_TO_IOC | 4090157117Smjacob MPI_SGE_FLAGS_SIMPLE_ELEMENT | 4091157117Smjacob MPI_SGE_FLAGS_LAST_ELEMENT | 4092157117Smjacob MPI_SGE_FLAGS_END_OF_LIST | 4093157117Smjacob MPI_SGE_FLAGS_END_OF_BUFFER; 4094164315Sjb fl <<= MPI_SGE_FLAGS_SHIFT; 4095164315Sjb fl |= (MPT_NRFM(mpt) - MPT_RQSL(mpt)); 4096164315Sjb se->FlagsLength = htole32(fl); 4097164315Sjb se->Address = htole32((uint32_t) paddr); 4098158278Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 4099157662Smjacob "add ELS index %d ioindex %d for %p:%u\n", 4100157662Smjacob req->index, ioindex, req, req->serno); 4101157662Smjacob KASSERT(((req->state & REQ_STATE_LOCKED) != 0), 4102157662Smjacob ("mpt_fc_post_els: request not locked")); 4103157117Smjacob mpt_send_cmd(mpt, req); 4104157117Smjacob} 4105157117Smjacob 4106157117Smjacobstatic void 4107157117Smjacobmpt_post_target_command(struct mpt_softc *mpt, request_t *req, int ioindex) 4108157117Smjacob{ 4109157117Smjacob PTR_MSG_TARGET_CMD_BUFFER_POST_REQUEST fc; 4110157117Smjacob PTR_CMD_BUFFER_DESCRIPTOR cb; 4111157117Smjacob bus_addr_t paddr; 4112157117Smjacob 4113157117Smjacob paddr = req->req_pbuf; 4114157117Smjacob paddr += MPT_RQSL(mpt); 4115157117Smjacob memset(req->req_vbuf, 0, MPT_REQUEST_AREA); 4116157354Smjacob MPT_TGT_STATE(mpt, req)->state = TGT_STATE_LOADING; 4117157117Smjacob 4118157117Smjacob fc = req->req_vbuf; 4119157117Smjacob fc->BufferCount = 1; 4120157117Smjacob fc->Function = MPI_FUNCTION_TARGET_CMD_BUFFER_POST; 4121157117Smjacob fc->MsgContext = htole32(req->index | mpt->scsi_tgt_handler_id); 4122157117Smjacob 4123157117Smjacob cb = &fc->Buffer[0]; 4124157117Smjacob cb->IoIndex = htole16(ioindex); 4125164315Sjb cb->u.PhysicalAddress32 = htole32((U32) paddr); 4126157117Smjacob 4127157117Smjacob mpt_check_doorbell(mpt); 4128157117Smjacob mpt_send_cmd(mpt, req); 4129157117Smjacob} 4130157117Smjacob 4131157662Smjacobstatic int 4132157662Smjacobmpt_add_els_buffers(struct mpt_softc *mpt) 4133157662Smjacob{ 4134157662Smjacob int i; 4135157662Smjacob 4136157662Smjacob if (mpt->is_fc == 0) { 4137157662Smjacob return (TRUE); 4138157662Smjacob } 4139157662Smjacob 4140157662Smjacob if (mpt->els_cmds_allocated) { 4141157662Smjacob return (TRUE); 4142157662Smjacob } 4143157662Smjacob 4144157662Smjacob mpt->els_cmd_ptrs = malloc(MPT_MAX_ELS * sizeof (request_t *), 4145157662Smjacob M_DEVBUF, M_NOWAIT | M_ZERO); 4146157662Smjacob 4147157662Smjacob if (mpt->els_cmd_ptrs == NULL) { 4148157662Smjacob return (FALSE); 4149157662Smjacob } 4150157662Smjacob 4151157662Smjacob /* 4152157662Smjacob * Feed the chip some ELS buffer resources 4153157662Smjacob */ 4154157662Smjacob for (i = 0; i < MPT_MAX_ELS; i++) { 4155157662Smjacob request_t *req = mpt_get_request(mpt, FALSE); 4156157662Smjacob if (req == NULL) { 4157157662Smjacob break; 4158157662Smjacob } 4159157662Smjacob req->state |= REQ_STATE_LOCKED; 4160157662Smjacob mpt->els_cmd_ptrs[i] = req; 4161157662Smjacob mpt_fc_post_els(mpt, req, i); 4162157662Smjacob } 4163157662Smjacob 4164157662Smjacob if (i == 0) { 4165157662Smjacob mpt_prt(mpt, "unable to add ELS buffer resources\n"); 4166157662Smjacob free(mpt->els_cmd_ptrs, M_DEVBUF); 4167157662Smjacob mpt->els_cmd_ptrs = NULL; 4168157662Smjacob return (FALSE); 4169157662Smjacob } 4170157662Smjacob if (i != MPT_MAX_ELS) { 4171157662Smjacob mpt_lprt(mpt, MPT_PRT_INFO, 4172157662Smjacob "only added %d of %d ELS buffers\n", i, MPT_MAX_ELS); 4173157662Smjacob } 4174157662Smjacob mpt->els_cmds_allocated = i; 4175157662Smjacob return(TRUE); 4176157662Smjacob} 4177157662Smjacob 4178157662Smjacobstatic int 4179157117Smjacobmpt_add_target_commands(struct mpt_softc *mpt) 4180157117Smjacob{ 4181157117Smjacob int i, max; 4182157117Smjacob 4183157117Smjacob if (mpt->tgt_cmd_ptrs) { 4184157662Smjacob return (TRUE); 4185157117Smjacob } 4186157117Smjacob 4187157117Smjacob max = MPT_MAX_REQUESTS(mpt) >> 1; 4188157117Smjacob if (max > mpt->mpt_max_tgtcmds) { 4189157117Smjacob max = mpt->mpt_max_tgtcmds; 4190157117Smjacob } 4191157117Smjacob mpt->tgt_cmd_ptrs = 4192157662Smjacob malloc(max * sizeof (request_t *), M_DEVBUF, M_NOWAIT | M_ZERO); 4193157117Smjacob if (mpt->tgt_cmd_ptrs == NULL) { 4194157662Smjacob mpt_prt(mpt, 4195157662Smjacob "mpt_add_target_commands: could not allocate cmd ptrs\n"); 4196157662Smjacob return (FALSE); 4197157117Smjacob } 4198157117Smjacob 4199157117Smjacob for (i = 0; i < max; i++) { 4200157117Smjacob request_t *req; 4201157117Smjacob 4202157117Smjacob req = mpt_get_request(mpt, FALSE); 4203157117Smjacob if (req == NULL) { 4204157117Smjacob break; 4205157117Smjacob } 4206157354Smjacob req->state |= REQ_STATE_LOCKED; 4207157117Smjacob mpt->tgt_cmd_ptrs[i] = req; 4208157117Smjacob mpt_post_target_command(mpt, req, i); 4209157117Smjacob } 4210157117Smjacob 4211157662Smjacob 4212157117Smjacob if (i == 0) { 4213157117Smjacob mpt_lprt(mpt, MPT_PRT_ERROR, "could not add any target bufs\n"); 4214157117Smjacob free(mpt->tgt_cmd_ptrs, M_DEVBUF); 4215157117Smjacob mpt->tgt_cmd_ptrs = NULL; 4216157662Smjacob return (FALSE); 4217157117Smjacob } 4218157662Smjacob 4219157662Smjacob mpt->tgt_cmds_allocated = i; 4220157662Smjacob 4221157662Smjacob if (i < max) { 4222157662Smjacob mpt_lprt(mpt, MPT_PRT_INFO, 4223157662Smjacob "added %d of %d target bufs\n", i, max); 4224157662Smjacob } 4225157662Smjacob return (i); 4226157117Smjacob} 4227157117Smjacob 4228157117Smjacobstatic int 4229157117Smjacobmpt_enable_lun(struct mpt_softc *mpt, target_id_t tgt, lun_id_t lun) 4230157117Smjacob{ 4231224493Smarius 4232157117Smjacob if (tgt == CAM_TARGET_WILDCARD && lun == CAM_LUN_WILDCARD) { 4233157117Smjacob mpt->twildcard = 1; 4234157117Smjacob } else if (lun >= MPT_MAX_LUNS) { 4235157117Smjacob return (EINVAL); 4236157117Smjacob } else if (tgt != CAM_TARGET_WILDCARD && tgt != 0) { 4237157117Smjacob return (EINVAL); 4238157117Smjacob } 4239157117Smjacob if (mpt->tenabled == 0) { 4240157117Smjacob if (mpt->is_fc) { 4241157117Smjacob (void) mpt_fc_reset_link(mpt, 0); 4242157117Smjacob } 4243157117Smjacob mpt->tenabled = 1; 4244157117Smjacob } 4245157117Smjacob if (lun == CAM_LUN_WILDCARD) { 4246157117Smjacob mpt->trt_wildcard.enabled = 1; 4247157117Smjacob } else { 4248157117Smjacob mpt->trt[lun].enabled = 1; 4249157117Smjacob } 4250157117Smjacob return (0); 4251157117Smjacob} 4252157117Smjacob 4253157117Smjacobstatic int 4254157117Smjacobmpt_disable_lun(struct mpt_softc *mpt, target_id_t tgt, lun_id_t lun) 4255157117Smjacob{ 4256157117Smjacob int i; 4257224493Smarius 4258157117Smjacob if (tgt == CAM_TARGET_WILDCARD && lun == CAM_LUN_WILDCARD) { 4259157117Smjacob mpt->twildcard = 0; 4260157117Smjacob } else if (lun >= MPT_MAX_LUNS) { 4261157117Smjacob return (EINVAL); 4262157117Smjacob } else if (tgt != CAM_TARGET_WILDCARD && tgt != 0) { 4263157117Smjacob return (EINVAL); 4264157117Smjacob } 4265157117Smjacob if (lun == CAM_LUN_WILDCARD) { 4266157117Smjacob mpt->trt_wildcard.enabled = 0; 4267157117Smjacob } else { 4268157117Smjacob mpt->trt[lun].enabled = 0; 4269157117Smjacob } 4270157117Smjacob for (i = 0; i < MPT_MAX_LUNS; i++) { 4271157117Smjacob if (mpt->trt[lun].enabled) { 4272157117Smjacob break; 4273157117Smjacob } 4274157117Smjacob } 4275157117Smjacob if (i == MPT_MAX_LUNS && mpt->twildcard == 0) { 4276157117Smjacob if (mpt->is_fc) { 4277157117Smjacob (void) mpt_fc_reset_link(mpt, 0); 4278157117Smjacob } 4279157662Smjacob mpt->tenabled = 0; 4280157117Smjacob } 4281157117Smjacob return (0); 4282157117Smjacob} 4283157117Smjacob 4284147883Sscottl/* 4285157117Smjacob * Called with MPT lock held 4286157117Smjacob */ 4287157117Smjacobstatic void 4288157117Smjacobmpt_target_start_io(struct mpt_softc *mpt, union ccb *ccb) 4289157117Smjacob{ 4290157117Smjacob struct ccb_scsiio *csio = &ccb->csio; 4291157117Smjacob request_t *cmd_req = MPT_TAG_2_REQ(mpt, csio->tag_id); 4292157117Smjacob mpt_tgt_state_t *tgt = MPT_TGT_STATE(mpt, cmd_req); 4293157117Smjacob 4294157662Smjacob switch (tgt->state) { 4295157662Smjacob case TGT_STATE_IN_CAM: 4296157662Smjacob break; 4297157662Smjacob case TGT_STATE_MOVING_DATA: 4298157662Smjacob mpt_set_ccb_status(ccb, CAM_REQUEUE_REQ); 4299157662Smjacob xpt_freeze_simq(mpt->sim, 1); 4300157662Smjacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 4301157662Smjacob tgt->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 4302157662Smjacob xpt_done(ccb); 4303157662Smjacob return; 4304157662Smjacob default: 4305157662Smjacob mpt_prt(mpt, "ccb %p flags 0x%x tag 0x%08x had bad request " 4306157662Smjacob "starting I/O\n", ccb, csio->ccb_h.flags, csio->tag_id); 4307157354Smjacob mpt_tgt_dump_req_state(mpt, cmd_req); 4308157354Smjacob mpt_set_ccb_status(ccb, CAM_REQ_CMP_ERR); 4309157117Smjacob xpt_done(ccb); 4310157117Smjacob return; 4311157117Smjacob } 4312157117Smjacob 4313157117Smjacob if (csio->dxfer_len) { 4314157117Smjacob bus_dmamap_callback_t *cb; 4315157117Smjacob PTR_MSG_TARGET_ASSIST_REQUEST ta; 4316157117Smjacob request_t *req; 4317251874Sscottl int error; 4318157117Smjacob 4319157117Smjacob KASSERT((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE, 4320231629Smarius ("dxfer_len %u but direction is NONE", csio->dxfer_len)); 4321157117Smjacob 4322157354Smjacob if ((req = mpt_get_request(mpt, FALSE)) == NULL) { 4323157354Smjacob if (mpt->outofbeer == 0) { 4324157354Smjacob mpt->outofbeer = 1; 4325157354Smjacob xpt_freeze_simq(mpt->sim, 1); 4326157354Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, "FREEZEQ\n"); 4327157354Smjacob } 4328157354Smjacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 4329157117Smjacob mpt_set_ccb_status(ccb, CAM_REQUEUE_REQ); 4330157117Smjacob xpt_done(ccb); 4331157117Smjacob return; 4332157117Smjacob } 4333157117Smjacob ccb->ccb_h.status = CAM_SIM_QUEUED | CAM_REQ_INPROG; 4334157117Smjacob if (sizeof (bus_addr_t) > 4) { 4335157117Smjacob cb = mpt_execute_req_a64; 4336157117Smjacob } else { 4337157117Smjacob cb = mpt_execute_req; 4338157117Smjacob } 4339157117Smjacob 4340157117Smjacob req->ccb = ccb; 4341157117Smjacob ccb->ccb_h.ccb_req_ptr = req; 4342157117Smjacob 4343157117Smjacob /* 4344157117Smjacob * Record the currently active ccb and the 4345157117Smjacob * request for it in our target state area. 4346157117Smjacob */ 4347157117Smjacob tgt->ccb = ccb; 4348157117Smjacob tgt->req = req; 4349157117Smjacob 4350157117Smjacob memset(req->req_vbuf, 0, MPT_RQSL(mpt)); 4351157117Smjacob ta = req->req_vbuf; 4352157117Smjacob 4353160391Smjacob if (mpt->is_sas) { 4354157117Smjacob PTR_MPI_TARGET_SSP_CMD_BUFFER ssp = 4355157117Smjacob cmd_req->req_vbuf; 4356157117Smjacob ta->QueueTag = ssp->InitiatorTag; 4357159178Smjacob } else if (mpt->is_spi) { 4358157117Smjacob PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER sp = 4359157117Smjacob cmd_req->req_vbuf; 4360157117Smjacob ta->QueueTag = sp->Tag; 4361157117Smjacob } 4362157117Smjacob ta->Function = MPI_FUNCTION_TARGET_ASSIST; 4363157117Smjacob ta->MsgContext = htole32(req->index | mpt->scsi_tgt_handler_id); 4364157117Smjacob ta->ReplyWord = htole32(tgt->reply_desc); 4365195274Sdelphij if (csio->ccb_h.target_lun > MPT_MAX_LUNS) { 4366157117Smjacob ta->LUN[0] = 4367157117Smjacob 0x40 | ((csio->ccb_h.target_lun >> 8) & 0x3f); 4368157117Smjacob ta->LUN[1] = csio->ccb_h.target_lun & 0xff; 4369157117Smjacob } else { 4370157117Smjacob ta->LUN[1] = csio->ccb_h.target_lun; 4371157117Smjacob } 4372157117Smjacob 4373157117Smjacob ta->RelativeOffset = tgt->bytes_xfered; 4374157117Smjacob ta->DataLength = ccb->csio.dxfer_len; 4375157117Smjacob if (ta->DataLength > tgt->resid) { 4376157117Smjacob ta->DataLength = tgt->resid; 4377157117Smjacob } 4378157117Smjacob 4379157117Smjacob /* 4380157117Smjacob * XXX Should be done after data transfer completes? 4381157117Smjacob */ 4382157117Smjacob tgt->resid -= csio->dxfer_len; 4383157117Smjacob tgt->bytes_xfered += csio->dxfer_len; 4384157117Smjacob 4385157117Smjacob if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 4386157117Smjacob ta->TargetAssistFlags |= 4387157117Smjacob TARGET_ASSIST_FLAGS_DATA_DIRECTION; 4388157117Smjacob } 4389157117Smjacob 4390157117Smjacob#ifdef WE_TRUST_AUTO_GOOD_STATUS 4391157117Smjacob if ((ccb->ccb_h.flags & CAM_SEND_STATUS) && 4392157117Smjacob csio->scsi_status == SCSI_STATUS_OK && tgt->resid == 0) { 4393157117Smjacob ta->TargetAssistFlags |= 4394157117Smjacob TARGET_ASSIST_FLAGS_AUTO_STATUS; 4395157117Smjacob } 4396157117Smjacob#endif 4397157117Smjacob tgt->state = TGT_STATE_SETTING_UP_FOR_DATA; 4398157117Smjacob 4399157117Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 4400157117Smjacob "DATA_CCB %p tag %x %u bytes %u resid flg %x req %p:%u " 4401157117Smjacob "nxtstate=%d\n", csio, csio->tag_id, csio->dxfer_len, 4402157117Smjacob tgt->resid, ccb->ccb_h.flags, req, req->serno, tgt->state); 4403157117Smjacob 4404251874Sscottl error = bus_dmamap_load_ccb(mpt->buffer_dmat, req->dmap, ccb, 4405251874Sscottl cb, req, 0); 4406251874Sscottl if (error == EINPROGRESS) { 4407251874Sscottl xpt_freeze_simq(mpt->sim, 1); 4408251874Sscottl ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 4409157117Smjacob } 4410157117Smjacob } else { 4411157117Smjacob uint8_t *sp = NULL, sense[MPT_SENSE_SIZE]; 4412157117Smjacob 4413157117Smjacob /* 4414157117Smjacob * XXX: I don't know why this seems to happen, but 4415157117Smjacob * XXX: completing the CCB seems to make things happy. 4416157117Smjacob * XXX: This seems to happen if the initiator requests 4417157117Smjacob * XXX: enough data that we have to do multiple CTIOs. 4418157117Smjacob */ 4419157117Smjacob if ((ccb->ccb_h.flags & CAM_SEND_STATUS) == 0) { 4420157117Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 4421157117Smjacob "Meaningless STATUS CCB (%p): flags %x status %x " 4422157117Smjacob "resid %d bytes_xfered %u\n", ccb, ccb->ccb_h.flags, 4423157117Smjacob ccb->ccb_h.status, tgt->resid, tgt->bytes_xfered); 4424157117Smjacob mpt_set_ccb_status(ccb, CAM_REQ_CMP); 4425157117Smjacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 4426157117Smjacob xpt_done(ccb); 4427157117Smjacob return; 4428157117Smjacob } 4429157117Smjacob if (ccb->ccb_h.flags & CAM_SEND_SENSE) { 4430157117Smjacob sp = sense; 4431157117Smjacob memcpy(sp, &csio->sense_data, 4432157117Smjacob min(csio->sense_len, MPT_SENSE_SIZE)); 4433157117Smjacob } 4434157117Smjacob mpt_scsi_tgt_status(mpt, ccb, cmd_req, csio->scsi_status, sp); 4435157117Smjacob } 4436157117Smjacob} 4437157117Smjacob 4438160391Smjacobstatic void 4439160391Smjacobmpt_scsi_tgt_local(struct mpt_softc *mpt, request_t *cmd_req, 4440160391Smjacob uint32_t lun, int send, uint8_t *data, size_t length) 4441160391Smjacob{ 4442160391Smjacob mpt_tgt_state_t *tgt; 4443160391Smjacob PTR_MSG_TARGET_ASSIST_REQUEST ta; 4444160391Smjacob SGE_SIMPLE32 *se; 4445160391Smjacob uint32_t flags; 4446160391Smjacob uint8_t *dptr; 4447160391Smjacob bus_addr_t pptr; 4448160391Smjacob request_t *req; 4449160391Smjacob 4450164348Smjacob /* 4451164348Smjacob * We enter with resid set to the data load for the command. 4452164348Smjacob */ 4453164348Smjacob tgt = MPT_TGT_STATE(mpt, cmd_req); 4454164348Smjacob if (length == 0 || tgt->resid == 0) { 4455164348Smjacob tgt->resid = 0; 4456160391Smjacob mpt_scsi_tgt_status(mpt, NULL, cmd_req, 0, NULL); 4457160391Smjacob return; 4458160391Smjacob } 4459160391Smjacob 4460160391Smjacob if ((req = mpt_get_request(mpt, FALSE)) == NULL) { 4461160391Smjacob mpt_prt(mpt, "out of resources- dropping local response\n"); 4462160391Smjacob return; 4463160391Smjacob } 4464160391Smjacob tgt->is_local = 1; 4465160391Smjacob 4466160391Smjacob 4467160391Smjacob memset(req->req_vbuf, 0, MPT_RQSL(mpt)); 4468160391Smjacob ta = req->req_vbuf; 4469160391Smjacob 4470160391Smjacob if (mpt->is_sas) { 4471160391Smjacob PTR_MPI_TARGET_SSP_CMD_BUFFER ssp = cmd_req->req_vbuf; 4472160391Smjacob ta->QueueTag = ssp->InitiatorTag; 4473160391Smjacob } else if (mpt->is_spi) { 4474160391Smjacob PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER sp = cmd_req->req_vbuf; 4475160391Smjacob ta->QueueTag = sp->Tag; 4476160391Smjacob } 4477160391Smjacob ta->Function = MPI_FUNCTION_TARGET_ASSIST; 4478160391Smjacob ta->MsgContext = htole32(req->index | mpt->scsi_tgt_handler_id); 4479160391Smjacob ta->ReplyWord = htole32(tgt->reply_desc); 4480195274Sdelphij if (lun > MPT_MAX_LUNS) { 4481160391Smjacob ta->LUN[0] = 0x40 | ((lun >> 8) & 0x3f); 4482160391Smjacob ta->LUN[1] = lun & 0xff; 4483160391Smjacob } else { 4484160391Smjacob ta->LUN[1] = lun; 4485160391Smjacob } 4486160391Smjacob ta->RelativeOffset = 0; 4487160391Smjacob ta->DataLength = length; 4488160391Smjacob 4489160391Smjacob dptr = req->req_vbuf; 4490160391Smjacob dptr += MPT_RQSL(mpt); 4491160391Smjacob pptr = req->req_pbuf; 4492160391Smjacob pptr += MPT_RQSL(mpt); 4493160391Smjacob memcpy(dptr, data, min(length, MPT_RQSL(mpt))); 4494160391Smjacob 4495160391Smjacob se = (SGE_SIMPLE32 *) &ta->SGL[0]; 4496160391Smjacob memset(se, 0,sizeof (*se)); 4497160391Smjacob 4498160391Smjacob flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT; 4499160391Smjacob if (send) { 4500160391Smjacob ta->TargetAssistFlags |= TARGET_ASSIST_FLAGS_DATA_DIRECTION; 4501160391Smjacob flags |= MPI_SGE_FLAGS_HOST_TO_IOC; 4502160391Smjacob } 4503160391Smjacob se->Address = pptr; 4504160391Smjacob MPI_pSGE_SET_LENGTH(se, length); 4505160391Smjacob flags |= MPI_SGE_FLAGS_LAST_ELEMENT; 4506160391Smjacob flags |= MPI_SGE_FLAGS_END_OF_LIST | MPI_SGE_FLAGS_END_OF_BUFFER; 4507160391Smjacob MPI_pSGE_SET_FLAGS(se, flags); 4508160391Smjacob 4509160391Smjacob tgt->ccb = NULL; 4510160391Smjacob tgt->req = req; 4511164348Smjacob tgt->resid -= length; 4512160391Smjacob tgt->bytes_xfered = length; 4513160391Smjacob#ifdef WE_TRUST_AUTO_GOOD_STATUS 4514160391Smjacob tgt->state = TGT_STATE_MOVING_DATA_AND_STATUS; 4515160391Smjacob#else 4516160391Smjacob tgt->state = TGT_STATE_MOVING_DATA; 4517160391Smjacob#endif 4518160391Smjacob mpt_send_cmd(mpt, req); 4519160391Smjacob} 4520160391Smjacob 4521157117Smjacob/* 4522157117Smjacob * Abort queued up CCBs 4523157117Smjacob */ 4524157117Smjacobstatic cam_status 4525157117Smjacobmpt_abort_target_ccb(struct mpt_softc *mpt, union ccb *ccb) 4526157117Smjacob{ 4527157117Smjacob struct mpt_hdr_stailq *lp; 4528157117Smjacob struct ccb_hdr *srch; 4529157117Smjacob int found = 0; 4530157117Smjacob union ccb *accb = ccb->cab.abort_ccb; 4531157117Smjacob tgt_resource_t *trtp; 4532157117Smjacob 4533157117Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, "aborting ccb %p\n", accb); 4534157117Smjacob 4535157117Smjacob if (ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) { 4536157117Smjacob trtp = &mpt->trt_wildcard; 4537157117Smjacob } else { 4538157117Smjacob trtp = &mpt->trt[ccb->ccb_h.target_lun]; 4539157117Smjacob } 4540157117Smjacob 4541157117Smjacob if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { 4542157117Smjacob lp = &trtp->atios; 4543237825Sken } else if (accb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) { 4544157117Smjacob lp = &trtp->inots; 4545157117Smjacob } else { 4546157117Smjacob return (CAM_REQ_INVALID); 4547157117Smjacob } 4548157117Smjacob 4549157117Smjacob STAILQ_FOREACH(srch, lp, sim_links.stqe) { 4550157117Smjacob if (srch == &accb->ccb_h) { 4551157117Smjacob found = 1; 4552157117Smjacob STAILQ_REMOVE(lp, srch, ccb_hdr, sim_links.stqe); 4553157117Smjacob break; 4554157117Smjacob } 4555157117Smjacob } 4556157117Smjacob if (found) { 4557157117Smjacob accb->ccb_h.status = CAM_REQ_ABORTED; 4558157117Smjacob xpt_done(accb); 4559157117Smjacob return (CAM_REQ_CMP); 4560157117Smjacob } 4561157117Smjacob mpt_prt(mpt, "mpt_abort_tgt_ccb: CCB %p not found\n", ccb); 4562157117Smjacob return (CAM_PATH_INVALID); 4563157117Smjacob} 4564157117Smjacob 4565157117Smjacob/* 4566157117Smjacob * Ask the MPT to abort the current target command 4567157117Smjacob */ 4568157354Smjacobstatic int 4569157117Smjacobmpt_abort_target_cmd(struct mpt_softc *mpt, request_t *cmd_req) 4570157117Smjacob{ 4571157117Smjacob int error; 4572157117Smjacob request_t *req; 4573157117Smjacob PTR_MSG_TARGET_MODE_ABORT abtp; 4574157117Smjacob 4575157117Smjacob req = mpt_get_request(mpt, FALSE); 4576157117Smjacob if (req == NULL) { 4577157354Smjacob return (-1); 4578157117Smjacob } 4579157117Smjacob abtp = req->req_vbuf; 4580157117Smjacob memset(abtp, 0, sizeof (*abtp)); 4581157117Smjacob 4582157117Smjacob abtp->MsgContext = htole32(req->index | mpt->scsi_tgt_handler_id); 4583157117Smjacob abtp->AbortType = TARGET_MODE_ABORT_TYPE_EXACT_IO; 4584157117Smjacob abtp->Function = MPI_FUNCTION_TARGET_MODE_ABORT; 4585157117Smjacob abtp->ReplyWord = htole32(MPT_TGT_STATE(mpt, cmd_req)->reply_desc); 4586157354Smjacob error = 0; 4587157117Smjacob if (mpt->is_fc || mpt->is_sas) { 4588157117Smjacob mpt_send_cmd(mpt, req); 4589157117Smjacob } else { 4590157117Smjacob error = mpt_send_handshake_cmd(mpt, sizeof(*req), req); 4591157117Smjacob } 4592157354Smjacob return (error); 4593157117Smjacob} 4594157117Smjacob 4595157117Smjacob/* 4596157354Smjacob * WE_TRUST_AUTO_GOOD_STATUS- I've found that setting 4597157354Smjacob * TARGET_STATUS_SEND_FLAGS_AUTO_GOOD_STATUS leads the 4598157354Smjacob * FC929 to set bogus FC_RSP fields (nonzero residuals 4599157354Smjacob * but w/o RESID fields set). This causes QLogic initiators 4600157354Smjacob * to think maybe that a frame was lost. 4601157354Smjacob * 4602157354Smjacob * WE_CAN_USE_AUTO_REPOST- we can't use AUTO_REPOST because 4603157354Smjacob * we use allocated requests to do TARGET_ASSIST and we 4604157354Smjacob * need to know when to release them. 4605147883Sscottl */ 4606157354Smjacob 4607147883Sscottlstatic void 4608157354Smjacobmpt_scsi_tgt_status(struct mpt_softc *mpt, union ccb *ccb, request_t *cmd_req, 4609157354Smjacob uint8_t status, uint8_t const *sense_data) 4610147883Sscottl{ 4611157354Smjacob uint8_t *cmd_vbuf; 4612157354Smjacob mpt_tgt_state_t *tgt; 4613157354Smjacob PTR_MSG_TARGET_STATUS_SEND_REQUEST tp; 4614157354Smjacob request_t *req; 4615157354Smjacob bus_addr_t paddr; 4616157354Smjacob int resplen = 0; 4617164315Sjb uint32_t fl; 4618147883Sscottl 4619157354Smjacob cmd_vbuf = cmd_req->req_vbuf; 4620157354Smjacob cmd_vbuf += MPT_RQSL(mpt); 4621157354Smjacob tgt = MPT_TGT_STATE(mpt, cmd_req); 4622157354Smjacob 4623157354Smjacob if ((req = mpt_get_request(mpt, FALSE)) == NULL) { 4624157354Smjacob if (mpt->outofbeer == 0) { 4625157354Smjacob mpt->outofbeer = 1; 4626157354Smjacob xpt_freeze_simq(mpt->sim, 1); 4627157354Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, "FREEZEQ\n"); 4628157354Smjacob } 4629157354Smjacob if (ccb) { 4630157354Smjacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 4631157354Smjacob mpt_set_ccb_status(ccb, CAM_REQUEUE_REQ); 4632157354Smjacob xpt_done(ccb); 4633157354Smjacob } else { 4634157354Smjacob mpt_prt(mpt, 4635160391Smjacob "could not allocate status request- dropping\n"); 4636157354Smjacob } 4637156022Smjacob return; 4638156022Smjacob } 4639157354Smjacob req->ccb = ccb; 4640157354Smjacob if (ccb) { 4641157354Smjacob ccb->ccb_h.ccb_mpt_ptr = mpt; 4642157354Smjacob ccb->ccb_h.ccb_req_ptr = req; 4643157354Smjacob } 4644147883Sscottl 4645147883Sscottl /* 4646157354Smjacob * Record the currently active ccb, if any, and the 4647157354Smjacob * request for it in our target state area. 4648147883Sscottl */ 4649157354Smjacob tgt->ccb = ccb; 4650157354Smjacob tgt->req = req; 4651157354Smjacob tgt->state = TGT_STATE_SENDING_STATUS; 4652147883Sscottl 4653157354Smjacob tp = req->req_vbuf; 4654157354Smjacob paddr = req->req_pbuf; 4655157354Smjacob paddr += MPT_RQSL(mpt); 4656157354Smjacob 4657157354Smjacob memset(tp, 0, sizeof (*tp)); 4658157354Smjacob tp->Function = MPI_FUNCTION_TARGET_STATUS_SEND; 4659157354Smjacob if (mpt->is_fc) { 4660157354Smjacob PTR_MPI_TARGET_FCP_CMD_BUFFER fc = 4661157354Smjacob (PTR_MPI_TARGET_FCP_CMD_BUFFER) cmd_vbuf; 4662157354Smjacob uint8_t *sts_vbuf; 4663157354Smjacob uint32_t *rsp; 4664157354Smjacob 4665157354Smjacob sts_vbuf = req->req_vbuf; 4666157354Smjacob sts_vbuf += MPT_RQSL(mpt); 4667157354Smjacob rsp = (uint32_t *) sts_vbuf; 4668157354Smjacob memcpy(tp->LUN, fc->FcpLun, sizeof (tp->LUN)); 4669157354Smjacob 4670147883Sscottl /* 4671157354Smjacob * The MPI_TARGET_FCP_RSP_BUFFER define is unfortunate. 4672157354Smjacob * It has to be big-endian in memory and is organized 4673157354Smjacob * in 32 bit words, which are much easier to deal with 4674157354Smjacob * as words which are swizzled as needed. 4675157354Smjacob * 4676157354Smjacob * All we're filling here is the FC_RSP payload. 4677157354Smjacob * We may just have the chip synthesize it if 4678157354Smjacob * we have no residual and an OK status. 4679157354Smjacob * 4680147883Sscottl */ 4681157354Smjacob memset(rsp, 0, sizeof (MPI_TARGET_FCP_RSP_BUFFER)); 4682157354Smjacob 4683157354Smjacob rsp[2] = status; 4684157354Smjacob if (tgt->resid) { 4685157662Smjacob rsp[2] |= 0x800; /* XXXX NEED MNEMONIC!!!! */ 4686157354Smjacob rsp[3] = htobe32(tgt->resid); 4687157354Smjacob#ifdef WE_TRUST_AUTO_GOOD_STATUS 4688157354Smjacob resplen = sizeof (MPI_TARGET_FCP_RSP_BUFFER); 4689157354Smjacob#endif 4690157354Smjacob } 4691157354Smjacob if (status == SCSI_STATUS_CHECK_COND) { 4692157354Smjacob int i; 4693157354Smjacob 4694157662Smjacob rsp[2] |= 0x200; /* XXXX NEED MNEMONIC!!!! */ 4695157354Smjacob rsp[4] = htobe32(MPT_SENSE_SIZE); 4696157944Smjacob if (sense_data) { 4697157944Smjacob memcpy(&rsp[8], sense_data, MPT_SENSE_SIZE); 4698157944Smjacob } else { 4699157944Smjacob mpt_prt(mpt, "mpt_scsi_tgt_status: CHECK CONDI" 4700157944Smjacob "TION but no sense data?\n"); 4701157944Smjacob memset(&rsp, 0, MPT_SENSE_SIZE); 4702157944Smjacob } 4703157354Smjacob for (i = 8; i < (8 + (MPT_SENSE_SIZE >> 2)); i++) { 4704157354Smjacob rsp[i] = htobe32(rsp[i]); 4705157354Smjacob } 4706157354Smjacob#ifdef WE_TRUST_AUTO_GOOD_STATUS 4707157354Smjacob resplen = sizeof (MPI_TARGET_FCP_RSP_BUFFER); 4708157354Smjacob#endif 4709157354Smjacob } 4710157354Smjacob#ifndef WE_TRUST_AUTO_GOOD_STATUS 4711157354Smjacob resplen = sizeof (MPI_TARGET_FCP_RSP_BUFFER); 4712157354Smjacob#endif 4713157354Smjacob rsp[2] = htobe32(rsp[2]); 4714157354Smjacob } else if (mpt->is_sas) { 4715157354Smjacob PTR_MPI_TARGET_SSP_CMD_BUFFER ssp = 4716157354Smjacob (PTR_MPI_TARGET_SSP_CMD_BUFFER) cmd_vbuf; 4717157354Smjacob memcpy(tp->LUN, ssp->LogicalUnitNumber, sizeof (tp->LUN)); 4718157354Smjacob } else { 4719157354Smjacob PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER sp = 4720157354Smjacob (PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER) cmd_vbuf; 4721157354Smjacob tp->StatusCode = status; 4722157354Smjacob tp->QueueTag = htole16(sp->Tag); 4723157354Smjacob memcpy(tp->LUN, sp->LogicalUnitNumber, sizeof (tp->LUN)); 4724147883Sscottl } 4725147883Sscottl 4726157354Smjacob tp->ReplyWord = htole32(tgt->reply_desc); 4727157354Smjacob tp->MsgContext = htole32(req->index | mpt->scsi_tgt_handler_id); 4728157354Smjacob 4729157354Smjacob#ifdef WE_CAN_USE_AUTO_REPOST 4730157354Smjacob tp->MsgFlags = TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER; 4731157354Smjacob#endif 4732157354Smjacob if (status == SCSI_STATUS_OK && resplen == 0) { 4733157354Smjacob tp->MsgFlags |= TARGET_STATUS_SEND_FLAGS_AUTO_GOOD_STATUS; 4734157354Smjacob } else { 4735164315Sjb tp->StatusDataSGE.u.Address32 = htole32((uint32_t) paddr); 4736164315Sjb fl = 4737157354Smjacob MPI_SGE_FLAGS_HOST_TO_IOC | 4738157354Smjacob MPI_SGE_FLAGS_SIMPLE_ELEMENT | 4739157354Smjacob MPI_SGE_FLAGS_LAST_ELEMENT | 4740157354Smjacob MPI_SGE_FLAGS_END_OF_LIST | 4741157354Smjacob MPI_SGE_FLAGS_END_OF_BUFFER; 4742164315Sjb fl <<= MPI_SGE_FLAGS_SHIFT; 4743164315Sjb fl |= resplen; 4744164315Sjb tp->StatusDataSGE.FlagsLength = htole32(fl); 4745157354Smjacob } 4746157354Smjacob 4747157354Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 4748157354Smjacob "STATUS_CCB %p (wit%s sense) tag %x req %p:%u resid %u\n", 4749157354Smjacob ccb, sense_data?"h" : "hout", ccb? ccb->csio.tag_id : -1, req, 4750157354Smjacob req->serno, tgt->resid); 4751157354Smjacob if (ccb) { 4752157354Smjacob ccb->ccb_h.status = CAM_SIM_QUEUED | CAM_REQ_INPROG; 4753169293Smjacob mpt_req_timeout(req, 60 * hz, mpt_timeout, ccb); 4754157354Smjacob } 4755157354Smjacob mpt_send_cmd(mpt, req); 4756157354Smjacob} 4757157354Smjacob 4758157354Smjacobstatic void 4759157354Smjacobmpt_scsi_tgt_tsk_mgmt(struct mpt_softc *mpt, request_t *req, mpt_task_mgmt_t fc, 4760157354Smjacob tgt_resource_t *trtp, int init_id) 4761157354Smjacob{ 4762237825Sken struct ccb_immediate_notify *inot; 4763157354Smjacob mpt_tgt_state_t *tgt; 4764157354Smjacob 4765157354Smjacob tgt = MPT_TGT_STATE(mpt, req); 4766237825Sken inot = (struct ccb_immediate_notify *) STAILQ_FIRST(&trtp->inots); 4767157354Smjacob if (inot == NULL) { 4768157354Smjacob mpt_lprt(mpt, MPT_PRT_WARN, "no INOTSs- sending back BSY\n"); 4769157354Smjacob mpt_scsi_tgt_status(mpt, NULL, req, SCSI_STATUS_BUSY, NULL); 4770157354Smjacob return; 4771157354Smjacob } 4772157354Smjacob STAILQ_REMOVE_HEAD(&trtp->inots, sim_links.stqe); 4773157354Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG1, 4774157354Smjacob "Get FREE INOT %p lun %d\n", inot, inot->ccb_h.target_lun); 4775157354Smjacob 4776157354Smjacob inot->initiator_id = init_id; /* XXX */ 4777147883Sscottl /* 4778157354Smjacob * This is a somewhat grotesque attempt to map from task management 4779157354Smjacob * to old style SCSI messages. God help us all. 4780147883Sscottl */ 4781157354Smjacob switch (fc) { 4782157354Smjacob case MPT_ABORT_TASK_SET: 4783237825Sken inot->arg = MSG_ABORT_TAG; 4784157354Smjacob break; 4785157354Smjacob case MPT_CLEAR_TASK_SET: 4786237825Sken inot->arg = MSG_CLEAR_TASK_SET; 4787157354Smjacob break; 4788157354Smjacob case MPT_TARGET_RESET: 4789237825Sken inot->arg = MSG_TARGET_RESET; 4790157354Smjacob break; 4791157354Smjacob case MPT_CLEAR_ACA: 4792237825Sken inot->arg = MSG_CLEAR_ACA; 4793157354Smjacob break; 4794157354Smjacob case MPT_TERMINATE_TASK: 4795237825Sken inot->arg = MSG_ABORT_TAG; 4796157354Smjacob break; 4797157354Smjacob default: 4798237825Sken inot->arg = MSG_NOOP; 4799157354Smjacob break; 4800157354Smjacob } 4801237825Sken /* 4802237825Sken * XXX KDM we need the sequence/tag number for the target of the 4803237825Sken * task management operation, especially if it is an abort. 4804237825Sken */ 4805157354Smjacob tgt->ccb = (union ccb *) inot; 4806157354Smjacob inot->ccb_h.status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN; 4807157354Smjacob xpt_done((union ccb *)inot); 4808157354Smjacob} 4809147883Sscottl 4810157354Smjacobstatic void 4811157354Smjacobmpt_scsi_tgt_atio(struct mpt_softc *mpt, request_t *req, uint32_t reply_desc) 4812157354Smjacob{ 4813164348Smjacob static uint8_t null_iqd[SHORT_INQUIRY_LENGTH] = { 4814164348Smjacob 0x7f, 0x00, 0x02, 0x02, 0x20, 0x00, 0x00, 0x32, 4815164348Smjacob 'F', 'R', 'E', 'E', 'B', 'S', 'D', ' ', 4816164348Smjacob 'L', 'S', 'I', '-', 'L', 'O', 'G', 'I', 4817164348Smjacob 'C', ' ', 'N', 'U', 'L', 'D', 'E', 'V', 4818164348Smjacob '0', '0', '0', '1' 4819164348Smjacob }; 4820157354Smjacob struct ccb_accept_tio *atiop; 4821157354Smjacob lun_id_t lun; 4822157354Smjacob int tag_action = 0; 4823157354Smjacob mpt_tgt_state_t *tgt; 4824157944Smjacob tgt_resource_t *trtp = NULL; 4825157354Smjacob U8 *lunptr; 4826157354Smjacob U8 *vbuf; 4827157354Smjacob U16 itag; 4828157354Smjacob U16 ioindex; 4829157354Smjacob mpt_task_mgmt_t fct = MPT_NIL_TMT_VALUE; 4830157354Smjacob uint8_t *cdbp; 4831157117Smjacob 4832157354Smjacob /* 4833157354Smjacob * Stash info for the current command where we can get at it later. 4834157354Smjacob */ 4835157354Smjacob vbuf = req->req_vbuf; 4836157354Smjacob vbuf += MPT_RQSL(mpt); 4837157354Smjacob 4838157354Smjacob /* 4839157354Smjacob * Get our state pointer set up. 4840157354Smjacob */ 4841157354Smjacob tgt = MPT_TGT_STATE(mpt, req); 4842157354Smjacob if (tgt->state != TGT_STATE_LOADED) { 4843157354Smjacob mpt_tgt_dump_req_state(mpt, req); 4844157354Smjacob panic("bad target state in mpt_scsi_tgt_atio"); 4845157354Smjacob } 4846157354Smjacob memset(tgt, 0, sizeof (mpt_tgt_state_t)); 4847157354Smjacob tgt->state = TGT_STATE_IN_CAM; 4848157354Smjacob tgt->reply_desc = reply_desc; 4849157354Smjacob ioindex = GET_IO_INDEX(reply_desc); 4850163925Smjacob if (mpt->verbose >= MPT_PRT_DEBUG) { 4851163925Smjacob mpt_dump_data(mpt, "mpt_scsi_tgt_atio response", vbuf, 4852163925Smjacob max(sizeof (MPI_TARGET_FCP_CMD_BUFFER), 4853163925Smjacob max(sizeof (MPI_TARGET_SSP_CMD_BUFFER), 4854163925Smjacob sizeof (MPI_TARGET_SCSI_SPI_CMD_BUFFER)))); 4855163925Smjacob } 4856157354Smjacob if (mpt->is_fc) { 4857157354Smjacob PTR_MPI_TARGET_FCP_CMD_BUFFER fc; 4858157354Smjacob fc = (PTR_MPI_TARGET_FCP_CMD_BUFFER) vbuf; 4859157354Smjacob if (fc->FcpCntl[2]) { 4860147883Sscottl /* 4861157354Smjacob * Task Management Request 4862147883Sscottl */ 4863157354Smjacob switch (fc->FcpCntl[2]) { 4864157354Smjacob case 0x2: 4865157354Smjacob fct = MPT_ABORT_TASK_SET; 4866157354Smjacob break; 4867157354Smjacob case 0x4: 4868157354Smjacob fct = MPT_CLEAR_TASK_SET; 4869157354Smjacob break; 4870157354Smjacob case 0x20: 4871157354Smjacob fct = MPT_TARGET_RESET; 4872157354Smjacob break; 4873157354Smjacob case 0x40: 4874157354Smjacob fct = MPT_CLEAR_ACA; 4875157354Smjacob break; 4876157354Smjacob case 0x80: 4877157354Smjacob fct = MPT_TERMINATE_TASK; 4878157354Smjacob break; 4879157354Smjacob default: 4880157354Smjacob mpt_prt(mpt, "CORRUPTED TASK MGMT BITS: 0x%x\n", 4881157354Smjacob fc->FcpCntl[2]); 4882157354Smjacob mpt_scsi_tgt_status(mpt, 0, req, 4883157354Smjacob SCSI_STATUS_OK, 0); 4884157354Smjacob return; 4885157354Smjacob } 4886157944Smjacob } else { 4887157944Smjacob switch (fc->FcpCntl[1]) { 4888157944Smjacob case 0: 4889157944Smjacob tag_action = MSG_SIMPLE_Q_TAG; 4890157944Smjacob break; 4891157944Smjacob case 1: 4892157944Smjacob tag_action = MSG_HEAD_OF_Q_TAG; 4893157944Smjacob break; 4894157944Smjacob case 2: 4895157944Smjacob tag_action = MSG_ORDERED_Q_TAG; 4896157944Smjacob break; 4897157944Smjacob default: 4898157944Smjacob /* 4899157944Smjacob * Bah. Ignore Untagged Queing and ACA 4900157944Smjacob */ 4901157944Smjacob tag_action = MSG_SIMPLE_Q_TAG; 4902157944Smjacob break; 4903157944Smjacob } 4904147883Sscottl } 4905157354Smjacob tgt->resid = be32toh(fc->FcpDl); 4906157354Smjacob cdbp = fc->FcpCdb; 4907157354Smjacob lunptr = fc->FcpLun; 4908157354Smjacob itag = be16toh(fc->OptionalOxid); 4909157354Smjacob } else if (mpt->is_sas) { 4910157354Smjacob PTR_MPI_TARGET_SSP_CMD_BUFFER ssp; 4911157354Smjacob ssp = (PTR_MPI_TARGET_SSP_CMD_BUFFER) vbuf; 4912157354Smjacob cdbp = ssp->CDB; 4913157354Smjacob lunptr = ssp->LogicalUnitNumber; 4914157354Smjacob itag = ssp->InitiatorTag; 4915157354Smjacob } else { 4916157354Smjacob PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER sp; 4917157354Smjacob sp = (PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER) vbuf; 4918157354Smjacob cdbp = sp->CDB; 4919157354Smjacob lunptr = sp->LogicalUnitNumber; 4920157354Smjacob itag = sp->Tag; 4921157354Smjacob } 4922147883Sscottl 4923157354Smjacob /* 4924157354Smjacob * Generate a simple lun 4925157354Smjacob */ 4926157354Smjacob switch (lunptr[0] & 0xc0) { 4927157354Smjacob case 0x40: 4928157354Smjacob lun = ((lunptr[0] & 0x3f) << 8) | lunptr[1]; 4929157354Smjacob break; 4930157354Smjacob case 0: 4931157354Smjacob lun = lunptr[1]; 4932157354Smjacob break; 4933157354Smjacob default: 4934157354Smjacob mpt_lprt(mpt, MPT_PRT_ERROR, "cannot handle this type lun\n"); 4935157354Smjacob lun = 0xffff; 4936157354Smjacob break; 4937157354Smjacob } 4938147883Sscottl 4939157354Smjacob /* 4940157354Smjacob * Deal with non-enabled or bad luns here. 4941157354Smjacob */ 4942157354Smjacob if (lun >= MPT_MAX_LUNS || mpt->tenabled == 0 || 4943157354Smjacob mpt->trt[lun].enabled == 0) { 4944157354Smjacob if (mpt->twildcard) { 4945157354Smjacob trtp = &mpt->trt_wildcard; 4946160391Smjacob } else if (fct == MPT_NIL_TMT_VALUE) { 4947160391Smjacob /* 4948160391Smjacob * In this case, we haven't got an upstream listener 4949160391Smjacob * for either a specific lun or wildcard luns. We 4950160391Smjacob * have to make some sensible response. For regular 4951160391Smjacob * inquiry, just return some NOT HERE inquiry data. 4952160391Smjacob * For VPD inquiry, report illegal field in cdb. 4953160391Smjacob * For REQUEST SENSE, just return NO SENSE data. 4954160391Smjacob * REPORT LUNS gets illegal command. 4955160391Smjacob * All other commands get 'no such device'. 4956160391Smjacob */ 4957160391Smjacob uint8_t *sp, cond, buf[MPT_SENSE_SIZE]; 4958164348Smjacob size_t len; 4959160391Smjacob 4960160391Smjacob memset(buf, 0, MPT_SENSE_SIZE); 4961160391Smjacob cond = SCSI_STATUS_CHECK_COND; 4962160391Smjacob buf[0] = 0xf0; 4963160391Smjacob buf[2] = 0x5; 4964160391Smjacob buf[7] = 0x8; 4965160391Smjacob sp = buf; 4966160391Smjacob tgt->tag_id = MPT_MAKE_TAGID(mpt, req, ioindex); 4967160391Smjacob 4968160391Smjacob switch (cdbp[0]) { 4969160391Smjacob case INQUIRY: 4970160391Smjacob { 4971160391Smjacob if (cdbp[1] != 0) { 4972160391Smjacob buf[12] = 0x26; 4973160391Smjacob buf[13] = 0x01; 4974160391Smjacob break; 4975160391Smjacob } 4976164348Smjacob len = min(tgt->resid, cdbp[4]); 4977164348Smjacob len = min(len, sizeof (null_iqd)); 4978164348Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 4979164349Smjacob "local inquiry %ld bytes\n", (long) len); 4980160391Smjacob mpt_scsi_tgt_local(mpt, req, lun, 1, 4981164348Smjacob null_iqd, len); 4982160391Smjacob return; 4983160391Smjacob } 4984160391Smjacob case REQUEST_SENSE: 4985160391Smjacob { 4986160391Smjacob buf[2] = 0x0; 4987164348Smjacob len = min(tgt->resid, cdbp[4]); 4988164348Smjacob len = min(len, sizeof (buf)); 4989164348Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 4990164349Smjacob "local reqsense %ld bytes\n", (long) len); 4991160391Smjacob mpt_scsi_tgt_local(mpt, req, lun, 1, 4992164348Smjacob buf, len); 4993160391Smjacob return; 4994160391Smjacob } 4995160391Smjacob case REPORT_LUNS: 4996164348Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, "REPORT LUNS\n"); 4997160391Smjacob buf[12] = 0x26; 4998164348Smjacob return; 4999160391Smjacob default: 5000164348Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 5001164348Smjacob "CMD 0x%x to unmanaged lun %u\n", 5002164348Smjacob cdbp[0], lun); 5003160391Smjacob buf[12] = 0x25; 5004160391Smjacob break; 5005160391Smjacob } 5006160391Smjacob mpt_scsi_tgt_status(mpt, NULL, req, cond, sp); 5007157354Smjacob return; 5008157354Smjacob } 5009160391Smjacob /* otherwise, leave trtp NULL */ 5010157354Smjacob } else { 5011157354Smjacob trtp = &mpt->trt[lun]; 5012157354Smjacob } 5013147883Sscottl 5014157944Smjacob /* 5015157944Smjacob * Deal with any task management 5016157944Smjacob */ 5017157354Smjacob if (fct != MPT_NIL_TMT_VALUE) { 5018157944Smjacob if (trtp == NULL) { 5019157944Smjacob mpt_prt(mpt, "task mgmt function %x but no listener\n", 5020157944Smjacob fct); 5021157944Smjacob mpt_scsi_tgt_status(mpt, 0, req, 5022157944Smjacob SCSI_STATUS_OK, 0); 5023157944Smjacob } else { 5024157944Smjacob mpt_scsi_tgt_tsk_mgmt(mpt, req, fct, trtp, 5025157944Smjacob GET_INITIATOR_INDEX(reply_desc)); 5026157944Smjacob } 5027157354Smjacob return; 5028157354Smjacob } 5029157354Smjacob 5030157944Smjacob 5031157354Smjacob atiop = (struct ccb_accept_tio *) STAILQ_FIRST(&trtp->atios); 5032157354Smjacob if (atiop == NULL) { 5033157354Smjacob mpt_lprt(mpt, MPT_PRT_WARN, 5034157354Smjacob "no ATIOs for lun %u- sending back %s\n", lun, 5035157354Smjacob mpt->tenabled? "QUEUE FULL" : "BUSY"); 5036157354Smjacob mpt_scsi_tgt_status(mpt, NULL, req, 5037157354Smjacob mpt->tenabled? SCSI_STATUS_QUEUE_FULL : SCSI_STATUS_BUSY, 5038157354Smjacob NULL); 5039157354Smjacob return; 5040157354Smjacob } 5041157354Smjacob STAILQ_REMOVE_HEAD(&trtp->atios, sim_links.stqe); 5042157354Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG1, 5043157354Smjacob "Get FREE ATIO %p lun %d\n", atiop, atiop->ccb_h.target_lun); 5044157354Smjacob atiop->ccb_h.ccb_mpt_ptr = mpt; 5045157853Smjacob atiop->ccb_h.status = CAM_CDB_RECVD; 5046157354Smjacob atiop->ccb_h.target_lun = lun; 5047157354Smjacob atiop->sense_len = 0; 5048157853Smjacob atiop->init_id = GET_INITIATOR_INDEX(reply_desc); 5049157853Smjacob atiop->cdb_len = mpt_cdblen(cdbp[0], 16); 5050157853Smjacob memcpy(atiop->cdb_io.cdb_bytes, cdbp, atiop->cdb_len); 5051157354Smjacob 5052157354Smjacob /* 5053157354Smjacob * The tag we construct here allows us to find the 5054157354Smjacob * original request that the command came in with. 5055157354Smjacob * 5056157354Smjacob * This way we don't have to depend on anything but the 5057157354Smjacob * tag to find things when CCBs show back up from CAM. 5058157354Smjacob */ 5059157853Smjacob atiop->tag_id = MPT_MAKE_TAGID(mpt, req, ioindex); 5060157354Smjacob tgt->tag_id = atiop->tag_id; 5061157354Smjacob if (tag_action) { 5062157853Smjacob atiop->tag_action = tag_action; 5063157354Smjacob atiop->ccb_h.flags = CAM_TAG_ACTION_VALID; 5064157354Smjacob } 5065157354Smjacob if (mpt->verbose >= MPT_PRT_DEBUG) { 5066157354Smjacob int i; 5067157354Smjacob mpt_prt(mpt, "START_CCB %p for lun %u CDB=<", atiop, 5068157354Smjacob atiop->ccb_h.target_lun); 5069157354Smjacob for (i = 0; i < atiop->cdb_len; i++) { 5070157354Smjacob mpt_prtc(mpt, "%02x%c", cdbp[i] & 0xff, 5071157354Smjacob (i == (atiop->cdb_len - 1))? '>' : ' '); 5072147883Sscottl } 5073157354Smjacob mpt_prtc(mpt, " itag %x tag %x rdesc %x dl=%u\n", 5074157354Smjacob itag, atiop->tag_id, tgt->reply_desc, tgt->resid); 5075157354Smjacob } 5076157354Smjacob 5077157354Smjacob xpt_done((union ccb *)atiop); 5078157354Smjacob} 5079147883Sscottl 5080157354Smjacobstatic void 5081157354Smjacobmpt_tgt_dump_tgt_state(struct mpt_softc *mpt, request_t *req) 5082157354Smjacob{ 5083157354Smjacob mpt_tgt_state_t *tgt = MPT_TGT_STATE(mpt, req); 5084157354Smjacob 5085157354Smjacob mpt_prt(mpt, "req %p:%u tgt:rdesc 0x%x resid %u xfrd %u ccb %p treq %p " 5086157662Smjacob "nx %d tag 0x%08x state=%d\n", req, req->serno, tgt->reply_desc, 5087157354Smjacob tgt->resid, tgt->bytes_xfered, tgt->ccb, tgt->req, tgt->nxfers, 5088157354Smjacob tgt->tag_id, tgt->state); 5089157354Smjacob} 5090157354Smjacob 5091157354Smjacobstatic void 5092157354Smjacobmpt_tgt_dump_req_state(struct mpt_softc *mpt, request_t *req) 5093157354Smjacob{ 5094224493Smarius 5095157354Smjacob mpt_prt(mpt, "req %p:%u index %u (%x) state %x\n", req, req->serno, 5096157354Smjacob req->index, req->index, req->state); 5097157354Smjacob mpt_tgt_dump_tgt_state(mpt, req); 5098157354Smjacob} 5099157354Smjacob 5100157354Smjacobstatic int 5101157354Smjacobmpt_scsi_tgt_reply_handler(struct mpt_softc *mpt, request_t *req, 5102157354Smjacob uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) 5103157354Smjacob{ 5104157354Smjacob int dbg; 5105157354Smjacob union ccb *ccb; 5106157354Smjacob U16 status; 5107157354Smjacob 5108157354Smjacob if (reply_frame == NULL) { 5109147883Sscottl /* 5110157662Smjacob * Figure out what the state of the command is. 5111147883Sscottl */ 5112157354Smjacob mpt_tgt_state_t *tgt = MPT_TGT_STATE(mpt, req); 5113147883Sscottl 5114157662Smjacob#ifdef INVARIANTS 5115157662Smjacob mpt_req_spcl(mpt, req, "turbo scsi_tgt_reply", __LINE__); 5116157354Smjacob if (tgt->req) { 5117157662Smjacob mpt_req_not_spcl(mpt, tgt->req, 5118157662Smjacob "turbo scsi_tgt_reply associated req", __LINE__); 5119157354Smjacob } 5120157662Smjacob#endif 5121157354Smjacob switch(tgt->state) { 5122157354Smjacob case TGT_STATE_LOADED: 5123157662Smjacob /* 5124157662Smjacob * This is a new command starting. 5125157662Smjacob */ 5126157354Smjacob mpt_scsi_tgt_atio(mpt, req, reply_desc); 5127157354Smjacob break; 5128157354Smjacob case TGT_STATE_MOVING_DATA: 5129157354Smjacob { 5130157354Smjacob uint8_t *sp = NULL, sense[MPT_SENSE_SIZE]; 5131157354Smjacob 5132157354Smjacob ccb = tgt->ccb; 5133157662Smjacob if (tgt->req == NULL) { 5134157662Smjacob panic("mpt: turbo target reply with null " 5135157662Smjacob "associated request moving data"); 5136157662Smjacob /* NOTREACHED */ 5137157662Smjacob } 5138157662Smjacob if (ccb == NULL) { 5139160391Smjacob if (tgt->is_local == 0) { 5140160391Smjacob panic("mpt: turbo target reply with " 5141160391Smjacob "null associated ccb moving data"); 5142160391Smjacob /* NOTREACHED */ 5143160391Smjacob } 5144160391Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 5145160391Smjacob "TARGET_ASSIST local done\n"); 5146160391Smjacob TAILQ_REMOVE(&mpt->request_pending_list, 5147160391Smjacob tgt->req, links); 5148160391Smjacob mpt_free_request(mpt, tgt->req); 5149160391Smjacob tgt->req = NULL; 5150160391Smjacob mpt_scsi_tgt_status(mpt, NULL, req, 5151160391Smjacob 0, NULL); 5152160391Smjacob return (TRUE); 5153157662Smjacob } 5154157354Smjacob tgt->ccb = NULL; 5155157354Smjacob tgt->nxfers++; 5156169293Smjacob mpt_req_untimeout(req, mpt_timeout, ccb); 5157157354Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 5158157662Smjacob "TARGET_ASSIST %p (req %p:%u) done tag 0x%x\n", 5159157662Smjacob ccb, tgt->req, tgt->req->serno, ccb->csio.tag_id); 5160157354Smjacob /* 5161157354Smjacob * Free the Target Assist Request 5162157354Smjacob */ 5163157662Smjacob KASSERT(tgt->req->ccb == ccb, 5164157662Smjacob ("tgt->req %p:%u tgt->req->ccb %p", tgt->req, 5165157662Smjacob tgt->req->serno, tgt->req->ccb)); 5166157662Smjacob TAILQ_REMOVE(&mpt->request_pending_list, 5167157662Smjacob tgt->req, links); 5168157354Smjacob mpt_free_request(mpt, tgt->req); 5169157354Smjacob tgt->req = NULL; 5170157662Smjacob 5171157354Smjacob /* 5172157354Smjacob * Do we need to send status now? That is, are 5173157354Smjacob * we done with all our data transfers? 5174157354Smjacob */ 5175157354Smjacob if ((ccb->ccb_h.flags & CAM_SEND_STATUS) == 0) { 5176157354Smjacob mpt_set_ccb_status(ccb, CAM_REQ_CMP); 5177157354Smjacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 5178157354Smjacob KASSERT(ccb->ccb_h.status, 5179231629Smarius ("zero ccb sts at %d", __LINE__)); 5180157354Smjacob tgt->state = TGT_STATE_IN_CAM; 5181157354Smjacob if (mpt->outofbeer) { 5182157354Smjacob ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 5183157354Smjacob mpt->outofbeer = 0; 5184157354Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, "THAWQ\n"); 5185157354Smjacob } 5186157354Smjacob xpt_done(ccb); 5187157354Smjacob break; 5188157354Smjacob } 5189157662Smjacob /* 5190157662Smjacob * Otherwise, send status (and sense) 5191157662Smjacob */ 5192157354Smjacob if (ccb->ccb_h.flags & CAM_SEND_SENSE) { 5193157354Smjacob sp = sense; 5194157354Smjacob memcpy(sp, &ccb->csio.sense_data, 5195157354Smjacob min(ccb->csio.sense_len, MPT_SENSE_SIZE)); 5196157354Smjacob } 5197157354Smjacob mpt_scsi_tgt_status(mpt, ccb, req, 5198157354Smjacob ccb->csio.scsi_status, sp); 5199157354Smjacob break; 5200157354Smjacob } 5201157354Smjacob case TGT_STATE_SENDING_STATUS: 5202157354Smjacob case TGT_STATE_MOVING_DATA_AND_STATUS: 5203157354Smjacob { 5204157354Smjacob int ioindex; 5205157354Smjacob ccb = tgt->ccb; 5206157354Smjacob 5207157662Smjacob if (tgt->req == NULL) { 5208157662Smjacob panic("mpt: turbo target reply with null " 5209157662Smjacob "associated request sending status"); 5210157662Smjacob /* NOTREACHED */ 5211157662Smjacob } 5212157662Smjacob 5213157354Smjacob if (ccb) { 5214157354Smjacob tgt->ccb = NULL; 5215157662Smjacob if (tgt->state == 5216157662Smjacob TGT_STATE_MOVING_DATA_AND_STATUS) { 5217157662Smjacob tgt->nxfers++; 5218157662Smjacob } 5219169293Smjacob mpt_req_untimeout(req, mpt_timeout, ccb); 5220157354Smjacob if (ccb->ccb_h.flags & CAM_SEND_SENSE) { 5221157354Smjacob ccb->ccb_h.status |= CAM_SENT_SENSE; 5222157354Smjacob } 5223157354Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 5224157354Smjacob "TARGET_STATUS tag %x sts %x flgs %x req " 5225157354Smjacob "%p\n", ccb->csio.tag_id, ccb->ccb_h.status, 5226157354Smjacob ccb->ccb_h.flags, tgt->req); 5227157354Smjacob /* 5228157354Smjacob * Free the Target Send Status Request 5229157354Smjacob */ 5230157662Smjacob KASSERT(tgt->req->ccb == ccb, 5231157662Smjacob ("tgt->req %p:%u tgt->req->ccb %p", 5232157662Smjacob tgt->req, tgt->req->serno, tgt->req->ccb)); 5233157354Smjacob /* 5234157354Smjacob * Notify CAM that we're done 5235157354Smjacob */ 5236157354Smjacob mpt_set_ccb_status(ccb, CAM_REQ_CMP); 5237157354Smjacob ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 5238157354Smjacob KASSERT(ccb->ccb_h.status, 5239231629Smarius ("ZERO ccb sts at %d", __LINE__)); 5240157354Smjacob tgt->ccb = NULL; 5241157354Smjacob } else { 5242157354Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, 5243157662Smjacob "TARGET_STATUS non-CAM for req %p:%u\n", 5244157662Smjacob tgt->req, tgt->req->serno); 5245157354Smjacob } 5246157662Smjacob TAILQ_REMOVE(&mpt->request_pending_list, 5247157662Smjacob tgt->req, links); 5248157354Smjacob mpt_free_request(mpt, tgt->req); 5249157354Smjacob tgt->req = NULL; 5250157354Smjacob 5251157354Smjacob /* 5252157354Smjacob * And re-post the Command Buffer. 5253160391Smjacob * This will reset the state. 5254157354Smjacob */ 5255157354Smjacob ioindex = GET_IO_INDEX(reply_desc); 5256157662Smjacob TAILQ_REMOVE(&mpt->request_pending_list, req, links); 5257160391Smjacob tgt->is_local = 0; 5258157354Smjacob mpt_post_target_command(mpt, req, ioindex); 5259157354Smjacob 5260157354Smjacob /* 5261157354Smjacob * And post a done for anyone who cares 5262157354Smjacob */ 5263157354Smjacob if (ccb) { 5264157354Smjacob if (mpt->outofbeer) { 5265157354Smjacob ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 5266157354Smjacob mpt->outofbeer = 0; 5267157354Smjacob mpt_lprt(mpt, MPT_PRT_DEBUG, "THAWQ\n"); 5268157354Smjacob } 5269157354Smjacob xpt_done(ccb); 5270157354Smjacob } 5271157354Smjacob break; 5272157354Smjacob } 5273157354Smjacob case TGT_STATE_NIL: /* XXX This Never Happens XXX */ 5274157354Smjacob tgt->state = TGT_STATE_LOADED; 5275157354Smjacob break; 5276157354Smjacob default: 5277157354Smjacob mpt_prt(mpt, "Unknown Target State 0x%x in Context " 5278157354Smjacob "Reply Function\n", tgt->state); 5279157354Smjacob } 5280157354Smjacob return (TRUE); 5281147883Sscottl } 5282157354Smjacob 5283157354Smjacob status = le16toh(reply_frame->IOCStatus); 5284157354Smjacob if (status != MPI_IOCSTATUS_SUCCESS) { 5285157354Smjacob dbg = MPT_PRT_ERROR; 5286157354Smjacob } else { 5287157354Smjacob dbg = MPT_PRT_DEBUG1; 5288157354Smjacob } 5289157354Smjacob 5290157354Smjacob mpt_lprt(mpt, dbg, 5291157354Smjacob "SCSI_TGT REPLY: req=%p:%u reply=%p func=%x IOCstatus 0x%x\n", 5292157354Smjacob req, req->serno, reply_frame, reply_frame->Function, status); 5293157354Smjacob 5294157354Smjacob switch (reply_frame->Function) { 5295157354Smjacob case MPI_FUNCTION_TARGET_CMD_BUFFER_POST: 5296157354Smjacob { 5297157662Smjacob mpt_tgt_state_t *tgt; 5298157662Smjacob#ifdef INVARIANTS 5299157662Smjacob mpt_req_spcl(mpt, req, "tgt reply BUFFER POST", __LINE__); 5300157662Smjacob#endif 5301157662Smjacob if (status != MPI_IOCSTATUS_SUCCESS) { 5302157662Smjacob /* 5303157662Smjacob * XXX What to do? 5304157662Smjacob */ 5305157662Smjacob break; 5306157662Smjacob } 5307157662Smjacob tgt = MPT_TGT_STATE(mpt, req); 5308157354Smjacob KASSERT(tgt->state == TGT_STATE_LOADING, 5309231629Smarius ("bad state 0x%x on reply to buffer post", tgt->state)); 5310157662Smjacob mpt_assign_serno(mpt, req); 5311157354Smjacob tgt->state = TGT_STATE_LOADED; 5312157354Smjacob break; 5313157354Smjacob } 5314157354Smjacob case MPI_FUNCTION_TARGET_ASSIST: 5315157662Smjacob#ifdef INVARIANTS 5316157662Smjacob mpt_req_not_spcl(mpt, req, "tgt reply TARGET ASSIST", __LINE__); 5317157662Smjacob#endif 5318157662Smjacob mpt_prt(mpt, "target assist completion\n"); 5319157662Smjacob TAILQ_REMOVE(&mpt->request_pending_list, req, links); 5320157354Smjacob mpt_free_request(mpt, req); 5321157354Smjacob break; 5322157354Smjacob case MPI_FUNCTION_TARGET_STATUS_SEND: 5323157662Smjacob#ifdef INVARIANTS 5324157662Smjacob mpt_req_not_spcl(mpt, req, "tgt reply STATUS SEND", __LINE__); 5325157662Smjacob#endif 5326157662Smjacob mpt_prt(mpt, "status send completion\n"); 5327157662Smjacob TAILQ_REMOVE(&mpt->request_pending_list, req, links); 5328157354Smjacob mpt_free_request(mpt, req); 5329157354Smjacob break; 5330157354Smjacob case MPI_FUNCTION_TARGET_MODE_ABORT: 5331157354Smjacob { 5332157354Smjacob PTR_MSG_TARGET_MODE_ABORT_REPLY abtrp = 5333157354Smjacob (PTR_MSG_TARGET_MODE_ABORT_REPLY) reply_frame; 5334157354Smjacob PTR_MSG_TARGET_MODE_ABORT abtp = 5335157354Smjacob (PTR_MSG_TARGET_MODE_ABORT) req->req_vbuf; 5336157354Smjacob uint32_t cc = GET_IO_INDEX(le32toh(abtp->ReplyWord)); 5337157662Smjacob#ifdef INVARIANTS 5338157662Smjacob mpt_req_not_spcl(mpt, req, "tgt reply TMODE ABORT", __LINE__); 5339157662Smjacob#endif 5340157354Smjacob mpt_prt(mpt, "ABORT RX_ID 0x%x Complete; status 0x%x cnt %u\n", 5341157354Smjacob cc, le16toh(abtrp->IOCStatus), le32toh(abtrp->AbortCount)); 5342157662Smjacob TAILQ_REMOVE(&mpt->request_pending_list, req, links); 5343157354Smjacob mpt_free_request(mpt, req); 5344157354Smjacob break; 5345157354Smjacob } 5346157354Smjacob default: 5347157354Smjacob mpt_prt(mpt, "Unknown Target Address Reply Function code: " 5348157354Smjacob "0x%x\n", reply_frame->Function); 5349157354Smjacob break; 5350157354Smjacob } 5351157354Smjacob return (TRUE); 5352147883Sscottl} 5353