1c12c399aSSascha Wildner /*- 2c12c399aSSascha Wildner * Copyright (c) 2009 Yahoo! Inc. 3c12c399aSSascha Wildner * All rights reserved. 4c12c399aSSascha Wildner * 5c12c399aSSascha Wildner * Redistribution and use in source and binary forms, with or without 6c12c399aSSascha Wildner * modification, are permitted provided that the following conditions 7c12c399aSSascha Wildner * are met: 8c12c399aSSascha Wildner * 1. Redistributions of source code must retain the above copyright 9c12c399aSSascha Wildner * notice, this list of conditions and the following disclaimer. 10c12c399aSSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright 11c12c399aSSascha Wildner * notice, this list of conditions and the following disclaimer in the 12c12c399aSSascha Wildner * documentation and/or other materials provided with the distribution. 13c12c399aSSascha Wildner * 14c12c399aSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15c12c399aSSascha Wildner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16c12c399aSSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17c12c399aSSascha Wildner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18c12c399aSSascha Wildner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19c12c399aSSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20c12c399aSSascha Wildner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21c12c399aSSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22c12c399aSSascha Wildner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23c12c399aSSascha Wildner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24c12c399aSSascha Wildner * SUCH DAMAGE. 25c12c399aSSascha Wildner */ 26c12c399aSSascha Wildner /*- 27c12c399aSSascha Wildner * Copyright (c) 2011 LSI Corp. 28c12c399aSSascha Wildner * All rights reserved. 29c12c399aSSascha Wildner * 30c12c399aSSascha Wildner * Redistribution and use in source and binary forms, with or without 31c12c399aSSascha Wildner * modification, are permitted provided that the following conditions 32c12c399aSSascha Wildner * are met: 33c12c399aSSascha Wildner * 1. Redistributions of source code must retain the above copyright 34c12c399aSSascha Wildner * notice, this list of conditions and the following disclaimer. 35c12c399aSSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright 36c12c399aSSascha Wildner * notice, this list of conditions and the following disclaimer in the 37c12c399aSSascha Wildner * documentation and/or other materials provided with the distribution. 38c12c399aSSascha Wildner * 39c12c399aSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 40c12c399aSSascha Wildner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41c12c399aSSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 42c12c399aSSascha Wildner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 43c12c399aSSascha Wildner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 44c12c399aSSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 45c12c399aSSascha Wildner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 46c12c399aSSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 47c12c399aSSascha Wildner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 48c12c399aSSascha Wildner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 49c12c399aSSascha Wildner * SUCH DAMAGE. 50c12c399aSSascha Wildner * 51c12c399aSSascha Wildner * LSI MPT-Fusion Host Adapter FreeBSD 52c12c399aSSascha Wildner * 53c12c399aSSascha Wildner * $FreeBSD: src/sys/dev/mps/mps_sas.c,v 1.16 2012/01/26 18:17:21 ken Exp $ 54c12c399aSSascha Wildner */ 55c12c399aSSascha Wildner 56c12c399aSSascha Wildner /* Communications core for LSI MPT2 */ 57c12c399aSSascha Wildner 58c12c399aSSascha Wildner /* TODO Move headers to mpsvar */ 59c12c399aSSascha Wildner #include <sys/types.h> 60c12c399aSSascha Wildner #include <sys/param.h> 61c12c399aSSascha Wildner #include <sys/systm.h> 62c12c399aSSascha Wildner #include <sys/kernel.h> 63c12c399aSSascha Wildner #include <sys/module.h> 64c12c399aSSascha Wildner #include <sys/bus.h> 65c12c399aSSascha Wildner #include <sys/conf.h> 66c12c399aSSascha Wildner #include <sys/eventhandler.h> 67c12c399aSSascha Wildner #include <sys/globaldata.h> 68c12c399aSSascha Wildner #include <sys/bio.h> 69c12c399aSSascha Wildner #include <sys/malloc.h> 70c12c399aSSascha Wildner #include <sys/uio.h> 71c12c399aSSascha Wildner #include <sys/sysctl.h> 72c12c399aSSascha Wildner #include <sys/endian.h> 73c12c399aSSascha Wildner #include <sys/queue.h> 74c12c399aSSascha Wildner #include <sys/kthread.h> 75c12c399aSSascha Wildner #include <sys/taskqueue.h> 76c12c399aSSascha Wildner #include <sys/sbuf.h> 77c12c399aSSascha Wildner 78c12c399aSSascha Wildner #include <sys/rman.h> 79c12c399aSSascha Wildner 80c12c399aSSascha Wildner #include <machine/stdarg.h> 81c12c399aSSascha Wildner 82c12c399aSSascha Wildner #include <bus/cam/cam.h> 83c12c399aSSascha Wildner #include <bus/cam/cam_ccb.h> 84c12c399aSSascha Wildner #include <bus/cam/cam_xpt.h> 85c12c399aSSascha Wildner #include <bus/cam/cam_debug.h> 86c12c399aSSascha Wildner #include <bus/cam/cam_sim.h> 87c12c399aSSascha Wildner #include <bus/cam/cam_xpt_sim.h> 88c12c399aSSascha Wildner #include <bus/cam/cam_xpt_periph.h> 89c12c399aSSascha Wildner #include <bus/cam/cam_periph.h> 90c12c399aSSascha Wildner #include <bus/cam/scsi/scsi_all.h> 91c12c399aSSascha Wildner #include <bus/cam/scsi/scsi_message.h> 92c12c399aSSascha Wildner #if 0 /* XXX __FreeBSD_version >= 900026 */ 93c12c399aSSascha Wildner #include <bus/cam/scsi/smp_all.h> 94c12c399aSSascha Wildner #endif 95c12c399aSSascha Wildner 96c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2_type.h> 97c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2.h> 98c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2_ioc.h> 99c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2_sas.h> 100c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2_cnfg.h> 101c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2_init.h> 102c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2_tool.h> 103c12c399aSSascha Wildner #include <dev/raid/mps/mps_ioctl.h> 104c12c399aSSascha Wildner #include <dev/raid/mps/mpsvar.h> 105c12c399aSSascha Wildner #include <dev/raid/mps/mps_table.h> 106c12c399aSSascha Wildner #include <dev/raid/mps/mps_sas.h> 107c12c399aSSascha Wildner 108c12c399aSSascha Wildner #define MPSSAS_DISCOVERY_TIMEOUT 20 109c12c399aSSascha Wildner #define MPSSAS_MAX_DISCOVERY_TIMEOUTS 10 /* 200 seconds */ 110c12c399aSSascha Wildner 111c12c399aSSascha Wildner /* 112c12c399aSSascha Wildner * static array to check SCSI OpCode for EEDP protection bits 113c12c399aSSascha Wildner */ 114c12c399aSSascha Wildner #define PRO_R MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP 115c12c399aSSascha Wildner #define PRO_W MPI2_SCSIIO_EEDPFLAGS_INSERT_OP 116c12c399aSSascha Wildner #define PRO_V MPI2_SCSIIO_EEDPFLAGS_INSERT_OP 117c12c399aSSascha Wildner static uint8_t op_code_prot[256] = { 118c12c399aSSascha Wildner 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 119c12c399aSSascha Wildner 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120c12c399aSSascha Wildner 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, 121c12c399aSSascha Wildner 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122c12c399aSSascha Wildner 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123c12c399aSSascha Wildner 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124c12c399aSSascha Wildner 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125c12c399aSSascha Wildner 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 126c12c399aSSascha Wildner 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, 127c12c399aSSascha Wildner 0, 0, 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128c12c399aSSascha Wildner 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, 129c12c399aSSascha Wildner 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130c12c399aSSascha Wildner 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131c12c399aSSascha Wildner 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132c12c399aSSascha Wildner 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 133c12c399aSSascha Wildner 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 134c12c399aSSascha Wildner }; 135c12c399aSSascha Wildner 136c12c399aSSascha Wildner MALLOC_DEFINE(M_MPSSAS, "MPSSAS", "MPS SAS memory"); 137c12c399aSSascha Wildner 138c12c399aSSascha Wildner static struct mpssas_target * mpssas_find_target_by_handle(struct mpssas_softc *, int, uint16_t); 13936fe16feSSascha Wildner static void mpssas_log_command(struct mps_command *, const char *, ...) 14036fe16feSSascha Wildner __printflike(2, 3); 141c12c399aSSascha Wildner #if 0 /* XXX unused */ 142c12c399aSSascha Wildner static void mpssas_discovery_timeout(void *data); 143c12c399aSSascha Wildner #endif 144c12c399aSSascha Wildner static void mpssas_remove_device(struct mps_softc *, struct mps_command *); 145c12c399aSSascha Wildner static void mpssas_remove_complete(struct mps_softc *, struct mps_command *); 146c12c399aSSascha Wildner static void mpssas_action(struct cam_sim *sim, union ccb *ccb); 147c12c399aSSascha Wildner static void mpssas_poll(struct cam_sim *sim); 148c12c399aSSascha Wildner static void mpssas_scsiio_timeout(void *data); 149c12c399aSSascha Wildner static void mpssas_abort_complete(struct mps_softc *sc, struct mps_command *cm); 150c12c399aSSascha Wildner static void mpssas_direct_drive_io(struct mpssas_softc *sassc, 151c12c399aSSascha Wildner struct mps_command *cm, union ccb *ccb); 152c12c399aSSascha Wildner static void mpssas_action_scsiio(struct mpssas_softc *, union ccb *); 153c12c399aSSascha Wildner static void mpssas_scsiio_complete(struct mps_softc *, struct mps_command *); 154c12c399aSSascha Wildner static void mpssas_action_resetdev(struct mpssas_softc *, union ccb *); 155c12c399aSSascha Wildner #if __FreeBSD_version >= 900026 156c12c399aSSascha Wildner static void mpssas_smpio_complete(struct mps_softc *sc, struct mps_command *cm); 157c12c399aSSascha Wildner static void mpssas_send_smpcmd(struct mpssas_softc *sassc, union ccb *ccb, 158c12c399aSSascha Wildner uint64_t sasaddr); 159c12c399aSSascha Wildner static void mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb); 160c12c399aSSascha Wildner #endif //FreeBSD_version >= 900026 161c12c399aSSascha Wildner static void mpssas_resetdev_complete(struct mps_softc *, struct mps_command *); 162c12c399aSSascha Wildner static int mpssas_send_abort(struct mps_softc *sc, struct mps_command *tm, struct mps_command *cm); 163c12c399aSSascha Wildner static int mpssas_send_reset(struct mps_softc *sc, struct mps_command *tm, uint8_t type); 164c12c399aSSascha Wildner static void mpssas_rescan(struct mpssas_softc *sassc, union ccb *ccb); 165c12c399aSSascha Wildner static void mpssas_rescan_done(struct cam_periph *periph, union ccb *done_ccb); 166c12c399aSSascha Wildner static void mpssas_scanner_thread(void *arg); 167c12c399aSSascha Wildner #if __FreeBSD_version >= 1000006 168c12c399aSSascha Wildner static void mpssas_async(void *callback_arg, uint32_t code, 169c12c399aSSascha Wildner struct cam_path *path, void *arg); 170c12c399aSSascha Wildner #else 171c12c399aSSascha Wildner static void mpssas_check_eedp(struct mpssas_softc *sassc); 172c12c399aSSascha Wildner static void mpssas_read_cap_done(struct cam_periph *periph, union ccb *done_ccb); 173c12c399aSSascha Wildner #endif 174c12c399aSSascha Wildner static int mpssas_send_portenable(struct mps_softc *sc); 175c12c399aSSascha Wildner static void mpssas_portenable_complete(struct mps_softc *sc, 176c12c399aSSascha Wildner struct mps_command *cm); 177c12c399aSSascha Wildner 178c12c399aSSascha Wildner static struct mpssas_target * 179c12c399aSSascha Wildner mpssas_find_target_by_handle(struct mpssas_softc *sassc, int start, uint16_t handle) 180c12c399aSSascha Wildner { 181c12c399aSSascha Wildner struct mpssas_target *target; 182c12c399aSSascha Wildner int i; 183c12c399aSSascha Wildner 184c12c399aSSascha Wildner for (i = start; i < sassc->sc->facts->MaxTargets; i++) { 185c12c399aSSascha Wildner target = &sassc->targets[i]; 186c12c399aSSascha Wildner if (target->handle == handle) 187c12c399aSSascha Wildner return (target); 188c12c399aSSascha Wildner } 189c12c399aSSascha Wildner 190c12c399aSSascha Wildner return (NULL); 191c12c399aSSascha Wildner } 192c12c399aSSascha Wildner 193c12c399aSSascha Wildner /* we need to freeze the simq during attach and diag reset, to avoid failing 194c12c399aSSascha Wildner * commands before device handles have been found by discovery. Since 195c12c399aSSascha Wildner * discovery involves reading config pages and possibly sending commands, 196c12c399aSSascha Wildner * discovery actions may continue even after we receive the end of discovery 197c12c399aSSascha Wildner * event, so refcount discovery actions instead of assuming we can unfreeze 198c12c399aSSascha Wildner * the simq when we get the event. 199c12c399aSSascha Wildner */ 200c12c399aSSascha Wildner void 201c12c399aSSascha Wildner mpssas_startup_increment(struct mpssas_softc *sassc) 202c12c399aSSascha Wildner { 203c12c399aSSascha Wildner if ((sassc->flags & MPSSAS_IN_STARTUP) != 0) { 204c12c399aSSascha Wildner if (sassc->startup_refcount++ == 0) { 205c12c399aSSascha Wildner /* just starting, freeze the simq */ 206c12c399aSSascha Wildner mps_dprint(sassc->sc, MPS_INFO, 207c12c399aSSascha Wildner "%s freezing simq\n", __func__); 208c12c399aSSascha Wildner xpt_freeze_simq(sassc->sim, 1); 209c12c399aSSascha Wildner } 210c12c399aSSascha Wildner mps_dprint(sassc->sc, MPS_TRACE, "%s refcount %u\n", __func__, 211c12c399aSSascha Wildner sassc->startup_refcount); 212c12c399aSSascha Wildner } 213c12c399aSSascha Wildner } 214c12c399aSSascha Wildner 215c12c399aSSascha Wildner void 216c12c399aSSascha Wildner mpssas_startup_decrement(struct mpssas_softc *sassc) 217c12c399aSSascha Wildner { 218c12c399aSSascha Wildner if ((sassc->flags & MPSSAS_IN_STARTUP) != 0) { 219c12c399aSSascha Wildner if (--sassc->startup_refcount == 0) { 220c12c399aSSascha Wildner /* finished all discovery-related actions, release 221c12c399aSSascha Wildner * the simq and rescan for the latest topology. 222c12c399aSSascha Wildner */ 223c12c399aSSascha Wildner mps_dprint(sassc->sc, MPS_INFO, 224c12c399aSSascha Wildner "%s releasing simq\n", __func__); 225c12c399aSSascha Wildner sassc->flags &= ~MPSSAS_IN_STARTUP; 226c12c399aSSascha Wildner xpt_release_simq(sassc->sim, 1); 227c12c399aSSascha Wildner mpssas_rescan_target(sassc->sc, NULL); 228c12c399aSSascha Wildner } 229c12c399aSSascha Wildner mps_dprint(sassc->sc, MPS_TRACE, "%s refcount %u\n", __func__, 230c12c399aSSascha Wildner sassc->startup_refcount); 231c12c399aSSascha Wildner } 232c12c399aSSascha Wildner } 233c12c399aSSascha Wildner 234c12c399aSSascha Wildner /* LSI's firmware requires us to stop sending commands when we're doing task 235c12c399aSSascha Wildner * management, so refcount the TMs and keep the simq frozen when any are in 236c12c399aSSascha Wildner * use. 237c12c399aSSascha Wildner */ 238c12c399aSSascha Wildner struct mps_command * 239c12c399aSSascha Wildner mpssas_alloc_tm(struct mps_softc *sc) 240c12c399aSSascha Wildner { 241c12c399aSSascha Wildner struct mps_command *tm; 242c12c399aSSascha Wildner 243c12c399aSSascha Wildner tm = mps_alloc_high_priority_command(sc); 244c12c399aSSascha Wildner if (tm != NULL) { 245c12c399aSSascha Wildner if (sc->sassc->tm_count++ == 0) { 246c12c399aSSascha Wildner mps_printf(sc, "%s freezing simq\n", __func__); 247c12c399aSSascha Wildner xpt_freeze_simq(sc->sassc->sim, 1); 248c12c399aSSascha Wildner } 249c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, "%s tm_count %u\n", __func__, 250c12c399aSSascha Wildner sc->sassc->tm_count); 251c12c399aSSascha Wildner } 252c12c399aSSascha Wildner return tm; 253c12c399aSSascha Wildner } 254c12c399aSSascha Wildner 255c12c399aSSascha Wildner void 256c12c399aSSascha Wildner mpssas_free_tm(struct mps_softc *sc, struct mps_command *tm) 257c12c399aSSascha Wildner { 258c12c399aSSascha Wildner if (tm == NULL) 259c12c399aSSascha Wildner return; 260c12c399aSSascha Wildner 261c12c399aSSascha Wildner /* if there are no TMs in use, we can release the simq. We use our 262c12c399aSSascha Wildner * own refcount so that it's easier for a diag reset to cleanup and 263c12c399aSSascha Wildner * release the simq. 264c12c399aSSascha Wildner */ 265c12c399aSSascha Wildner if (--sc->sassc->tm_count == 0) { 266c12c399aSSascha Wildner mps_printf(sc, "%s releasing simq\n", __func__); 267c12c399aSSascha Wildner xpt_release_simq(sc->sassc->sim, 1); 268c12c399aSSascha Wildner } 269c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, "%s tm_count %u\n", __func__, 270c12c399aSSascha Wildner sc->sassc->tm_count); 271c12c399aSSascha Wildner 272c12c399aSSascha Wildner mps_free_high_priority_command(sc, tm); 273c12c399aSSascha Wildner } 274c12c399aSSascha Wildner 275c12c399aSSascha Wildner 276c12c399aSSascha Wildner void 277c12c399aSSascha Wildner mpssas_rescan_target(struct mps_softc *sc, struct mpssas_target *targ) 278c12c399aSSascha Wildner { 279c12c399aSSascha Wildner struct mpssas_softc *sassc = sc->sassc; 280c12c399aSSascha Wildner path_id_t pathid; 281c12c399aSSascha Wildner target_id_t targetid; 282c12c399aSSascha Wildner union ccb *ccb; 283c12c399aSSascha Wildner 284c12c399aSSascha Wildner pathid = cam_sim_path(sassc->sim); 285c12c399aSSascha Wildner if (targ == NULL) 286c12c399aSSascha Wildner targetid = CAM_TARGET_WILDCARD; 287c12c399aSSascha Wildner else 288c12c399aSSascha Wildner targetid = targ - sassc->targets; 289c12c399aSSascha Wildner 290c12c399aSSascha Wildner /* 291c12c399aSSascha Wildner * Allocate a CCB and schedule a rescan. 292c12c399aSSascha Wildner */ 293c12c399aSSascha Wildner ccb = kmalloc(sizeof(union ccb), M_TEMP, M_WAITOK | M_ZERO); 294c12c399aSSascha Wildner 295c12c399aSSascha Wildner if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, pathid, 296c12c399aSSascha Wildner targetid, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 297c12c399aSSascha Wildner mps_dprint(sc, MPS_FAULT, "unable to create path for rescan\n"); 298c12c399aSSascha Wildner xpt_free_ccb(ccb); 299c12c399aSSascha Wildner return; 300c12c399aSSascha Wildner } 301c12c399aSSascha Wildner 302c12c399aSSascha Wildner /* XXX Hardwired to scan the bus for now */ 303c12c399aSSascha Wildner ccb->ccb_h.func_code = XPT_SCAN_BUS; 304c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, "%s targetid %u\n", __func__, targetid); 305c12c399aSSascha Wildner mpssas_rescan(sassc, ccb); 306c12c399aSSascha Wildner } 307c12c399aSSascha Wildner 308c12c399aSSascha Wildner static void 309c12c399aSSascha Wildner mpssas_log_command(struct mps_command *cm, const char *fmt, ...) 310c12c399aSSascha Wildner { 311c12c399aSSascha Wildner struct sbuf sb; 312c12c399aSSascha Wildner __va_list ap; 313c12c399aSSascha Wildner char str[192]; 314c12c399aSSascha Wildner char path_str[64]; 315c12c399aSSascha Wildner 316c12c399aSSascha Wildner if (cm == NULL) 317c12c399aSSascha Wildner return; 318c12c399aSSascha Wildner 319c12c399aSSascha Wildner sbuf_new(&sb, str, sizeof(str), 0); 320c12c399aSSascha Wildner 321c12c399aSSascha Wildner __va_start(ap, fmt); 322c12c399aSSascha Wildner 323c12c399aSSascha Wildner if (cm->cm_ccb != NULL) { 324c12c399aSSascha Wildner xpt_path_string(cm->cm_ccb->csio.ccb_h.path, path_str, 325c12c399aSSascha Wildner sizeof(path_str)); 326c12c399aSSascha Wildner sbuf_cat(&sb, path_str); 327c12c399aSSascha Wildner if (cm->cm_ccb->ccb_h.func_code == XPT_SCSI_IO) { 328c12c399aSSascha Wildner scsi_command_string(&cm->cm_ccb->csio, &sb); 329c12c399aSSascha Wildner sbuf_printf(&sb, "length %d ", 330c12c399aSSascha Wildner cm->cm_ccb->csio.dxfer_len); 331c12c399aSSascha Wildner } 332c12c399aSSascha Wildner } 333c12c399aSSascha Wildner else { 334c12c399aSSascha Wildner sbuf_printf(&sb, "(noperiph:%s%d:%u:%u:%u): ", 335c12c399aSSascha Wildner cam_sim_name(cm->cm_sc->sassc->sim), 336c12c399aSSascha Wildner cam_sim_unit(cm->cm_sc->sassc->sim), 337c12c399aSSascha Wildner cam_sim_bus(cm->cm_sc->sassc->sim), 338c12c399aSSascha Wildner cm->cm_targ ? cm->cm_targ->tid : 0xFFFFFFFF, 339c12c399aSSascha Wildner cm->cm_lun); 340c12c399aSSascha Wildner } 341c12c399aSSascha Wildner 342c12c399aSSascha Wildner sbuf_printf(&sb, "SMID %u ", cm->cm_desc.Default.SMID); 343c12c399aSSascha Wildner sbuf_vprintf(&sb, fmt, ap); 344c12c399aSSascha Wildner sbuf_finish(&sb); 345c12c399aSSascha Wildner kprintf("%s", sbuf_data(&sb)); 346c12c399aSSascha Wildner 347c12c399aSSascha Wildner __va_end(ap); 348c12c399aSSascha Wildner } 349c12c399aSSascha Wildner 350c12c399aSSascha Wildner static void 351c12c399aSSascha Wildner mpssas_lost_target(struct mps_softc *sc, struct mpssas_target *targ) 352c12c399aSSascha Wildner { 353c12c399aSSascha Wildner struct mpssas_softc *sassc = sc->sassc; 354c12c399aSSascha Wildner path_id_t pathid = cam_sim_path(sassc->sim); 355c12c399aSSascha Wildner struct cam_path *path; 356c12c399aSSascha Wildner 357c12c399aSSascha Wildner mps_printf(sc, "%s targetid %u\n", __func__, targ->tid); 358c12c399aSSascha Wildner if (xpt_create_path(&path, NULL, pathid, targ->tid, 0) != CAM_REQ_CMP) { 359c12c399aSSascha Wildner mps_printf(sc, "unable to create path for lost target %d\n", 360c12c399aSSascha Wildner targ->tid); 361c12c399aSSascha Wildner return; 362c12c399aSSascha Wildner } 363c12c399aSSascha Wildner 364c12c399aSSascha Wildner xpt_async(AC_LOST_DEVICE, path, NULL); 365c12c399aSSascha Wildner xpt_free_path(path); 366c12c399aSSascha Wildner } 367c12c399aSSascha Wildner 368c12c399aSSascha Wildner /* 369c12c399aSSascha Wildner * The MPT2 firmware performs debounce on the link to avoid transient link 370c12c399aSSascha Wildner * errors and false removals. When it does decide that link has been lost 371c12c399aSSascha Wildner * and a device need to go away, it expects that the host will perform a 372c12c399aSSascha Wildner * target reset and then an op remove. The reset has the side-effect of 373c12c399aSSascha Wildner * aborting any outstanding requests for the device, which is required for 374c12c399aSSascha Wildner * the op-remove to succeed. It's not clear if the host should check for 375c12c399aSSascha Wildner * the device coming back alive after the reset. 376c12c399aSSascha Wildner */ 377c12c399aSSascha Wildner void 378c12c399aSSascha Wildner mpssas_prepare_remove(struct mpssas_softc *sassc, uint16_t handle) 379c12c399aSSascha Wildner { 380c12c399aSSascha Wildner MPI2_SCSI_TASK_MANAGE_REQUEST *req; 381c12c399aSSascha Wildner struct mps_softc *sc; 382c12c399aSSascha Wildner struct mps_command *cm; 383c12c399aSSascha Wildner struct mpssas_target *targ = NULL; 384c12c399aSSascha Wildner 385c12c399aSSascha Wildner mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__); 386c12c399aSSascha Wildner 387c12c399aSSascha Wildner /* 388c12c399aSSascha Wildner * If this is a WD controller, determine if the disk should be exposed 389c12c399aSSascha Wildner * to the OS or not. If disk should be exposed, return from this 390c12c399aSSascha Wildner * function without doing anything. 391c12c399aSSascha Wildner */ 392c12c399aSSascha Wildner sc = sassc->sc; 393c12c399aSSascha Wildner if ((sc->mps_flags & MPS_FLAGS_WD_AVAILABLE) && (sc->WD_hide_expose == 394c12c399aSSascha Wildner MPS_WD_EXPOSE_ALWAYS)) { 395c12c399aSSascha Wildner return; 396c12c399aSSascha Wildner } 397c12c399aSSascha Wildner 398c12c399aSSascha Wildner targ = mpssas_find_target_by_handle(sassc, 0, handle); 399c12c399aSSascha Wildner if (targ == NULL) { 400c12c399aSSascha Wildner /* FIXME: what is the action? */ 401c12c399aSSascha Wildner /* We don't know about this device? */ 402c12c399aSSascha Wildner kprintf("%s: invalid handle 0x%x \n", __func__, handle); 403c12c399aSSascha Wildner return; 404c12c399aSSascha Wildner } 405c12c399aSSascha Wildner 406c12c399aSSascha Wildner targ->flags |= MPSSAS_TARGET_INREMOVAL; 407c12c399aSSascha Wildner 408c12c399aSSascha Wildner cm = mpssas_alloc_tm(sc); 409c12c399aSSascha Wildner if (cm == NULL) { 410c12c399aSSascha Wildner mps_printf(sc, "%s: command alloc failure\n", __func__); 411c12c399aSSascha Wildner return; 412c12c399aSSascha Wildner } 413c12c399aSSascha Wildner 414c12c399aSSascha Wildner mpssas_lost_target(sc, targ); 415c12c399aSSascha Wildner 416c12c399aSSascha Wildner req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; 417c12c399aSSascha Wildner memset(req, 0, sizeof(*req)); 418c12c399aSSascha Wildner req->DevHandle = targ->handle; 419c12c399aSSascha Wildner req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 420c12c399aSSascha Wildner req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; 421c12c399aSSascha Wildner 422c12c399aSSascha Wildner /* SAS Hard Link Reset / SATA Link Reset */ 423c12c399aSSascha Wildner req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; 424c12c399aSSascha Wildner 425c12c399aSSascha Wildner cm->cm_targ = targ; 426c12c399aSSascha Wildner cm->cm_data = NULL; 427c12c399aSSascha Wildner cm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 428c12c399aSSascha Wildner cm->cm_complete = mpssas_remove_device; 429c12c399aSSascha Wildner cm->cm_complete_data = (void *)(uintptr_t)handle; 430c12c399aSSascha Wildner mps_map_command(sc, cm); 431c12c399aSSascha Wildner } 432c12c399aSSascha Wildner 433c12c399aSSascha Wildner static void 434c12c399aSSascha Wildner mpssas_remove_device(struct mps_softc *sc, struct mps_command *tm) 435c12c399aSSascha Wildner { 436c12c399aSSascha Wildner MPI2_SCSI_TASK_MANAGE_REPLY *reply; 437c12c399aSSascha Wildner MPI2_SAS_IOUNIT_CONTROL_REQUEST *req; 438c12c399aSSascha Wildner struct mpssas_target *targ; 439c12c399aSSascha Wildner struct mps_command *next_cm; 440c12c399aSSascha Wildner uint16_t handle; 441c12c399aSSascha Wildner 442c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, "%s\n", __func__); 443c12c399aSSascha Wildner 444c12c399aSSascha Wildner reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 445c12c399aSSascha Wildner handle = (uint16_t)(uintptr_t)tm->cm_complete_data; 446c12c399aSSascha Wildner targ = tm->cm_targ; 447c12c399aSSascha Wildner 448c12c399aSSascha Wildner /* 449c12c399aSSascha Wildner * Currently there should be no way we can hit this case. It only 450c12c399aSSascha Wildner * happens when we have a failure to allocate chain frames, and 451c12c399aSSascha Wildner * task management commands don't have S/G lists. 452c12c399aSSascha Wildner */ 453c12c399aSSascha Wildner if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { 454c12c399aSSascha Wildner mps_printf(sc, "%s: cm_flags = %#x for remove of handle %#04x! " 455c12c399aSSascha Wildner "This should not happen!\n", __func__, tm->cm_flags, 456c12c399aSSascha Wildner handle); 457c12c399aSSascha Wildner mpssas_free_tm(sc, tm); 458c12c399aSSascha Wildner return; 459c12c399aSSascha Wildner } 460c12c399aSSascha Wildner 461c12c399aSSascha Wildner if (reply == NULL) { 462c12c399aSSascha Wildner /* XXX retry the remove after the diag reset completes? */ 463c12c399aSSascha Wildner mps_printf(sc, "%s NULL reply reseting device 0x%04x\n", 464c12c399aSSascha Wildner __func__, handle); 465c12c399aSSascha Wildner mpssas_free_tm(sc, tm); 466c12c399aSSascha Wildner return; 467c12c399aSSascha Wildner } 468c12c399aSSascha Wildner 469c12c399aSSascha Wildner if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) { 470c12c399aSSascha Wildner mps_printf(sc, "IOCStatus = 0x%x while resetting device 0x%x\n", 471c12c399aSSascha Wildner reply->IOCStatus, handle); 472c12c399aSSascha Wildner mpssas_free_tm(sc, tm); 473c12c399aSSascha Wildner return; 474c12c399aSSascha Wildner } 475c12c399aSSascha Wildner 476c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, "Reset aborted %u commands\n", 47790ff74f1SSascha Wildner reply->TerminationCount); 478c12c399aSSascha Wildner mps_free_reply(sc, tm->cm_reply_data); 479c12c399aSSascha Wildner tm->cm_reply = NULL; /* Ensures the the reply won't get re-freed */ 480c12c399aSSascha Wildner 481c12c399aSSascha Wildner /* Reuse the existing command */ 482c12c399aSSascha Wildner req = (MPI2_SAS_IOUNIT_CONTROL_REQUEST *)tm->cm_req; 483c12c399aSSascha Wildner memset(req, 0, sizeof(*req)); 484c12c399aSSascha Wildner req->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; 485c12c399aSSascha Wildner req->Operation = MPI2_SAS_OP_REMOVE_DEVICE; 486c12c399aSSascha Wildner req->DevHandle = handle; 487c12c399aSSascha Wildner tm->cm_data = NULL; 488c12c399aSSascha Wildner tm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 489c12c399aSSascha Wildner tm->cm_complete = mpssas_remove_complete; 490c12c399aSSascha Wildner tm->cm_complete_data = (void *)(uintptr_t)handle; 491c12c399aSSascha Wildner 492c12c399aSSascha Wildner mps_map_command(sc, tm); 493c12c399aSSascha Wildner 494c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, "clearing target %u handle 0x%04x\n", 495c12c399aSSascha Wildner targ->tid, handle); 496c12c399aSSascha Wildner TAILQ_FOREACH_MUTABLE(tm, &targ->commands, cm_link, next_cm) { 497c12c399aSSascha Wildner union ccb *ccb; 498c12c399aSSascha Wildner 499c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, "Completing missed command %p\n", tm); 500c12c399aSSascha Wildner ccb = tm->cm_complete_data; 501c12c399aSSascha Wildner ccb->ccb_h.status = CAM_DEV_NOT_THERE; 502c12c399aSSascha Wildner mpssas_scsiio_complete(sc, tm); 503c12c399aSSascha Wildner } 504c12c399aSSascha Wildner } 505c12c399aSSascha Wildner 506c12c399aSSascha Wildner static void 507c12c399aSSascha Wildner mpssas_remove_complete(struct mps_softc *sc, struct mps_command *tm) 508c12c399aSSascha Wildner { 509c12c399aSSascha Wildner MPI2_SAS_IOUNIT_CONTROL_REPLY *reply; 510c12c399aSSascha Wildner uint16_t handle; 511c12c399aSSascha Wildner struct mpssas_target *targ; 512c12c399aSSascha Wildner 513c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, "%s\n", __func__); 514c12c399aSSascha Wildner 515c12c399aSSascha Wildner reply = (MPI2_SAS_IOUNIT_CONTROL_REPLY *)tm->cm_reply; 516c12c399aSSascha Wildner handle = (uint16_t)(uintptr_t)tm->cm_complete_data; 517c12c399aSSascha Wildner 518c12c399aSSascha Wildner /* 519c12c399aSSascha Wildner * Currently there should be no way we can hit this case. It only 520c12c399aSSascha Wildner * happens when we have a failure to allocate chain frames, and 521c12c399aSSascha Wildner * task management commands don't have S/G lists. 522c12c399aSSascha Wildner */ 523c12c399aSSascha Wildner if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { 524c12c399aSSascha Wildner mps_printf(sc, "%s: cm_flags = %#x for remove of handle %#04x! " 525c12c399aSSascha Wildner "This should not happen!\n", __func__, tm->cm_flags, 526c12c399aSSascha Wildner handle); 527c12c399aSSascha Wildner mpssas_free_tm(sc, tm); 528c12c399aSSascha Wildner return; 529c12c399aSSascha Wildner } 530c12c399aSSascha Wildner 531c12c399aSSascha Wildner if (reply == NULL) { 532c12c399aSSascha Wildner /* most likely a chip reset */ 533c12c399aSSascha Wildner mps_printf(sc, "%s NULL reply removing device 0x%04x\n", 534c12c399aSSascha Wildner __func__, handle); 535c12c399aSSascha Wildner mpssas_free_tm(sc, tm); 536c12c399aSSascha Wildner return; 537c12c399aSSascha Wildner } 538c12c399aSSascha Wildner 539c12c399aSSascha Wildner mps_printf(sc, "%s on handle 0x%04x, IOCStatus= 0x%x\n", __func__, 540c12c399aSSascha Wildner handle, reply->IOCStatus); 541c12c399aSSascha Wildner 542c12c399aSSascha Wildner /* 543c12c399aSSascha Wildner * Don't clear target if remove fails because things will get confusing. 544c12c399aSSascha Wildner * Leave the devname and sasaddr intact so that we know to avoid reusing 545c12c399aSSascha Wildner * this target id if possible, and so we can assign the same target id 546c12c399aSSascha Wildner * to this device if it comes back in the future. 547c12c399aSSascha Wildner */ 548c12c399aSSascha Wildner if (reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) { 549c12c399aSSascha Wildner targ = tm->cm_targ; 550c12c399aSSascha Wildner targ->handle = 0x0; 551c12c399aSSascha Wildner targ->encl_handle = 0x0; 552c12c399aSSascha Wildner targ->encl_slot = 0x0; 553c12c399aSSascha Wildner targ->exp_dev_handle = 0x0; 554c12c399aSSascha Wildner targ->phy_num = 0x0; 555c12c399aSSascha Wildner targ->linkrate = 0x0; 556c12c399aSSascha Wildner targ->devinfo = 0x0; 557c12c399aSSascha Wildner } 558c12c399aSSascha Wildner 559c12c399aSSascha Wildner mpssas_free_tm(sc, tm); 560c12c399aSSascha Wildner } 561c12c399aSSascha Wildner 562c12c399aSSascha Wildner static int 563c12c399aSSascha Wildner mpssas_register_events(struct mps_softc *sc) 564c12c399aSSascha Wildner { 565c12c399aSSascha Wildner uint8_t events[16]; 566c12c399aSSascha Wildner 567c12c399aSSascha Wildner bzero(events, 16); 568c12c399aSSascha Wildner setbit(events, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE); 569c12c399aSSascha Wildner setbit(events, MPI2_EVENT_SAS_DISCOVERY); 570c12c399aSSascha Wildner setbit(events, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE); 571c12c399aSSascha Wildner setbit(events, MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE); 572c12c399aSSascha Wildner setbit(events, MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW); 573c12c399aSSascha Wildner setbit(events, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST); 574c12c399aSSascha Wildner setbit(events, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE); 575c12c399aSSascha Wildner setbit(events, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST); 576c12c399aSSascha Wildner setbit(events, MPI2_EVENT_IR_VOLUME); 577c12c399aSSascha Wildner setbit(events, MPI2_EVENT_IR_PHYSICAL_DISK); 578c12c399aSSascha Wildner setbit(events, MPI2_EVENT_IR_OPERATION_STATUS); 579c12c399aSSascha Wildner setbit(events, MPI2_EVENT_LOG_ENTRY_ADDED); 580c12c399aSSascha Wildner 581c12c399aSSascha Wildner mps_register_events(sc, events, mpssas_evt_handler, NULL, 582c12c399aSSascha Wildner &sc->sassc->mpssas_eh); 583c12c399aSSascha Wildner 584c12c399aSSascha Wildner return (0); 585c12c399aSSascha Wildner } 586c12c399aSSascha Wildner 587c12c399aSSascha Wildner int 588c12c399aSSascha Wildner mps_attach_sas(struct mps_softc *sc) 589c12c399aSSascha Wildner { 590c12c399aSSascha Wildner struct mpssas_softc *sassc; 591c12c399aSSascha Wildner #if __FreeBSD_version >= 1000006 592c12c399aSSascha Wildner cam_status status; 593c12c399aSSascha Wildner #endif 594c12c399aSSascha Wildner int unit, error = 0; 595c12c399aSSascha Wildner 596c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, "%s\n", __func__); 597c12c399aSSascha Wildner 598c12c399aSSascha Wildner sassc = kmalloc(sizeof(struct mpssas_softc), M_MPT2, M_WAITOK|M_ZERO); 599c12c399aSSascha Wildner sassc->targets = kmalloc(sizeof(struct mpssas_target) * 600c12c399aSSascha Wildner sc->facts->MaxTargets, M_MPT2, M_WAITOK|M_ZERO); 601c12c399aSSascha Wildner sc->sassc = sassc; 602c12c399aSSascha Wildner sassc->sc = sc; 603c12c399aSSascha Wildner 604c12c399aSSascha Wildner if ((sassc->devq = cam_simq_alloc(sc->num_reqs)) == NULL) { 605c12c399aSSascha Wildner mps_dprint(sc, MPS_FAULT, "Cannot allocate SIMQ\n"); 606c12c399aSSascha Wildner error = ENOMEM; 607c12c399aSSascha Wildner goto out; 608c12c399aSSascha Wildner } 609c12c399aSSascha Wildner 610c12c399aSSascha Wildner unit = device_get_unit(sc->mps_dev); 611c12c399aSSascha Wildner sassc->sim = cam_sim_alloc(mpssas_action, mpssas_poll, "mps", sassc, 612c12c399aSSascha Wildner unit, &sc->mps_lock, sc->num_reqs, sc->num_reqs, sassc->devq); 613c12c399aSSascha Wildner if (sassc->sim == NULL) { 614c12c399aSSascha Wildner mps_dprint(sc, MPS_FAULT, "Cannot allocate SIM\n"); 615c12c399aSSascha Wildner error = EINVAL; 616c12c399aSSascha Wildner goto out; 617c12c399aSSascha Wildner } 618c12c399aSSascha Wildner 619c12c399aSSascha Wildner TAILQ_INIT(&sassc->ev_queue); 620c12c399aSSascha Wildner 621c12c399aSSascha Wildner /* Initialize taskqueue for Event Handling */ 622c12c399aSSascha Wildner TASK_INIT(&sassc->ev_task, 0, mpssas_firmware_event_work, sc); 623c12c399aSSascha Wildner sassc->ev_tq = taskqueue_create("mps_taskq", M_NOWAIT | M_ZERO, 624c12c399aSSascha Wildner taskqueue_thread_enqueue, &sassc->ev_tq); 625c12c399aSSascha Wildner 626c12c399aSSascha Wildner /* Run the task queue with lowest priority */ 627c12c399aSSascha Wildner taskqueue_start_threads(&sassc->ev_tq, 1, 255, -1, "%s taskq", 628c12c399aSSascha Wildner device_get_nameunit(sc->mps_dev)); 629c12c399aSSascha Wildner 630c12c399aSSascha Wildner TAILQ_INIT(&sassc->ccb_scanq); 631c12c399aSSascha Wildner error = mps_kproc_create(mpssas_scanner_thread, sassc, 632c12c399aSSascha Wildner &sassc->rescan_thread, 0, 0, "mps_scan%d", unit); 633c12c399aSSascha Wildner if (error) { 634c12c399aSSascha Wildner mps_printf(sc, "Error %d starting rescan thread\n", error); 635c12c399aSSascha Wildner goto out; 636c12c399aSSascha Wildner } 637c12c399aSSascha Wildner 638c12c399aSSascha Wildner mps_lock(sc); 639c12c399aSSascha Wildner sassc->flags |= MPSSAS_SCANTHREAD; 640c12c399aSSascha Wildner 641c12c399aSSascha Wildner /* 642c12c399aSSascha Wildner * XXX There should be a bus for every port on the adapter, but since 643c12c399aSSascha Wildner * we're just going to fake the topology for now, we'll pretend that 644c12c399aSSascha Wildner * everything is just a target on a single bus. 645c12c399aSSascha Wildner */ 646c12c399aSSascha Wildner if ((error = xpt_bus_register(sassc->sim, 0)) != 0) { 647c12c399aSSascha Wildner mps_dprint(sc, MPS_FAULT, "Error %d registering SCSI bus\n", 648c12c399aSSascha Wildner error); 649c12c399aSSascha Wildner mps_unlock(sc); 650c12c399aSSascha Wildner goto out; 651c12c399aSSascha Wildner } 652c12c399aSSascha Wildner 653c12c399aSSascha Wildner /* 654c12c399aSSascha Wildner * Assume that discovery events will start right away. Freezing 655c12c399aSSascha Wildner * the simq will prevent the CAM boottime scanner from running 656c12c399aSSascha Wildner * before discovery is complete. 657c12c399aSSascha Wildner */ 658c12c399aSSascha Wildner sassc->flags |= MPSSAS_IN_STARTUP | MPSSAS_IN_DISCOVERY; 659c12c399aSSascha Wildner xpt_freeze_simq(sassc->sim, 1); 660c12c399aSSascha Wildner sc->sassc->startup_refcount = 0; 661c12c399aSSascha Wildner 662c12c399aSSascha Wildner callout_init_mp(&sassc->discovery_callout); 663c12c399aSSascha Wildner sassc->discovery_timeouts = 0; 664c12c399aSSascha Wildner 665c12c399aSSascha Wildner sassc->tm_count = 0; 666c12c399aSSascha Wildner 667c12c399aSSascha Wildner #if __FreeBSD_version >= 1000006 668c12c399aSSascha Wildner status = xpt_register_async(AC_ADVINFO_CHANGED, mpssas_async, sc, NULL); 669c12c399aSSascha Wildner if (status != CAM_REQ_CMP) { 670c12c399aSSascha Wildner mps_printf(sc, "Error %#x registering async handler for " 671c12c399aSSascha Wildner "AC_ADVINFO_CHANGED events\n", status); 672c12c399aSSascha Wildner } 673c12c399aSSascha Wildner #endif 674c12c399aSSascha Wildner 675c12c399aSSascha Wildner mps_unlock(sc); 676c12c399aSSascha Wildner 677c12c399aSSascha Wildner mpssas_register_events(sc); 678c12c399aSSascha Wildner out: 679c12c399aSSascha Wildner if (error) 680c12c399aSSascha Wildner mps_detach_sas(sc); 681c12c399aSSascha Wildner return (error); 682c12c399aSSascha Wildner } 683c12c399aSSascha Wildner 684c12c399aSSascha Wildner int 685c12c399aSSascha Wildner mps_detach_sas(struct mps_softc *sc) 686c12c399aSSascha Wildner { 687c12c399aSSascha Wildner struct mpssas_softc *sassc; 688c12c399aSSascha Wildner 689c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, "%s\n", __func__); 690c12c399aSSascha Wildner 691c12c399aSSascha Wildner if (sc->sassc == NULL) 692c12c399aSSascha Wildner return (0); 693c12c399aSSascha Wildner 694c12c399aSSascha Wildner sassc = sc->sassc; 695c12c399aSSascha Wildner mps_deregister_events(sc, sassc->mpssas_eh); 696c12c399aSSascha Wildner 697c12c399aSSascha Wildner /* 698c12c399aSSascha Wildner * Drain and free the event handling taskqueue with the lock 699c12c399aSSascha Wildner * unheld so that any parallel processing tasks drain properly 700c12c399aSSascha Wildner * without deadlocking. 701c12c399aSSascha Wildner */ 702c12c399aSSascha Wildner if (sassc->ev_tq != NULL) 703c12c399aSSascha Wildner taskqueue_free(sassc->ev_tq); 704c12c399aSSascha Wildner 705c12c399aSSascha Wildner /* Make sure CAM doesn't wedge if we had to bail out early. */ 706c12c399aSSascha Wildner mps_lock(sc); 707c12c399aSSascha Wildner 708c12c399aSSascha Wildner /* Deregister our async handler */ 709c12c399aSSascha Wildner #if __FreeBSD_version >= 1000006 710c12c399aSSascha Wildner xpt_register_async(0, mpssas_async, sc, NULL); 711c12c399aSSascha Wildner #endif 712c12c399aSSascha Wildner 713c12c399aSSascha Wildner if (sassc->flags & MPSSAS_IN_STARTUP) 714c12c399aSSascha Wildner xpt_release_simq(sassc->sim, 1); 715c12c399aSSascha Wildner 716c12c399aSSascha Wildner if (sassc->sim != NULL) { 717c12c399aSSascha Wildner xpt_bus_deregister(cam_sim_path(sassc->sim)); 718c12c399aSSascha Wildner cam_sim_free(sassc->sim); 719c12c399aSSascha Wildner } 720c12c399aSSascha Wildner 721c12c399aSSascha Wildner if (sassc->flags & MPSSAS_SCANTHREAD) { 722c12c399aSSascha Wildner sassc->flags |= MPSSAS_SHUTDOWN; 723c12c399aSSascha Wildner wakeup(&sassc->ccb_scanq); 724c12c399aSSascha Wildner 725c12c399aSSascha Wildner if (sassc->flags & MPSSAS_SCANTHREAD) { 726c12c399aSSascha Wildner lksleep(&sassc->flags, &sc->mps_lock, 0, 727c12c399aSSascha Wildner "mps_shutdown", 30 * hz); 728c12c399aSSascha Wildner } 729c12c399aSSascha Wildner } 730c12c399aSSascha Wildner mps_unlock(sc); 731c12c399aSSascha Wildner 732c12c399aSSascha Wildner if (sassc->devq != NULL) 733c12c399aSSascha Wildner cam_simq_release(sassc->devq); 734c12c399aSSascha Wildner 735c12c399aSSascha Wildner kfree(sassc->targets, M_MPT2); 736c12c399aSSascha Wildner kfree(sassc, M_MPT2); 737c12c399aSSascha Wildner sc->sassc = NULL; 738c12c399aSSascha Wildner 739c12c399aSSascha Wildner return (0); 740c12c399aSSascha Wildner } 741c12c399aSSascha Wildner 742c12c399aSSascha Wildner void 743c12c399aSSascha Wildner mpssas_discovery_end(struct mpssas_softc *sassc) 744c12c399aSSascha Wildner { 745c12c399aSSascha Wildner struct mps_softc *sc = sassc->sc; 746c12c399aSSascha Wildner 747c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, "%s\n", __func__); 748c12c399aSSascha Wildner 749c12c399aSSascha Wildner if (sassc->flags & MPSSAS_DISCOVERY_TIMEOUT_PENDING) 750c12c399aSSascha Wildner callout_stop(&sassc->discovery_callout); 751c12c399aSSascha Wildner 752c12c399aSSascha Wildner } 753c12c399aSSascha Wildner 754c12c399aSSascha Wildner #if 0 /* XXX unused */ 755c12c399aSSascha Wildner static void 756c12c399aSSascha Wildner mpssas_discovery_timeout(void *data) 757c12c399aSSascha Wildner { 758c12c399aSSascha Wildner struct mpssas_softc *sassc = data; 759c12c399aSSascha Wildner struct mps_softc *sc; 760c12c399aSSascha Wildner 761c12c399aSSascha Wildner sc = sassc->sc; 762c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, "%s\n", __func__); 763c12c399aSSascha Wildner 764c12c399aSSascha Wildner mps_lock(sc); 765c12c399aSSascha Wildner mps_printf(sc, 766c12c399aSSascha Wildner "Timeout waiting for discovery, interrupts may not be working!\n"); 767c12c399aSSascha Wildner sassc->flags &= ~MPSSAS_DISCOVERY_TIMEOUT_PENDING; 768c12c399aSSascha Wildner 769c12c399aSSascha Wildner /* Poll the hardware for events in case interrupts aren't working */ 770c12c399aSSascha Wildner mps_intr_locked(sc); 771c12c399aSSascha Wildner 772c12c399aSSascha Wildner mps_printf(sassc->sc, 773c12c399aSSascha Wildner "Finished polling after discovery timeout at %d\n", ticks); 774c12c399aSSascha Wildner 775c12c399aSSascha Wildner if ((sassc->flags & MPSSAS_IN_DISCOVERY) == 0) { 776c12c399aSSascha Wildner mpssas_discovery_end(sassc); 777c12c399aSSascha Wildner } else { 778c12c399aSSascha Wildner if (sassc->discovery_timeouts < MPSSAS_MAX_DISCOVERY_TIMEOUTS) { 779c12c399aSSascha Wildner sassc->flags |= MPSSAS_DISCOVERY_TIMEOUT_PENDING; 780c12c399aSSascha Wildner callout_reset(&sassc->discovery_callout, 781c12c399aSSascha Wildner MPSSAS_DISCOVERY_TIMEOUT * hz, 782c12c399aSSascha Wildner mpssas_discovery_timeout, sassc); 783c12c399aSSascha Wildner sassc->discovery_timeouts++; 784c12c399aSSascha Wildner } else { 785c12c399aSSascha Wildner mps_dprint(sassc->sc, MPS_FAULT, 786c12c399aSSascha Wildner "Discovery timed out, continuing.\n"); 787c12c399aSSascha Wildner sassc->flags &= ~MPSSAS_IN_DISCOVERY; 788c12c399aSSascha Wildner mpssas_discovery_end(sassc); 789c12c399aSSascha Wildner } 790c12c399aSSascha Wildner } 791c12c399aSSascha Wildner 792c12c399aSSascha Wildner mps_unlock(sc); 793c12c399aSSascha Wildner } 794c12c399aSSascha Wildner #endif 795c12c399aSSascha Wildner 796c12c399aSSascha Wildner static void 797c12c399aSSascha Wildner mpssas_action(struct cam_sim *sim, union ccb *ccb) 798c12c399aSSascha Wildner { 799c12c399aSSascha Wildner struct mpssas_softc *sassc; 800c12c399aSSascha Wildner 801c12c399aSSascha Wildner sassc = cam_sim_softc(sim); 802c12c399aSSascha Wildner 803c12c399aSSascha Wildner mps_dprint(sassc->sc, MPS_TRACE, "%s func 0x%x\n", __func__, 804c12c399aSSascha Wildner ccb->ccb_h.func_code); 805c12c399aSSascha Wildner KKASSERT(lockstatus(&sassc->sc->mps_lock, curthread) != 0); 806c12c399aSSascha Wildner 807c12c399aSSascha Wildner switch (ccb->ccb_h.func_code) { 808c12c399aSSascha Wildner case XPT_PATH_INQ: 809c12c399aSSascha Wildner { 810c12c399aSSascha Wildner struct ccb_pathinq *cpi = &ccb->cpi; 811c12c399aSSascha Wildner 812c12c399aSSascha Wildner cpi->version_num = 1; 813c12c399aSSascha Wildner cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; 814c12c399aSSascha Wildner cpi->target_sprt = 0; 815c12c399aSSascha Wildner cpi->hba_misc = PIM_NOBUSRESET; 816c12c399aSSascha Wildner cpi->hba_eng_cnt = 0; 817c12c399aSSascha Wildner cpi->max_target = sassc->sc->facts->MaxTargets - 1; 818c12c399aSSascha Wildner cpi->max_lun = 0; 819c12c399aSSascha Wildner cpi->initiator_id = 255; 820c12c399aSSascha Wildner strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 821c12c399aSSascha Wildner strncpy(cpi->hba_vid, "LSILogic", HBA_IDLEN); 822c12c399aSSascha Wildner strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 823c12c399aSSascha Wildner cpi->unit_number = cam_sim_unit(sim); 824c12c399aSSascha Wildner cpi->bus_id = cam_sim_bus(sim); 825c12c399aSSascha Wildner cpi->base_transfer_speed = 150000; 826c12c399aSSascha Wildner cpi->transport = XPORT_SAS; 827c12c399aSSascha Wildner cpi->transport_version = 0; 828c12c399aSSascha Wildner cpi->protocol = PROTO_SCSI; 829c12c399aSSascha Wildner cpi->protocol_version = SCSI_REV_SPC; 830c12c399aSSascha Wildner #if __FreeBSD_version >= 800001 831c12c399aSSascha Wildner /* 832c12c399aSSascha Wildner * XXX KDM where does this number come from? 833c12c399aSSascha Wildner */ 834c12c399aSSascha Wildner cpi->maxio = 256 * 1024; 835c12c399aSSascha Wildner #endif 836c12c399aSSascha Wildner cpi->ccb_h.status = CAM_REQ_CMP; 837c12c399aSSascha Wildner break; 838c12c399aSSascha Wildner } 839c12c399aSSascha Wildner case XPT_GET_TRAN_SETTINGS: 840c12c399aSSascha Wildner { 841c12c399aSSascha Wildner struct ccb_trans_settings *cts; 842c12c399aSSascha Wildner struct ccb_trans_settings_sas *sas; 843c12c399aSSascha Wildner struct ccb_trans_settings_scsi *scsi; 844c12c399aSSascha Wildner struct mpssas_target *targ; 845c12c399aSSascha Wildner 846c12c399aSSascha Wildner cts = &ccb->cts; 847c12c399aSSascha Wildner sas = &cts->xport_specific.sas; 848c12c399aSSascha Wildner scsi = &cts->proto_specific.scsi; 849c12c399aSSascha Wildner 850c12c399aSSascha Wildner targ = &sassc->targets[cts->ccb_h.target_id]; 851c12c399aSSascha Wildner if (targ->handle == 0x0) { 852c12c399aSSascha Wildner cts->ccb_h.status = CAM_TID_INVALID; 853c12c399aSSascha Wildner break; 854c12c399aSSascha Wildner } 855c12c399aSSascha Wildner 856c12c399aSSascha Wildner cts->protocol_version = SCSI_REV_SPC2; 857c12c399aSSascha Wildner cts->transport = XPORT_SAS; 858c12c399aSSascha Wildner cts->transport_version = 0; 859c12c399aSSascha Wildner 860c12c399aSSascha Wildner sas->valid = CTS_SAS_VALID_SPEED; 861c12c399aSSascha Wildner switch (targ->linkrate) { 862c12c399aSSascha Wildner case 0x08: 863c12c399aSSascha Wildner sas->bitrate = 150000; 864c12c399aSSascha Wildner break; 865c12c399aSSascha Wildner case 0x09: 866c12c399aSSascha Wildner sas->bitrate = 300000; 867c12c399aSSascha Wildner break; 868c12c399aSSascha Wildner case 0x0a: 869c12c399aSSascha Wildner sas->bitrate = 600000; 870c12c399aSSascha Wildner break; 871c12c399aSSascha Wildner default: 872c12c399aSSascha Wildner sas->valid = 0; 873c12c399aSSascha Wildner } 874c12c399aSSascha Wildner 875c12c399aSSascha Wildner cts->protocol = PROTO_SCSI; 876c12c399aSSascha Wildner scsi->valid = CTS_SCSI_VALID_TQ; 877c12c399aSSascha Wildner scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; 878c12c399aSSascha Wildner 879c12c399aSSascha Wildner cts->ccb_h.status = CAM_REQ_CMP; 880c12c399aSSascha Wildner break; 881c12c399aSSascha Wildner } 882c12c399aSSascha Wildner case XPT_CALC_GEOMETRY: 883c12c399aSSascha Wildner cam_calc_geometry(&ccb->ccg, /*extended*/1); 884c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP; 885c12c399aSSascha Wildner break; 886c12c399aSSascha Wildner case XPT_RESET_DEV: 887c12c399aSSascha Wildner mps_printf(sassc->sc, "mpssas_action XPT_RESET_DEV\n"); 888c12c399aSSascha Wildner mpssas_action_resetdev(sassc, ccb); 889c12c399aSSascha Wildner return; 890c12c399aSSascha Wildner case XPT_RESET_BUS: 891c12c399aSSascha Wildner case XPT_ABORT: 892c12c399aSSascha Wildner case XPT_TERM_IO: 893c12c399aSSascha Wildner mps_printf(sassc->sc, "mpssas_action faking success for " 894c12c399aSSascha Wildner "abort or reset\n"); 895c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP; 896c12c399aSSascha Wildner break; 897c12c399aSSascha Wildner case XPT_SCSI_IO: 898c12c399aSSascha Wildner mpssas_action_scsiio(sassc, ccb); 899c12c399aSSascha Wildner return; 900c12c399aSSascha Wildner #if __FreeBSD_version >= 900026 901c12c399aSSascha Wildner case XPT_SMP_IO: 902c12c399aSSascha Wildner mpssas_action_smpio(sassc, ccb); 903c12c399aSSascha Wildner return; 904c12c399aSSascha Wildner #endif 905c12c399aSSascha Wildner default: 906c12c399aSSascha Wildner ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 907c12c399aSSascha Wildner break; 908c12c399aSSascha Wildner } 909c12c399aSSascha Wildner xpt_done(ccb); 910c12c399aSSascha Wildner 911c12c399aSSascha Wildner } 912c12c399aSSascha Wildner 913c12c399aSSascha Wildner static void 914c12c399aSSascha Wildner mpssas_announce_reset(struct mps_softc *sc, uint32_t ac_code, 915c12c399aSSascha Wildner target_id_t target_id, lun_id_t lun_id) 916c12c399aSSascha Wildner { 917c12c399aSSascha Wildner path_id_t path_id = cam_sim_path(sc->sassc->sim); 918c12c399aSSascha Wildner struct cam_path *path; 919c12c399aSSascha Wildner 920c12c399aSSascha Wildner mps_printf(sc, "%s code %x target %d lun %d\n", __func__, 921c12c399aSSascha Wildner ac_code, target_id, lun_id); 922c12c399aSSascha Wildner 923c12c399aSSascha Wildner if (xpt_create_path(&path, NULL, 924c12c399aSSascha Wildner path_id, target_id, lun_id) != CAM_REQ_CMP) { 925c12c399aSSascha Wildner mps_printf(sc, "unable to create path for reset " 926c12c399aSSascha Wildner "notification\n"); 927c12c399aSSascha Wildner return; 928c12c399aSSascha Wildner } 929c12c399aSSascha Wildner 930c12c399aSSascha Wildner xpt_async(ac_code, path, NULL); 931c12c399aSSascha Wildner xpt_free_path(path); 932c12c399aSSascha Wildner } 933c12c399aSSascha Wildner 934c12c399aSSascha Wildner static void 935c12c399aSSascha Wildner mpssas_complete_all_commands(struct mps_softc *sc) 936c12c399aSSascha Wildner { 937c12c399aSSascha Wildner struct mps_command *cm; 938c12c399aSSascha Wildner int i; 939c12c399aSSascha Wildner int completed; 940c12c399aSSascha Wildner 941c12c399aSSascha Wildner mps_printf(sc, "%s\n", __func__); 942c12c399aSSascha Wildner KKASSERT(lockstatus(&sc->mps_lock, curthread) != 0); 943c12c399aSSascha Wildner 944c12c399aSSascha Wildner /* complete all commands with a NULL reply */ 945c12c399aSSascha Wildner for (i = 1; i < sc->num_reqs; i++) { 946c12c399aSSascha Wildner cm = &sc->commands[i]; 947c12c399aSSascha Wildner cm->cm_reply = NULL; 948c12c399aSSascha Wildner completed = 0; 949c12c399aSSascha Wildner 950c12c399aSSascha Wildner if (cm->cm_flags & MPS_CM_FLAGS_POLLED) 951c12c399aSSascha Wildner cm->cm_flags |= MPS_CM_FLAGS_COMPLETE; 952c12c399aSSascha Wildner 953c12c399aSSascha Wildner if (cm->cm_complete != NULL) { 954c12c399aSSascha Wildner mpssas_log_command(cm, 955c12c399aSSascha Wildner "completing cm %p state %x ccb %p for diag reset\n", 956c12c399aSSascha Wildner cm, cm->cm_state, cm->cm_ccb); 957c12c399aSSascha Wildner 958c12c399aSSascha Wildner cm->cm_complete(sc, cm); 959c12c399aSSascha Wildner completed = 1; 960c12c399aSSascha Wildner } 961c12c399aSSascha Wildner 962c12c399aSSascha Wildner if (cm->cm_flags & MPS_CM_FLAGS_WAKEUP) { 963c12c399aSSascha Wildner mpssas_log_command(cm, 964c12c399aSSascha Wildner "waking up cm %p state %x ccb %p for diag reset\n", 965c12c399aSSascha Wildner cm, cm->cm_state, cm->cm_ccb); 966c12c399aSSascha Wildner wakeup(cm); 967c12c399aSSascha Wildner completed = 1; 968c12c399aSSascha Wildner } 969c12c399aSSascha Wildner 970c12c399aSSascha Wildner if ((completed == 0) && (cm->cm_state != MPS_CM_STATE_FREE)) { 971c12c399aSSascha Wildner /* this should never happen, but if it does, log */ 972c12c399aSSascha Wildner mpssas_log_command(cm, 973c12c399aSSascha Wildner "cm %p state %x flags 0x%x ccb %p during diag " 974c12c399aSSascha Wildner "reset\n", cm, cm->cm_state, cm->cm_flags, 975c12c399aSSascha Wildner cm->cm_ccb); 976c12c399aSSascha Wildner } 977c12c399aSSascha Wildner } 978c12c399aSSascha Wildner } 979c12c399aSSascha Wildner 980c12c399aSSascha Wildner void 981c12c399aSSascha Wildner mpssas_handle_reinit(struct mps_softc *sc) 982c12c399aSSascha Wildner { 983c12c399aSSascha Wildner int i; 984c12c399aSSascha Wildner 985c12c399aSSascha Wildner /* Go back into startup mode and freeze the simq, so that CAM 986c12c399aSSascha Wildner * doesn't send any commands until after we've rediscovered all 987c12c399aSSascha Wildner * targets and found the proper device handles for them. 988c12c399aSSascha Wildner * 989c12c399aSSascha Wildner * After the reset, portenable will trigger discovery, and after all 990c12c399aSSascha Wildner * discovery-related activities have finished, the simq will be 991c12c399aSSascha Wildner * released. 992c12c399aSSascha Wildner */ 993c12c399aSSascha Wildner mps_printf(sc, "%s startup\n", __func__); 994c12c399aSSascha Wildner sc->sassc->flags |= MPSSAS_IN_STARTUP; 995c12c399aSSascha Wildner sc->sassc->flags |= MPSSAS_IN_DISCOVERY; 996c12c399aSSascha Wildner xpt_freeze_simq(sc->sassc->sim, 1); 997c12c399aSSascha Wildner 998c12c399aSSascha Wildner /* notify CAM of a bus reset */ 999c12c399aSSascha Wildner mpssas_announce_reset(sc, AC_BUS_RESET, CAM_TARGET_WILDCARD, 1000c12c399aSSascha Wildner CAM_LUN_WILDCARD); 1001c12c399aSSascha Wildner 1002c12c399aSSascha Wildner /* complete and cleanup after all outstanding commands */ 1003c12c399aSSascha Wildner mpssas_complete_all_commands(sc); 1004c12c399aSSascha Wildner 1005c12c399aSSascha Wildner mps_printf(sc, "%s startup %u tm %u after command completion\n", 1006c12c399aSSascha Wildner __func__, sc->sassc->startup_refcount, sc->sassc->tm_count); 1007c12c399aSSascha Wildner 1008c12c399aSSascha Wildner /* 1009c12c399aSSascha Wildner * The simq was explicitly frozen above, so set the refcount to 0. 1010c12c399aSSascha Wildner * The simq will be explicitly released after port enable completes. 1011c12c399aSSascha Wildner */ 1012c12c399aSSascha Wildner sc->sassc->startup_refcount = 0; 1013c12c399aSSascha Wildner 1014c12c399aSSascha Wildner /* zero all the target handles, since they may change after the 1015c12c399aSSascha Wildner * reset, and we have to rediscover all the targets and use the new 1016c12c399aSSascha Wildner * handles. 1017c12c399aSSascha Wildner */ 1018c12c399aSSascha Wildner for (i = 0; i < sc->facts->MaxTargets; i++) { 1019c12c399aSSascha Wildner if (sc->sassc->targets[i].outstanding != 0) 1020c12c399aSSascha Wildner mps_printf(sc, "target %u outstanding %u\n", 1021c12c399aSSascha Wildner i, sc->sassc->targets[i].outstanding); 1022c12c399aSSascha Wildner sc->sassc->targets[i].handle = 0x0; 1023c12c399aSSascha Wildner sc->sassc->targets[i].exp_dev_handle = 0x0; 1024c12c399aSSascha Wildner sc->sassc->targets[i].outstanding = 0; 1025c12c399aSSascha Wildner sc->sassc->targets[i].flags = MPSSAS_TARGET_INDIAGRESET; 1026c12c399aSSascha Wildner } 1027c12c399aSSascha Wildner } 1028c12c399aSSascha Wildner static void 1029c12c399aSSascha Wildner mpssas_tm_timeout(void *data) 1030c12c399aSSascha Wildner { 1031c12c399aSSascha Wildner struct mps_command *tm = data; 1032c12c399aSSascha Wildner struct mps_softc *sc = tm->cm_sc; 1033c12c399aSSascha Wildner 1034c12c399aSSascha Wildner mps_lock(sc); 1035c12c399aSSascha Wildner mpssas_log_command(tm, "task mgmt %p timed out\n", tm); 1036c12c399aSSascha Wildner mps_reinit(sc); 1037c12c399aSSascha Wildner mps_unlock(sc); 1038c12c399aSSascha Wildner } 1039c12c399aSSascha Wildner 1040c12c399aSSascha Wildner static void 1041c12c399aSSascha Wildner mpssas_logical_unit_reset_complete(struct mps_softc *sc, struct mps_command *tm) 1042c12c399aSSascha Wildner { 1043c12c399aSSascha Wildner MPI2_SCSI_TASK_MANAGE_REPLY *reply; 1044c12c399aSSascha Wildner unsigned int cm_count = 0; 1045c12c399aSSascha Wildner struct mps_command *cm; 1046c12c399aSSascha Wildner struct mpssas_target *targ; 1047c12c399aSSascha Wildner 1048c12c399aSSascha Wildner callout_stop(&tm->cm_callout); 1049c12c399aSSascha Wildner 1050c12c399aSSascha Wildner reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 1051c12c399aSSascha Wildner targ = tm->cm_targ; 1052c12c399aSSascha Wildner 1053c12c399aSSascha Wildner /* 1054c12c399aSSascha Wildner * Currently there should be no way we can hit this case. It only 1055c12c399aSSascha Wildner * happens when we have a failure to allocate chain frames, and 1056c12c399aSSascha Wildner * task management commands don't have S/G lists. 1057c12c399aSSascha Wildner */ 1058c12c399aSSascha Wildner if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { 1059c12c399aSSascha Wildner mps_printf(sc, "%s: cm_flags = %#x for LUN reset! " 1060c12c399aSSascha Wildner "This should not happen!\n", __func__, tm->cm_flags); 1061c12c399aSSascha Wildner mpssas_free_tm(sc, tm); 1062c12c399aSSascha Wildner return; 1063c12c399aSSascha Wildner } 1064c12c399aSSascha Wildner 1065c12c399aSSascha Wildner if (reply == NULL) { 1066c12c399aSSascha Wildner mpssas_log_command(tm, "NULL reset reply for tm %p\n", tm); 1067c12c399aSSascha Wildner if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) { 1068c12c399aSSascha Wildner /* this completion was due to a reset, just cleanup */ 1069c12c399aSSascha Wildner targ->flags &= ~MPSSAS_TARGET_INRESET; 1070c12c399aSSascha Wildner targ->tm = NULL; 1071c12c399aSSascha Wildner mpssas_free_tm(sc, tm); 1072c12c399aSSascha Wildner } 1073c12c399aSSascha Wildner else { 1074c12c399aSSascha Wildner /* we should have gotten a reply. */ 1075c12c399aSSascha Wildner mps_reinit(sc); 1076c12c399aSSascha Wildner } 1077c12c399aSSascha Wildner return; 1078c12c399aSSascha Wildner } 1079c12c399aSSascha Wildner 1080c12c399aSSascha Wildner mpssas_log_command(tm, 1081c12c399aSSascha Wildner "logical unit reset status 0x%x code 0x%x count %u\n", 1082c12c399aSSascha Wildner reply->IOCStatus, reply->ResponseCode, 1083c12c399aSSascha Wildner reply->TerminationCount); 1084c12c399aSSascha Wildner 1085c12c399aSSascha Wildner /* See if there are any outstanding commands for this LUN. 1086c12c399aSSascha Wildner * This could be made more efficient by using a per-LU data 1087c12c399aSSascha Wildner * structure of some sort. 1088c12c399aSSascha Wildner */ 1089c12c399aSSascha Wildner TAILQ_FOREACH(cm, &targ->commands, cm_link) { 1090c12c399aSSascha Wildner if (cm->cm_lun == tm->cm_lun) 1091c12c399aSSascha Wildner cm_count++; 1092c12c399aSSascha Wildner } 1093c12c399aSSascha Wildner 1094c12c399aSSascha Wildner if (cm_count == 0) { 1095c12c399aSSascha Wildner mpssas_log_command(tm, 1096c12c399aSSascha Wildner "logical unit %u finished recovery after reset\n", 109736fe16feSSascha Wildner tm->cm_lun); 1098c12c399aSSascha Wildner 1099c12c399aSSascha Wildner mpssas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid, 1100c12c399aSSascha Wildner tm->cm_lun); 1101c12c399aSSascha Wildner 1102c12c399aSSascha Wildner /* we've finished recovery for this logical unit. check and 1103c12c399aSSascha Wildner * see if some other logical unit has a timedout command 1104c12c399aSSascha Wildner * that needs to be processed. 1105c12c399aSSascha Wildner */ 1106c12c399aSSascha Wildner cm = TAILQ_FIRST(&targ->timedout_commands); 1107c12c399aSSascha Wildner if (cm) { 1108c12c399aSSascha Wildner mpssas_send_abort(sc, tm, cm); 1109c12c399aSSascha Wildner } 1110c12c399aSSascha Wildner else { 1111c12c399aSSascha Wildner targ->tm = NULL; 1112c12c399aSSascha Wildner mpssas_free_tm(sc, tm); 1113c12c399aSSascha Wildner } 1114c12c399aSSascha Wildner } 1115c12c399aSSascha Wildner else { 1116c12c399aSSascha Wildner /* if we still have commands for this LUN, the reset 1117c12c399aSSascha Wildner * effectively failed, regardless of the status reported. 1118c12c399aSSascha Wildner * Escalate to a target reset. 1119c12c399aSSascha Wildner */ 1120c12c399aSSascha Wildner mpssas_log_command(tm, 1121c12c399aSSascha Wildner "logical unit reset complete for tm %p, but still have %u command(s)\n", 1122c12c399aSSascha Wildner tm, cm_count); 1123c12c399aSSascha Wildner mpssas_send_reset(sc, tm, 1124c12c399aSSascha Wildner MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET); 1125c12c399aSSascha Wildner } 1126c12c399aSSascha Wildner } 1127c12c399aSSascha Wildner 1128c12c399aSSascha Wildner static void 1129c12c399aSSascha Wildner mpssas_target_reset_complete(struct mps_softc *sc, struct mps_command *tm) 1130c12c399aSSascha Wildner { 1131c12c399aSSascha Wildner MPI2_SCSI_TASK_MANAGE_REPLY *reply; 1132c12c399aSSascha Wildner struct mpssas_target *targ; 1133c12c399aSSascha Wildner 1134c12c399aSSascha Wildner callout_stop(&tm->cm_callout); 1135c12c399aSSascha Wildner 1136c12c399aSSascha Wildner reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 1137c12c399aSSascha Wildner targ = tm->cm_targ; 1138c12c399aSSascha Wildner 1139c12c399aSSascha Wildner /* 1140c12c399aSSascha Wildner * Currently there should be no way we can hit this case. It only 1141c12c399aSSascha Wildner * happens when we have a failure to allocate chain frames, and 1142c12c399aSSascha Wildner * task management commands don't have S/G lists. 1143c12c399aSSascha Wildner */ 1144c12c399aSSascha Wildner if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { 1145c12c399aSSascha Wildner mps_printf(sc, "%s: cm_flags = %#x for target reset! " 1146c12c399aSSascha Wildner "This should not happen!\n", __func__, tm->cm_flags); 1147c12c399aSSascha Wildner mpssas_free_tm(sc, tm); 1148c12c399aSSascha Wildner return; 1149c12c399aSSascha Wildner } 1150c12c399aSSascha Wildner 1151c12c399aSSascha Wildner if (reply == NULL) { 1152c12c399aSSascha Wildner mpssas_log_command(tm, "NULL reset reply for tm %p\n", tm); 1153c12c399aSSascha Wildner if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) { 1154c12c399aSSascha Wildner /* this completion was due to a reset, just cleanup */ 1155c12c399aSSascha Wildner targ->flags &= ~MPSSAS_TARGET_INRESET; 1156c12c399aSSascha Wildner targ->tm = NULL; 1157c12c399aSSascha Wildner mpssas_free_tm(sc, tm); 1158c12c399aSSascha Wildner } 1159c12c399aSSascha Wildner else { 1160c12c399aSSascha Wildner /* we should have gotten a reply. */ 1161c12c399aSSascha Wildner mps_reinit(sc); 1162c12c399aSSascha Wildner } 1163c12c399aSSascha Wildner return; 1164c12c399aSSascha Wildner } 1165c12c399aSSascha Wildner 1166c12c399aSSascha Wildner mpssas_log_command(tm, 1167c12c399aSSascha Wildner "target reset status 0x%x code 0x%x count %u\n", 1168c12c399aSSascha Wildner reply->IOCStatus, reply->ResponseCode, 1169c12c399aSSascha Wildner reply->TerminationCount); 1170c12c399aSSascha Wildner 1171c12c399aSSascha Wildner targ->flags &= ~MPSSAS_TARGET_INRESET; 1172c12c399aSSascha Wildner 1173c12c399aSSascha Wildner if (targ->outstanding == 0) { 1174c12c399aSSascha Wildner /* we've finished recovery for this target and all 1175c12c399aSSascha Wildner * of its logical units. 1176c12c399aSSascha Wildner */ 1177c12c399aSSascha Wildner mpssas_log_command(tm, 1178c12c399aSSascha Wildner "recovery finished after target reset\n"); 1179c12c399aSSascha Wildner 1180c12c399aSSascha Wildner mpssas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid, 1181c12c399aSSascha Wildner CAM_LUN_WILDCARD); 1182c12c399aSSascha Wildner 1183c12c399aSSascha Wildner targ->tm = NULL; 1184c12c399aSSascha Wildner mpssas_free_tm(sc, tm); 1185c12c399aSSascha Wildner } 1186c12c399aSSascha Wildner else { 1187c12c399aSSascha Wildner /* after a target reset, if this target still has 1188c12c399aSSascha Wildner * outstanding commands, the reset effectively failed, 1189c12c399aSSascha Wildner * regardless of the status reported. escalate. 1190c12c399aSSascha Wildner */ 1191c12c399aSSascha Wildner mpssas_log_command(tm, 1192c12c399aSSascha Wildner "target reset complete for tm %p, but still have %u command(s)\n", 1193c12c399aSSascha Wildner tm, targ->outstanding); 1194c12c399aSSascha Wildner mps_reinit(sc); 1195c12c399aSSascha Wildner } 1196c12c399aSSascha Wildner } 1197c12c399aSSascha Wildner 1198c12c399aSSascha Wildner #define MPS_RESET_TIMEOUT 30 1199c12c399aSSascha Wildner 1200c12c399aSSascha Wildner static int 1201c12c399aSSascha Wildner mpssas_send_reset(struct mps_softc *sc, struct mps_command *tm, uint8_t type) 1202c12c399aSSascha Wildner { 1203c12c399aSSascha Wildner MPI2_SCSI_TASK_MANAGE_REQUEST *req; 1204c12c399aSSascha Wildner struct mpssas_target *target; 1205c12c399aSSascha Wildner int err; 1206c12c399aSSascha Wildner 1207c12c399aSSascha Wildner target = tm->cm_targ; 1208c12c399aSSascha Wildner if (target->handle == 0) { 1209c12c399aSSascha Wildner mps_printf(sc, "%s null devhandle for target_id %d\n", 1210c12c399aSSascha Wildner __func__, target->tid); 1211c12c399aSSascha Wildner return -1; 1212c12c399aSSascha Wildner } 1213c12c399aSSascha Wildner 1214c12c399aSSascha Wildner req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 1215c12c399aSSascha Wildner req->DevHandle = target->handle; 1216c12c399aSSascha Wildner req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 1217c12c399aSSascha Wildner req->TaskType = type; 1218c12c399aSSascha Wildner 1219c12c399aSSascha Wildner if (type == MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET) { 1220c12c399aSSascha Wildner /* XXX Need to handle invalid LUNs */ 1221c12c399aSSascha Wildner MPS_SET_LUN(req->LUN, tm->cm_lun); 1222c12c399aSSascha Wildner tm->cm_targ->logical_unit_resets++; 1223c12c399aSSascha Wildner mpssas_log_command(tm, "sending logical unit reset\n"); 1224c12c399aSSascha Wildner tm->cm_complete = mpssas_logical_unit_reset_complete; 1225c12c399aSSascha Wildner } 1226c12c399aSSascha Wildner else if (type == MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET) { 1227c12c399aSSascha Wildner /* Target reset method = SAS Hard Link Reset / SATA Link Reset */ 1228c12c399aSSascha Wildner req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; 1229c12c399aSSascha Wildner tm->cm_targ->target_resets++; 1230c12c399aSSascha Wildner tm->cm_targ->flags |= MPSSAS_TARGET_INRESET; 1231c12c399aSSascha Wildner mpssas_log_command(tm, "sending target reset\n"); 1232c12c399aSSascha Wildner tm->cm_complete = mpssas_target_reset_complete; 1233c12c399aSSascha Wildner } 1234c12c399aSSascha Wildner else { 1235c12c399aSSascha Wildner mps_printf(sc, "unexpected reset type 0x%x\n", type); 1236c12c399aSSascha Wildner return -1; 1237c12c399aSSascha Wildner } 1238c12c399aSSascha Wildner 1239c12c399aSSascha Wildner tm->cm_data = NULL; 1240c12c399aSSascha Wildner tm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 1241c12c399aSSascha Wildner tm->cm_complete_data = (void *)tm; 1242c12c399aSSascha Wildner 1243c12c399aSSascha Wildner callout_reset(&tm->cm_callout, MPS_RESET_TIMEOUT * hz, 1244c12c399aSSascha Wildner mpssas_tm_timeout, tm); 1245c12c399aSSascha Wildner 1246c12c399aSSascha Wildner err = mps_map_command(sc, tm); 1247c12c399aSSascha Wildner if (err) 1248c12c399aSSascha Wildner mpssas_log_command(tm, 1249c12c399aSSascha Wildner "error %d sending reset type %u\n", 1250c12c399aSSascha Wildner err, type); 1251c12c399aSSascha Wildner 1252c12c399aSSascha Wildner return err; 1253c12c399aSSascha Wildner } 1254c12c399aSSascha Wildner 1255c12c399aSSascha Wildner 1256c12c399aSSascha Wildner static void 1257c12c399aSSascha Wildner mpssas_abort_complete(struct mps_softc *sc, struct mps_command *tm) 1258c12c399aSSascha Wildner { 1259c12c399aSSascha Wildner struct mps_command *cm; 1260c12c399aSSascha Wildner MPI2_SCSI_TASK_MANAGE_REPLY *reply; 1261c12c399aSSascha Wildner MPI2_SCSI_TASK_MANAGE_REQUEST *req; 1262c12c399aSSascha Wildner struct mpssas_target *targ; 1263c12c399aSSascha Wildner 1264c12c399aSSascha Wildner callout_stop(&tm->cm_callout); 1265c12c399aSSascha Wildner 1266c12c399aSSascha Wildner req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 1267c12c399aSSascha Wildner reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 1268c12c399aSSascha Wildner targ = tm->cm_targ; 1269c12c399aSSascha Wildner 1270c12c399aSSascha Wildner /* 1271c12c399aSSascha Wildner * Currently there should be no way we can hit this case. It only 1272c12c399aSSascha Wildner * happens when we have a failure to allocate chain frames, and 1273c12c399aSSascha Wildner * task management commands don't have S/G lists. 1274c12c399aSSascha Wildner */ 1275c12c399aSSascha Wildner if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { 1276c12c399aSSascha Wildner mpssas_log_command(tm, 1277c12c399aSSascha Wildner "cm_flags = %#x for abort %p TaskMID %u!\n", 1278c12c399aSSascha Wildner tm->cm_flags, tm, req->TaskMID); 1279c12c399aSSascha Wildner mpssas_free_tm(sc, tm); 1280c12c399aSSascha Wildner return; 1281c12c399aSSascha Wildner } 1282c12c399aSSascha Wildner 1283c12c399aSSascha Wildner if (reply == NULL) { 1284c12c399aSSascha Wildner mpssas_log_command(tm, 1285c12c399aSSascha Wildner "NULL abort reply for tm %p TaskMID %u\n", 1286c12c399aSSascha Wildner tm, req->TaskMID); 1287c12c399aSSascha Wildner if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) { 1288c12c399aSSascha Wildner /* this completion was due to a reset, just cleanup */ 1289c12c399aSSascha Wildner targ->tm = NULL; 1290c12c399aSSascha Wildner mpssas_free_tm(sc, tm); 1291c12c399aSSascha Wildner } 1292c12c399aSSascha Wildner else { 1293c12c399aSSascha Wildner /* we should have gotten a reply. */ 1294c12c399aSSascha Wildner mps_reinit(sc); 1295c12c399aSSascha Wildner } 1296c12c399aSSascha Wildner return; 1297c12c399aSSascha Wildner } 1298c12c399aSSascha Wildner 1299c12c399aSSascha Wildner mpssas_log_command(tm, 1300c12c399aSSascha Wildner "abort TaskMID %u status 0x%x code 0x%x count %u\n", 1301c12c399aSSascha Wildner req->TaskMID, 1302c12c399aSSascha Wildner reply->IOCStatus, reply->ResponseCode, 1303c12c399aSSascha Wildner reply->TerminationCount); 1304c12c399aSSascha Wildner 1305c12c399aSSascha Wildner cm = TAILQ_FIRST(&tm->cm_targ->timedout_commands); 1306c12c399aSSascha Wildner if (cm == NULL) { 1307c12c399aSSascha Wildner /* if there are no more timedout commands, we're done with 1308c12c399aSSascha Wildner * error recovery for this target. 1309c12c399aSSascha Wildner */ 1310c12c399aSSascha Wildner mpssas_log_command(tm, 1311c12c399aSSascha Wildner "finished recovery after aborting TaskMID %u\n", 1312c12c399aSSascha Wildner req->TaskMID); 1313c12c399aSSascha Wildner 1314c12c399aSSascha Wildner targ->tm = NULL; 1315c12c399aSSascha Wildner mpssas_free_tm(sc, tm); 1316c12c399aSSascha Wildner } 1317c12c399aSSascha Wildner else if (req->TaskMID != cm->cm_desc.Default.SMID) { 1318c12c399aSSascha Wildner /* abort success, but we have more timedout commands to abort */ 1319c12c399aSSascha Wildner mpssas_log_command(tm, 1320c12c399aSSascha Wildner "continuing recovery after aborting TaskMID %u\n", 1321c12c399aSSascha Wildner req->TaskMID); 1322c12c399aSSascha Wildner 1323c12c399aSSascha Wildner mpssas_send_abort(sc, tm, cm); 1324c12c399aSSascha Wildner } 1325c12c399aSSascha Wildner else { 1326c12c399aSSascha Wildner /* we didn't get a command completion, so the abort 1327c12c399aSSascha Wildner * failed as far as we're concerned. escalate. 1328c12c399aSSascha Wildner */ 1329c12c399aSSascha Wildner mpssas_log_command(tm, 1330c12c399aSSascha Wildner "abort failed for TaskMID %u tm %p\n", 1331c12c399aSSascha Wildner req->TaskMID, tm); 1332c12c399aSSascha Wildner 1333c12c399aSSascha Wildner mpssas_send_reset(sc, tm, 1334c12c399aSSascha Wildner MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET); 1335c12c399aSSascha Wildner } 1336c12c399aSSascha Wildner } 1337c12c399aSSascha Wildner 1338c12c399aSSascha Wildner #define MPS_ABORT_TIMEOUT 5 1339c12c399aSSascha Wildner 1340c12c399aSSascha Wildner static int 1341c12c399aSSascha Wildner mpssas_send_abort(struct mps_softc *sc, struct mps_command *tm, struct mps_command *cm) 1342c12c399aSSascha Wildner { 1343c12c399aSSascha Wildner MPI2_SCSI_TASK_MANAGE_REQUEST *req; 1344c12c399aSSascha Wildner struct mpssas_target *targ; 1345c12c399aSSascha Wildner int err; 1346c12c399aSSascha Wildner 1347c12c399aSSascha Wildner targ = cm->cm_targ; 1348c12c399aSSascha Wildner if (targ->handle == 0) { 1349c12c399aSSascha Wildner mps_printf(sc, "%s null devhandle for target_id %d\n", 1350c12c399aSSascha Wildner __func__, cm->cm_ccb->ccb_h.target_id); 1351c12c399aSSascha Wildner return -1; 1352c12c399aSSascha Wildner } 1353c12c399aSSascha Wildner 1354c12c399aSSascha Wildner req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 1355c12c399aSSascha Wildner req->DevHandle = targ->handle; 1356c12c399aSSascha Wildner req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 1357c12c399aSSascha Wildner req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK; 1358c12c399aSSascha Wildner 1359c12c399aSSascha Wildner /* XXX Need to handle invalid LUNs */ 1360c12c399aSSascha Wildner MPS_SET_LUN(req->LUN, cm->cm_ccb->ccb_h.target_lun); 1361c12c399aSSascha Wildner 1362c12c399aSSascha Wildner req->TaskMID = cm->cm_desc.Default.SMID; 1363c12c399aSSascha Wildner 1364c12c399aSSascha Wildner tm->cm_data = NULL; 1365c12c399aSSascha Wildner tm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 1366c12c399aSSascha Wildner tm->cm_complete = mpssas_abort_complete; 1367c12c399aSSascha Wildner tm->cm_complete_data = (void *)tm; 1368c12c399aSSascha Wildner tm->cm_targ = cm->cm_targ; 1369c12c399aSSascha Wildner tm->cm_lun = cm->cm_lun; 1370c12c399aSSascha Wildner 1371c12c399aSSascha Wildner callout_reset(&tm->cm_callout, MPS_ABORT_TIMEOUT * hz, 1372c12c399aSSascha Wildner mpssas_tm_timeout, tm); 1373c12c399aSSascha Wildner 1374c12c399aSSascha Wildner targ->aborts++; 1375c12c399aSSascha Wildner 1376c12c399aSSascha Wildner err = mps_map_command(sc, tm); 1377c12c399aSSascha Wildner if (err) 1378c12c399aSSascha Wildner mpssas_log_command(tm, 1379c12c399aSSascha Wildner "error %d sending abort for cm %p SMID %u\n", 1380c12c399aSSascha Wildner err, cm, req->TaskMID); 1381c12c399aSSascha Wildner return err; 1382c12c399aSSascha Wildner } 1383c12c399aSSascha Wildner 1384c12c399aSSascha Wildner 1385c12c399aSSascha Wildner static void 1386c12c399aSSascha Wildner mpssas_scsiio_timeout(void *data) 1387c12c399aSSascha Wildner { 1388c12c399aSSascha Wildner struct mps_softc *sc; 1389c12c399aSSascha Wildner struct mps_command *cm; 1390c12c399aSSascha Wildner struct mpssas_target *targ; 1391c12c399aSSascha Wildner 1392c12c399aSSascha Wildner cm = (struct mps_command *)data; 1393c12c399aSSascha Wildner sc = cm->cm_sc; 1394c12c399aSSascha Wildner 1395c12c399aSSascha Wildner KKASSERT(lockstatus(&sc->mps_lock, curthread) != 0); 1396c12c399aSSascha Wildner 1397c12c399aSSascha Wildner mps_printf(sc, "%s checking sc %p cm %p\n", __func__, sc, cm); 1398c12c399aSSascha Wildner 1399c12c399aSSascha Wildner /* 1400c12c399aSSascha Wildner * Run the interrupt handler to make sure it's not pending. This 1401c12c399aSSascha Wildner * isn't perfect because the command could have already completed 1402c12c399aSSascha Wildner * and been re-used, though this is unlikely. 1403c12c399aSSascha Wildner */ 1404c12c399aSSascha Wildner mps_intr_locked(sc); 1405c12c399aSSascha Wildner if (cm->cm_state == MPS_CM_STATE_FREE) { 1406c12c399aSSascha Wildner mps_printf(sc, "SCSI command %p sc %p almost timed out\n", cm, sc); 1407c12c399aSSascha Wildner return; 1408c12c399aSSascha Wildner } 1409c12c399aSSascha Wildner 1410c12c399aSSascha Wildner if (cm->cm_ccb == NULL) { 1411c12c399aSSascha Wildner mps_printf(sc, "command timeout with NULL ccb\n"); 1412c12c399aSSascha Wildner return; 1413c12c399aSSascha Wildner } 1414c12c399aSSascha Wildner 1415c12c399aSSascha Wildner mpssas_log_command(cm, "command timeout cm %p ccb %p\n", 1416c12c399aSSascha Wildner cm, cm->cm_ccb); 1417c12c399aSSascha Wildner 1418c12c399aSSascha Wildner targ = cm->cm_targ; 1419c12c399aSSascha Wildner targ->timeouts++; 1420c12c399aSSascha Wildner 1421c12c399aSSascha Wildner /* XXX first, check the firmware state, to see if it's still 1422c12c399aSSascha Wildner * operational. if not, do a diag reset. 1423c12c399aSSascha Wildner */ 1424c12c399aSSascha Wildner 1425c12c399aSSascha Wildner cm->cm_ccb->ccb_h.status = CAM_CMD_TIMEOUT; 1426c12c399aSSascha Wildner cm->cm_state = MPS_CM_STATE_TIMEDOUT; 1427c12c399aSSascha Wildner TAILQ_INSERT_TAIL(&targ->timedout_commands, cm, cm_recovery); 1428c12c399aSSascha Wildner 1429c12c399aSSascha Wildner if (targ->tm != NULL) { 1430c12c399aSSascha Wildner /* target already in recovery, just queue up another 1431c12c399aSSascha Wildner * timedout command to be processed later. 1432c12c399aSSascha Wildner */ 1433c12c399aSSascha Wildner mps_printf(sc, "queued timedout cm %p for processing by tm %p\n", 1434c12c399aSSascha Wildner cm, targ->tm); 1435c12c399aSSascha Wildner } 1436c12c399aSSascha Wildner else if ((targ->tm = mpssas_alloc_tm(sc)) != NULL) { 1437c12c399aSSascha Wildner mps_printf(sc, "timedout cm %p allocated tm %p\n", 1438c12c399aSSascha Wildner cm, targ->tm); 1439c12c399aSSascha Wildner 1440c12c399aSSascha Wildner /* start recovery by aborting the first timedout command */ 1441c12c399aSSascha Wildner mpssas_send_abort(sc, targ->tm, cm); 1442c12c399aSSascha Wildner } 1443c12c399aSSascha Wildner else { 1444c12c399aSSascha Wildner /* XXX queue this target up for recovery once a TM becomes 1445c12c399aSSascha Wildner * available. The firmware only has a limited number of 1446c12c399aSSascha Wildner * HighPriority credits for the high priority requests used 1447c12c399aSSascha Wildner * for task management, and we ran out. 1448c12c399aSSascha Wildner * 1449c12c399aSSascha Wildner * Isilon: don't worry about this for now, since we have 1450c12c399aSSascha Wildner * more credits than disks in an enclosure, and limit 1451c12c399aSSascha Wildner * ourselves to one TM per target for recovery. 1452c12c399aSSascha Wildner */ 1453c12c399aSSascha Wildner mps_printf(sc, "timedout cm %p failed to allocate a tm\n", 1454c12c399aSSascha Wildner cm); 1455c12c399aSSascha Wildner } 1456c12c399aSSascha Wildner 1457c12c399aSSascha Wildner } 1458c12c399aSSascha Wildner 1459c12c399aSSascha Wildner static void 1460c12c399aSSascha Wildner mpssas_action_scsiio(struct mpssas_softc *sassc, union ccb *ccb) 1461c12c399aSSascha Wildner { 1462c12c399aSSascha Wildner MPI2_SCSI_IO_REQUEST *req; 1463c12c399aSSascha Wildner struct ccb_scsiio *csio; 1464c12c399aSSascha Wildner struct mps_softc *sc; 1465c12c399aSSascha Wildner struct mpssas_target *targ; 1466c12c399aSSascha Wildner struct mpssas_lun *lun; 1467c12c399aSSascha Wildner struct mps_command *cm; 1468c12c399aSSascha Wildner uint8_t i, lba_byte, *ref_tag_addr; 1469c12c399aSSascha Wildner uint16_t eedp_flags; 1470c12c399aSSascha Wildner 1471c12c399aSSascha Wildner sc = sassc->sc; 1472c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, "%s ccb %p\n", __func__, ccb); 1473c12c399aSSascha Wildner KKASSERT(lockstatus(&sc->mps_lock, curthread) != 0); 1474c12c399aSSascha Wildner 1475c12c399aSSascha Wildner csio = &ccb->csio; 1476c12c399aSSascha Wildner targ = &sassc->targets[csio->ccb_h.target_id]; 1477c12c399aSSascha Wildner if (targ->handle == 0x0) { 1478c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, "%s NULL handle for target %u\n", 1479c12c399aSSascha Wildner __func__, csio->ccb_h.target_id); 1480c12c399aSSascha Wildner csio->ccb_h.status = CAM_TID_INVALID; 1481c12c399aSSascha Wildner xpt_done(ccb); 1482c12c399aSSascha Wildner return; 1483c12c399aSSascha Wildner } 1484c12c399aSSascha Wildner /* 1485c12c399aSSascha Wildner * If devinfo is 0 this will be a volume. In that case don't tell CAM 1486c12c399aSSascha Wildner * that the volume has timed out. We want volumes to be enumerated 1487c12c399aSSascha Wildner * until they are deleted/removed, not just failed. 1488c12c399aSSascha Wildner */ 1489c12c399aSSascha Wildner if (targ->flags & MPSSAS_TARGET_INREMOVAL) { 1490c12c399aSSascha Wildner if (targ->devinfo == 0) 1491c12c399aSSascha Wildner csio->ccb_h.status = CAM_REQ_CMP; 1492c12c399aSSascha Wildner else 1493c12c399aSSascha Wildner csio->ccb_h.status = CAM_SEL_TIMEOUT; 1494c12c399aSSascha Wildner xpt_done(ccb); 1495c12c399aSSascha Wildner return; 1496c12c399aSSascha Wildner } 1497c12c399aSSascha Wildner 1498c12c399aSSascha Wildner if ((sc->mps_flags & MPS_FLAGS_SHUTDOWN) != 0) { 1499c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, "%s shutting down\n", __func__); 1500c12c399aSSascha Wildner csio->ccb_h.status = CAM_TID_INVALID; 1501c12c399aSSascha Wildner xpt_done(ccb); 1502c12c399aSSascha Wildner return; 1503c12c399aSSascha Wildner } 1504c12c399aSSascha Wildner 1505c12c399aSSascha Wildner cm = mps_alloc_command(sc); 1506c12c399aSSascha Wildner if (cm == NULL) { 1507c12c399aSSascha Wildner if ((sassc->flags & MPSSAS_QUEUE_FROZEN) == 0) { 1508c12c399aSSascha Wildner xpt_freeze_simq(sassc->sim, 1); 1509c12c399aSSascha Wildner sassc->flags |= MPSSAS_QUEUE_FROZEN; 1510c12c399aSSascha Wildner } 1511c12c399aSSascha Wildner ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1512c12c399aSSascha Wildner ccb->ccb_h.status |= CAM_REQUEUE_REQ; 1513c12c399aSSascha Wildner xpt_done(ccb); 1514c12c399aSSascha Wildner return; 1515c12c399aSSascha Wildner } 1516c12c399aSSascha Wildner 1517c12c399aSSascha Wildner req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req; 1518c12c399aSSascha Wildner bzero(req, sizeof(*req)); 1519c12c399aSSascha Wildner req->DevHandle = targ->handle; 1520c12c399aSSascha Wildner req->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; 1521c12c399aSSascha Wildner req->MsgFlags = 0; 1522c12c399aSSascha Wildner req->SenseBufferLowAddress = cm->cm_sense_busaddr; 1523c12c399aSSascha Wildner req->SenseBufferLength = MPS_SENSE_LEN; 1524c12c399aSSascha Wildner req->SGLFlags = 0; 1525c12c399aSSascha Wildner req->ChainOffset = 0; 1526c12c399aSSascha Wildner req->SGLOffset0 = 24; /* 32bit word offset to the SGL */ 1527c12c399aSSascha Wildner req->SGLOffset1= 0; 1528c12c399aSSascha Wildner req->SGLOffset2= 0; 1529c12c399aSSascha Wildner req->SGLOffset3= 0; 1530c12c399aSSascha Wildner req->SkipCount = 0; 1531c12c399aSSascha Wildner req->DataLength = csio->dxfer_len; 1532c12c399aSSascha Wildner req->BidirectionalDataLength = 0; 1533c12c399aSSascha Wildner req->IoFlags = csio->cdb_len; 1534c12c399aSSascha Wildner req->EEDPFlags = 0; 1535c12c399aSSascha Wildner 1536c12c399aSSascha Wildner /* Note: BiDirectional transfers are not supported */ 1537c12c399aSSascha Wildner switch (csio->ccb_h.flags & CAM_DIR_MASK) { 1538c12c399aSSascha Wildner case CAM_DIR_IN: 1539c12c399aSSascha Wildner req->Control = MPI2_SCSIIO_CONTROL_READ; 1540c12c399aSSascha Wildner cm->cm_flags |= MPS_CM_FLAGS_DATAIN; 1541c12c399aSSascha Wildner break; 1542c12c399aSSascha Wildner case CAM_DIR_OUT: 1543c12c399aSSascha Wildner req->Control = MPI2_SCSIIO_CONTROL_WRITE; 1544c12c399aSSascha Wildner cm->cm_flags |= MPS_CM_FLAGS_DATAOUT; 1545c12c399aSSascha Wildner break; 1546c12c399aSSascha Wildner case CAM_DIR_NONE: 1547c12c399aSSascha Wildner default: 1548c12c399aSSascha Wildner req->Control = MPI2_SCSIIO_CONTROL_NODATATRANSFER; 1549c12c399aSSascha Wildner break; 1550c12c399aSSascha Wildner } 1551c12c399aSSascha Wildner 1552c12c399aSSascha Wildner /* 1553c12c399aSSascha Wildner * It looks like the hardware doesn't require an explicit tag 1554c12c399aSSascha Wildner * number for each transaction. SAM Task Management not supported 1555c12c399aSSascha Wildner * at the moment. 1556c12c399aSSascha Wildner */ 1557c12c399aSSascha Wildner switch (csio->tag_action) { 1558c12c399aSSascha Wildner case MSG_HEAD_OF_Q_TAG: 1559c12c399aSSascha Wildner req->Control |= MPI2_SCSIIO_CONTROL_HEADOFQ; 1560c12c399aSSascha Wildner break; 1561c12c399aSSascha Wildner case MSG_ORDERED_Q_TAG: 1562c12c399aSSascha Wildner req->Control |= MPI2_SCSIIO_CONTROL_ORDEREDQ; 1563c12c399aSSascha Wildner break; 1564c12c399aSSascha Wildner case MSG_ACA_TASK: 1565c12c399aSSascha Wildner req->Control |= MPI2_SCSIIO_CONTROL_ACAQ; 1566c12c399aSSascha Wildner break; 1567c12c399aSSascha Wildner case CAM_TAG_ACTION_NONE: 1568c12c399aSSascha Wildner case MSG_SIMPLE_Q_TAG: 1569c12c399aSSascha Wildner default: 1570c12c399aSSascha Wildner req->Control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; 1571c12c399aSSascha Wildner break; 1572c12c399aSSascha Wildner } 1573c12c399aSSascha Wildner req->Control |= sc->mapping_table[csio->ccb_h.target_id].TLR_bits; 1574c12c399aSSascha Wildner 1575c12c399aSSascha Wildner if (MPS_SET_LUN(req->LUN, csio->ccb_h.target_lun) != 0) { 1576c12c399aSSascha Wildner mps_free_command(sc, cm); 1577c12c399aSSascha Wildner ccb->ccb_h.status = CAM_LUN_INVALID; 1578c12c399aSSascha Wildner xpt_done(ccb); 1579c12c399aSSascha Wildner return; 1580c12c399aSSascha Wildner } 1581c12c399aSSascha Wildner 1582c12c399aSSascha Wildner if (csio->ccb_h.flags & CAM_CDB_POINTER) 1583c12c399aSSascha Wildner bcopy(csio->cdb_io.cdb_ptr, &req->CDB.CDB32[0], csio->cdb_len); 1584c12c399aSSascha Wildner else 1585c12c399aSSascha Wildner bcopy(csio->cdb_io.cdb_bytes, &req->CDB.CDB32[0],csio->cdb_len); 1586c12c399aSSascha Wildner req->IoFlags = csio->cdb_len; 1587c12c399aSSascha Wildner 1588c12c399aSSascha Wildner /* 1589c12c399aSSascha Wildner * Check if EEDP is supported and enabled. If it is then check if the 1590c12c399aSSascha Wildner * SCSI opcode could be using EEDP. If so, make sure the LUN exists and 1591c12c399aSSascha Wildner * is formatted for EEDP support. If all of this is true, set CDB up 1592c12c399aSSascha Wildner * for EEDP transfer. 1593c12c399aSSascha Wildner */ 1594c12c399aSSascha Wildner eedp_flags = op_code_prot[req->CDB.CDB32[0]]; 1595c12c399aSSascha Wildner if (sc->eedp_enabled && eedp_flags) { 1596c12c399aSSascha Wildner SLIST_FOREACH(lun, &targ->luns, lun_link) { 1597c12c399aSSascha Wildner if (lun->lun_id == csio->ccb_h.target_lun) { 1598c12c399aSSascha Wildner break; 1599c12c399aSSascha Wildner } 1600c12c399aSSascha Wildner } 1601c12c399aSSascha Wildner 1602c12c399aSSascha Wildner if ((lun != NULL) && (lun->eedp_formatted)) { 1603c12c399aSSascha Wildner req->EEDPBlockSize = lun->eedp_block_size; 1604c12c399aSSascha Wildner eedp_flags |= (MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | 1605c12c399aSSascha Wildner MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | 1606c12c399aSSascha Wildner MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD); 1607c12c399aSSascha Wildner req->EEDPFlags = eedp_flags; 1608c12c399aSSascha Wildner 1609c12c399aSSascha Wildner /* 1610c12c399aSSascha Wildner * If CDB less than 32, fill in Primary Ref Tag with 1611c12c399aSSascha Wildner * low 4 bytes of LBA. If CDB is 32, tag stuff is 1612c12c399aSSascha Wildner * already there. Also, set protection bit. FreeBSD 1613c12c399aSSascha Wildner * currently does not support CDBs bigger than 16, but 1614c12c399aSSascha Wildner * the code doesn't hurt, and will be here for the 1615c12c399aSSascha Wildner * future. 1616c12c399aSSascha Wildner */ 1617c12c399aSSascha Wildner if (csio->cdb_len != 32) { 1618c12c399aSSascha Wildner lba_byte = (csio->cdb_len == 16) ? 6 : 2; 1619c12c399aSSascha Wildner ref_tag_addr = (uint8_t *)&req->CDB.EEDP32. 1620c12c399aSSascha Wildner PrimaryReferenceTag; 1621c12c399aSSascha Wildner for (i = 0; i < 4; i++) { 1622c12c399aSSascha Wildner *ref_tag_addr = 1623c12c399aSSascha Wildner req->CDB.CDB32[lba_byte + i]; 1624c12c399aSSascha Wildner ref_tag_addr++; 1625c12c399aSSascha Wildner } 1626c12c399aSSascha Wildner req->CDB.EEDP32.PrimaryApplicationTagMask = 1627c12c399aSSascha Wildner 0xFFFF; 1628c12c399aSSascha Wildner req->CDB.CDB32[1] = (req->CDB.CDB32[1] & 0x1F) | 1629c12c399aSSascha Wildner 0x20; 1630c12c399aSSascha Wildner } else { 1631c12c399aSSascha Wildner eedp_flags |= 1632c12c399aSSascha Wildner MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG; 1633c12c399aSSascha Wildner req->EEDPFlags = eedp_flags; 1634c12c399aSSascha Wildner req->CDB.CDB32[10] = (req->CDB.CDB32[10] & 1635c12c399aSSascha Wildner 0x1F) | 0x20; 1636c12c399aSSascha Wildner } 1637c12c399aSSascha Wildner } 1638c12c399aSSascha Wildner } 1639c12c399aSSascha Wildner 1640c12c399aSSascha Wildner cm->cm_data = csio->data_ptr; 1641c12c399aSSascha Wildner cm->cm_length = csio->dxfer_len; 1642c12c399aSSascha Wildner cm->cm_sge = &req->SGL; 1643c12c399aSSascha Wildner cm->cm_sglsize = (32 - 24) * 4; 1644c12c399aSSascha Wildner cm->cm_desc.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; 1645c12c399aSSascha Wildner cm->cm_desc.SCSIIO.DevHandle = targ->handle; 1646c12c399aSSascha Wildner cm->cm_complete = mpssas_scsiio_complete; 1647c12c399aSSascha Wildner cm->cm_complete_data = ccb; 1648c12c399aSSascha Wildner cm->cm_targ = targ; 1649c12c399aSSascha Wildner cm->cm_lun = csio->ccb_h.target_lun; 1650c12c399aSSascha Wildner cm->cm_ccb = ccb; 1651c12c399aSSascha Wildner 1652c12c399aSSascha Wildner /* 1653c12c399aSSascha Wildner * If HBA is a WD and the command is not for a retry, try to build a 1654c12c399aSSascha Wildner * direct I/O message. If failed, or the command is for a retry, send 1655c12c399aSSascha Wildner * the I/O to the IR volume itself. 1656c12c399aSSascha Wildner */ 1657c12c399aSSascha Wildner if (sc->WD_valid_config) { 1658c12c399aSSascha Wildner if (ccb->ccb_h.status != MPS_WD_RETRY) { 1659c12c399aSSascha Wildner mpssas_direct_drive_io(sassc, cm, ccb); 1660c12c399aSSascha Wildner } else { 1661c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_INPROG; 1662c12c399aSSascha Wildner } 1663c12c399aSSascha Wildner } 1664c12c399aSSascha Wildner 1665c12c399aSSascha Wildner callout_reset(&cm->cm_callout, (ccb->ccb_h.timeout * hz) / 1000, 1666c12c399aSSascha Wildner mpssas_scsiio_timeout, cm); 1667c12c399aSSascha Wildner 1668c12c399aSSascha Wildner targ->issued++; 1669c12c399aSSascha Wildner targ->outstanding++; 1670c12c399aSSascha Wildner TAILQ_INSERT_TAIL(&targ->commands, cm, cm_link); 1671c12c399aSSascha Wildner 1672c12c399aSSascha Wildner if ((sc->mps_debug & MPS_TRACE) != 0) 1673c12c399aSSascha Wildner mpssas_log_command(cm, "%s cm %p ccb %p outstanding %u\n", 1674c12c399aSSascha Wildner __func__, cm, ccb, targ->outstanding); 1675c12c399aSSascha Wildner 1676c12c399aSSascha Wildner mps_map_command(sc, cm); 1677c12c399aSSascha Wildner return; 1678c12c399aSSascha Wildner } 1679c12c399aSSascha Wildner 1680c12c399aSSascha Wildner static void 1681c12c399aSSascha Wildner mpssas_scsiio_complete(struct mps_softc *sc, struct mps_command *cm) 1682c12c399aSSascha Wildner { 1683c12c399aSSascha Wildner MPI2_SCSI_IO_REPLY *rep; 1684c12c399aSSascha Wildner union ccb *ccb; 1685c12c399aSSascha Wildner struct ccb_scsiio *csio; 1686c12c399aSSascha Wildner struct mpssas_softc *sassc; 1687c12c399aSSascha Wildner struct scsi_vpd_supported_page_list *vpd_list = NULL; 1688c12c399aSSascha Wildner u8 *TLR_bits, TLR_on; 1689c12c399aSSascha Wildner int dir = 0, i; 1690c12c399aSSascha Wildner u16 alloc_len; 1691c12c399aSSascha Wildner 1692c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, 1693c12c399aSSascha Wildner "%s cm %p SMID %u ccb %p reply %p outstanding %u\n", 1694c12c399aSSascha Wildner __func__, cm, cm->cm_desc.Default.SMID, cm->cm_ccb, cm->cm_reply, 1695c12c399aSSascha Wildner cm->cm_targ->outstanding); 1696c12c399aSSascha Wildner 1697c12c399aSSascha Wildner callout_stop(&cm->cm_callout); 1698c12c399aSSascha Wildner KKASSERT(lockstatus(&sc->mps_lock, curthread) != 0); 1699c12c399aSSascha Wildner 1700c12c399aSSascha Wildner sassc = sc->sassc; 1701c12c399aSSascha Wildner ccb = cm->cm_complete_data; 1702c12c399aSSascha Wildner csio = &ccb->csio; 1703c12c399aSSascha Wildner rep = (MPI2_SCSI_IO_REPLY *)cm->cm_reply; 1704c12c399aSSascha Wildner /* 1705c12c399aSSascha Wildner * XXX KDM if the chain allocation fails, does it matter if we do 1706c12c399aSSascha Wildner * the sync and unload here? It is simpler to do it in every case, 1707c12c399aSSascha Wildner * assuming it doesn't cause problems. 1708c12c399aSSascha Wildner */ 1709c12c399aSSascha Wildner if (cm->cm_data != NULL) { 1710c12c399aSSascha Wildner if (cm->cm_flags & MPS_CM_FLAGS_DATAIN) 1711c12c399aSSascha Wildner dir = BUS_DMASYNC_POSTREAD; 1712c12c399aSSascha Wildner else if (cm->cm_flags & MPS_CM_FLAGS_DATAOUT) 1713c12c399aSSascha Wildner dir = BUS_DMASYNC_POSTWRITE;; 1714c12c399aSSascha Wildner bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir); 1715c12c399aSSascha Wildner bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); 1716c12c399aSSascha Wildner } 1717c12c399aSSascha Wildner 1718c12c399aSSascha Wildner cm->cm_targ->completed++; 1719c12c399aSSascha Wildner cm->cm_targ->outstanding--; 1720c12c399aSSascha Wildner TAILQ_REMOVE(&cm->cm_targ->commands, cm, cm_link); 1721c12c399aSSascha Wildner 1722c12c399aSSascha Wildner if (cm->cm_state == MPS_CM_STATE_TIMEDOUT) { 1723c12c399aSSascha Wildner TAILQ_REMOVE(&cm->cm_targ->timedout_commands, cm, cm_recovery); 1724c12c399aSSascha Wildner if (cm->cm_reply != NULL) 1725c12c399aSSascha Wildner mpssas_log_command(cm, 1726c12c399aSSascha Wildner "completed timedout cm %p ccb %p during recovery " 1727c12c399aSSascha Wildner "ioc %x scsi %x state %x xfer %u\n", 1728c12c399aSSascha Wildner cm, cm->cm_ccb, 1729c12c399aSSascha Wildner rep->IOCStatus, rep->SCSIStatus, rep->SCSIState, 1730c12c399aSSascha Wildner rep->TransferCount); 1731c12c399aSSascha Wildner else 1732c12c399aSSascha Wildner mpssas_log_command(cm, 1733c12c399aSSascha Wildner "completed timedout cm %p ccb %p during recovery\n", 1734c12c399aSSascha Wildner cm, cm->cm_ccb); 1735c12c399aSSascha Wildner } else if (cm->cm_targ->tm != NULL) { 1736c12c399aSSascha Wildner if (cm->cm_reply != NULL) 1737c12c399aSSascha Wildner mpssas_log_command(cm, 1738c12c399aSSascha Wildner "completed cm %p ccb %p during recovery " 1739c12c399aSSascha Wildner "ioc %x scsi %x state %x xfer %u\n", 1740c12c399aSSascha Wildner cm, cm->cm_ccb, 1741c12c399aSSascha Wildner rep->IOCStatus, rep->SCSIStatus, rep->SCSIState, 1742c12c399aSSascha Wildner rep->TransferCount); 1743c12c399aSSascha Wildner else 1744c12c399aSSascha Wildner mpssas_log_command(cm, 1745c12c399aSSascha Wildner "completed cm %p ccb %p during recovery\n", 1746c12c399aSSascha Wildner cm, cm->cm_ccb); 1747c12c399aSSascha Wildner } else if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) { 1748c12c399aSSascha Wildner mpssas_log_command(cm, 1749c12c399aSSascha Wildner "reset completed cm %p ccb %p\n", 1750c12c399aSSascha Wildner cm, cm->cm_ccb); 1751c12c399aSSascha Wildner } 1752c12c399aSSascha Wildner 1753c12c399aSSascha Wildner if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { 1754c12c399aSSascha Wildner /* 1755c12c399aSSascha Wildner * We ran into an error after we tried to map the command, 1756c12c399aSSascha Wildner * so we're getting a callback without queueing the command 1757c12c399aSSascha Wildner * to the hardware. So we set the status here, and it will 1758c12c399aSSascha Wildner * be retained below. We'll go through the "fast path", 1759c12c399aSSascha Wildner * because there can be no reply when we haven't actually 1760c12c399aSSascha Wildner * gone out to the hardware. 1761c12c399aSSascha Wildner */ 1762c12c399aSSascha Wildner ccb->ccb_h.status |= CAM_REQUEUE_REQ; 1763c12c399aSSascha Wildner 1764c12c399aSSascha Wildner /* 1765c12c399aSSascha Wildner * Currently the only error included in the mask is 1766c12c399aSSascha Wildner * MPS_CM_FLAGS_CHAIN_FAILED, which means we're out of 1767c12c399aSSascha Wildner * chain frames. We need to freeze the queue until we get 1768c12c399aSSascha Wildner * a command that completed without this error, which will 1769c12c399aSSascha Wildner * hopefully have some chain frames attached that we can 1770c12c399aSSascha Wildner * use. If we wanted to get smarter about it, we would 1771c12c399aSSascha Wildner * only unfreeze the queue in this condition when we're 1772c12c399aSSascha Wildner * sure that we're getting some chain frames back. That's 1773c12c399aSSascha Wildner * probably unnecessary. 1774c12c399aSSascha Wildner */ 1775c12c399aSSascha Wildner if ((sassc->flags & MPSSAS_QUEUE_FROZEN) == 0) { 1776c12c399aSSascha Wildner xpt_freeze_simq(sassc->sim, 1); 1777c12c399aSSascha Wildner sassc->flags |= MPSSAS_QUEUE_FROZEN; 1778c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, "Error sending command, " 1779c12c399aSSascha Wildner "freezing SIM queue\n"); 1780c12c399aSSascha Wildner } 1781c12c399aSSascha Wildner } 1782c12c399aSSascha Wildner 1783c12c399aSSascha Wildner /* Take the fast path to completion */ 1784c12c399aSSascha Wildner if (cm->cm_reply == NULL) { 1785c12c399aSSascha Wildner if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { 1786c12c399aSSascha Wildner if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) 1787c12c399aSSascha Wildner ccb->ccb_h.status = CAM_SCSI_BUS_RESET; 1788c12c399aSSascha Wildner else { 1789c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP; 1790c12c399aSSascha Wildner ccb->csio.scsi_status = SCSI_STATUS_OK; 1791c12c399aSSascha Wildner } 1792c12c399aSSascha Wildner if (sassc->flags & MPSSAS_QUEUE_FROZEN) { 1793c12c399aSSascha Wildner ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 1794c12c399aSSascha Wildner sassc->flags &= ~MPSSAS_QUEUE_FROZEN; 1795c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, 1796c12c399aSSascha Wildner "Unfreezing SIM queue\n"); 1797c12c399aSSascha Wildner } 1798c12c399aSSascha Wildner } 1799c12c399aSSascha Wildner 1800c12c399aSSascha Wildner /* 1801c12c399aSSascha Wildner * There are two scenarios where the status won't be 1802c12c399aSSascha Wildner * CAM_REQ_CMP. The first is if MPS_CM_FLAGS_ERROR_MASK is 1803c12c399aSSascha Wildner * set, the second is in the MPS_FLAGS_DIAGRESET above. 1804c12c399aSSascha Wildner */ 1805c12c399aSSascha Wildner if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1806c12c399aSSascha Wildner /* 1807c12c399aSSascha Wildner * Freeze the dev queue so that commands are 1808c12c399aSSascha Wildner * executed in the correct order with after error 1809c12c399aSSascha Wildner * recovery. 1810c12c399aSSascha Wildner */ 1811c12c399aSSascha Wildner ccb->ccb_h.status |= CAM_DEV_QFRZN; 1812c12c399aSSascha Wildner xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1); 1813c12c399aSSascha Wildner } 1814c12c399aSSascha Wildner mps_free_command(sc, cm); 1815c12c399aSSascha Wildner xpt_done(ccb); 1816c12c399aSSascha Wildner return; 1817c12c399aSSascha Wildner } 1818c12c399aSSascha Wildner 1819c12c399aSSascha Wildner if (sc->mps_debug & MPS_TRACE) 1820c12c399aSSascha Wildner mpssas_log_command(cm, 1821c12c399aSSascha Wildner "ioc %x scsi %x state %x xfer %u\n", 1822c12c399aSSascha Wildner rep->IOCStatus, rep->SCSIStatus, 1823c12c399aSSascha Wildner rep->SCSIState, rep->TransferCount); 1824c12c399aSSascha Wildner 1825c12c399aSSascha Wildner /* 1826c12c399aSSascha Wildner * If this is a Direct Drive I/O, reissue the I/O to the original IR 1827c12c399aSSascha Wildner * Volume if an error occurred (normal I/O retry). Use the original 1828c12c399aSSascha Wildner * CCB, but set a flag that this will be a retry so that it's sent to 1829c12c399aSSascha Wildner * the original volume. Free the command but reuse the CCB. 1830c12c399aSSascha Wildner */ 1831c12c399aSSascha Wildner if (cm->cm_flags & MPS_CM_FLAGS_DD_IO) { 1832c12c399aSSascha Wildner mps_free_command(sc, cm); 1833c12c399aSSascha Wildner ccb->ccb_h.status = MPS_WD_RETRY; 1834c12c399aSSascha Wildner mpssas_action_scsiio(sassc, ccb); 1835c12c399aSSascha Wildner return; 1836c12c399aSSascha Wildner } 1837c12c399aSSascha Wildner 1838c12c399aSSascha Wildner switch (rep->IOCStatus & MPI2_IOCSTATUS_MASK) { 1839c12c399aSSascha Wildner case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: 1840c12c399aSSascha Wildner csio->resid = cm->cm_length - rep->TransferCount; 1841c12c399aSSascha Wildner /* FALLTHROUGH */ 1842c12c399aSSascha Wildner case MPI2_IOCSTATUS_SUCCESS: 1843c12c399aSSascha Wildner case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: 1844c12c399aSSascha Wildner 1845c12c399aSSascha Wildner if ((rep->IOCStatus & MPI2_IOCSTATUS_MASK) == 1846c12c399aSSascha Wildner MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR) 1847c12c399aSSascha Wildner mpssas_log_command(cm, "recovered error\n"); 1848c12c399aSSascha Wildner 1849c12c399aSSascha Wildner /* Completion failed at the transport level. */ 1850c12c399aSSascha Wildner if (rep->SCSIState & (MPI2_SCSI_STATE_NO_SCSI_STATUS | 1851c12c399aSSascha Wildner MPI2_SCSI_STATE_TERMINATED)) { 1852c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP_ERR; 1853c12c399aSSascha Wildner break; 1854c12c399aSSascha Wildner } 1855c12c399aSSascha Wildner 1856c12c399aSSascha Wildner /* In a modern packetized environment, an autosense failure 1857c12c399aSSascha Wildner * implies that there's not much else that can be done to 1858c12c399aSSascha Wildner * recover the command. 1859c12c399aSSascha Wildner */ 1860c12c399aSSascha Wildner if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_FAILED) { 1861c12c399aSSascha Wildner ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; 1862c12c399aSSascha Wildner break; 1863c12c399aSSascha Wildner } 1864c12c399aSSascha Wildner 1865c12c399aSSascha Wildner /* 1866c12c399aSSascha Wildner * CAM doesn't care about SAS Response Info data, but if this is 1867c12c399aSSascha Wildner * the state check if TLR should be done. If not, clear the 1868c12c399aSSascha Wildner * TLR_bits for the target. 1869c12c399aSSascha Wildner */ 1870c12c399aSSascha Wildner if ((rep->SCSIState & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) && 1871c12c399aSSascha Wildner ((rep->ResponseInfo & MPI2_SCSI_RI_MASK_REASONCODE) == 1872c12c399aSSascha Wildner MPS_SCSI_RI_INVALID_FRAME)) { 1873c12c399aSSascha Wildner sc->mapping_table[csio->ccb_h.target_id].TLR_bits = 1874c12c399aSSascha Wildner (u8)MPI2_SCSIIO_CONTROL_NO_TLR; 1875c12c399aSSascha Wildner } 1876c12c399aSSascha Wildner 1877c12c399aSSascha Wildner /* 1878c12c399aSSascha Wildner * Intentionally override the normal SCSI status reporting 1879c12c399aSSascha Wildner * for these two cases. These are likely to happen in a 1880c12c399aSSascha Wildner * multi-initiator environment, and we want to make sure that 1881c12c399aSSascha Wildner * CAM retries these commands rather than fail them. 1882c12c399aSSascha Wildner */ 1883c12c399aSSascha Wildner if ((rep->SCSIStatus == MPI2_SCSI_STATUS_COMMAND_TERMINATED) || 1884c12c399aSSascha Wildner (rep->SCSIStatus == MPI2_SCSI_STATUS_TASK_ABORTED)) { 1885c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_ABORTED; 1886c12c399aSSascha Wildner break; 1887c12c399aSSascha Wildner } 1888c12c399aSSascha Wildner 1889c12c399aSSascha Wildner /* Handle normal status and sense */ 1890c12c399aSSascha Wildner csio->scsi_status = rep->SCSIStatus; 1891c12c399aSSascha Wildner if (rep->SCSIStatus == MPI2_SCSI_STATUS_GOOD) 1892c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP; 1893c12c399aSSascha Wildner else 1894c12c399aSSascha Wildner ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; 1895c12c399aSSascha Wildner 1896c12c399aSSascha Wildner if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) { 1897c12c399aSSascha Wildner int sense_len, returned_sense_len; 1898c12c399aSSascha Wildner 1899c12c399aSSascha Wildner returned_sense_len = min(rep->SenseCount, 1900c12c399aSSascha Wildner sizeof(struct scsi_sense_data)); 1901c12c399aSSascha Wildner if (returned_sense_len < ccb->csio.sense_len) 1902c12c399aSSascha Wildner ccb->csio.sense_resid = ccb->csio.sense_len - 1903c12c399aSSascha Wildner returned_sense_len; 1904c12c399aSSascha Wildner else 1905c12c399aSSascha Wildner ccb->csio.sense_resid = 0; 1906c12c399aSSascha Wildner 1907c12c399aSSascha Wildner sense_len = min(returned_sense_len, 1908c12c399aSSascha Wildner ccb->csio.sense_len - ccb->csio.sense_resid); 1909c12c399aSSascha Wildner bzero(&ccb->csio.sense_data, 1910*bc14747bSSascha Wildner sizeof(ccb->csio.sense_data)); 1911c12c399aSSascha Wildner bcopy(cm->cm_sense, &ccb->csio.sense_data, sense_len); 1912c12c399aSSascha Wildner ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 1913c12c399aSSascha Wildner } 1914c12c399aSSascha Wildner 1915c12c399aSSascha Wildner /* 1916c12c399aSSascha Wildner * Check if this is an INQUIRY command. If it's a VPD inquiry, 1917c12c399aSSascha Wildner * and it's page code 0 (Supported Page List), and there is 1918c12c399aSSascha Wildner * inquiry data, and this is for a sequential access device, and 1919c12c399aSSascha Wildner * the device is an SSP target, and TLR is supported by the 1920c12c399aSSascha Wildner * controller, turn the TLR_bits value ON if page 0x90 is 1921c12c399aSSascha Wildner * supported. 1922c12c399aSSascha Wildner */ 1923c12c399aSSascha Wildner if ((csio->cdb_io.cdb_bytes[0] == INQUIRY) && 1924c12c399aSSascha Wildner (csio->cdb_io.cdb_bytes[1] & SI_EVPD) && 1925c12c399aSSascha Wildner (csio->cdb_io.cdb_bytes[2] == SVPD_SUPPORTED_PAGE_LIST) && 1926c12c399aSSascha Wildner (csio->data_ptr != NULL) && (((uint8_t *)cm->cm_data)[0] == 1927c12c399aSSascha Wildner T_SEQUENTIAL) && (sc->control_TLR) && 1928c12c399aSSascha Wildner (sc->mapping_table[csio->ccb_h.target_id].device_info & 1929c12c399aSSascha Wildner MPI2_SAS_DEVICE_INFO_SSP_TARGET)) { 1930c12c399aSSascha Wildner vpd_list = (struct scsi_vpd_supported_page_list *) 1931c12c399aSSascha Wildner csio->data_ptr; 1932c12c399aSSascha Wildner TLR_bits = &sc->mapping_table[csio->ccb_h.target_id]. 1933c12c399aSSascha Wildner TLR_bits; 1934c12c399aSSascha Wildner *TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR; 1935c12c399aSSascha Wildner TLR_on = (u8)MPI2_SCSIIO_CONTROL_TLR_ON; 1936c12c399aSSascha Wildner alloc_len = ((u16)csio->cdb_io.cdb_bytes[3] << 8) + 1937c12c399aSSascha Wildner csio->cdb_io.cdb_bytes[4]; 1938c12c399aSSascha Wildner for (i = 0; i < MIN(vpd_list->length, alloc_len); i++) { 1939c12c399aSSascha Wildner if (vpd_list->list[i] == 0x90) { 1940c12c399aSSascha Wildner *TLR_bits = TLR_on; 1941c12c399aSSascha Wildner break; 1942c12c399aSSascha Wildner } 1943c12c399aSSascha Wildner } 1944c12c399aSSascha Wildner } 1945c12c399aSSascha Wildner break; 1946c12c399aSSascha Wildner case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: 1947c12c399aSSascha Wildner case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: 1948c12c399aSSascha Wildner /* 1949c12c399aSSascha Wildner * If devinfo is 0 this will be a volume. In that case don't 1950c12c399aSSascha Wildner * tell CAM that the volume is not there. We want volumes to 1951c12c399aSSascha Wildner * be enumerated until they are deleted/removed, not just 1952c12c399aSSascha Wildner * failed. 1953c12c399aSSascha Wildner */ 1954c12c399aSSascha Wildner if (cm->cm_targ->devinfo == 0) 1955c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP; 1956c12c399aSSascha Wildner else 1957c12c399aSSascha Wildner ccb->ccb_h.status = CAM_DEV_NOT_THERE; 1958c12c399aSSascha Wildner break; 1959c12c399aSSascha Wildner case MPI2_IOCSTATUS_INVALID_SGL: 1960c12c399aSSascha Wildner mps_print_scsiio_cmd(sc, cm); 1961c12c399aSSascha Wildner ccb->ccb_h.status = CAM_UNREC_HBA_ERROR; 1962c12c399aSSascha Wildner break; 1963c12c399aSSascha Wildner case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: 1964c12c399aSSascha Wildner /* 1965c12c399aSSascha Wildner * This is one of the responses that comes back when an I/O 1966c12c399aSSascha Wildner * has been aborted. If it is because of a timeout that we 1967c12c399aSSascha Wildner * initiated, just set the status to CAM_CMD_TIMEOUT. 1968c12c399aSSascha Wildner * Otherwise set it to CAM_REQ_ABORTED. The effect on the 1969c12c399aSSascha Wildner * command is the same (it gets retried, subject to the 1970c12c399aSSascha Wildner * retry counter), the only difference is what gets printed 1971c12c399aSSascha Wildner * on the console. 1972c12c399aSSascha Wildner */ 1973c12c399aSSascha Wildner if (cm->cm_state == MPS_CM_STATE_TIMEDOUT) 1974c12c399aSSascha Wildner ccb->ccb_h.status = CAM_CMD_TIMEOUT; 1975c12c399aSSascha Wildner else 1976c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_ABORTED; 1977c12c399aSSascha Wildner break; 1978c12c399aSSascha Wildner case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: 1979c12c399aSSascha Wildner /* resid is ignored for this condition */ 1980c12c399aSSascha Wildner csio->resid = 0; 1981c12c399aSSascha Wildner ccb->ccb_h.status = CAM_DATA_RUN_ERR; 1982c12c399aSSascha Wildner break; 1983c12c399aSSascha Wildner case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: 1984c12c399aSSascha Wildner case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: 1985c12c399aSSascha Wildner /* 1986c12c399aSSascha Wildner * Since these are generally external (i.e. hopefully 1987c12c399aSSascha Wildner * transient transport-related) errors, retry these without 1988c12c399aSSascha Wildner * decrementing the retry count. 1989c12c399aSSascha Wildner */ 1990c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQUEUE_REQ; 1991c12c399aSSascha Wildner mpssas_log_command(cm, 1992c12c399aSSascha Wildner "terminated ioc %x scsi %x state %x xfer %u\n", 1993c12c399aSSascha Wildner rep->IOCStatus, rep->SCSIStatus, rep->SCSIState, 1994c12c399aSSascha Wildner rep->TransferCount); 1995c12c399aSSascha Wildner break; 1996c12c399aSSascha Wildner case MPI2_IOCSTATUS_INVALID_FUNCTION: 1997c12c399aSSascha Wildner case MPI2_IOCSTATUS_INTERNAL_ERROR: 1998c12c399aSSascha Wildner case MPI2_IOCSTATUS_INVALID_VPID: 1999c12c399aSSascha Wildner case MPI2_IOCSTATUS_INVALID_FIELD: 2000c12c399aSSascha Wildner case MPI2_IOCSTATUS_INVALID_STATE: 2001c12c399aSSascha Wildner case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED: 2002c12c399aSSascha Wildner case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: 2003c12c399aSSascha Wildner case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: 2004c12c399aSSascha Wildner case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: 2005c12c399aSSascha Wildner case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: 2006c12c399aSSascha Wildner default: 2007c12c399aSSascha Wildner mpssas_log_command(cm, 2008c12c399aSSascha Wildner "completed ioc %x scsi %x state %x xfer %u\n", 2009c12c399aSSascha Wildner rep->IOCStatus, rep->SCSIStatus, rep->SCSIState, 2010c12c399aSSascha Wildner rep->TransferCount); 2011c12c399aSSascha Wildner csio->resid = cm->cm_length; 2012c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2013c12c399aSSascha Wildner break; 2014c12c399aSSascha Wildner } 2015c12c399aSSascha Wildner 2016c12c399aSSascha Wildner if (sassc->flags & MPSSAS_QUEUE_FROZEN) { 2017c12c399aSSascha Wildner ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 2018c12c399aSSascha Wildner sassc->flags &= ~MPSSAS_QUEUE_FROZEN; 2019c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, "Command completed, " 2020c12c399aSSascha Wildner "unfreezing SIM queue\n"); 2021c12c399aSSascha Wildner } 2022c12c399aSSascha Wildner 2023c12c399aSSascha Wildner if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2024c12c399aSSascha Wildner ccb->ccb_h.status |= CAM_DEV_QFRZN; 2025c12c399aSSascha Wildner xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1); 2026c12c399aSSascha Wildner } 2027c12c399aSSascha Wildner 2028c12c399aSSascha Wildner mps_free_command(sc, cm); 2029c12c399aSSascha Wildner xpt_done(ccb); 2030c12c399aSSascha Wildner } 2031c12c399aSSascha Wildner 2032c12c399aSSascha Wildner static void 2033c12c399aSSascha Wildner mpssas_direct_drive_io(struct mpssas_softc *sassc, struct mps_command *cm, 2034c12c399aSSascha Wildner union ccb *ccb) { 2035c12c399aSSascha Wildner pMpi2SCSIIORequest_t pIO_req; 2036c12c399aSSascha Wildner struct mps_softc *sc = sassc->sc; 2037c12c399aSSascha Wildner uint64_t virtLBA; 2038c12c399aSSascha Wildner uint32_t physLBA, stripe_offset, stripe_unit; 2039c12c399aSSascha Wildner uint32_t io_size, column; 2040c12c399aSSascha Wildner uint8_t *ptrLBA, lba_idx, physLBA_byte, *CDB; 2041c12c399aSSascha Wildner 2042c12c399aSSascha Wildner /* 2043c12c399aSSascha Wildner * If this is a valid SCSI command (Read6, Read10, Read16, Write6, 2044c12c399aSSascha Wildner * Write10, or Write16), build a direct I/O message. Otherwise, the I/O 2045c12c399aSSascha Wildner * will be sent to the IR volume itself. Since Read6 and Write6 are a 2046c12c399aSSascha Wildner * bit different than the 10/16 CDBs, handle them separately. 2047c12c399aSSascha Wildner */ 2048c12c399aSSascha Wildner pIO_req = (pMpi2SCSIIORequest_t)cm->cm_req; 2049c12c399aSSascha Wildner CDB = pIO_req->CDB.CDB32; 2050c12c399aSSascha Wildner 2051c12c399aSSascha Wildner /* 2052c12c399aSSascha Wildner * Handle 6 byte CDBs. 2053c12c399aSSascha Wildner */ 2054c12c399aSSascha Wildner if ((pIO_req->DevHandle == sc->DD_dev_handle) && ((CDB[0] == READ_6) || 2055c12c399aSSascha Wildner (CDB[0] == WRITE_6))) { 2056c12c399aSSascha Wildner /* 2057c12c399aSSascha Wildner * Get the transfer size in blocks. 2058c12c399aSSascha Wildner */ 2059c12c399aSSascha Wildner io_size = (cm->cm_length >> sc->DD_block_exponent); 2060c12c399aSSascha Wildner 2061c12c399aSSascha Wildner /* 2062c12c399aSSascha Wildner * Get virtual LBA given in the CDB. 2063c12c399aSSascha Wildner */ 2064c12c399aSSascha Wildner virtLBA = ((uint64_t)(CDB[1] & 0x1F) << 16) | 2065c12c399aSSascha Wildner ((uint64_t)CDB[2] << 8) | (uint64_t)CDB[3]; 2066c12c399aSSascha Wildner 2067c12c399aSSascha Wildner /* 2068c12c399aSSascha Wildner * Check that LBA range for I/O does not exceed volume's 2069c12c399aSSascha Wildner * MaxLBA. 2070c12c399aSSascha Wildner */ 2071c12c399aSSascha Wildner if ((virtLBA + (uint64_t)io_size - 1) <= 2072c12c399aSSascha Wildner sc->DD_max_lba) { 2073c12c399aSSascha Wildner /* 2074c12c399aSSascha Wildner * Check if the I/O crosses a stripe boundary. If not, 2075c12c399aSSascha Wildner * translate the virtual LBA to a physical LBA and set 2076c12c399aSSascha Wildner * the DevHandle for the PhysDisk to be used. If it 2077c12c399aSSascha Wildner * does cross a boundry, do normal I/O. To get the 2078c12c399aSSascha Wildner * right DevHandle to use, get the map number for the 2079c12c399aSSascha Wildner * column, then use that map number to look up the 2080c12c399aSSascha Wildner * DevHandle of the PhysDisk. 2081c12c399aSSascha Wildner */ 2082c12c399aSSascha Wildner stripe_offset = (uint32_t)virtLBA & 2083c12c399aSSascha Wildner (sc->DD_stripe_size - 1); 2084c12c399aSSascha Wildner if ((stripe_offset + io_size) <= sc->DD_stripe_size) { 2085c12c399aSSascha Wildner physLBA = (uint32_t)virtLBA >> 2086c12c399aSSascha Wildner sc->DD_stripe_exponent; 2087c12c399aSSascha Wildner stripe_unit = physLBA / sc->DD_num_phys_disks; 2088c12c399aSSascha Wildner column = physLBA % sc->DD_num_phys_disks; 2089c12c399aSSascha Wildner pIO_req->DevHandle = 2090c12c399aSSascha Wildner sc->DD_column_map[column].dev_handle; 2091c12c399aSSascha Wildner cm->cm_desc.SCSIIO.DevHandle = 2092c12c399aSSascha Wildner pIO_req->DevHandle; 2093c12c399aSSascha Wildner 2094c12c399aSSascha Wildner physLBA = (stripe_unit << 2095c12c399aSSascha Wildner sc->DD_stripe_exponent) + stripe_offset; 2096c12c399aSSascha Wildner ptrLBA = &pIO_req->CDB.CDB32[1]; 2097c12c399aSSascha Wildner physLBA_byte = (uint8_t)(physLBA >> 16); 2098c12c399aSSascha Wildner *ptrLBA = physLBA_byte; 2099c12c399aSSascha Wildner ptrLBA = &pIO_req->CDB.CDB32[2]; 2100c12c399aSSascha Wildner physLBA_byte = (uint8_t)(physLBA >> 8); 2101c12c399aSSascha Wildner *ptrLBA = physLBA_byte; 2102c12c399aSSascha Wildner ptrLBA = &pIO_req->CDB.CDB32[3]; 2103c12c399aSSascha Wildner physLBA_byte = (uint8_t)physLBA; 2104c12c399aSSascha Wildner *ptrLBA = physLBA_byte; 2105c12c399aSSascha Wildner 2106c12c399aSSascha Wildner /* 2107c12c399aSSascha Wildner * Set flag that Direct Drive I/O is 2108c12c399aSSascha Wildner * being done. 2109c12c399aSSascha Wildner */ 2110c12c399aSSascha Wildner cm->cm_flags |= MPS_CM_FLAGS_DD_IO; 2111c12c399aSSascha Wildner } 2112c12c399aSSascha Wildner } 2113c12c399aSSascha Wildner return; 2114c12c399aSSascha Wildner } 2115c12c399aSSascha Wildner 2116c12c399aSSascha Wildner /* 2117c12c399aSSascha Wildner * Handle 10 or 16 byte CDBs. 2118c12c399aSSascha Wildner */ 2119c12c399aSSascha Wildner if ((pIO_req->DevHandle == sc->DD_dev_handle) && ((CDB[0] == READ_10) || 2120c12c399aSSascha Wildner (CDB[0] == WRITE_10) || (CDB[0] == READ_16) || 2121c12c399aSSascha Wildner (CDB[0] == WRITE_16))) { 2122c12c399aSSascha Wildner /* 2123c12c399aSSascha Wildner * For 16-byte CDB's, verify that the upper 4 bytes of the CDB 2124c12c399aSSascha Wildner * are 0. If not, this is accessing beyond 2TB so handle it in 2125c12c399aSSascha Wildner * the else section. 10-byte CDB's are OK. 2126c12c399aSSascha Wildner */ 2127c12c399aSSascha Wildner if ((CDB[0] < READ_16) || 2128c12c399aSSascha Wildner !(CDB[2] | CDB[3] | CDB[4] | CDB[5])) { 2129c12c399aSSascha Wildner /* 2130c12c399aSSascha Wildner * Get the transfer size in blocks. 2131c12c399aSSascha Wildner */ 2132c12c399aSSascha Wildner io_size = (cm->cm_length >> sc->DD_block_exponent); 2133c12c399aSSascha Wildner 2134c12c399aSSascha Wildner /* 2135c12c399aSSascha Wildner * Get virtual LBA. Point to correct lower 4 bytes of 2136c12c399aSSascha Wildner * LBA in the CDB depending on command. 2137c12c399aSSascha Wildner */ 2138c12c399aSSascha Wildner lba_idx = (CDB[0] < READ_16) ? 2 : 6; 2139c12c399aSSascha Wildner virtLBA = ((uint64_t)CDB[lba_idx] << 24) | 2140c12c399aSSascha Wildner ((uint64_t)CDB[lba_idx + 1] << 16) | 2141c12c399aSSascha Wildner ((uint64_t)CDB[lba_idx + 2] << 8) | 2142c12c399aSSascha Wildner (uint64_t)CDB[lba_idx + 3]; 2143c12c399aSSascha Wildner 2144c12c399aSSascha Wildner /* 2145c12c399aSSascha Wildner * Check that LBA range for I/O does not exceed volume's 2146c12c399aSSascha Wildner * MaxLBA. 2147c12c399aSSascha Wildner */ 2148c12c399aSSascha Wildner if ((virtLBA + (uint64_t)io_size - 1) <= 2149c12c399aSSascha Wildner sc->DD_max_lba) { 2150c12c399aSSascha Wildner /* 2151c12c399aSSascha Wildner * Check if the I/O crosses a stripe boundary. 2152c12c399aSSascha Wildner * If not, translate the virtual LBA to a 2153c12c399aSSascha Wildner * physical LBA and set the DevHandle for the 2154c12c399aSSascha Wildner * PhysDisk to be used. If it does cross a 2155c12c399aSSascha Wildner * boundry, do normal I/O. To get the right 2156c12c399aSSascha Wildner * DevHandle to use, get the map number for the 2157c12c399aSSascha Wildner * column, then use that map number to look up 2158c12c399aSSascha Wildner * the DevHandle of the PhysDisk. 2159c12c399aSSascha Wildner */ 2160c12c399aSSascha Wildner stripe_offset = (uint32_t)virtLBA & 2161c12c399aSSascha Wildner (sc->DD_stripe_size - 1); 2162c12c399aSSascha Wildner if ((stripe_offset + io_size) <= 2163c12c399aSSascha Wildner sc->DD_stripe_size) { 2164c12c399aSSascha Wildner physLBA = (uint32_t)virtLBA >> 2165c12c399aSSascha Wildner sc->DD_stripe_exponent; 2166c12c399aSSascha Wildner stripe_unit = physLBA / 2167c12c399aSSascha Wildner sc->DD_num_phys_disks; 2168c12c399aSSascha Wildner column = physLBA % 2169c12c399aSSascha Wildner sc->DD_num_phys_disks; 2170c12c399aSSascha Wildner pIO_req->DevHandle = 2171c12c399aSSascha Wildner sc->DD_column_map[column]. 2172c12c399aSSascha Wildner dev_handle; 2173c12c399aSSascha Wildner cm->cm_desc.SCSIIO.DevHandle = 2174c12c399aSSascha Wildner pIO_req->DevHandle; 2175c12c399aSSascha Wildner 2176c12c399aSSascha Wildner physLBA = (stripe_unit << 2177c12c399aSSascha Wildner sc->DD_stripe_exponent) + 2178c12c399aSSascha Wildner stripe_offset; 2179c12c399aSSascha Wildner ptrLBA = 2180c12c399aSSascha Wildner &pIO_req->CDB.CDB32[lba_idx]; 2181c12c399aSSascha Wildner physLBA_byte = (uint8_t)(physLBA >> 24); 2182c12c399aSSascha Wildner *ptrLBA = physLBA_byte; 2183c12c399aSSascha Wildner ptrLBA = 2184c12c399aSSascha Wildner &pIO_req->CDB.CDB32[lba_idx + 1]; 2185c12c399aSSascha Wildner physLBA_byte = (uint8_t)(physLBA >> 16); 2186c12c399aSSascha Wildner *ptrLBA = physLBA_byte; 2187c12c399aSSascha Wildner ptrLBA = 2188c12c399aSSascha Wildner &pIO_req->CDB.CDB32[lba_idx + 2]; 2189c12c399aSSascha Wildner physLBA_byte = (uint8_t)(physLBA >> 8); 2190c12c399aSSascha Wildner *ptrLBA = physLBA_byte; 2191c12c399aSSascha Wildner ptrLBA = 2192c12c399aSSascha Wildner &pIO_req->CDB.CDB32[lba_idx + 3]; 2193c12c399aSSascha Wildner physLBA_byte = (uint8_t)physLBA; 2194c12c399aSSascha Wildner *ptrLBA = physLBA_byte; 2195c12c399aSSascha Wildner 2196c12c399aSSascha Wildner /* 2197c12c399aSSascha Wildner * Set flag that Direct Drive I/O is 2198c12c399aSSascha Wildner * being done. 2199c12c399aSSascha Wildner */ 2200c12c399aSSascha Wildner cm->cm_flags |= MPS_CM_FLAGS_DD_IO; 2201c12c399aSSascha Wildner } 2202c12c399aSSascha Wildner } 2203c12c399aSSascha Wildner } else { 2204c12c399aSSascha Wildner /* 2205c12c399aSSascha Wildner * 16-byte CDB and the upper 4 bytes of the CDB are not 2206c12c399aSSascha Wildner * 0. Get the transfer size in blocks. 2207c12c399aSSascha Wildner */ 2208c12c399aSSascha Wildner io_size = (cm->cm_length >> sc->DD_block_exponent); 2209c12c399aSSascha Wildner 2210c12c399aSSascha Wildner /* 2211c12c399aSSascha Wildner * Get virtual LBA. 2212c12c399aSSascha Wildner */ 2213c12c399aSSascha Wildner virtLBA = ((uint64_t)CDB[2] << 54) | 2214c12c399aSSascha Wildner ((uint64_t)CDB[3] << 48) | 2215c12c399aSSascha Wildner ((uint64_t)CDB[4] << 40) | 2216c12c399aSSascha Wildner ((uint64_t)CDB[5] << 32) | 2217c12c399aSSascha Wildner ((uint64_t)CDB[6] << 24) | 2218c12c399aSSascha Wildner ((uint64_t)CDB[7] << 16) | 2219c12c399aSSascha Wildner ((uint64_t)CDB[8] << 8) | 2220c12c399aSSascha Wildner (uint64_t)CDB[9]; 2221c12c399aSSascha Wildner 2222c12c399aSSascha Wildner /* 2223c12c399aSSascha Wildner * Check that LBA range for I/O does not exceed volume's 2224c12c399aSSascha Wildner * MaxLBA. 2225c12c399aSSascha Wildner */ 2226c12c399aSSascha Wildner if ((virtLBA + (uint64_t)io_size - 1) <= 2227c12c399aSSascha Wildner sc->DD_max_lba) { 2228c12c399aSSascha Wildner /* 2229c12c399aSSascha Wildner * Check if the I/O crosses a stripe boundary. 2230c12c399aSSascha Wildner * If not, translate the virtual LBA to a 2231c12c399aSSascha Wildner * physical LBA and set the DevHandle for the 2232c12c399aSSascha Wildner * PhysDisk to be used. If it does cross a 2233c12c399aSSascha Wildner * boundry, do normal I/O. To get the right 2234c12c399aSSascha Wildner * DevHandle to use, get the map number for the 2235c12c399aSSascha Wildner * column, then use that map number to look up 2236c12c399aSSascha Wildner * the DevHandle of the PhysDisk. 2237c12c399aSSascha Wildner */ 2238c12c399aSSascha Wildner stripe_offset = (uint32_t)virtLBA & 2239c12c399aSSascha Wildner (sc->DD_stripe_size - 1); 2240c12c399aSSascha Wildner if ((stripe_offset + io_size) <= 2241c12c399aSSascha Wildner sc->DD_stripe_size) { 2242c12c399aSSascha Wildner physLBA = (uint32_t)(virtLBA >> 2243c12c399aSSascha Wildner sc->DD_stripe_exponent); 2244c12c399aSSascha Wildner stripe_unit = physLBA / 2245c12c399aSSascha Wildner sc->DD_num_phys_disks; 2246c12c399aSSascha Wildner column = physLBA % 2247c12c399aSSascha Wildner sc->DD_num_phys_disks; 2248c12c399aSSascha Wildner pIO_req->DevHandle = 2249c12c399aSSascha Wildner sc->DD_column_map[column]. 2250c12c399aSSascha Wildner dev_handle; 2251c12c399aSSascha Wildner cm->cm_desc.SCSIIO.DevHandle = 2252c12c399aSSascha Wildner pIO_req->DevHandle; 2253c12c399aSSascha Wildner 2254c12c399aSSascha Wildner physLBA = (stripe_unit << 2255c12c399aSSascha Wildner sc->DD_stripe_exponent) + 2256c12c399aSSascha Wildner stripe_offset; 2257c12c399aSSascha Wildner 2258c12c399aSSascha Wildner /* 2259c12c399aSSascha Wildner * Set upper 4 bytes of LBA to 0. We 2260c12c399aSSascha Wildner * assume that the phys disks are less 2261c12c399aSSascha Wildner * than 2 TB's in size. Then, set the 2262c12c399aSSascha Wildner * lower 4 bytes. 2263c12c399aSSascha Wildner */ 2264c12c399aSSascha Wildner pIO_req->CDB.CDB32[2] = 0; 2265c12c399aSSascha Wildner pIO_req->CDB.CDB32[3] = 0; 2266c12c399aSSascha Wildner pIO_req->CDB.CDB32[4] = 0; 2267c12c399aSSascha Wildner pIO_req->CDB.CDB32[5] = 0; 2268c12c399aSSascha Wildner ptrLBA = &pIO_req->CDB.CDB32[6]; 2269c12c399aSSascha Wildner physLBA_byte = (uint8_t)(physLBA >> 24); 2270c12c399aSSascha Wildner *ptrLBA = physLBA_byte; 2271c12c399aSSascha Wildner ptrLBA = &pIO_req->CDB.CDB32[7]; 2272c12c399aSSascha Wildner physLBA_byte = (uint8_t)(physLBA >> 16); 2273c12c399aSSascha Wildner *ptrLBA = physLBA_byte; 2274c12c399aSSascha Wildner ptrLBA = &pIO_req->CDB.CDB32[8]; 2275c12c399aSSascha Wildner physLBA_byte = (uint8_t)(physLBA >> 8); 2276c12c399aSSascha Wildner *ptrLBA = physLBA_byte; 2277c12c399aSSascha Wildner ptrLBA = &pIO_req->CDB.CDB32[9]; 2278c12c399aSSascha Wildner physLBA_byte = (uint8_t)physLBA; 2279c12c399aSSascha Wildner *ptrLBA = physLBA_byte; 2280c12c399aSSascha Wildner 2281c12c399aSSascha Wildner /* 2282c12c399aSSascha Wildner * Set flag that Direct Drive I/O is 2283c12c399aSSascha Wildner * being done. 2284c12c399aSSascha Wildner */ 2285c12c399aSSascha Wildner cm->cm_flags |= MPS_CM_FLAGS_DD_IO; 2286c12c399aSSascha Wildner } 2287c12c399aSSascha Wildner } 2288c12c399aSSascha Wildner } 2289c12c399aSSascha Wildner } 2290c12c399aSSascha Wildner } 2291c12c399aSSascha Wildner 2292c12c399aSSascha Wildner #if __FreeBSD_version >= 900026 2293c12c399aSSascha Wildner static void 2294c12c399aSSascha Wildner mpssas_smpio_complete(struct mps_softc *sc, struct mps_command *cm) 2295c12c399aSSascha Wildner { 2296c12c399aSSascha Wildner MPI2_SMP_PASSTHROUGH_REPLY *rpl; 2297c12c399aSSascha Wildner MPI2_SMP_PASSTHROUGH_REQUEST *req; 2298c12c399aSSascha Wildner uint64_t sasaddr; 2299c12c399aSSascha Wildner union ccb *ccb; 2300c12c399aSSascha Wildner 2301c12c399aSSascha Wildner ccb = cm->cm_complete_data; 2302c12c399aSSascha Wildner 2303c12c399aSSascha Wildner /* 2304c12c399aSSascha Wildner * Currently there should be no way we can hit this case. It only 2305c12c399aSSascha Wildner * happens when we have a failure to allocate chain frames, and SMP 2306c12c399aSSascha Wildner * commands require two S/G elements only. That should be handled 2307c12c399aSSascha Wildner * in the standard request size. 2308c12c399aSSascha Wildner */ 2309c12c399aSSascha Wildner if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { 2310c12c399aSSascha Wildner mps_printf(sc, "%s: cm_flags = %#x on SMP request!\n", 2311c12c399aSSascha Wildner __func__, cm->cm_flags); 2312c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2313c12c399aSSascha Wildner goto bailout; 2314c12c399aSSascha Wildner } 2315c12c399aSSascha Wildner 2316c12c399aSSascha Wildner rpl = (MPI2_SMP_PASSTHROUGH_REPLY *)cm->cm_reply; 2317c12c399aSSascha Wildner if (rpl == NULL) { 2318c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, "%s: NULL cm_reply!\n", __func__); 2319c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2320c12c399aSSascha Wildner goto bailout; 2321c12c399aSSascha Wildner } 2322c12c399aSSascha Wildner 2323c12c399aSSascha Wildner req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req; 2324c12c399aSSascha Wildner sasaddr = le32toh(req->SASAddress.Low); 2325c12c399aSSascha Wildner sasaddr |= ((uint64_t)(le32toh(req->SASAddress.High))) << 32; 2326c12c399aSSascha Wildner 2327c12c399aSSascha Wildner if ((rpl->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS || 2328c12c399aSSascha Wildner rpl->SASStatus != MPI2_SASSTATUS_SUCCESS) { 2329c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, "%s: IOCStatus %04x SASStatus %02x\n", 2330c12c399aSSascha Wildner __func__, rpl->IOCStatus, rpl->SASStatus); 2331c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2332c12c399aSSascha Wildner goto bailout; 2333c12c399aSSascha Wildner } 2334c12c399aSSascha Wildner 2335c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, "%s: SMP request to SAS address " 2336c12c399aSSascha Wildner "%#jx completed successfully\n", __func__, 2337c12c399aSSascha Wildner (uintmax_t)sasaddr); 2338c12c399aSSascha Wildner 2339c12c399aSSascha Wildner if (ccb->smpio.smp_response[2] == SMP_FR_ACCEPTED) 2340c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP; 2341c12c399aSSascha Wildner else 2342c12c399aSSascha Wildner ccb->ccb_h.status = CAM_SMP_STATUS_ERROR; 2343c12c399aSSascha Wildner 2344c12c399aSSascha Wildner bailout: 2345c12c399aSSascha Wildner /* 2346c12c399aSSascha Wildner * We sync in both directions because we had DMAs in the S/G list 2347c12c399aSSascha Wildner * in both directions. 2348c12c399aSSascha Wildner */ 2349c12c399aSSascha Wildner bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, 2350c12c399aSSascha Wildner BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 2351c12c399aSSascha Wildner bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); 2352c12c399aSSascha Wildner mps_free_command(sc, cm); 2353c12c399aSSascha Wildner xpt_done(ccb); 2354c12c399aSSascha Wildner } 2355c12c399aSSascha Wildner 2356c12c399aSSascha Wildner static void 2357c12c399aSSascha Wildner mpssas_send_smpcmd(struct mpssas_softc *sassc, union ccb *ccb, uint64_t sasaddr) 2358c12c399aSSascha Wildner { 2359c12c399aSSascha Wildner struct mps_command *cm; 2360c12c399aSSascha Wildner uint8_t *request, *response; 2361c12c399aSSascha Wildner MPI2_SMP_PASSTHROUGH_REQUEST *req; 2362c12c399aSSascha Wildner struct mps_softc *sc; 2363c12c399aSSascha Wildner int error; 2364c12c399aSSascha Wildner 2365c12c399aSSascha Wildner sc = sassc->sc; 2366c12c399aSSascha Wildner error = 0; 2367c12c399aSSascha Wildner 2368c12c399aSSascha Wildner /* 2369c12c399aSSascha Wildner * XXX We don't yet support physical addresses here. 2370c12c399aSSascha Wildner */ 2371c12c399aSSascha Wildner if (ccb->ccb_h.flags & (CAM_DATA_PHYS|CAM_SG_LIST_PHYS)) { 2372c12c399aSSascha Wildner mps_printf(sc, "%s: physical addresses not supported\n", 2373c12c399aSSascha Wildner __func__); 2374c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_INVALID; 2375c12c399aSSascha Wildner xpt_done(ccb); 2376c12c399aSSascha Wildner return; 2377c12c399aSSascha Wildner } 2378c12c399aSSascha Wildner 2379c12c399aSSascha Wildner /* 2380c12c399aSSascha Wildner * If the user wants to send an S/G list, check to make sure they 2381c12c399aSSascha Wildner * have single buffers. 2382c12c399aSSascha Wildner */ 2383c12c399aSSascha Wildner if (ccb->ccb_h.flags & CAM_SCATTER_VALID) { 2384c12c399aSSascha Wildner /* 2385c12c399aSSascha Wildner * The chip does not support more than one buffer for the 2386c12c399aSSascha Wildner * request or response. 2387c12c399aSSascha Wildner */ 2388c12c399aSSascha Wildner if ((ccb->smpio.smp_request_sglist_cnt > 1) 2389c12c399aSSascha Wildner || (ccb->smpio.smp_response_sglist_cnt > 1)) { 2390c12c399aSSascha Wildner mps_printf(sc, "%s: multiple request or response " 2391c12c399aSSascha Wildner "buffer segments not supported for SMP\n", 2392c12c399aSSascha Wildner __func__); 2393c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_INVALID; 2394c12c399aSSascha Wildner xpt_done(ccb); 2395c12c399aSSascha Wildner return; 2396c12c399aSSascha Wildner } 2397c12c399aSSascha Wildner 2398c12c399aSSascha Wildner /* 2399c12c399aSSascha Wildner * The CAM_SCATTER_VALID flag was originally implemented 2400c12c399aSSascha Wildner * for the XPT_SCSI_IO CCB, which only has one data pointer. 2401c12c399aSSascha Wildner * We have two. So, just take that flag to mean that we 2402c12c399aSSascha Wildner * might have S/G lists, and look at the S/G segment count 2403c12c399aSSascha Wildner * to figure out whether that is the case for each individual 2404c12c399aSSascha Wildner * buffer. 2405c12c399aSSascha Wildner */ 2406c12c399aSSascha Wildner if (ccb->smpio.smp_request_sglist_cnt != 0) { 2407c12c399aSSascha Wildner bus_dma_segment_t *req_sg; 2408c12c399aSSascha Wildner 2409c12c399aSSascha Wildner req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request; 2410c12c399aSSascha Wildner request = (uint8_t *)req_sg[0].ds_addr; 2411c12c399aSSascha Wildner } else 2412c12c399aSSascha Wildner request = ccb->smpio.smp_request; 2413c12c399aSSascha Wildner 2414c12c399aSSascha Wildner if (ccb->smpio.smp_response_sglist_cnt != 0) { 2415c12c399aSSascha Wildner bus_dma_segment_t *rsp_sg; 2416c12c399aSSascha Wildner 2417c12c399aSSascha Wildner rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response; 2418c12c399aSSascha Wildner response = (uint8_t *)rsp_sg[0].ds_addr; 2419c12c399aSSascha Wildner } else 2420c12c399aSSascha Wildner response = ccb->smpio.smp_response; 2421c12c399aSSascha Wildner } else { 2422c12c399aSSascha Wildner request = ccb->smpio.smp_request; 2423c12c399aSSascha Wildner response = ccb->smpio.smp_response; 2424c12c399aSSascha Wildner } 2425c12c399aSSascha Wildner 2426c12c399aSSascha Wildner cm = mps_alloc_command(sc); 2427c12c399aSSascha Wildner if (cm == NULL) { 2428c12c399aSSascha Wildner mps_printf(sc, "%s: cannot allocate command\n", __func__); 2429c12c399aSSascha Wildner ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 2430c12c399aSSascha Wildner xpt_done(ccb); 2431c12c399aSSascha Wildner return; 2432c12c399aSSascha Wildner } 2433c12c399aSSascha Wildner 2434c12c399aSSascha Wildner req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req; 2435c12c399aSSascha Wildner bzero(req, sizeof(*req)); 2436c12c399aSSascha Wildner req->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; 2437c12c399aSSascha Wildner 2438c12c399aSSascha Wildner /* Allow the chip to use any route to this SAS address. */ 2439c12c399aSSascha Wildner req->PhysicalPort = 0xff; 2440c12c399aSSascha Wildner 2441c12c399aSSascha Wildner req->RequestDataLength = ccb->smpio.smp_request_len; 2442c12c399aSSascha Wildner req->SGLFlags = 2443c12c399aSSascha Wildner MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE | MPI2_SGLFLAGS_SGL_TYPE_MPI; 2444c12c399aSSascha Wildner 2445c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, "%s: sending SMP request to SAS " 2446c12c399aSSascha Wildner "address %#jx\n", __func__, (uintmax_t)sasaddr); 2447c12c399aSSascha Wildner 2448c12c399aSSascha Wildner mpi_init_sge(cm, req, &req->SGL); 2449c12c399aSSascha Wildner 2450c12c399aSSascha Wildner /* 2451c12c399aSSascha Wildner * Set up a uio to pass into mps_map_command(). This allows us to 2452c12c399aSSascha Wildner * do one map command, and one busdma call in there. 2453c12c399aSSascha Wildner */ 2454c12c399aSSascha Wildner cm->cm_uio.uio_iov = cm->cm_iovec; 2455c12c399aSSascha Wildner cm->cm_uio.uio_iovcnt = 2; 2456c12c399aSSascha Wildner cm->cm_uio.uio_segflg = UIO_SYSSPACE; 2457c12c399aSSascha Wildner 2458c12c399aSSascha Wildner /* 2459c12c399aSSascha Wildner * The read/write flag isn't used by busdma, but set it just in 2460c12c399aSSascha Wildner * case. This isn't exactly accurate, either, since we're going in 2461c12c399aSSascha Wildner * both directions. 2462c12c399aSSascha Wildner */ 2463c12c399aSSascha Wildner cm->cm_uio.uio_rw = UIO_WRITE; 2464c12c399aSSascha Wildner 2465c12c399aSSascha Wildner cm->cm_iovec[0].iov_base = request; 2466c12c399aSSascha Wildner cm->cm_iovec[0].iov_len = req->RequestDataLength; 2467c12c399aSSascha Wildner cm->cm_iovec[1].iov_base = response; 2468c12c399aSSascha Wildner cm->cm_iovec[1].iov_len = ccb->smpio.smp_response_len; 2469c12c399aSSascha Wildner 2470c12c399aSSascha Wildner cm->cm_uio.uio_resid = cm->cm_iovec[0].iov_len + 2471c12c399aSSascha Wildner cm->cm_iovec[1].iov_len; 2472c12c399aSSascha Wildner 2473c12c399aSSascha Wildner /* 2474c12c399aSSascha Wildner * Trigger a warning message in mps_data_cb() for the user if we 2475c12c399aSSascha Wildner * wind up exceeding two S/G segments. The chip expects one 2476c12c399aSSascha Wildner * segment for the request and another for the response. 2477c12c399aSSascha Wildner */ 2478c12c399aSSascha Wildner cm->cm_max_segs = 2; 2479c12c399aSSascha Wildner 2480c12c399aSSascha Wildner cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 2481c12c399aSSascha Wildner cm->cm_complete = mpssas_smpio_complete; 2482c12c399aSSascha Wildner cm->cm_complete_data = ccb; 2483c12c399aSSascha Wildner 2484c12c399aSSascha Wildner /* 2485c12c399aSSascha Wildner * Tell the mapping code that we're using a uio, and that this is 2486c12c399aSSascha Wildner * an SMP passthrough request. There is a little special-case 2487c12c399aSSascha Wildner * logic there (in mps_data_cb()) to handle the bidirectional 2488c12c399aSSascha Wildner * transfer. 2489c12c399aSSascha Wildner */ 2490c12c399aSSascha Wildner cm->cm_flags |= MPS_CM_FLAGS_USE_UIO | MPS_CM_FLAGS_SMP_PASS | 2491c12c399aSSascha Wildner MPS_CM_FLAGS_DATAIN | MPS_CM_FLAGS_DATAOUT; 2492c12c399aSSascha Wildner 2493c12c399aSSascha Wildner /* The chip data format is little endian. */ 2494c12c399aSSascha Wildner req->SASAddress.High = htole32(sasaddr >> 32); 2495c12c399aSSascha Wildner req->SASAddress.Low = htole32(sasaddr); 2496c12c399aSSascha Wildner 2497c12c399aSSascha Wildner /* 2498c12c399aSSascha Wildner * XXX Note that we don't have a timeout/abort mechanism here. 2499c12c399aSSascha Wildner * From the manual, it looks like task management requests only 2500c12c399aSSascha Wildner * work for SCSI IO and SATA passthrough requests. We may need to 2501c12c399aSSascha Wildner * have a mechanism to retry requests in the event of a chip reset 2502c12c399aSSascha Wildner * at least. Hopefully the chip will insure that any errors short 2503c12c399aSSascha Wildner * of that are relayed back to the driver. 2504c12c399aSSascha Wildner */ 2505c12c399aSSascha Wildner error = mps_map_command(sc, cm); 2506c12c399aSSascha Wildner if ((error != 0) && (error != EINPROGRESS)) { 2507c12c399aSSascha Wildner mps_printf(sc, "%s: error %d returned from mps_map_command()\n", 2508c12c399aSSascha Wildner __func__, error); 2509c12c399aSSascha Wildner goto bailout_error; 2510c12c399aSSascha Wildner } 2511c12c399aSSascha Wildner 2512c12c399aSSascha Wildner return; 2513c12c399aSSascha Wildner 2514c12c399aSSascha Wildner bailout_error: 2515c12c399aSSascha Wildner mps_free_command(sc, cm); 2516c12c399aSSascha Wildner ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 2517c12c399aSSascha Wildner xpt_done(ccb); 2518c12c399aSSascha Wildner return; 2519c12c399aSSascha Wildner 2520c12c399aSSascha Wildner } 2521c12c399aSSascha Wildner 2522c12c399aSSascha Wildner static void 2523c12c399aSSascha Wildner mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb) 2524c12c399aSSascha Wildner { 2525c12c399aSSascha Wildner struct mps_softc *sc; 2526c12c399aSSascha Wildner struct mpssas_target *targ; 2527c12c399aSSascha Wildner uint64_t sasaddr = 0; 2528c12c399aSSascha Wildner 2529c12c399aSSascha Wildner sc = sassc->sc; 2530c12c399aSSascha Wildner 2531c12c399aSSascha Wildner /* 2532c12c399aSSascha Wildner * Make sure the target exists. 2533c12c399aSSascha Wildner */ 2534c12c399aSSascha Wildner targ = &sassc->targets[ccb->ccb_h.target_id]; 2535c12c399aSSascha Wildner if (targ->handle == 0x0) { 2536c12c399aSSascha Wildner mps_printf(sc, "%s: target %d does not exist!\n", __func__, 2537c12c399aSSascha Wildner ccb->ccb_h.target_id); 2538c12c399aSSascha Wildner ccb->ccb_h.status = CAM_SEL_TIMEOUT; 2539c12c399aSSascha Wildner xpt_done(ccb); 2540c12c399aSSascha Wildner return; 2541c12c399aSSascha Wildner } 2542c12c399aSSascha Wildner 2543c12c399aSSascha Wildner /* 2544c12c399aSSascha Wildner * If this device has an embedded SMP target, we'll talk to it 2545c12c399aSSascha Wildner * directly. 2546c12c399aSSascha Wildner * figure out what the expander's address is. 2547c12c399aSSascha Wildner */ 2548c12c399aSSascha Wildner if ((targ->devinfo & MPI2_SAS_DEVICE_INFO_SMP_TARGET) != 0) 2549c12c399aSSascha Wildner sasaddr = targ->sasaddr; 2550c12c399aSSascha Wildner 2551c12c399aSSascha Wildner /* 2552c12c399aSSascha Wildner * If we don't have a SAS address for the expander yet, try 2553c12c399aSSascha Wildner * grabbing it from the page 0x83 information cached in the 2554c12c399aSSascha Wildner * transport layer for this target. LSI expanders report the 2555c12c399aSSascha Wildner * expander SAS address as the port-associated SAS address in 2556c12c399aSSascha Wildner * Inquiry VPD page 0x83. Maxim expanders don't report it in page 2557c12c399aSSascha Wildner * 0x83. 2558c12c399aSSascha Wildner * 2559c12c399aSSascha Wildner * XXX KDM disable this for now, but leave it commented out so that 2560c12c399aSSascha Wildner * it is obvious that this is another possible way to get the SAS 2561c12c399aSSascha Wildner * address. 2562c12c399aSSascha Wildner * 2563c12c399aSSascha Wildner * The parent handle method below is a little more reliable, and 2564c12c399aSSascha Wildner * the other benefit is that it works for devices other than SES 2565c12c399aSSascha Wildner * devices. So you can send a SMP request to a da(4) device and it 2566c12c399aSSascha Wildner * will get routed to the expander that device is attached to. 2567c12c399aSSascha Wildner * (Assuming the da(4) device doesn't contain an SMP target...) 2568c12c399aSSascha Wildner */ 2569c12c399aSSascha Wildner #if 0 2570c12c399aSSascha Wildner if (sasaddr == 0) 2571c12c399aSSascha Wildner sasaddr = xpt_path_sas_addr(ccb->ccb_h.path); 2572c12c399aSSascha Wildner #endif 2573c12c399aSSascha Wildner 2574c12c399aSSascha Wildner /* 2575c12c399aSSascha Wildner * If we still don't have a SAS address for the expander, look for 2576c12c399aSSascha Wildner * the parent device of this device, which is probably the expander. 2577c12c399aSSascha Wildner */ 2578c12c399aSSascha Wildner if (sasaddr == 0) { 2579c12c399aSSascha Wildner #ifdef OLD_MPS_PROBE 2580c12c399aSSascha Wildner struct mpssas_target *parent_target; 2581c12c399aSSascha Wildner #endif 2582c12c399aSSascha Wildner 2583c12c399aSSascha Wildner if (targ->parent_handle == 0x0) { 2584c12c399aSSascha Wildner mps_printf(sc, "%s: handle %d does not have a valid " 2585c12c399aSSascha Wildner "parent handle!\n", __func__, targ->handle); 2586c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_INVALID; 2587c12c399aSSascha Wildner goto bailout; 2588c12c399aSSascha Wildner } 2589c12c399aSSascha Wildner #ifdef OLD_MPS_PROBE 2590c12c399aSSascha Wildner parent_target = mpssas_find_target_by_handle(sassc, 0, 2591c12c399aSSascha Wildner targ->parent_handle); 2592c12c399aSSascha Wildner 2593c12c399aSSascha Wildner if (parent_target == NULL) { 2594c12c399aSSascha Wildner mps_printf(sc, "%s: handle %d does not have a valid " 2595c12c399aSSascha Wildner "parent target!\n", __func__, targ->handle); 2596c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_INVALID; 2597c12c399aSSascha Wildner goto bailout; 2598c12c399aSSascha Wildner } 2599c12c399aSSascha Wildner 2600c12c399aSSascha Wildner if ((parent_target->devinfo & 2601c12c399aSSascha Wildner MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) { 2602c12c399aSSascha Wildner mps_printf(sc, "%s: handle %d parent %d does not " 2603c12c399aSSascha Wildner "have an SMP target!\n", __func__, 2604c12c399aSSascha Wildner targ->handle, parent_target->handle); 2605c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_INVALID; 2606c12c399aSSascha Wildner goto bailout; 2607c12c399aSSascha Wildner 2608c12c399aSSascha Wildner } 2609c12c399aSSascha Wildner 2610c12c399aSSascha Wildner sasaddr = parent_target->sasaddr; 2611c12c399aSSascha Wildner #else /* OLD_MPS_PROBE */ 2612c12c399aSSascha Wildner if ((targ->parent_devinfo & 2613c12c399aSSascha Wildner MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) { 2614c12c399aSSascha Wildner mps_printf(sc, "%s: handle %d parent %d does not " 2615c12c399aSSascha Wildner "have an SMP target!\n", __func__, 2616c12c399aSSascha Wildner targ->handle, targ->parent_handle); 2617c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_INVALID; 2618c12c399aSSascha Wildner goto bailout; 2619c12c399aSSascha Wildner 2620c12c399aSSascha Wildner } 2621c12c399aSSascha Wildner if (targ->parent_sasaddr == 0x0) { 2622c12c399aSSascha Wildner mps_printf(sc, "%s: handle %d parent handle %d does " 2623c12c399aSSascha Wildner "not have a valid SAS address!\n", 2624c12c399aSSascha Wildner __func__, targ->handle, targ->parent_handle); 2625c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_INVALID; 2626c12c399aSSascha Wildner goto bailout; 2627c12c399aSSascha Wildner } 2628c12c399aSSascha Wildner 2629c12c399aSSascha Wildner sasaddr = targ->parent_sasaddr; 2630c12c399aSSascha Wildner #endif /* OLD_MPS_PROBE */ 2631c12c399aSSascha Wildner 2632c12c399aSSascha Wildner } 2633c12c399aSSascha Wildner 2634c12c399aSSascha Wildner if (sasaddr == 0) { 2635c12c399aSSascha Wildner mps_printf(sc, "%s: unable to find SAS address for handle %d\n", 2636c12c399aSSascha Wildner __func__, targ->handle); 2637c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_INVALID; 2638c12c399aSSascha Wildner goto bailout; 2639c12c399aSSascha Wildner } 2640c12c399aSSascha Wildner mpssas_send_smpcmd(sassc, ccb, sasaddr); 2641c12c399aSSascha Wildner 2642c12c399aSSascha Wildner return; 2643c12c399aSSascha Wildner 2644c12c399aSSascha Wildner bailout: 2645c12c399aSSascha Wildner xpt_done(ccb); 2646c12c399aSSascha Wildner 2647c12c399aSSascha Wildner } 2648c12c399aSSascha Wildner #endif //__FreeBSD_version >= 900026 2649c12c399aSSascha Wildner 2650c12c399aSSascha Wildner static void 2651c12c399aSSascha Wildner mpssas_action_resetdev(struct mpssas_softc *sassc, union ccb *ccb) 2652c12c399aSSascha Wildner { 2653c12c399aSSascha Wildner MPI2_SCSI_TASK_MANAGE_REQUEST *req; 2654c12c399aSSascha Wildner struct mps_softc *sc; 2655c12c399aSSascha Wildner struct mps_command *tm; 2656c12c399aSSascha Wildner struct mpssas_target *targ; 2657c12c399aSSascha Wildner 2658c12c399aSSascha Wildner mps_dprint(sassc->sc, MPS_TRACE, __func__); 2659c12c399aSSascha Wildner KKASSERT(lockstatus(&sassc->sc->mps_lock, curthread) != 0); 2660c12c399aSSascha Wildner 2661c12c399aSSascha Wildner sc = sassc->sc; 2662c12c399aSSascha Wildner tm = mps_alloc_command(sc); 2663c12c399aSSascha Wildner if (tm == NULL) { 2664923ccc4eSSascha Wildner mps_printf(sc, "command alloc failure in mpssas_action_resetdev\n"); 2665c12c399aSSascha Wildner ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 2666c12c399aSSascha Wildner xpt_done(ccb); 2667c12c399aSSascha Wildner return; 2668c12c399aSSascha Wildner } 2669c12c399aSSascha Wildner 2670c12c399aSSascha Wildner targ = &sassc->targets[ccb->ccb_h.target_id]; 2671c12c399aSSascha Wildner req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 2672c12c399aSSascha Wildner req->DevHandle = targ->handle; 2673c12c399aSSascha Wildner req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 2674c12c399aSSascha Wildner req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; 2675c12c399aSSascha Wildner 2676c12c399aSSascha Wildner /* SAS Hard Link Reset / SATA Link Reset */ 2677c12c399aSSascha Wildner req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; 2678c12c399aSSascha Wildner 2679c12c399aSSascha Wildner tm->cm_data = NULL; 2680c12c399aSSascha Wildner tm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 2681c12c399aSSascha Wildner tm->cm_complete = mpssas_resetdev_complete; 2682c12c399aSSascha Wildner tm->cm_complete_data = ccb; 2683c12c399aSSascha Wildner mps_map_command(sc, tm); 2684c12c399aSSascha Wildner } 2685c12c399aSSascha Wildner 2686c12c399aSSascha Wildner static void 2687c12c399aSSascha Wildner mpssas_resetdev_complete(struct mps_softc *sc, struct mps_command *tm) 2688c12c399aSSascha Wildner { 2689c12c399aSSascha Wildner MPI2_SCSI_TASK_MANAGE_REPLY *resp; 2690c12c399aSSascha Wildner union ccb *ccb; 2691c12c399aSSascha Wildner 2692c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, __func__); 2693c12c399aSSascha Wildner KKASSERT(lockstatus(&sc->mps_lock, curthread) != 0); 2694c12c399aSSascha Wildner 2695c12c399aSSascha Wildner resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 2696c12c399aSSascha Wildner ccb = tm->cm_complete_data; 2697c12c399aSSascha Wildner 2698c12c399aSSascha Wildner /* 2699c12c399aSSascha Wildner * Currently there should be no way we can hit this case. It only 2700c12c399aSSascha Wildner * happens when we have a failure to allocate chain frames, and 2701c12c399aSSascha Wildner * task management commands don't have S/G lists. 2702c12c399aSSascha Wildner */ 2703c12c399aSSascha Wildner if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { 2704c12c399aSSascha Wildner MPI2_SCSI_TASK_MANAGE_REQUEST *req; 2705c12c399aSSascha Wildner 2706c12c399aSSascha Wildner req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 2707c12c399aSSascha Wildner 2708c12c399aSSascha Wildner mps_printf(sc, "%s: cm_flags = %#x for reset of handle %#04x! " 2709c12c399aSSascha Wildner "This should not happen!\n", __func__, tm->cm_flags, 2710c12c399aSSascha Wildner req->DevHandle); 2711c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2712c12c399aSSascha Wildner goto bailout; 2713c12c399aSSascha Wildner } 2714c12c399aSSascha Wildner 2715c12c399aSSascha Wildner kprintf("%s: IOCStatus = 0x%x ResponseCode = 0x%x\n", __func__, 2716c12c399aSSascha Wildner resp->IOCStatus, resp->ResponseCode); 2717c12c399aSSascha Wildner 2718c12c399aSSascha Wildner if (resp->ResponseCode == MPI2_SCSITASKMGMT_RSP_TM_COMPLETE) { 2719c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP; 2720c12c399aSSascha Wildner mpssas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid, 2721c12c399aSSascha Wildner CAM_LUN_WILDCARD); 2722c12c399aSSascha Wildner } 2723c12c399aSSascha Wildner else 2724c12c399aSSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2725c12c399aSSascha Wildner 2726c12c399aSSascha Wildner bailout: 2727c12c399aSSascha Wildner 2728c12c399aSSascha Wildner mpssas_free_tm(sc, tm); 2729c12c399aSSascha Wildner xpt_done(ccb); 2730c12c399aSSascha Wildner } 2731c12c399aSSascha Wildner 2732c12c399aSSascha Wildner static void 2733c12c399aSSascha Wildner mpssas_poll(struct cam_sim *sim) 2734c12c399aSSascha Wildner { 2735c12c399aSSascha Wildner struct mpssas_softc *sassc; 2736c12c399aSSascha Wildner 2737c12c399aSSascha Wildner sassc = cam_sim_softc(sim); 2738c12c399aSSascha Wildner 2739c12c399aSSascha Wildner if (sassc->sc->mps_debug & MPS_TRACE) { 2740c12c399aSSascha Wildner /* frequent debug messages during a panic just slow 2741c12c399aSSascha Wildner * everything down too much. 2742c12c399aSSascha Wildner */ 2743c12c399aSSascha Wildner mps_printf(sassc->sc, "%s clearing MPS_TRACE\n", __func__); 2744c12c399aSSascha Wildner sassc->sc->mps_debug &= ~MPS_TRACE; 2745c12c399aSSascha Wildner } 2746c12c399aSSascha Wildner 2747c12c399aSSascha Wildner mps_intr_locked(sassc->sc); 2748c12c399aSSascha Wildner } 2749c12c399aSSascha Wildner 2750c12c399aSSascha Wildner static void 2751c12c399aSSascha Wildner mpssas_rescan_done(struct cam_periph *periph, union ccb *done_ccb) 2752c12c399aSSascha Wildner { 2753c12c399aSSascha Wildner struct mpssas_softc *sassc; 2754c12c399aSSascha Wildner char path_str[64]; 2755c12c399aSSascha Wildner 2756c12c399aSSascha Wildner if (done_ccb == NULL) 2757c12c399aSSascha Wildner return; 2758c12c399aSSascha Wildner 2759c12c399aSSascha Wildner sassc = (struct mpssas_softc *)done_ccb->ccb_h.ppriv_ptr1; 2760c12c399aSSascha Wildner 2761c12c399aSSascha Wildner KKASSERT(lockstatus(&sassc->sc->mps_lock, curthread) != 0); 2762c12c399aSSascha Wildner 2763c12c399aSSascha Wildner xpt_path_string(done_ccb->ccb_h.path, path_str, sizeof(path_str)); 2764c12c399aSSascha Wildner mps_dprint(sassc->sc, MPS_INFO, "Completing rescan for %s\n", path_str); 2765c12c399aSSascha Wildner 2766c12c399aSSascha Wildner xpt_free_path(done_ccb->ccb_h.path); 2767c12c399aSSascha Wildner xpt_free_ccb(done_ccb); 2768c12c399aSSascha Wildner 2769c12c399aSSascha Wildner #if __FreeBSD_version < 1000006 2770c12c399aSSascha Wildner /* 2771c12c399aSSascha Wildner * Before completing scan, get EEDP stuff for all of the existing 2772c12c399aSSascha Wildner * targets. 2773c12c399aSSascha Wildner */ 2774c12c399aSSascha Wildner mpssas_check_eedp(sassc); 2775c12c399aSSascha Wildner #endif 2776c12c399aSSascha Wildner 2777c12c399aSSascha Wildner } 2778c12c399aSSascha Wildner 2779c12c399aSSascha Wildner /* thread to handle bus rescans */ 2780c12c399aSSascha Wildner static void 2781c12c399aSSascha Wildner mpssas_scanner_thread(void *arg) 2782c12c399aSSascha Wildner { 2783c12c399aSSascha Wildner struct mpssas_softc *sassc; 2784c12c399aSSascha Wildner struct mps_softc *sc; 2785c12c399aSSascha Wildner union ccb *ccb; 2786c12c399aSSascha Wildner 2787c12c399aSSascha Wildner sassc = (struct mpssas_softc *)arg; 2788c12c399aSSascha Wildner sc = sassc->sc; 2789c12c399aSSascha Wildner 2790c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, "%s\n", __func__); 2791c12c399aSSascha Wildner 2792c12c399aSSascha Wildner mps_lock(sc); 2793c12c399aSSascha Wildner for (;;) { 2794c12c399aSSascha Wildner lksleep(&sassc->ccb_scanq, &sc->mps_lock, 0, "mps_scanq", 0); 2795c12c399aSSascha Wildner if (sassc->flags & MPSSAS_SHUTDOWN) { 2796c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, "Scanner shutting down\n"); 2797c12c399aSSascha Wildner break; 2798c12c399aSSascha Wildner } 2799c12c399aSSascha Wildner ccb = (union ccb *)TAILQ_FIRST(&sassc->ccb_scanq); 2800c12c399aSSascha Wildner if (ccb == NULL) 2801c12c399aSSascha Wildner continue; 2802c12c399aSSascha Wildner TAILQ_REMOVE(&sassc->ccb_scanq, &ccb->ccb_h, sim_links.tqe); 2803c12c399aSSascha Wildner xpt_action(ccb); 2804c12c399aSSascha Wildner } 2805c12c399aSSascha Wildner 2806c12c399aSSascha Wildner sassc->flags &= ~MPSSAS_SCANTHREAD; 2807c12c399aSSascha Wildner wakeup(&sassc->flags); 2808c12c399aSSascha Wildner mps_unlock(sc); 2809c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, "Scanner exiting\n"); 2810c12c399aSSascha Wildner mps_kproc_exit(0); 2811c12c399aSSascha Wildner } 2812c12c399aSSascha Wildner 2813c12c399aSSascha Wildner static void 2814c12c399aSSascha Wildner mpssas_rescan(struct mpssas_softc *sassc, union ccb *ccb) 2815c12c399aSSascha Wildner { 2816c12c399aSSascha Wildner char path_str[64]; 2817c12c399aSSascha Wildner 2818c12c399aSSascha Wildner mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__); 2819c12c399aSSascha Wildner 2820c12c399aSSascha Wildner KKASSERT(lockstatus(&sassc->sc->mps_lock, curthread) != 0); 2821c12c399aSSascha Wildner 2822c12c399aSSascha Wildner if (ccb == NULL) 2823c12c399aSSascha Wildner return; 2824c12c399aSSascha Wildner 2825c12c399aSSascha Wildner xpt_path_string(ccb->ccb_h.path, path_str, sizeof(path_str)); 2826c12c399aSSascha Wildner mps_dprint(sassc->sc, MPS_INFO, "Queueing rescan for %s\n", path_str); 2827c12c399aSSascha Wildner 2828c12c399aSSascha Wildner /* Prepare request */ 2829c12c399aSSascha Wildner ccb->ccb_h.ppriv_ptr1 = sassc; 2830c12c399aSSascha Wildner ccb->ccb_h.cbfcnp = mpssas_rescan_done; 2831c12c399aSSascha Wildner xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, MPS_PRIORITY_XPT); 2832c12c399aSSascha Wildner TAILQ_INSERT_TAIL(&sassc->ccb_scanq, &ccb->ccb_h, sim_links.tqe); 2833c12c399aSSascha Wildner wakeup(&sassc->ccb_scanq); 2834c12c399aSSascha Wildner } 2835c12c399aSSascha Wildner 2836c12c399aSSascha Wildner #if __FreeBSD_version >= 1000006 2837c12c399aSSascha Wildner static void 2838c12c399aSSascha Wildner mpssas_async(void *callback_arg, uint32_t code, struct cam_path *path, 2839c12c399aSSascha Wildner void *arg) 2840c12c399aSSascha Wildner { 2841c12c399aSSascha Wildner struct mps_softc *sc; 2842c12c399aSSascha Wildner 2843c12c399aSSascha Wildner sc = (struct mps_softc *)callback_arg; 2844c12c399aSSascha Wildner 2845c12c399aSSascha Wildner switch (code) { 2846c12c399aSSascha Wildner case AC_ADVINFO_CHANGED: { 2847c12c399aSSascha Wildner struct mpssas_target *target; 2848c12c399aSSascha Wildner struct mpssas_softc *sassc; 2849c12c399aSSascha Wildner struct scsi_read_capacity_data_long rcap_buf; 2850c12c399aSSascha Wildner struct ccb_dev_advinfo cdai; 2851c12c399aSSascha Wildner struct mpssas_lun *lun; 2852c12c399aSSascha Wildner lun_id_t lunid; 2853c12c399aSSascha Wildner int found_lun; 2854c12c399aSSascha Wildner uintptr_t buftype; 2855c12c399aSSascha Wildner 2856c12c399aSSascha Wildner buftype = (uintptr_t)arg; 2857c12c399aSSascha Wildner 2858c12c399aSSascha Wildner found_lun = 0; 2859c12c399aSSascha Wildner sassc = sc->sassc; 2860c12c399aSSascha Wildner 2861c12c399aSSascha Wildner /* 2862c12c399aSSascha Wildner * We're only interested in read capacity data changes. 2863c12c399aSSascha Wildner */ 2864c12c399aSSascha Wildner if (buftype != CDAI_TYPE_RCAPLONG) 2865c12c399aSSascha Wildner break; 2866c12c399aSSascha Wildner 2867c12c399aSSascha Wildner /* 2868c12c399aSSascha Wildner * We're only interested in devices that are attached to 2869c12c399aSSascha Wildner * this controller. 2870c12c399aSSascha Wildner */ 2871c12c399aSSascha Wildner if (xpt_path_path_id(path) != sassc->sim->path_id) 2872c12c399aSSascha Wildner break; 2873c12c399aSSascha Wildner 2874c12c399aSSascha Wildner /* 2875c12c399aSSascha Wildner * We should have a handle for this, but check to make sure. 2876c12c399aSSascha Wildner */ 2877c12c399aSSascha Wildner target = &sassc->targets[xpt_path_target_id(path)]; 2878c12c399aSSascha Wildner if (target->handle == 0) 2879c12c399aSSascha Wildner break; 2880c12c399aSSascha Wildner 2881c12c399aSSascha Wildner lunid = xpt_path_lun_id(path); 2882c12c399aSSascha Wildner 2883c12c399aSSascha Wildner SLIST_FOREACH(lun, &target->luns, lun_link) { 2884c12c399aSSascha Wildner if (lun->lun_id == lunid) { 2885c12c399aSSascha Wildner found_lun = 1; 2886c12c399aSSascha Wildner break; 2887c12c399aSSascha Wildner } 2888c12c399aSSascha Wildner } 2889c12c399aSSascha Wildner 2890c12c399aSSascha Wildner if (found_lun == 0) { 2891c12c399aSSascha Wildner lun = kmalloc(sizeof(struct mpssas_lun), M_MPT2, 2892c12c399aSSascha Wildner M_NOWAIT | M_ZERO); 2893c12c399aSSascha Wildner if (lun == NULL) { 2894c12c399aSSascha Wildner mps_dprint(sc, MPS_FAULT, "Unable to alloc " 2895c12c399aSSascha Wildner "LUN for EEDP support.\n"); 2896c12c399aSSascha Wildner break; 2897c12c399aSSascha Wildner } 2898c12c399aSSascha Wildner lun->lun_id = lunid; 2899c12c399aSSascha Wildner SLIST_INSERT_HEAD(&target->luns, lun, lun_link); 2900c12c399aSSascha Wildner } 2901c12c399aSSascha Wildner 2902c12c399aSSascha Wildner bzero(&rcap_buf, sizeof(rcap_buf)); 2903c12c399aSSascha Wildner xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL); 2904c12c399aSSascha Wildner cdai.ccb_h.func_code = XPT_DEV_ADVINFO; 2905c12c399aSSascha Wildner cdai.ccb_h.flags = CAM_DIR_IN; 2906c12c399aSSascha Wildner cdai.buftype = CDAI_TYPE_RCAPLONG; 2907c12c399aSSascha Wildner cdai.flags = 0; 2908c12c399aSSascha Wildner cdai.bufsiz = sizeof(rcap_buf); 2909c12c399aSSascha Wildner cdai.buf = (uint8_t *)&rcap_buf; 2910c12c399aSSascha Wildner xpt_action((union ccb *)&cdai); 2911c12c399aSSascha Wildner if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0) 2912c12c399aSSascha Wildner cam_release_devq(cdai.ccb_h.path, 2913c12c399aSSascha Wildner 0, 0, 0, FALSE); 2914c12c399aSSascha Wildner 2915c12c399aSSascha Wildner if (((cdai.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 2916c12c399aSSascha Wildner && (rcap_buf.prot & SRC16_PROT_EN)) { 2917c12c399aSSascha Wildner lun->eedp_formatted = TRUE; 2918c12c399aSSascha Wildner lun->eedp_block_size = scsi_4btoul(rcap_buf.length); 2919c12c399aSSascha Wildner } else { 2920c12c399aSSascha Wildner lun->eedp_formatted = FALSE; 2921c12c399aSSascha Wildner lun->eedp_block_size = 0; 2922c12c399aSSascha Wildner } 2923c12c399aSSascha Wildner break; 2924c12c399aSSascha Wildner } 2925c12c399aSSascha Wildner default: 2926c12c399aSSascha Wildner break; 2927c12c399aSSascha Wildner } 2928c12c399aSSascha Wildner } 2929c12c399aSSascha Wildner #else /* __FreeBSD_version >= 1000006 */ 2930c12c399aSSascha Wildner 2931c12c399aSSascha Wildner static void 2932c12c399aSSascha Wildner mpssas_check_eedp(struct mpssas_softc *sassc) 2933c12c399aSSascha Wildner { 2934c12c399aSSascha Wildner struct mps_softc *sc = sassc->sc; 2935c12c399aSSascha Wildner struct ccb_scsiio *csio; 2936c12c399aSSascha Wildner struct scsi_read_capacity_16 *scsi_cmd; 2937c12c399aSSascha Wildner struct scsi_read_capacity_eedp *rcap_buf; 2938c12c399aSSascha Wildner union ccb *ccb; 2939c12c399aSSascha Wildner path_id_t pathid = cam_sim_path(sassc->sim); 2940c12c399aSSascha Wildner target_id_t targetid; 2941c12c399aSSascha Wildner lun_id_t lunid; 2942c12c399aSSascha Wildner struct cam_periph *found_periph; 2943c12c399aSSascha Wildner struct mpssas_target *target; 2944c12c399aSSascha Wildner struct mpssas_lun *lun; 2945c12c399aSSascha Wildner uint8_t found_lun; 2946c12c399aSSascha Wildner 2947c12c399aSSascha Wildner /* 2948c12c399aSSascha Wildner * Issue a READ CAPACITY 16 command to each LUN of each target. This 2949c12c399aSSascha Wildner * info is used to determine if the LUN is formatted for EEDP support. 2950c12c399aSSascha Wildner */ 2951c12c399aSSascha Wildner for (targetid = 0; targetid < sc->facts->MaxTargets; targetid++) { 2952c12c399aSSascha Wildner target = &sassc->targets[targetid]; 2953c12c399aSSascha Wildner if (target->handle == 0x0) { 2954c12c399aSSascha Wildner continue; 2955c12c399aSSascha Wildner } 2956c12c399aSSascha Wildner 2957c12c399aSSascha Wildner lunid = 0; 2958c12c399aSSascha Wildner do { 2959c12c399aSSascha Wildner rcap_buf = 2960c12c399aSSascha Wildner kmalloc(sizeof(struct scsi_read_capacity_eedp), 2961c12c399aSSascha Wildner M_MPT2, M_NOWAIT | M_ZERO); 2962c12c399aSSascha Wildner if (rcap_buf == NULL) { 2963c12c399aSSascha Wildner mps_dprint(sc, MPS_FAULT, "Unable to alloc read " 2964c12c399aSSascha Wildner "capacity buffer for EEDP support.\n"); 2965c12c399aSSascha Wildner return; 2966c12c399aSSascha Wildner } 2967c12c399aSSascha Wildner 2968c12c399aSSascha Wildner ccb = kmalloc(sizeof(union ccb), M_TEMP, 2969c12c399aSSascha Wildner M_WAITOK | M_ZERO); 2970c12c399aSSascha Wildner 2971c12c399aSSascha Wildner if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, 2972c12c399aSSascha Wildner pathid, targetid, lunid) != CAM_REQ_CMP) { 2973c12c399aSSascha Wildner mps_dprint(sc, MPS_FAULT, "Unable to create " 2974c12c399aSSascha Wildner "path for EEDP support\n"); 2975c12c399aSSascha Wildner kfree(rcap_buf, M_MPT2); 2976c12c399aSSascha Wildner xpt_free_ccb(ccb); 2977c12c399aSSascha Wildner return; 2978c12c399aSSascha Wildner } 2979c12c399aSSascha Wildner 2980c12c399aSSascha Wildner /* 2981c12c399aSSascha Wildner * If a periph is returned, the LUN exists. Create an 2982c12c399aSSascha Wildner * entry in the target's LUN list. 2983c12c399aSSascha Wildner */ 2984c12c399aSSascha Wildner if ((found_periph = cam_periph_find(ccb->ccb_h.path, 2985c12c399aSSascha Wildner NULL)) != NULL) { 2986c12c399aSSascha Wildner /* 2987c12c399aSSascha Wildner * If LUN is already in list, don't create a new 2988c12c399aSSascha Wildner * one. 2989c12c399aSSascha Wildner */ 2990c12c399aSSascha Wildner found_lun = FALSE; 2991c12c399aSSascha Wildner SLIST_FOREACH(lun, &target->luns, lun_link) { 2992c12c399aSSascha Wildner if (lun->lun_id == lunid) { 2993c12c399aSSascha Wildner found_lun = TRUE; 2994c12c399aSSascha Wildner break; 2995c12c399aSSascha Wildner } 2996c12c399aSSascha Wildner } 2997c12c399aSSascha Wildner if (!found_lun) { 2998c12c399aSSascha Wildner lun = kmalloc(sizeof(struct mpssas_lun), 2999c12c399aSSascha Wildner M_MPT2, M_WAITOK | M_ZERO); 3000c12c399aSSascha Wildner lun->lun_id = lunid; 3001c12c399aSSascha Wildner SLIST_INSERT_HEAD(&target->luns, lun, 3002c12c399aSSascha Wildner lun_link); 3003c12c399aSSascha Wildner } 3004c12c399aSSascha Wildner lunid++; 3005c12c399aSSascha Wildner 3006c12c399aSSascha Wildner /* 3007c12c399aSSascha Wildner * Issue a READ CAPACITY 16 command for the LUN. 3008c12c399aSSascha Wildner * The mpssas_read_cap_done function will load 3009c12c399aSSascha Wildner * the read cap info into the LUN struct. 3010c12c399aSSascha Wildner */ 3011c12c399aSSascha Wildner csio = &ccb->csio; 3012c12c399aSSascha Wildner csio->ccb_h.func_code = XPT_SCSI_IO; 3013c12c399aSSascha Wildner csio->ccb_h.flags = CAM_DIR_IN; 3014c12c399aSSascha Wildner csio->ccb_h.retry_count = 4; 3015c12c399aSSascha Wildner csio->ccb_h.cbfcnp = mpssas_read_cap_done; 3016c12c399aSSascha Wildner csio->ccb_h.timeout = 60000; 3017c12c399aSSascha Wildner csio->data_ptr = (uint8_t *)rcap_buf; 3018c12c399aSSascha Wildner csio->dxfer_len = sizeof(struct 3019c12c399aSSascha Wildner scsi_read_capacity_eedp); 3020c12c399aSSascha Wildner csio->sense_len = MPS_SENSE_LEN; 3021c12c399aSSascha Wildner csio->cdb_len = sizeof(*scsi_cmd); 3022c12c399aSSascha Wildner csio->tag_action = MSG_SIMPLE_Q_TAG; 3023c12c399aSSascha Wildner 3024c12c399aSSascha Wildner scsi_cmd = (struct scsi_read_capacity_16 *) 3025c12c399aSSascha Wildner &csio->cdb_io.cdb_bytes; 3026c12c399aSSascha Wildner bzero(scsi_cmd, sizeof(*scsi_cmd)); 3027c12c399aSSascha Wildner scsi_cmd->opcode = 0x9E; 3028c12c399aSSascha Wildner scsi_cmd->service_action = SRC16_SERVICE_ACTION; 3029c12c399aSSascha Wildner ((uint8_t *)scsi_cmd)[13] = sizeof(struct 3030c12c399aSSascha Wildner scsi_read_capacity_eedp); 3031c12c399aSSascha Wildner 3032c12c399aSSascha Wildner /* 3033c12c399aSSascha Wildner * Set the path, target and lun IDs for the READ 3034c12c399aSSascha Wildner * CAPACITY request. 3035c12c399aSSascha Wildner */ 3036c12c399aSSascha Wildner ccb->ccb_h.path_id = 3037c12c399aSSascha Wildner xpt_path_path_id(ccb->ccb_h.path); 3038c12c399aSSascha Wildner ccb->ccb_h.target_id = 3039c12c399aSSascha Wildner xpt_path_target_id(ccb->ccb_h.path); 3040c12c399aSSascha Wildner ccb->ccb_h.target_lun = 3041c12c399aSSascha Wildner xpt_path_lun_id(ccb->ccb_h.path); 3042c12c399aSSascha Wildner 3043c12c399aSSascha Wildner ccb->ccb_h.ppriv_ptr1 = sassc; 3044c12c399aSSascha Wildner xpt_action(ccb); 3045c12c399aSSascha Wildner } else { 3046c12c399aSSascha Wildner kfree(rcap_buf, M_MPT2); 3047c12c399aSSascha Wildner xpt_free_path(ccb->ccb_h.path); 3048c12c399aSSascha Wildner xpt_free_ccb(ccb); 3049c12c399aSSascha Wildner } 3050c12c399aSSascha Wildner } while (found_periph); 3051c12c399aSSascha Wildner } 3052c12c399aSSascha Wildner } 3053c12c399aSSascha Wildner 3054c12c399aSSascha Wildner 3055c12c399aSSascha Wildner static void 3056c12c399aSSascha Wildner mpssas_read_cap_done(struct cam_periph *periph, union ccb *done_ccb) 3057c12c399aSSascha Wildner { 3058c12c399aSSascha Wildner struct mpssas_softc *sassc; 3059c12c399aSSascha Wildner struct mpssas_target *target; 3060c12c399aSSascha Wildner struct mpssas_lun *lun; 3061c12c399aSSascha Wildner struct scsi_read_capacity_eedp *rcap_buf; 3062c12c399aSSascha Wildner 3063c12c399aSSascha Wildner if (done_ccb == NULL) 3064c12c399aSSascha Wildner return; 3065c12c399aSSascha Wildner 3066c12c399aSSascha Wildner rcap_buf = (struct scsi_read_capacity_eedp *)done_ccb->csio.data_ptr; 3067c12c399aSSascha Wildner 3068c12c399aSSascha Wildner /* 3069c12c399aSSascha Wildner * Get the LUN ID for the path and look it up in the LUN list for the 3070c12c399aSSascha Wildner * target. 3071c12c399aSSascha Wildner */ 3072c12c399aSSascha Wildner sassc = (struct mpssas_softc *)done_ccb->ccb_h.ppriv_ptr1; 3073c12c399aSSascha Wildner target = &sassc->targets[done_ccb->ccb_h.target_id]; 3074c12c399aSSascha Wildner SLIST_FOREACH(lun, &target->luns, lun_link) { 3075c12c399aSSascha Wildner if (lun->lun_id != done_ccb->ccb_h.target_lun) 3076c12c399aSSascha Wildner continue; 3077c12c399aSSascha Wildner 3078c12c399aSSascha Wildner /* 3079c12c399aSSascha Wildner * Got the LUN in the target's LUN list. Fill it in 3080c12c399aSSascha Wildner * with EEDP info. If the READ CAP 16 command had some 3081c12c399aSSascha Wildner * SCSI error (common if command is not supported), mark 3082c12c399aSSascha Wildner * the lun as not supporting EEDP and set the block size 3083c12c399aSSascha Wildner * to 0. 3084c12c399aSSascha Wildner */ 3085c12c399aSSascha Wildner if (((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 3086c12c399aSSascha Wildner || (done_ccb->csio.scsi_status != SCSI_STATUS_OK)) { 3087c12c399aSSascha Wildner lun->eedp_formatted = FALSE; 3088c12c399aSSascha Wildner lun->eedp_block_size = 0; 3089c12c399aSSascha Wildner break; 3090c12c399aSSascha Wildner } 3091c12c399aSSascha Wildner 3092c12c399aSSascha Wildner if (rcap_buf->protect & 0x01) { 3093c12c399aSSascha Wildner lun->eedp_formatted = TRUE; 3094c12c399aSSascha Wildner lun->eedp_block_size = scsi_4btoul(rcap_buf->length); 3095c12c399aSSascha Wildner } 3096c12c399aSSascha Wildner break; 3097c12c399aSSascha Wildner } 3098c12c399aSSascha Wildner 3099c12c399aSSascha Wildner // Finished with this CCB and path. 3100c12c399aSSascha Wildner kfree(rcap_buf, M_MPT2); 3101c12c399aSSascha Wildner xpt_free_path(done_ccb->ccb_h.path); 3102c12c399aSSascha Wildner xpt_free_ccb(done_ccb); 3103c12c399aSSascha Wildner } 3104c12c399aSSascha Wildner #endif /* __FreeBSD_version >= 1000006 */ 3105c12c399aSSascha Wildner 3106c12c399aSSascha Wildner int 3107c12c399aSSascha Wildner mpssas_startup(struct mps_softc *sc) 3108c12c399aSSascha Wildner { 3109c12c399aSSascha Wildner struct mpssas_softc *sassc; 3110c12c399aSSascha Wildner 3111c12c399aSSascha Wildner /* 3112c12c399aSSascha Wildner * Send the port enable message and set the wait_for_port_enable flag. 3113c12c399aSSascha Wildner * This flag helps to keep the simq frozen until all discovery events 3114c12c399aSSascha Wildner * are processed. 3115c12c399aSSascha Wildner */ 3116c12c399aSSascha Wildner sassc = sc->sassc; 3117c12c399aSSascha Wildner mpssas_startup_increment(sassc); 3118c12c399aSSascha Wildner sc->wait_for_port_enable = 1; 3119c12c399aSSascha Wildner mpssas_send_portenable(sc); 3120c12c399aSSascha Wildner return (0); 3121c12c399aSSascha Wildner } 3122c12c399aSSascha Wildner 3123c12c399aSSascha Wildner static int 3124c12c399aSSascha Wildner mpssas_send_portenable(struct mps_softc *sc) 3125c12c399aSSascha Wildner { 3126c12c399aSSascha Wildner MPI2_PORT_ENABLE_REQUEST *request; 3127c12c399aSSascha Wildner struct mps_command *cm; 3128c12c399aSSascha Wildner 3129c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, "%s\n", __func__); 3130c12c399aSSascha Wildner 3131c12c399aSSascha Wildner if ((cm = mps_alloc_command(sc)) == NULL) 3132c12c399aSSascha Wildner return (EBUSY); 3133c12c399aSSascha Wildner request = (MPI2_PORT_ENABLE_REQUEST *)cm->cm_req; 3134c12c399aSSascha Wildner request->Function = MPI2_FUNCTION_PORT_ENABLE; 3135c12c399aSSascha Wildner request->MsgFlags = 0; 3136c12c399aSSascha Wildner request->VP_ID = 0; 3137c12c399aSSascha Wildner cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 3138c12c399aSSascha Wildner cm->cm_complete = mpssas_portenable_complete; 3139c12c399aSSascha Wildner cm->cm_data = NULL; 3140c12c399aSSascha Wildner cm->cm_sge = NULL; 3141c12c399aSSascha Wildner 3142c12c399aSSascha Wildner mps_map_command(sc, cm); 3143c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, 3144c12c399aSSascha Wildner "mps_send_portenable finished cm %p req %p complete %p\n", 3145c12c399aSSascha Wildner cm, cm->cm_req, cm->cm_complete); 3146c12c399aSSascha Wildner return (0); 3147c12c399aSSascha Wildner } 3148c12c399aSSascha Wildner 3149c12c399aSSascha Wildner static void 3150c12c399aSSascha Wildner mpssas_portenable_complete(struct mps_softc *sc, struct mps_command *cm) 3151c12c399aSSascha Wildner { 3152c12c399aSSascha Wildner MPI2_PORT_ENABLE_REPLY *reply; 3153c12c399aSSascha Wildner struct mpssas_softc *sassc; 3154c12c399aSSascha Wildner struct mpssas_target *target; 3155c12c399aSSascha Wildner int i; 3156c12c399aSSascha Wildner 3157c12c399aSSascha Wildner mps_dprint(sc, MPS_TRACE, "%s\n", __func__); 3158c12c399aSSascha Wildner sassc = sc->sassc; 3159c12c399aSSascha Wildner 3160c12c399aSSascha Wildner /* 3161c12c399aSSascha Wildner * Currently there should be no way we can hit this case. It only 3162c12c399aSSascha Wildner * happens when we have a failure to allocate chain frames, and 3163c12c399aSSascha Wildner * port enable commands don't have S/G lists. 3164c12c399aSSascha Wildner */ 3165c12c399aSSascha Wildner if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { 3166c12c399aSSascha Wildner mps_printf(sc, "%s: cm_flags = %#x for port enable! " 3167c12c399aSSascha Wildner "This should not happen!\n", __func__, cm->cm_flags); 3168c12c399aSSascha Wildner } 3169c12c399aSSascha Wildner 3170c12c399aSSascha Wildner reply = (MPI2_PORT_ENABLE_REPLY *)cm->cm_reply; 3171c12c399aSSascha Wildner if (reply == NULL) 3172c12c399aSSascha Wildner mps_dprint(sc, MPS_FAULT, "Portenable NULL reply\n"); 3173c12c399aSSascha Wildner else if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != 3174c12c399aSSascha Wildner MPI2_IOCSTATUS_SUCCESS) 3175c12c399aSSascha Wildner mps_dprint(sc, MPS_FAULT, "Portenable failed\n"); 3176c12c399aSSascha Wildner 3177c12c399aSSascha Wildner mps_free_command(sc, cm); 3178c12c399aSSascha Wildner if (sc->mps_ich.ich_arg != NULL) { 3179c12c399aSSascha Wildner mps_dprint(sc, MPS_INFO, "disestablish config intrhook\n"); 3180c12c399aSSascha Wildner config_intrhook_disestablish(&sc->mps_ich); 3181c12c399aSSascha Wildner sc->mps_ich.ich_arg = NULL; 3182c12c399aSSascha Wildner } 3183c12c399aSSascha Wildner 3184c12c399aSSascha Wildner /* 3185c12c399aSSascha Wildner * Get WarpDrive info after discovery is complete but before the scan 3186c12c399aSSascha Wildner * starts. At this point, all devices are ready to be exposed to the 3187c12c399aSSascha Wildner * OS. If devices should be hidden instead, take them out of the 3188c12c399aSSascha Wildner * 'targets' array before the scan. The devinfo for a disk will have 3189c12c399aSSascha Wildner * some info and a volume's will be 0. Use that to remove disks. 3190c12c399aSSascha Wildner */ 3191c12c399aSSascha Wildner mps_wd_config_pages(sc); 3192c12c399aSSascha Wildner if (((sc->mps_flags & MPS_FLAGS_WD_AVAILABLE) 3193c12c399aSSascha Wildner && (sc->WD_hide_expose == MPS_WD_HIDE_ALWAYS)) 3194c12c399aSSascha Wildner || (sc->WD_valid_config && (sc->WD_hide_expose == 3195c12c399aSSascha Wildner MPS_WD_HIDE_IF_VOLUME))) { 3196c12c399aSSascha Wildner for (i = 0; i < sassc->sc->facts->MaxTargets; i++) { 3197c12c399aSSascha Wildner target = &sassc->targets[i]; 3198c12c399aSSascha Wildner if (target->devinfo) { 3199c12c399aSSascha Wildner target->devinfo = 0x0; 3200c12c399aSSascha Wildner target->encl_handle = 0x0; 3201c12c399aSSascha Wildner target->encl_slot = 0x0; 3202c12c399aSSascha Wildner target->handle = 0x0; 3203c12c399aSSascha Wildner target->tid = 0x0; 3204c12c399aSSascha Wildner target->linkrate = 0x0; 3205c12c399aSSascha Wildner target->flags = 0x0; 3206c12c399aSSascha Wildner } 3207c12c399aSSascha Wildner } 3208c12c399aSSascha Wildner } 3209c12c399aSSascha Wildner 3210c12c399aSSascha Wildner /* 3211c12c399aSSascha Wildner * Done waiting for port enable to complete. Decrement the refcount. 3212c12c399aSSascha Wildner * If refcount is 0, discovery is complete and a rescan of the bus can 3213c12c399aSSascha Wildner * take place. Since the simq was explicitly frozen before port 3214c12c399aSSascha Wildner * enable, it must be explicitly released here to keep the 3215c12c399aSSascha Wildner * freeze/release count in sync. 3216c12c399aSSascha Wildner */ 3217c12c399aSSascha Wildner sc->wait_for_port_enable = 0; 3218c12c399aSSascha Wildner sc->port_enable_complete = 1; 3219c12c399aSSascha Wildner mpssas_startup_decrement(sassc); 3220c12c399aSSascha Wildner xpt_release_simq(sassc->sim, 1); 3221c12c399aSSascha Wildner } 3222