1991554f2SKenneth D. Merry /*- 2991554f2SKenneth D. Merry * Copyright (c) 2009 Yahoo! Inc. 3a2c14879SStephen McConnell * Copyright (c) 2011-2015 LSI Corp. 47a2a6a1aSStephen McConnell * Copyright (c) 2013-2016 Avago Technologies 5991554f2SKenneth D. Merry * All rights reserved. 6991554f2SKenneth D. Merry * 7991554f2SKenneth D. Merry * Redistribution and use in source and binary forms, with or without 8991554f2SKenneth D. Merry * modification, are permitted provided that the following conditions 9991554f2SKenneth D. Merry * are met: 10991554f2SKenneth D. Merry * 1. Redistributions of source code must retain the above copyright 11991554f2SKenneth D. Merry * notice, this list of conditions and the following disclaimer. 12991554f2SKenneth D. Merry * 2. Redistributions in binary form must reproduce the above copyright 13991554f2SKenneth D. Merry * notice, this list of conditions and the following disclaimer in the 14991554f2SKenneth D. Merry * documentation and/or other materials provided with the distribution. 15991554f2SKenneth D. Merry * 16991554f2SKenneth D. Merry * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17991554f2SKenneth D. Merry * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18991554f2SKenneth D. Merry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19991554f2SKenneth D. Merry * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20991554f2SKenneth D. Merry * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21991554f2SKenneth D. Merry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22991554f2SKenneth D. Merry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23991554f2SKenneth D. Merry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24991554f2SKenneth D. Merry * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25991554f2SKenneth D. Merry * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26991554f2SKenneth D. Merry * SUCH DAMAGE. 27a2c14879SStephen McConnell * 28a2c14879SStephen McConnell * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD 29a2c14879SStephen McConnell * 30991554f2SKenneth D. Merry */ 31991554f2SKenneth D. Merry 32991554f2SKenneth D. Merry #include <sys/cdefs.h> 33991554f2SKenneth D. Merry __FBSDID("$FreeBSD$"); 34991554f2SKenneth D. Merry 35a2c14879SStephen McConnell /* Communications core for Avago Technologies (LSI) MPT3 */ 36991554f2SKenneth D. Merry 37991554f2SKenneth D. Merry /* TODO Move headers to mprvar */ 38991554f2SKenneth D. Merry #include <sys/types.h> 39991554f2SKenneth D. Merry #include <sys/param.h> 40991554f2SKenneth D. Merry #include <sys/systm.h> 41991554f2SKenneth D. Merry #include <sys/kernel.h> 42991554f2SKenneth D. Merry #include <sys/selinfo.h> 43991554f2SKenneth D. Merry #include <sys/module.h> 44991554f2SKenneth D. Merry #include <sys/bus.h> 45991554f2SKenneth D. Merry #include <sys/conf.h> 46991554f2SKenneth D. Merry #include <sys/bio.h> 47991554f2SKenneth D. Merry #include <sys/malloc.h> 48991554f2SKenneth D. Merry #include <sys/uio.h> 49991554f2SKenneth D. Merry #include <sys/sysctl.h> 50991554f2SKenneth D. Merry #include <sys/endian.h> 51991554f2SKenneth D. Merry #include <sys/queue.h> 52991554f2SKenneth D. Merry #include <sys/kthread.h> 53991554f2SKenneth D. Merry #include <sys/taskqueue.h> 54991554f2SKenneth D. Merry #include <sys/sbuf.h> 55991554f2SKenneth D. Merry 56991554f2SKenneth D. Merry #include <machine/bus.h> 57991554f2SKenneth D. Merry #include <machine/resource.h> 58991554f2SKenneth D. Merry #include <sys/rman.h> 59991554f2SKenneth D. Merry 60991554f2SKenneth D. Merry #include <machine/stdarg.h> 61991554f2SKenneth D. Merry 62991554f2SKenneth D. Merry #include <cam/cam.h> 63991554f2SKenneth D. Merry #include <cam/cam_ccb.h> 64991554f2SKenneth D. Merry #include <cam/cam_debug.h> 65991554f2SKenneth D. Merry #include <cam/cam_sim.h> 66991554f2SKenneth D. Merry #include <cam/cam_xpt_sim.h> 67991554f2SKenneth D. Merry #include <cam/cam_xpt_periph.h> 68991554f2SKenneth D. Merry #include <cam/cam_periph.h> 69991554f2SKenneth D. Merry #include <cam/scsi/scsi_all.h> 70991554f2SKenneth D. Merry #include <cam/scsi/scsi_message.h> 71991554f2SKenneth D. Merry #if __FreeBSD_version >= 900026 72991554f2SKenneth D. Merry #include <cam/scsi/smp_all.h> 73991554f2SKenneth D. Merry #endif 74991554f2SKenneth D. Merry 7567feec50SStephen McConnell #include <dev/nvme/nvme.h> 7667feec50SStephen McConnell 77991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_type.h> 78991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2.h> 79991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_ioc.h> 80991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_sas.h> 8167feec50SStephen McConnell #include <dev/mpr/mpi/mpi2_pci.h> 82991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_cnfg.h> 83991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_init.h> 84991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_tool.h> 85991554f2SKenneth D. Merry #include <dev/mpr/mpr_ioctl.h> 86991554f2SKenneth D. Merry #include <dev/mpr/mprvar.h> 87991554f2SKenneth D. Merry #include <dev/mpr/mpr_table.h> 88991554f2SKenneth D. Merry #include <dev/mpr/mpr_sas.h> 89991554f2SKenneth D. Merry 90991554f2SKenneth D. Merry #define MPRSAS_DISCOVERY_TIMEOUT 20 91991554f2SKenneth D. Merry #define MPRSAS_MAX_DISCOVERY_TIMEOUTS 10 /* 200 seconds */ 92991554f2SKenneth D. Merry 93991554f2SKenneth D. Merry /* 94991554f2SKenneth D. Merry * static array to check SCSI OpCode for EEDP protection bits 95991554f2SKenneth D. Merry */ 96991554f2SKenneth D. Merry #define PRO_R MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP 97991554f2SKenneth D. Merry #define PRO_W MPI2_SCSIIO_EEDPFLAGS_INSERT_OP 98991554f2SKenneth D. Merry #define PRO_V MPI2_SCSIIO_EEDPFLAGS_INSERT_OP 99991554f2SKenneth D. Merry static uint8_t op_code_prot[256] = { 100991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, 103991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104991554f2SKenneth D. Merry 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, 109991554f2SKenneth D. Merry 0, 0, 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, 111991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 114991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 116991554f2SKenneth D. Merry }; 117991554f2SKenneth D. Merry 118991554f2SKenneth D. Merry MALLOC_DEFINE(M_MPRSAS, "MPRSAS", "MPR SAS memory"); 119991554f2SKenneth D. Merry 120991554f2SKenneth D. Merry static void mprsas_remove_device(struct mpr_softc *, struct mpr_command *); 121991554f2SKenneth D. Merry static void mprsas_remove_complete(struct mpr_softc *, struct mpr_command *); 122991554f2SKenneth D. Merry static void mprsas_action(struct cam_sim *sim, union ccb *ccb); 123991554f2SKenneth D. Merry static void mprsas_poll(struct cam_sim *sim); 124991554f2SKenneth D. Merry static void mprsas_scsiio_timeout(void *data); 1257a2a6a1aSStephen McConnell static void mprsas_abort_complete(struct mpr_softc *sc, struct mpr_command *cm); 126991554f2SKenneth D. Merry static void mprsas_action_scsiio(struct mprsas_softc *, union ccb *); 127991554f2SKenneth D. Merry static void mprsas_scsiio_complete(struct mpr_softc *, struct mpr_command *); 128991554f2SKenneth D. Merry static void mprsas_action_resetdev(struct mprsas_softc *, union ccb *); 1297a2a6a1aSStephen McConnell static void mprsas_resetdev_complete(struct mpr_softc *, struct mpr_command *); 130991554f2SKenneth D. Merry static int mprsas_send_abort(struct mpr_softc *sc, struct mpr_command *tm, 131991554f2SKenneth D. Merry struct mpr_command *cm); 132991554f2SKenneth D. Merry static void mprsas_async(void *callback_arg, uint32_t code, 133991554f2SKenneth D. Merry struct cam_path *path, void *arg); 134991554f2SKenneth D. Merry #if (__FreeBSD_version < 901503) || \ 135991554f2SKenneth D. Merry ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) 136991554f2SKenneth D. Merry static void mprsas_check_eedp(struct mpr_softc *sc, struct cam_path *path, 137991554f2SKenneth D. Merry struct ccb_getdev *cgd); 138991554f2SKenneth D. Merry static void mprsas_read_cap_done(struct cam_periph *periph, 139991554f2SKenneth D. Merry union ccb *done_ccb); 140991554f2SKenneth D. Merry #endif 141991554f2SKenneth D. Merry static int mprsas_send_portenable(struct mpr_softc *sc); 142991554f2SKenneth D. Merry static void mprsas_portenable_complete(struct mpr_softc *sc, 143991554f2SKenneth D. Merry struct mpr_command *cm); 144991554f2SKenneth D. Merry 145991554f2SKenneth D. Merry #if __FreeBSD_version >= 900026 1467a2a6a1aSStephen McConnell static void mprsas_smpio_complete(struct mpr_softc *sc, struct mpr_command *cm); 1477a2a6a1aSStephen McConnell static void mprsas_send_smpcmd(struct mprsas_softc *sassc, union ccb *ccb, 1487a2a6a1aSStephen McConnell uint64_t sasaddr); 149a2c14879SStephen McConnell static void mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb); 150a2c14879SStephen McConnell #endif //FreeBSD_version >= 900026 151991554f2SKenneth D. Merry 152991554f2SKenneth D. Merry struct mprsas_target * 153991554f2SKenneth D. Merry mprsas_find_target_by_handle(struct mprsas_softc *sassc, int start, 154991554f2SKenneth D. Merry uint16_t handle) 155991554f2SKenneth D. Merry { 156991554f2SKenneth D. Merry struct mprsas_target *target; 157991554f2SKenneth D. Merry int i; 158991554f2SKenneth D. Merry 159991554f2SKenneth D. Merry for (i = start; i < sassc->maxtargets; i++) { 160991554f2SKenneth D. Merry target = &sassc->targets[i]; 161991554f2SKenneth D. Merry if (target->handle == handle) 162991554f2SKenneth D. Merry return (target); 163991554f2SKenneth D. Merry } 164991554f2SKenneth D. Merry 165991554f2SKenneth D. Merry return (NULL); 166991554f2SKenneth D. Merry } 167991554f2SKenneth D. Merry 168991554f2SKenneth D. Merry /* we need to freeze the simq during attach and diag reset, to avoid failing 169991554f2SKenneth D. Merry * commands before device handles have been found by discovery. Since 170991554f2SKenneth D. Merry * discovery involves reading config pages and possibly sending commands, 171991554f2SKenneth D. Merry * discovery actions may continue even after we receive the end of discovery 172991554f2SKenneth D. Merry * event, so refcount discovery actions instead of assuming we can unfreeze 173991554f2SKenneth D. Merry * the simq when we get the event. 174991554f2SKenneth D. Merry */ 175991554f2SKenneth D. Merry void 176991554f2SKenneth D. Merry mprsas_startup_increment(struct mprsas_softc *sassc) 177991554f2SKenneth D. Merry { 178991554f2SKenneth D. Merry MPR_FUNCTRACE(sassc->sc); 179991554f2SKenneth D. Merry 180991554f2SKenneth D. Merry if ((sassc->flags & MPRSAS_IN_STARTUP) != 0) { 181991554f2SKenneth D. Merry if (sassc->startup_refcount++ == 0) { 182991554f2SKenneth D. Merry /* just starting, freeze the simq */ 183991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_INIT, 184991554f2SKenneth D. Merry "%s freezing simq\n", __func__); 185a371d6f9SKenneth D. Merry #if (__FreeBSD_version >= 1000039) || \ 186a371d6f9SKenneth D. Merry ((__FreeBSD_version < 1000000) && (__FreeBSD_version >= 902502)) 187991554f2SKenneth D. Merry xpt_hold_boot(); 188991554f2SKenneth D. Merry #endif 189991554f2SKenneth D. Merry xpt_freeze_simq(sassc->sim, 1); 190991554f2SKenneth D. Merry } 191991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_INIT, "%s refcount %u\n", __func__, 192991554f2SKenneth D. Merry sassc->startup_refcount); 193991554f2SKenneth D. Merry } 194991554f2SKenneth D. Merry } 195991554f2SKenneth D. Merry 196991554f2SKenneth D. Merry void 197991554f2SKenneth D. Merry mprsas_release_simq_reinit(struct mprsas_softc *sassc) 198991554f2SKenneth D. Merry { 199991554f2SKenneth D. Merry if (sassc->flags & MPRSAS_QUEUE_FROZEN) { 200991554f2SKenneth D. Merry sassc->flags &= ~MPRSAS_QUEUE_FROZEN; 201991554f2SKenneth D. Merry xpt_release_simq(sassc->sim, 1); 202991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_INFO, "Unfreezing SIM queue\n"); 203991554f2SKenneth D. Merry } 204991554f2SKenneth D. Merry } 205991554f2SKenneth D. Merry 206991554f2SKenneth D. Merry void 207991554f2SKenneth D. Merry mprsas_startup_decrement(struct mprsas_softc *sassc) 208991554f2SKenneth D. Merry { 209991554f2SKenneth D. Merry MPR_FUNCTRACE(sassc->sc); 210991554f2SKenneth D. Merry 211991554f2SKenneth D. Merry if ((sassc->flags & MPRSAS_IN_STARTUP) != 0) { 212991554f2SKenneth D. Merry if (--sassc->startup_refcount == 0) { 213991554f2SKenneth D. Merry /* finished all discovery-related actions, release 214991554f2SKenneth D. Merry * the simq and rescan for the latest topology. 215991554f2SKenneth D. Merry */ 216991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_INIT, 217991554f2SKenneth D. Merry "%s releasing simq\n", __func__); 218991554f2SKenneth D. Merry sassc->flags &= ~MPRSAS_IN_STARTUP; 219991554f2SKenneth D. Merry xpt_release_simq(sassc->sim, 1); 220a371d6f9SKenneth D. Merry #if (__FreeBSD_version >= 1000039) || \ 221a371d6f9SKenneth D. Merry ((__FreeBSD_version < 1000000) && (__FreeBSD_version >= 902502)) 222991554f2SKenneth D. Merry xpt_release_boot(); 223991554f2SKenneth D. Merry #else 224991554f2SKenneth D. Merry mprsas_rescan_target(sassc->sc, NULL); 225991554f2SKenneth D. Merry #endif 226991554f2SKenneth D. Merry } 227991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_INIT, "%s refcount %u\n", __func__, 228991554f2SKenneth D. Merry sassc->startup_refcount); 229991554f2SKenneth D. Merry } 230991554f2SKenneth D. Merry } 231991554f2SKenneth D. Merry 232a2c14879SStephen McConnell /* The firmware requires us to stop sending commands when we're doing task 233991554f2SKenneth D. Merry * management, so refcount the TMs and keep the simq frozen when any are in 234991554f2SKenneth D. Merry * use. 235991554f2SKenneth D. Merry */ 236991554f2SKenneth D. Merry struct mpr_command * 237991554f2SKenneth D. Merry mprsas_alloc_tm(struct mpr_softc *sc) 238991554f2SKenneth D. Merry { 239991554f2SKenneth D. Merry struct mpr_command *tm; 240991554f2SKenneth D. Merry 241991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 242991554f2SKenneth D. Merry tm = mpr_alloc_high_priority_command(sc); 243991554f2SKenneth D. Merry return tm; 244991554f2SKenneth D. Merry } 245991554f2SKenneth D. Merry 246991554f2SKenneth D. Merry void 247991554f2SKenneth D. Merry mprsas_free_tm(struct mpr_softc *sc, struct mpr_command *tm) 248991554f2SKenneth D. Merry { 24988619392SStephen McConnell int target_id = 0xFFFFFFFF; 25088619392SStephen McConnell 251a2c14879SStephen McConnell MPR_FUNCTRACE(sc); 252991554f2SKenneth D. Merry if (tm == NULL) 253991554f2SKenneth D. Merry return; 254991554f2SKenneth D. Merry 255a2c14879SStephen McConnell /* 256a2c14879SStephen McConnell * For TM's the devq is frozen for the device. Unfreeze it here and 257a2c14879SStephen McConnell * free the resources used for freezing the devq. Must clear the 258a2c14879SStephen McConnell * INRESET flag as well or scsi I/O will not work. 259991554f2SKenneth D. Merry */ 260a2c14879SStephen McConnell if (tm->cm_targ != NULL) { 261a2c14879SStephen McConnell tm->cm_targ->flags &= ~MPRSAS_TARGET_INRESET; 26288619392SStephen McConnell target_id = tm->cm_targ->tid; 263991554f2SKenneth D. Merry } 264a2c14879SStephen McConnell if (tm->cm_ccb) { 265a2c14879SStephen McConnell mpr_dprint(sc, MPR_INFO, "Unfreezing devq for target ID %d\n", 26688619392SStephen McConnell target_id); 267a2c14879SStephen McConnell xpt_release_devq(tm->cm_ccb->ccb_h.path, 1, TRUE); 268a2c14879SStephen McConnell xpt_free_path(tm->cm_ccb->ccb_h.path); 269a2c14879SStephen McConnell xpt_free_ccb(tm->cm_ccb); 270a2c14879SStephen McConnell } 271991554f2SKenneth D. Merry 272991554f2SKenneth D. Merry mpr_free_high_priority_command(sc, tm); 273991554f2SKenneth D. Merry } 274991554f2SKenneth D. Merry 275991554f2SKenneth D. Merry void 276991554f2SKenneth D. Merry mprsas_rescan_target(struct mpr_softc *sc, struct mprsas_target *targ) 277991554f2SKenneth D. Merry { 278991554f2SKenneth D. Merry struct mprsas_softc *sassc = sc->sassc; 279991554f2SKenneth D. Merry path_id_t pathid; 280991554f2SKenneth D. Merry target_id_t targetid; 281991554f2SKenneth D. Merry union ccb *ccb; 282991554f2SKenneth D. Merry 283991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 284991554f2SKenneth D. Merry pathid = cam_sim_path(sassc->sim); 285991554f2SKenneth D. Merry if (targ == NULL) 286991554f2SKenneth D. Merry targetid = CAM_TARGET_WILDCARD; 287991554f2SKenneth D. Merry else 288991554f2SKenneth D. Merry targetid = targ - sassc->targets; 289991554f2SKenneth D. Merry 290991554f2SKenneth D. Merry /* 291991554f2SKenneth D. Merry * Allocate a CCB and schedule a rescan. 292991554f2SKenneth D. Merry */ 293991554f2SKenneth D. Merry ccb = xpt_alloc_ccb_nowait(); 294991554f2SKenneth D. Merry if (ccb == NULL) { 295991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "unable to alloc CCB for rescan\n"); 296991554f2SKenneth D. Merry return; 297991554f2SKenneth D. Merry } 298991554f2SKenneth D. Merry 299a2c14879SStephen McConnell if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid, targetid, 300a2c14879SStephen McConnell CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 301991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "unable to create path for rescan\n"); 302991554f2SKenneth D. Merry xpt_free_ccb(ccb); 303991554f2SKenneth D. Merry return; 304991554f2SKenneth D. Merry } 305991554f2SKenneth D. Merry 306991554f2SKenneth D. Merry if (targetid == CAM_TARGET_WILDCARD) 307991554f2SKenneth D. Merry ccb->ccb_h.func_code = XPT_SCAN_BUS; 308991554f2SKenneth D. Merry else 309991554f2SKenneth D. Merry ccb->ccb_h.func_code = XPT_SCAN_TGT; 310991554f2SKenneth D. Merry 311991554f2SKenneth D. Merry mpr_dprint(sc, MPR_TRACE, "%s targetid %u\n", __func__, targetid); 312991554f2SKenneth D. Merry xpt_rescan(ccb); 313991554f2SKenneth D. Merry } 314991554f2SKenneth D. Merry 315991554f2SKenneth D. Merry static void 316991554f2SKenneth D. Merry mprsas_log_command(struct mpr_command *cm, u_int level, const char *fmt, ...) 317991554f2SKenneth D. Merry { 318991554f2SKenneth D. Merry struct sbuf sb; 319991554f2SKenneth D. Merry va_list ap; 320991554f2SKenneth D. Merry char str[192]; 321991554f2SKenneth D. Merry char path_str[64]; 322991554f2SKenneth D. Merry 323991554f2SKenneth D. Merry if (cm == NULL) 324991554f2SKenneth D. Merry return; 325991554f2SKenneth D. Merry 326991554f2SKenneth D. Merry /* No need to be in here if debugging isn't enabled */ 327991554f2SKenneth D. Merry if ((cm->cm_sc->mpr_debug & level) == 0) 328991554f2SKenneth D. Merry return; 329991554f2SKenneth D. Merry 330991554f2SKenneth D. Merry sbuf_new(&sb, str, sizeof(str), 0); 331991554f2SKenneth D. Merry 332991554f2SKenneth D. Merry va_start(ap, fmt); 333991554f2SKenneth D. Merry 334991554f2SKenneth D. Merry if (cm->cm_ccb != NULL) { 335991554f2SKenneth D. Merry xpt_path_string(cm->cm_ccb->csio.ccb_h.path, path_str, 336991554f2SKenneth D. Merry sizeof(path_str)); 337991554f2SKenneth D. Merry sbuf_cat(&sb, path_str); 338991554f2SKenneth D. Merry if (cm->cm_ccb->ccb_h.func_code == XPT_SCSI_IO) { 339991554f2SKenneth D. Merry scsi_command_string(&cm->cm_ccb->csio, &sb); 340991554f2SKenneth D. Merry sbuf_printf(&sb, "length %d ", 341991554f2SKenneth D. Merry cm->cm_ccb->csio.dxfer_len); 342991554f2SKenneth D. Merry } 343991554f2SKenneth D. Merry } else { 344991554f2SKenneth D. Merry sbuf_printf(&sb, "(noperiph:%s%d:%u:%u:%u): ", 345991554f2SKenneth D. Merry cam_sim_name(cm->cm_sc->sassc->sim), 346991554f2SKenneth D. Merry cam_sim_unit(cm->cm_sc->sassc->sim), 347991554f2SKenneth D. Merry cam_sim_bus(cm->cm_sc->sassc->sim), 348991554f2SKenneth D. Merry cm->cm_targ ? cm->cm_targ->tid : 0xFFFFFFFF, 349991554f2SKenneth D. Merry cm->cm_lun); 350991554f2SKenneth D. Merry } 351991554f2SKenneth D. Merry 352991554f2SKenneth D. Merry sbuf_printf(&sb, "SMID %u ", cm->cm_desc.Default.SMID); 353991554f2SKenneth D. Merry sbuf_vprintf(&sb, fmt, ap); 354991554f2SKenneth D. Merry sbuf_finish(&sb); 355c11c484fSScott Long mpr_print_field(cm->cm_sc, "%s", sbuf_data(&sb)); 356991554f2SKenneth D. Merry 357991554f2SKenneth D. Merry va_end(ap); 358991554f2SKenneth D. Merry } 359991554f2SKenneth D. Merry 360991554f2SKenneth D. Merry static void 361991554f2SKenneth D. Merry mprsas_remove_volume(struct mpr_softc *sc, struct mpr_command *tm) 362991554f2SKenneth D. Merry { 363991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *reply; 364991554f2SKenneth D. Merry struct mprsas_target *targ; 365991554f2SKenneth D. Merry uint16_t handle; 366991554f2SKenneth D. Merry 367991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 368991554f2SKenneth D. Merry 369991554f2SKenneth D. Merry reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 370991554f2SKenneth D. Merry handle = (uint16_t)(uintptr_t)tm->cm_complete_data; 371991554f2SKenneth D. Merry targ = tm->cm_targ; 372991554f2SKenneth D. Merry 373991554f2SKenneth D. Merry if (reply == NULL) { 374991554f2SKenneth D. Merry /* XXX retry the remove after the diag reset completes? */ 375991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "%s NULL reply resetting device " 376991554f2SKenneth D. Merry "0x%04x\n", __func__, handle); 377991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 378991554f2SKenneth D. Merry return; 379991554f2SKenneth D. Merry } 380991554f2SKenneth D. Merry 381d3f6eabfSStephen McConnell if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) != 382d3f6eabfSStephen McConnell MPI2_IOCSTATUS_SUCCESS) { 38358581c13SStephen McConnell mpr_dprint(sc, MPR_ERROR, "IOCStatus = 0x%x while resetting " 384d3f6eabfSStephen McConnell "device 0x%x\n", le16toh(reply->IOCStatus), handle); 385991554f2SKenneth D. Merry } 386991554f2SKenneth D. Merry 387991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "Reset aborted %u commands\n", 388d3f6eabfSStephen McConnell le32toh(reply->TerminationCount)); 389991554f2SKenneth D. Merry mpr_free_reply(sc, tm->cm_reply_data); 390991554f2SKenneth D. Merry tm->cm_reply = NULL; /* Ensures the reply won't get re-freed */ 391991554f2SKenneth D. Merry 392991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "clearing target %u handle 0x%04x\n", 393991554f2SKenneth D. Merry targ->tid, handle); 394991554f2SKenneth D. Merry 395991554f2SKenneth D. Merry /* 396991554f2SKenneth D. Merry * Don't clear target if remove fails because things will get confusing. 397991554f2SKenneth D. Merry * Leave the devname and sasaddr intact so that we know to avoid reusing 398991554f2SKenneth D. Merry * this target id if possible, and so we can assign the same target id 399991554f2SKenneth D. Merry * to this device if it comes back in the future. 400991554f2SKenneth D. Merry */ 401d3f6eabfSStephen McConnell if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) == 402d3f6eabfSStephen McConnell MPI2_IOCSTATUS_SUCCESS) { 403991554f2SKenneth D. Merry targ = tm->cm_targ; 404991554f2SKenneth D. Merry targ->handle = 0x0; 405991554f2SKenneth D. Merry targ->encl_handle = 0x0; 406991554f2SKenneth D. Merry targ->encl_level_valid = 0x0; 407991554f2SKenneth D. Merry targ->encl_level = 0x0; 408991554f2SKenneth D. Merry targ->connector_name[0] = ' '; 409991554f2SKenneth D. Merry targ->connector_name[1] = ' '; 410991554f2SKenneth D. Merry targ->connector_name[2] = ' '; 411991554f2SKenneth D. Merry targ->connector_name[3] = ' '; 412991554f2SKenneth D. Merry targ->encl_slot = 0x0; 413991554f2SKenneth D. Merry targ->exp_dev_handle = 0x0; 414991554f2SKenneth D. Merry targ->phy_num = 0x0; 415991554f2SKenneth D. Merry targ->linkrate = 0x0; 416991554f2SKenneth D. Merry targ->devinfo = 0x0; 417991554f2SKenneth D. Merry targ->flags = 0x0; 418991554f2SKenneth D. Merry targ->scsi_req_desc_type = 0; 419991554f2SKenneth D. Merry } 420991554f2SKenneth D. Merry 421991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 422991554f2SKenneth D. Merry } 423991554f2SKenneth D. Merry 424991554f2SKenneth D. Merry 425991554f2SKenneth D. Merry /* 426991554f2SKenneth D. Merry * No Need to call "MPI2_SAS_OP_REMOVE_DEVICE" For Volume removal. 427991554f2SKenneth D. Merry * Otherwise Volume Delete is same as Bare Drive Removal. 428991554f2SKenneth D. Merry */ 429991554f2SKenneth D. Merry void 430991554f2SKenneth D. Merry mprsas_prepare_volume_remove(struct mprsas_softc *sassc, uint16_t handle) 431991554f2SKenneth D. Merry { 432991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 433991554f2SKenneth D. Merry struct mpr_softc *sc; 434991554f2SKenneth D. Merry struct mpr_command *cm; 435991554f2SKenneth D. Merry struct mprsas_target *targ = NULL; 436991554f2SKenneth D. Merry 437991554f2SKenneth D. Merry MPR_FUNCTRACE(sassc->sc); 438991554f2SKenneth D. Merry sc = sassc->sc; 439991554f2SKenneth D. Merry 440991554f2SKenneth D. Merry targ = mprsas_find_target_by_handle(sassc, 0, handle); 441991554f2SKenneth D. Merry if (targ == NULL) { 442991554f2SKenneth D. Merry /* FIXME: what is the action? */ 443991554f2SKenneth D. Merry /* We don't know about this device? */ 444991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, 445991554f2SKenneth D. Merry "%s %d : invalid handle 0x%x \n", __func__,__LINE__, handle); 446991554f2SKenneth D. Merry return; 447991554f2SKenneth D. Merry } 448991554f2SKenneth D. Merry 449991554f2SKenneth D. Merry targ->flags |= MPRSAS_TARGET_INREMOVAL; 450991554f2SKenneth D. Merry 451991554f2SKenneth D. Merry cm = mprsas_alloc_tm(sc); 452991554f2SKenneth D. Merry if (cm == NULL) { 453991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, 454991554f2SKenneth D. Merry "%s: command alloc failure\n", __func__); 455991554f2SKenneth D. Merry return; 456991554f2SKenneth D. Merry } 457991554f2SKenneth D. Merry 458991554f2SKenneth D. Merry mprsas_rescan_target(sc, targ); 459991554f2SKenneth D. Merry 460991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; 461991554f2SKenneth D. Merry req->DevHandle = targ->handle; 462991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 463991554f2SKenneth D. Merry req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; 464991554f2SKenneth D. Merry 465991554f2SKenneth D. Merry /* SAS Hard Link Reset / SATA Link Reset */ 466991554f2SKenneth D. Merry req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; 467991554f2SKenneth D. Merry 468991554f2SKenneth D. Merry cm->cm_targ = targ; 469991554f2SKenneth D. Merry cm->cm_data = NULL; 470991554f2SKenneth D. Merry cm->cm_desc.HighPriority.RequestFlags = 471991554f2SKenneth D. Merry MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 472991554f2SKenneth D. Merry cm->cm_complete = mprsas_remove_volume; 473991554f2SKenneth D. Merry cm->cm_complete_data = (void *)(uintptr_t)handle; 474a2c14879SStephen McConnell 475a2c14879SStephen McConnell mpr_dprint(sc, MPR_INFO, "%s: Sending reset for target ID %d\n", 476a2c14879SStephen McConnell __func__, targ->tid); 477a2c14879SStephen McConnell mprsas_prepare_for_tm(sc, cm, targ, CAM_LUN_WILDCARD); 478a2c14879SStephen McConnell 479991554f2SKenneth D. Merry mpr_map_command(sc, cm); 480991554f2SKenneth D. Merry } 481991554f2SKenneth D. Merry 482991554f2SKenneth D. Merry /* 48367feec50SStephen McConnell * The firmware performs debounce on the link to avoid transient link errors 48467feec50SStephen McConnell * and false removals. When it does decide that link has been lost and a 48567feec50SStephen McConnell * device needs to go away, it expects that the host will perform a target reset 48667feec50SStephen McConnell * and then an op remove. The reset has the side-effect of aborting any 48767feec50SStephen McConnell * outstanding requests for the device, which is required for the op-remove to 48867feec50SStephen McConnell * succeed. It's not clear if the host should check for the device coming back 48967feec50SStephen McConnell * alive after the reset. 490991554f2SKenneth D. Merry */ 491991554f2SKenneth D. Merry void 492991554f2SKenneth D. Merry mprsas_prepare_remove(struct mprsas_softc *sassc, uint16_t handle) 493991554f2SKenneth D. Merry { 494991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 495991554f2SKenneth D. Merry struct mpr_softc *sc; 496991554f2SKenneth D. Merry struct mpr_command *cm; 497991554f2SKenneth D. Merry struct mprsas_target *targ = NULL; 498991554f2SKenneth D. Merry 499991554f2SKenneth D. Merry MPR_FUNCTRACE(sassc->sc); 500991554f2SKenneth D. Merry 501991554f2SKenneth D. Merry sc = sassc->sc; 502991554f2SKenneth D. Merry 503991554f2SKenneth D. Merry targ = mprsas_find_target_by_handle(sassc, 0, handle); 504991554f2SKenneth D. Merry if (targ == NULL) { 505991554f2SKenneth D. Merry /* FIXME: what is the action? */ 506991554f2SKenneth D. Merry /* We don't know about this device? */ 507991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s : invalid handle 0x%x \n", 508991554f2SKenneth D. Merry __func__, handle); 509991554f2SKenneth D. Merry return; 510991554f2SKenneth D. Merry } 511991554f2SKenneth D. Merry 512991554f2SKenneth D. Merry targ->flags |= MPRSAS_TARGET_INREMOVAL; 513991554f2SKenneth D. Merry 514991554f2SKenneth D. Merry cm = mprsas_alloc_tm(sc); 515991554f2SKenneth D. Merry if (cm == NULL) { 516991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: command alloc failure\n", 517991554f2SKenneth D. Merry __func__); 518991554f2SKenneth D. Merry return; 519991554f2SKenneth D. Merry } 520991554f2SKenneth D. Merry 521991554f2SKenneth D. Merry mprsas_rescan_target(sc, targ); 522991554f2SKenneth D. Merry 523991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; 524991554f2SKenneth D. Merry memset(req, 0, sizeof(*req)); 525991554f2SKenneth D. Merry req->DevHandle = htole16(targ->handle); 526991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 527991554f2SKenneth D. Merry req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; 528991554f2SKenneth D. Merry 529991554f2SKenneth D. Merry /* SAS Hard Link Reset / SATA Link Reset */ 530991554f2SKenneth D. Merry req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; 531991554f2SKenneth D. Merry 532991554f2SKenneth D. Merry cm->cm_targ = targ; 533991554f2SKenneth D. Merry cm->cm_data = NULL; 534991554f2SKenneth D. Merry cm->cm_desc.HighPriority.RequestFlags = 535991554f2SKenneth D. Merry MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 536991554f2SKenneth D. Merry cm->cm_complete = mprsas_remove_device; 537991554f2SKenneth D. Merry cm->cm_complete_data = (void *)(uintptr_t)handle; 538a2c14879SStephen McConnell 539a2c14879SStephen McConnell mpr_dprint(sc, MPR_INFO, "%s: Sending reset for target ID %d\n", 540a2c14879SStephen McConnell __func__, targ->tid); 541a2c14879SStephen McConnell mprsas_prepare_for_tm(sc, cm, targ, CAM_LUN_WILDCARD); 542a2c14879SStephen McConnell 543991554f2SKenneth D. Merry mpr_map_command(sc, cm); 544991554f2SKenneth D. Merry } 545991554f2SKenneth D. Merry 546991554f2SKenneth D. Merry static void 547991554f2SKenneth D. Merry mprsas_remove_device(struct mpr_softc *sc, struct mpr_command *tm) 548991554f2SKenneth D. Merry { 549991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *reply; 550991554f2SKenneth D. Merry MPI2_SAS_IOUNIT_CONTROL_REQUEST *req; 551991554f2SKenneth D. Merry struct mprsas_target *targ; 552991554f2SKenneth D. Merry struct mpr_command *next_cm; 553991554f2SKenneth D. Merry uint16_t handle; 554991554f2SKenneth D. Merry 555991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 556991554f2SKenneth D. Merry 557991554f2SKenneth D. Merry reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 558991554f2SKenneth D. Merry handle = (uint16_t)(uintptr_t)tm->cm_complete_data; 559991554f2SKenneth D. Merry targ = tm->cm_targ; 560991554f2SKenneth D. Merry 561991554f2SKenneth D. Merry /* 562991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 563991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 564991554f2SKenneth D. Merry * task management commands don't have S/G lists. 565991554f2SKenneth D. Merry */ 566991554f2SKenneth D. Merry if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 567991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for remove of " 568991554f2SKenneth D. Merry "handle %#04x! This should not happen!\n", __func__, 569991554f2SKenneth D. Merry tm->cm_flags, handle); 570991554f2SKenneth D. Merry } 571991554f2SKenneth D. Merry 572991554f2SKenneth D. Merry if (reply == NULL) { 573991554f2SKenneth D. Merry /* XXX retry the remove after the diag reset completes? */ 574991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "%s NULL reply resetting device " 575991554f2SKenneth D. Merry "0x%04x\n", __func__, handle); 576991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 577991554f2SKenneth D. Merry return; 578991554f2SKenneth D. Merry } 579991554f2SKenneth D. Merry 580d3f6eabfSStephen McConnell if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) != 581d3f6eabfSStephen McConnell MPI2_IOCSTATUS_SUCCESS) { 58258581c13SStephen McConnell mpr_dprint(sc, MPR_ERROR, "IOCStatus = 0x%x while resetting " 583991554f2SKenneth D. Merry "device 0x%x\n", le16toh(reply->IOCStatus), handle); 584991554f2SKenneth D. Merry } 585991554f2SKenneth D. Merry 586991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "Reset aborted %u commands\n", 587991554f2SKenneth D. Merry le32toh(reply->TerminationCount)); 588991554f2SKenneth D. Merry mpr_free_reply(sc, tm->cm_reply_data); 589991554f2SKenneth D. Merry tm->cm_reply = NULL; /* Ensures the reply won't get re-freed */ 590991554f2SKenneth D. Merry 591991554f2SKenneth D. Merry /* Reuse the existing command */ 592991554f2SKenneth D. Merry req = (MPI2_SAS_IOUNIT_CONTROL_REQUEST *)tm->cm_req; 593991554f2SKenneth D. Merry memset(req, 0, sizeof(*req)); 594991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; 595991554f2SKenneth D. Merry req->Operation = MPI2_SAS_OP_REMOVE_DEVICE; 596991554f2SKenneth D. Merry req->DevHandle = htole16(handle); 597991554f2SKenneth D. Merry tm->cm_data = NULL; 598991554f2SKenneth D. Merry tm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 599991554f2SKenneth D. Merry tm->cm_complete = mprsas_remove_complete; 600991554f2SKenneth D. Merry tm->cm_complete_data = (void *)(uintptr_t)handle; 601991554f2SKenneth D. Merry 602991554f2SKenneth D. Merry mpr_map_command(sc, tm); 603991554f2SKenneth D. Merry 604a2c14879SStephen McConnell mpr_dprint(sc, MPR_INFO, "clearing target %u handle 0x%04x\n", 605991554f2SKenneth D. Merry targ->tid, handle); 606991554f2SKenneth D. Merry if (targ->encl_level_valid) { 607a2c14879SStephen McConnell mpr_dprint(sc, MPR_INFO, "At enclosure level %d, slot %d, " 608991554f2SKenneth D. Merry "connector name (%4s)\n", targ->encl_level, targ->encl_slot, 609991554f2SKenneth D. Merry targ->connector_name); 610991554f2SKenneth D. Merry } 611991554f2SKenneth D. Merry TAILQ_FOREACH_SAFE(tm, &targ->commands, cm_link, next_cm) { 612991554f2SKenneth D. Merry union ccb *ccb; 613991554f2SKenneth D. Merry 614991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "Completing missed command %p\n", tm); 615991554f2SKenneth D. Merry ccb = tm->cm_complete_data; 616a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); 617991554f2SKenneth D. Merry mprsas_scsiio_complete(sc, tm); 618991554f2SKenneth D. Merry } 619991554f2SKenneth D. Merry } 620991554f2SKenneth D. Merry 621991554f2SKenneth D. Merry static void 622991554f2SKenneth D. Merry mprsas_remove_complete(struct mpr_softc *sc, struct mpr_command *tm) 623991554f2SKenneth D. Merry { 624991554f2SKenneth D. Merry MPI2_SAS_IOUNIT_CONTROL_REPLY *reply; 625991554f2SKenneth D. Merry uint16_t handle; 626991554f2SKenneth D. Merry struct mprsas_target *targ; 627991554f2SKenneth D. Merry struct mprsas_lun *lun; 628991554f2SKenneth D. Merry 629991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 630991554f2SKenneth D. Merry 631991554f2SKenneth D. Merry reply = (MPI2_SAS_IOUNIT_CONTROL_REPLY *)tm->cm_reply; 632991554f2SKenneth D. Merry handle = (uint16_t)(uintptr_t)tm->cm_complete_data; 633991554f2SKenneth D. Merry 634991554f2SKenneth D. Merry /* 635991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 636991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 637991554f2SKenneth D. Merry * task management commands don't have S/G lists. 638991554f2SKenneth D. Merry */ 639991554f2SKenneth D. Merry if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 640991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "%s: cm_flags = %#x for remove of " 641991554f2SKenneth D. Merry "handle %#04x! This should not happen!\n", __func__, 642991554f2SKenneth D. Merry tm->cm_flags, handle); 643991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 644991554f2SKenneth D. Merry return; 645991554f2SKenneth D. Merry } 646991554f2SKenneth D. Merry 647991554f2SKenneth D. Merry if (reply == NULL) { 648991554f2SKenneth D. Merry /* most likely a chip reset */ 649991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "%s NULL reply removing device " 650991554f2SKenneth D. Merry "0x%04x\n", __func__, handle); 651991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 652991554f2SKenneth D. Merry return; 653991554f2SKenneth D. Merry } 654991554f2SKenneth D. Merry 655991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "%s on handle 0x%04x, IOCStatus= 0x%x\n", 656991554f2SKenneth D. Merry __func__, handle, le16toh(reply->IOCStatus)); 657991554f2SKenneth D. Merry 658991554f2SKenneth D. Merry /* 659991554f2SKenneth D. Merry * Don't clear target if remove fails because things will get confusing. 660991554f2SKenneth D. Merry * Leave the devname and sasaddr intact so that we know to avoid reusing 661991554f2SKenneth D. Merry * this target id if possible, and so we can assign the same target id 662991554f2SKenneth D. Merry * to this device if it comes back in the future. 663991554f2SKenneth D. Merry */ 664d3f6eabfSStephen McConnell if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) == 665d3f6eabfSStephen McConnell MPI2_IOCSTATUS_SUCCESS) { 666991554f2SKenneth D. Merry targ = tm->cm_targ; 667991554f2SKenneth D. Merry targ->handle = 0x0; 668991554f2SKenneth D. Merry targ->encl_handle = 0x0; 669991554f2SKenneth D. Merry targ->encl_level_valid = 0x0; 670991554f2SKenneth D. Merry targ->encl_level = 0x0; 671991554f2SKenneth D. Merry targ->connector_name[0] = ' '; 672991554f2SKenneth D. Merry targ->connector_name[1] = ' '; 673991554f2SKenneth D. Merry targ->connector_name[2] = ' '; 674991554f2SKenneth D. Merry targ->connector_name[3] = ' '; 675991554f2SKenneth D. Merry targ->encl_slot = 0x0; 676991554f2SKenneth D. Merry targ->exp_dev_handle = 0x0; 677991554f2SKenneth D. Merry targ->phy_num = 0x0; 678991554f2SKenneth D. Merry targ->linkrate = 0x0; 679991554f2SKenneth D. Merry targ->devinfo = 0x0; 680991554f2SKenneth D. Merry targ->flags = 0x0; 681991554f2SKenneth D. Merry targ->scsi_req_desc_type = 0; 682991554f2SKenneth D. Merry 683991554f2SKenneth D. Merry while (!SLIST_EMPTY(&targ->luns)) { 684991554f2SKenneth D. Merry lun = SLIST_FIRST(&targ->luns); 685991554f2SKenneth D. Merry SLIST_REMOVE_HEAD(&targ->luns, lun_link); 686991554f2SKenneth D. Merry free(lun, M_MPR); 687991554f2SKenneth D. Merry } 688991554f2SKenneth D. Merry } 689991554f2SKenneth D. Merry 690991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 691991554f2SKenneth D. Merry } 692991554f2SKenneth D. Merry 693991554f2SKenneth D. Merry static int 694991554f2SKenneth D. Merry mprsas_register_events(struct mpr_softc *sc) 695991554f2SKenneth D. Merry { 696991554f2SKenneth D. Merry uint8_t events[16]; 697991554f2SKenneth D. Merry 698991554f2SKenneth D. Merry bzero(events, 16); 699991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE); 700991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_DISCOVERY); 701991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE); 702991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE); 703991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW); 704991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST); 705991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE); 706991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST); 707991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_IR_VOLUME); 708991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_IR_PHYSICAL_DISK); 709991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_IR_OPERATION_STATUS); 710991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_TEMP_THRESHOLD); 71167feec50SStephen McConnell if (sc->facts->MsgVersion >= MPI2_VERSION_02_06) { 7122bbc5fcbSStephen McConnell setbit(events, MPI2_EVENT_ACTIVE_CABLE_EXCEPTION); 71367feec50SStephen McConnell if (sc->mpr_flags & MPR_FLAGS_GEN35_IOC) { 71467feec50SStephen McConnell setbit(events, MPI2_EVENT_PCIE_DEVICE_STATUS_CHANGE); 71567feec50SStephen McConnell setbit(events, MPI2_EVENT_PCIE_ENUMERATION); 71667feec50SStephen McConnell setbit(events, MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST); 71767feec50SStephen McConnell } 71867feec50SStephen McConnell } 719991554f2SKenneth D. Merry 720991554f2SKenneth D. Merry mpr_register_events(sc, events, mprsas_evt_handler, NULL, 721991554f2SKenneth D. Merry &sc->sassc->mprsas_eh); 722991554f2SKenneth D. Merry 723991554f2SKenneth D. Merry return (0); 724991554f2SKenneth D. Merry } 725991554f2SKenneth D. Merry 726991554f2SKenneth D. Merry int 727991554f2SKenneth D. Merry mpr_attach_sas(struct mpr_softc *sc) 728991554f2SKenneth D. Merry { 729991554f2SKenneth D. Merry struct mprsas_softc *sassc; 730991554f2SKenneth D. Merry cam_status status; 731991554f2SKenneth D. Merry int unit, error = 0; 732991554f2SKenneth D. Merry 733991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 734*757ff642SScott Long mpr_dprint(sc, MPR_INIT, "%s entered\n", __func__); 735991554f2SKenneth D. Merry 736991554f2SKenneth D. Merry sassc = malloc(sizeof(struct mprsas_softc), M_MPR, M_WAITOK|M_ZERO); 737991554f2SKenneth D. Merry if (!sassc) { 738*757ff642SScott Long mpr_dprint(sc, MPR_INIT|MPR_ERROR, 739*757ff642SScott Long "Cannot allocate SAS subsystem memory\n"); 740991554f2SKenneth D. Merry return (ENOMEM); 741991554f2SKenneth D. Merry } 742991554f2SKenneth D. Merry 743991554f2SKenneth D. Merry /* 744a2c14879SStephen McConnell * XXX MaxTargets could change during a reinit. Since we don't 745991554f2SKenneth D. Merry * resize the targets[] array during such an event, cache the value 746991554f2SKenneth D. Merry * of MaxTargets here so that we don't get into trouble later. This 747991554f2SKenneth D. Merry * should move into the reinit logic. 748991554f2SKenneth D. Merry */ 749327f2e6cSStephen McConnell sassc->maxtargets = sc->facts->MaxTargets + sc->facts->MaxVolumes; 750991554f2SKenneth D. Merry sassc->targets = malloc(sizeof(struct mprsas_target) * 751991554f2SKenneth D. Merry sassc->maxtargets, M_MPR, M_WAITOK|M_ZERO); 752991554f2SKenneth D. Merry if (!sassc->targets) { 753*757ff642SScott Long mpr_dprint(sc, MPR_INIT|MPR_ERROR, 754*757ff642SScott Long "Cannot allocate SAS target memory\n"); 755991554f2SKenneth D. Merry free(sassc, M_MPR); 756991554f2SKenneth D. Merry return (ENOMEM); 757991554f2SKenneth D. Merry } 758991554f2SKenneth D. Merry sc->sassc = sassc; 759991554f2SKenneth D. Merry sassc->sc = sc; 760991554f2SKenneth D. Merry 761991554f2SKenneth D. Merry if ((sassc->devq = cam_simq_alloc(sc->num_reqs)) == NULL) { 762*757ff642SScott Long mpr_dprint(sc, MPR_INIT|MPR_ERROR, "Cannot allocate SIMQ\n"); 763991554f2SKenneth D. Merry error = ENOMEM; 764991554f2SKenneth D. Merry goto out; 765991554f2SKenneth D. Merry } 766991554f2SKenneth D. Merry 767991554f2SKenneth D. Merry unit = device_get_unit(sc->mpr_dev); 768991554f2SKenneth D. Merry sassc->sim = cam_sim_alloc(mprsas_action, mprsas_poll, "mpr", sassc, 769991554f2SKenneth D. Merry unit, &sc->mpr_mtx, sc->num_reqs, sc->num_reqs, sassc->devq); 770991554f2SKenneth D. Merry if (sassc->sim == NULL) { 771*757ff642SScott Long mpr_dprint(sc, MPR_INIT|MPR_ERROR, "Cannot allocate SIM\n"); 772991554f2SKenneth D. Merry error = EINVAL; 773991554f2SKenneth D. Merry goto out; 774991554f2SKenneth D. Merry } 775991554f2SKenneth D. Merry 776991554f2SKenneth D. Merry TAILQ_INIT(&sassc->ev_queue); 777991554f2SKenneth D. Merry 778991554f2SKenneth D. Merry /* Initialize taskqueue for Event Handling */ 779991554f2SKenneth D. Merry TASK_INIT(&sassc->ev_task, 0, mprsas_firmware_event_work, sc); 780991554f2SKenneth D. Merry sassc->ev_tq = taskqueue_create("mpr_taskq", M_NOWAIT | M_ZERO, 781991554f2SKenneth D. Merry taskqueue_thread_enqueue, &sassc->ev_tq); 782c2a0f07aSAlexander Motin taskqueue_start_threads(&sassc->ev_tq, 1, PRIBIO, "%s taskq", 783991554f2SKenneth D. Merry device_get_nameunit(sc->mpr_dev)); 784991554f2SKenneth D. Merry 785991554f2SKenneth D. Merry mpr_lock(sc); 786991554f2SKenneth D. Merry 787991554f2SKenneth D. Merry /* 788991554f2SKenneth D. Merry * XXX There should be a bus for every port on the adapter, but since 789991554f2SKenneth D. Merry * we're just going to fake the topology for now, we'll pretend that 790991554f2SKenneth D. Merry * everything is just a target on a single bus. 791991554f2SKenneth D. Merry */ 792991554f2SKenneth D. Merry if ((error = xpt_bus_register(sassc->sim, sc->mpr_dev, 0)) != 0) { 793*757ff642SScott Long mpr_dprint(sc, MPR_INIT|MPR_ERROR, 794*757ff642SScott Long "Error %d registering SCSI bus\n", error); 795991554f2SKenneth D. Merry mpr_unlock(sc); 796991554f2SKenneth D. Merry goto out; 797991554f2SKenneth D. Merry } 798991554f2SKenneth D. Merry 799991554f2SKenneth D. Merry /* 800a2c14879SStephen McConnell * Assume that discovery events will start right away. 801991554f2SKenneth D. Merry * 802991554f2SKenneth D. Merry * Hold off boot until discovery is complete. 803991554f2SKenneth D. Merry */ 804991554f2SKenneth D. Merry sassc->flags |= MPRSAS_IN_STARTUP | MPRSAS_IN_DISCOVERY; 805991554f2SKenneth D. Merry sc->sassc->startup_refcount = 0; 806991554f2SKenneth D. Merry mprsas_startup_increment(sassc); 807991554f2SKenneth D. Merry 808a2c14879SStephen McConnell callout_init(&sassc->discovery_callout, 1 /*mpsafe*/); 809991554f2SKenneth D. Merry 810991554f2SKenneth D. Merry /* 811991554f2SKenneth D. Merry * Register for async events so we can determine the EEDP 812991554f2SKenneth D. Merry * capabilities of devices. 813991554f2SKenneth D. Merry */ 814991554f2SKenneth D. Merry status = xpt_create_path(&sassc->path, /*periph*/NULL, 815991554f2SKenneth D. Merry cam_sim_path(sc->sassc->sim), CAM_TARGET_WILDCARD, 816991554f2SKenneth D. Merry CAM_LUN_WILDCARD); 817991554f2SKenneth D. Merry if (status != CAM_REQ_CMP) { 818*757ff642SScott Long mpr_dprint(sc, MPR_INIT|MPR_ERROR, 819*757ff642SScott Long "Error %#x creating sim path\n", status); 820991554f2SKenneth D. Merry sassc->path = NULL; 821991554f2SKenneth D. Merry } else { 822991554f2SKenneth D. Merry int event; 823991554f2SKenneth D. Merry 824991554f2SKenneth D. Merry #if (__FreeBSD_version >= 1000006) || \ 825991554f2SKenneth D. Merry ((__FreeBSD_version >= 901503) && (__FreeBSD_version < 1000000)) 826991554f2SKenneth D. Merry event = AC_ADVINFO_CHANGED | AC_FOUND_DEVICE; 827991554f2SKenneth D. Merry #else 828991554f2SKenneth D. Merry event = AC_FOUND_DEVICE; 829991554f2SKenneth D. Merry #endif 83007aa4de1SKenneth D. Merry 83107aa4de1SKenneth D. Merry /* 83207aa4de1SKenneth D. Merry * Prior to the CAM locking improvements, we can't call 83307aa4de1SKenneth D. Merry * xpt_register_async() with a particular path specified. 83407aa4de1SKenneth D. Merry * 83507aa4de1SKenneth D. Merry * If a path isn't specified, xpt_register_async() will 83607aa4de1SKenneth D. Merry * generate a wildcard path and acquire the XPT lock while 83707aa4de1SKenneth D. Merry * it calls xpt_action() to execute the XPT_SASYNC_CB CCB. 83807aa4de1SKenneth D. Merry * It will then drop the XPT lock once that is done. 83907aa4de1SKenneth D. Merry * 84007aa4de1SKenneth D. Merry * If a path is specified for xpt_register_async(), it will 84107aa4de1SKenneth D. Merry * not acquire and drop the XPT lock around the call to 84207aa4de1SKenneth D. Merry * xpt_action(). xpt_action() asserts that the caller 84307aa4de1SKenneth D. Merry * holds the SIM lock, so the SIM lock has to be held when 84407aa4de1SKenneth D. Merry * calling xpt_register_async() when the path is specified. 84507aa4de1SKenneth D. Merry * 84607aa4de1SKenneth D. Merry * But xpt_register_async calls xpt_for_all_devices(), 84707aa4de1SKenneth D. Merry * which calls xptbustraverse(), which will acquire each 84807aa4de1SKenneth D. Merry * SIM lock. When it traverses our particular bus, it will 84907aa4de1SKenneth D. Merry * necessarily acquire the SIM lock, which will lead to a 85007aa4de1SKenneth D. Merry * recursive lock acquisition. 85107aa4de1SKenneth D. Merry * 85207aa4de1SKenneth D. Merry * The CAM locking changes fix this problem by acquiring 85307aa4de1SKenneth D. Merry * the XPT topology lock around bus traversal in 85407aa4de1SKenneth D. Merry * xptbustraverse(), so the caller can hold the SIM lock 85507aa4de1SKenneth D. Merry * and it does not cause a recursive lock acquisition. 85607aa4de1SKenneth D. Merry * 85707aa4de1SKenneth D. Merry * These __FreeBSD_version values are approximate, especially 85807aa4de1SKenneth D. Merry * for stable/10, which is two months later than the actual 85907aa4de1SKenneth D. Merry * change. 86007aa4de1SKenneth D. Merry */ 86107aa4de1SKenneth D. Merry 86207aa4de1SKenneth D. Merry #if (__FreeBSD_version < 1000703) || \ 86307aa4de1SKenneth D. Merry ((__FreeBSD_version >= 1100000) && (__FreeBSD_version < 1100002)) 86407aa4de1SKenneth D. Merry mpr_unlock(sc); 86507aa4de1SKenneth D. Merry status = xpt_register_async(event, mprsas_async, sc, 86607aa4de1SKenneth D. Merry NULL); 86707aa4de1SKenneth D. Merry mpr_lock(sc); 86807aa4de1SKenneth D. Merry #else 869991554f2SKenneth D. Merry status = xpt_register_async(event, mprsas_async, sc, 870991554f2SKenneth D. Merry sassc->path); 87107aa4de1SKenneth D. Merry #endif 87207aa4de1SKenneth D. Merry 873991554f2SKenneth D. Merry if (status != CAM_REQ_CMP) { 874991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, 875991554f2SKenneth D. Merry "Error %#x registering async handler for " 876991554f2SKenneth D. Merry "AC_ADVINFO_CHANGED events\n", status); 877991554f2SKenneth D. Merry xpt_free_path(sassc->path); 878991554f2SKenneth D. Merry sassc->path = NULL; 879991554f2SKenneth D. Merry } 880991554f2SKenneth D. Merry } 881991554f2SKenneth D. Merry if (status != CAM_REQ_CMP) { 882991554f2SKenneth D. Merry /* 883991554f2SKenneth D. Merry * EEDP use is the exception, not the rule. 884991554f2SKenneth D. Merry * Warn the user, but do not fail to attach. 885991554f2SKenneth D. Merry */ 886991554f2SKenneth D. Merry mpr_printf(sc, "EEDP capabilities disabled.\n"); 887991554f2SKenneth D. Merry } 888991554f2SKenneth D. Merry 889991554f2SKenneth D. Merry mpr_unlock(sc); 890991554f2SKenneth D. Merry 891991554f2SKenneth D. Merry mprsas_register_events(sc); 892991554f2SKenneth D. Merry out: 893991554f2SKenneth D. Merry if (error) 894991554f2SKenneth D. Merry mpr_detach_sas(sc); 895*757ff642SScott Long 896*757ff642SScott Long mpr_dprint(sc, MPR_INIT, "%s exit, error= %d\n", __func__, error); 897991554f2SKenneth D. Merry return (error); 898991554f2SKenneth D. Merry } 899991554f2SKenneth D. Merry 900991554f2SKenneth D. Merry int 901991554f2SKenneth D. Merry mpr_detach_sas(struct mpr_softc *sc) 902991554f2SKenneth D. Merry { 903991554f2SKenneth D. Merry struct mprsas_softc *sassc; 904991554f2SKenneth D. Merry struct mprsas_lun *lun, *lun_tmp; 905991554f2SKenneth D. Merry struct mprsas_target *targ; 906991554f2SKenneth D. Merry int i; 907991554f2SKenneth D. Merry 908991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 909991554f2SKenneth D. Merry 910991554f2SKenneth D. Merry if (sc->sassc == NULL) 911991554f2SKenneth D. Merry return (0); 912991554f2SKenneth D. Merry 913991554f2SKenneth D. Merry sassc = sc->sassc; 914991554f2SKenneth D. Merry mpr_deregister_events(sc, sassc->mprsas_eh); 915991554f2SKenneth D. Merry 916991554f2SKenneth D. Merry /* 917991554f2SKenneth D. Merry * Drain and free the event handling taskqueue with the lock 918991554f2SKenneth D. Merry * unheld so that any parallel processing tasks drain properly 919991554f2SKenneth D. Merry * without deadlocking. 920991554f2SKenneth D. Merry */ 921991554f2SKenneth D. Merry if (sassc->ev_tq != NULL) 922991554f2SKenneth D. Merry taskqueue_free(sassc->ev_tq); 923991554f2SKenneth D. Merry 924991554f2SKenneth D. Merry /* Make sure CAM doesn't wedge if we had to bail out early. */ 925991554f2SKenneth D. Merry mpr_lock(sc); 926991554f2SKenneth D. Merry 927991554f2SKenneth D. Merry /* Deregister our async handler */ 928991554f2SKenneth D. Merry if (sassc->path != NULL) { 929991554f2SKenneth D. Merry xpt_register_async(0, mprsas_async, sc, sassc->path); 930991554f2SKenneth D. Merry xpt_free_path(sassc->path); 931991554f2SKenneth D. Merry sassc->path = NULL; 932991554f2SKenneth D. Merry } 933991554f2SKenneth D. Merry 934991554f2SKenneth D. Merry if (sassc->flags & MPRSAS_IN_STARTUP) 935991554f2SKenneth D. Merry xpt_release_simq(sassc->sim, 1); 936991554f2SKenneth D. Merry 937991554f2SKenneth D. Merry if (sassc->sim != NULL) { 938991554f2SKenneth D. Merry xpt_bus_deregister(cam_sim_path(sassc->sim)); 939991554f2SKenneth D. Merry cam_sim_free(sassc->sim, FALSE); 940991554f2SKenneth D. Merry } 941991554f2SKenneth D. Merry 942991554f2SKenneth D. Merry mpr_unlock(sc); 943991554f2SKenneth D. Merry 944991554f2SKenneth D. Merry if (sassc->devq != NULL) 945991554f2SKenneth D. Merry cam_simq_free(sassc->devq); 946991554f2SKenneth D. Merry 947991554f2SKenneth D. Merry for (i = 0; i < sassc->maxtargets; i++) { 948991554f2SKenneth D. Merry targ = &sassc->targets[i]; 949991554f2SKenneth D. Merry SLIST_FOREACH_SAFE(lun, &targ->luns, lun_link, lun_tmp) { 950991554f2SKenneth D. Merry free(lun, M_MPR); 951991554f2SKenneth D. Merry } 952991554f2SKenneth D. Merry } 953991554f2SKenneth D. Merry free(sassc->targets, M_MPR); 954991554f2SKenneth D. Merry free(sassc, M_MPR); 955991554f2SKenneth D. Merry sc->sassc = NULL; 956991554f2SKenneth D. Merry 957991554f2SKenneth D. Merry return (0); 958991554f2SKenneth D. Merry } 959991554f2SKenneth D. Merry 960991554f2SKenneth D. Merry void 961991554f2SKenneth D. Merry mprsas_discovery_end(struct mprsas_softc *sassc) 962991554f2SKenneth D. Merry { 963991554f2SKenneth D. Merry struct mpr_softc *sc = sassc->sc; 964991554f2SKenneth D. Merry 965991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 966991554f2SKenneth D. Merry 967991554f2SKenneth D. Merry if (sassc->flags & MPRSAS_DISCOVERY_TIMEOUT_PENDING) 968991554f2SKenneth D. Merry callout_stop(&sassc->discovery_callout); 969991554f2SKenneth D. Merry 970327f2e6cSStephen McConnell /* 971327f2e6cSStephen McConnell * After discovery has completed, check the mapping table for any 972327f2e6cSStephen McConnell * missing devices and update their missing counts. Only do this once 973327f2e6cSStephen McConnell * whenever the driver is initialized so that missing counts aren't 974327f2e6cSStephen McConnell * updated unnecessarily. Note that just because discovery has 975327f2e6cSStephen McConnell * completed doesn't mean that events have been processed yet. The 976327f2e6cSStephen McConnell * check_devices function is a callout timer that checks if ALL devices 977327f2e6cSStephen McConnell * are missing. If so, it will wait a little longer for events to 978327f2e6cSStephen McConnell * complete and keep resetting itself until some device in the mapping 979327f2e6cSStephen McConnell * table is not missing, meaning that event processing has started. 980327f2e6cSStephen McConnell */ 981327f2e6cSStephen McConnell if (sc->track_mapping_events) { 982327f2e6cSStephen McConnell mpr_dprint(sc, MPR_XINFO | MPR_MAPPING, "Discovery has " 983327f2e6cSStephen McConnell "completed. Check for missing devices in the mapping " 984327f2e6cSStephen McConnell "table.\n"); 985327f2e6cSStephen McConnell callout_reset(&sc->device_check_callout, 986327f2e6cSStephen McConnell MPR_MISSING_CHECK_DELAY * hz, mpr_mapping_check_devices, 987327f2e6cSStephen McConnell sc); 988327f2e6cSStephen McConnell } 989991554f2SKenneth D. Merry } 990991554f2SKenneth D. Merry 991991554f2SKenneth D. Merry static void 992991554f2SKenneth D. Merry mprsas_action(struct cam_sim *sim, union ccb *ccb) 993991554f2SKenneth D. Merry { 994991554f2SKenneth D. Merry struct mprsas_softc *sassc; 995991554f2SKenneth D. Merry 996991554f2SKenneth D. Merry sassc = cam_sim_softc(sim); 997991554f2SKenneth D. Merry 998991554f2SKenneth D. Merry MPR_FUNCTRACE(sassc->sc); 999a2c14879SStephen McConnell mpr_dprint(sassc->sc, MPR_TRACE, "ccb func_code 0x%x\n", 1000991554f2SKenneth D. Merry ccb->ccb_h.func_code); 1001991554f2SKenneth D. Merry mtx_assert(&sassc->sc->mpr_mtx, MA_OWNED); 1002991554f2SKenneth D. Merry 1003991554f2SKenneth D. Merry switch (ccb->ccb_h.func_code) { 1004991554f2SKenneth D. Merry case XPT_PATH_INQ: 1005991554f2SKenneth D. Merry { 1006991554f2SKenneth D. Merry struct ccb_pathinq *cpi = &ccb->cpi; 100732b0a21eSStephen McConnell struct mpr_softc *sc = sassc->sc; 100832b0a21eSStephen McConnell uint8_t sges_per_frame; 1009991554f2SKenneth D. Merry 1010991554f2SKenneth D. Merry cpi->version_num = 1; 1011991554f2SKenneth D. Merry cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; 1012991554f2SKenneth D. Merry cpi->target_sprt = 0; 1013a371d6f9SKenneth D. Merry #if (__FreeBSD_version >= 1000039) || \ 1014a371d6f9SKenneth D. Merry ((__FreeBSD_version < 1000000) && (__FreeBSD_version >= 902502)) 1015991554f2SKenneth D. Merry cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED | PIM_NOSCAN; 1016991554f2SKenneth D. Merry #else 1017991554f2SKenneth D. Merry cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED; 1018991554f2SKenneth D. Merry #endif 1019991554f2SKenneth D. Merry cpi->hba_eng_cnt = 0; 1020991554f2SKenneth D. Merry cpi->max_target = sassc->maxtargets - 1; 1021991554f2SKenneth D. Merry cpi->max_lun = 255; 1022327f2e6cSStephen McConnell 1023327f2e6cSStephen McConnell /* 1024327f2e6cSStephen McConnell * initiator_id is set here to an ID outside the set of valid 1025327f2e6cSStephen McConnell * target IDs (including volumes). 1026327f2e6cSStephen McConnell */ 1027327f2e6cSStephen McConnell cpi->initiator_id = sassc->maxtargets; 10284195c7deSAlan Somers strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 10294195c7deSAlan Somers strlcpy(cpi->hba_vid, "Avago Tech", HBA_IDLEN); 10304195c7deSAlan Somers strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 1031991554f2SKenneth D. Merry cpi->unit_number = cam_sim_unit(sim); 1032991554f2SKenneth D. Merry cpi->bus_id = cam_sim_bus(sim); 1033991554f2SKenneth D. Merry /* 1034991554f2SKenneth D. Merry * XXXSLM-I think this needs to change based on config page or 1035991554f2SKenneth D. Merry * something instead of hardcoded to 150000. 1036991554f2SKenneth D. Merry */ 1037991554f2SKenneth D. Merry cpi->base_transfer_speed = 150000; 1038991554f2SKenneth D. Merry cpi->transport = XPORT_SAS; 1039991554f2SKenneth D. Merry cpi->transport_version = 0; 1040991554f2SKenneth D. Merry cpi->protocol = PROTO_SCSI; 1041991554f2SKenneth D. Merry cpi->protocol_version = SCSI_REV_SPC; 104232b0a21eSStephen McConnell 1043991554f2SKenneth D. Merry /* 104432b0a21eSStephen McConnell * Max IO Size is Page Size * the following: 104532b0a21eSStephen McConnell * ((SGEs per frame - 1 for chain element) * 104632b0a21eSStephen McConnell * Max Chain Depth) + 1 for no chain needed in last frame 104732b0a21eSStephen McConnell * 104832b0a21eSStephen McConnell * If user suggests a Max IO size to use, use the smaller of the 104932b0a21eSStephen McConnell * user's value and the calculated value as long as the user's 105032b0a21eSStephen McConnell * value is larger than 0. The user's value is in pages. 1051991554f2SKenneth D. Merry */ 105232b0a21eSStephen McConnell sges_per_frame = (sc->chain_frame_size / 105332b0a21eSStephen McConnell sizeof(MPI2_IEEE_SGE_SIMPLE64)) - 1; 105432b0a21eSStephen McConnell cpi->maxio = (sges_per_frame * sc->facts->MaxChainDepth) + 1; 105532b0a21eSStephen McConnell cpi->maxio *= PAGE_SIZE; 105632b0a21eSStephen McConnell if ((sc->max_io_pages > 0) && (sc->max_io_pages * PAGE_SIZE < 105732b0a21eSStephen McConnell cpi->maxio)) 105832b0a21eSStephen McConnell cpi->maxio = sc->max_io_pages * PAGE_SIZE; 105967feec50SStephen McConnell sc->maxio = cpi->maxio; 1060a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); 1061991554f2SKenneth D. Merry break; 1062991554f2SKenneth D. Merry } 1063991554f2SKenneth D. Merry case XPT_GET_TRAN_SETTINGS: 1064991554f2SKenneth D. Merry { 1065991554f2SKenneth D. Merry struct ccb_trans_settings *cts; 1066991554f2SKenneth D. Merry struct ccb_trans_settings_sas *sas; 1067991554f2SKenneth D. Merry struct ccb_trans_settings_scsi *scsi; 1068991554f2SKenneth D. Merry struct mprsas_target *targ; 1069991554f2SKenneth D. Merry 1070991554f2SKenneth D. Merry cts = &ccb->cts; 1071991554f2SKenneth D. Merry sas = &cts->xport_specific.sas; 1072991554f2SKenneth D. Merry scsi = &cts->proto_specific.scsi; 1073991554f2SKenneth D. Merry 1074991554f2SKenneth D. Merry KASSERT(cts->ccb_h.target_id < sassc->maxtargets, 1075991554f2SKenneth D. Merry ("Target %d out of bounds in XPT_GET_TRAN_SETTINGS\n", 1076991554f2SKenneth D. Merry cts->ccb_h.target_id)); 1077991554f2SKenneth D. Merry targ = &sassc->targets[cts->ccb_h.target_id]; 1078991554f2SKenneth D. Merry if (targ->handle == 0x0) { 1079a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); 1080991554f2SKenneth D. Merry break; 1081991554f2SKenneth D. Merry } 1082991554f2SKenneth D. Merry 1083991554f2SKenneth D. Merry cts->protocol_version = SCSI_REV_SPC2; 1084991554f2SKenneth D. Merry cts->transport = XPORT_SAS; 1085991554f2SKenneth D. Merry cts->transport_version = 0; 1086991554f2SKenneth D. Merry 1087991554f2SKenneth D. Merry sas->valid = CTS_SAS_VALID_SPEED; 1088991554f2SKenneth D. Merry switch (targ->linkrate) { 1089991554f2SKenneth D. Merry case 0x08: 1090991554f2SKenneth D. Merry sas->bitrate = 150000; 1091991554f2SKenneth D. Merry break; 1092991554f2SKenneth D. Merry case 0x09: 1093991554f2SKenneth D. Merry sas->bitrate = 300000; 1094991554f2SKenneth D. Merry break; 1095991554f2SKenneth D. Merry case 0x0a: 1096991554f2SKenneth D. Merry sas->bitrate = 600000; 1097991554f2SKenneth D. Merry break; 109882315915SAlexander Motin case 0x0b: 109982315915SAlexander Motin sas->bitrate = 1200000; 110082315915SAlexander Motin break; 1101991554f2SKenneth D. Merry default: 1102991554f2SKenneth D. Merry sas->valid = 0; 1103991554f2SKenneth D. Merry } 1104991554f2SKenneth D. Merry 1105991554f2SKenneth D. Merry cts->protocol = PROTO_SCSI; 1106991554f2SKenneth D. Merry scsi->valid = CTS_SCSI_VALID_TQ; 1107991554f2SKenneth D. Merry scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; 1108991554f2SKenneth D. Merry 1109a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); 1110991554f2SKenneth D. Merry break; 1111991554f2SKenneth D. Merry } 1112991554f2SKenneth D. Merry case XPT_CALC_GEOMETRY: 1113991554f2SKenneth D. Merry cam_calc_geometry(&ccb->ccg, /*extended*/1); 1114a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); 1115991554f2SKenneth D. Merry break; 1116991554f2SKenneth D. Merry case XPT_RESET_DEV: 11177a2a6a1aSStephen McConnell mpr_dprint(sassc->sc, MPR_XINFO, "mprsas_action " 11187a2a6a1aSStephen McConnell "XPT_RESET_DEV\n"); 1119991554f2SKenneth D. Merry mprsas_action_resetdev(sassc, ccb); 1120991554f2SKenneth D. Merry return; 1121991554f2SKenneth D. Merry case XPT_RESET_BUS: 1122991554f2SKenneth D. Merry case XPT_ABORT: 1123991554f2SKenneth D. Merry case XPT_TERM_IO: 11247a2a6a1aSStephen McConnell mpr_dprint(sassc->sc, MPR_XINFO, "mprsas_action faking success " 11257a2a6a1aSStephen McConnell "for abort or reset\n"); 1126a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); 1127991554f2SKenneth D. Merry break; 1128991554f2SKenneth D. Merry case XPT_SCSI_IO: 1129991554f2SKenneth D. Merry mprsas_action_scsiio(sassc, ccb); 1130991554f2SKenneth D. Merry return; 1131991554f2SKenneth D. Merry #if __FreeBSD_version >= 900026 1132991554f2SKenneth D. Merry case XPT_SMP_IO: 1133991554f2SKenneth D. Merry mprsas_action_smpio(sassc, ccb); 1134991554f2SKenneth D. Merry return; 1135991554f2SKenneth D. Merry #endif 1136991554f2SKenneth D. Merry default: 1137a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_FUNC_NOTAVAIL); 1138991554f2SKenneth D. Merry break; 1139991554f2SKenneth D. Merry } 1140991554f2SKenneth D. Merry xpt_done(ccb); 1141991554f2SKenneth D. Merry 1142991554f2SKenneth D. Merry } 1143991554f2SKenneth D. Merry 1144991554f2SKenneth D. Merry static void 1145991554f2SKenneth D. Merry mprsas_announce_reset(struct mpr_softc *sc, uint32_t ac_code, 1146991554f2SKenneth D. Merry target_id_t target_id, lun_id_t lun_id) 1147991554f2SKenneth D. Merry { 1148991554f2SKenneth D. Merry path_id_t path_id = cam_sim_path(sc->sassc->sim); 1149991554f2SKenneth D. Merry struct cam_path *path; 1150991554f2SKenneth D. Merry 1151991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "%s code %x target %d lun %jx\n", __func__, 1152991554f2SKenneth D. Merry ac_code, target_id, (uintmax_t)lun_id); 1153991554f2SKenneth D. Merry 1154991554f2SKenneth D. Merry if (xpt_create_path(&path, NULL, 1155991554f2SKenneth D. Merry path_id, target_id, lun_id) != CAM_REQ_CMP) { 1156991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "unable to create path for reset " 1157991554f2SKenneth D. Merry "notification\n"); 1158991554f2SKenneth D. Merry return; 1159991554f2SKenneth D. Merry } 1160991554f2SKenneth D. Merry 1161991554f2SKenneth D. Merry xpt_async(ac_code, path, NULL); 1162991554f2SKenneth D. Merry xpt_free_path(path); 1163991554f2SKenneth D. Merry } 1164991554f2SKenneth D. Merry 1165991554f2SKenneth D. Merry static void 1166991554f2SKenneth D. Merry mprsas_complete_all_commands(struct mpr_softc *sc) 1167991554f2SKenneth D. Merry { 1168991554f2SKenneth D. Merry struct mpr_command *cm; 1169991554f2SKenneth D. Merry int i; 1170991554f2SKenneth D. Merry int completed; 1171991554f2SKenneth D. Merry 1172991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 1173991554f2SKenneth D. Merry mtx_assert(&sc->mpr_mtx, MA_OWNED); 1174991554f2SKenneth D. Merry 1175991554f2SKenneth D. Merry /* complete all commands with a NULL reply */ 1176991554f2SKenneth D. Merry for (i = 1; i < sc->num_reqs; i++) { 1177991554f2SKenneth D. Merry cm = &sc->commands[i]; 1178991554f2SKenneth D. Merry cm->cm_reply = NULL; 1179991554f2SKenneth D. Merry completed = 0; 1180991554f2SKenneth D. Merry 1181991554f2SKenneth D. Merry if (cm->cm_flags & MPR_CM_FLAGS_POLLED) 1182991554f2SKenneth D. Merry cm->cm_flags |= MPR_CM_FLAGS_COMPLETE; 1183991554f2SKenneth D. Merry 1184991554f2SKenneth D. Merry if (cm->cm_complete != NULL) { 1185991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 11867a2a6a1aSStephen McConnell "completing cm %p state %x ccb %p for diag reset\n", 11877a2a6a1aSStephen McConnell cm, cm->cm_state, cm->cm_ccb); 1188991554f2SKenneth D. Merry cm->cm_complete(sc, cm); 1189991554f2SKenneth D. Merry completed = 1; 1190991554f2SKenneth D. Merry } 1191991554f2SKenneth D. Merry 1192991554f2SKenneth D. Merry if (cm->cm_flags & MPR_CM_FLAGS_WAKEUP) { 1193991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 1194991554f2SKenneth D. Merry "waking up cm %p state %x ccb %p for diag reset\n", 1195991554f2SKenneth D. Merry cm, cm->cm_state, cm->cm_ccb); 1196991554f2SKenneth D. Merry wakeup(cm); 1197991554f2SKenneth D. Merry completed = 1; 1198991554f2SKenneth D. Merry } 1199991554f2SKenneth D. Merry 12006d4ffcb4SKenneth D. Merry if (cm->cm_sc->io_cmds_active != 0) 1201a2c14879SStephen McConnell cm->cm_sc->io_cmds_active--; 1202a2c14879SStephen McConnell 1203991554f2SKenneth D. Merry if ((completed == 0) && (cm->cm_state != MPR_CM_STATE_FREE)) { 1204991554f2SKenneth D. Merry /* this should never happen, but if it does, log */ 1205991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 1206991554f2SKenneth D. Merry "cm %p state %x flags 0x%x ccb %p during diag " 1207991554f2SKenneth D. Merry "reset\n", cm, cm->cm_state, cm->cm_flags, 1208991554f2SKenneth D. Merry cm->cm_ccb); 1209991554f2SKenneth D. Merry } 1210991554f2SKenneth D. Merry } 1211991554f2SKenneth D. Merry } 1212991554f2SKenneth D. Merry 1213991554f2SKenneth D. Merry void 1214991554f2SKenneth D. Merry mprsas_handle_reinit(struct mpr_softc *sc) 1215991554f2SKenneth D. Merry { 1216991554f2SKenneth D. Merry int i; 1217991554f2SKenneth D. Merry 1218991554f2SKenneth D. Merry /* Go back into startup mode and freeze the simq, so that CAM 1219991554f2SKenneth D. Merry * doesn't send any commands until after we've rediscovered all 1220991554f2SKenneth D. Merry * targets and found the proper device handles for them. 1221991554f2SKenneth D. Merry * 1222991554f2SKenneth D. Merry * After the reset, portenable will trigger discovery, and after all 1223991554f2SKenneth D. Merry * discovery-related activities have finished, the simq will be 1224991554f2SKenneth D. Merry * released. 1225991554f2SKenneth D. Merry */ 1226991554f2SKenneth D. Merry mpr_dprint(sc, MPR_INIT, "%s startup\n", __func__); 1227991554f2SKenneth D. Merry sc->sassc->flags |= MPRSAS_IN_STARTUP; 1228991554f2SKenneth D. Merry sc->sassc->flags |= MPRSAS_IN_DISCOVERY; 1229991554f2SKenneth D. Merry mprsas_startup_increment(sc->sassc); 1230991554f2SKenneth D. Merry 1231991554f2SKenneth D. Merry /* notify CAM of a bus reset */ 1232991554f2SKenneth D. Merry mprsas_announce_reset(sc, AC_BUS_RESET, CAM_TARGET_WILDCARD, 1233991554f2SKenneth D. Merry CAM_LUN_WILDCARD); 1234991554f2SKenneth D. Merry 1235991554f2SKenneth D. Merry /* complete and cleanup after all outstanding commands */ 1236991554f2SKenneth D. Merry mprsas_complete_all_commands(sc); 1237991554f2SKenneth D. Merry 1238a2c14879SStephen McConnell mpr_dprint(sc, MPR_INIT, "%s startup %u after command completion\n", 1239a2c14879SStephen McConnell __func__, sc->sassc->startup_refcount); 1240991554f2SKenneth D. Merry 1241991554f2SKenneth D. Merry /* zero all the target handles, since they may change after the 1242991554f2SKenneth D. Merry * reset, and we have to rediscover all the targets and use the new 1243991554f2SKenneth D. Merry * handles. 1244991554f2SKenneth D. Merry */ 1245991554f2SKenneth D. Merry for (i = 0; i < sc->sassc->maxtargets; i++) { 1246991554f2SKenneth D. Merry if (sc->sassc->targets[i].outstanding != 0) 1247991554f2SKenneth D. Merry mpr_dprint(sc, MPR_INIT, "target %u outstanding %u\n", 1248991554f2SKenneth D. Merry i, sc->sassc->targets[i].outstanding); 1249991554f2SKenneth D. Merry sc->sassc->targets[i].handle = 0x0; 1250991554f2SKenneth D. Merry sc->sassc->targets[i].exp_dev_handle = 0x0; 1251991554f2SKenneth D. Merry sc->sassc->targets[i].outstanding = 0; 1252991554f2SKenneth D. Merry sc->sassc->targets[i].flags = MPRSAS_TARGET_INDIAGRESET; 1253991554f2SKenneth D. Merry } 1254991554f2SKenneth D. Merry } 1255991554f2SKenneth D. Merry static void 1256991554f2SKenneth D. Merry mprsas_tm_timeout(void *data) 1257991554f2SKenneth D. Merry { 1258991554f2SKenneth D. Merry struct mpr_command *tm = data; 1259991554f2SKenneth D. Merry struct mpr_softc *sc = tm->cm_sc; 1260991554f2SKenneth D. Merry 1261991554f2SKenneth D. Merry mtx_assert(&sc->mpr_mtx, MA_OWNED); 1262991554f2SKenneth D. Merry 12637a2a6a1aSStephen McConnell mprsas_log_command(tm, MPR_INFO|MPR_RECOVERY, "task mgmt %p timed " 12647a2a6a1aSStephen McConnell "out\n", tm); 1265991554f2SKenneth D. Merry mpr_reinit(sc); 1266991554f2SKenneth D. Merry } 1267991554f2SKenneth D. Merry 1268991554f2SKenneth D. Merry static void 12697a2a6a1aSStephen McConnell mprsas_logical_unit_reset_complete(struct mpr_softc *sc, struct mpr_command *tm) 1270991554f2SKenneth D. Merry { 1271991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *reply; 1272991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 1273991554f2SKenneth D. Merry unsigned int cm_count = 0; 1274991554f2SKenneth D. Merry struct mpr_command *cm; 1275991554f2SKenneth D. Merry struct mprsas_target *targ; 1276991554f2SKenneth D. Merry 1277991554f2SKenneth D. Merry callout_stop(&tm->cm_callout); 1278991554f2SKenneth D. Merry 1279991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 1280991554f2SKenneth D. Merry reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 1281991554f2SKenneth D. Merry targ = tm->cm_targ; 1282991554f2SKenneth D. Merry 1283991554f2SKenneth D. Merry /* 1284991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 1285991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 1286991554f2SKenneth D. Merry * task management commands don't have S/G lists. 1287991554f2SKenneth D. Merry */ 1288991554f2SKenneth D. Merry if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 1289991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for LUN reset! " 1290991554f2SKenneth D. Merry "This should not happen!\n", __func__, tm->cm_flags); 1291991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1292991554f2SKenneth D. Merry return; 1293991554f2SKenneth D. Merry } 1294991554f2SKenneth D. Merry 1295991554f2SKenneth D. Merry if (reply == NULL) { 12967a2a6a1aSStephen McConnell mprsas_log_command(tm, MPR_RECOVERY, "NULL reset reply for tm " 12977a2a6a1aSStephen McConnell "%p\n", tm); 1298991554f2SKenneth D. Merry if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) { 1299991554f2SKenneth D. Merry /* this completion was due to a reset, just cleanup */ 1300991554f2SKenneth D. Merry targ->tm = NULL; 1301991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1302991554f2SKenneth D. Merry } 1303991554f2SKenneth D. Merry else { 1304991554f2SKenneth D. Merry /* we should have gotten a reply. */ 1305991554f2SKenneth D. Merry mpr_reinit(sc); 1306991554f2SKenneth D. Merry } 1307991554f2SKenneth D. Merry return; 1308991554f2SKenneth D. Merry } 1309991554f2SKenneth D. Merry 1310991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1311991554f2SKenneth D. Merry "logical unit reset status 0x%x code 0x%x count %u\n", 1312991554f2SKenneth D. Merry le16toh(reply->IOCStatus), le32toh(reply->ResponseCode), 1313991554f2SKenneth D. Merry le32toh(reply->TerminationCount)); 1314991554f2SKenneth D. Merry 1315991554f2SKenneth D. Merry /* See if there are any outstanding commands for this LUN. 1316991554f2SKenneth D. Merry * This could be made more efficient by using a per-LU data 1317991554f2SKenneth D. Merry * structure of some sort. 1318991554f2SKenneth D. Merry */ 1319991554f2SKenneth D. Merry TAILQ_FOREACH(cm, &targ->commands, cm_link) { 1320991554f2SKenneth D. Merry if (cm->cm_lun == tm->cm_lun) 1321991554f2SKenneth D. Merry cm_count++; 1322991554f2SKenneth D. Merry } 1323991554f2SKenneth D. Merry 1324991554f2SKenneth D. Merry if (cm_count == 0) { 1325991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, 1326991554f2SKenneth D. Merry "logical unit %u finished recovery after reset\n", 1327991554f2SKenneth D. Merry tm->cm_lun, tm); 1328991554f2SKenneth D. Merry 1329991554f2SKenneth D. Merry mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid, 1330991554f2SKenneth D. Merry tm->cm_lun); 1331991554f2SKenneth D. Merry 1332991554f2SKenneth D. Merry /* we've finished recovery for this logical unit. check and 1333991554f2SKenneth D. Merry * see if some other logical unit has a timedout command 1334991554f2SKenneth D. Merry * that needs to be processed. 1335991554f2SKenneth D. Merry */ 1336991554f2SKenneth D. Merry cm = TAILQ_FIRST(&targ->timedout_commands); 1337991554f2SKenneth D. Merry if (cm) { 1338991554f2SKenneth D. Merry mprsas_send_abort(sc, tm, cm); 1339991554f2SKenneth D. Merry } 1340991554f2SKenneth D. Merry else { 1341991554f2SKenneth D. Merry targ->tm = NULL; 1342991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1343991554f2SKenneth D. Merry } 1344991554f2SKenneth D. Merry } 1345991554f2SKenneth D. Merry else { 1346991554f2SKenneth D. Merry /* if we still have commands for this LUN, the reset 1347991554f2SKenneth D. Merry * effectively failed, regardless of the status reported. 1348991554f2SKenneth D. Merry * Escalate to a target reset. 1349991554f2SKenneth D. Merry */ 1350991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1351991554f2SKenneth D. Merry "logical unit reset complete for tm %p, but still have %u " 1352991554f2SKenneth D. Merry "command(s)\n", tm, cm_count); 1353991554f2SKenneth D. Merry mprsas_send_reset(sc, tm, 1354991554f2SKenneth D. Merry MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET); 1355991554f2SKenneth D. Merry } 1356991554f2SKenneth D. Merry } 1357991554f2SKenneth D. Merry 1358991554f2SKenneth D. Merry static void 1359991554f2SKenneth D. Merry mprsas_target_reset_complete(struct mpr_softc *sc, struct mpr_command *tm) 1360991554f2SKenneth D. Merry { 1361991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *reply; 1362991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 1363991554f2SKenneth D. Merry struct mprsas_target *targ; 1364991554f2SKenneth D. Merry 1365991554f2SKenneth D. Merry callout_stop(&tm->cm_callout); 1366991554f2SKenneth D. Merry 1367991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 1368991554f2SKenneth D. Merry reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 1369991554f2SKenneth D. Merry targ = tm->cm_targ; 1370991554f2SKenneth D. Merry 1371991554f2SKenneth D. Merry /* 1372991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 1373991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 1374991554f2SKenneth D. Merry * task management commands don't have S/G lists. 1375991554f2SKenneth D. Merry */ 1376991554f2SKenneth D. Merry if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 1377a2c14879SStephen McConnell mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for target " 1378a2c14879SStephen McConnell "reset! This should not happen!\n", __func__, tm->cm_flags); 1379991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1380991554f2SKenneth D. Merry return; 1381991554f2SKenneth D. Merry } 1382991554f2SKenneth D. Merry 1383991554f2SKenneth D. Merry if (reply == NULL) { 13847a2a6a1aSStephen McConnell mprsas_log_command(tm, MPR_RECOVERY, "NULL reset reply for tm " 13857a2a6a1aSStephen McConnell "%p\n", tm); 1386991554f2SKenneth D. Merry if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) { 1387991554f2SKenneth D. Merry /* this completion was due to a reset, just cleanup */ 1388991554f2SKenneth D. Merry targ->tm = NULL; 1389991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1390991554f2SKenneth D. Merry } 1391991554f2SKenneth D. Merry else { 1392991554f2SKenneth D. Merry /* we should have gotten a reply. */ 1393991554f2SKenneth D. Merry mpr_reinit(sc); 1394991554f2SKenneth D. Merry } 1395991554f2SKenneth D. Merry return; 1396991554f2SKenneth D. Merry } 1397991554f2SKenneth D. Merry 1398991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1399991554f2SKenneth D. Merry "target reset status 0x%x code 0x%x count %u\n", 1400991554f2SKenneth D. Merry le16toh(reply->IOCStatus), le32toh(reply->ResponseCode), 1401991554f2SKenneth D. Merry le32toh(reply->TerminationCount)); 1402991554f2SKenneth D. Merry 1403991554f2SKenneth D. Merry if (targ->outstanding == 0) { 1404991554f2SKenneth D. Merry /* we've finished recovery for this target and all 1405991554f2SKenneth D. Merry * of its logical units. 1406991554f2SKenneth D. Merry */ 1407991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, 1408991554f2SKenneth D. Merry "recovery finished after target reset\n"); 1409991554f2SKenneth D. Merry 1410991554f2SKenneth D. Merry mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid, 1411991554f2SKenneth D. Merry CAM_LUN_WILDCARD); 1412991554f2SKenneth D. Merry 1413991554f2SKenneth D. Merry targ->tm = NULL; 1414991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1415991554f2SKenneth D. Merry } 1416991554f2SKenneth D. Merry else { 1417991554f2SKenneth D. Merry /* after a target reset, if this target still has 1418991554f2SKenneth D. Merry * outstanding commands, the reset effectively failed, 1419991554f2SKenneth D. Merry * regardless of the status reported. escalate. 1420991554f2SKenneth D. Merry */ 1421991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1422991554f2SKenneth D. Merry "target reset complete for tm %p, but still have %u " 1423991554f2SKenneth D. Merry "command(s)\n", tm, targ->outstanding); 1424991554f2SKenneth D. Merry mpr_reinit(sc); 1425991554f2SKenneth D. Merry } 1426991554f2SKenneth D. Merry } 1427991554f2SKenneth D. Merry 1428991554f2SKenneth D. Merry #define MPR_RESET_TIMEOUT 30 1429991554f2SKenneth D. Merry 1430a2c14879SStephen McConnell int 1431991554f2SKenneth D. Merry mprsas_send_reset(struct mpr_softc *sc, struct mpr_command *tm, uint8_t type) 1432991554f2SKenneth D. Merry { 1433991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 1434991554f2SKenneth D. Merry struct mprsas_target *target; 1435991554f2SKenneth D. Merry int err; 1436991554f2SKenneth D. Merry 1437991554f2SKenneth D. Merry target = tm->cm_targ; 1438991554f2SKenneth D. Merry if (target->handle == 0) { 1439a2c14879SStephen McConnell mpr_dprint(sc, MPR_ERROR, "%s null devhandle for target_id " 1440a2c14879SStephen McConnell "%d\n", __func__, target->tid); 1441991554f2SKenneth D. Merry return -1; 1442991554f2SKenneth D. Merry } 1443991554f2SKenneth D. Merry 1444991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 1445991554f2SKenneth D. Merry req->DevHandle = htole16(target->handle); 1446991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 1447991554f2SKenneth D. Merry req->TaskType = type; 1448991554f2SKenneth D. Merry 1449991554f2SKenneth D. Merry if (type == MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET) { 1450991554f2SKenneth D. Merry /* XXX Need to handle invalid LUNs */ 1451991554f2SKenneth D. Merry MPR_SET_LUN(req->LUN, tm->cm_lun); 1452991554f2SKenneth D. Merry tm->cm_targ->logical_unit_resets++; 1453991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, 1454991554f2SKenneth D. Merry "sending logical unit reset\n"); 1455991554f2SKenneth D. Merry tm->cm_complete = mprsas_logical_unit_reset_complete; 1456a2c14879SStephen McConnell mprsas_prepare_for_tm(sc, tm, target, tm->cm_lun); 1457991554f2SKenneth D. Merry } 1458991554f2SKenneth D. Merry else if (type == MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET) { 1459991554f2SKenneth D. Merry /* 1460991554f2SKenneth D. Merry * Target reset method = 1461991554f2SKenneth D. Merry * SAS Hard Link Reset / SATA Link Reset 1462991554f2SKenneth D. Merry */ 1463991554f2SKenneth D. Merry req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; 1464991554f2SKenneth D. Merry tm->cm_targ->target_resets++; 1465991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, 1466991554f2SKenneth D. Merry "sending target reset\n"); 1467991554f2SKenneth D. Merry tm->cm_complete = mprsas_target_reset_complete; 1468a2c14879SStephen McConnell mprsas_prepare_for_tm(sc, tm, target, CAM_LUN_WILDCARD); 1469991554f2SKenneth D. Merry } 1470991554f2SKenneth D. Merry else { 1471991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "unexpected reset type 0x%x\n", type); 1472991554f2SKenneth D. Merry return -1; 1473991554f2SKenneth D. Merry } 1474991554f2SKenneth D. Merry 1475a2c14879SStephen McConnell mpr_dprint(sc, MPR_INFO, "to target %u handle 0x%04x\n", target->tid, 1476991554f2SKenneth D. Merry target->handle); 1477991554f2SKenneth D. Merry if (target->encl_level_valid) { 1478a2c14879SStephen McConnell mpr_dprint(sc, MPR_INFO, "At enclosure level %d, slot %d, " 1479991554f2SKenneth D. Merry "connector name (%4s)\n", target->encl_level, 1480991554f2SKenneth D. Merry target->encl_slot, target->connector_name); 1481991554f2SKenneth D. Merry } 1482991554f2SKenneth D. Merry 1483991554f2SKenneth D. Merry tm->cm_data = NULL; 1484991554f2SKenneth D. Merry tm->cm_desc.HighPriority.RequestFlags = 1485991554f2SKenneth D. Merry MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 1486991554f2SKenneth D. Merry tm->cm_complete_data = (void *)tm; 1487991554f2SKenneth D. Merry 1488991554f2SKenneth D. Merry callout_reset(&tm->cm_callout, MPR_RESET_TIMEOUT * hz, 1489991554f2SKenneth D. Merry mprsas_tm_timeout, tm); 1490991554f2SKenneth D. Merry 1491991554f2SKenneth D. Merry err = mpr_map_command(sc, tm); 1492991554f2SKenneth D. Merry if (err) 1493991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1494a2c14879SStephen McConnell "error %d sending reset type %u\n", err, type); 1495991554f2SKenneth D. Merry 1496991554f2SKenneth D. Merry return err; 1497991554f2SKenneth D. Merry } 1498991554f2SKenneth D. Merry 1499991554f2SKenneth D. Merry 1500991554f2SKenneth D. Merry static void 1501991554f2SKenneth D. Merry mprsas_abort_complete(struct mpr_softc *sc, struct mpr_command *tm) 1502991554f2SKenneth D. Merry { 1503991554f2SKenneth D. Merry struct mpr_command *cm; 1504991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *reply; 1505991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 1506991554f2SKenneth D. Merry struct mprsas_target *targ; 1507991554f2SKenneth D. Merry 1508991554f2SKenneth D. Merry callout_stop(&tm->cm_callout); 1509991554f2SKenneth D. Merry 1510991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 1511991554f2SKenneth D. Merry reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 1512991554f2SKenneth D. Merry targ = tm->cm_targ; 1513991554f2SKenneth D. Merry 1514991554f2SKenneth D. Merry /* 1515991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 1516991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 1517991554f2SKenneth D. Merry * task management commands don't have S/G lists. 1518991554f2SKenneth D. Merry */ 1519991554f2SKenneth D. Merry if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 1520991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1521991554f2SKenneth D. Merry "cm_flags = %#x for abort %p TaskMID %u!\n", 1522991554f2SKenneth D. Merry tm->cm_flags, tm, le16toh(req->TaskMID)); 1523991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1524991554f2SKenneth D. Merry return; 1525991554f2SKenneth D. Merry } 1526991554f2SKenneth D. Merry 1527991554f2SKenneth D. Merry if (reply == NULL) { 1528991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1529991554f2SKenneth D. Merry "NULL abort reply for tm %p TaskMID %u\n", 1530991554f2SKenneth D. Merry tm, le16toh(req->TaskMID)); 1531991554f2SKenneth D. Merry if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) { 1532991554f2SKenneth D. Merry /* this completion was due to a reset, just cleanup */ 1533991554f2SKenneth D. Merry targ->tm = NULL; 1534991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1535991554f2SKenneth D. Merry } 1536991554f2SKenneth D. Merry else { 1537991554f2SKenneth D. Merry /* we should have gotten a reply. */ 1538991554f2SKenneth D. Merry mpr_reinit(sc); 1539991554f2SKenneth D. Merry } 1540991554f2SKenneth D. Merry return; 1541991554f2SKenneth D. Merry } 1542991554f2SKenneth D. Merry 1543991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1544991554f2SKenneth D. Merry "abort TaskMID %u status 0x%x code 0x%x count %u\n", 1545991554f2SKenneth D. Merry le16toh(req->TaskMID), 1546991554f2SKenneth D. Merry le16toh(reply->IOCStatus), le32toh(reply->ResponseCode), 1547991554f2SKenneth D. Merry le32toh(reply->TerminationCount)); 1548991554f2SKenneth D. Merry 1549991554f2SKenneth D. Merry cm = TAILQ_FIRST(&tm->cm_targ->timedout_commands); 1550991554f2SKenneth D. Merry if (cm == NULL) { 1551991554f2SKenneth D. Merry /* if there are no more timedout commands, we're done with 1552991554f2SKenneth D. Merry * error recovery for this target. 1553991554f2SKenneth D. Merry */ 1554991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1555991554f2SKenneth D. Merry "finished recovery after aborting TaskMID %u\n", 1556991554f2SKenneth D. Merry le16toh(req->TaskMID)); 1557991554f2SKenneth D. Merry 1558991554f2SKenneth D. Merry targ->tm = NULL; 1559991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1560991554f2SKenneth D. Merry } 1561991554f2SKenneth D. Merry else if (le16toh(req->TaskMID) != cm->cm_desc.Default.SMID) { 1562991554f2SKenneth D. Merry /* abort success, but we have more timedout commands to abort */ 1563991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1564991554f2SKenneth D. Merry "continuing recovery after aborting TaskMID %u\n", 1565991554f2SKenneth D. Merry le16toh(req->TaskMID)); 1566991554f2SKenneth D. Merry 1567991554f2SKenneth D. Merry mprsas_send_abort(sc, tm, cm); 1568991554f2SKenneth D. Merry } 1569991554f2SKenneth D. Merry else { 1570991554f2SKenneth D. Merry /* we didn't get a command completion, so the abort 1571991554f2SKenneth D. Merry * failed as far as we're concerned. escalate. 1572991554f2SKenneth D. Merry */ 1573991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1574991554f2SKenneth D. Merry "abort failed for TaskMID %u tm %p\n", 1575991554f2SKenneth D. Merry le16toh(req->TaskMID), tm); 1576991554f2SKenneth D. Merry 1577991554f2SKenneth D. Merry mprsas_send_reset(sc, tm, 1578991554f2SKenneth D. Merry MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET); 1579991554f2SKenneth D. Merry } 1580991554f2SKenneth D. Merry } 1581991554f2SKenneth D. Merry 1582991554f2SKenneth D. Merry #define MPR_ABORT_TIMEOUT 5 1583991554f2SKenneth D. Merry 1584991554f2SKenneth D. Merry static int 1585991554f2SKenneth D. Merry mprsas_send_abort(struct mpr_softc *sc, struct mpr_command *tm, 1586991554f2SKenneth D. Merry struct mpr_command *cm) 1587991554f2SKenneth D. Merry { 1588991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 1589991554f2SKenneth D. Merry struct mprsas_target *targ; 1590991554f2SKenneth D. Merry int err; 1591991554f2SKenneth D. Merry 1592991554f2SKenneth D. Merry targ = cm->cm_targ; 1593991554f2SKenneth D. Merry if (targ->handle == 0) { 1594991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR,"%s null devhandle for target_id %d\n", 1595991554f2SKenneth D. Merry __func__, cm->cm_ccb->ccb_h.target_id); 1596991554f2SKenneth D. Merry return -1; 1597991554f2SKenneth D. Merry } 1598991554f2SKenneth D. Merry 1599855fe445SScott Long mprsas_log_command(cm, MPR_RECOVERY|MPR_INFO, 1600991554f2SKenneth D. Merry "Aborting command %p\n", cm); 1601991554f2SKenneth D. Merry 1602991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 1603991554f2SKenneth D. Merry req->DevHandle = htole16(targ->handle); 1604991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 1605991554f2SKenneth D. Merry req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK; 1606991554f2SKenneth D. Merry 1607991554f2SKenneth D. Merry /* XXX Need to handle invalid LUNs */ 1608991554f2SKenneth D. Merry MPR_SET_LUN(req->LUN, cm->cm_ccb->ccb_h.target_lun); 1609991554f2SKenneth D. Merry 1610991554f2SKenneth D. Merry req->TaskMID = htole16(cm->cm_desc.Default.SMID); 1611991554f2SKenneth D. Merry 1612991554f2SKenneth D. Merry tm->cm_data = NULL; 1613991554f2SKenneth D. Merry tm->cm_desc.HighPriority.RequestFlags = 1614991554f2SKenneth D. Merry MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 1615991554f2SKenneth D. Merry tm->cm_complete = mprsas_abort_complete; 1616991554f2SKenneth D. Merry tm->cm_complete_data = (void *)tm; 1617991554f2SKenneth D. Merry tm->cm_targ = cm->cm_targ; 1618991554f2SKenneth D. Merry tm->cm_lun = cm->cm_lun; 1619991554f2SKenneth D. Merry 1620991554f2SKenneth D. Merry callout_reset(&tm->cm_callout, MPR_ABORT_TIMEOUT * hz, 1621991554f2SKenneth D. Merry mprsas_tm_timeout, tm); 1622991554f2SKenneth D. Merry 1623991554f2SKenneth D. Merry targ->aborts++; 1624991554f2SKenneth D. Merry 1625a2c14879SStephen McConnell mpr_dprint(sc, MPR_INFO, "Sending reset from %s for target ID %d\n", 1626a2c14879SStephen McConnell __func__, targ->tid); 1627a2c14879SStephen McConnell mprsas_prepare_for_tm(sc, tm, targ, tm->cm_lun); 1628a2c14879SStephen McConnell 1629991554f2SKenneth D. Merry err = mpr_map_command(sc, tm); 1630991554f2SKenneth D. Merry if (err) 1631855fe445SScott Long mpr_dprint(sc, MPR_RECOVERY, 1632991554f2SKenneth D. Merry "error %d sending abort for cm %p SMID %u\n", 1633991554f2SKenneth D. Merry err, cm, req->TaskMID); 1634991554f2SKenneth D. Merry return err; 1635991554f2SKenneth D. Merry } 1636991554f2SKenneth D. Merry 1637991554f2SKenneth D. Merry static void 1638991554f2SKenneth D. Merry mprsas_scsiio_timeout(void *data) 1639991554f2SKenneth D. Merry { 1640991554f2SKenneth D. Merry struct mpr_softc *sc; 1641991554f2SKenneth D. Merry struct mpr_command *cm; 1642991554f2SKenneth D. Merry struct mprsas_target *targ; 1643991554f2SKenneth D. Merry 1644991554f2SKenneth D. Merry cm = (struct mpr_command *)data; 1645991554f2SKenneth D. Merry sc = cm->cm_sc; 1646991554f2SKenneth D. Merry 1647991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 1648991554f2SKenneth D. Merry mtx_assert(&sc->mpr_mtx, MA_OWNED); 1649991554f2SKenneth D. Merry 1650991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "Timeout checking cm %p\n", cm); 1651991554f2SKenneth D. Merry 1652991554f2SKenneth D. Merry /* 1653991554f2SKenneth D. Merry * Run the interrupt handler to make sure it's not pending. This 1654991554f2SKenneth D. Merry * isn't perfect because the command could have already completed 1655991554f2SKenneth D. Merry * and been re-used, though this is unlikely. 1656991554f2SKenneth D. Merry */ 1657991554f2SKenneth D. Merry mpr_intr_locked(sc); 1658991554f2SKenneth D. Merry if (cm->cm_state == MPR_CM_STATE_FREE) { 1659991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_XINFO, 1660991554f2SKenneth D. Merry "SCSI command %p almost timed out\n", cm); 1661991554f2SKenneth D. Merry return; 1662991554f2SKenneth D. Merry } 1663991554f2SKenneth D. Merry 1664991554f2SKenneth D. Merry if (cm->cm_ccb == NULL) { 1665991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "command timeout with NULL ccb\n"); 1666991554f2SKenneth D. Merry return; 1667991554f2SKenneth D. Merry } 1668991554f2SKenneth D. Merry 1669991554f2SKenneth D. Merry targ = cm->cm_targ; 1670991554f2SKenneth D. Merry targ->timeouts++; 1671991554f2SKenneth D. Merry 1672855fe445SScott Long mprsas_log_command(cm, MPR_ERROR, "command timeout %d cm %p target " 1673855fe445SScott Long "%u, handle(0x%04x)\n", cm->cm_ccb->ccb_h.timeout, cm, targ->tid, 1674855fe445SScott Long targ->handle); 1675991554f2SKenneth D. Merry if (targ->encl_level_valid) { 1676a2c14879SStephen McConnell mpr_dprint(sc, MPR_ERROR, "At enclosure level %d, slot %d, " 1677991554f2SKenneth D. Merry "connector name (%4s)\n", targ->encl_level, targ->encl_slot, 1678991554f2SKenneth D. Merry targ->connector_name); 1679991554f2SKenneth D. Merry } 1680991554f2SKenneth D. Merry 1681991554f2SKenneth D. Merry /* XXX first, check the firmware state, to see if it's still 1682991554f2SKenneth D. Merry * operational. if not, do a diag reset. 1683991554f2SKenneth D. Merry */ 1684a2c14879SStephen McConnell mprsas_set_ccbstatus(cm->cm_ccb, CAM_CMD_TIMEOUT); 1685991554f2SKenneth D. Merry cm->cm_state = MPR_CM_STATE_TIMEDOUT; 1686991554f2SKenneth D. Merry TAILQ_INSERT_TAIL(&targ->timedout_commands, cm, cm_recovery); 1687991554f2SKenneth D. Merry 1688991554f2SKenneth D. Merry if (targ->tm != NULL) { 1689991554f2SKenneth D. Merry /* target already in recovery, just queue up another 1690991554f2SKenneth D. Merry * timedout command to be processed later. 1691991554f2SKenneth D. Merry */ 1692991554f2SKenneth D. Merry mpr_dprint(sc, MPR_RECOVERY, "queued timedout cm %p for " 1693991554f2SKenneth D. Merry "processing by tm %p\n", cm, targ->tm); 1694991554f2SKenneth D. Merry } 1695991554f2SKenneth D. Merry else if ((targ->tm = mprsas_alloc_tm(sc)) != NULL) { 1696991554f2SKenneth D. Merry mpr_dprint(sc, MPR_RECOVERY, "timedout cm %p allocated tm %p\n", 1697991554f2SKenneth D. Merry cm, targ->tm); 1698991554f2SKenneth D. Merry 1699991554f2SKenneth D. Merry /* start recovery by aborting the first timedout command */ 1700991554f2SKenneth D. Merry mprsas_send_abort(sc, targ->tm, cm); 1701991554f2SKenneth D. Merry } 1702991554f2SKenneth D. Merry else { 1703991554f2SKenneth D. Merry /* XXX queue this target up for recovery once a TM becomes 1704991554f2SKenneth D. Merry * available. The firmware only has a limited number of 1705991554f2SKenneth D. Merry * HighPriority credits for the high priority requests used 1706991554f2SKenneth D. Merry * for task management, and we ran out. 1707991554f2SKenneth D. Merry * 1708991554f2SKenneth D. Merry * Isilon: don't worry about this for now, since we have 1709991554f2SKenneth D. Merry * more credits than disks in an enclosure, and limit 1710991554f2SKenneth D. Merry * ourselves to one TM per target for recovery. 1711991554f2SKenneth D. Merry */ 17127a2a6a1aSStephen McConnell mpr_dprint(sc, MPR_RECOVERY, "timedout cm %p failed to " 17137a2a6a1aSStephen McConnell "allocate a tm\n", cm); 1714991554f2SKenneth D. Merry } 1715991554f2SKenneth D. Merry } 1716991554f2SKenneth D. Merry 171767feec50SStephen McConnell /** 171867feec50SStephen McConnell * mprsas_build_nvme_unmap - Build Native NVMe DSM command equivalent 171967feec50SStephen McConnell * to SCSI Unmap. 172067feec50SStephen McConnell * Return 0 - for success, 172167feec50SStephen McConnell * 1 - to immediately return back the command with success status to CAM 172267feec50SStephen McConnell * negative value - to fallback to firmware path i.e. issue scsi unmap 172367feec50SStephen McConnell * to FW without any translation. 172467feec50SStephen McConnell */ 172567feec50SStephen McConnell static int 172667feec50SStephen McConnell mprsas_build_nvme_unmap(struct mpr_softc *sc, struct mpr_command *cm, 172767feec50SStephen McConnell union ccb *ccb, struct mprsas_target *targ) 172867feec50SStephen McConnell { 172967feec50SStephen McConnell Mpi26NVMeEncapsulatedRequest_t *req = NULL; 173067feec50SStephen McConnell struct ccb_scsiio *csio; 173167feec50SStephen McConnell struct unmap_parm_list *plist; 173267feec50SStephen McConnell struct nvme_dsm_range *nvme_dsm_ranges = NULL; 173367feec50SStephen McConnell struct nvme_command *c; 173467feec50SStephen McConnell int i, res; 173567feec50SStephen McConnell uint16_t ndesc, list_len, data_length; 173667feec50SStephen McConnell struct mpr_prp_page *prp_page_info; 173767feec50SStephen McConnell uint64_t nvme_dsm_ranges_dma_handle; 173867feec50SStephen McConnell 173967feec50SStephen McConnell csio = &ccb->csio; 174067feec50SStephen McConnell #if __FreeBSD_version >= 1100103 174167feec50SStephen McConnell list_len = (scsiio_cdb_ptr(csio)[7] << 8 | scsiio_cdb_ptr(csio)[8]); 174267feec50SStephen McConnell #else 174367feec50SStephen McConnell if (csio->ccb_h.flags & CAM_CDB_POINTER) { 174467feec50SStephen McConnell list_len = (ccb->csio.cdb_io.cdb_ptr[7] << 8 | 174567feec50SStephen McConnell ccb->csio.cdb_io.cdb_ptr[8]); 174667feec50SStephen McConnell } else { 174767feec50SStephen McConnell list_len = (ccb->csio.cdb_io.cdb_bytes[7] << 8 | 174867feec50SStephen McConnell ccb->csio.cdb_io.cdb_bytes[8]); 174967feec50SStephen McConnell } 175067feec50SStephen McConnell #endif 175167feec50SStephen McConnell if (!list_len) { 175267feec50SStephen McConnell mpr_dprint(sc, MPR_ERROR, "Parameter list length is Zero\n"); 175367feec50SStephen McConnell return -EINVAL; 175467feec50SStephen McConnell } 175567feec50SStephen McConnell 175667feec50SStephen McConnell plist = malloc(csio->dxfer_len, M_MPR, M_ZERO|M_NOWAIT); 175767feec50SStephen McConnell if (!plist) { 175867feec50SStephen McConnell mpr_dprint(sc, MPR_ERROR, "Unable to allocate memory to " 175967feec50SStephen McConnell "save UNMAP data\n"); 176067feec50SStephen McConnell return -ENOMEM; 176167feec50SStephen McConnell } 176267feec50SStephen McConnell 176367feec50SStephen McConnell /* Copy SCSI unmap data to a local buffer */ 176467feec50SStephen McConnell bcopy(csio->data_ptr, plist, csio->dxfer_len); 176567feec50SStephen McConnell 176667feec50SStephen McConnell /* return back the unmap command to CAM with success status, 176767feec50SStephen McConnell * if number of descripts is zero. 176867feec50SStephen McConnell */ 176967feec50SStephen McConnell ndesc = be16toh(plist->unmap_blk_desc_data_len) >> 4; 177067feec50SStephen McConnell if (!ndesc) { 177167feec50SStephen McConnell mpr_dprint(sc, MPR_XINFO, "Number of descriptors in " 177267feec50SStephen McConnell "UNMAP cmd is Zero\n"); 177367feec50SStephen McConnell res = 1; 177467feec50SStephen McConnell goto out; 177567feec50SStephen McConnell } 177667feec50SStephen McConnell 177767feec50SStephen McConnell data_length = ndesc * sizeof(struct nvme_dsm_range); 177867feec50SStephen McConnell if (data_length > targ->MDTS) { 177967feec50SStephen McConnell mpr_dprint(sc, MPR_ERROR, "data length: %d is greater than " 178067feec50SStephen McConnell "Device's MDTS: %d\n", data_length, targ->MDTS); 178167feec50SStephen McConnell res = -EINVAL; 178267feec50SStephen McConnell goto out; 178367feec50SStephen McConnell } 178467feec50SStephen McConnell 178567feec50SStephen McConnell prp_page_info = mpr_alloc_prp_page(sc); 178667feec50SStephen McConnell KASSERT(prp_page_info != NULL, ("%s: There is no PRP Page for " 178767feec50SStephen McConnell "UNMAP command.\n", __func__)); 178867feec50SStephen McConnell 178967feec50SStephen McConnell /* 179067feec50SStephen McConnell * Insert the allocated PRP page into the command's PRP page list. This 179167feec50SStephen McConnell * will be freed when the command is freed. 179267feec50SStephen McConnell */ 179367feec50SStephen McConnell TAILQ_INSERT_TAIL(&cm->cm_prp_page_list, prp_page_info, prp_page_link); 179467feec50SStephen McConnell 179567feec50SStephen McConnell nvme_dsm_ranges = (struct nvme_dsm_range *)prp_page_info->prp_page; 179667feec50SStephen McConnell nvme_dsm_ranges_dma_handle = prp_page_info->prp_page_busaddr; 179767feec50SStephen McConnell 179867feec50SStephen McConnell bzero(nvme_dsm_ranges, data_length); 179967feec50SStephen McConnell 180067feec50SStephen McConnell /* Convert SCSI unmap's descriptor data to NVMe DSM specific Range data 180167feec50SStephen McConnell * for each descriptors contained in SCSI UNMAP data. 180267feec50SStephen McConnell */ 180367feec50SStephen McConnell for (i = 0; i < ndesc; i++) { 180467feec50SStephen McConnell nvme_dsm_ranges[i].length = 180567feec50SStephen McConnell htole32(be32toh(plist->desc[i].nlb)); 180667feec50SStephen McConnell nvme_dsm_ranges[i].starting_lba = 180767feec50SStephen McConnell htole64(be64toh(plist->desc[i].slba)); 180867feec50SStephen McConnell nvme_dsm_ranges[i].attributes = 0; 180967feec50SStephen McConnell } 181067feec50SStephen McConnell 181167feec50SStephen McConnell /* Build MPI2.6's NVMe Encapsulated Request Message */ 181267feec50SStephen McConnell req = (Mpi26NVMeEncapsulatedRequest_t *)cm->cm_req; 181367feec50SStephen McConnell bzero(req, sizeof(*req)); 181467feec50SStephen McConnell req->DevHandle = htole16(targ->handle); 181567feec50SStephen McConnell req->Function = MPI2_FUNCTION_NVME_ENCAPSULATED; 181667feec50SStephen McConnell req->Flags = MPI26_NVME_FLAGS_WRITE; 181767feec50SStephen McConnell req->ErrorResponseBaseAddress.High = 181867feec50SStephen McConnell htole32((uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32)); 181967feec50SStephen McConnell req->ErrorResponseBaseAddress.Low = 182067feec50SStephen McConnell htole32(cm->cm_sense_busaddr); 182167feec50SStephen McConnell req->ErrorResponseAllocationLength = 182267feec50SStephen McConnell htole16(sizeof(struct nvme_completion)); 182367feec50SStephen McConnell req->EncapsulatedCommandLength = 182467feec50SStephen McConnell htole16(sizeof(struct nvme_command)); 182567feec50SStephen McConnell req->DataLength = htole32(data_length); 182667feec50SStephen McConnell 182767feec50SStephen McConnell /* Build NVMe DSM command */ 182867feec50SStephen McConnell c = (struct nvme_command *) req->NVMe_Command; 182967feec50SStephen McConnell c->opc = NVME_OPC_DATASET_MANAGEMENT; 183067feec50SStephen McConnell c->nsid = htole32(csio->ccb_h.target_lun + 1); 183167feec50SStephen McConnell c->cdw10 = htole32(ndesc - 1); 183267feec50SStephen McConnell c->cdw11 = htole32(NVME_DSM_ATTR_DEALLOCATE); 183367feec50SStephen McConnell 183467feec50SStephen McConnell cm->cm_length = data_length; 183567feec50SStephen McConnell cm->cm_data = NULL; 183667feec50SStephen McConnell 183767feec50SStephen McConnell cm->cm_complete = mprsas_scsiio_complete; 183867feec50SStephen McConnell cm->cm_complete_data = ccb; 183967feec50SStephen McConnell cm->cm_targ = targ; 184067feec50SStephen McConnell cm->cm_lun = csio->ccb_h.target_lun; 184167feec50SStephen McConnell cm->cm_ccb = ccb; 184267feec50SStephen McConnell 184367feec50SStephen McConnell cm->cm_desc.Default.RequestFlags = 184467feec50SStephen McConnell MPI26_REQ_DESCRIPT_FLAGS_PCIE_ENCAPSULATED; 184567feec50SStephen McConnell 184667feec50SStephen McConnell #if __FreeBSD_version >= 1000029 184767feec50SStephen McConnell callout_reset_sbt(&cm->cm_callout, SBT_1MS * ccb->ccb_h.timeout, 0, 184867feec50SStephen McConnell mprsas_scsiio_timeout, cm, 0); 184967feec50SStephen McConnell #else //__FreeBSD_version < 1000029 185067feec50SStephen McConnell callout_reset(&cm->cm_callout, (ccb->ccb_h.timeout * hz) / 1000, 185167feec50SStephen McConnell mprsas_scsiio_timeout, cm); 185267feec50SStephen McConnell #endif //__FreeBSD_version >= 1000029 185367feec50SStephen McConnell 185467feec50SStephen McConnell targ->issued++; 185567feec50SStephen McConnell targ->outstanding++; 185667feec50SStephen McConnell TAILQ_INSERT_TAIL(&targ->commands, cm, cm_link); 185767feec50SStephen McConnell ccb->ccb_h.status |= CAM_SIM_QUEUED; 185867feec50SStephen McConnell 185967feec50SStephen McConnell mprsas_log_command(cm, MPR_XINFO, "%s cm %p ccb %p outstanding %u\n", 186067feec50SStephen McConnell __func__, cm, ccb, targ->outstanding); 186167feec50SStephen McConnell 186218982e8fSStephen McConnell mpr_build_nvme_prp(sc, cm, req, 186318982e8fSStephen McConnell (void *)(uintptr_t)nvme_dsm_ranges_dma_handle, 0, data_length); 186467feec50SStephen McConnell mpr_map_command(sc, cm); 186567feec50SStephen McConnell 186667feec50SStephen McConnell out: 186767feec50SStephen McConnell free(plist, M_MPR); 186867feec50SStephen McConnell return 0; 186967feec50SStephen McConnell } 187067feec50SStephen McConnell 1871991554f2SKenneth D. Merry static void 1872991554f2SKenneth D. Merry mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb) 1873991554f2SKenneth D. Merry { 1874991554f2SKenneth D. Merry MPI2_SCSI_IO_REQUEST *req; 1875991554f2SKenneth D. Merry struct ccb_scsiio *csio; 1876991554f2SKenneth D. Merry struct mpr_softc *sc; 1877991554f2SKenneth D. Merry struct mprsas_target *targ; 1878991554f2SKenneth D. Merry struct mprsas_lun *lun; 1879991554f2SKenneth D. Merry struct mpr_command *cm; 188067feec50SStephen McConnell uint8_t i, lba_byte, *ref_tag_addr, scsi_opcode; 1881991554f2SKenneth D. Merry uint16_t eedp_flags; 1882991554f2SKenneth D. Merry uint32_t mpi_control; 188367feec50SStephen McConnell int rc; 1884991554f2SKenneth D. Merry 1885991554f2SKenneth D. Merry sc = sassc->sc; 1886991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 1887991554f2SKenneth D. Merry mtx_assert(&sc->mpr_mtx, MA_OWNED); 1888991554f2SKenneth D. Merry 1889991554f2SKenneth D. Merry csio = &ccb->csio; 1890a2c14879SStephen McConnell KASSERT(csio->ccb_h.target_id < sassc->maxtargets, 1891a2c14879SStephen McConnell ("Target %d out of bounds in XPT_SCSI_IO\n", 1892a2c14879SStephen McConnell csio->ccb_h.target_id)); 1893991554f2SKenneth D. Merry targ = &sassc->targets[csio->ccb_h.target_id]; 1894991554f2SKenneth D. Merry mpr_dprint(sc, MPR_TRACE, "ccb %p target flag %x\n", ccb, targ->flags); 1895991554f2SKenneth D. Merry if (targ->handle == 0x0) { 1896991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s NULL handle for target %u\n", 1897991554f2SKenneth D. Merry __func__, csio->ccb_h.target_id); 1898a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); 1899991554f2SKenneth D. Merry xpt_done(ccb); 1900991554f2SKenneth D. Merry return; 1901991554f2SKenneth D. Merry } 1902991554f2SKenneth D. Merry if (targ->flags & MPR_TARGET_FLAGS_RAID_COMPONENT) { 1903a2c14879SStephen McConnell mpr_dprint(sc, MPR_ERROR, "%s Raid component no SCSI IO " 1904991554f2SKenneth D. Merry "supported %u\n", __func__, csio->ccb_h.target_id); 1905a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); 1906991554f2SKenneth D. Merry xpt_done(ccb); 1907991554f2SKenneth D. Merry return; 1908991554f2SKenneth D. Merry } 1909991554f2SKenneth D. Merry /* 1910991554f2SKenneth D. Merry * Sometimes, it is possible to get a command that is not "In 1911991554f2SKenneth D. Merry * Progress" and was actually aborted by the upper layer. Check for 1912991554f2SKenneth D. Merry * this here and complete the command without error. 1913991554f2SKenneth D. Merry */ 1914a2c14879SStephen McConnell if (mprsas_get_ccbstatus(ccb) != CAM_REQ_INPROG) { 1915991554f2SKenneth D. Merry mpr_dprint(sc, MPR_TRACE, "%s Command is not in progress for " 1916991554f2SKenneth D. Merry "target %u\n", __func__, csio->ccb_h.target_id); 1917991554f2SKenneth D. Merry xpt_done(ccb); 1918991554f2SKenneth D. Merry return; 1919991554f2SKenneth D. Merry } 1920991554f2SKenneth D. Merry /* 1921991554f2SKenneth D. Merry * If devinfo is 0 this will be a volume. In that case don't tell CAM 1922991554f2SKenneth D. Merry * that the volume has timed out. We want volumes to be enumerated 1923991554f2SKenneth D. Merry * until they are deleted/removed, not just failed. 1924991554f2SKenneth D. Merry */ 1925991554f2SKenneth D. Merry if (targ->flags & MPRSAS_TARGET_INREMOVAL) { 1926991554f2SKenneth D. Merry if (targ->devinfo == 0) 1927a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); 1928991554f2SKenneth D. Merry else 1929a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_SEL_TIMEOUT); 1930991554f2SKenneth D. Merry xpt_done(ccb); 1931991554f2SKenneth D. Merry return; 1932991554f2SKenneth D. Merry } 1933991554f2SKenneth D. Merry 1934991554f2SKenneth D. Merry if ((sc->mpr_flags & MPR_FLAGS_SHUTDOWN) != 0) { 1935a2c14879SStephen McConnell mpr_dprint(sc, MPR_INFO, "%s shutting down\n", __func__); 1936a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); 1937a2c14879SStephen McConnell xpt_done(ccb); 1938a2c14879SStephen McConnell return; 1939a2c14879SStephen McConnell } 1940a2c14879SStephen McConnell 1941a2c14879SStephen McConnell /* 1942a2c14879SStephen McConnell * If target has a reset in progress, freeze the devq and return. The 1943a2c14879SStephen McConnell * devq will be released when the TM reset is finished. 1944a2c14879SStephen McConnell */ 1945a2c14879SStephen McConnell if (targ->flags & MPRSAS_TARGET_INRESET) { 1946a2c14879SStephen McConnell ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN; 1947a2c14879SStephen McConnell mpr_dprint(sc, MPR_INFO, "%s: Freezing devq for target ID %d\n", 1948a2c14879SStephen McConnell __func__, targ->tid); 1949a2c14879SStephen McConnell xpt_freeze_devq(ccb->ccb_h.path, 1); 1950991554f2SKenneth D. Merry xpt_done(ccb); 1951991554f2SKenneth D. Merry return; 1952991554f2SKenneth D. Merry } 1953991554f2SKenneth D. Merry 1954991554f2SKenneth D. Merry cm = mpr_alloc_command(sc); 1955991554f2SKenneth D. Merry if (cm == NULL || (sc->mpr_flags & MPR_FLAGS_DIAGRESET)) { 1956991554f2SKenneth D. Merry if (cm != NULL) { 1957991554f2SKenneth D. Merry mpr_free_command(sc, cm); 1958991554f2SKenneth D. Merry } 1959991554f2SKenneth D. Merry if ((sassc->flags & MPRSAS_QUEUE_FROZEN) == 0) { 1960991554f2SKenneth D. Merry xpt_freeze_simq(sassc->sim, 1); 1961991554f2SKenneth D. Merry sassc->flags |= MPRSAS_QUEUE_FROZEN; 1962991554f2SKenneth D. Merry } 1963991554f2SKenneth D. Merry ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1964991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_REQUEUE_REQ; 1965991554f2SKenneth D. Merry xpt_done(ccb); 1966991554f2SKenneth D. Merry return; 1967991554f2SKenneth D. Merry } 1968991554f2SKenneth D. Merry 196967feec50SStephen McConnell /* For NVME device's issue UNMAP command directly to NVME drives by 197067feec50SStephen McConnell * constructing equivalent native NVMe DataSetManagement command. 197167feec50SStephen McConnell */ 197267feec50SStephen McConnell #if __FreeBSD_version >= 1100103 197367feec50SStephen McConnell scsi_opcode = scsiio_cdb_ptr(csio)[0]; 197467feec50SStephen McConnell #else 197567feec50SStephen McConnell if (csio->ccb_h.flags & CAM_CDB_POINTER) 197667feec50SStephen McConnell scsi_opcode = csio->cdb_io.cdb_ptr[0]; 197767feec50SStephen McConnell else 197867feec50SStephen McConnell scsi_opcode = csio->cdb_io.cdb_bytes[0]; 197967feec50SStephen McConnell #endif 198067feec50SStephen McConnell if (scsi_opcode == UNMAP && 198167feec50SStephen McConnell targ->is_nvme && 198267feec50SStephen McConnell (csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) { 198367feec50SStephen McConnell rc = mprsas_build_nvme_unmap(sc, cm, ccb, targ); 198467feec50SStephen McConnell if (rc == 1) { /* return command to CAM with success status */ 198567feec50SStephen McConnell mpr_free_command(sc, cm); 198667feec50SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); 198767feec50SStephen McConnell xpt_done(ccb); 198867feec50SStephen McConnell return; 198967feec50SStephen McConnell } else if (!rc) /* Issued NVMe Encapsulated Request Message */ 199067feec50SStephen McConnell return; 199167feec50SStephen McConnell } 199267feec50SStephen McConnell 1993991554f2SKenneth D. Merry req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req; 1994991554f2SKenneth D. Merry bzero(req, sizeof(*req)); 1995991554f2SKenneth D. Merry req->DevHandle = htole16(targ->handle); 1996991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; 1997991554f2SKenneth D. Merry req->MsgFlags = 0; 1998991554f2SKenneth D. Merry req->SenseBufferLowAddress = htole32(cm->cm_sense_busaddr); 1999991554f2SKenneth D. Merry req->SenseBufferLength = MPR_SENSE_LEN; 2000991554f2SKenneth D. Merry req->SGLFlags = 0; 2001991554f2SKenneth D. Merry req->ChainOffset = 0; 2002991554f2SKenneth D. Merry req->SGLOffset0 = 24; /* 32bit word offset to the SGL */ 2003991554f2SKenneth D. Merry req->SGLOffset1= 0; 2004991554f2SKenneth D. Merry req->SGLOffset2= 0; 2005991554f2SKenneth D. Merry req->SGLOffset3= 0; 2006991554f2SKenneth D. Merry req->SkipCount = 0; 2007991554f2SKenneth D. Merry req->DataLength = htole32(csio->dxfer_len); 2008991554f2SKenneth D. Merry req->BidirectionalDataLength = 0; 2009991554f2SKenneth D. Merry req->IoFlags = htole16(csio->cdb_len); 2010991554f2SKenneth D. Merry req->EEDPFlags = 0; 2011991554f2SKenneth D. Merry 2012991554f2SKenneth D. Merry /* Note: BiDirectional transfers are not supported */ 2013991554f2SKenneth D. Merry switch (csio->ccb_h.flags & CAM_DIR_MASK) { 2014991554f2SKenneth D. Merry case CAM_DIR_IN: 2015991554f2SKenneth D. Merry mpi_control = MPI2_SCSIIO_CONTROL_READ; 2016991554f2SKenneth D. Merry cm->cm_flags |= MPR_CM_FLAGS_DATAIN; 2017991554f2SKenneth D. Merry break; 2018991554f2SKenneth D. Merry case CAM_DIR_OUT: 2019991554f2SKenneth D. Merry mpi_control = MPI2_SCSIIO_CONTROL_WRITE; 2020991554f2SKenneth D. Merry cm->cm_flags |= MPR_CM_FLAGS_DATAOUT; 2021991554f2SKenneth D. Merry break; 2022991554f2SKenneth D. Merry case CAM_DIR_NONE: 2023991554f2SKenneth D. Merry default: 2024991554f2SKenneth D. Merry mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER; 2025991554f2SKenneth D. Merry break; 2026991554f2SKenneth D. Merry } 2027991554f2SKenneth D. Merry 2028991554f2SKenneth D. Merry if (csio->cdb_len == 32) 2029991554f2SKenneth D. Merry mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT; 2030991554f2SKenneth D. Merry /* 2031991554f2SKenneth D. Merry * It looks like the hardware doesn't require an explicit tag 2032991554f2SKenneth D. Merry * number for each transaction. SAM Task Management not supported 2033991554f2SKenneth D. Merry * at the moment. 2034991554f2SKenneth D. Merry */ 2035991554f2SKenneth D. Merry switch (csio->tag_action) { 2036991554f2SKenneth D. Merry case MSG_HEAD_OF_Q_TAG: 2037991554f2SKenneth D. Merry mpi_control |= MPI2_SCSIIO_CONTROL_HEADOFQ; 2038991554f2SKenneth D. Merry break; 2039991554f2SKenneth D. Merry case MSG_ORDERED_Q_TAG: 2040991554f2SKenneth D. Merry mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ; 2041991554f2SKenneth D. Merry break; 2042991554f2SKenneth D. Merry case MSG_ACA_TASK: 2043991554f2SKenneth D. Merry mpi_control |= MPI2_SCSIIO_CONTROL_ACAQ; 2044991554f2SKenneth D. Merry break; 2045991554f2SKenneth D. Merry case CAM_TAG_ACTION_NONE: 2046991554f2SKenneth D. Merry case MSG_SIMPLE_Q_TAG: 2047991554f2SKenneth D. Merry default: 2048991554f2SKenneth D. Merry mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; 2049991554f2SKenneth D. Merry break; 2050991554f2SKenneth D. Merry } 2051991554f2SKenneth D. Merry mpi_control |= sc->mapping_table[csio->ccb_h.target_id].TLR_bits; 2052991554f2SKenneth D. Merry req->Control = htole32(mpi_control); 2053991554f2SKenneth D. Merry 2054991554f2SKenneth D. Merry if (MPR_SET_LUN(req->LUN, csio->ccb_h.target_lun) != 0) { 2055991554f2SKenneth D. Merry mpr_free_command(sc, cm); 2056a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_LUN_INVALID); 2057991554f2SKenneth D. Merry xpt_done(ccb); 2058991554f2SKenneth D. Merry return; 2059991554f2SKenneth D. Merry } 2060991554f2SKenneth D. Merry 2061991554f2SKenneth D. Merry if (csio->ccb_h.flags & CAM_CDB_POINTER) 2062991554f2SKenneth D. Merry bcopy(csio->cdb_io.cdb_ptr, &req->CDB.CDB32[0], csio->cdb_len); 2063fa699bb2SAlan Somers else { 2064fa699bb2SAlan Somers KASSERT(csio->cdb_len <= IOCDBLEN, 206567feec50SStephen McConnell ("cdb_len %d is greater than IOCDBLEN but CAM_CDB_POINTER " 206667feec50SStephen McConnell "is not set", csio->cdb_len)); 2067991554f2SKenneth D. Merry bcopy(csio->cdb_io.cdb_bytes, &req->CDB.CDB32[0],csio->cdb_len); 2068fa699bb2SAlan Somers } 2069991554f2SKenneth D. Merry req->IoFlags = htole16(csio->cdb_len); 2070991554f2SKenneth D. Merry 2071991554f2SKenneth D. Merry /* 2072991554f2SKenneth D. Merry * Check if EEDP is supported and enabled. If it is then check if the 2073991554f2SKenneth D. Merry * SCSI opcode could be using EEDP. If so, make sure the LUN exists and 2074991554f2SKenneth D. Merry * is formatted for EEDP support. If all of this is true, set CDB up 2075991554f2SKenneth D. Merry * for EEDP transfer. 2076991554f2SKenneth D. Merry */ 2077991554f2SKenneth D. Merry eedp_flags = op_code_prot[req->CDB.CDB32[0]]; 2078991554f2SKenneth D. Merry if (sc->eedp_enabled && eedp_flags) { 2079991554f2SKenneth D. Merry SLIST_FOREACH(lun, &targ->luns, lun_link) { 2080991554f2SKenneth D. Merry if (lun->lun_id == csio->ccb_h.target_lun) { 2081991554f2SKenneth D. Merry break; 2082991554f2SKenneth D. Merry } 2083991554f2SKenneth D. Merry } 2084991554f2SKenneth D. Merry 2085991554f2SKenneth D. Merry if ((lun != NULL) && (lun->eedp_formatted)) { 2086991554f2SKenneth D. Merry req->EEDPBlockSize = htole16(lun->eedp_block_size); 2087991554f2SKenneth D. Merry eedp_flags |= (MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | 2088991554f2SKenneth D. Merry MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | 2089991554f2SKenneth D. Merry MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD); 209067feec50SStephen McConnell if (sc->mpr_flags & MPR_FLAGS_GEN35_IOC) { 209167feec50SStephen McConnell eedp_flags |= 209267feec50SStephen McConnell MPI25_SCSIIO_EEDPFLAGS_APPTAG_DISABLE_MODE; 209367feec50SStephen McConnell } 2094991554f2SKenneth D. Merry req->EEDPFlags = htole16(eedp_flags); 2095991554f2SKenneth D. Merry 2096991554f2SKenneth D. Merry /* 2097991554f2SKenneth D. Merry * If CDB less than 32, fill in Primary Ref Tag with 2098991554f2SKenneth D. Merry * low 4 bytes of LBA. If CDB is 32, tag stuff is 2099991554f2SKenneth D. Merry * already there. Also, set protection bit. FreeBSD 2100991554f2SKenneth D. Merry * currently does not support CDBs bigger than 16, but 2101991554f2SKenneth D. Merry * the code doesn't hurt, and will be here for the 2102991554f2SKenneth D. Merry * future. 2103991554f2SKenneth D. Merry */ 2104991554f2SKenneth D. Merry if (csio->cdb_len != 32) { 2105991554f2SKenneth D. Merry lba_byte = (csio->cdb_len == 16) ? 6 : 2; 2106991554f2SKenneth D. Merry ref_tag_addr = (uint8_t *)&req->CDB.EEDP32. 2107991554f2SKenneth D. Merry PrimaryReferenceTag; 2108991554f2SKenneth D. Merry for (i = 0; i < 4; i++) { 2109991554f2SKenneth D. Merry *ref_tag_addr = 2110991554f2SKenneth D. Merry req->CDB.CDB32[lba_byte + i]; 2111991554f2SKenneth D. Merry ref_tag_addr++; 2112991554f2SKenneth D. Merry } 2113991554f2SKenneth D. Merry req->CDB.EEDP32.PrimaryReferenceTag = 2114991554f2SKenneth D. Merry htole32(req-> 2115991554f2SKenneth D. Merry CDB.EEDP32.PrimaryReferenceTag); 2116991554f2SKenneth D. Merry req->CDB.EEDP32.PrimaryApplicationTagMask = 2117991554f2SKenneth D. Merry 0xFFFF; 2118991554f2SKenneth D. Merry req->CDB.CDB32[1] = (req->CDB.CDB32[1] & 0x1F) | 2119991554f2SKenneth D. Merry 0x20; 2120991554f2SKenneth D. Merry } else { 2121991554f2SKenneth D. Merry eedp_flags |= 2122991554f2SKenneth D. Merry MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG; 2123991554f2SKenneth D. Merry req->EEDPFlags = htole16(eedp_flags); 2124991554f2SKenneth D. Merry req->CDB.CDB32[10] = (req->CDB.CDB32[10] & 2125991554f2SKenneth D. Merry 0x1F) | 0x20; 2126991554f2SKenneth D. Merry } 2127991554f2SKenneth D. Merry } 2128991554f2SKenneth D. Merry } 2129991554f2SKenneth D. Merry 2130991554f2SKenneth D. Merry cm->cm_length = csio->dxfer_len; 2131991554f2SKenneth D. Merry if (cm->cm_length != 0) { 2132991554f2SKenneth D. Merry cm->cm_data = ccb; 2133991554f2SKenneth D. Merry cm->cm_flags |= MPR_CM_FLAGS_USE_CCB; 2134991554f2SKenneth D. Merry } else { 2135991554f2SKenneth D. Merry cm->cm_data = NULL; 2136991554f2SKenneth D. Merry } 2137991554f2SKenneth D. Merry cm->cm_sge = &req->SGL; 2138991554f2SKenneth D. Merry cm->cm_sglsize = (32 - 24) * 4; 2139991554f2SKenneth D. Merry cm->cm_complete = mprsas_scsiio_complete; 2140991554f2SKenneth D. Merry cm->cm_complete_data = ccb; 2141991554f2SKenneth D. Merry cm->cm_targ = targ; 2142991554f2SKenneth D. Merry cm->cm_lun = csio->ccb_h.target_lun; 2143991554f2SKenneth D. Merry cm->cm_ccb = ccb; 2144991554f2SKenneth D. Merry /* 2145991554f2SKenneth D. Merry * If using FP desc type, need to set a bit in IoFlags (SCSI IO is 0) 2146991554f2SKenneth D. Merry * and set descriptor type. 2147991554f2SKenneth D. Merry */ 2148991554f2SKenneth D. Merry if (targ->scsi_req_desc_type == 2149991554f2SKenneth D. Merry MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO) { 2150991554f2SKenneth D. Merry req->IoFlags |= MPI25_SCSIIO_IOFLAGS_FAST_PATH; 2151991554f2SKenneth D. Merry cm->cm_desc.FastPathSCSIIO.RequestFlags = 2152991554f2SKenneth D. Merry MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; 215367feec50SStephen McConnell if (!sc->atomic_desc_capable) { 215467feec50SStephen McConnell cm->cm_desc.FastPathSCSIIO.DevHandle = 215567feec50SStephen McConnell htole16(targ->handle); 215667feec50SStephen McConnell } 2157991554f2SKenneth D. Merry } else { 2158991554f2SKenneth D. Merry cm->cm_desc.SCSIIO.RequestFlags = 2159991554f2SKenneth D. Merry MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; 216067feec50SStephen McConnell if (!sc->atomic_desc_capable) 2161991554f2SKenneth D. Merry cm->cm_desc.SCSIIO.DevHandle = htole16(targ->handle); 2162991554f2SKenneth D. Merry } 2163991554f2SKenneth D. Merry 2164407073a0SStephen McConnell #if __FreeBSD_version >= 1000029 216585c9dd9dSSteven Hartland callout_reset_sbt(&cm->cm_callout, SBT_1MS * ccb->ccb_h.timeout, 0, 216685c9dd9dSSteven Hartland mprsas_scsiio_timeout, cm, 0); 2167407073a0SStephen McConnell #else //__FreeBSD_version < 1000029 2168407073a0SStephen McConnell callout_reset(&cm->cm_callout, (ccb->ccb_h.timeout * hz) / 1000, 2169407073a0SStephen McConnell mprsas_scsiio_timeout, cm); 2170407073a0SStephen McConnell #endif //__FreeBSD_version >= 1000029 2171991554f2SKenneth D. Merry 2172991554f2SKenneth D. Merry targ->issued++; 2173991554f2SKenneth D. Merry targ->outstanding++; 2174991554f2SKenneth D. Merry TAILQ_INSERT_TAIL(&targ->commands, cm, cm_link); 2175991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_SIM_QUEUED; 2176991554f2SKenneth D. Merry 2177991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_XINFO, "%s cm %p ccb %p outstanding %u\n", 2178991554f2SKenneth D. Merry __func__, cm, ccb, targ->outstanding); 2179991554f2SKenneth D. Merry 2180991554f2SKenneth D. Merry mpr_map_command(sc, cm); 2181991554f2SKenneth D. Merry return; 2182991554f2SKenneth D. Merry } 2183991554f2SKenneth D. Merry 2184991554f2SKenneth D. Merry static void 2185991554f2SKenneth D. Merry mpr_response_code(struct mpr_softc *sc, u8 response_code) 2186991554f2SKenneth D. Merry { 2187991554f2SKenneth D. Merry char *desc; 2188991554f2SKenneth D. Merry 2189991554f2SKenneth D. Merry switch (response_code) { 2190991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE: 2191991554f2SKenneth D. Merry desc = "task management request completed"; 2192991554f2SKenneth D. Merry break; 2193991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME: 2194991554f2SKenneth D. Merry desc = "invalid frame"; 2195991554f2SKenneth D. Merry break; 2196991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED: 2197991554f2SKenneth D. Merry desc = "task management request not supported"; 2198991554f2SKenneth D. Merry break; 2199991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_TM_FAILED: 2200991554f2SKenneth D. Merry desc = "task management request failed"; 2201991554f2SKenneth D. Merry break; 2202991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED: 2203991554f2SKenneth D. Merry desc = "task management request succeeded"; 2204991554f2SKenneth D. Merry break; 2205991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN: 2206991554f2SKenneth D. Merry desc = "invalid lun"; 2207991554f2SKenneth D. Merry break; 2208991554f2SKenneth D. Merry case 0xA: 2209991554f2SKenneth D. Merry desc = "overlapped tag attempted"; 2210991554f2SKenneth D. Merry break; 2211991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC: 2212991554f2SKenneth D. Merry desc = "task queued, however not sent to target"; 2213991554f2SKenneth D. Merry break; 2214991554f2SKenneth D. Merry default: 2215991554f2SKenneth D. Merry desc = "unknown"; 2216991554f2SKenneth D. Merry break; 2217991554f2SKenneth D. Merry } 2218991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "response_code(0x%01x): %s\n", response_code, 2219991554f2SKenneth D. Merry desc); 2220991554f2SKenneth D. Merry } 2221991554f2SKenneth D. Merry 2222991554f2SKenneth D. Merry /** 2223991554f2SKenneth D. Merry * mpr_sc_failed_io_info - translated non-succesfull SCSI_IO request 2224991554f2SKenneth D. Merry */ 2225991554f2SKenneth D. Merry static void 2226991554f2SKenneth D. Merry mpr_sc_failed_io_info(struct mpr_softc *sc, struct ccb_scsiio *csio, 2227991554f2SKenneth D. Merry Mpi2SCSIIOReply_t *mpi_reply, struct mprsas_target *targ) 2228991554f2SKenneth D. Merry { 2229991554f2SKenneth D. Merry u32 response_info; 2230991554f2SKenneth D. Merry u8 *response_bytes; 2231991554f2SKenneth D. Merry u16 ioc_status = le16toh(mpi_reply->IOCStatus) & 2232991554f2SKenneth D. Merry MPI2_IOCSTATUS_MASK; 2233991554f2SKenneth D. Merry u8 scsi_state = mpi_reply->SCSIState; 2234991554f2SKenneth D. Merry u8 scsi_status = mpi_reply->SCSIStatus; 2235991554f2SKenneth D. Merry char *desc_ioc_state = NULL; 2236991554f2SKenneth D. Merry char *desc_scsi_status = NULL; 2237991554f2SKenneth D. Merry char *desc_scsi_state = sc->tmp_string; 2238991554f2SKenneth D. Merry u32 log_info = le32toh(mpi_reply->IOCLogInfo); 2239991554f2SKenneth D. Merry 2240991554f2SKenneth D. Merry if (log_info == 0x31170000) 2241991554f2SKenneth D. Merry return; 2242991554f2SKenneth D. Merry 2243991554f2SKenneth D. Merry switch (ioc_status) { 2244991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SUCCESS: 2245991554f2SKenneth D. Merry desc_ioc_state = "success"; 2246991554f2SKenneth D. Merry break; 2247991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_FUNCTION: 2248991554f2SKenneth D. Merry desc_ioc_state = "invalid function"; 2249991554f2SKenneth D. Merry break; 2250991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: 2251991554f2SKenneth D. Merry desc_ioc_state = "scsi recovered error"; 2252991554f2SKenneth D. Merry break; 2253991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: 2254991554f2SKenneth D. Merry desc_ioc_state = "scsi invalid dev handle"; 2255991554f2SKenneth D. Merry break; 2256991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: 2257991554f2SKenneth D. Merry desc_ioc_state = "scsi device not there"; 2258991554f2SKenneth D. Merry break; 2259991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: 2260991554f2SKenneth D. Merry desc_ioc_state = "scsi data overrun"; 2261991554f2SKenneth D. Merry break; 2262991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: 2263991554f2SKenneth D. Merry desc_ioc_state = "scsi data underrun"; 2264991554f2SKenneth D. Merry break; 2265991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: 2266991554f2SKenneth D. Merry desc_ioc_state = "scsi io data error"; 2267991554f2SKenneth D. Merry break; 2268991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: 2269991554f2SKenneth D. Merry desc_ioc_state = "scsi protocol error"; 2270991554f2SKenneth D. Merry break; 2271991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: 2272991554f2SKenneth D. Merry desc_ioc_state = "scsi task terminated"; 2273991554f2SKenneth D. Merry break; 2274991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: 2275991554f2SKenneth D. Merry desc_ioc_state = "scsi residual mismatch"; 2276991554f2SKenneth D. Merry break; 2277991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: 2278991554f2SKenneth D. Merry desc_ioc_state = "scsi task mgmt failed"; 2279991554f2SKenneth D. Merry break; 2280991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: 2281991554f2SKenneth D. Merry desc_ioc_state = "scsi ioc terminated"; 2282991554f2SKenneth D. Merry break; 2283991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: 2284991554f2SKenneth D. Merry desc_ioc_state = "scsi ext terminated"; 2285991554f2SKenneth D. Merry break; 2286991554f2SKenneth D. Merry case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: 2287991554f2SKenneth D. Merry desc_ioc_state = "eedp guard error"; 2288991554f2SKenneth D. Merry break; 2289991554f2SKenneth D. Merry case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: 2290991554f2SKenneth D. Merry desc_ioc_state = "eedp ref tag error"; 2291991554f2SKenneth D. Merry break; 2292991554f2SKenneth D. Merry case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: 2293991554f2SKenneth D. Merry desc_ioc_state = "eedp app tag error"; 2294991554f2SKenneth D. Merry break; 22952bbc5fcbSStephen McConnell case MPI2_IOCSTATUS_INSUFFICIENT_POWER: 22962bbc5fcbSStephen McConnell desc_ioc_state = "insufficient power"; 22972bbc5fcbSStephen McConnell break; 2298991554f2SKenneth D. Merry default: 2299991554f2SKenneth D. Merry desc_ioc_state = "unknown"; 2300991554f2SKenneth D. Merry break; 2301991554f2SKenneth D. Merry } 2302991554f2SKenneth D. Merry 2303991554f2SKenneth D. Merry switch (scsi_status) { 2304991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_GOOD: 2305991554f2SKenneth D. Merry desc_scsi_status = "good"; 2306991554f2SKenneth D. Merry break; 2307991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_CHECK_CONDITION: 2308991554f2SKenneth D. Merry desc_scsi_status = "check condition"; 2309991554f2SKenneth D. Merry break; 2310991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_CONDITION_MET: 2311991554f2SKenneth D. Merry desc_scsi_status = "condition met"; 2312991554f2SKenneth D. Merry break; 2313991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_BUSY: 2314991554f2SKenneth D. Merry desc_scsi_status = "busy"; 2315991554f2SKenneth D. Merry break; 2316991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_INTERMEDIATE: 2317991554f2SKenneth D. Merry desc_scsi_status = "intermediate"; 2318991554f2SKenneth D. Merry break; 2319991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET: 2320991554f2SKenneth D. Merry desc_scsi_status = "intermediate condmet"; 2321991554f2SKenneth D. Merry break; 2322991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_RESERVATION_CONFLICT: 2323991554f2SKenneth D. Merry desc_scsi_status = "reservation conflict"; 2324991554f2SKenneth D. Merry break; 2325991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_COMMAND_TERMINATED: 2326991554f2SKenneth D. Merry desc_scsi_status = "command terminated"; 2327991554f2SKenneth D. Merry break; 2328991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_TASK_SET_FULL: 2329991554f2SKenneth D. Merry desc_scsi_status = "task set full"; 2330991554f2SKenneth D. Merry break; 2331991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_ACA_ACTIVE: 2332991554f2SKenneth D. Merry desc_scsi_status = "aca active"; 2333991554f2SKenneth D. Merry break; 2334991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_TASK_ABORTED: 2335991554f2SKenneth D. Merry desc_scsi_status = "task aborted"; 2336991554f2SKenneth D. Merry break; 2337991554f2SKenneth D. Merry default: 2338991554f2SKenneth D. Merry desc_scsi_status = "unknown"; 2339991554f2SKenneth D. Merry break; 2340991554f2SKenneth D. Merry } 2341991554f2SKenneth D. Merry 2342991554f2SKenneth D. Merry desc_scsi_state[0] = '\0'; 2343991554f2SKenneth D. Merry if (!scsi_state) 2344991554f2SKenneth D. Merry desc_scsi_state = " "; 2345991554f2SKenneth D. Merry if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) 2346991554f2SKenneth D. Merry strcat(desc_scsi_state, "response info "); 2347991554f2SKenneth D. Merry if (scsi_state & MPI2_SCSI_STATE_TERMINATED) 2348991554f2SKenneth D. Merry strcat(desc_scsi_state, "state terminated "); 2349991554f2SKenneth D. Merry if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS) 2350991554f2SKenneth D. Merry strcat(desc_scsi_state, "no status "); 2351991554f2SKenneth D. Merry if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED) 2352991554f2SKenneth D. Merry strcat(desc_scsi_state, "autosense failed "); 2353991554f2SKenneth D. Merry if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) 2354991554f2SKenneth D. Merry strcat(desc_scsi_state, "autosense valid "); 2355991554f2SKenneth D. Merry 2356991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "\thandle(0x%04x), ioc_status(%s)(0x%04x)\n", 2357991554f2SKenneth D. Merry le16toh(mpi_reply->DevHandle), desc_ioc_state, ioc_status); 2358991554f2SKenneth D. Merry if (targ->encl_level_valid) { 2359991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, " 2360991554f2SKenneth D. Merry "connector name (%4s)\n", targ->encl_level, targ->encl_slot, 2361991554f2SKenneth D. Merry targ->connector_name); 2362991554f2SKenneth D. Merry } 2363991554f2SKenneth D. Merry /* We can add more detail about underflow data here 2364991554f2SKenneth D. Merry * TO-DO 2365991554f2SKenneth D. Merry * */ 2366991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "\tscsi_status(%s)(0x%02x), " 2367991554f2SKenneth D. Merry "scsi_state(%s)(0x%02x)\n", desc_scsi_status, scsi_status, 2368991554f2SKenneth D. Merry desc_scsi_state, scsi_state); 2369991554f2SKenneth D. Merry 2370991554f2SKenneth D. Merry if (sc->mpr_debug & MPR_XINFO && 2371991554f2SKenneth D. Merry scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) { 2372991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "-> Sense Buffer Data : Start :\n"); 2373991554f2SKenneth D. Merry scsi_sense_print(csio); 2374991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "-> Sense Buffer Data : End :\n"); 2375991554f2SKenneth D. Merry } 2376991554f2SKenneth D. Merry 2377991554f2SKenneth D. Merry if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) { 2378991554f2SKenneth D. Merry response_info = le32toh(mpi_reply->ResponseInfo); 2379991554f2SKenneth D. Merry response_bytes = (u8 *)&response_info; 2380991554f2SKenneth D. Merry mpr_response_code(sc,response_bytes[0]); 2381991554f2SKenneth D. Merry } 2382991554f2SKenneth D. Merry } 2383991554f2SKenneth D. Merry 238467feec50SStephen McConnell /** mprsas_nvme_trans_status_code 238567feec50SStephen McConnell * 238667feec50SStephen McConnell * Convert Native NVMe command error status to 238767feec50SStephen McConnell * equivalent SCSI error status. 238867feec50SStephen McConnell * 238967feec50SStephen McConnell * Returns appropriate scsi_status 239067feec50SStephen McConnell */ 239167feec50SStephen McConnell static u8 239267feec50SStephen McConnell mprsas_nvme_trans_status_code(struct nvme_status nvme_status, 239367feec50SStephen McConnell struct mpr_command *cm) 239467feec50SStephen McConnell { 239567feec50SStephen McConnell u8 status = MPI2_SCSI_STATUS_GOOD; 239667feec50SStephen McConnell int skey, asc, ascq; 239767feec50SStephen McConnell union ccb *ccb = cm->cm_complete_data; 239867feec50SStephen McConnell int returned_sense_len; 239967feec50SStephen McConnell 240067feec50SStephen McConnell status = MPI2_SCSI_STATUS_CHECK_CONDITION; 240167feec50SStephen McConnell skey = SSD_KEY_ILLEGAL_REQUEST; 240267feec50SStephen McConnell asc = SCSI_ASC_NO_SENSE; 240367feec50SStephen McConnell ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; 240467feec50SStephen McConnell 240567feec50SStephen McConnell switch (nvme_status.sct) { 240667feec50SStephen McConnell case NVME_SCT_GENERIC: 240767feec50SStephen McConnell switch (nvme_status.sc) { 240867feec50SStephen McConnell case NVME_SC_SUCCESS: 240967feec50SStephen McConnell status = MPI2_SCSI_STATUS_GOOD; 241067feec50SStephen McConnell skey = SSD_KEY_NO_SENSE; 241167feec50SStephen McConnell asc = SCSI_ASC_NO_SENSE; 241267feec50SStephen McConnell ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; 241367feec50SStephen McConnell break; 241467feec50SStephen McConnell case NVME_SC_INVALID_OPCODE: 241567feec50SStephen McConnell status = MPI2_SCSI_STATUS_CHECK_CONDITION; 241667feec50SStephen McConnell skey = SSD_KEY_ILLEGAL_REQUEST; 241767feec50SStephen McConnell asc = SCSI_ASC_ILLEGAL_COMMAND; 241867feec50SStephen McConnell ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; 241967feec50SStephen McConnell break; 242067feec50SStephen McConnell case NVME_SC_INVALID_FIELD: 242167feec50SStephen McConnell status = MPI2_SCSI_STATUS_CHECK_CONDITION; 242267feec50SStephen McConnell skey = SSD_KEY_ILLEGAL_REQUEST; 242367feec50SStephen McConnell asc = SCSI_ASC_INVALID_CDB; 242467feec50SStephen McConnell ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; 242567feec50SStephen McConnell break; 242667feec50SStephen McConnell case NVME_SC_DATA_TRANSFER_ERROR: 242767feec50SStephen McConnell status = MPI2_SCSI_STATUS_CHECK_CONDITION; 242867feec50SStephen McConnell skey = SSD_KEY_MEDIUM_ERROR; 242967feec50SStephen McConnell asc = SCSI_ASC_NO_SENSE; 243067feec50SStephen McConnell ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; 243167feec50SStephen McConnell break; 243267feec50SStephen McConnell case NVME_SC_ABORTED_POWER_LOSS: 243367feec50SStephen McConnell status = MPI2_SCSI_STATUS_TASK_ABORTED; 243467feec50SStephen McConnell skey = SSD_KEY_ABORTED_COMMAND; 243567feec50SStephen McConnell asc = SCSI_ASC_WARNING; 243667feec50SStephen McConnell ascq = SCSI_ASCQ_POWER_LOSS_EXPECTED; 243767feec50SStephen McConnell break; 243867feec50SStephen McConnell case NVME_SC_INTERNAL_DEVICE_ERROR: 243967feec50SStephen McConnell status = MPI2_SCSI_STATUS_CHECK_CONDITION; 244067feec50SStephen McConnell skey = SSD_KEY_HARDWARE_ERROR; 244167feec50SStephen McConnell asc = SCSI_ASC_INTERNAL_TARGET_FAILURE; 244267feec50SStephen McConnell ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; 244367feec50SStephen McConnell break; 244467feec50SStephen McConnell case NVME_SC_ABORTED_BY_REQUEST: 244567feec50SStephen McConnell case NVME_SC_ABORTED_SQ_DELETION: 244667feec50SStephen McConnell case NVME_SC_ABORTED_FAILED_FUSED: 244767feec50SStephen McConnell case NVME_SC_ABORTED_MISSING_FUSED: 244867feec50SStephen McConnell status = MPI2_SCSI_STATUS_TASK_ABORTED; 244967feec50SStephen McConnell skey = SSD_KEY_ABORTED_COMMAND; 245067feec50SStephen McConnell asc = SCSI_ASC_NO_SENSE; 245167feec50SStephen McConnell ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; 245267feec50SStephen McConnell break; 245367feec50SStephen McConnell case NVME_SC_INVALID_NAMESPACE_OR_FORMAT: 245467feec50SStephen McConnell status = MPI2_SCSI_STATUS_CHECK_CONDITION; 245567feec50SStephen McConnell skey = SSD_KEY_ILLEGAL_REQUEST; 245667feec50SStephen McConnell asc = SCSI_ASC_ACCESS_DENIED_INVALID_LUN_ID; 245767feec50SStephen McConnell ascq = SCSI_ASCQ_INVALID_LUN_ID; 245867feec50SStephen McConnell break; 245967feec50SStephen McConnell case NVME_SC_LBA_OUT_OF_RANGE: 246067feec50SStephen McConnell status = MPI2_SCSI_STATUS_CHECK_CONDITION; 246167feec50SStephen McConnell skey = SSD_KEY_ILLEGAL_REQUEST; 246267feec50SStephen McConnell asc = SCSI_ASC_ILLEGAL_BLOCK; 246367feec50SStephen McConnell ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; 246467feec50SStephen McConnell break; 246567feec50SStephen McConnell case NVME_SC_CAPACITY_EXCEEDED: 246667feec50SStephen McConnell status = MPI2_SCSI_STATUS_CHECK_CONDITION; 246767feec50SStephen McConnell skey = SSD_KEY_MEDIUM_ERROR; 246867feec50SStephen McConnell asc = SCSI_ASC_NO_SENSE; 246967feec50SStephen McConnell ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; 247067feec50SStephen McConnell break; 247167feec50SStephen McConnell case NVME_SC_NAMESPACE_NOT_READY: 247267feec50SStephen McConnell status = MPI2_SCSI_STATUS_CHECK_CONDITION; 247367feec50SStephen McConnell skey = SSD_KEY_NOT_READY; 247467feec50SStephen McConnell asc = SCSI_ASC_LUN_NOT_READY; 247567feec50SStephen McConnell ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; 247667feec50SStephen McConnell break; 247767feec50SStephen McConnell } 247867feec50SStephen McConnell break; 247967feec50SStephen McConnell case NVME_SCT_COMMAND_SPECIFIC: 248067feec50SStephen McConnell switch (nvme_status.sc) { 248167feec50SStephen McConnell case NVME_SC_INVALID_FORMAT: 248267feec50SStephen McConnell status = MPI2_SCSI_STATUS_CHECK_CONDITION; 248367feec50SStephen McConnell skey = SSD_KEY_ILLEGAL_REQUEST; 248467feec50SStephen McConnell asc = SCSI_ASC_FORMAT_COMMAND_FAILED; 248567feec50SStephen McConnell ascq = SCSI_ASCQ_FORMAT_COMMAND_FAILED; 248667feec50SStephen McConnell break; 248767feec50SStephen McConnell case NVME_SC_CONFLICTING_ATTRIBUTES: 248867feec50SStephen McConnell status = MPI2_SCSI_STATUS_CHECK_CONDITION; 248967feec50SStephen McConnell skey = SSD_KEY_ILLEGAL_REQUEST; 249067feec50SStephen McConnell asc = SCSI_ASC_INVALID_CDB; 249167feec50SStephen McConnell ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; 249267feec50SStephen McConnell break; 249367feec50SStephen McConnell } 249467feec50SStephen McConnell break; 249567feec50SStephen McConnell case NVME_SCT_MEDIA_ERROR: 249667feec50SStephen McConnell switch (nvme_status.sc) { 249767feec50SStephen McConnell case NVME_SC_WRITE_FAULTS: 249867feec50SStephen McConnell status = MPI2_SCSI_STATUS_CHECK_CONDITION; 249967feec50SStephen McConnell skey = SSD_KEY_MEDIUM_ERROR; 250067feec50SStephen McConnell asc = SCSI_ASC_PERIPHERAL_DEV_WRITE_FAULT; 250167feec50SStephen McConnell ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; 250267feec50SStephen McConnell break; 250367feec50SStephen McConnell case NVME_SC_UNRECOVERED_READ_ERROR: 250467feec50SStephen McConnell status = MPI2_SCSI_STATUS_CHECK_CONDITION; 250567feec50SStephen McConnell skey = SSD_KEY_MEDIUM_ERROR; 250667feec50SStephen McConnell asc = SCSI_ASC_UNRECOVERED_READ_ERROR; 250767feec50SStephen McConnell ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; 250867feec50SStephen McConnell break; 250967feec50SStephen McConnell case NVME_SC_GUARD_CHECK_ERROR: 251067feec50SStephen McConnell status = MPI2_SCSI_STATUS_CHECK_CONDITION; 251167feec50SStephen McConnell skey = SSD_KEY_MEDIUM_ERROR; 251267feec50SStephen McConnell asc = SCSI_ASC_LOG_BLOCK_GUARD_CHECK_FAILED; 251367feec50SStephen McConnell ascq = SCSI_ASCQ_LOG_BLOCK_GUARD_CHECK_FAILED; 251467feec50SStephen McConnell break; 251567feec50SStephen McConnell case NVME_SC_APPLICATION_TAG_CHECK_ERROR: 251667feec50SStephen McConnell status = MPI2_SCSI_STATUS_CHECK_CONDITION; 251767feec50SStephen McConnell skey = SSD_KEY_MEDIUM_ERROR; 251867feec50SStephen McConnell asc = SCSI_ASC_LOG_BLOCK_APPTAG_CHECK_FAILED; 251967feec50SStephen McConnell ascq = SCSI_ASCQ_LOG_BLOCK_APPTAG_CHECK_FAILED; 252067feec50SStephen McConnell break; 252167feec50SStephen McConnell case NVME_SC_REFERENCE_TAG_CHECK_ERROR: 252267feec50SStephen McConnell status = MPI2_SCSI_STATUS_CHECK_CONDITION; 252367feec50SStephen McConnell skey = SSD_KEY_MEDIUM_ERROR; 252467feec50SStephen McConnell asc = SCSI_ASC_LOG_BLOCK_REFTAG_CHECK_FAILED; 252567feec50SStephen McConnell ascq = SCSI_ASCQ_LOG_BLOCK_REFTAG_CHECK_FAILED; 252667feec50SStephen McConnell break; 252767feec50SStephen McConnell case NVME_SC_COMPARE_FAILURE: 252867feec50SStephen McConnell status = MPI2_SCSI_STATUS_CHECK_CONDITION; 252967feec50SStephen McConnell skey = SSD_KEY_MISCOMPARE; 253067feec50SStephen McConnell asc = SCSI_ASC_MISCOMPARE_DURING_VERIFY; 253167feec50SStephen McConnell ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; 253267feec50SStephen McConnell break; 253367feec50SStephen McConnell case NVME_SC_ACCESS_DENIED: 253467feec50SStephen McConnell status = MPI2_SCSI_STATUS_CHECK_CONDITION; 253567feec50SStephen McConnell skey = SSD_KEY_ILLEGAL_REQUEST; 253667feec50SStephen McConnell asc = SCSI_ASC_ACCESS_DENIED_INVALID_LUN_ID; 253767feec50SStephen McConnell ascq = SCSI_ASCQ_INVALID_LUN_ID; 253867feec50SStephen McConnell break; 253967feec50SStephen McConnell } 254067feec50SStephen McConnell break; 254167feec50SStephen McConnell } 254267feec50SStephen McConnell 254367feec50SStephen McConnell returned_sense_len = sizeof(struct scsi_sense_data); 254467feec50SStephen McConnell if (returned_sense_len < ccb->csio.sense_len) 254567feec50SStephen McConnell ccb->csio.sense_resid = ccb->csio.sense_len - 254667feec50SStephen McConnell returned_sense_len; 254767feec50SStephen McConnell else 254867feec50SStephen McConnell ccb->csio.sense_resid = 0; 254967feec50SStephen McConnell 255067feec50SStephen McConnell scsi_set_sense_data(&ccb->csio.sense_data, SSD_TYPE_FIXED, 255167feec50SStephen McConnell 1, skey, asc, ascq, SSD_ELEM_NONE); 255267feec50SStephen McConnell ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 255367feec50SStephen McConnell 255467feec50SStephen McConnell return status; 255567feec50SStephen McConnell } 255667feec50SStephen McConnell 255767feec50SStephen McConnell /** mprsas_complete_nvme_unmap 255867feec50SStephen McConnell * 255967feec50SStephen McConnell * Complete native NVMe command issued using NVMe Encapsulated 256067feec50SStephen McConnell * Request Message. 256167feec50SStephen McConnell */ 256267feec50SStephen McConnell static u8 256367feec50SStephen McConnell mprsas_complete_nvme_unmap(struct mpr_softc *sc, struct mpr_command *cm) 256467feec50SStephen McConnell { 256567feec50SStephen McConnell Mpi26NVMeEncapsulatedErrorReply_t *mpi_reply; 256667feec50SStephen McConnell struct nvme_completion *nvme_completion = NULL; 256767feec50SStephen McConnell u8 scsi_status = MPI2_SCSI_STATUS_GOOD; 256867feec50SStephen McConnell 256967feec50SStephen McConnell mpi_reply =(Mpi26NVMeEncapsulatedErrorReply_t *)cm->cm_reply; 257067feec50SStephen McConnell if (le16toh(mpi_reply->ErrorResponseCount)){ 257167feec50SStephen McConnell nvme_completion = (struct nvme_completion *)cm->cm_sense; 257267feec50SStephen McConnell scsi_status = mprsas_nvme_trans_status_code( 257367feec50SStephen McConnell nvme_completion->status, cm); 257467feec50SStephen McConnell } 257567feec50SStephen McConnell return scsi_status; 257667feec50SStephen McConnell } 257767feec50SStephen McConnell 2578991554f2SKenneth D. Merry static void 2579991554f2SKenneth D. Merry mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) 2580991554f2SKenneth D. Merry { 2581991554f2SKenneth D. Merry MPI2_SCSI_IO_REPLY *rep; 2582991554f2SKenneth D. Merry union ccb *ccb; 2583991554f2SKenneth D. Merry struct ccb_scsiio *csio; 2584991554f2SKenneth D. Merry struct mprsas_softc *sassc; 2585991554f2SKenneth D. Merry struct scsi_vpd_supported_page_list *vpd_list = NULL; 258667feec50SStephen McConnell u8 *TLR_bits, TLR_on, *scsi_cdb; 2587991554f2SKenneth D. Merry int dir = 0, i; 2588991554f2SKenneth D. Merry u16 alloc_len; 2589a2c14879SStephen McConnell struct mprsas_target *target; 2590a2c14879SStephen McConnell target_id_t target_id; 2591991554f2SKenneth D. Merry 2592991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 2593991554f2SKenneth D. Merry mpr_dprint(sc, MPR_TRACE, 2594991554f2SKenneth D. Merry "cm %p SMID %u ccb %p reply %p outstanding %u\n", cm, 2595991554f2SKenneth D. Merry cm->cm_desc.Default.SMID, cm->cm_ccb, cm->cm_reply, 2596991554f2SKenneth D. Merry cm->cm_targ->outstanding); 2597991554f2SKenneth D. Merry 2598991554f2SKenneth D. Merry callout_stop(&cm->cm_callout); 2599991554f2SKenneth D. Merry mtx_assert(&sc->mpr_mtx, MA_OWNED); 2600991554f2SKenneth D. Merry 2601991554f2SKenneth D. Merry sassc = sc->sassc; 2602991554f2SKenneth D. Merry ccb = cm->cm_complete_data; 2603991554f2SKenneth D. Merry csio = &ccb->csio; 2604a2c14879SStephen McConnell target_id = csio->ccb_h.target_id; 2605991554f2SKenneth D. Merry rep = (MPI2_SCSI_IO_REPLY *)cm->cm_reply; 2606991554f2SKenneth D. Merry /* 2607991554f2SKenneth D. Merry * XXX KDM if the chain allocation fails, does it matter if we do 2608991554f2SKenneth D. Merry * the sync and unload here? It is simpler to do it in every case, 2609991554f2SKenneth D. Merry * assuming it doesn't cause problems. 2610991554f2SKenneth D. Merry */ 2611991554f2SKenneth D. Merry if (cm->cm_data != NULL) { 2612991554f2SKenneth D. Merry if (cm->cm_flags & MPR_CM_FLAGS_DATAIN) 2613991554f2SKenneth D. Merry dir = BUS_DMASYNC_POSTREAD; 2614991554f2SKenneth D. Merry else if (cm->cm_flags & MPR_CM_FLAGS_DATAOUT) 2615991554f2SKenneth D. Merry dir = BUS_DMASYNC_POSTWRITE; 2616991554f2SKenneth D. Merry bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir); 2617991554f2SKenneth D. Merry bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); 2618991554f2SKenneth D. Merry } 2619991554f2SKenneth D. Merry 2620991554f2SKenneth D. Merry cm->cm_targ->completed++; 2621991554f2SKenneth D. Merry cm->cm_targ->outstanding--; 2622991554f2SKenneth D. Merry TAILQ_REMOVE(&cm->cm_targ->commands, cm, cm_link); 2623991554f2SKenneth D. Merry ccb->ccb_h.status &= ~(CAM_STATUS_MASK | CAM_SIM_QUEUED); 2624991554f2SKenneth D. Merry 2625991554f2SKenneth D. Merry if (cm->cm_state == MPR_CM_STATE_TIMEDOUT) { 2626991554f2SKenneth D. Merry TAILQ_REMOVE(&cm->cm_targ->timedout_commands, cm, cm_recovery); 2627991554f2SKenneth D. Merry if (cm->cm_reply != NULL) 2628991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 2629991554f2SKenneth D. Merry "completed timedout cm %p ccb %p during recovery " 2630991554f2SKenneth D. Merry "ioc %x scsi %x state %x xfer %u\n", cm, cm->cm_ccb, 2631991554f2SKenneth D. Merry le16toh(rep->IOCStatus), rep->SCSIStatus, 2632991554f2SKenneth D. Merry rep->SCSIState, le32toh(rep->TransferCount)); 2633991554f2SKenneth D. Merry else 2634991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 2635991554f2SKenneth D. Merry "completed timedout cm %p ccb %p during recovery\n", 2636991554f2SKenneth D. Merry cm, cm->cm_ccb); 2637991554f2SKenneth D. Merry } else if (cm->cm_targ->tm != NULL) { 2638991554f2SKenneth D. Merry if (cm->cm_reply != NULL) 2639991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 2640991554f2SKenneth D. Merry "completed cm %p ccb %p during recovery " 2641991554f2SKenneth D. Merry "ioc %x scsi %x state %x xfer %u\n", 2642991554f2SKenneth D. Merry cm, cm->cm_ccb, le16toh(rep->IOCStatus), 2643991554f2SKenneth D. Merry rep->SCSIStatus, rep->SCSIState, 2644991554f2SKenneth D. Merry le32toh(rep->TransferCount)); 2645991554f2SKenneth D. Merry else 2646991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 2647991554f2SKenneth D. Merry "completed cm %p ccb %p during recovery\n", 2648991554f2SKenneth D. Merry cm, cm->cm_ccb); 2649991554f2SKenneth D. Merry } else if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) { 2650991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 2651991554f2SKenneth D. Merry "reset completed cm %p ccb %p\n", cm, cm->cm_ccb); 2652991554f2SKenneth D. Merry } 2653991554f2SKenneth D. Merry 2654991554f2SKenneth D. Merry if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 2655991554f2SKenneth D. Merry /* 2656991554f2SKenneth D. Merry * We ran into an error after we tried to map the command, 2657991554f2SKenneth D. Merry * so we're getting a callback without queueing the command 2658991554f2SKenneth D. Merry * to the hardware. So we set the status here, and it will 2659991554f2SKenneth D. Merry * be retained below. We'll go through the "fast path", 2660991554f2SKenneth D. Merry * because there can be no reply when we haven't actually 2661991554f2SKenneth D. Merry * gone out to the hardware. 2662991554f2SKenneth D. Merry */ 2663a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQUEUE_REQ); 2664991554f2SKenneth D. Merry 2665991554f2SKenneth D. Merry /* 2666991554f2SKenneth D. Merry * Currently the only error included in the mask is 2667991554f2SKenneth D. Merry * MPR_CM_FLAGS_CHAIN_FAILED, which means we're out of 2668991554f2SKenneth D. Merry * chain frames. We need to freeze the queue until we get 2669991554f2SKenneth D. Merry * a command that completed without this error, which will 2670991554f2SKenneth D. Merry * hopefully have some chain frames attached that we can 2671991554f2SKenneth D. Merry * use. If we wanted to get smarter about it, we would 2672991554f2SKenneth D. Merry * only unfreeze the queue in this condition when we're 2673991554f2SKenneth D. Merry * sure that we're getting some chain frames back. That's 2674991554f2SKenneth D. Merry * probably unnecessary. 2675991554f2SKenneth D. Merry */ 2676991554f2SKenneth D. Merry if ((sassc->flags & MPRSAS_QUEUE_FROZEN) == 0) { 2677991554f2SKenneth D. Merry xpt_freeze_simq(sassc->sim, 1); 2678991554f2SKenneth D. Merry sassc->flags |= MPRSAS_QUEUE_FROZEN; 26796c85e33eSScott Long mpr_dprint(sc, MPR_XINFO, "Error sending command, " 2680991554f2SKenneth D. Merry "freezing SIM queue\n"); 2681991554f2SKenneth D. Merry } 2682991554f2SKenneth D. Merry } 2683991554f2SKenneth D. Merry 2684991554f2SKenneth D. Merry /* 268567feec50SStephen McConnell * Point to the SCSI CDB, which is dependent on the CAM_CDB_POINTER 268667feec50SStephen McConnell * flag, and use it in a few places in the rest of this function for 268767feec50SStephen McConnell * convenience. Use the macro if available. 268867feec50SStephen McConnell */ 268967feec50SStephen McConnell #if __FreeBSD_version >= 1100103 269067feec50SStephen McConnell scsi_cdb = scsiio_cdb_ptr(csio); 269167feec50SStephen McConnell #else 269267feec50SStephen McConnell if (csio->ccb_h.flags & CAM_CDB_POINTER) 269367feec50SStephen McConnell scsi_cdb = csio->cdb_io.cdb_ptr; 269467feec50SStephen McConnell else 269567feec50SStephen McConnell scsi_cdb = csio->cdb_io.cdb_bytes; 269667feec50SStephen McConnell #endif 269767feec50SStephen McConnell 269867feec50SStephen McConnell /* 2699991554f2SKenneth D. Merry * If this is a Start Stop Unit command and it was issued by the driver 2700991554f2SKenneth D. Merry * during shutdown, decrement the refcount to account for all of the 2701991554f2SKenneth D. Merry * commands that were sent. All SSU commands should be completed before 2702991554f2SKenneth D. Merry * shutdown completes, meaning SSU_refcount will be 0 after SSU_started 2703991554f2SKenneth D. Merry * is TRUE. 2704991554f2SKenneth D. Merry */ 270567feec50SStephen McConnell if (sc->SSU_started && (scsi_cdb[0] == START_STOP_UNIT)) { 2706991554f2SKenneth D. Merry mpr_dprint(sc, MPR_INFO, "Decrementing SSU count.\n"); 2707991554f2SKenneth D. Merry sc->SSU_refcount--; 2708991554f2SKenneth D. Merry } 2709991554f2SKenneth D. Merry 2710991554f2SKenneth D. Merry /* Take the fast path to completion */ 2711991554f2SKenneth D. Merry if (cm->cm_reply == NULL) { 2712a2c14879SStephen McConnell if (mprsas_get_ccbstatus(ccb) == CAM_REQ_INPROG) { 2713991554f2SKenneth D. Merry if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) 2714a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_SCSI_BUS_RESET); 2715991554f2SKenneth D. Merry else { 2716a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); 2717a2c14879SStephen McConnell csio->scsi_status = SCSI_STATUS_OK; 2718991554f2SKenneth D. Merry } 2719991554f2SKenneth D. Merry if (sassc->flags & MPRSAS_QUEUE_FROZEN) { 2720991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 2721991554f2SKenneth D. Merry sassc->flags &= ~MPRSAS_QUEUE_FROZEN; 2722991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, 2723991554f2SKenneth D. Merry "Unfreezing SIM queue\n"); 2724991554f2SKenneth D. Merry } 2725991554f2SKenneth D. Merry } 2726991554f2SKenneth D. Merry 2727991554f2SKenneth D. Merry /* 2728991554f2SKenneth D. Merry * There are two scenarios where the status won't be 2729991554f2SKenneth D. Merry * CAM_REQ_CMP. The first is if MPR_CM_FLAGS_ERROR_MASK is 2730991554f2SKenneth D. Merry * set, the second is in the MPR_FLAGS_DIAGRESET above. 2731991554f2SKenneth D. Merry */ 2732a2c14879SStephen McConnell if (mprsas_get_ccbstatus(ccb) != CAM_REQ_CMP) { 2733991554f2SKenneth D. Merry /* 2734991554f2SKenneth D. Merry * Freeze the dev queue so that commands are 2735a2c14879SStephen McConnell * executed in the correct order after error 2736991554f2SKenneth D. Merry * recovery. 2737991554f2SKenneth D. Merry */ 2738991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_DEV_QFRZN; 2739991554f2SKenneth D. Merry xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1); 2740991554f2SKenneth D. Merry } 2741991554f2SKenneth D. Merry mpr_free_command(sc, cm); 2742991554f2SKenneth D. Merry xpt_done(ccb); 2743991554f2SKenneth D. Merry return; 2744991554f2SKenneth D. Merry } 2745991554f2SKenneth D. Merry 274667feec50SStephen McConnell target = &sassc->targets[target_id]; 274767feec50SStephen McConnell if (scsi_cdb[0] == UNMAP && 274867feec50SStephen McConnell target->is_nvme && 274967feec50SStephen McConnell (csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) { 275067feec50SStephen McConnell rep->SCSIStatus = mprsas_complete_nvme_unmap(sc, cm); 275167feec50SStephen McConnell csio->scsi_status = rep->SCSIStatus; 275267feec50SStephen McConnell } 275367feec50SStephen McConnell 2754991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_XINFO, 2755991554f2SKenneth D. Merry "ioc %x scsi %x state %x xfer %u\n", 2756991554f2SKenneth D. Merry le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState, 2757991554f2SKenneth D. Merry le32toh(rep->TransferCount)); 2758991554f2SKenneth D. Merry 2759991554f2SKenneth D. Merry switch (le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) { 2760991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: 2761991554f2SKenneth D. Merry csio->resid = cm->cm_length - le32toh(rep->TransferCount); 2762991554f2SKenneth D. Merry /* FALLTHROUGH */ 2763991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SUCCESS: 2764991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: 2765991554f2SKenneth D. Merry if ((le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) == 2766991554f2SKenneth D. Merry MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR) 2767991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_XINFO, "recovered error\n"); 2768991554f2SKenneth D. Merry 2769991554f2SKenneth D. Merry /* Completion failed at the transport level. */ 2770991554f2SKenneth D. Merry if (rep->SCSIState & (MPI2_SCSI_STATE_NO_SCSI_STATUS | 2771991554f2SKenneth D. Merry MPI2_SCSI_STATE_TERMINATED)) { 2772a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); 2773991554f2SKenneth D. Merry break; 2774991554f2SKenneth D. Merry } 2775991554f2SKenneth D. Merry 2776991554f2SKenneth D. Merry /* In a modern packetized environment, an autosense failure 2777991554f2SKenneth D. Merry * implies that there's not much else that can be done to 2778991554f2SKenneth D. Merry * recover the command. 2779991554f2SKenneth D. Merry */ 2780991554f2SKenneth D. Merry if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_FAILED) { 2781a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_AUTOSENSE_FAIL); 2782991554f2SKenneth D. Merry break; 2783991554f2SKenneth D. Merry } 2784991554f2SKenneth D. Merry 2785991554f2SKenneth D. Merry /* 2786991554f2SKenneth D. Merry * CAM doesn't care about SAS Response Info data, but if this is 2787991554f2SKenneth D. Merry * the state check if TLR should be done. If not, clear the 2788991554f2SKenneth D. Merry * TLR_bits for the target. 2789991554f2SKenneth D. Merry */ 2790991554f2SKenneth D. Merry if ((rep->SCSIState & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) && 2791991554f2SKenneth D. Merry ((le32toh(rep->ResponseInfo) & MPI2_SCSI_RI_MASK_REASONCODE) 2792991554f2SKenneth D. Merry == MPR_SCSI_RI_INVALID_FRAME)) { 2793a2c14879SStephen McConnell sc->mapping_table[target_id].TLR_bits = 2794991554f2SKenneth D. Merry (u8)MPI2_SCSIIO_CONTROL_NO_TLR; 2795991554f2SKenneth D. Merry } 2796991554f2SKenneth D. Merry 2797991554f2SKenneth D. Merry /* 2798991554f2SKenneth D. Merry * Intentionally override the normal SCSI status reporting 2799991554f2SKenneth D. Merry * for these two cases. These are likely to happen in a 2800991554f2SKenneth D. Merry * multi-initiator environment, and we want to make sure that 2801991554f2SKenneth D. Merry * CAM retries these commands rather than fail them. 2802991554f2SKenneth D. Merry */ 2803991554f2SKenneth D. Merry if ((rep->SCSIStatus == MPI2_SCSI_STATUS_COMMAND_TERMINATED) || 2804991554f2SKenneth D. Merry (rep->SCSIStatus == MPI2_SCSI_STATUS_TASK_ABORTED)) { 2805a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_ABORTED); 2806991554f2SKenneth D. Merry break; 2807991554f2SKenneth D. Merry } 2808991554f2SKenneth D. Merry 2809991554f2SKenneth D. Merry /* Handle normal status and sense */ 2810991554f2SKenneth D. Merry csio->scsi_status = rep->SCSIStatus; 2811991554f2SKenneth D. Merry if (rep->SCSIStatus == MPI2_SCSI_STATUS_GOOD) 2812a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); 2813991554f2SKenneth D. Merry else 2814a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_SCSI_STATUS_ERROR); 2815991554f2SKenneth D. Merry 2816991554f2SKenneth D. Merry if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) { 2817991554f2SKenneth D. Merry int sense_len, returned_sense_len; 2818991554f2SKenneth D. Merry 2819991554f2SKenneth D. Merry returned_sense_len = min(le32toh(rep->SenseCount), 2820991554f2SKenneth D. Merry sizeof(struct scsi_sense_data)); 2821991554f2SKenneth D. Merry if (returned_sense_len < csio->sense_len) 2822991554f2SKenneth D. Merry csio->sense_resid = csio->sense_len - 2823991554f2SKenneth D. Merry returned_sense_len; 2824991554f2SKenneth D. Merry else 2825991554f2SKenneth D. Merry csio->sense_resid = 0; 2826991554f2SKenneth D. Merry 2827991554f2SKenneth D. Merry sense_len = min(returned_sense_len, 2828991554f2SKenneth D. Merry csio->sense_len - csio->sense_resid); 2829991554f2SKenneth D. Merry bzero(&csio->sense_data, sizeof(csio->sense_data)); 2830991554f2SKenneth D. Merry bcopy(cm->cm_sense, &csio->sense_data, sense_len); 2831991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 2832991554f2SKenneth D. Merry } 2833991554f2SKenneth D. Merry 2834991554f2SKenneth D. Merry /* 2835991554f2SKenneth D. Merry * Check if this is an INQUIRY command. If it's a VPD inquiry, 2836991554f2SKenneth D. Merry * and it's page code 0 (Supported Page List), and there is 2837991554f2SKenneth D. Merry * inquiry data, and this is for a sequential access device, and 2838991554f2SKenneth D. Merry * the device is an SSP target, and TLR is supported by the 2839991554f2SKenneth D. Merry * controller, turn the TLR_bits value ON if page 0x90 is 2840991554f2SKenneth D. Merry * supported. 2841991554f2SKenneth D. Merry */ 284267feec50SStephen McConnell if ((scsi_cdb[0] == INQUIRY) && 284367feec50SStephen McConnell (scsi_cdb[1] & SI_EVPD) && 284467feec50SStephen McConnell (scsi_cdb[2] == SVPD_SUPPORTED_PAGE_LIST) && 2845991554f2SKenneth D. Merry ((csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) && 2846d2b4e18bSKenneth D. Merry (csio->data_ptr != NULL) && 2847d2b4e18bSKenneth D. Merry ((csio->data_ptr[0] & 0x1f) == T_SEQUENTIAL) && 2848d2b4e18bSKenneth D. Merry (sc->control_TLR) && 2849a2c14879SStephen McConnell (sc->mapping_table[target_id].device_info & 2850991554f2SKenneth D. Merry MPI2_SAS_DEVICE_INFO_SSP_TARGET)) { 2851991554f2SKenneth D. Merry vpd_list = (struct scsi_vpd_supported_page_list *) 2852991554f2SKenneth D. Merry csio->data_ptr; 2853a2c14879SStephen McConnell TLR_bits = &sc->mapping_table[target_id].TLR_bits; 2854991554f2SKenneth D. Merry *TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR; 2855991554f2SKenneth D. Merry TLR_on = (u8)MPI2_SCSIIO_CONTROL_TLR_ON; 285667feec50SStephen McConnell alloc_len = ((u16)scsi_cdb[3] << 8) + scsi_cdb[4]; 2857d2b4e18bSKenneth D. Merry alloc_len -= csio->resid; 2858991554f2SKenneth D. Merry for (i = 0; i < MIN(vpd_list->length, alloc_len); i++) { 2859991554f2SKenneth D. Merry if (vpd_list->list[i] == 0x90) { 2860991554f2SKenneth D. Merry *TLR_bits = TLR_on; 2861991554f2SKenneth D. Merry break; 2862991554f2SKenneth D. Merry } 2863991554f2SKenneth D. Merry } 2864991554f2SKenneth D. Merry } 2865a2c14879SStephen McConnell 2866a2c14879SStephen McConnell /* 2867a2c14879SStephen McConnell * If this is a SATA direct-access end device, mark it so that 2868a2c14879SStephen McConnell * a SCSI StartStopUnit command will be sent to it when the 2869a2c14879SStephen McConnell * driver is being shutdown. 2870a2c14879SStephen McConnell */ 287167feec50SStephen McConnell if ((scsi_cdb[0] == INQUIRY) && 2872fa699bb2SAlan Somers (csio->data_ptr != NULL) && 2873a2c14879SStephen McConnell ((csio->data_ptr[0] & 0x1f) == T_DIRECT) && 2874a2c14879SStephen McConnell (sc->mapping_table[target_id].device_info & 2875a2c14879SStephen McConnell MPI2_SAS_DEVICE_INFO_SATA_DEVICE) && 2876a2c14879SStephen McConnell ((sc->mapping_table[target_id].device_info & 2877a2c14879SStephen McConnell MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) == 2878a2c14879SStephen McConnell MPI2_SAS_DEVICE_INFO_END_DEVICE)) { 2879a2c14879SStephen McConnell target = &sassc->targets[target_id]; 2880a2c14879SStephen McConnell target->supports_SSU = TRUE; 2881a2c14879SStephen McConnell mpr_dprint(sc, MPR_XINFO, "Target %d supports SSU\n", 2882a2c14879SStephen McConnell target_id); 2883a2c14879SStephen McConnell } 2884991554f2SKenneth D. Merry break; 2885991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: 2886991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: 2887991554f2SKenneth D. Merry /* 2888991554f2SKenneth D. Merry * If devinfo is 0 this will be a volume. In that case don't 2889991554f2SKenneth D. Merry * tell CAM that the volume is not there. We want volumes to 2890991554f2SKenneth D. Merry * be enumerated until they are deleted/removed, not just 2891991554f2SKenneth D. Merry * failed. 2892991554f2SKenneth D. Merry */ 2893991554f2SKenneth D. Merry if (cm->cm_targ->devinfo == 0) 2894a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); 2895991554f2SKenneth D. Merry else 2896a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); 2897991554f2SKenneth D. Merry break; 2898991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_SGL: 2899991554f2SKenneth D. Merry mpr_print_scsiio_cmd(sc, cm); 2900a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_UNREC_HBA_ERROR); 2901991554f2SKenneth D. Merry break; 2902991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: 2903991554f2SKenneth D. Merry /* 2904991554f2SKenneth D. Merry * This is one of the responses that comes back when an I/O 2905991554f2SKenneth D. Merry * has been aborted. If it is because of a timeout that we 2906991554f2SKenneth D. Merry * initiated, just set the status to CAM_CMD_TIMEOUT. 2907991554f2SKenneth D. Merry * Otherwise set it to CAM_REQ_ABORTED. The effect on the 2908991554f2SKenneth D. Merry * command is the same (it gets retried, subject to the 2909991554f2SKenneth D. Merry * retry counter), the only difference is what gets printed 2910991554f2SKenneth D. Merry * on the console. 2911991554f2SKenneth D. Merry */ 2912991554f2SKenneth D. Merry if (cm->cm_state == MPR_CM_STATE_TIMEDOUT) 2913a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_CMD_TIMEOUT); 2914991554f2SKenneth D. Merry else 2915a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_ABORTED); 2916991554f2SKenneth D. Merry break; 2917991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: 2918991554f2SKenneth D. Merry /* resid is ignored for this condition */ 2919991554f2SKenneth D. Merry csio->resid = 0; 2920a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_DATA_RUN_ERR); 2921991554f2SKenneth D. Merry break; 2922991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: 2923991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: 2924991554f2SKenneth D. Merry /* 29256adfa7edSAlan Somers * These can sometimes be transient transport-related 29266adfa7edSAlan Somers * errors, and sometimes persistent drive-related errors. 29276adfa7edSAlan Somers * We used to retry these without decrementing the retry 29286adfa7edSAlan Somers * count by returning CAM_REQUEUE_REQ. Unfortunately, if 29296adfa7edSAlan Somers * we hit a persistent drive problem that returns one of 29306adfa7edSAlan Somers * these error codes, we would retry indefinitely. So, 29316adfa7edSAlan Somers * return CAM_REQ_CMP_ERROR so that we decrement the retry 29326adfa7edSAlan Somers * count and avoid infinite retries. We're taking the 29336adfa7edSAlan Somers * potential risk of flagging false failures in the event 29346adfa7edSAlan Somers * of a topology-related error (e.g. a SAS expander problem 29356adfa7edSAlan Somers * causes a command addressed to a drive to fail), but 29366adfa7edSAlan Somers * avoiding getting into an infinite retry loop. 2937991554f2SKenneth D. Merry */ 29386adfa7edSAlan Somers mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); 2939991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_INFO, 2940694cb8b8SScott Long "terminated ioc %x loginfo %x scsi %x state %x xfer %u\n", 2941694cb8b8SScott Long le16toh(rep->IOCStatus), le32toh(rep->IOCLogInfo), 2942694cb8b8SScott Long rep->SCSIStatus, rep->SCSIState, 2943991554f2SKenneth D. Merry le32toh(rep->TransferCount)); 2944991554f2SKenneth D. Merry break; 2945991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_FUNCTION: 2946991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INTERNAL_ERROR: 2947991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_VPID: 2948991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_FIELD: 2949991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_STATE: 2950991554f2SKenneth D. Merry case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED: 2951991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: 2952991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: 2953991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: 2954991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: 2955991554f2SKenneth D. Merry default: 2956991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_XINFO, 2957694cb8b8SScott Long "completed ioc %x loginfo %x scsi %x state %x xfer %u\n", 2958694cb8b8SScott Long le16toh(rep->IOCStatus), le32toh(rep->IOCLogInfo), 2959694cb8b8SScott Long rep->SCSIStatus, rep->SCSIState, 2960991554f2SKenneth D. Merry le32toh(rep->TransferCount)); 2961991554f2SKenneth D. Merry csio->resid = cm->cm_length; 296267feec50SStephen McConnell 296367feec50SStephen McConnell if (scsi_cdb[0] == UNMAP && 296467feec50SStephen McConnell target->is_nvme && 296567feec50SStephen McConnell (csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) 296667feec50SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); 296767feec50SStephen McConnell else 2968a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); 296967feec50SStephen McConnell 2970991554f2SKenneth D. Merry break; 2971991554f2SKenneth D. Merry } 2972991554f2SKenneth D. Merry 2973991554f2SKenneth D. Merry mpr_sc_failed_io_info(sc, csio, rep, cm->cm_targ); 2974991554f2SKenneth D. Merry 2975991554f2SKenneth D. Merry if (sassc->flags & MPRSAS_QUEUE_FROZEN) { 2976991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 2977991554f2SKenneth D. Merry sassc->flags &= ~MPRSAS_QUEUE_FROZEN; 2978991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "Command completed, unfreezing SIM " 2979991554f2SKenneth D. Merry "queue\n"); 2980991554f2SKenneth D. Merry } 2981991554f2SKenneth D. Merry 2982a2c14879SStephen McConnell if (mprsas_get_ccbstatus(ccb) != CAM_REQ_CMP) { 2983991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_DEV_QFRZN; 2984991554f2SKenneth D. Merry xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1); 2985991554f2SKenneth D. Merry } 2986991554f2SKenneth D. Merry 2987991554f2SKenneth D. Merry mpr_free_command(sc, cm); 2988991554f2SKenneth D. Merry xpt_done(ccb); 2989991554f2SKenneth D. Merry } 2990991554f2SKenneth D. Merry 2991991554f2SKenneth D. Merry #if __FreeBSD_version >= 900026 2992991554f2SKenneth D. Merry static void 2993991554f2SKenneth D. Merry mprsas_smpio_complete(struct mpr_softc *sc, struct mpr_command *cm) 2994991554f2SKenneth D. Merry { 2995991554f2SKenneth D. Merry MPI2_SMP_PASSTHROUGH_REPLY *rpl; 2996991554f2SKenneth D. Merry MPI2_SMP_PASSTHROUGH_REQUEST *req; 2997991554f2SKenneth D. Merry uint64_t sasaddr; 2998991554f2SKenneth D. Merry union ccb *ccb; 2999991554f2SKenneth D. Merry 3000991554f2SKenneth D. Merry ccb = cm->cm_complete_data; 3001991554f2SKenneth D. Merry 3002991554f2SKenneth D. Merry /* 3003991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 3004991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and SMP 3005991554f2SKenneth D. Merry * commands require two S/G elements only. That should be handled 3006991554f2SKenneth D. Merry * in the standard request size. 3007991554f2SKenneth D. Merry */ 3008991554f2SKenneth D. Merry if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 3009a2c14879SStephen McConnell mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x on SMP " 3010a2c14879SStephen McConnell "request!\n", __func__, cm->cm_flags); 3011a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); 3012991554f2SKenneth D. Merry goto bailout; 3013991554f2SKenneth D. Merry } 3014991554f2SKenneth D. Merry 3015991554f2SKenneth D. Merry rpl = (MPI2_SMP_PASSTHROUGH_REPLY *)cm->cm_reply; 3016991554f2SKenneth D. Merry if (rpl == NULL) { 3017991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: NULL cm_reply!\n", __func__); 3018a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); 3019991554f2SKenneth D. Merry goto bailout; 3020991554f2SKenneth D. Merry } 3021991554f2SKenneth D. Merry 3022991554f2SKenneth D. Merry req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req; 3023991554f2SKenneth D. Merry sasaddr = le32toh(req->SASAddress.Low); 3024991554f2SKenneth D. Merry sasaddr |= ((uint64_t)(le32toh(req->SASAddress.High))) << 32; 3025991554f2SKenneth D. Merry 3026991554f2SKenneth D. Merry if ((le16toh(rpl->IOCStatus) & MPI2_IOCSTATUS_MASK) != 3027991554f2SKenneth D. Merry MPI2_IOCSTATUS_SUCCESS || 3028991554f2SKenneth D. Merry rpl->SASStatus != MPI2_SASSTATUS_SUCCESS) { 3029991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "%s: IOCStatus %04x SASStatus %02x\n", 3030991554f2SKenneth D. Merry __func__, le16toh(rpl->IOCStatus), rpl->SASStatus); 3031a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); 3032991554f2SKenneth D. Merry goto bailout; 3033991554f2SKenneth D. Merry } 3034991554f2SKenneth D. Merry 3035a2c14879SStephen McConnell mpr_dprint(sc, MPR_XINFO, "%s: SMP request to SAS address %#jx " 3036a2c14879SStephen McConnell "completed successfully\n", __func__, (uintmax_t)sasaddr); 3037991554f2SKenneth D. Merry 3038991554f2SKenneth D. Merry if (ccb->smpio.smp_response[2] == SMP_FR_ACCEPTED) 3039a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); 3040991554f2SKenneth D. Merry else 3041a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_SMP_STATUS_ERROR); 3042991554f2SKenneth D. Merry 3043991554f2SKenneth D. Merry bailout: 3044991554f2SKenneth D. Merry /* 3045991554f2SKenneth D. Merry * We sync in both directions because we had DMAs in the S/G list 3046991554f2SKenneth D. Merry * in both directions. 3047991554f2SKenneth D. Merry */ 3048991554f2SKenneth D. Merry bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, 3049991554f2SKenneth D. Merry BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 3050991554f2SKenneth D. Merry bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); 3051991554f2SKenneth D. Merry mpr_free_command(sc, cm); 3052991554f2SKenneth D. Merry xpt_done(ccb); 3053991554f2SKenneth D. Merry } 3054991554f2SKenneth D. Merry 3055991554f2SKenneth D. Merry static void 30567a2a6a1aSStephen McConnell mprsas_send_smpcmd(struct mprsas_softc *sassc, union ccb *ccb, uint64_t sasaddr) 3057991554f2SKenneth D. Merry { 3058991554f2SKenneth D. Merry struct mpr_command *cm; 3059991554f2SKenneth D. Merry uint8_t *request, *response; 3060991554f2SKenneth D. Merry MPI2_SMP_PASSTHROUGH_REQUEST *req; 3061991554f2SKenneth D. Merry struct mpr_softc *sc; 3062991554f2SKenneth D. Merry struct sglist *sg; 3063991554f2SKenneth D. Merry int error; 3064991554f2SKenneth D. Merry 3065991554f2SKenneth D. Merry sc = sassc->sc; 3066991554f2SKenneth D. Merry sg = NULL; 3067991554f2SKenneth D. Merry error = 0; 3068991554f2SKenneth D. Merry 3069c503306dSKenneth D. Merry #if (__FreeBSD_version >= 1000028) || \ 3070c503306dSKenneth D. Merry ((__FreeBSD_version >= 902001) && (__FreeBSD_version < 1000000)) 3071991554f2SKenneth D. Merry switch (ccb->ccb_h.flags & CAM_DATA_MASK) { 3072991554f2SKenneth D. Merry case CAM_DATA_PADDR: 3073991554f2SKenneth D. Merry case CAM_DATA_SG_PADDR: 3074991554f2SKenneth D. Merry /* 3075991554f2SKenneth D. Merry * XXX We don't yet support physical addresses here. 3076991554f2SKenneth D. Merry */ 3077991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: physical addresses not " 3078991554f2SKenneth D. Merry "supported\n", __func__); 3079a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_INVALID); 3080991554f2SKenneth D. Merry xpt_done(ccb); 3081991554f2SKenneth D. Merry return; 3082991554f2SKenneth D. Merry case CAM_DATA_SG: 3083991554f2SKenneth D. Merry /* 3084991554f2SKenneth D. Merry * The chip does not support more than one buffer for the 3085991554f2SKenneth D. Merry * request or response. 3086991554f2SKenneth D. Merry */ 3087991554f2SKenneth D. Merry if ((ccb->smpio.smp_request_sglist_cnt > 1) 3088991554f2SKenneth D. Merry || (ccb->smpio.smp_response_sglist_cnt > 1)) { 30897a2a6a1aSStephen McConnell mpr_dprint(sc, MPR_ERROR, "%s: multiple request or " 30907a2a6a1aSStephen McConnell "response buffer segments not supported for SMP\n", 30917a2a6a1aSStephen McConnell __func__); 3092a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_INVALID); 3093991554f2SKenneth D. Merry xpt_done(ccb); 3094991554f2SKenneth D. Merry return; 3095991554f2SKenneth D. Merry } 3096991554f2SKenneth D. Merry 3097991554f2SKenneth D. Merry /* 3098991554f2SKenneth D. Merry * The CAM_SCATTER_VALID flag was originally implemented 3099991554f2SKenneth D. Merry * for the XPT_SCSI_IO CCB, which only has one data pointer. 3100991554f2SKenneth D. Merry * We have two. So, just take that flag to mean that we 3101991554f2SKenneth D. Merry * might have S/G lists, and look at the S/G segment count 3102991554f2SKenneth D. Merry * to figure out whether that is the case for each individual 3103991554f2SKenneth D. Merry * buffer. 3104991554f2SKenneth D. Merry */ 3105991554f2SKenneth D. Merry if (ccb->smpio.smp_request_sglist_cnt != 0) { 3106991554f2SKenneth D. Merry bus_dma_segment_t *req_sg; 3107991554f2SKenneth D. Merry 3108991554f2SKenneth D. Merry req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request; 3109991554f2SKenneth D. Merry request = (uint8_t *)(uintptr_t)req_sg[0].ds_addr; 3110991554f2SKenneth D. Merry } else 3111991554f2SKenneth D. Merry request = ccb->smpio.smp_request; 3112991554f2SKenneth D. Merry 3113991554f2SKenneth D. Merry if (ccb->smpio.smp_response_sglist_cnt != 0) { 3114991554f2SKenneth D. Merry bus_dma_segment_t *rsp_sg; 3115991554f2SKenneth D. Merry 3116991554f2SKenneth D. Merry rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response; 3117991554f2SKenneth D. Merry response = (uint8_t *)(uintptr_t)rsp_sg[0].ds_addr; 3118991554f2SKenneth D. Merry } else 3119991554f2SKenneth D. Merry response = ccb->smpio.smp_response; 3120991554f2SKenneth D. Merry break; 3121991554f2SKenneth D. Merry case CAM_DATA_VADDR: 3122991554f2SKenneth D. Merry request = ccb->smpio.smp_request; 3123991554f2SKenneth D. Merry response = ccb->smpio.smp_response; 3124991554f2SKenneth D. Merry break; 3125991554f2SKenneth D. Merry default: 3126a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_INVALID); 3127991554f2SKenneth D. Merry xpt_done(ccb); 3128991554f2SKenneth D. Merry return; 3129991554f2SKenneth D. Merry } 3130c503306dSKenneth D. Merry #else /* __FreeBSD_version < 1000028 */ 3131991554f2SKenneth D. Merry /* 3132991554f2SKenneth D. Merry * XXX We don't yet support physical addresses here. 3133991554f2SKenneth D. Merry */ 3134991554f2SKenneth D. Merry if (ccb->ccb_h.flags & (CAM_DATA_PHYS|CAM_SG_LIST_PHYS)) { 3135a2c14879SStephen McConnell mpr_dprint(sc, MPR_ERROR, "%s: physical addresses not " 3136a2c14879SStephen McConnell "supported\n", __func__); 3137a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_INVALID); 3138991554f2SKenneth D. Merry xpt_done(ccb); 3139991554f2SKenneth D. Merry return; 3140991554f2SKenneth D. Merry } 3141991554f2SKenneth D. Merry 3142991554f2SKenneth D. Merry /* 3143991554f2SKenneth D. Merry * If the user wants to send an S/G list, check to make sure they 3144991554f2SKenneth D. Merry * have single buffers. 3145991554f2SKenneth D. Merry */ 3146991554f2SKenneth D. Merry if (ccb->ccb_h.flags & CAM_SCATTER_VALID) { 3147991554f2SKenneth D. Merry /* 3148991554f2SKenneth D. Merry * The chip does not support more than one buffer for the 3149991554f2SKenneth D. Merry * request or response. 3150991554f2SKenneth D. Merry */ 3151991554f2SKenneth D. Merry if ((ccb->smpio.smp_request_sglist_cnt > 1) 3152991554f2SKenneth D. Merry || (ccb->smpio.smp_response_sglist_cnt > 1)) { 3153991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: multiple request or " 3154991554f2SKenneth D. Merry "response buffer segments not supported for SMP\n", 3155991554f2SKenneth D. Merry __func__); 3156a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_INVALID); 3157991554f2SKenneth D. Merry xpt_done(ccb); 3158991554f2SKenneth D. Merry return; 3159991554f2SKenneth D. Merry } 3160991554f2SKenneth D. Merry 3161991554f2SKenneth D. Merry /* 3162991554f2SKenneth D. Merry * The CAM_SCATTER_VALID flag was originally implemented 3163991554f2SKenneth D. Merry * for the XPT_SCSI_IO CCB, which only has one data pointer. 3164991554f2SKenneth D. Merry * We have two. So, just take that flag to mean that we 3165991554f2SKenneth D. Merry * might have S/G lists, and look at the S/G segment count 3166991554f2SKenneth D. Merry * to figure out whether that is the case for each individual 3167991554f2SKenneth D. Merry * buffer. 3168991554f2SKenneth D. Merry */ 3169991554f2SKenneth D. Merry if (ccb->smpio.smp_request_sglist_cnt != 0) { 3170991554f2SKenneth D. Merry bus_dma_segment_t *req_sg; 3171991554f2SKenneth D. Merry 3172991554f2SKenneth D. Merry req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request; 3173c503306dSKenneth D. Merry request = (uint8_t *)(uintptr_t)req_sg[0].ds_addr; 3174991554f2SKenneth D. Merry } else 3175991554f2SKenneth D. Merry request = ccb->smpio.smp_request; 3176991554f2SKenneth D. Merry 3177991554f2SKenneth D. Merry if (ccb->smpio.smp_response_sglist_cnt != 0) { 3178991554f2SKenneth D. Merry bus_dma_segment_t *rsp_sg; 3179991554f2SKenneth D. Merry 3180991554f2SKenneth D. Merry rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response; 3181c503306dSKenneth D. Merry response = (uint8_t *)(uintptr_t)rsp_sg[0].ds_addr; 3182991554f2SKenneth D. Merry } else 3183991554f2SKenneth D. Merry response = ccb->smpio.smp_response; 3184991554f2SKenneth D. Merry } else { 3185991554f2SKenneth D. Merry request = ccb->smpio.smp_request; 3186991554f2SKenneth D. Merry response = ccb->smpio.smp_response; 3187991554f2SKenneth D. Merry } 3188c503306dSKenneth D. Merry #endif /* __FreeBSD_version < 1000028 */ 3189991554f2SKenneth D. Merry 3190991554f2SKenneth D. Merry cm = mpr_alloc_command(sc); 3191991554f2SKenneth D. Merry if (cm == NULL) { 31927a2a6a1aSStephen McConnell mpr_dprint(sc, MPR_ERROR, "%s: cannot allocate command\n", 31937a2a6a1aSStephen McConnell __func__); 3194a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_RESRC_UNAVAIL); 3195991554f2SKenneth D. Merry xpt_done(ccb); 3196991554f2SKenneth D. Merry return; 3197991554f2SKenneth D. Merry } 3198991554f2SKenneth D. Merry 3199991554f2SKenneth D. Merry req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req; 3200991554f2SKenneth D. Merry bzero(req, sizeof(*req)); 3201991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; 3202991554f2SKenneth D. Merry 3203991554f2SKenneth D. Merry /* Allow the chip to use any route to this SAS address. */ 3204991554f2SKenneth D. Merry req->PhysicalPort = 0xff; 3205991554f2SKenneth D. Merry 3206991554f2SKenneth D. Merry req->RequestDataLength = htole16(ccb->smpio.smp_request_len); 3207991554f2SKenneth D. Merry req->SGLFlags = 3208991554f2SKenneth D. Merry MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE | MPI2_SGLFLAGS_SGL_TYPE_MPI; 3209991554f2SKenneth D. Merry 3210991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "%s: sending SMP request to SAS address " 3211991554f2SKenneth D. Merry "%#jx\n", __func__, (uintmax_t)sasaddr); 3212991554f2SKenneth D. Merry 3213991554f2SKenneth D. Merry mpr_init_sge(cm, req, &req->SGL); 3214991554f2SKenneth D. Merry 3215991554f2SKenneth D. Merry /* 3216991554f2SKenneth D. Merry * Set up a uio to pass into mpr_map_command(). This allows us to 3217991554f2SKenneth D. Merry * do one map command, and one busdma call in there. 3218991554f2SKenneth D. Merry */ 3219991554f2SKenneth D. Merry cm->cm_uio.uio_iov = cm->cm_iovec; 3220991554f2SKenneth D. Merry cm->cm_uio.uio_iovcnt = 2; 3221991554f2SKenneth D. Merry cm->cm_uio.uio_segflg = UIO_SYSSPACE; 3222991554f2SKenneth D. Merry 3223991554f2SKenneth D. Merry /* 3224991554f2SKenneth D. Merry * The read/write flag isn't used by busdma, but set it just in 3225991554f2SKenneth D. Merry * case. This isn't exactly accurate, either, since we're going in 3226991554f2SKenneth D. Merry * both directions. 3227991554f2SKenneth D. Merry */ 3228991554f2SKenneth D. Merry cm->cm_uio.uio_rw = UIO_WRITE; 3229991554f2SKenneth D. Merry 3230991554f2SKenneth D. Merry cm->cm_iovec[0].iov_base = request; 3231991554f2SKenneth D. Merry cm->cm_iovec[0].iov_len = le16toh(req->RequestDataLength); 3232991554f2SKenneth D. Merry cm->cm_iovec[1].iov_base = response; 3233991554f2SKenneth D. Merry cm->cm_iovec[1].iov_len = ccb->smpio.smp_response_len; 3234991554f2SKenneth D. Merry 3235991554f2SKenneth D. Merry cm->cm_uio.uio_resid = cm->cm_iovec[0].iov_len + 3236991554f2SKenneth D. Merry cm->cm_iovec[1].iov_len; 3237991554f2SKenneth D. Merry 3238991554f2SKenneth D. Merry /* 3239991554f2SKenneth D. Merry * Trigger a warning message in mpr_data_cb() for the user if we 3240991554f2SKenneth D. Merry * wind up exceeding two S/G segments. The chip expects one 3241991554f2SKenneth D. Merry * segment for the request and another for the response. 3242991554f2SKenneth D. Merry */ 3243991554f2SKenneth D. Merry cm->cm_max_segs = 2; 3244991554f2SKenneth D. Merry 3245991554f2SKenneth D. Merry cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 3246991554f2SKenneth D. Merry cm->cm_complete = mprsas_smpio_complete; 3247991554f2SKenneth D. Merry cm->cm_complete_data = ccb; 3248991554f2SKenneth D. Merry 3249991554f2SKenneth D. Merry /* 3250991554f2SKenneth D. Merry * Tell the mapping code that we're using a uio, and that this is 3251991554f2SKenneth D. Merry * an SMP passthrough request. There is a little special-case 3252991554f2SKenneth D. Merry * logic there (in mpr_data_cb()) to handle the bidirectional 3253991554f2SKenneth D. Merry * transfer. 3254991554f2SKenneth D. Merry */ 3255991554f2SKenneth D. Merry cm->cm_flags |= MPR_CM_FLAGS_USE_UIO | MPR_CM_FLAGS_SMP_PASS | 3256991554f2SKenneth D. Merry MPR_CM_FLAGS_DATAIN | MPR_CM_FLAGS_DATAOUT; 3257991554f2SKenneth D. Merry 3258991554f2SKenneth D. Merry /* The chip data format is little endian. */ 3259991554f2SKenneth D. Merry req->SASAddress.High = htole32(sasaddr >> 32); 3260991554f2SKenneth D. Merry req->SASAddress.Low = htole32(sasaddr); 3261991554f2SKenneth D. Merry 3262991554f2SKenneth D. Merry /* 3263991554f2SKenneth D. Merry * XXX Note that we don't have a timeout/abort mechanism here. 3264991554f2SKenneth D. Merry * From the manual, it looks like task management requests only 3265991554f2SKenneth D. Merry * work for SCSI IO and SATA passthrough requests. We may need to 3266991554f2SKenneth D. Merry * have a mechanism to retry requests in the event of a chip reset 3267991554f2SKenneth D. Merry * at least. Hopefully the chip will insure that any errors short 3268991554f2SKenneth D. Merry * of that are relayed back to the driver. 3269991554f2SKenneth D. Merry */ 3270991554f2SKenneth D. Merry error = mpr_map_command(sc, cm); 3271991554f2SKenneth D. Merry if ((error != 0) && (error != EINPROGRESS)) { 3272991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: error %d returned from " 3273991554f2SKenneth D. Merry "mpr_map_command()\n", __func__, error); 3274991554f2SKenneth D. Merry goto bailout_error; 3275991554f2SKenneth D. Merry } 3276991554f2SKenneth D. Merry 3277991554f2SKenneth D. Merry return; 3278991554f2SKenneth D. Merry 3279991554f2SKenneth D. Merry bailout_error: 3280991554f2SKenneth D. Merry mpr_free_command(sc, cm); 3281a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_RESRC_UNAVAIL); 3282991554f2SKenneth D. Merry xpt_done(ccb); 3283991554f2SKenneth D. Merry return; 3284991554f2SKenneth D. Merry } 3285991554f2SKenneth D. Merry 3286991554f2SKenneth D. Merry static void 3287991554f2SKenneth D. Merry mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb) 3288991554f2SKenneth D. Merry { 3289991554f2SKenneth D. Merry struct mpr_softc *sc; 3290991554f2SKenneth D. Merry struct mprsas_target *targ; 3291991554f2SKenneth D. Merry uint64_t sasaddr = 0; 3292991554f2SKenneth D. Merry 3293991554f2SKenneth D. Merry sc = sassc->sc; 3294991554f2SKenneth D. Merry 3295991554f2SKenneth D. Merry /* 3296991554f2SKenneth D. Merry * Make sure the target exists. 3297991554f2SKenneth D. Merry */ 3298991554f2SKenneth D. Merry KASSERT(ccb->ccb_h.target_id < sassc->maxtargets, 3299991554f2SKenneth D. Merry ("Target %d out of bounds in XPT_SMP_IO\n", ccb->ccb_h.target_id)); 3300991554f2SKenneth D. Merry targ = &sassc->targets[ccb->ccb_h.target_id]; 3301991554f2SKenneth D. Merry if (targ->handle == 0x0) { 3302991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: target %d does not exist!\n", 3303991554f2SKenneth D. Merry __func__, ccb->ccb_h.target_id); 3304a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_SEL_TIMEOUT); 3305991554f2SKenneth D. Merry xpt_done(ccb); 3306991554f2SKenneth D. Merry return; 3307991554f2SKenneth D. Merry } 3308991554f2SKenneth D. Merry 3309991554f2SKenneth D. Merry /* 3310991554f2SKenneth D. Merry * If this device has an embedded SMP target, we'll talk to it 3311991554f2SKenneth D. Merry * directly. 3312991554f2SKenneth D. Merry * figure out what the expander's address is. 3313991554f2SKenneth D. Merry */ 3314991554f2SKenneth D. Merry if ((targ->devinfo & MPI2_SAS_DEVICE_INFO_SMP_TARGET) != 0) 3315991554f2SKenneth D. Merry sasaddr = targ->sasaddr; 3316991554f2SKenneth D. Merry 3317991554f2SKenneth D. Merry /* 3318991554f2SKenneth D. Merry * If we don't have a SAS address for the expander yet, try 3319991554f2SKenneth D. Merry * grabbing it from the page 0x83 information cached in the 3320991554f2SKenneth D. Merry * transport layer for this target. LSI expanders report the 3321991554f2SKenneth D. Merry * expander SAS address as the port-associated SAS address in 3322991554f2SKenneth D. Merry * Inquiry VPD page 0x83. Maxim expanders don't report it in page 3323991554f2SKenneth D. Merry * 0x83. 3324991554f2SKenneth D. Merry * 3325991554f2SKenneth D. Merry * XXX KDM disable this for now, but leave it commented out so that 3326991554f2SKenneth D. Merry * it is obvious that this is another possible way to get the SAS 3327991554f2SKenneth D. Merry * address. 3328991554f2SKenneth D. Merry * 3329991554f2SKenneth D. Merry * The parent handle method below is a little more reliable, and 3330991554f2SKenneth D. Merry * the other benefit is that it works for devices other than SES 3331991554f2SKenneth D. Merry * devices. So you can send a SMP request to a da(4) device and it 3332991554f2SKenneth D. Merry * will get routed to the expander that device is attached to. 3333991554f2SKenneth D. Merry * (Assuming the da(4) device doesn't contain an SMP target...) 3334991554f2SKenneth D. Merry */ 3335991554f2SKenneth D. Merry #if 0 3336991554f2SKenneth D. Merry if (sasaddr == 0) 3337991554f2SKenneth D. Merry sasaddr = xpt_path_sas_addr(ccb->ccb_h.path); 3338991554f2SKenneth D. Merry #endif 3339991554f2SKenneth D. Merry 3340991554f2SKenneth D. Merry /* 3341991554f2SKenneth D. Merry * If we still don't have a SAS address for the expander, look for 3342991554f2SKenneth D. Merry * the parent device of this device, which is probably the expander. 3343991554f2SKenneth D. Merry */ 3344991554f2SKenneth D. Merry if (sasaddr == 0) { 3345991554f2SKenneth D. Merry #ifdef OLD_MPR_PROBE 3346991554f2SKenneth D. Merry struct mprsas_target *parent_target; 3347991554f2SKenneth D. Merry #endif 3348991554f2SKenneth D. Merry 3349991554f2SKenneth D. Merry if (targ->parent_handle == 0x0) { 3350991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: handle %d does not have " 3351991554f2SKenneth D. Merry "a valid parent handle!\n", __func__, targ->handle); 3352a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); 3353991554f2SKenneth D. Merry goto bailout; 3354991554f2SKenneth D. Merry } 3355991554f2SKenneth D. Merry #ifdef OLD_MPR_PROBE 3356991554f2SKenneth D. Merry parent_target = mprsas_find_target_by_handle(sassc, 0, 3357991554f2SKenneth D. Merry targ->parent_handle); 3358991554f2SKenneth D. Merry 3359991554f2SKenneth D. Merry if (parent_target == NULL) { 3360991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: handle %d does not have " 3361991554f2SKenneth D. Merry "a valid parent target!\n", __func__, targ->handle); 3362a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); 3363991554f2SKenneth D. Merry goto bailout; 3364991554f2SKenneth D. Merry } 3365991554f2SKenneth D. Merry 3366991554f2SKenneth D. Merry if ((parent_target->devinfo & 3367991554f2SKenneth D. Merry MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) { 3368991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent %d " 3369991554f2SKenneth D. Merry "does not have an SMP target!\n", __func__, 3370991554f2SKenneth D. Merry targ->handle, parent_target->handle); 3371a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); 3372991554f2SKenneth D. Merry goto bailout; 3373991554f2SKenneth D. Merry } 3374991554f2SKenneth D. Merry 3375991554f2SKenneth D. Merry sasaddr = parent_target->sasaddr; 3376991554f2SKenneth D. Merry #else /* OLD_MPR_PROBE */ 3377991554f2SKenneth D. Merry if ((targ->parent_devinfo & 3378991554f2SKenneth D. Merry MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) { 3379991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent %d " 3380991554f2SKenneth D. Merry "does not have an SMP target!\n", __func__, 3381991554f2SKenneth D. Merry targ->handle, targ->parent_handle); 3382a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); 3383991554f2SKenneth D. Merry goto bailout; 3384991554f2SKenneth D. Merry 3385991554f2SKenneth D. Merry } 3386991554f2SKenneth D. Merry if (targ->parent_sasaddr == 0x0) { 3387991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent handle " 3388991554f2SKenneth D. Merry "%d does not have a valid SAS address!\n", __func__, 3389991554f2SKenneth D. Merry targ->handle, targ->parent_handle); 3390a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); 3391991554f2SKenneth D. Merry goto bailout; 3392991554f2SKenneth D. Merry } 3393991554f2SKenneth D. Merry 3394991554f2SKenneth D. Merry sasaddr = targ->parent_sasaddr; 3395991554f2SKenneth D. Merry #endif /* OLD_MPR_PROBE */ 3396991554f2SKenneth D. Merry 3397991554f2SKenneth D. Merry } 3398991554f2SKenneth D. Merry 3399991554f2SKenneth D. Merry if (sasaddr == 0) { 3400991554f2SKenneth D. Merry mpr_dprint(sc, MPR_INFO, "%s: unable to find SAS address for " 3401991554f2SKenneth D. Merry "handle %d\n", __func__, targ->handle); 3402a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); 3403991554f2SKenneth D. Merry goto bailout; 3404991554f2SKenneth D. Merry } 3405991554f2SKenneth D. Merry mprsas_send_smpcmd(sassc, ccb, sasaddr); 3406991554f2SKenneth D. Merry 3407991554f2SKenneth D. Merry return; 3408991554f2SKenneth D. Merry 3409991554f2SKenneth D. Merry bailout: 3410991554f2SKenneth D. Merry xpt_done(ccb); 3411991554f2SKenneth D. Merry 3412991554f2SKenneth D. Merry } 3413991554f2SKenneth D. Merry #endif //__FreeBSD_version >= 900026 3414991554f2SKenneth D. Merry 3415991554f2SKenneth D. Merry static void 3416991554f2SKenneth D. Merry mprsas_action_resetdev(struct mprsas_softc *sassc, union ccb *ccb) 3417991554f2SKenneth D. Merry { 3418991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 3419991554f2SKenneth D. Merry struct mpr_softc *sc; 3420991554f2SKenneth D. Merry struct mpr_command *tm; 3421991554f2SKenneth D. Merry struct mprsas_target *targ; 3422991554f2SKenneth D. Merry 3423991554f2SKenneth D. Merry MPR_FUNCTRACE(sassc->sc); 3424991554f2SKenneth D. Merry mtx_assert(&sassc->sc->mpr_mtx, MA_OWNED); 3425991554f2SKenneth D. Merry 34267a2a6a1aSStephen McConnell KASSERT(ccb->ccb_h.target_id < sassc->maxtargets, ("Target %d out of " 34277a2a6a1aSStephen McConnell "bounds in XPT_RESET_DEV\n", ccb->ccb_h.target_id)); 3428991554f2SKenneth D. Merry sc = sassc->sc; 3429991554f2SKenneth D. Merry tm = mpr_alloc_command(sc); 3430991554f2SKenneth D. Merry if (tm == NULL) { 34317a2a6a1aSStephen McConnell mpr_dprint(sc, MPR_ERROR, "command alloc failure in " 34327a2a6a1aSStephen McConnell "mprsas_action_resetdev\n"); 3433a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_RESRC_UNAVAIL); 3434991554f2SKenneth D. Merry xpt_done(ccb); 3435991554f2SKenneth D. Merry return; 3436991554f2SKenneth D. Merry } 3437991554f2SKenneth D. Merry 3438991554f2SKenneth D. Merry targ = &sassc->targets[ccb->ccb_h.target_id]; 3439991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 3440991554f2SKenneth D. Merry req->DevHandle = htole16(targ->handle); 3441991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 3442991554f2SKenneth D. Merry req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; 3443991554f2SKenneth D. Merry 3444991554f2SKenneth D. Merry /* SAS Hard Link Reset / SATA Link Reset */ 3445991554f2SKenneth D. Merry req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; 3446991554f2SKenneth D. Merry 3447991554f2SKenneth D. Merry tm->cm_data = NULL; 3448991554f2SKenneth D. Merry tm->cm_desc.HighPriority.RequestFlags = 3449991554f2SKenneth D. Merry MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 3450991554f2SKenneth D. Merry tm->cm_complete = mprsas_resetdev_complete; 3451991554f2SKenneth D. Merry tm->cm_complete_data = ccb; 3452a2c14879SStephen McConnell 3453a2c14879SStephen McConnell mpr_dprint(sc, MPR_INFO, "%s: Sending reset for target ID %d\n", 3454a2c14879SStephen McConnell __func__, targ->tid); 3455991554f2SKenneth D. Merry tm->cm_targ = targ; 3456a2c14879SStephen McConnell targ->flags |= MPRSAS_TARGET_INRESET; 3457a2c14879SStephen McConnell 3458991554f2SKenneth D. Merry mpr_map_command(sc, tm); 3459991554f2SKenneth D. Merry } 3460991554f2SKenneth D. Merry 3461991554f2SKenneth D. Merry static void 3462991554f2SKenneth D. Merry mprsas_resetdev_complete(struct mpr_softc *sc, struct mpr_command *tm) 3463991554f2SKenneth D. Merry { 3464991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *resp; 3465991554f2SKenneth D. Merry union ccb *ccb; 3466991554f2SKenneth D. Merry 3467991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 3468991554f2SKenneth D. Merry mtx_assert(&sc->mpr_mtx, MA_OWNED); 3469991554f2SKenneth D. Merry 3470991554f2SKenneth D. Merry resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 3471991554f2SKenneth D. Merry ccb = tm->cm_complete_data; 3472991554f2SKenneth D. Merry 3473991554f2SKenneth D. Merry /* 3474991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 3475991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 3476991554f2SKenneth D. Merry * task management commands don't have S/G lists. 3477991554f2SKenneth D. Merry */ 3478991554f2SKenneth D. Merry if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 3479991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 3480991554f2SKenneth D. Merry 3481991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 3482991554f2SKenneth D. Merry 3483991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for reset of " 3484991554f2SKenneth D. Merry "handle %#04x! This should not happen!\n", __func__, 3485991554f2SKenneth D. Merry tm->cm_flags, req->DevHandle); 3486a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); 3487991554f2SKenneth D. Merry goto bailout; 3488991554f2SKenneth D. Merry } 3489991554f2SKenneth D. Merry 34907a2a6a1aSStephen McConnell mpr_dprint(sc, MPR_XINFO, "%s: IOCStatus = 0x%x ResponseCode = 0x%x\n", 34917a2a6a1aSStephen McConnell __func__, le16toh(resp->IOCStatus), le32toh(resp->ResponseCode)); 3492991554f2SKenneth D. Merry 3493991554f2SKenneth D. Merry if (le32toh(resp->ResponseCode) == MPI2_SCSITASKMGMT_RSP_TM_COMPLETE) { 3494a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); 3495991554f2SKenneth D. Merry mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid, 3496991554f2SKenneth D. Merry CAM_LUN_WILDCARD); 3497991554f2SKenneth D. Merry } 3498991554f2SKenneth D. Merry else 3499a2c14879SStephen McConnell mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); 3500991554f2SKenneth D. Merry 3501991554f2SKenneth D. Merry bailout: 3502991554f2SKenneth D. Merry 3503991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 3504991554f2SKenneth D. Merry xpt_done(ccb); 3505991554f2SKenneth D. Merry } 3506991554f2SKenneth D. Merry 3507991554f2SKenneth D. Merry static void 3508991554f2SKenneth D. Merry mprsas_poll(struct cam_sim *sim) 3509991554f2SKenneth D. Merry { 3510991554f2SKenneth D. Merry struct mprsas_softc *sassc; 3511991554f2SKenneth D. Merry 3512991554f2SKenneth D. Merry sassc = cam_sim_softc(sim); 3513991554f2SKenneth D. Merry 3514991554f2SKenneth D. Merry if (sassc->sc->mpr_debug & MPR_TRACE) { 3515991554f2SKenneth D. Merry /* frequent debug messages during a panic just slow 3516991554f2SKenneth D. Merry * everything down too much. 3517991554f2SKenneth D. Merry */ 3518a2c14879SStephen McConnell mpr_dprint(sassc->sc, MPR_XINFO, "%s clearing MPR_TRACE\n", 3519a2c14879SStephen McConnell __func__); 3520991554f2SKenneth D. Merry sassc->sc->mpr_debug &= ~MPR_TRACE; 3521991554f2SKenneth D. Merry } 3522991554f2SKenneth D. Merry 3523991554f2SKenneth D. Merry mpr_intr_locked(sassc->sc); 3524991554f2SKenneth D. Merry } 3525991554f2SKenneth D. Merry 3526991554f2SKenneth D. Merry static void 3527991554f2SKenneth D. Merry mprsas_async(void *callback_arg, uint32_t code, struct cam_path *path, 3528991554f2SKenneth D. Merry void *arg) 3529991554f2SKenneth D. Merry { 3530991554f2SKenneth D. Merry struct mpr_softc *sc; 3531991554f2SKenneth D. Merry 3532991554f2SKenneth D. Merry sc = (struct mpr_softc *)callback_arg; 3533991554f2SKenneth D. Merry 3534991554f2SKenneth D. Merry switch (code) { 3535991554f2SKenneth D. Merry #if (__FreeBSD_version >= 1000006) || \ 3536991554f2SKenneth D. Merry ((__FreeBSD_version >= 901503) && (__FreeBSD_version < 1000000)) 3537991554f2SKenneth D. Merry case AC_ADVINFO_CHANGED: { 3538991554f2SKenneth D. Merry struct mprsas_target *target; 3539991554f2SKenneth D. Merry struct mprsas_softc *sassc; 3540991554f2SKenneth D. Merry struct scsi_read_capacity_data_long rcap_buf; 3541991554f2SKenneth D. Merry struct ccb_dev_advinfo cdai; 3542991554f2SKenneth D. Merry struct mprsas_lun *lun; 3543991554f2SKenneth D. Merry lun_id_t lunid; 3544991554f2SKenneth D. Merry int found_lun; 3545991554f2SKenneth D. Merry uintptr_t buftype; 3546991554f2SKenneth D. Merry 3547991554f2SKenneth D. Merry buftype = (uintptr_t)arg; 3548991554f2SKenneth D. Merry 3549991554f2SKenneth D. Merry found_lun = 0; 3550991554f2SKenneth D. Merry sassc = sc->sassc; 3551991554f2SKenneth D. Merry 3552991554f2SKenneth D. Merry /* 3553991554f2SKenneth D. Merry * We're only interested in read capacity data changes. 3554991554f2SKenneth D. Merry */ 3555991554f2SKenneth D. Merry if (buftype != CDAI_TYPE_RCAPLONG) 3556991554f2SKenneth D. Merry break; 3557991554f2SKenneth D. Merry 3558991554f2SKenneth D. Merry /* 355907aa4de1SKenneth D. Merry * See the comment in mpr_attach_sas() for a detailed 356007aa4de1SKenneth D. Merry * explanation. In these versions of FreeBSD we register 356107aa4de1SKenneth D. Merry * for all events and filter out the events that don't 356207aa4de1SKenneth D. Merry * apply to us. 356307aa4de1SKenneth D. Merry */ 356407aa4de1SKenneth D. Merry #if (__FreeBSD_version < 1000703) || \ 356507aa4de1SKenneth D. Merry ((__FreeBSD_version >= 1100000) && (__FreeBSD_version < 1100002)) 356607aa4de1SKenneth D. Merry if (xpt_path_path_id(path) != sassc->sim->path_id) 356707aa4de1SKenneth D. Merry break; 356807aa4de1SKenneth D. Merry #endif 356907aa4de1SKenneth D. Merry 357007aa4de1SKenneth D. Merry /* 3571991554f2SKenneth D. Merry * We should have a handle for this, but check to make sure. 3572991554f2SKenneth D. Merry */ 3573991554f2SKenneth D. Merry KASSERT(xpt_path_target_id(path) < sassc->maxtargets, 3574991554f2SKenneth D. Merry ("Target %d out of bounds in mprsas_async\n", 3575991554f2SKenneth D. Merry xpt_path_target_id(path))); 3576991554f2SKenneth D. Merry target = &sassc->targets[xpt_path_target_id(path)]; 3577991554f2SKenneth D. Merry if (target->handle == 0) 3578991554f2SKenneth D. Merry break; 3579991554f2SKenneth D. Merry 3580991554f2SKenneth D. Merry lunid = xpt_path_lun_id(path); 3581991554f2SKenneth D. Merry 3582991554f2SKenneth D. Merry SLIST_FOREACH(lun, &target->luns, lun_link) { 3583991554f2SKenneth D. Merry if (lun->lun_id == lunid) { 3584991554f2SKenneth D. Merry found_lun = 1; 3585991554f2SKenneth D. Merry break; 3586991554f2SKenneth D. Merry } 3587991554f2SKenneth D. Merry } 3588991554f2SKenneth D. Merry 3589991554f2SKenneth D. Merry if (found_lun == 0) { 3590991554f2SKenneth D. Merry lun = malloc(sizeof(struct mprsas_lun), M_MPR, 3591991554f2SKenneth D. Merry M_NOWAIT | M_ZERO); 3592991554f2SKenneth D. Merry if (lun == NULL) { 3593991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "Unable to alloc " 3594991554f2SKenneth D. Merry "LUN for EEDP support.\n"); 3595991554f2SKenneth D. Merry break; 3596991554f2SKenneth D. Merry } 3597991554f2SKenneth D. Merry lun->lun_id = lunid; 3598991554f2SKenneth D. Merry SLIST_INSERT_HEAD(&target->luns, lun, lun_link); 3599991554f2SKenneth D. Merry } 3600991554f2SKenneth D. Merry 3601991554f2SKenneth D. Merry bzero(&rcap_buf, sizeof(rcap_buf)); 3602991554f2SKenneth D. Merry xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL); 3603991554f2SKenneth D. Merry cdai.ccb_h.func_code = XPT_DEV_ADVINFO; 3604991554f2SKenneth D. Merry cdai.ccb_h.flags = CAM_DIR_IN; 3605991554f2SKenneth D. Merry cdai.buftype = CDAI_TYPE_RCAPLONG; 36066c0541faSKenneth D. Merry #if (__FreeBSD_version >= 1100061) || \ 36076c0541faSKenneth D. Merry ((__FreeBSD_version >= 1001510) && (__FreeBSD_version < 1100000)) 3608e8577fb4SKenneth D. Merry cdai.flags = CDAI_FLAG_NONE; 3609e8577fb4SKenneth D. Merry #else 3610991554f2SKenneth D. Merry cdai.flags = 0; 3611e8577fb4SKenneth D. Merry #endif 3612991554f2SKenneth D. Merry cdai.bufsiz = sizeof(rcap_buf); 3613991554f2SKenneth D. Merry cdai.buf = (uint8_t *)&rcap_buf; 3614991554f2SKenneth D. Merry xpt_action((union ccb *)&cdai); 3615991554f2SKenneth D. Merry if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0) 3616991554f2SKenneth D. Merry cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE); 3617991554f2SKenneth D. Merry 3618a2c14879SStephen McConnell if ((mprsas_get_ccbstatus((union ccb *)&cdai) == CAM_REQ_CMP) 3619991554f2SKenneth D. Merry && (rcap_buf.prot & SRC16_PROT_EN)) { 3620991554f2SKenneth D. Merry lun->eedp_formatted = TRUE; 3621991554f2SKenneth D. Merry lun->eedp_block_size = scsi_4btoul(rcap_buf.length); 3622991554f2SKenneth D. Merry } else { 3623991554f2SKenneth D. Merry lun->eedp_formatted = FALSE; 3624991554f2SKenneth D. Merry lun->eedp_block_size = 0; 3625991554f2SKenneth D. Merry } 3626991554f2SKenneth D. Merry break; 3627991554f2SKenneth D. Merry } 3628991554f2SKenneth D. Merry #endif 3629991554f2SKenneth D. Merry case AC_FOUND_DEVICE: { 3630991554f2SKenneth D. Merry struct ccb_getdev *cgd; 3631991554f2SKenneth D. Merry 363207aa4de1SKenneth D. Merry /* 363307aa4de1SKenneth D. Merry * See the comment in mpr_attach_sas() for a detailed 363407aa4de1SKenneth D. Merry * explanation. In these versions of FreeBSD we register 363507aa4de1SKenneth D. Merry * for all events and filter out the events that don't 363607aa4de1SKenneth D. Merry * apply to us. 363707aa4de1SKenneth D. Merry */ 363807aa4de1SKenneth D. Merry #if (__FreeBSD_version < 1000703) || \ 363907aa4de1SKenneth D. Merry ((__FreeBSD_version >= 1100000) && (__FreeBSD_version < 1100002)) 364007aa4de1SKenneth D. Merry if (xpt_path_path_id(path) != sc->sassc->sim->path_id) 364107aa4de1SKenneth D. Merry break; 364207aa4de1SKenneth D. Merry #endif 364307aa4de1SKenneth D. Merry 3644991554f2SKenneth D. Merry cgd = arg; 3645991554f2SKenneth D. Merry #if (__FreeBSD_version < 901503) || \ 3646991554f2SKenneth D. Merry ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) 3647991554f2SKenneth D. Merry mprsas_check_eedp(sc, path, cgd); 3648991554f2SKenneth D. Merry #endif 3649991554f2SKenneth D. Merry break; 3650991554f2SKenneth D. Merry } 3651991554f2SKenneth D. Merry default: 3652991554f2SKenneth D. Merry break; 3653991554f2SKenneth D. Merry } 3654991554f2SKenneth D. Merry } 3655991554f2SKenneth D. Merry 3656991554f2SKenneth D. Merry #if (__FreeBSD_version < 901503) || \ 3657991554f2SKenneth D. Merry ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) 3658991554f2SKenneth D. Merry static void 3659991554f2SKenneth D. Merry mprsas_check_eedp(struct mpr_softc *sc, struct cam_path *path, 3660991554f2SKenneth D. Merry struct ccb_getdev *cgd) 3661991554f2SKenneth D. Merry { 3662991554f2SKenneth D. Merry struct mprsas_softc *sassc = sc->sassc; 3663991554f2SKenneth D. Merry struct ccb_scsiio *csio; 3664991554f2SKenneth D. Merry struct scsi_read_capacity_16 *scsi_cmd; 3665991554f2SKenneth D. Merry struct scsi_read_capacity_eedp *rcap_buf; 3666991554f2SKenneth D. Merry path_id_t pathid; 3667991554f2SKenneth D. Merry target_id_t targetid; 3668991554f2SKenneth D. Merry lun_id_t lunid; 3669991554f2SKenneth D. Merry union ccb *ccb; 3670991554f2SKenneth D. Merry struct cam_path *local_path; 3671991554f2SKenneth D. Merry struct mprsas_target *target; 3672991554f2SKenneth D. Merry struct mprsas_lun *lun; 3673991554f2SKenneth D. Merry uint8_t found_lun; 3674991554f2SKenneth D. Merry char path_str[64]; 3675991554f2SKenneth D. Merry 3676991554f2SKenneth D. Merry pathid = cam_sim_path(sassc->sim); 3677991554f2SKenneth D. Merry targetid = xpt_path_target_id(path); 3678991554f2SKenneth D. Merry lunid = xpt_path_lun_id(path); 3679991554f2SKenneth D. Merry 36807a2a6a1aSStephen McConnell KASSERT(targetid < sassc->maxtargets, ("Target %d out of bounds in " 36817a2a6a1aSStephen McConnell "mprsas_check_eedp\n", targetid)); 3682991554f2SKenneth D. Merry target = &sassc->targets[targetid]; 3683991554f2SKenneth D. Merry if (target->handle == 0x0) 3684991554f2SKenneth D. Merry return; 3685991554f2SKenneth D. Merry 3686991554f2SKenneth D. Merry /* 3687991554f2SKenneth D. Merry * Determine if the device is EEDP capable. 3688991554f2SKenneth D. Merry * 3689991554f2SKenneth D. Merry * If this flag is set in the inquiry data, the device supports 3690991554f2SKenneth D. Merry * protection information, and must support the 16 byte read capacity 36917a2a6a1aSStephen McConnell * command, otherwise continue without sending read cap 16. 3692991554f2SKenneth D. Merry */ 3693991554f2SKenneth D. Merry if ((cgd->inq_data.spc3_flags & SPC3_SID_PROTECT) == 0) 3694991554f2SKenneth D. Merry return; 3695991554f2SKenneth D. Merry 3696991554f2SKenneth D. Merry /* 3697991554f2SKenneth D. Merry * Issue a READ CAPACITY 16 command. This info is used to determine if 3698991554f2SKenneth D. Merry * the LUN is formatted for EEDP support. 3699991554f2SKenneth D. Merry */ 3700991554f2SKenneth D. Merry ccb = xpt_alloc_ccb_nowait(); 3701991554f2SKenneth D. Merry if (ccb == NULL) { 3702991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "Unable to alloc CCB for EEDP " 3703991554f2SKenneth D. Merry "support.\n"); 3704991554f2SKenneth D. Merry return; 3705991554f2SKenneth D. Merry } 3706991554f2SKenneth D. Merry 37077a2a6a1aSStephen McConnell if (xpt_create_path(&local_path, xpt_periph, pathid, targetid, lunid) != 37087a2a6a1aSStephen McConnell CAM_REQ_CMP) { 3709991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "Unable to create path for EEDP " 37107a2a6a1aSStephen McConnell "support.\n"); 3711991554f2SKenneth D. Merry xpt_free_ccb(ccb); 3712991554f2SKenneth D. Merry return; 3713991554f2SKenneth D. Merry } 3714991554f2SKenneth D. Merry 3715991554f2SKenneth D. Merry /* 3716991554f2SKenneth D. Merry * If LUN is already in list, don't create a new one. 3717991554f2SKenneth D. Merry */ 3718991554f2SKenneth D. Merry found_lun = FALSE; 3719991554f2SKenneth D. Merry SLIST_FOREACH(lun, &target->luns, lun_link) { 3720991554f2SKenneth D. Merry if (lun->lun_id == lunid) { 3721991554f2SKenneth D. Merry found_lun = TRUE; 3722991554f2SKenneth D. Merry break; 3723991554f2SKenneth D. Merry } 3724991554f2SKenneth D. Merry } 3725991554f2SKenneth D. Merry if (!found_lun) { 3726991554f2SKenneth D. Merry lun = malloc(sizeof(struct mprsas_lun), M_MPR, 3727991554f2SKenneth D. Merry M_NOWAIT | M_ZERO); 3728991554f2SKenneth D. Merry if (lun == NULL) { 3729991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "Unable to alloc LUN for " 3730991554f2SKenneth D. Merry "EEDP support.\n"); 3731991554f2SKenneth D. Merry xpt_free_path(local_path); 3732991554f2SKenneth D. Merry xpt_free_ccb(ccb); 3733991554f2SKenneth D. Merry return; 3734991554f2SKenneth D. Merry } 3735991554f2SKenneth D. Merry lun->lun_id = lunid; 3736991554f2SKenneth D. Merry SLIST_INSERT_HEAD(&target->luns, lun, lun_link); 3737991554f2SKenneth D. Merry } 3738991554f2SKenneth D. Merry 3739991554f2SKenneth D. Merry xpt_path_string(local_path, path_str, sizeof(path_str)); 3740991554f2SKenneth D. Merry mpr_dprint(sc, MPR_INFO, "Sending read cap: path %s handle %d\n", 3741991554f2SKenneth D. Merry path_str, target->handle); 3742991554f2SKenneth D. Merry 3743991554f2SKenneth D. Merry /* 3744991554f2SKenneth D. Merry * Issue a READ CAPACITY 16 command for the LUN. The 3745991554f2SKenneth D. Merry * mprsas_read_cap_done function will load the read cap info into the 3746991554f2SKenneth D. Merry * LUN struct. 3747991554f2SKenneth D. Merry */ 3748991554f2SKenneth D. Merry rcap_buf = malloc(sizeof(struct scsi_read_capacity_eedp), M_MPR, 3749991554f2SKenneth D. Merry M_NOWAIT | M_ZERO); 3750991554f2SKenneth D. Merry if (rcap_buf == NULL) { 3751a2c14879SStephen McConnell mpr_dprint(sc, MPR_ERROR, "Unable to alloc read capacity " 3752991554f2SKenneth D. Merry "buffer for EEDP support.\n"); 3753991554f2SKenneth D. Merry xpt_free_path(ccb->ccb_h.path); 3754991554f2SKenneth D. Merry xpt_free_ccb(ccb); 3755991554f2SKenneth D. Merry return; 3756991554f2SKenneth D. Merry } 3757991554f2SKenneth D. Merry xpt_setup_ccb(&ccb->ccb_h, local_path, CAM_PRIORITY_XPT); 3758991554f2SKenneth D. Merry csio = &ccb->csio; 3759991554f2SKenneth D. Merry csio->ccb_h.func_code = XPT_SCSI_IO; 3760991554f2SKenneth D. Merry csio->ccb_h.flags = CAM_DIR_IN; 3761991554f2SKenneth D. Merry csio->ccb_h.retry_count = 4; 3762991554f2SKenneth D. Merry csio->ccb_h.cbfcnp = mprsas_read_cap_done; 3763991554f2SKenneth D. Merry csio->ccb_h.timeout = 60000; 3764991554f2SKenneth D. Merry csio->data_ptr = (uint8_t *)rcap_buf; 3765991554f2SKenneth D. Merry csio->dxfer_len = sizeof(struct scsi_read_capacity_eedp); 3766991554f2SKenneth D. Merry csio->sense_len = MPR_SENSE_LEN; 3767991554f2SKenneth D. Merry csio->cdb_len = sizeof(*scsi_cmd); 3768991554f2SKenneth D. Merry csio->tag_action = MSG_SIMPLE_Q_TAG; 3769991554f2SKenneth D. Merry 3770991554f2SKenneth D. Merry scsi_cmd = (struct scsi_read_capacity_16 *)&csio->cdb_io.cdb_bytes; 3771991554f2SKenneth D. Merry bzero(scsi_cmd, sizeof(*scsi_cmd)); 3772991554f2SKenneth D. Merry scsi_cmd->opcode = 0x9E; 3773991554f2SKenneth D. Merry scsi_cmd->service_action = SRC16_SERVICE_ACTION; 3774991554f2SKenneth D. Merry ((uint8_t *)scsi_cmd)[13] = sizeof(struct scsi_read_capacity_eedp); 3775991554f2SKenneth D. Merry 3776991554f2SKenneth D. Merry ccb->ccb_h.ppriv_ptr1 = sassc; 3777991554f2SKenneth D. Merry xpt_action(ccb); 3778991554f2SKenneth D. Merry } 3779991554f2SKenneth D. Merry 3780991554f2SKenneth D. Merry static void 3781991554f2SKenneth D. Merry mprsas_read_cap_done(struct cam_periph *periph, union ccb *done_ccb) 3782991554f2SKenneth D. Merry { 3783991554f2SKenneth D. Merry struct mprsas_softc *sassc; 3784991554f2SKenneth D. Merry struct mprsas_target *target; 3785991554f2SKenneth D. Merry struct mprsas_lun *lun; 3786991554f2SKenneth D. Merry struct scsi_read_capacity_eedp *rcap_buf; 3787991554f2SKenneth D. Merry 3788991554f2SKenneth D. Merry if (done_ccb == NULL) 3789991554f2SKenneth D. Merry return; 3790991554f2SKenneth D. Merry 3791991554f2SKenneth D. Merry /* Driver need to release devq, it Scsi command is 3792991554f2SKenneth D. Merry * generated by driver internally. 3793991554f2SKenneth D. Merry * Currently there is a single place where driver 3794991554f2SKenneth D. Merry * calls scsi command internally. In future if driver 3795991554f2SKenneth D. Merry * calls more scsi command internally, it needs to release 3796991554f2SKenneth D. Merry * devq internally, since those command will not go back to 3797991554f2SKenneth D. Merry * cam_periph. 3798991554f2SKenneth D. Merry */ 3799991554f2SKenneth D. Merry if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) ) { 3800991554f2SKenneth D. Merry done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN; 3801991554f2SKenneth D. Merry xpt_release_devq(done_ccb->ccb_h.path, 3802991554f2SKenneth D. Merry /*count*/ 1, /*run_queue*/TRUE); 3803991554f2SKenneth D. Merry } 3804991554f2SKenneth D. Merry 3805991554f2SKenneth D. Merry rcap_buf = (struct scsi_read_capacity_eedp *)done_ccb->csio.data_ptr; 3806991554f2SKenneth D. Merry 3807991554f2SKenneth D. Merry /* 3808991554f2SKenneth D. Merry * Get the LUN ID for the path and look it up in the LUN list for the 3809991554f2SKenneth D. Merry * target. 3810991554f2SKenneth D. Merry */ 3811991554f2SKenneth D. Merry sassc = (struct mprsas_softc *)done_ccb->ccb_h.ppriv_ptr1; 38127a2a6a1aSStephen McConnell KASSERT(done_ccb->ccb_h.target_id < sassc->maxtargets, ("Target %d out " 38137a2a6a1aSStephen McConnell "of bounds in mprsas_read_cap_done\n", done_ccb->ccb_h.target_id)); 3814991554f2SKenneth D. Merry target = &sassc->targets[done_ccb->ccb_h.target_id]; 3815991554f2SKenneth D. Merry SLIST_FOREACH(lun, &target->luns, lun_link) { 3816991554f2SKenneth D. Merry if (lun->lun_id != done_ccb->ccb_h.target_lun) 3817991554f2SKenneth D. Merry continue; 3818991554f2SKenneth D. Merry 3819991554f2SKenneth D. Merry /* 3820991554f2SKenneth D. Merry * Got the LUN in the target's LUN list. Fill it in with EEDP 3821991554f2SKenneth D. Merry * info. If the READ CAP 16 command had some SCSI error (common 3822991554f2SKenneth D. Merry * if command is not supported), mark the lun as not supporting 3823991554f2SKenneth D. Merry * EEDP and set the block size to 0. 3824991554f2SKenneth D. Merry */ 3825a2c14879SStephen McConnell if ((mprsas_get_ccbstatus(done_ccb) != CAM_REQ_CMP) || 3826a2c14879SStephen McConnell (done_ccb->csio.scsi_status != SCSI_STATUS_OK)) { 3827991554f2SKenneth D. Merry lun->eedp_formatted = FALSE; 3828991554f2SKenneth D. Merry lun->eedp_block_size = 0; 3829991554f2SKenneth D. Merry break; 3830991554f2SKenneth D. Merry } 3831991554f2SKenneth D. Merry 3832991554f2SKenneth D. Merry if (rcap_buf->protect & 0x01) { 3833a2c14879SStephen McConnell mpr_dprint(sassc->sc, MPR_INFO, "LUN %d for target ID " 3834a2c14879SStephen McConnell "%d is formatted for EEDP support.\n", 3835a2c14879SStephen McConnell done_ccb->ccb_h.target_lun, 3836991554f2SKenneth D. Merry done_ccb->ccb_h.target_id); 3837991554f2SKenneth D. Merry lun->eedp_formatted = TRUE; 3838991554f2SKenneth D. Merry lun->eedp_block_size = scsi_4btoul(rcap_buf->length); 3839991554f2SKenneth D. Merry } 3840991554f2SKenneth D. Merry break; 3841991554f2SKenneth D. Merry } 3842991554f2SKenneth D. Merry 3843991554f2SKenneth D. Merry // Finished with this CCB and path. 3844991554f2SKenneth D. Merry free(rcap_buf, M_MPR); 3845991554f2SKenneth D. Merry xpt_free_path(done_ccb->ccb_h.path); 3846991554f2SKenneth D. Merry xpt_free_ccb(done_ccb); 3847991554f2SKenneth D. Merry } 3848991554f2SKenneth D. Merry #endif /* (__FreeBSD_version < 901503) || \ 3849991554f2SKenneth D. Merry ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) */ 3850991554f2SKenneth D. Merry 3851a2c14879SStephen McConnell void 3852a2c14879SStephen McConnell mprsas_prepare_for_tm(struct mpr_softc *sc, struct mpr_command *tm, 3853a2c14879SStephen McConnell struct mprsas_target *target, lun_id_t lun_id) 3854a2c14879SStephen McConnell { 3855a2c14879SStephen McConnell union ccb *ccb; 3856a2c14879SStephen McConnell path_id_t path_id; 3857a2c14879SStephen McConnell 3858a2c14879SStephen McConnell /* 3859a2c14879SStephen McConnell * Set the INRESET flag for this target so that no I/O will be sent to 3860a2c14879SStephen McConnell * the target until the reset has completed. If an I/O request does 3861a2c14879SStephen McConnell * happen, the devq will be frozen. The CCB holds the path which is 3862a2c14879SStephen McConnell * used to release the devq. The devq is released and the CCB is freed 3863a2c14879SStephen McConnell * when the TM completes. 3864a2c14879SStephen McConnell */ 3865a2c14879SStephen McConnell ccb = xpt_alloc_ccb_nowait(); 3866a2c14879SStephen McConnell if (ccb) { 3867a2c14879SStephen McConnell path_id = cam_sim_path(sc->sassc->sim); 3868a2c14879SStephen McConnell if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, path_id, 3869a2c14879SStephen McConnell target->tid, lun_id) != CAM_REQ_CMP) { 3870a2c14879SStephen McConnell xpt_free_ccb(ccb); 3871a2c14879SStephen McConnell } else { 3872a2c14879SStephen McConnell tm->cm_ccb = ccb; 3873a2c14879SStephen McConnell tm->cm_targ = target; 3874a2c14879SStephen McConnell target->flags |= MPRSAS_TARGET_INRESET; 3875a2c14879SStephen McConnell } 3876a2c14879SStephen McConnell } 3877a2c14879SStephen McConnell } 3878a2c14879SStephen McConnell 3879991554f2SKenneth D. Merry int 3880991554f2SKenneth D. Merry mprsas_startup(struct mpr_softc *sc) 3881991554f2SKenneth D. Merry { 3882991554f2SKenneth D. Merry /* 3883991554f2SKenneth D. Merry * Send the port enable message and set the wait_for_port_enable flag. 3884991554f2SKenneth D. Merry * This flag helps to keep the simq frozen until all discovery events 3885991554f2SKenneth D. Merry * are processed. 3886991554f2SKenneth D. Merry */ 3887991554f2SKenneth D. Merry sc->wait_for_port_enable = 1; 3888991554f2SKenneth D. Merry mprsas_send_portenable(sc); 3889991554f2SKenneth D. Merry return (0); 3890991554f2SKenneth D. Merry } 3891991554f2SKenneth D. Merry 3892991554f2SKenneth D. Merry static int 3893991554f2SKenneth D. Merry mprsas_send_portenable(struct mpr_softc *sc) 3894991554f2SKenneth D. Merry { 3895991554f2SKenneth D. Merry MPI2_PORT_ENABLE_REQUEST *request; 3896991554f2SKenneth D. Merry struct mpr_command *cm; 3897991554f2SKenneth D. Merry 3898991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 3899991554f2SKenneth D. Merry 3900991554f2SKenneth D. Merry if ((cm = mpr_alloc_command(sc)) == NULL) 3901991554f2SKenneth D. Merry return (EBUSY); 3902991554f2SKenneth D. Merry request = (MPI2_PORT_ENABLE_REQUEST *)cm->cm_req; 3903991554f2SKenneth D. Merry request->Function = MPI2_FUNCTION_PORT_ENABLE; 3904991554f2SKenneth D. Merry request->MsgFlags = 0; 3905991554f2SKenneth D. Merry request->VP_ID = 0; 3906991554f2SKenneth D. Merry cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 3907991554f2SKenneth D. Merry cm->cm_complete = mprsas_portenable_complete; 3908991554f2SKenneth D. Merry cm->cm_data = NULL; 3909991554f2SKenneth D. Merry cm->cm_sge = NULL; 3910991554f2SKenneth D. Merry 3911991554f2SKenneth D. Merry mpr_map_command(sc, cm); 3912991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, 3913991554f2SKenneth D. Merry "mpr_send_portenable finished cm %p req %p complete %p\n", 3914991554f2SKenneth D. Merry cm, cm->cm_req, cm->cm_complete); 3915991554f2SKenneth D. Merry return (0); 3916991554f2SKenneth D. Merry } 3917991554f2SKenneth D. Merry 3918991554f2SKenneth D. Merry static void 3919991554f2SKenneth D. Merry mprsas_portenable_complete(struct mpr_softc *sc, struct mpr_command *cm) 3920991554f2SKenneth D. Merry { 3921991554f2SKenneth D. Merry MPI2_PORT_ENABLE_REPLY *reply; 3922991554f2SKenneth D. Merry struct mprsas_softc *sassc; 3923991554f2SKenneth D. Merry 3924991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 3925991554f2SKenneth D. Merry sassc = sc->sassc; 3926991554f2SKenneth D. Merry 3927991554f2SKenneth D. Merry /* 3928991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 3929991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 3930991554f2SKenneth D. Merry * port enable commands don't have S/G lists. 3931991554f2SKenneth D. Merry */ 3932991554f2SKenneth D. Merry if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 3933991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for port enable! " 3934991554f2SKenneth D. Merry "This should not happen!\n", __func__, cm->cm_flags); 3935991554f2SKenneth D. Merry } 3936991554f2SKenneth D. Merry 3937991554f2SKenneth D. Merry reply = (MPI2_PORT_ENABLE_REPLY *)cm->cm_reply; 3938991554f2SKenneth D. Merry if (reply == NULL) 3939991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "Portenable NULL reply\n"); 3940991554f2SKenneth D. Merry else if (le16toh(reply->IOCStatus & MPI2_IOCSTATUS_MASK) != 3941991554f2SKenneth D. Merry MPI2_IOCSTATUS_SUCCESS) 3942991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "Portenable failed\n"); 3943991554f2SKenneth D. Merry 3944991554f2SKenneth D. Merry mpr_free_command(sc, cm); 3945991554f2SKenneth D. Merry if (sc->mpr_ich.ich_arg != NULL) { 3946991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "disestablish config intrhook\n"); 3947991554f2SKenneth D. Merry config_intrhook_disestablish(&sc->mpr_ich); 3948991554f2SKenneth D. Merry sc->mpr_ich.ich_arg = NULL; 3949991554f2SKenneth D. Merry } 3950991554f2SKenneth D. Merry 3951991554f2SKenneth D. Merry /* 3952991554f2SKenneth D. Merry * Done waiting for port enable to complete. Decrement the refcount. 3953991554f2SKenneth D. Merry * If refcount is 0, discovery is complete and a rescan of the bus can 3954991554f2SKenneth D. Merry * take place. 3955991554f2SKenneth D. Merry */ 3956991554f2SKenneth D. Merry sc->wait_for_port_enable = 0; 3957991554f2SKenneth D. Merry sc->port_enable_complete = 1; 3958991554f2SKenneth D. Merry wakeup(&sc->port_enable_complete); 3959991554f2SKenneth D. Merry mprsas_startup_decrement(sassc); 3960991554f2SKenneth D. Merry } 3961991554f2SKenneth D. Merry 3962991554f2SKenneth D. Merry int 3963991554f2SKenneth D. Merry mprsas_check_id(struct mprsas_softc *sassc, int id) 3964991554f2SKenneth D. Merry { 3965991554f2SKenneth D. Merry struct mpr_softc *sc = sassc->sc; 3966991554f2SKenneth D. Merry char *ids; 3967991554f2SKenneth D. Merry char *name; 3968991554f2SKenneth D. Merry 3969991554f2SKenneth D. Merry ids = &sc->exclude_ids[0]; 3970991554f2SKenneth D. Merry while((name = strsep(&ids, ",")) != NULL) { 3971991554f2SKenneth D. Merry if (name[0] == '\0') 3972991554f2SKenneth D. Merry continue; 3973991554f2SKenneth D. Merry if (strtol(name, NULL, 0) == (long)id) 3974991554f2SKenneth D. Merry return (1); 3975991554f2SKenneth D. Merry } 3976991554f2SKenneth D. Merry 3977991554f2SKenneth D. Merry return (0); 3978991554f2SKenneth D. Merry } 3979a2c14879SStephen McConnell 3980a2c14879SStephen McConnell void 3981a2c14879SStephen McConnell mprsas_realloc_targets(struct mpr_softc *sc, int maxtargets) 3982a2c14879SStephen McConnell { 3983a2c14879SStephen McConnell struct mprsas_softc *sassc; 3984a2c14879SStephen McConnell struct mprsas_lun *lun, *lun_tmp; 3985a2c14879SStephen McConnell struct mprsas_target *targ; 3986a2c14879SStephen McConnell int i; 3987a2c14879SStephen McConnell 3988a2c14879SStephen McConnell sassc = sc->sassc; 3989a2c14879SStephen McConnell /* 3990a2c14879SStephen McConnell * The number of targets is based on IOC Facts, so free all of 3991a2c14879SStephen McConnell * the allocated LUNs for each target and then the target buffer 3992a2c14879SStephen McConnell * itself. 3993a2c14879SStephen McConnell */ 3994a2c14879SStephen McConnell for (i=0; i< maxtargets; i++) { 3995a2c14879SStephen McConnell targ = &sassc->targets[i]; 3996a2c14879SStephen McConnell SLIST_FOREACH_SAFE(lun, &targ->luns, lun_link, lun_tmp) { 3997a2c14879SStephen McConnell free(lun, M_MPR); 3998a2c14879SStephen McConnell } 3999a2c14879SStephen McConnell } 4000a2c14879SStephen McConnell free(sassc->targets, M_MPR); 4001a2c14879SStephen McConnell 4002a2c14879SStephen McConnell sassc->targets = malloc(sizeof(struct mprsas_target) * maxtargets, 4003a2c14879SStephen McConnell M_MPR, M_WAITOK|M_ZERO); 4004a2c14879SStephen McConnell if (!sassc->targets) { 4005a2c14879SStephen McConnell panic("%s failed to alloc targets with error %d\n", 4006a2c14879SStephen McConnell __func__, ENOMEM); 4007a2c14879SStephen McConnell } 4008a2c14879SStephen McConnell } 4009