1 1.80 andvar /* $NetBSD: mfi.c,v 1.80 2024/02/02 22:26:58 andvar Exp $ */ 2 1.1 bouyer /* $OpenBSD: mfi.c,v 1.66 2006/11/28 23:59:45 dlg Exp $ */ 3 1.43 bouyer 4 1.43 bouyer /* 5 1.43 bouyer * Copyright (c) 2012 Manuel Bouyer. 6 1.43 bouyer * 7 1.43 bouyer * Redistribution and use in source and binary forms, with or without 8 1.43 bouyer * modification, are permitted provided that the following conditions 9 1.43 bouyer * are met: 10 1.43 bouyer * 1. Redistributions of source code must retain the above copyright 11 1.43 bouyer * notice, this list of conditions and the following disclaimer. 12 1.43 bouyer * 2. Redistributions in binary form must reproduce the above copyright 13 1.43 bouyer * notice, this list of conditions and the following disclaimer in the 14 1.43 bouyer * documentation and/or other materials provided with the distribution. 15 1.43 bouyer * 16 1.43 bouyer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.43 bouyer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.43 bouyer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.43 bouyer * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.43 bouyer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 1.43 bouyer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 1.43 bouyer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 1.43 bouyer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 1.43 bouyer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 1.43 bouyer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 1.43 bouyer */ 27 1.43 bouyer 28 1.1 bouyer /* 29 1.1 bouyer * Copyright (c) 2006 Marco Peereboom <marco (at) peereboom.us> 30 1.1 bouyer * 31 1.1 bouyer * Permission to use, copy, modify, and distribute this software for any 32 1.1 bouyer * purpose with or without fee is hereby granted, provided that the above 33 1.1 bouyer * copyright notice and this permission notice appear in all copies. 34 1.1 bouyer * 35 1.1 bouyer * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 36 1.1 bouyer * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 37 1.1 bouyer * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 38 1.1 bouyer * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 39 1.1 bouyer * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 40 1.1 bouyer * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 41 1.1 bouyer * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 42 1.1 bouyer */ 43 1.1 bouyer 44 1.43 bouyer /*- 45 1.43 bouyer * Redistribution and use in source and binary forms, with or without 46 1.43 bouyer * modification, are permitted provided that the following conditions 47 1.43 bouyer * are met: 48 1.43 bouyer * 49 1.43 bouyer * Copyright 1994-2009 The FreeBSD Project. 50 1.43 bouyer * All rights reserved. 51 1.43 bouyer * 52 1.43 bouyer * 1. Redistributions of source code must retain the above copyright 53 1.43 bouyer * notice, this list of conditions and the following disclaimer. 54 1.43 bouyer * 2. Redistributions in binary form must reproduce the above copyright 55 1.43 bouyer * notice, this list of conditions and the following disclaimer in the 56 1.43 bouyer * documentation and/or other materials provided with the distribution. 57 1.43 bouyer * 58 1.43 bouyer * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT``AS IS'' AND 59 1.43 bouyer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 60 1.43 bouyer * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 61 1.43 bouyer * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR 62 1.43 bouyer * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 63 1.43 bouyer * EXEMPLARY,OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 64 1.43 bouyer * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 65 1.43 bouyer * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY 66 1.43 bouyer * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 67 1.43 bouyer * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 68 1.43 bouyer * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 69 1.43 bouyer * 70 1.43 bouyer * The views and conclusions contained in the software and documentation 71 1.43 bouyer * are those of the authors and should not be interpreted as representing 72 1.43 bouyer * official policies,either expressed or implied, of the FreeBSD Project. 73 1.43 bouyer */ 74 1.43 bouyer 75 1.2 bouyer #include <sys/cdefs.h> 76 1.80 andvar __KERNEL_RCSID(0, "$NetBSD: mfi.c,v 1.80 2024/02/02 22:26:58 andvar Exp $"); 77 1.2 bouyer 78 1.4 bouyer #include "bio.h" 79 1.1 bouyer 80 1.1 bouyer #include <sys/param.h> 81 1.1 bouyer #include <sys/systm.h> 82 1.1 bouyer #include <sys/buf.h> 83 1.1 bouyer #include <sys/ioctl.h> 84 1.1 bouyer #include <sys/device.h> 85 1.1 bouyer #include <sys/kernel.h> 86 1.1 bouyer #include <sys/malloc.h> 87 1.1 bouyer #include <sys/proc.h> 88 1.43 bouyer #include <sys/cpu.h> 89 1.47 bouyer #include <sys/conf.h> 90 1.47 bouyer #include <sys/kauth.h> 91 1.1 bouyer 92 1.1 bouyer #include <uvm/uvm_param.h> 93 1.1 bouyer 94 1.10 ad #include <sys/bus.h> 95 1.1 bouyer 96 1.1 bouyer #include <dev/scsipi/scsipi_all.h> 97 1.1 bouyer #include <dev/scsipi/scsi_all.h> 98 1.1 bouyer #include <dev/scsipi/scsi_spc.h> 99 1.1 bouyer #include <dev/scsipi/scsipi_disk.h> 100 1.1 bouyer #include <dev/scsipi/scsi_disk.h> 101 1.1 bouyer #include <dev/scsipi/scsiconf.h> 102 1.1 bouyer 103 1.1 bouyer #include <dev/ic/mfireg.h> 104 1.1 bouyer #include <dev/ic/mfivar.h> 105 1.47 bouyer #include <dev/ic/mfiio.h> 106 1.1 bouyer 107 1.1 bouyer #if NBIO > 0 108 1.1 bouyer #include <dev/biovar.h> 109 1.1 bouyer #endif /* NBIO > 0 */ 110 1.1 bouyer 111 1.58 riastrad #include "ioconf.h" 112 1.58 riastrad 113 1.1 bouyer #ifdef MFI_DEBUG 114 1.1 bouyer uint32_t mfi_debug = 0 115 1.73 msaitoh /* | MFI_D_CMD */ 116 1.1 bouyer /* | MFI_D_INTR */ 117 1.1 bouyer /* | MFI_D_MISC */ 118 1.1 bouyer /* | MFI_D_DMA */ 119 1.43 bouyer /* | MFI_D_IOCTL */ 120 1.1 bouyer /* | MFI_D_RW */ 121 1.1 bouyer /* | MFI_D_MEM */ 122 1.1 bouyer /* | MFI_D_CCB */ 123 1.43 bouyer /* | MFI_D_SYNC */ 124 1.1 bouyer ; 125 1.1 bouyer #endif 126 1.1 bouyer 127 1.13 xtraeme static void mfi_scsipi_request(struct scsipi_channel *, 128 1.13 xtraeme scsipi_adapter_req_t, void *); 129 1.13 xtraeme static void mfiminphys(struct buf *bp); 130 1.13 xtraeme 131 1.13 xtraeme static struct mfi_ccb *mfi_get_ccb(struct mfi_softc *); 132 1.13 xtraeme static void mfi_put_ccb(struct mfi_ccb *); 133 1.13 xtraeme static int mfi_init_ccb(struct mfi_softc *); 134 1.13 xtraeme 135 1.13 xtraeme static struct mfi_mem *mfi_allocmem(struct mfi_softc *, size_t); 136 1.27 dyoung static void mfi_freemem(struct mfi_softc *, struct mfi_mem **); 137 1.13 xtraeme 138 1.13 xtraeme static int mfi_transition_firmware(struct mfi_softc *); 139 1.13 xtraeme static int mfi_initialize_firmware(struct mfi_softc *); 140 1.13 xtraeme static int mfi_get_info(struct mfi_softc *); 141 1.45 bouyer static int mfi_get_bbu(struct mfi_softc *, 142 1.45 bouyer struct mfi_bbu_status *); 143 1.45 bouyer /* return codes for mfi_get_bbu */ 144 1.45 bouyer #define MFI_BBU_GOOD 0 145 1.45 bouyer #define MFI_BBU_BAD 1 146 1.45 bouyer #define MFI_BBU_UNKNOWN 2 147 1.13 xtraeme static uint32_t mfi_read(struct mfi_softc *, bus_size_t); 148 1.13 xtraeme static void mfi_write(struct mfi_softc *, bus_size_t, uint32_t); 149 1.13 xtraeme static int mfi_poll(struct mfi_ccb *); 150 1.13 xtraeme static int mfi_create_sgl(struct mfi_ccb *, int); 151 1.1 bouyer 152 1.1 bouyer /* commands */ 153 1.13 xtraeme static int mfi_scsi_ld(struct mfi_ccb *, struct scsipi_xfer *); 154 1.43 bouyer static int mfi_scsi_ld_io(struct mfi_ccb *, struct scsipi_xfer *, 155 1.43 bouyer uint64_t, uint32_t); 156 1.43 bouyer static void mfi_scsi_ld_done(struct mfi_ccb *); 157 1.43 bouyer static void mfi_scsi_xs_done(struct mfi_ccb *, int, int); 158 1.45 bouyer static int mfi_mgmt_internal(struct mfi_softc *, uint32_t, 159 1.74 msaitoh uint32_t, uint32_t, void *, const union mfi_mbox *, 160 1.74 msaitoh bool); 161 1.19 bouyer static int mfi_mgmt(struct mfi_ccb *,struct scsipi_xfer *, 162 1.74 msaitoh uint32_t, uint32_t, uint32_t, void *, 163 1.74 msaitoh const union mfi_mbox *); 164 1.13 xtraeme static void mfi_mgmt_done(struct mfi_ccb *); 165 1.1 bouyer 166 1.1 bouyer #if NBIO > 0 167 1.23 cegger static int mfi_ioctl(device_t, u_long, void *); 168 1.13 xtraeme static int mfi_ioctl_inq(struct mfi_softc *, struct bioc_inq *); 169 1.13 xtraeme static int mfi_ioctl_vol(struct mfi_softc *, struct bioc_vol *); 170 1.13 xtraeme static int mfi_ioctl_disk(struct mfi_softc *, struct bioc_disk *); 171 1.13 xtraeme static int mfi_ioctl_alarm(struct mfi_softc *, 172 1.13 xtraeme struct bioc_alarm *); 173 1.13 xtraeme static int mfi_ioctl_blink(struct mfi_softc *sc, 174 1.13 xtraeme struct bioc_blink *); 175 1.13 xtraeme static int mfi_ioctl_setstate(struct mfi_softc *, 176 1.13 xtraeme struct bioc_setstate *); 177 1.13 xtraeme static int mfi_bio_hs(struct mfi_softc *, int, int, void *); 178 1.13 xtraeme static int mfi_create_sensors(struct mfi_softc *); 179 1.24 dyoung static int mfi_destroy_sensors(struct mfi_softc *); 180 1.13 xtraeme static void mfi_sensor_refresh(struct sysmon_envsys *, 181 1.13 xtraeme envsys_data_t *); 182 1.1 bouyer #endif /* NBIO > 0 */ 183 1.45 bouyer static bool mfi_shutdown(device_t, int); 184 1.45 bouyer static bool mfi_suspend(device_t, const pmf_qual_t *); 185 1.45 bouyer static bool mfi_resume(device_t, const pmf_qual_t *); 186 1.1 bouyer 187 1.47 bouyer static dev_type_open(mfifopen); 188 1.47 bouyer static dev_type_close(mfifclose); 189 1.47 bouyer static dev_type_ioctl(mfifioctl); 190 1.47 bouyer const struct cdevsw mfi_cdevsw = { 191 1.52 dholland .d_open = mfifopen, 192 1.52 dholland .d_close = mfifclose, 193 1.52 dholland .d_read = noread, 194 1.52 dholland .d_write = nowrite, 195 1.52 dholland .d_ioctl = mfifioctl, 196 1.52 dholland .d_stop = nostop, 197 1.52 dholland .d_tty = notty, 198 1.52 dholland .d_poll = nopoll, 199 1.52 dholland .d_mmap = nommap, 200 1.52 dholland .d_kqfilter = nokqfilter, 201 1.53 dholland .d_discard = nodiscard, 202 1.52 dholland .d_flag = D_OTHER 203 1.47 bouyer }; 204 1.47 bouyer 205 1.13 xtraeme static uint32_t mfi_xscale_fw_state(struct mfi_softc *sc); 206 1.73 msaitoh static void mfi_xscale_intr_ena(struct mfi_softc *sc); 207 1.73 msaitoh static void mfi_xscale_intr_dis(struct mfi_softc *sc); 208 1.73 msaitoh static int mfi_xscale_intr(struct mfi_softc *sc); 209 1.73 msaitoh static void mfi_xscale_post(struct mfi_softc *sc, struct mfi_ccb *ccb); 210 1.30 dyoung 211 1.12 xtraeme static const struct mfi_iop_ops mfi_iop_xscale = { 212 1.12 xtraeme mfi_xscale_fw_state, 213 1.24 dyoung mfi_xscale_intr_dis, 214 1.12 xtraeme mfi_xscale_intr_ena, 215 1.12 xtraeme mfi_xscale_intr, 216 1.43 bouyer mfi_xscale_post, 217 1.43 bouyer mfi_scsi_ld_io, 218 1.12 xtraeme }; 219 1.30 dyoung 220 1.13 xtraeme static uint32_t mfi_ppc_fw_state(struct mfi_softc *sc); 221 1.73 msaitoh static void mfi_ppc_intr_ena(struct mfi_softc *sc); 222 1.73 msaitoh static void mfi_ppc_intr_dis(struct mfi_softc *sc); 223 1.73 msaitoh static int mfi_ppc_intr(struct mfi_softc *sc); 224 1.73 msaitoh static void mfi_ppc_post(struct mfi_softc *sc, struct mfi_ccb *ccb); 225 1.30 dyoung 226 1.12 xtraeme static const struct mfi_iop_ops mfi_iop_ppc = { 227 1.12 xtraeme mfi_ppc_fw_state, 228 1.24 dyoung mfi_ppc_intr_dis, 229 1.12 xtraeme mfi_ppc_intr_ena, 230 1.12 xtraeme mfi_ppc_intr, 231 1.43 bouyer mfi_ppc_post, 232 1.43 bouyer mfi_scsi_ld_io, 233 1.12 xtraeme }; 234 1.30 dyoung 235 1.33 msaitoh uint32_t mfi_gen2_fw_state(struct mfi_softc *sc); 236 1.33 msaitoh void mfi_gen2_intr_ena(struct mfi_softc *sc); 237 1.33 msaitoh void mfi_gen2_intr_dis(struct mfi_softc *sc); 238 1.33 msaitoh int mfi_gen2_intr(struct mfi_softc *sc); 239 1.33 msaitoh void mfi_gen2_post(struct mfi_softc *sc, struct mfi_ccb *ccb); 240 1.33 msaitoh 241 1.33 msaitoh static const struct mfi_iop_ops mfi_iop_gen2 = { 242 1.33 msaitoh mfi_gen2_fw_state, 243 1.33 msaitoh mfi_gen2_intr_dis, 244 1.33 msaitoh mfi_gen2_intr_ena, 245 1.33 msaitoh mfi_gen2_intr, 246 1.43 bouyer mfi_gen2_post, 247 1.43 bouyer mfi_scsi_ld_io, 248 1.33 msaitoh }; 249 1.33 msaitoh 250 1.38 sborrill u_int32_t mfi_skinny_fw_state(struct mfi_softc *); 251 1.38 sborrill void mfi_skinny_intr_dis(struct mfi_softc *); 252 1.38 sborrill void mfi_skinny_intr_ena(struct mfi_softc *); 253 1.38 sborrill int mfi_skinny_intr(struct mfi_softc *); 254 1.38 sborrill void mfi_skinny_post(struct mfi_softc *, struct mfi_ccb *); 255 1.38 sborrill 256 1.38 sborrill static const struct mfi_iop_ops mfi_iop_skinny = { 257 1.38 sborrill mfi_skinny_fw_state, 258 1.38 sborrill mfi_skinny_intr_dis, 259 1.38 sborrill mfi_skinny_intr_ena, 260 1.38 sborrill mfi_skinny_intr, 261 1.43 bouyer mfi_skinny_post, 262 1.43 bouyer mfi_scsi_ld_io, 263 1.43 bouyer }; 264 1.43 bouyer 265 1.43 bouyer static int mfi_tbolt_init_desc_pool(struct mfi_softc *); 266 1.43 bouyer static int mfi_tbolt_init_MFI_queue(struct mfi_softc *); 267 1.43 bouyer static void mfi_tbolt_build_mpt_ccb(struct mfi_ccb *); 268 1.43 bouyer int mfi_tbolt_scsi_ld_io(struct mfi_ccb *, struct scsipi_xfer *, 269 1.43 bouyer uint64_t, uint32_t); 270 1.43 bouyer static void mfi_tbolt_scsi_ld_done(struct mfi_ccb *); 271 1.43 bouyer static int mfi_tbolt_create_sgl(struct mfi_ccb *, int); 272 1.43 bouyer void mfi_tbolt_sync_map_info(struct work *, void *); 273 1.43 bouyer static void mfi_sync_map_complete(struct mfi_ccb *); 274 1.43 bouyer 275 1.43 bouyer u_int32_t mfi_tbolt_fw_state(struct mfi_softc *); 276 1.43 bouyer void mfi_tbolt_intr_dis(struct mfi_softc *); 277 1.43 bouyer void mfi_tbolt_intr_ena(struct mfi_softc *); 278 1.43 bouyer int mfi_tbolt_intr(struct mfi_softc *sc); 279 1.43 bouyer void mfi_tbolt_post(struct mfi_softc *, struct mfi_ccb *); 280 1.43 bouyer 281 1.43 bouyer static const struct mfi_iop_ops mfi_iop_tbolt = { 282 1.43 bouyer mfi_tbolt_fw_state, 283 1.43 bouyer mfi_tbolt_intr_dis, 284 1.43 bouyer mfi_tbolt_intr_ena, 285 1.43 bouyer mfi_tbolt_intr, 286 1.43 bouyer mfi_tbolt_post, 287 1.43 bouyer mfi_tbolt_scsi_ld_io, 288 1.38 sborrill }; 289 1.38 sborrill 290 1.73 msaitoh #define mfi_fw_state(_s) ((_s)->sc_iop->mio_fw_state(_s)) 291 1.73 msaitoh #define mfi_intr_enable(_s) ((_s)->sc_iop->mio_intr_ena(_s)) 292 1.73 msaitoh #define mfi_intr_disable(_s) ((_s)->sc_iop->mio_intr_dis(_s)) 293 1.73 msaitoh #define mfi_my_intr(_s) ((_s)->sc_iop->mio_intr(_s)) 294 1.73 msaitoh #define mfi_post(_s, _c) ((_s)->sc_iop->mio_post((_s), (_c))) 295 1.12 xtraeme 296 1.13 xtraeme static struct mfi_ccb * 297 1.1 bouyer mfi_get_ccb(struct mfi_softc *sc) 298 1.1 bouyer { 299 1.1 bouyer struct mfi_ccb *ccb; 300 1.1 bouyer int s; 301 1.1 bouyer 302 1.1 bouyer s = splbio(); 303 1.1 bouyer ccb = TAILQ_FIRST(&sc->sc_ccb_freeq); 304 1.1 bouyer if (ccb) { 305 1.1 bouyer TAILQ_REMOVE(&sc->sc_ccb_freeq, ccb, ccb_link); 306 1.1 bouyer ccb->ccb_state = MFI_CCB_READY; 307 1.1 bouyer } 308 1.1 bouyer splx(s); 309 1.1 bouyer 310 1.1 bouyer DNPRINTF(MFI_D_CCB, "%s: mfi_get_ccb: %p\n", DEVNAME(sc), ccb); 311 1.45 bouyer if (__predict_false(ccb == NULL && sc->sc_running)) 312 1.43 bouyer aprint_error_dev(sc->sc_dev, "out of ccb\n"); 313 1.1 bouyer 314 1.13 xtraeme return ccb; 315 1.1 bouyer } 316 1.1 bouyer 317 1.13 xtraeme static void 318 1.1 bouyer mfi_put_ccb(struct mfi_ccb *ccb) 319 1.1 bouyer { 320 1.1 bouyer struct mfi_softc *sc = ccb->ccb_sc; 321 1.37 sborrill struct mfi_frame_header *hdr = &ccb->ccb_frame->mfr_header; 322 1.1 bouyer int s; 323 1.1 bouyer 324 1.1 bouyer DNPRINTF(MFI_D_CCB, "%s: mfi_put_ccb: %p\n", DEVNAME(sc), ccb); 325 1.1 bouyer 326 1.37 sborrill hdr->mfh_cmd_status = 0x0; 327 1.37 sborrill hdr->mfh_flags = 0x0; 328 1.1 bouyer ccb->ccb_state = MFI_CCB_FREE; 329 1.1 bouyer ccb->ccb_xs = NULL; 330 1.1 bouyer ccb->ccb_flags = 0; 331 1.1 bouyer ccb->ccb_done = NULL; 332 1.1 bouyer ccb->ccb_direction = 0; 333 1.1 bouyer ccb->ccb_frame_size = 0; 334 1.1 bouyer ccb->ccb_extra_frames = 0; 335 1.1 bouyer ccb->ccb_sgl = NULL; 336 1.1 bouyer ccb->ccb_data = NULL; 337 1.1 bouyer ccb->ccb_len = 0; 338 1.43 bouyer if (sc->sc_ioptype == MFI_IOP_TBOLT) { 339 1.43 bouyer /* erase tb_request_desc but preserve SMID */ 340 1.43 bouyer int index = ccb->ccb_tb_request_desc.header.SMID; 341 1.43 bouyer ccb->ccb_tb_request_desc.words = 0; 342 1.43 bouyer ccb->ccb_tb_request_desc.header.SMID = index; 343 1.43 bouyer } 344 1.37 sborrill s = splbio(); 345 1.1 bouyer TAILQ_INSERT_TAIL(&sc->sc_ccb_freeq, ccb, ccb_link); 346 1.1 bouyer splx(s); 347 1.1 bouyer } 348 1.1 bouyer 349 1.13 xtraeme static int 350 1.24 dyoung mfi_destroy_ccb(struct mfi_softc *sc) 351 1.24 dyoung { 352 1.24 dyoung struct mfi_ccb *ccb; 353 1.24 dyoung uint32_t i; 354 1.24 dyoung 355 1.43 bouyer DNPRINTF(MFI_D_CCB, "%s: mfi_destroy_ccb\n", DEVNAME(sc)); 356 1.24 dyoung 357 1.24 dyoung 358 1.24 dyoung for (i = 0; (ccb = mfi_get_ccb(sc)) != NULL; i++) { 359 1.24 dyoung /* create a dma map for transfer */ 360 1.43 bouyer bus_dmamap_destroy(sc->sc_datadmat, ccb->ccb_dmamap); 361 1.24 dyoung } 362 1.24 dyoung 363 1.24 dyoung if (i < sc->sc_max_cmds) 364 1.24 dyoung return EBUSY; 365 1.24 dyoung 366 1.24 dyoung free(sc->sc_ccb, M_DEVBUF); 367 1.24 dyoung 368 1.24 dyoung return 0; 369 1.24 dyoung } 370 1.24 dyoung 371 1.24 dyoung static int 372 1.1 bouyer mfi_init_ccb(struct mfi_softc *sc) 373 1.1 bouyer { 374 1.1 bouyer struct mfi_ccb *ccb; 375 1.1 bouyer uint32_t i; 376 1.1 bouyer int error; 377 1.43 bouyer bus_addr_t io_req_base_phys; 378 1.43 bouyer uint8_t *io_req_base; 379 1.43 bouyer int offset; 380 1.1 bouyer 381 1.1 bouyer DNPRINTF(MFI_D_CCB, "%s: mfi_init_ccb\n", DEVNAME(sc)); 382 1.1 bouyer 383 1.1 bouyer sc->sc_ccb = malloc(sizeof(struct mfi_ccb) * sc->sc_max_cmds, 384 1.13 xtraeme M_DEVBUF, M_WAITOK|M_ZERO); 385 1.43 bouyer if (sc->sc_ioptype == MFI_IOP_TBOLT) { 386 1.43 bouyer /* 387 1.43 bouyer * The first 256 bytes (SMID 0) is not used. 388 1.43 bouyer * Don't add to the cmd list. 389 1.43 bouyer */ 390 1.54 christos io_req_base = (uint8_t *)MFIMEM_KVA(sc->sc_tbolt_reqmsgpool) + 391 1.54 christos MEGASAS_THUNDERBOLT_NEW_MSG_SIZE; 392 1.54 christos io_req_base_phys = MFIMEM_DVA(sc->sc_tbolt_reqmsgpool) + 393 1.54 christos MEGASAS_THUNDERBOLT_NEW_MSG_SIZE; 394 1.55 christos } else { 395 1.55 christos io_req_base = NULL; /* XXX: gcc */ 396 1.55 christos io_req_base_phys = 0; /* XXX: gcc */ 397 1.43 bouyer } 398 1.1 bouyer 399 1.1 bouyer for (i = 0; i < sc->sc_max_cmds; i++) { 400 1.1 bouyer ccb = &sc->sc_ccb[i]; 401 1.1 bouyer 402 1.1 bouyer ccb->ccb_sc = sc; 403 1.1 bouyer 404 1.1 bouyer /* select i'th frame */ 405 1.1 bouyer ccb->ccb_frame = (union mfi_frame *) 406 1.1 bouyer ((char*)MFIMEM_KVA(sc->sc_frames) + sc->sc_frames_size * i); 407 1.1 bouyer ccb->ccb_pframe = 408 1.1 bouyer MFIMEM_DVA(sc->sc_frames) + sc->sc_frames_size * i; 409 1.1 bouyer ccb->ccb_frame->mfr_header.mfh_context = i; 410 1.1 bouyer 411 1.1 bouyer /* select i'th sense */ 412 1.1 bouyer ccb->ccb_sense = (struct mfi_sense *) 413 1.1 bouyer ((char*)MFIMEM_KVA(sc->sc_sense) + MFI_SENSE_SIZE * i); 414 1.1 bouyer ccb->ccb_psense = 415 1.1 bouyer (MFIMEM_DVA(sc->sc_sense) + MFI_SENSE_SIZE * i); 416 1.1 bouyer 417 1.1 bouyer /* create a dma map for transfer */ 418 1.43 bouyer error = bus_dmamap_create(sc->sc_datadmat, 419 1.1 bouyer MAXPHYS, sc->sc_max_sgl, MAXPHYS, 0, 420 1.1 bouyer BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ccb_dmamap); 421 1.1 bouyer if (error) { 422 1.43 bouyer aprint_error_dev(sc->sc_dev, 423 1.43 bouyer "cannot create ccb dmamap (%d)\n", error); 424 1.1 bouyer goto destroy; 425 1.1 bouyer } 426 1.43 bouyer if (sc->sc_ioptype == MFI_IOP_TBOLT) { 427 1.43 bouyer offset = MEGASAS_THUNDERBOLT_NEW_MSG_SIZE * i; 428 1.43 bouyer ccb->ccb_tb_io_request = 429 1.43 bouyer (struct mfi_mpi2_request_raid_scsi_io *) 430 1.43 bouyer (io_req_base + offset); 431 1.43 bouyer ccb->ccb_tb_pio_request = 432 1.43 bouyer io_req_base_phys + offset; 433 1.43 bouyer offset = MEGASAS_MAX_SZ_CHAIN_FRAME * i; 434 1.43 bouyer ccb->ccb_tb_sg_frame = 435 1.43 bouyer (mpi2_sge_io_union *)(sc->sc_reply_pool_limit + 436 1.43 bouyer offset); 437 1.43 bouyer ccb->ccb_tb_psg_frame = sc->sc_sg_frame_busaddr + 438 1.43 bouyer offset; 439 1.43 bouyer /* SMID 0 is reserved. Set SMID/index from 1 */ 440 1.43 bouyer ccb->ccb_tb_request_desc.header.SMID = i + 1; 441 1.43 bouyer } 442 1.1 bouyer 443 1.1 bouyer DNPRINTF(MFI_D_CCB, 444 1.77 msaitoh "ccb(%d): %p frame: %p (%#lx) sense: %p (%#lx) map: %p\n", 445 1.1 bouyer ccb->ccb_frame->mfr_header.mfh_context, ccb, 446 1.77 msaitoh ccb->ccb_frame, (u_long)ccb->ccb_pframe, 447 1.77 msaitoh ccb->ccb_sense, (u_long)ccb->ccb_psense, 448 1.77 msaitoh ccb->ccb_dmamap); 449 1.1 bouyer 450 1.1 bouyer /* add ccb to queue */ 451 1.1 bouyer mfi_put_ccb(ccb); 452 1.1 bouyer } 453 1.1 bouyer 454 1.13 xtraeme return 0; 455 1.1 bouyer destroy: 456 1.1 bouyer /* free dma maps and ccb memory */ 457 1.17 cegger while (i) { 458 1.17 cegger i--; 459 1.1 bouyer ccb = &sc->sc_ccb[i]; 460 1.43 bouyer bus_dmamap_destroy(sc->sc_datadmat, ccb->ccb_dmamap); 461 1.1 bouyer } 462 1.1 bouyer 463 1.1 bouyer free(sc->sc_ccb, M_DEVBUF); 464 1.1 bouyer 465 1.13 xtraeme return 1; 466 1.1 bouyer } 467 1.1 bouyer 468 1.13 xtraeme static uint32_t 469 1.1 bouyer mfi_read(struct mfi_softc *sc, bus_size_t r) 470 1.1 bouyer { 471 1.1 bouyer uint32_t rv; 472 1.1 bouyer 473 1.1 bouyer bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4, 474 1.1 bouyer BUS_SPACE_BARRIER_READ); 475 1.1 bouyer rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, r); 476 1.1 bouyer 477 1.77 msaitoh DNPRINTF(MFI_D_RW, "%s: mr %#zx 0x08%x ", DEVNAME(sc), r, rv); 478 1.13 xtraeme return rv; 479 1.1 bouyer } 480 1.1 bouyer 481 1.13 xtraeme static void 482 1.1 bouyer mfi_write(struct mfi_softc *sc, bus_size_t r, uint32_t v) 483 1.1 bouyer { 484 1.77 msaitoh DNPRINTF(MFI_D_RW, "%s: mw %#zx 0x%08x", DEVNAME(sc), r, v); 485 1.1 bouyer 486 1.1 bouyer bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v); 487 1.1 bouyer bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4, 488 1.1 bouyer BUS_SPACE_BARRIER_WRITE); 489 1.1 bouyer } 490 1.1 bouyer 491 1.13 xtraeme static struct mfi_mem * 492 1.1 bouyer mfi_allocmem(struct mfi_softc *sc, size_t size) 493 1.1 bouyer { 494 1.1 bouyer struct mfi_mem *mm; 495 1.1 bouyer int nsegs; 496 1.1 bouyer 497 1.77 msaitoh DNPRINTF(MFI_D_MEM, "%s: mfi_allocmem: %zu\n", DEVNAME(sc), 498 1.77 msaitoh size); 499 1.1 bouyer 500 1.62 chs mm = malloc(sizeof(struct mfi_mem), M_DEVBUF, M_WAITOK|M_ZERO); 501 1.1 bouyer mm->am_size = size; 502 1.1 bouyer 503 1.1 bouyer if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 504 1.1 bouyer BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &mm->am_map) != 0) 505 1.30 dyoung goto amfree; 506 1.1 bouyer 507 1.1 bouyer if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &mm->am_seg, 1, 508 1.1 bouyer &nsegs, BUS_DMA_NOWAIT) != 0) 509 1.1 bouyer goto destroy; 510 1.1 bouyer 511 1.1 bouyer if (bus_dmamem_map(sc->sc_dmat, &mm->am_seg, nsegs, size, &mm->am_kva, 512 1.1 bouyer BUS_DMA_NOWAIT) != 0) 513 1.1 bouyer goto free; 514 1.1 bouyer 515 1.1 bouyer if (bus_dmamap_load(sc->sc_dmat, mm->am_map, mm->am_kva, size, NULL, 516 1.1 bouyer BUS_DMA_NOWAIT) != 0) 517 1.1 bouyer goto unmap; 518 1.1 bouyer 519 1.78 hannken DNPRINTF(MFI_D_MEM, " kva: %p dva: %" PRIxBUSADDR " map: %p\n", 520 1.78 hannken mm->am_kva, mm->am_map->dm_segs[0].ds_addr, mm->am_map); 521 1.1 bouyer 522 1.1 bouyer memset(mm->am_kva, 0, size); 523 1.13 xtraeme return mm; 524 1.1 bouyer 525 1.1 bouyer unmap: 526 1.1 bouyer bus_dmamem_unmap(sc->sc_dmat, mm->am_kva, size); 527 1.1 bouyer free: 528 1.1 bouyer bus_dmamem_free(sc->sc_dmat, &mm->am_seg, 1); 529 1.1 bouyer destroy: 530 1.1 bouyer bus_dmamap_destroy(sc->sc_dmat, mm->am_map); 531 1.1 bouyer amfree: 532 1.1 bouyer free(mm, M_DEVBUF); 533 1.1 bouyer 534 1.13 xtraeme return NULL; 535 1.1 bouyer } 536 1.1 bouyer 537 1.13 xtraeme static void 538 1.27 dyoung mfi_freemem(struct mfi_softc *sc, struct mfi_mem **mmp) 539 1.1 bouyer { 540 1.27 dyoung struct mfi_mem *mm = *mmp; 541 1.27 dyoung 542 1.27 dyoung if (mm == NULL) 543 1.27 dyoung return; 544 1.27 dyoung 545 1.27 dyoung *mmp = NULL; 546 1.27 dyoung 547 1.1 bouyer DNPRINTF(MFI_D_MEM, "%s: mfi_freemem: %p\n", DEVNAME(sc), mm); 548 1.1 bouyer 549 1.1 bouyer bus_dmamap_unload(sc->sc_dmat, mm->am_map); 550 1.1 bouyer bus_dmamem_unmap(sc->sc_dmat, mm->am_kva, mm->am_size); 551 1.1 bouyer bus_dmamem_free(sc->sc_dmat, &mm->am_seg, 1); 552 1.1 bouyer bus_dmamap_destroy(sc->sc_dmat, mm->am_map); 553 1.1 bouyer free(mm, M_DEVBUF); 554 1.1 bouyer } 555 1.1 bouyer 556 1.13 xtraeme static int 557 1.1 bouyer mfi_transition_firmware(struct mfi_softc *sc) 558 1.1 bouyer { 559 1.18 gmcgarry uint32_t fw_state, cur_state; 560 1.1 bouyer int max_wait, i; 561 1.1 bouyer 562 1.12 xtraeme fw_state = mfi_fw_state(sc) & MFI_STATE_MASK; 563 1.1 bouyer 564 1.1 bouyer DNPRINTF(MFI_D_CMD, "%s: mfi_transition_firmware: %#x\n", DEVNAME(sc), 565 1.1 bouyer fw_state); 566 1.1 bouyer 567 1.1 bouyer while (fw_state != MFI_STATE_READY) { 568 1.1 bouyer DNPRINTF(MFI_D_MISC, 569 1.1 bouyer "%s: waiting for firmware to become ready\n", 570 1.1 bouyer DEVNAME(sc)); 571 1.1 bouyer cur_state = fw_state; 572 1.1 bouyer switch (fw_state) { 573 1.1 bouyer case MFI_STATE_FAULT: 574 1.43 bouyer aprint_error_dev(sc->sc_dev, "firmware fault\n"); 575 1.13 xtraeme return 1; 576 1.1 bouyer case MFI_STATE_WAIT_HANDSHAKE: 577 1.43 bouyer if (sc->sc_ioptype == MFI_IOP_SKINNY || 578 1.43 bouyer sc->sc_ioptype == MFI_IOP_TBOLT) 579 1.38 sborrill mfi_write(sc, MFI_SKINNY_IDB, MFI_INIT_CLEAR_HANDSHAKE); 580 1.38 sborrill else 581 1.38 sborrill mfi_write(sc, MFI_IDB, MFI_INIT_CLEAR_HANDSHAKE); 582 1.1 bouyer max_wait = 2; 583 1.1 bouyer break; 584 1.1 bouyer case MFI_STATE_OPERATIONAL: 585 1.43 bouyer if (sc->sc_ioptype == MFI_IOP_SKINNY || 586 1.43 bouyer sc->sc_ioptype == MFI_IOP_TBOLT) 587 1.69 msaitoh mfi_write(sc, MFI_SKINNY_IDB, MFI_RESET_FLAGS); 588 1.38 sborrill else 589 1.38 sborrill mfi_write(sc, MFI_IDB, MFI_INIT_READY); 590 1.1 bouyer max_wait = 10; 591 1.1 bouyer break; 592 1.1 bouyer case MFI_STATE_UNDEFINED: 593 1.1 bouyer case MFI_STATE_BB_INIT: 594 1.1 bouyer max_wait = 2; 595 1.1 bouyer break; 596 1.1 bouyer case MFI_STATE_FW_INIT: 597 1.1 bouyer case MFI_STATE_DEVICE_SCAN: 598 1.1 bouyer case MFI_STATE_FLUSH_CACHE: 599 1.1 bouyer max_wait = 20; 600 1.1 bouyer break; 601 1.43 bouyer case MFI_STATE_BOOT_MESSAGE_PENDING: 602 1.48 bouyer if (sc->sc_ioptype == MFI_IOP_SKINNY || 603 1.48 bouyer sc->sc_ioptype == MFI_IOP_TBOLT) { 604 1.43 bouyer mfi_write(sc, MFI_SKINNY_IDB, MFI_INIT_HOTPLUG); 605 1.48 bouyer } else { 606 1.48 bouyer mfi_write(sc, MFI_IDB, MFI_INIT_HOTPLUG); 607 1.43 bouyer } 608 1.48 bouyer max_wait = 180; 609 1.48 bouyer break; 610 1.1 bouyer default: 611 1.43 bouyer aprint_error_dev(sc->sc_dev, 612 1.43 bouyer "unknown firmware state %d\n", fw_state); 613 1.13 xtraeme return 1; 614 1.1 bouyer } 615 1.1 bouyer for (i = 0; i < (max_wait * 10); i++) { 616 1.12 xtraeme fw_state = mfi_fw_state(sc) & MFI_STATE_MASK; 617 1.1 bouyer if (fw_state == cur_state) 618 1.1 bouyer DELAY(100000); 619 1.1 bouyer else 620 1.1 bouyer break; 621 1.1 bouyer } 622 1.1 bouyer if (fw_state == cur_state) { 623 1.43 bouyer aprint_error_dev(sc->sc_dev, 624 1.43 bouyer "firmware stuck in state %#x\n", fw_state); 625 1.13 xtraeme return 1; 626 1.1 bouyer } 627 1.1 bouyer } 628 1.1 bouyer 629 1.13 xtraeme return 0; 630 1.1 bouyer } 631 1.1 bouyer 632 1.13 xtraeme static int 633 1.1 bouyer mfi_initialize_firmware(struct mfi_softc *sc) 634 1.1 bouyer { 635 1.1 bouyer struct mfi_ccb *ccb; 636 1.1 bouyer struct mfi_init_frame *init; 637 1.1 bouyer struct mfi_init_qinfo *qinfo; 638 1.1 bouyer 639 1.1 bouyer DNPRINTF(MFI_D_MISC, "%s: mfi_initialize_firmware\n", DEVNAME(sc)); 640 1.1 bouyer 641 1.1 bouyer if ((ccb = mfi_get_ccb(sc)) == NULL) 642 1.13 xtraeme return 1; 643 1.1 bouyer 644 1.1 bouyer init = &ccb->ccb_frame->mfr_init; 645 1.1 bouyer qinfo = (struct mfi_init_qinfo *)((uint8_t *)init + MFI_FRAME_SIZE); 646 1.1 bouyer 647 1.1 bouyer memset(qinfo, 0, sizeof *qinfo); 648 1.1 bouyer qinfo->miq_rq_entries = sc->sc_max_cmds + 1; 649 1.1 bouyer qinfo->miq_rq_addr_lo = htole32(MFIMEM_DVA(sc->sc_pcq) + 650 1.1 bouyer offsetof(struct mfi_prod_cons, mpc_reply_q)); 651 1.1 bouyer qinfo->miq_pi_addr_lo = htole32(MFIMEM_DVA(sc->sc_pcq) + 652 1.1 bouyer offsetof(struct mfi_prod_cons, mpc_producer)); 653 1.1 bouyer qinfo->miq_ci_addr_lo = htole32(MFIMEM_DVA(sc->sc_pcq) + 654 1.1 bouyer offsetof(struct mfi_prod_cons, mpc_consumer)); 655 1.1 bouyer 656 1.1 bouyer init->mif_header.mfh_cmd = MFI_CMD_INIT; 657 1.1 bouyer init->mif_header.mfh_data_len = sizeof *qinfo; 658 1.1 bouyer init->mif_qinfo_new_addr_lo = htole32(ccb->ccb_pframe + MFI_FRAME_SIZE); 659 1.1 bouyer 660 1.1 bouyer DNPRINTF(MFI_D_MISC, "%s: entries: %#x rq: %#x pi: %#x ci: %#x\n", 661 1.1 bouyer DEVNAME(sc), 662 1.1 bouyer qinfo->miq_rq_entries, qinfo->miq_rq_addr_lo, 663 1.1 bouyer qinfo->miq_pi_addr_lo, qinfo->miq_ci_addr_lo); 664 1.1 bouyer 665 1.1 bouyer if (mfi_poll(ccb)) { 666 1.43 bouyer aprint_error_dev(sc->sc_dev, 667 1.43 bouyer "mfi_initialize_firmware failed\n"); 668 1.13 xtraeme return 1; 669 1.1 bouyer } 670 1.1 bouyer 671 1.1 bouyer mfi_put_ccb(ccb); 672 1.1 bouyer 673 1.13 xtraeme return 0; 674 1.1 bouyer } 675 1.1 bouyer 676 1.13 xtraeme static int 677 1.1 bouyer mfi_get_info(struct mfi_softc *sc) 678 1.1 bouyer { 679 1.1 bouyer #ifdef MFI_DEBUG 680 1.1 bouyer int i; 681 1.1 bouyer #endif 682 1.1 bouyer DNPRINTF(MFI_D_MISC, "%s: mfi_get_info\n", DEVNAME(sc)); 683 1.1 bouyer 684 1.19 bouyer if (mfi_mgmt_internal(sc, MR_DCMD_CTRL_GET_INFO, MFI_DATA_IN, 685 1.45 bouyer sizeof(sc->sc_info), &sc->sc_info, NULL, cold ? true : false)) 686 1.13 xtraeme return 1; 687 1.1 bouyer 688 1.1 bouyer #ifdef MFI_DEBUG 689 1.1 bouyer for (i = 0; i < sc->sc_info.mci_image_component_count; i++) { 690 1.1 bouyer printf("%s: active FW %s Version %s date %s time %s\n", 691 1.1 bouyer DEVNAME(sc), 692 1.1 bouyer sc->sc_info.mci_image_component[i].mic_name, 693 1.1 bouyer sc->sc_info.mci_image_component[i].mic_version, 694 1.1 bouyer sc->sc_info.mci_image_component[i].mic_build_date, 695 1.1 bouyer sc->sc_info.mci_image_component[i].mic_build_time); 696 1.1 bouyer } 697 1.1 bouyer 698 1.1 bouyer for (i = 0; i < sc->sc_info.mci_pending_image_component_count; i++) { 699 1.1 bouyer printf("%s: pending FW %s Version %s date %s time %s\n", 700 1.1 bouyer DEVNAME(sc), 701 1.1 bouyer sc->sc_info.mci_pending_image_component[i].mic_name, 702 1.1 bouyer sc->sc_info.mci_pending_image_component[i].mic_version, 703 1.1 bouyer sc->sc_info.mci_pending_image_component[i].mic_build_date, 704 1.1 bouyer sc->sc_info.mci_pending_image_component[i].mic_build_time); 705 1.1 bouyer } 706 1.1 bouyer 707 1.1 bouyer printf("%s: max_arms %d max_spans %d max_arrs %d max_lds %d name %s\n", 708 1.1 bouyer DEVNAME(sc), 709 1.1 bouyer sc->sc_info.mci_max_arms, 710 1.1 bouyer sc->sc_info.mci_max_spans, 711 1.1 bouyer sc->sc_info.mci_max_arrays, 712 1.1 bouyer sc->sc_info.mci_max_lds, 713 1.1 bouyer sc->sc_info.mci_product_name); 714 1.1 bouyer 715 1.1 bouyer printf("%s: serial %s present %#x fw time %d max_cmds %d max_sg %d\n", 716 1.1 bouyer DEVNAME(sc), 717 1.1 bouyer sc->sc_info.mci_serial_number, 718 1.1 bouyer sc->sc_info.mci_hw_present, 719 1.1 bouyer sc->sc_info.mci_current_fw_time, 720 1.1 bouyer sc->sc_info.mci_max_cmds, 721 1.1 bouyer sc->sc_info.mci_max_sg_elements); 722 1.1 bouyer 723 1.1 bouyer printf("%s: max_rq %d lds_pres %d lds_deg %d lds_off %d pd_pres %d\n", 724 1.1 bouyer DEVNAME(sc), 725 1.1 bouyer sc->sc_info.mci_max_request_size, 726 1.1 bouyer sc->sc_info.mci_lds_present, 727 1.1 bouyer sc->sc_info.mci_lds_degraded, 728 1.1 bouyer sc->sc_info.mci_lds_offline, 729 1.1 bouyer sc->sc_info.mci_pd_present); 730 1.1 bouyer 731 1.1 bouyer printf("%s: pd_dsk_prs %d pd_dsk_pred_fail %d pd_dsk_fail %d\n", 732 1.1 bouyer DEVNAME(sc), 733 1.1 bouyer sc->sc_info.mci_pd_disks_present, 734 1.1 bouyer sc->sc_info.mci_pd_disks_pred_failure, 735 1.1 bouyer sc->sc_info.mci_pd_disks_failed); 736 1.1 bouyer 737 1.1 bouyer printf("%s: nvram %d mem %d flash %d\n", 738 1.1 bouyer DEVNAME(sc), 739 1.1 bouyer sc->sc_info.mci_nvram_size, 740 1.1 bouyer sc->sc_info.mci_memory_size, 741 1.1 bouyer sc->sc_info.mci_flash_size); 742 1.1 bouyer 743 1.1 bouyer printf("%s: ram_cor %d ram_uncor %d clus_all %d clus_act %d\n", 744 1.1 bouyer DEVNAME(sc), 745 1.1 bouyer sc->sc_info.mci_ram_correctable_errors, 746 1.1 bouyer sc->sc_info.mci_ram_uncorrectable_errors, 747 1.1 bouyer sc->sc_info.mci_cluster_allowed, 748 1.1 bouyer sc->sc_info.mci_cluster_active); 749 1.1 bouyer 750 1.1 bouyer printf("%s: max_strps_io %d raid_lvl %#x adapt_ops %#x ld_ops %#x\n", 751 1.1 bouyer DEVNAME(sc), 752 1.1 bouyer sc->sc_info.mci_max_strips_per_io, 753 1.1 bouyer sc->sc_info.mci_raid_levels, 754 1.1 bouyer sc->sc_info.mci_adapter_ops, 755 1.1 bouyer sc->sc_info.mci_ld_ops); 756 1.1 bouyer 757 1.1 bouyer printf("%s: strp_sz_min %d strp_sz_max %d pd_ops %#x pd_mix %#x\n", 758 1.1 bouyer DEVNAME(sc), 759 1.1 bouyer sc->sc_info.mci_stripe_sz_ops.min, 760 1.1 bouyer sc->sc_info.mci_stripe_sz_ops.max, 761 1.1 bouyer sc->sc_info.mci_pd_ops, 762 1.1 bouyer sc->sc_info.mci_pd_mix_support); 763 1.1 bouyer 764 1.1 bouyer printf("%s: ecc_bucket %d pckg_prop %s\n", 765 1.1 bouyer DEVNAME(sc), 766 1.1 bouyer sc->sc_info.mci_ecc_bucket_count, 767 1.1 bouyer sc->sc_info.mci_package_version); 768 1.1 bouyer 769 1.1 bouyer printf("%s: sq_nm %d prd_fail_poll %d intr_thrtl %d intr_thrtl_to %d\n", 770 1.1 bouyer DEVNAME(sc), 771 1.1 bouyer sc->sc_info.mci_properties.mcp_seq_num, 772 1.1 bouyer sc->sc_info.mci_properties.mcp_pred_fail_poll_interval, 773 1.1 bouyer sc->sc_info.mci_properties.mcp_intr_throttle_cnt, 774 1.1 bouyer sc->sc_info.mci_properties.mcp_intr_throttle_timeout); 775 1.1 bouyer 776 1.1 bouyer printf("%s: rbld_rate %d patr_rd_rate %d bgi_rate %d cc_rate %d\n", 777 1.1 bouyer DEVNAME(sc), 778 1.1 bouyer sc->sc_info.mci_properties.mcp_rebuild_rate, 779 1.1 bouyer sc->sc_info.mci_properties.mcp_patrol_read_rate, 780 1.1 bouyer sc->sc_info.mci_properties.mcp_bgi_rate, 781 1.1 bouyer sc->sc_info.mci_properties.mcp_cc_rate); 782 1.1 bouyer 783 1.1 bouyer printf("%s: rc_rate %d ch_flsh %d spin_cnt %d spin_dly %d clus_en %d\n", 784 1.1 bouyer DEVNAME(sc), 785 1.1 bouyer sc->sc_info.mci_properties.mcp_recon_rate, 786 1.1 bouyer sc->sc_info.mci_properties.mcp_cache_flush_interval, 787 1.1 bouyer sc->sc_info.mci_properties.mcp_spinup_drv_cnt, 788 1.1 bouyer sc->sc_info.mci_properties.mcp_spinup_delay, 789 1.1 bouyer sc->sc_info.mci_properties.mcp_cluster_enable); 790 1.1 bouyer 791 1.1 bouyer printf("%s: coerc %d alarm %d dis_auto_rbld %d dis_bat_wrn %d ecc %d\n", 792 1.1 bouyer DEVNAME(sc), 793 1.1 bouyer sc->sc_info.mci_properties.mcp_coercion_mode, 794 1.1 bouyer sc->sc_info.mci_properties.mcp_alarm_enable, 795 1.1 bouyer sc->sc_info.mci_properties.mcp_disable_auto_rebuild, 796 1.1 bouyer sc->sc_info.mci_properties.mcp_disable_battery_warn, 797 1.1 bouyer sc->sc_info.mci_properties.mcp_ecc_bucket_size); 798 1.1 bouyer 799 1.1 bouyer printf("%s: ecc_leak %d rest_hs %d exp_encl_dev %d\n", 800 1.1 bouyer DEVNAME(sc), 801 1.1 bouyer sc->sc_info.mci_properties.mcp_ecc_bucket_leak_rate, 802 1.1 bouyer sc->sc_info.mci_properties.mcp_restore_hotspare_on_insertion, 803 1.1 bouyer sc->sc_info.mci_properties.mcp_expose_encl_devices); 804 1.1 bouyer 805 1.1 bouyer printf("%s: vendor %#x device %#x subvendor %#x subdevice %#x\n", 806 1.1 bouyer DEVNAME(sc), 807 1.1 bouyer sc->sc_info.mci_pci.mip_vendor, 808 1.1 bouyer sc->sc_info.mci_pci.mip_device, 809 1.1 bouyer sc->sc_info.mci_pci.mip_subvendor, 810 1.1 bouyer sc->sc_info.mci_pci.mip_subdevice); 811 1.1 bouyer 812 1.1 bouyer printf("%s: type %#x port_count %d port_addr ", 813 1.1 bouyer DEVNAME(sc), 814 1.1 bouyer sc->sc_info.mci_host.mih_type, 815 1.1 bouyer sc->sc_info.mci_host.mih_port_count); 816 1.1 bouyer 817 1.1 bouyer for (i = 0; i < 8; i++) 818 1.46 bouyer printf("%.0" PRIx64 " ", sc->sc_info.mci_host.mih_port_addr[i]); 819 1.1 bouyer printf("\n"); 820 1.1 bouyer 821 1.1 bouyer printf("%s: type %.x port_count %d port_addr ", 822 1.1 bouyer DEVNAME(sc), 823 1.1 bouyer sc->sc_info.mci_device.mid_type, 824 1.1 bouyer sc->sc_info.mci_device.mid_port_count); 825 1.1 bouyer 826 1.46 bouyer for (i = 0; i < 8; i++) { 827 1.46 bouyer printf("%.0" PRIx64 " ", 828 1.46 bouyer sc->sc_info.mci_device.mid_port_addr[i]); 829 1.46 bouyer } 830 1.1 bouyer printf("\n"); 831 1.1 bouyer #endif /* MFI_DEBUG */ 832 1.1 bouyer 833 1.13 xtraeme return 0; 834 1.1 bouyer } 835 1.1 bouyer 836 1.45 bouyer static int 837 1.45 bouyer mfi_get_bbu(struct mfi_softc *sc, struct mfi_bbu_status *stat) 838 1.45 bouyer { 839 1.45 bouyer DNPRINTF(MFI_D_MISC, "%s: mfi_get_bbu\n", DEVNAME(sc)); 840 1.45 bouyer 841 1.45 bouyer if (mfi_mgmt_internal(sc, MR_DCMD_BBU_GET_STATUS, MFI_DATA_IN, 842 1.45 bouyer sizeof(*stat), stat, NULL, cold ? true : false)) 843 1.45 bouyer return MFI_BBU_UNKNOWN; 844 1.45 bouyer #ifdef MFI_DEBUG 845 1.45 bouyer printf("bbu type %d, voltage %d, current %d, temperature %d, " 846 1.45 bouyer "status 0x%x\n", stat->battery_type, stat->voltage, stat->current, 847 1.45 bouyer stat->temperature, stat->fw_status); 848 1.45 bouyer printf("details: "); 849 1.73 msaitoh switch (stat->battery_type) { 850 1.45 bouyer case MFI_BBU_TYPE_IBBU: 851 1.45 bouyer printf("guage %d relative charge %d charger state %d " 852 1.45 bouyer "charger ctrl %d\n", stat->detail.ibbu.gas_guage_status, 853 1.45 bouyer stat->detail.ibbu.relative_charge , 854 1.45 bouyer stat->detail.ibbu.charger_system_state , 855 1.45 bouyer stat->detail.ibbu.charger_system_ctrl); 856 1.45 bouyer printf("\tcurrent %d abs charge %d max error %d\n", 857 1.45 bouyer stat->detail.ibbu.charging_current , 858 1.45 bouyer stat->detail.ibbu.absolute_charge , 859 1.45 bouyer stat->detail.ibbu.max_error); 860 1.45 bouyer break; 861 1.45 bouyer case MFI_BBU_TYPE_BBU: 862 1.45 bouyer printf("guage %d relative charge %d charger state %d\n", 863 1.45 bouyer stat->detail.ibbu.gas_guage_status, 864 1.45 bouyer stat->detail.bbu.relative_charge , 865 1.45 bouyer stat->detail.bbu.charger_status ); 866 1.45 bouyer printf("\trem capacity %d fyll capacity %d SOH %d\n", 867 1.45 bouyer stat->detail.bbu.remaining_capacity , 868 1.45 bouyer stat->detail.bbu.full_charge_capacity , 869 1.45 bouyer stat->detail.bbu.is_SOH_good); 870 1.61 gdt break; 871 1.45 bouyer default: 872 1.45 bouyer printf("\n"); 873 1.45 bouyer } 874 1.45 bouyer #endif 875 1.73 msaitoh switch (stat->battery_type) { 876 1.45 bouyer case MFI_BBU_TYPE_BBU: 877 1.73 msaitoh return (stat->detail.bbu.is_SOH_good ? 878 1.45 bouyer MFI_BBU_GOOD : MFI_BBU_BAD); 879 1.45 bouyer case MFI_BBU_TYPE_NONE: 880 1.45 bouyer return MFI_BBU_UNKNOWN; 881 1.45 bouyer default: 882 1.45 bouyer if (stat->fw_status & 883 1.45 bouyer (MFI_BBU_STATE_PACK_MISSING | 884 1.45 bouyer MFI_BBU_STATE_VOLTAGE_LOW | 885 1.45 bouyer MFI_BBU_STATE_TEMPERATURE_HIGH | 886 1.45 bouyer MFI_BBU_STATE_LEARN_CYC_FAIL | 887 1.45 bouyer MFI_BBU_STATE_LEARN_CYC_TIMEOUT | 888 1.45 bouyer MFI_BBU_STATE_I2C_ERR_DETECT)) 889 1.45 bouyer return MFI_BBU_BAD; 890 1.45 bouyer return MFI_BBU_GOOD; 891 1.45 bouyer } 892 1.45 bouyer } 893 1.45 bouyer 894 1.13 xtraeme static void 895 1.1 bouyer mfiminphys(struct buf *bp) 896 1.1 bouyer { 897 1.1 bouyer DNPRINTF(MFI_D_MISC, "mfiminphys: %d\n", bp->b_bcount); 898 1.1 bouyer 899 1.1 bouyer /* XXX currently using MFI_MAXFER = MAXPHYS */ 900 1.1 bouyer if (bp->b_bcount > MFI_MAXFER) 901 1.1 bouyer bp->b_bcount = MFI_MAXFER; 902 1.1 bouyer minphys(bp); 903 1.1 bouyer } 904 1.1 bouyer 905 1.1 bouyer int 906 1.27 dyoung mfi_rescan(device_t self, const char *ifattr, const int *locators) 907 1.27 dyoung { 908 1.27 dyoung struct mfi_softc *sc = device_private(self); 909 1.27 dyoung 910 1.27 dyoung if (sc->sc_child != NULL) 911 1.27 dyoung return 0; 912 1.27 dyoung 913 1.65 thorpej sc->sc_child = config_found(self, &sc->sc_chan, scsiprint, CFARGS_NONE); 914 1.27 dyoung 915 1.27 dyoung return 0; 916 1.27 dyoung } 917 1.27 dyoung 918 1.27 dyoung void 919 1.27 dyoung mfi_childdetached(device_t self, device_t child) 920 1.27 dyoung { 921 1.27 dyoung struct mfi_softc *sc = device_private(self); 922 1.27 dyoung 923 1.27 dyoung KASSERT(self == sc->sc_dev); 924 1.27 dyoung KASSERT(child == sc->sc_child); 925 1.27 dyoung 926 1.27 dyoung if (child == sc->sc_child) 927 1.27 dyoung sc->sc_child = NULL; 928 1.27 dyoung } 929 1.27 dyoung 930 1.27 dyoung int 931 1.24 dyoung mfi_detach(struct mfi_softc *sc, int flags) 932 1.24 dyoung { 933 1.24 dyoung int error; 934 1.24 dyoung 935 1.24 dyoung DNPRINTF(MFI_D_MISC, "%s: mfi_detach\n", DEVNAME(sc)); 936 1.24 dyoung 937 1.26 dyoung if ((error = config_detach_children(sc->sc_dev, flags)) != 0) 938 1.25 dyoung return error; 939 1.25 dyoung 940 1.24 dyoung #if NBIO > 0 941 1.24 dyoung mfi_destroy_sensors(sc); 942 1.26 dyoung bio_unregister(sc->sc_dev); 943 1.24 dyoung #endif /* NBIO > 0 */ 944 1.24 dyoung 945 1.24 dyoung mfi_intr_disable(sc); 946 1.45 bouyer mfi_shutdown(sc->sc_dev, 0); 947 1.24 dyoung 948 1.43 bouyer if (sc->sc_ioptype == MFI_IOP_TBOLT) { 949 1.43 bouyer workqueue_destroy(sc->sc_ldsync_wq); 950 1.43 bouyer mfi_put_ccb(sc->sc_ldsync_ccb); 951 1.43 bouyer mfi_freemem(sc, &sc->sc_tbolt_reqmsgpool); 952 1.43 bouyer mfi_freemem(sc, &sc->sc_tbolt_ioc_init); 953 1.43 bouyer mfi_freemem(sc, &sc->sc_tbolt_verbuf); 954 1.43 bouyer } 955 1.43 bouyer 956 1.24 dyoung if ((error = mfi_destroy_ccb(sc)) != 0) 957 1.24 dyoung return error; 958 1.24 dyoung 959 1.27 dyoung mfi_freemem(sc, &sc->sc_sense); 960 1.24 dyoung 961 1.27 dyoung mfi_freemem(sc, &sc->sc_frames); 962 1.24 dyoung 963 1.27 dyoung mfi_freemem(sc, &sc->sc_pcq); 964 1.24 dyoung 965 1.24 dyoung return 0; 966 1.24 dyoung } 967 1.24 dyoung 968 1.45 bouyer static bool 969 1.45 bouyer mfi_shutdown(device_t dev, int how) 970 1.45 bouyer { 971 1.45 bouyer struct mfi_softc *sc = device_private(dev); 972 1.74 msaitoh union mfi_mbox mbox; 973 1.45 bouyer int s = splbio(); 974 1.72 msaitoh 975 1.45 bouyer DNPRINTF(MFI_D_MISC, "%s: mfi_shutdown\n", DEVNAME(sc)); 976 1.45 bouyer if (sc->sc_running) { 977 1.74 msaitoh memset(&mbox, 0, sizeof(mbox)); 978 1.74 msaitoh mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE; 979 1.45 bouyer if (mfi_mgmt_internal(sc, MR_DCMD_CTRL_CACHE_FLUSH, 980 1.74 msaitoh MFI_DATA_NONE, 0, NULL, &mbox, true)) { 981 1.45 bouyer aprint_error_dev(dev, "shutdown: cache flush failed\n"); 982 1.45 bouyer goto fail; 983 1.45 bouyer } 984 1.45 bouyer 985 1.74 msaitoh mbox.b[0] = 0; 986 1.45 bouyer if (mfi_mgmt_internal(sc, MR_DCMD_CTRL_SHUTDOWN, 987 1.74 msaitoh MFI_DATA_NONE, 0, NULL, &mbox, true)) { 988 1.45 bouyer aprint_error_dev(dev, "shutdown: " 989 1.45 bouyer "firmware shutdown failed\n"); 990 1.45 bouyer goto fail; 991 1.45 bouyer } 992 1.45 bouyer sc->sc_running = false; 993 1.45 bouyer } 994 1.45 bouyer splx(s); 995 1.45 bouyer return true; 996 1.45 bouyer fail: 997 1.45 bouyer splx(s); 998 1.45 bouyer return false; 999 1.45 bouyer } 1000 1.45 bouyer 1001 1.45 bouyer static bool 1002 1.45 bouyer mfi_suspend(device_t dev, const pmf_qual_t *q) 1003 1.45 bouyer { 1004 1.45 bouyer /* XXX to be implemented */ 1005 1.45 bouyer return false; 1006 1.45 bouyer } 1007 1.45 bouyer 1008 1.45 bouyer static bool 1009 1.45 bouyer mfi_resume(device_t dev, const pmf_qual_t *q) 1010 1.45 bouyer { 1011 1.45 bouyer /* XXX to be implemented */ 1012 1.45 bouyer return false; 1013 1.45 bouyer } 1014 1.45 bouyer 1015 1.24 dyoung int 1016 1.12 xtraeme mfi_attach(struct mfi_softc *sc, enum mfi_iop iop) 1017 1.1 bouyer { 1018 1.1 bouyer struct scsipi_adapter *adapt = &sc->sc_adapt; 1019 1.1 bouyer struct scsipi_channel *chan = &sc->sc_chan; 1020 1.39 bouyer uint32_t status, frames, max_sgl; 1021 1.1 bouyer int i; 1022 1.1 bouyer 1023 1.1 bouyer DNPRINTF(MFI_D_MISC, "%s: mfi_attach\n", DEVNAME(sc)); 1024 1.1 bouyer 1025 1.42 bouyer sc->sc_ioptype = iop; 1026 1.42 bouyer 1027 1.12 xtraeme switch (iop) { 1028 1.12 xtraeme case MFI_IOP_XSCALE: 1029 1.12 xtraeme sc->sc_iop = &mfi_iop_xscale; 1030 1.12 xtraeme break; 1031 1.12 xtraeme case MFI_IOP_PPC: 1032 1.12 xtraeme sc->sc_iop = &mfi_iop_ppc; 1033 1.12 xtraeme break; 1034 1.33 msaitoh case MFI_IOP_GEN2: 1035 1.33 msaitoh sc->sc_iop = &mfi_iop_gen2; 1036 1.33 msaitoh break; 1037 1.38 sborrill case MFI_IOP_SKINNY: 1038 1.38 sborrill sc->sc_iop = &mfi_iop_skinny; 1039 1.38 sborrill break; 1040 1.43 bouyer case MFI_IOP_TBOLT: 1041 1.43 bouyer sc->sc_iop = &mfi_iop_tbolt; 1042 1.43 bouyer break; 1043 1.12 xtraeme default: 1044 1.73 msaitoh panic("%s: unknown iop %d", DEVNAME(sc), iop); 1045 1.12 xtraeme } 1046 1.12 xtraeme 1047 1.1 bouyer if (mfi_transition_firmware(sc)) 1048 1.13 xtraeme return 1; 1049 1.1 bouyer 1050 1.1 bouyer TAILQ_INIT(&sc->sc_ccb_freeq); 1051 1.1 bouyer 1052 1.12 xtraeme status = mfi_fw_state(sc); 1053 1.1 bouyer sc->sc_max_cmds = status & MFI_STATE_MAXCMD_MASK; 1054 1.39 bouyer max_sgl = (status & MFI_STATE_MAXSGL_MASK) >> 16; 1055 1.43 bouyer if (sc->sc_ioptype == MFI_IOP_TBOLT) { 1056 1.59 riastrad sc->sc_max_sgl = uimin(max_sgl, (128 * 1024) / PAGE_SIZE + 1); 1057 1.43 bouyer sc->sc_sgl_size = sizeof(struct mfi_sg_ieee); 1058 1.43 bouyer } else if (sc->sc_64bit_dma) { 1059 1.59 riastrad sc->sc_max_sgl = uimin(max_sgl, (128 * 1024) / PAGE_SIZE + 1); 1060 1.39 bouyer sc->sc_sgl_size = sizeof(struct mfi_sg64); 1061 1.39 bouyer } else { 1062 1.39 bouyer sc->sc_max_sgl = max_sgl; 1063 1.39 bouyer sc->sc_sgl_size = sizeof(struct mfi_sg32); 1064 1.39 bouyer } 1065 1.69 msaitoh if (sc->sc_ioptype == MFI_IOP_SKINNY) 1066 1.69 msaitoh sc->sc_sgl_size = sizeof(struct mfi_sg_ieee); 1067 1.1 bouyer DNPRINTF(MFI_D_MISC, "%s: max commands: %u, max sgl: %u\n", 1068 1.1 bouyer DEVNAME(sc), sc->sc_max_cmds, sc->sc_max_sgl); 1069 1.1 bouyer 1070 1.43 bouyer if (sc->sc_ioptype == MFI_IOP_TBOLT) { 1071 1.43 bouyer uint32_t tb_mem_size; 1072 1.43 bouyer /* for Alignment */ 1073 1.66 msaitoh tb_mem_size = MEGASAS_THUNDERBOLT_MSG_ALIGNMENT; 1074 1.43 bouyer 1075 1.43 bouyer tb_mem_size += 1076 1.43 bouyer MEGASAS_THUNDERBOLT_NEW_MSG_SIZE * (sc->sc_max_cmds + 1); 1077 1.43 bouyer sc->sc_reply_pool_size = 1078 1.43 bouyer ((sc->sc_max_cmds + 1 + 15) / 16) * 16; 1079 1.43 bouyer tb_mem_size += 1080 1.43 bouyer MEGASAS_THUNDERBOLT_REPLY_SIZE * sc->sc_reply_pool_size; 1081 1.43 bouyer 1082 1.43 bouyer /* this is for SGL's */ 1083 1.43 bouyer tb_mem_size += MEGASAS_MAX_SZ_CHAIN_FRAME * sc->sc_max_cmds; 1084 1.43 bouyer sc->sc_tbolt_reqmsgpool = mfi_allocmem(sc, tb_mem_size); 1085 1.43 bouyer if (sc->sc_tbolt_reqmsgpool == NULL) { 1086 1.43 bouyer aprint_error_dev(sc->sc_dev, 1087 1.43 bouyer "unable to allocate thunderbolt " 1088 1.43 bouyer "request message pool\n"); 1089 1.43 bouyer goto nopcq; 1090 1.43 bouyer } 1091 1.43 bouyer if (mfi_tbolt_init_desc_pool(sc)) { 1092 1.43 bouyer aprint_error_dev(sc->sc_dev, 1093 1.43 bouyer "Thunderbolt pool preparation error\n"); 1094 1.43 bouyer goto nopcq; 1095 1.43 bouyer } 1096 1.43 bouyer 1097 1.43 bouyer /* 1098 1.43 bouyer * Allocate DMA memory mapping for MPI2 IOC Init descriptor, 1099 1.79 andvar * we are taking it different from what we have allocated for 1100 1.43 bouyer * Request and reply descriptors to avoid confusion later 1101 1.43 bouyer */ 1102 1.43 bouyer sc->sc_tbolt_ioc_init = mfi_allocmem(sc, 1103 1.43 bouyer sizeof(struct mpi2_ioc_init_request)); 1104 1.43 bouyer if (sc->sc_tbolt_ioc_init == NULL) { 1105 1.43 bouyer aprint_error_dev(sc->sc_dev, 1106 1.43 bouyer "unable to allocate thunderbolt IOC init memory"); 1107 1.43 bouyer goto nopcq; 1108 1.43 bouyer } 1109 1.43 bouyer 1110 1.43 bouyer sc->sc_tbolt_verbuf = mfi_allocmem(sc, 1111 1.43 bouyer MEGASAS_MAX_NAME*sizeof(bus_addr_t)); 1112 1.43 bouyer if (sc->sc_tbolt_verbuf == NULL) { 1113 1.43 bouyer aprint_error_dev(sc->sc_dev, 1114 1.43 bouyer "unable to allocate thunderbolt version buffer\n"); 1115 1.43 bouyer goto nopcq; 1116 1.43 bouyer } 1117 1.43 bouyer 1118 1.43 bouyer } 1119 1.1 bouyer /* consumer/producer and reply queue memory */ 1120 1.1 bouyer sc->sc_pcq = mfi_allocmem(sc, (sizeof(uint32_t) * sc->sc_max_cmds) + 1121 1.1 bouyer sizeof(struct mfi_prod_cons)); 1122 1.1 bouyer if (sc->sc_pcq == NULL) { 1123 1.43 bouyer aprint_error_dev(sc->sc_dev, 1124 1.43 bouyer "unable to allocate reply queue memory\n"); 1125 1.1 bouyer goto nopcq; 1126 1.1 bouyer } 1127 1.1 bouyer bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_pcq), 0, 1128 1.1 bouyer sizeof(uint32_t) * sc->sc_max_cmds + sizeof(struct mfi_prod_cons), 1129 1.1 bouyer BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1130 1.1 bouyer 1131 1.1 bouyer /* frame memory */ 1132 1.39 bouyer frames = (sc->sc_sgl_size * sc->sc_max_sgl + MFI_FRAME_SIZE - 1) / 1133 1.39 bouyer MFI_FRAME_SIZE + 1; 1134 1.1 bouyer sc->sc_frames_size = frames * MFI_FRAME_SIZE; 1135 1.1 bouyer sc->sc_frames = mfi_allocmem(sc, sc->sc_frames_size * sc->sc_max_cmds); 1136 1.1 bouyer if (sc->sc_frames == NULL) { 1137 1.43 bouyer aprint_error_dev(sc->sc_dev, 1138 1.43 bouyer "unable to allocate frame memory\n"); 1139 1.1 bouyer goto noframe; 1140 1.1 bouyer } 1141 1.1 bouyer /* XXX hack, fix this */ 1142 1.1 bouyer if (MFIMEM_DVA(sc->sc_frames) & 0x3f) { 1143 1.43 bouyer aprint_error_dev(sc->sc_dev, 1144 1.43 bouyer "improper frame alignment (%#llx) FIXME\n", 1145 1.43 bouyer (long long int)MFIMEM_DVA(sc->sc_frames)); 1146 1.1 bouyer goto noframe; 1147 1.1 bouyer } 1148 1.1 bouyer 1149 1.1 bouyer /* sense memory */ 1150 1.1 bouyer sc->sc_sense = mfi_allocmem(sc, sc->sc_max_cmds * MFI_SENSE_SIZE); 1151 1.1 bouyer if (sc->sc_sense == NULL) { 1152 1.43 bouyer aprint_error_dev(sc->sc_dev, 1153 1.43 bouyer "unable to allocate sense memory\n"); 1154 1.1 bouyer goto nosense; 1155 1.1 bouyer } 1156 1.1 bouyer 1157 1.1 bouyer /* now that we have all memory bits go initialize ccbs */ 1158 1.1 bouyer if (mfi_init_ccb(sc)) { 1159 1.43 bouyer aprint_error_dev(sc->sc_dev, "could not init ccb list\n"); 1160 1.1 bouyer goto noinit; 1161 1.1 bouyer } 1162 1.1 bouyer 1163 1.1 bouyer /* kickstart firmware with all addresses and pointers */ 1164 1.43 bouyer if (sc->sc_ioptype == MFI_IOP_TBOLT) { 1165 1.43 bouyer if (mfi_tbolt_init_MFI_queue(sc)) { 1166 1.43 bouyer aprint_error_dev(sc->sc_dev, 1167 1.43 bouyer "could not initialize firmware\n"); 1168 1.43 bouyer goto noinit; 1169 1.43 bouyer } 1170 1.43 bouyer } else { 1171 1.43 bouyer if (mfi_initialize_firmware(sc)) { 1172 1.43 bouyer aprint_error_dev(sc->sc_dev, 1173 1.43 bouyer "could not initialize firmware\n"); 1174 1.43 bouyer goto noinit; 1175 1.43 bouyer } 1176 1.1 bouyer } 1177 1.45 bouyer sc->sc_running = true; 1178 1.1 bouyer 1179 1.1 bouyer if (mfi_get_info(sc)) { 1180 1.43 bouyer aprint_error_dev(sc->sc_dev, 1181 1.43 bouyer "could not retrieve controller information\n"); 1182 1.1 bouyer goto noinit; 1183 1.1 bouyer } 1184 1.45 bouyer aprint_normal_dev(sc->sc_dev, 1185 1.45 bouyer "%s version %s\n", 1186 1.45 bouyer sc->sc_info.mci_product_name, 1187 1.45 bouyer sc->sc_info.mci_package_version); 1188 1.45 bouyer 1189 1.1 bouyer 1190 1.45 bouyer aprint_normal_dev(sc->sc_dev, "logical drives %d, %dMB RAM, ", 1191 1.1 bouyer sc->sc_info.mci_lds_present, 1192 1.1 bouyer sc->sc_info.mci_memory_size); 1193 1.45 bouyer sc->sc_bbuok = false; 1194 1.45 bouyer if (sc->sc_info.mci_hw_present & MFI_INFO_HW_BBU) { 1195 1.45 bouyer struct mfi_bbu_status bbu_stat; 1196 1.45 bouyer int mfi_bbu_status = mfi_get_bbu(sc, &bbu_stat); 1197 1.45 bouyer aprint_normal("BBU type "); 1198 1.45 bouyer switch (bbu_stat.battery_type) { 1199 1.45 bouyer case MFI_BBU_TYPE_BBU: 1200 1.45 bouyer aprint_normal("BBU"); 1201 1.45 bouyer break; 1202 1.45 bouyer case MFI_BBU_TYPE_IBBU: 1203 1.45 bouyer aprint_normal("IBBU"); 1204 1.45 bouyer break; 1205 1.45 bouyer default: 1206 1.45 bouyer aprint_normal("unknown type %d", bbu_stat.battery_type); 1207 1.45 bouyer } 1208 1.45 bouyer aprint_normal(", status "); 1209 1.73 msaitoh switch (mfi_bbu_status) { 1210 1.45 bouyer case MFI_BBU_GOOD: 1211 1.45 bouyer aprint_normal("good\n"); 1212 1.45 bouyer sc->sc_bbuok = true; 1213 1.45 bouyer break; 1214 1.45 bouyer case MFI_BBU_BAD: 1215 1.45 bouyer aprint_normal("bad\n"); 1216 1.45 bouyer break; 1217 1.45 bouyer case MFI_BBU_UNKNOWN: 1218 1.45 bouyer aprint_normal("unknown\n"); 1219 1.45 bouyer break; 1220 1.45 bouyer default: 1221 1.45 bouyer panic("mfi_bbu_status"); 1222 1.45 bouyer } 1223 1.45 bouyer } else { 1224 1.45 bouyer aprint_normal("BBU not present\n"); 1225 1.45 bouyer } 1226 1.1 bouyer 1227 1.1 bouyer sc->sc_ld_cnt = sc->sc_info.mci_lds_present; 1228 1.1 bouyer sc->sc_max_ld = sc->sc_ld_cnt; 1229 1.1 bouyer for (i = 0; i < sc->sc_ld_cnt; i++) 1230 1.1 bouyer sc->sc_ld[i].ld_present = 1; 1231 1.1 bouyer 1232 1.1 bouyer memset(adapt, 0, sizeof(*adapt)); 1233 1.26 dyoung adapt->adapt_dev = sc->sc_dev; 1234 1.1 bouyer adapt->adapt_nchannels = 1; 1235 1.43 bouyer /* keep a few commands for management */ 1236 1.43 bouyer if (sc->sc_max_cmds > 4) 1237 1.43 bouyer adapt->adapt_openings = sc->sc_max_cmds - 4; 1238 1.1 bouyer else 1239 1.1 bouyer adapt->adapt_openings = sc->sc_max_cmds; 1240 1.1 bouyer adapt->adapt_max_periph = adapt->adapt_openings; 1241 1.1 bouyer adapt->adapt_request = mfi_scsipi_request; 1242 1.1 bouyer adapt->adapt_minphys = mfiminphys; 1243 1.1 bouyer 1244 1.1 bouyer memset(chan, 0, sizeof(*chan)); 1245 1.1 bouyer chan->chan_adapter = adapt; 1246 1.43 bouyer chan->chan_bustype = &scsi_sas_bustype; 1247 1.1 bouyer chan->chan_channel = 0; 1248 1.1 bouyer chan->chan_flags = 0; 1249 1.1 bouyer chan->chan_nluns = 8; 1250 1.1 bouyer chan->chan_ntargets = MFI_MAX_LD; 1251 1.1 bouyer chan->chan_id = MFI_MAX_LD; 1252 1.1 bouyer 1253 1.64 thorpej mfi_rescan(sc->sc_dev, NULL, NULL); 1254 1.1 bouyer 1255 1.1 bouyer /* enable interrupts */ 1256 1.12 xtraeme mfi_intr_enable(sc); 1257 1.1 bouyer 1258 1.1 bouyer #if NBIO > 0 1259 1.26 dyoung if (bio_register(sc->sc_dev, mfi_ioctl) != 0) 1260 1.1 bouyer panic("%s: controller registration failed", DEVNAME(sc)); 1261 1.1 bouyer if (mfi_create_sensors(sc) != 0) 1262 1.43 bouyer aprint_error_dev(sc->sc_dev, "unable to create sensors\n"); 1263 1.1 bouyer #endif /* NBIO > 0 */ 1264 1.45 bouyer if (!pmf_device_register1(sc->sc_dev, mfi_suspend, mfi_resume, 1265 1.45 bouyer mfi_shutdown)) { 1266 1.45 bouyer aprint_error_dev(sc->sc_dev, 1267 1.45 bouyer "couldn't establish power handler\n"); 1268 1.45 bouyer } 1269 1.1 bouyer 1270 1.13 xtraeme return 0; 1271 1.1 bouyer noinit: 1272 1.27 dyoung mfi_freemem(sc, &sc->sc_sense); 1273 1.1 bouyer nosense: 1274 1.27 dyoung mfi_freemem(sc, &sc->sc_frames); 1275 1.1 bouyer noframe: 1276 1.27 dyoung mfi_freemem(sc, &sc->sc_pcq); 1277 1.1 bouyer nopcq: 1278 1.43 bouyer if (sc->sc_ioptype == MFI_IOP_TBOLT) { 1279 1.43 bouyer if (sc->sc_tbolt_reqmsgpool) 1280 1.43 bouyer mfi_freemem(sc, &sc->sc_tbolt_reqmsgpool); 1281 1.43 bouyer if (sc->sc_tbolt_verbuf) 1282 1.43 bouyer mfi_freemem(sc, &sc->sc_tbolt_verbuf); 1283 1.43 bouyer } 1284 1.13 xtraeme return 1; 1285 1.1 bouyer } 1286 1.1 bouyer 1287 1.13 xtraeme static int 1288 1.1 bouyer mfi_poll(struct mfi_ccb *ccb) 1289 1.1 bouyer { 1290 1.1 bouyer struct mfi_softc *sc = ccb->ccb_sc; 1291 1.1 bouyer struct mfi_frame_header *hdr; 1292 1.1 bouyer int to = 0; 1293 1.43 bouyer int rv = 0; 1294 1.1 bouyer 1295 1.1 bouyer DNPRINTF(MFI_D_CMD, "%s: mfi_poll\n", DEVNAME(sc)); 1296 1.1 bouyer 1297 1.1 bouyer hdr = &ccb->ccb_frame->mfr_header; 1298 1.1 bouyer hdr->mfh_cmd_status = 0xff; 1299 1.43 bouyer if (!sc->sc_MFA_enabled) 1300 1.43 bouyer hdr->mfh_flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; 1301 1.43 bouyer 1302 1.43 bouyer /* no callback, caller is supposed to do the cleanup */ 1303 1.43 bouyer ccb->ccb_done = NULL; 1304 1.1 bouyer 1305 1.12 xtraeme mfi_post(sc, ccb); 1306 1.43 bouyer if (sc->sc_MFA_enabled) { 1307 1.43 bouyer /* 1308 1.43 bouyer * depending on the command type, result may be posted 1309 1.43 bouyer * to *hdr, or not. In addition it seems there's 1310 1.43 bouyer * no way to avoid posting the SMID to the reply queue. 1311 1.43 bouyer * So pool using the interrupt routine. 1312 1.43 bouyer */ 1313 1.43 bouyer while (ccb->ccb_state != MFI_CCB_DONE) { 1314 1.43 bouyer delay(1000); 1315 1.43 bouyer if (to++ > 5000) { /* XXX 5 seconds busywait sucks */ 1316 1.43 bouyer rv = 1; 1317 1.43 bouyer break; 1318 1.43 bouyer } 1319 1.43 bouyer mfi_tbolt_intrh(sc); 1320 1.43 bouyer } 1321 1.43 bouyer } else { 1322 1.1 bouyer bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_frames), 1323 1.1 bouyer ccb->ccb_pframe - MFIMEM_DVA(sc->sc_frames), 1324 1.1 bouyer sc->sc_frames_size, BUS_DMASYNC_POSTREAD); 1325 1.43 bouyer 1326 1.43 bouyer while (hdr->mfh_cmd_status == 0xff) { 1327 1.43 bouyer delay(1000); 1328 1.43 bouyer if (to++ > 5000) { /* XXX 5 seconds busywait sucks */ 1329 1.43 bouyer rv = 1; 1330 1.43 bouyer break; 1331 1.43 bouyer } 1332 1.43 bouyer bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_frames), 1333 1.43 bouyer ccb->ccb_pframe - MFIMEM_DVA(sc->sc_frames), 1334 1.43 bouyer sc->sc_frames_size, BUS_DMASYNC_POSTREAD); 1335 1.43 bouyer } 1336 1.1 bouyer } 1337 1.1 bouyer bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_frames), 1338 1.1 bouyer ccb->ccb_pframe - MFIMEM_DVA(sc->sc_frames), 1339 1.1 bouyer sc->sc_frames_size, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1340 1.1 bouyer 1341 1.1 bouyer if (ccb->ccb_data != NULL) { 1342 1.1 bouyer DNPRINTF(MFI_D_INTR, "%s: mfi_mgmt_done sync\n", 1343 1.1 bouyer DEVNAME(sc)); 1344 1.43 bouyer bus_dmamap_sync(sc->sc_datadmat, ccb->ccb_dmamap, 0, 1345 1.1 bouyer ccb->ccb_dmamap->dm_mapsize, 1346 1.1 bouyer (ccb->ccb_direction & MFI_DATA_IN) ? 1347 1.1 bouyer BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 1348 1.1 bouyer 1349 1.43 bouyer bus_dmamap_unload(sc->sc_datadmat, ccb->ccb_dmamap); 1350 1.1 bouyer } 1351 1.1 bouyer 1352 1.43 bouyer if (rv != 0) { 1353 1.43 bouyer aprint_error_dev(sc->sc_dev, "timeout on ccb %d\n", 1354 1.1 bouyer hdr->mfh_context); 1355 1.1 bouyer ccb->ccb_flags |= MFI_CCB_F_ERR; 1356 1.13 xtraeme return 1; 1357 1.1 bouyer } 1358 1.30 dyoung 1359 1.13 xtraeme return 0; 1360 1.1 bouyer } 1361 1.1 bouyer 1362 1.1 bouyer int 1363 1.1 bouyer mfi_intr(void *arg) 1364 1.1 bouyer { 1365 1.1 bouyer struct mfi_softc *sc = arg; 1366 1.1 bouyer struct mfi_prod_cons *pcq; 1367 1.1 bouyer struct mfi_ccb *ccb; 1368 1.12 xtraeme uint32_t producer, consumer, ctx; 1369 1.1 bouyer int claimed = 0; 1370 1.1 bouyer 1371 1.12 xtraeme if (!mfi_my_intr(sc)) 1372 1.12 xtraeme return 0; 1373 1.1 bouyer 1374 1.4 bouyer pcq = MFIMEM_KVA(sc->sc_pcq); 1375 1.4 bouyer 1376 1.77 msaitoh DNPRINTF(MFI_D_INTR, "%s: mfi_intr %p %p\n", DEVNAME(sc), sc, pcq); 1377 1.1 bouyer 1378 1.1 bouyer bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_pcq), 0, 1379 1.1 bouyer sizeof(uint32_t) * sc->sc_max_cmds + sizeof(struct mfi_prod_cons), 1380 1.1 bouyer BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1381 1.1 bouyer 1382 1.1 bouyer producer = pcq->mpc_producer; 1383 1.1 bouyer consumer = pcq->mpc_consumer; 1384 1.1 bouyer 1385 1.1 bouyer while (consumer != producer) { 1386 1.1 bouyer DNPRINTF(MFI_D_INTR, "%s: mfi_intr pi %#x ci %#x\n", 1387 1.1 bouyer DEVNAME(sc), producer, consumer); 1388 1.1 bouyer 1389 1.1 bouyer ctx = pcq->mpc_reply_q[consumer]; 1390 1.1 bouyer pcq->mpc_reply_q[consumer] = MFI_INVALID_CTX; 1391 1.1 bouyer if (ctx == MFI_INVALID_CTX) 1392 1.43 bouyer aprint_error_dev(sc->sc_dev, 1393 1.43 bouyer "invalid context, p: %d c: %d\n", 1394 1.43 bouyer producer, consumer); 1395 1.1 bouyer else { 1396 1.1 bouyer /* XXX remove from queue and call scsi_done */ 1397 1.1 bouyer ccb = &sc->sc_ccb[ctx]; 1398 1.1 bouyer DNPRINTF(MFI_D_INTR, "%s: mfi_intr context %#x\n", 1399 1.1 bouyer DEVNAME(sc), ctx); 1400 1.1 bouyer bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_frames), 1401 1.1 bouyer ccb->ccb_pframe - MFIMEM_DVA(sc->sc_frames), 1402 1.1 bouyer sc->sc_frames_size, 1403 1.1 bouyer BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1404 1.1 bouyer ccb->ccb_done(ccb); 1405 1.1 bouyer 1406 1.1 bouyer claimed = 1; 1407 1.1 bouyer } 1408 1.1 bouyer consumer++; 1409 1.1 bouyer if (consumer == (sc->sc_max_cmds + 1)) 1410 1.1 bouyer consumer = 0; 1411 1.1 bouyer } 1412 1.1 bouyer 1413 1.1 bouyer pcq->mpc_consumer = consumer; 1414 1.1 bouyer bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_pcq), 0, 1415 1.1 bouyer sizeof(uint32_t) * sc->sc_max_cmds + sizeof(struct mfi_prod_cons), 1416 1.1 bouyer BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1417 1.1 bouyer 1418 1.13 xtraeme return claimed; 1419 1.1 bouyer } 1420 1.1 bouyer 1421 1.13 xtraeme static int 1422 1.43 bouyer mfi_scsi_ld_io(struct mfi_ccb *ccb, struct scsipi_xfer *xs, uint64_t blockno, 1423 1.1 bouyer uint32_t blockcnt) 1424 1.1 bouyer { 1425 1.1 bouyer struct scsipi_periph *periph = xs->xs_periph; 1426 1.1 bouyer struct mfi_io_frame *io; 1427 1.1 bouyer 1428 1.43 bouyer DNPRINTF(MFI_D_CMD, "%s: mfi_scsi_ld_io: %d\n", 1429 1.15 cegger device_xname(periph->periph_channel->chan_adapter->adapt_dev), 1430 1.1 bouyer periph->periph_target); 1431 1.1 bouyer 1432 1.1 bouyer if (!xs->data) 1433 1.13 xtraeme return 1; 1434 1.1 bouyer 1435 1.1 bouyer io = &ccb->ccb_frame->mfr_io; 1436 1.1 bouyer if (xs->xs_control & XS_CTL_DATA_IN) { 1437 1.1 bouyer io->mif_header.mfh_cmd = MFI_CMD_LD_READ; 1438 1.1 bouyer ccb->ccb_direction = MFI_DATA_IN; 1439 1.1 bouyer } else { 1440 1.1 bouyer io->mif_header.mfh_cmd = MFI_CMD_LD_WRITE; 1441 1.1 bouyer ccb->ccb_direction = MFI_DATA_OUT; 1442 1.1 bouyer } 1443 1.1 bouyer io->mif_header.mfh_target_id = periph->periph_target; 1444 1.1 bouyer io->mif_header.mfh_timeout = 0; 1445 1.1 bouyer io->mif_header.mfh_flags = 0; 1446 1.1 bouyer io->mif_header.mfh_sense_len = MFI_SENSE_SIZE; 1447 1.1 bouyer io->mif_header.mfh_data_len= blockcnt; 1448 1.43 bouyer io->mif_lba_hi = (blockno >> 32); 1449 1.43 bouyer io->mif_lba_lo = (blockno & 0xffffffff); 1450 1.1 bouyer io->mif_sense_addr_lo = htole32(ccb->ccb_psense); 1451 1.1 bouyer io->mif_sense_addr_hi = 0; 1452 1.1 bouyer 1453 1.43 bouyer ccb->ccb_done = mfi_scsi_ld_done; 1454 1.1 bouyer ccb->ccb_xs = xs; 1455 1.1 bouyer ccb->ccb_frame_size = MFI_IO_FRAME_SIZE; 1456 1.1 bouyer ccb->ccb_sgl = &io->mif_sgl; 1457 1.1 bouyer ccb->ccb_data = xs->data; 1458 1.1 bouyer ccb->ccb_len = xs->datalen; 1459 1.1 bouyer 1460 1.14 xtraeme if (mfi_create_sgl(ccb, (xs->xs_control & XS_CTL_NOSLEEP) ? 1461 1.14 xtraeme BUS_DMA_NOWAIT : BUS_DMA_WAITOK)) 1462 1.13 xtraeme return 1; 1463 1.1 bouyer 1464 1.13 xtraeme return 0; 1465 1.1 bouyer } 1466 1.1 bouyer 1467 1.13 xtraeme static void 1468 1.43 bouyer mfi_scsi_ld_done(struct mfi_ccb *ccb) 1469 1.43 bouyer { 1470 1.43 bouyer struct mfi_frame_header *hdr = &ccb->ccb_frame->mfr_header; 1471 1.43 bouyer mfi_scsi_xs_done(ccb, hdr->mfh_cmd_status, hdr->mfh_scsi_status); 1472 1.43 bouyer } 1473 1.43 bouyer 1474 1.43 bouyer static void 1475 1.43 bouyer mfi_scsi_xs_done(struct mfi_ccb *ccb, int status, int scsi_status) 1476 1.1 bouyer { 1477 1.1 bouyer struct scsipi_xfer *xs = ccb->ccb_xs; 1478 1.1 bouyer struct mfi_softc *sc = ccb->ccb_sc; 1479 1.1 bouyer 1480 1.77 msaitoh DNPRINTF(MFI_D_INTR, "%s: mfi_scsi_xs_done %p %p\n", 1481 1.77 msaitoh DEVNAME(sc), ccb, ccb->ccb_frame); 1482 1.1 bouyer 1483 1.1 bouyer if (xs->data != NULL) { 1484 1.1 bouyer DNPRINTF(MFI_D_INTR, "%s: mfi_scsi_xs_done sync\n", 1485 1.1 bouyer DEVNAME(sc)); 1486 1.43 bouyer bus_dmamap_sync(sc->sc_datadmat, ccb->ccb_dmamap, 0, 1487 1.1 bouyer ccb->ccb_dmamap->dm_mapsize, 1488 1.1 bouyer (xs->xs_control & XS_CTL_DATA_IN) ? 1489 1.1 bouyer BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 1490 1.1 bouyer 1491 1.43 bouyer bus_dmamap_unload(sc->sc_datadmat, ccb->ccb_dmamap); 1492 1.1 bouyer } 1493 1.1 bouyer 1494 1.43 bouyer if (status != MFI_STAT_OK) { 1495 1.1 bouyer xs->error = XS_DRIVER_STUFFUP; 1496 1.1 bouyer DNPRINTF(MFI_D_INTR, "%s: mfi_scsi_xs_done stuffup %#x\n", 1497 1.43 bouyer DEVNAME(sc), status); 1498 1.1 bouyer 1499 1.43 bouyer if (scsi_status != 0) { 1500 1.1 bouyer bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_sense), 1501 1.1 bouyer ccb->ccb_psense - MFIMEM_DVA(sc->sc_sense), 1502 1.1 bouyer MFI_SENSE_SIZE, BUS_DMASYNC_POSTREAD); 1503 1.1 bouyer DNPRINTF(MFI_D_INTR, 1504 1.77 msaitoh "%s: mfi_scsi_xs_done sense %#x %p %p\n", 1505 1.43 bouyer DEVNAME(sc), scsi_status, 1506 1.77 msaitoh &xs->sense, ccb->ccb_sense); 1507 1.1 bouyer memset(&xs->sense, 0, sizeof(xs->sense)); 1508 1.1 bouyer memcpy(&xs->sense, ccb->ccb_sense, 1509 1.1 bouyer sizeof(struct scsi_sense_data)); 1510 1.1 bouyer xs->error = XS_SENSE; 1511 1.1 bouyer } 1512 1.1 bouyer } else { 1513 1.1 bouyer xs->error = XS_NOERROR; 1514 1.1 bouyer xs->status = SCSI_OK; 1515 1.1 bouyer xs->resid = 0; 1516 1.1 bouyer } 1517 1.1 bouyer 1518 1.1 bouyer mfi_put_ccb(ccb); 1519 1.1 bouyer scsipi_done(xs); 1520 1.1 bouyer } 1521 1.1 bouyer 1522 1.13 xtraeme static int 1523 1.1 bouyer mfi_scsi_ld(struct mfi_ccb *ccb, struct scsipi_xfer *xs) 1524 1.1 bouyer { 1525 1.1 bouyer struct mfi_pass_frame *pf; 1526 1.1 bouyer struct scsipi_periph *periph = xs->xs_periph; 1527 1.1 bouyer 1528 1.1 bouyer DNPRINTF(MFI_D_CMD, "%s: mfi_scsi_ld: %d\n", 1529 1.15 cegger device_xname(periph->periph_channel->chan_adapter->adapt_dev), 1530 1.1 bouyer periph->periph_target); 1531 1.1 bouyer 1532 1.1 bouyer pf = &ccb->ccb_frame->mfr_pass; 1533 1.1 bouyer pf->mpf_header.mfh_cmd = MFI_CMD_LD_SCSI_IO; 1534 1.1 bouyer pf->mpf_header.mfh_target_id = periph->periph_target; 1535 1.1 bouyer pf->mpf_header.mfh_lun_id = 0; 1536 1.1 bouyer pf->mpf_header.mfh_cdb_len = xs->cmdlen; 1537 1.1 bouyer pf->mpf_header.mfh_timeout = 0; 1538 1.1 bouyer pf->mpf_header.mfh_data_len= xs->datalen; /* XXX */ 1539 1.1 bouyer pf->mpf_header.mfh_sense_len = MFI_SENSE_SIZE; 1540 1.1 bouyer 1541 1.1 bouyer pf->mpf_sense_addr_hi = 0; 1542 1.1 bouyer pf->mpf_sense_addr_lo = htole32(ccb->ccb_psense); 1543 1.1 bouyer 1544 1.1 bouyer memset(pf->mpf_cdb, 0, 16); 1545 1.1 bouyer memcpy(pf->mpf_cdb, &xs->cmdstore, xs->cmdlen); 1546 1.1 bouyer 1547 1.43 bouyer ccb->ccb_done = mfi_scsi_ld_done; 1548 1.1 bouyer ccb->ccb_xs = xs; 1549 1.1 bouyer ccb->ccb_frame_size = MFI_PASS_FRAME_SIZE; 1550 1.1 bouyer ccb->ccb_sgl = &pf->mpf_sgl; 1551 1.1 bouyer 1552 1.1 bouyer if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) 1553 1.1 bouyer ccb->ccb_direction = (xs->xs_control & XS_CTL_DATA_IN) ? 1554 1.1 bouyer MFI_DATA_IN : MFI_DATA_OUT; 1555 1.1 bouyer else 1556 1.1 bouyer ccb->ccb_direction = MFI_DATA_NONE; 1557 1.1 bouyer 1558 1.1 bouyer if (xs->data) { 1559 1.1 bouyer ccb->ccb_data = xs->data; 1560 1.1 bouyer ccb->ccb_len = xs->datalen; 1561 1.1 bouyer 1562 1.14 xtraeme if (mfi_create_sgl(ccb, (xs->xs_control & XS_CTL_NOSLEEP) ? 1563 1.14 xtraeme BUS_DMA_NOWAIT : BUS_DMA_WAITOK)) 1564 1.13 xtraeme return 1; 1565 1.1 bouyer } 1566 1.1 bouyer 1567 1.13 xtraeme return 0; 1568 1.1 bouyer } 1569 1.1 bouyer 1570 1.13 xtraeme static void 1571 1.1 bouyer mfi_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req, 1572 1.1 bouyer void *arg) 1573 1.1 bouyer { 1574 1.1 bouyer struct scsipi_periph *periph; 1575 1.1 bouyer struct scsipi_xfer *xs; 1576 1.1 bouyer struct scsipi_adapter *adapt = chan->chan_adapter; 1577 1.26 dyoung struct mfi_softc *sc = device_private(adapt->adapt_dev); 1578 1.1 bouyer struct mfi_ccb *ccb; 1579 1.1 bouyer struct scsi_rw_6 *rw; 1580 1.1 bouyer struct scsipi_rw_10 *rwb; 1581 1.43 bouyer struct scsipi_rw_12 *rw12; 1582 1.43 bouyer struct scsipi_rw_16 *rw16; 1583 1.74 msaitoh union mfi_mbox mbox; 1584 1.43 bouyer uint64_t blockno; 1585 1.43 bouyer uint32_t blockcnt; 1586 1.1 bouyer uint8_t target; 1587 1.1 bouyer int s; 1588 1.1 bouyer 1589 1.1 bouyer switch (req) { 1590 1.1 bouyer case ADAPTER_REQ_GROW_RESOURCES: 1591 1.1 bouyer /* Not supported. */ 1592 1.1 bouyer return; 1593 1.1 bouyer case ADAPTER_REQ_SET_XFER_MODE: 1594 1.43 bouyer { 1595 1.43 bouyer struct scsipi_xfer_mode *xm = arg; 1596 1.43 bouyer xm->xm_mode = PERIPH_CAP_TQING; 1597 1.43 bouyer xm->xm_period = 0; 1598 1.43 bouyer xm->xm_offset = 0; 1599 1.43 bouyer scsipi_async_event(&sc->sc_chan, ASYNC_EVENT_XFER_MODE, xm); 1600 1.1 bouyer return; 1601 1.43 bouyer } 1602 1.1 bouyer case ADAPTER_REQ_RUN_XFER: 1603 1.1 bouyer break; 1604 1.1 bouyer } 1605 1.1 bouyer 1606 1.1 bouyer xs = arg; 1607 1.4 bouyer 1608 1.1 bouyer periph = xs->xs_periph; 1609 1.1 bouyer target = periph->periph_target; 1610 1.1 bouyer 1611 1.43 bouyer DNPRINTF(MFI_D_CMD, "%s: mfi_scsipi_request req %d opcode: %#x " 1612 1.43 bouyer "target %d lun %d\n", DEVNAME(sc), req, xs->cmd->opcode, 1613 1.43 bouyer periph->periph_target, periph->periph_lun); 1614 1.43 bouyer 1615 1.1 bouyer s = splbio(); 1616 1.1 bouyer if (target >= MFI_MAX_LD || !sc->sc_ld[target].ld_present || 1617 1.1 bouyer periph->periph_lun != 0) { 1618 1.1 bouyer DNPRINTF(MFI_D_CMD, "%s: invalid target %d\n", 1619 1.1 bouyer DEVNAME(sc), target); 1620 1.1 bouyer xs->error = XS_SELTIMEOUT; 1621 1.1 bouyer scsipi_done(xs); 1622 1.1 bouyer splx(s); 1623 1.1 bouyer return; 1624 1.1 bouyer } 1625 1.45 bouyer if ((xs->cmd->opcode == SCSI_SYNCHRONIZE_CACHE_10 || 1626 1.45 bouyer xs->cmd->opcode == SCSI_SYNCHRONIZE_CACHE_16) && sc->sc_bbuok) { 1627 1.45 bouyer /* the cache is stable storage, don't flush */ 1628 1.45 bouyer xs->error = XS_NOERROR; 1629 1.45 bouyer xs->status = SCSI_OK; 1630 1.45 bouyer xs->resid = 0; 1631 1.45 bouyer scsipi_done(xs); 1632 1.45 bouyer splx(s); 1633 1.45 bouyer return; 1634 1.45 bouyer } 1635 1.1 bouyer 1636 1.1 bouyer if ((ccb = mfi_get_ccb(sc)) == NULL) { 1637 1.1 bouyer DNPRINTF(MFI_D_CMD, "%s: mfi_scsipi_request no ccb\n", DEVNAME(sc)); 1638 1.1 bouyer xs->error = XS_RESOURCE_SHORTAGE; 1639 1.1 bouyer scsipi_done(xs); 1640 1.1 bouyer splx(s); 1641 1.1 bouyer return; 1642 1.1 bouyer } 1643 1.1 bouyer 1644 1.1 bouyer switch (xs->cmd->opcode) { 1645 1.1 bouyer /* IO path */ 1646 1.43 bouyer case READ_16: 1647 1.43 bouyer case WRITE_16: 1648 1.43 bouyer rw16 = (struct scsipi_rw_16 *)xs->cmd; 1649 1.43 bouyer blockno = _8btol(rw16->addr); 1650 1.43 bouyer blockcnt = _4btol(rw16->length); 1651 1.43 bouyer if (sc->sc_iop->mio_ld_io(ccb, xs, blockno, blockcnt)) { 1652 1.43 bouyer goto stuffup; 1653 1.43 bouyer } 1654 1.43 bouyer break; 1655 1.43 bouyer 1656 1.43 bouyer case READ_12: 1657 1.43 bouyer case WRITE_12: 1658 1.43 bouyer rw12 = (struct scsipi_rw_12 *)xs->cmd; 1659 1.43 bouyer blockno = _4btol(rw12->addr); 1660 1.43 bouyer blockcnt = _4btol(rw12->length); 1661 1.43 bouyer if (sc->sc_iop->mio_ld_io(ccb, xs, blockno, blockcnt)) { 1662 1.43 bouyer goto stuffup; 1663 1.43 bouyer } 1664 1.43 bouyer break; 1665 1.43 bouyer 1666 1.1 bouyer case READ_10: 1667 1.1 bouyer case WRITE_10: 1668 1.1 bouyer rwb = (struct scsipi_rw_10 *)xs->cmd; 1669 1.1 bouyer blockno = _4btol(rwb->addr); 1670 1.1 bouyer blockcnt = _2btol(rwb->length); 1671 1.43 bouyer if (sc->sc_iop->mio_ld_io(ccb, xs, blockno, blockcnt)) { 1672 1.1 bouyer goto stuffup; 1673 1.1 bouyer } 1674 1.1 bouyer break; 1675 1.1 bouyer 1676 1.1 bouyer case SCSI_READ_6_COMMAND: 1677 1.1 bouyer case SCSI_WRITE_6_COMMAND: 1678 1.1 bouyer rw = (struct scsi_rw_6 *)xs->cmd; 1679 1.1 bouyer blockno = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff); 1680 1.1 bouyer blockcnt = rw->length ? rw->length : 0x100; 1681 1.43 bouyer if (sc->sc_iop->mio_ld_io(ccb, xs, blockno, blockcnt)) { 1682 1.1 bouyer goto stuffup; 1683 1.1 bouyer } 1684 1.1 bouyer break; 1685 1.1 bouyer 1686 1.1 bouyer case SCSI_SYNCHRONIZE_CACHE_10: 1687 1.45 bouyer case SCSI_SYNCHRONIZE_CACHE_16: 1688 1.74 msaitoh memset(&mbox, 0, sizeof(mbox)); 1689 1.74 msaitoh mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE; 1690 1.19 bouyer if (mfi_mgmt(ccb, xs, 1691 1.74 msaitoh MR_DCMD_CTRL_CACHE_FLUSH, MFI_DATA_NONE, 0, NULL, &mbox)) { 1692 1.1 bouyer goto stuffup; 1693 1.19 bouyer } 1694 1.19 bouyer break; 1695 1.1 bouyer 1696 1.1 bouyer /* hand it of to the firmware and let it deal with it */ 1697 1.1 bouyer case SCSI_TEST_UNIT_READY: 1698 1.1 bouyer /* save off sd? after autoconf */ 1699 1.1 bouyer if (!cold) /* XXX bogus */ 1700 1.26 dyoung strlcpy(sc->sc_ld[target].ld_dev, device_xname(sc->sc_dev), 1701 1.1 bouyer sizeof(sc->sc_ld[target].ld_dev)); 1702 1.1 bouyer /* FALLTHROUGH */ 1703 1.1 bouyer 1704 1.1 bouyer default: 1705 1.1 bouyer if (mfi_scsi_ld(ccb, xs)) { 1706 1.1 bouyer goto stuffup; 1707 1.1 bouyer } 1708 1.1 bouyer break; 1709 1.1 bouyer } 1710 1.1 bouyer 1711 1.1 bouyer DNPRINTF(MFI_D_CMD, "%s: start io %d\n", DEVNAME(sc), target); 1712 1.1 bouyer 1713 1.1 bouyer if (xs->xs_control & XS_CTL_POLL) { 1714 1.1 bouyer if (mfi_poll(ccb)) { 1715 1.1 bouyer /* XXX check for sense in ccb->ccb_sense? */ 1716 1.43 bouyer aprint_error_dev(sc->sc_dev, 1717 1.43 bouyer "mfi_scsipi_request poll failed\n"); 1718 1.22 cegger memset(&xs->sense, 0, sizeof(xs->sense)); 1719 1.1 bouyer xs->sense.scsi_sense.response_code = 1720 1.1 bouyer SSD_RCODE_VALID | SSD_RCODE_CURRENT; 1721 1.1 bouyer xs->sense.scsi_sense.flags = SKEY_ILLEGAL_REQUEST; 1722 1.1 bouyer xs->sense.scsi_sense.asc = 0x20; /* invalid opcode */ 1723 1.1 bouyer xs->error = XS_SENSE; 1724 1.1 bouyer xs->status = SCSI_CHECK; 1725 1.1 bouyer } else { 1726 1.1 bouyer DNPRINTF(MFI_D_DMA, 1727 1.1 bouyer "%s: mfi_scsipi_request poll complete %d\n", 1728 1.1 bouyer DEVNAME(sc), ccb->ccb_dmamap->dm_nsegs); 1729 1.1 bouyer xs->error = XS_NOERROR; 1730 1.1 bouyer xs->status = SCSI_OK; 1731 1.1 bouyer xs->resid = 0; 1732 1.1 bouyer } 1733 1.1 bouyer mfi_put_ccb(ccb); 1734 1.1 bouyer scsipi_done(xs); 1735 1.1 bouyer splx(s); 1736 1.1 bouyer return; 1737 1.1 bouyer } 1738 1.1 bouyer 1739 1.12 xtraeme mfi_post(sc, ccb); 1740 1.1 bouyer 1741 1.1 bouyer DNPRINTF(MFI_D_DMA, "%s: mfi_scsipi_request queued %d\n", DEVNAME(sc), 1742 1.1 bouyer ccb->ccb_dmamap->dm_nsegs); 1743 1.1 bouyer 1744 1.1 bouyer splx(s); 1745 1.1 bouyer return; 1746 1.1 bouyer 1747 1.1 bouyer stuffup: 1748 1.43 bouyer mfi_put_ccb(ccb); 1749 1.1 bouyer xs->error = XS_DRIVER_STUFFUP; 1750 1.1 bouyer scsipi_done(xs); 1751 1.1 bouyer splx(s); 1752 1.1 bouyer } 1753 1.1 bouyer 1754 1.13 xtraeme static int 1755 1.1 bouyer mfi_create_sgl(struct mfi_ccb *ccb, int flags) 1756 1.1 bouyer { 1757 1.1 bouyer struct mfi_softc *sc = ccb->ccb_sc; 1758 1.1 bouyer struct mfi_frame_header *hdr; 1759 1.1 bouyer bus_dma_segment_t *sgd; 1760 1.1 bouyer union mfi_sgl *sgl; 1761 1.1 bouyer int error, i; 1762 1.1 bouyer 1763 1.77 msaitoh DNPRINTF(MFI_D_DMA, "%s: mfi_create_sgl %p\n", DEVNAME(sc), 1764 1.77 msaitoh ccb->ccb_data); 1765 1.1 bouyer 1766 1.1 bouyer if (!ccb->ccb_data) 1767 1.13 xtraeme return 1; 1768 1.1 bouyer 1769 1.43 bouyer KASSERT(flags == BUS_DMA_NOWAIT || !cpu_intr_p()); 1770 1.43 bouyer error = bus_dmamap_load(sc->sc_datadmat, ccb->ccb_dmamap, 1771 1.1 bouyer ccb->ccb_data, ccb->ccb_len, NULL, flags); 1772 1.1 bouyer if (error) { 1773 1.43 bouyer if (error == EFBIG) { 1774 1.43 bouyer aprint_error_dev(sc->sc_dev, "more than %d dma segs\n", 1775 1.1 bouyer sc->sc_max_sgl); 1776 1.43 bouyer } else { 1777 1.43 bouyer aprint_error_dev(sc->sc_dev, 1778 1.43 bouyer "error %d loading dma map\n", error); 1779 1.43 bouyer } 1780 1.13 xtraeme return 1; 1781 1.1 bouyer } 1782 1.1 bouyer 1783 1.1 bouyer hdr = &ccb->ccb_frame->mfr_header; 1784 1.1 bouyer sgl = ccb->ccb_sgl; 1785 1.1 bouyer sgd = ccb->ccb_dmamap->dm_segs; 1786 1.1 bouyer for (i = 0; i < ccb->ccb_dmamap->dm_nsegs; i++) { 1787 1.69 msaitoh if (((sc->sc_ioptype == MFI_IOP_SKINNY) || 1788 1.69 msaitoh (sc->sc_ioptype == MFI_IOP_TBOLT)) && 1789 1.43 bouyer (hdr->mfh_cmd == MFI_CMD_PD_SCSI_IO || 1790 1.43 bouyer hdr->mfh_cmd == MFI_CMD_LD_READ || 1791 1.43 bouyer hdr->mfh_cmd == MFI_CMD_LD_WRITE)) { 1792 1.43 bouyer sgl->sg_ieee[i].addr = htole64(sgd[i].ds_addr); 1793 1.43 bouyer sgl->sg_ieee[i].len = htole32(sgd[i].ds_len); 1794 1.43 bouyer sgl->sg_ieee[i].flags = 0; 1795 1.43 bouyer DNPRINTF(MFI_D_DMA, "%s: addr: %#" PRIx64 " len: %#" 1796 1.43 bouyer PRIx32 "\n", 1797 1.43 bouyer DEVNAME(sc), sgl->sg64[i].addr, sgl->sg64[i].len); 1798 1.43 bouyer hdr->mfh_flags |= MFI_FRAME_IEEE_SGL | MFI_FRAME_SGL64; 1799 1.43 bouyer } else if (sc->sc_64bit_dma) { 1800 1.39 bouyer sgl->sg64[i].addr = htole64(sgd[i].ds_addr); 1801 1.41 bouyer sgl->sg64[i].len = htole32(sgd[i].ds_len); 1802 1.39 bouyer DNPRINTF(MFI_D_DMA, "%s: addr: %#" PRIx64 " len: %#" 1803 1.43 bouyer PRIx32 "\n", 1804 1.39 bouyer DEVNAME(sc), sgl->sg64[i].addr, sgl->sg64[i].len); 1805 1.43 bouyer hdr->mfh_flags |= MFI_FRAME_SGL64; 1806 1.39 bouyer } else { 1807 1.39 bouyer sgl->sg32[i].addr = htole32(sgd[i].ds_addr); 1808 1.39 bouyer sgl->sg32[i].len = htole32(sgd[i].ds_len); 1809 1.39 bouyer DNPRINTF(MFI_D_DMA, "%s: addr: %#x len: %#x\n", 1810 1.39 bouyer DEVNAME(sc), sgl->sg32[i].addr, sgl->sg32[i].len); 1811 1.43 bouyer hdr->mfh_flags |= MFI_FRAME_SGL32; 1812 1.39 bouyer } 1813 1.1 bouyer } 1814 1.1 bouyer 1815 1.1 bouyer if (ccb->ccb_direction == MFI_DATA_IN) { 1816 1.1 bouyer hdr->mfh_flags |= MFI_FRAME_DIR_READ; 1817 1.43 bouyer bus_dmamap_sync(sc->sc_datadmat, ccb->ccb_dmamap, 0, 1818 1.1 bouyer ccb->ccb_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); 1819 1.1 bouyer } else { 1820 1.1 bouyer hdr->mfh_flags |= MFI_FRAME_DIR_WRITE; 1821 1.43 bouyer bus_dmamap_sync(sc->sc_datadmat, ccb->ccb_dmamap, 0, 1822 1.1 bouyer ccb->ccb_dmamap->dm_mapsize, BUS_DMASYNC_PREWRITE); 1823 1.1 bouyer } 1824 1.1 bouyer 1825 1.1 bouyer hdr->mfh_sg_count = ccb->ccb_dmamap->dm_nsegs; 1826 1.39 bouyer ccb->ccb_frame_size += sc->sc_sgl_size * ccb->ccb_dmamap->dm_nsegs; 1827 1.1 bouyer ccb->ccb_extra_frames = (ccb->ccb_frame_size - 1) / MFI_FRAME_SIZE; 1828 1.1 bouyer 1829 1.1 bouyer DNPRINTF(MFI_D_DMA, "%s: sg_count: %d frame_size: %d frames_size: %d" 1830 1.1 bouyer " dm_nsegs: %d extra_frames: %d\n", 1831 1.1 bouyer DEVNAME(sc), 1832 1.1 bouyer hdr->mfh_sg_count, 1833 1.1 bouyer ccb->ccb_frame_size, 1834 1.1 bouyer sc->sc_frames_size, 1835 1.1 bouyer ccb->ccb_dmamap->dm_nsegs, 1836 1.1 bouyer ccb->ccb_extra_frames); 1837 1.1 bouyer 1838 1.13 xtraeme return 0; 1839 1.1 bouyer } 1840 1.1 bouyer 1841 1.13 xtraeme static int 1842 1.19 bouyer mfi_mgmt_internal(struct mfi_softc *sc, uint32_t opc, uint32_t dir, 1843 1.74 msaitoh uint32_t len, void *buf, const union mfi_mbox *mbox, bool poll) 1844 1.33 msaitoh { 1845 1.1 bouyer struct mfi_ccb *ccb; 1846 1.1 bouyer int rv = 1; 1847 1.1 bouyer 1848 1.1 bouyer if ((ccb = mfi_get_ccb(sc)) == NULL) 1849 1.13 xtraeme return rv; 1850 1.19 bouyer rv = mfi_mgmt(ccb, NULL, opc, dir, len, buf, mbox); 1851 1.19 bouyer if (rv) 1852 1.19 bouyer return rv; 1853 1.19 bouyer 1854 1.45 bouyer if (poll) { 1855 1.43 bouyer rv = 1; 1856 1.19 bouyer if (mfi_poll(ccb)) 1857 1.19 bouyer goto done; 1858 1.19 bouyer } else { 1859 1.19 bouyer mfi_post(sc, ccb); 1860 1.19 bouyer 1861 1.19 bouyer DNPRINTF(MFI_D_MISC, "%s: mfi_mgmt_internal sleeping\n", 1862 1.19 bouyer DEVNAME(sc)); 1863 1.19 bouyer while (ccb->ccb_state != MFI_CCB_DONE) 1864 1.19 bouyer tsleep(ccb, PRIBIO, "mfi_mgmt", 0); 1865 1.19 bouyer 1866 1.19 bouyer if (ccb->ccb_flags & MFI_CCB_F_ERR) 1867 1.19 bouyer goto done; 1868 1.19 bouyer } 1869 1.19 bouyer rv = 0; 1870 1.19 bouyer 1871 1.19 bouyer done: 1872 1.19 bouyer mfi_put_ccb(ccb); 1873 1.19 bouyer return rv; 1874 1.19 bouyer } 1875 1.19 bouyer 1876 1.19 bouyer static int 1877 1.74 msaitoh mfi_mgmt(struct mfi_ccb *ccb, struct scsipi_xfer *xs, uint32_t opc, 1878 1.74 msaitoh uint32_t dir, uint32_t len, void *buf, const union mfi_mbox *mbox) 1879 1.19 bouyer { 1880 1.19 bouyer struct mfi_dcmd_frame *dcmd; 1881 1.19 bouyer 1882 1.19 bouyer DNPRINTF(MFI_D_MISC, "%s: mfi_mgmt %#x\n", DEVNAME(ccb->ccb_sc), opc); 1883 1.1 bouyer 1884 1.1 bouyer dcmd = &ccb->ccb_frame->mfr_dcmd; 1885 1.60 bouyer memset(dcmd->mdf_mbox.b, 0, MFI_MBOX_SIZE); 1886 1.1 bouyer dcmd->mdf_header.mfh_cmd = MFI_CMD_DCMD; 1887 1.1 bouyer dcmd->mdf_header.mfh_timeout = 0; 1888 1.1 bouyer 1889 1.1 bouyer dcmd->mdf_opcode = opc; 1890 1.1 bouyer dcmd->mdf_header.mfh_data_len = 0; 1891 1.1 bouyer ccb->ccb_direction = dir; 1892 1.19 bouyer ccb->ccb_xs = xs; 1893 1.1 bouyer ccb->ccb_done = mfi_mgmt_done; 1894 1.1 bouyer 1895 1.1 bouyer ccb->ccb_frame_size = MFI_DCMD_FRAME_SIZE; 1896 1.1 bouyer 1897 1.1 bouyer /* handle special opcodes */ 1898 1.1 bouyer if (mbox) 1899 1.60 bouyer memcpy(dcmd->mdf_mbox.b, mbox, MFI_MBOX_SIZE); 1900 1.1 bouyer 1901 1.1 bouyer if (dir != MFI_DATA_NONE) { 1902 1.1 bouyer dcmd->mdf_header.mfh_data_len = len; 1903 1.1 bouyer ccb->ccb_data = buf; 1904 1.1 bouyer ccb->ccb_len = len; 1905 1.1 bouyer ccb->ccb_sgl = &dcmd->mdf_sgl; 1906 1.1 bouyer 1907 1.1 bouyer if (mfi_create_sgl(ccb, BUS_DMA_WAITOK)) 1908 1.19 bouyer return 1; 1909 1.1 bouyer } 1910 1.19 bouyer return 0; 1911 1.1 bouyer } 1912 1.1 bouyer 1913 1.13 xtraeme static void 1914 1.1 bouyer mfi_mgmt_done(struct mfi_ccb *ccb) 1915 1.1 bouyer { 1916 1.19 bouyer struct scsipi_xfer *xs = ccb->ccb_xs; 1917 1.1 bouyer struct mfi_softc *sc = ccb->ccb_sc; 1918 1.1 bouyer struct mfi_frame_header *hdr = &ccb->ccb_frame->mfr_header; 1919 1.1 bouyer 1920 1.4 bouyer DNPRINTF(MFI_D_INTR, "%s: mfi_mgmt_done %#lx %#lx\n", 1921 1.4 bouyer DEVNAME(sc), (u_long)ccb, (u_long)ccb->ccb_frame); 1922 1.1 bouyer 1923 1.1 bouyer if (ccb->ccb_data != NULL) { 1924 1.1 bouyer DNPRINTF(MFI_D_INTR, "%s: mfi_mgmt_done sync\n", 1925 1.1 bouyer DEVNAME(sc)); 1926 1.43 bouyer bus_dmamap_sync(sc->sc_datadmat, ccb->ccb_dmamap, 0, 1927 1.1 bouyer ccb->ccb_dmamap->dm_mapsize, 1928 1.1 bouyer (ccb->ccb_direction & MFI_DATA_IN) ? 1929 1.1 bouyer BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 1930 1.1 bouyer 1931 1.43 bouyer bus_dmamap_unload(sc->sc_datadmat, ccb->ccb_dmamap); 1932 1.1 bouyer } 1933 1.1 bouyer 1934 1.1 bouyer if (hdr->mfh_cmd_status != MFI_STAT_OK) 1935 1.1 bouyer ccb->ccb_flags |= MFI_CCB_F_ERR; 1936 1.1 bouyer 1937 1.1 bouyer ccb->ccb_state = MFI_CCB_DONE; 1938 1.19 bouyer if (xs) { 1939 1.19 bouyer if (hdr->mfh_cmd_status != MFI_STAT_OK) { 1940 1.19 bouyer xs->error = XS_DRIVER_STUFFUP; 1941 1.19 bouyer } else { 1942 1.19 bouyer xs->error = XS_NOERROR; 1943 1.19 bouyer xs->status = SCSI_OK; 1944 1.19 bouyer xs->resid = 0; 1945 1.19 bouyer } 1946 1.19 bouyer mfi_put_ccb(ccb); 1947 1.19 bouyer scsipi_done(xs); 1948 1.30 dyoung } else 1949 1.19 bouyer wakeup(ccb); 1950 1.1 bouyer } 1951 1.1 bouyer 1952 1.1 bouyer #if NBIO > 0 1953 1.1 bouyer int 1954 1.23 cegger mfi_ioctl(device_t dev, u_long cmd, void *addr) 1955 1.1 bouyer { 1956 1.26 dyoung struct mfi_softc *sc = device_private(dev); 1957 1.1 bouyer int error = 0; 1958 1.31 bouyer int s; 1959 1.31 bouyer 1960 1.31 bouyer KERNEL_LOCK(1, curlwp); 1961 1.31 bouyer s = splbio(); 1962 1.1 bouyer 1963 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl ", DEVNAME(sc)); 1964 1.1 bouyer 1965 1.1 bouyer switch (cmd) { 1966 1.1 bouyer case BIOCINQ: 1967 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "inq\n"); 1968 1.1 bouyer error = mfi_ioctl_inq(sc, (struct bioc_inq *)addr); 1969 1.1 bouyer break; 1970 1.1 bouyer 1971 1.1 bouyer case BIOCVOL: 1972 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "vol\n"); 1973 1.1 bouyer error = mfi_ioctl_vol(sc, (struct bioc_vol *)addr); 1974 1.1 bouyer break; 1975 1.1 bouyer 1976 1.1 bouyer case BIOCDISK: 1977 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "disk\n"); 1978 1.1 bouyer error = mfi_ioctl_disk(sc, (struct bioc_disk *)addr); 1979 1.1 bouyer break; 1980 1.1 bouyer 1981 1.1 bouyer case BIOCALARM: 1982 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "alarm\n"); 1983 1.1 bouyer error = mfi_ioctl_alarm(sc, (struct bioc_alarm *)addr); 1984 1.1 bouyer break; 1985 1.1 bouyer 1986 1.1 bouyer case BIOCBLINK: 1987 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "blink\n"); 1988 1.1 bouyer error = mfi_ioctl_blink(sc, (struct bioc_blink *)addr); 1989 1.1 bouyer break; 1990 1.1 bouyer 1991 1.1 bouyer case BIOCSETSTATE: 1992 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "setstate\n"); 1993 1.1 bouyer error = mfi_ioctl_setstate(sc, (struct bioc_setstate *)addr); 1994 1.1 bouyer break; 1995 1.1 bouyer 1996 1.1 bouyer default: 1997 1.1 bouyer DNPRINTF(MFI_D_IOCTL, " invalid ioctl\n"); 1998 1.1 bouyer error = EINVAL; 1999 1.1 bouyer } 2000 1.4 bouyer splx(s); 2001 1.31 bouyer KERNEL_UNLOCK_ONE(curlwp); 2002 1.13 xtraeme 2003 1.4 bouyer DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl return %x\n", DEVNAME(sc), error); 2004 1.13 xtraeme return error; 2005 1.1 bouyer } 2006 1.1 bouyer 2007 1.13 xtraeme static int 2008 1.1 bouyer mfi_ioctl_inq(struct mfi_softc *sc, struct bioc_inq *bi) 2009 1.1 bouyer { 2010 1.1 bouyer struct mfi_conf *cfg; 2011 1.1 bouyer int rv = EINVAL; 2012 1.1 bouyer 2013 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_inq\n", DEVNAME(sc)); 2014 1.1 bouyer 2015 1.1 bouyer if (mfi_get_info(sc)) { 2016 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_inq failed\n", 2017 1.1 bouyer DEVNAME(sc)); 2018 1.13 xtraeme return EIO; 2019 1.1 bouyer } 2020 1.1 bouyer 2021 1.1 bouyer /* get figures */ 2022 1.1 bouyer cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK); 2023 1.60 bouyer if (mfi_mgmt_internal(sc, MR_DCMD_CONF_GET, MFI_DATA_IN, 2024 1.45 bouyer sizeof *cfg, cfg, NULL, false)) 2025 1.1 bouyer goto freeme; 2026 1.1 bouyer 2027 1.1 bouyer strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev)); 2028 1.1 bouyer bi->bi_novol = cfg->mfc_no_ld + cfg->mfc_no_hs; 2029 1.1 bouyer bi->bi_nodisk = sc->sc_info.mci_pd_disks_present; 2030 1.1 bouyer 2031 1.1 bouyer rv = 0; 2032 1.1 bouyer freeme: 2033 1.1 bouyer free(cfg, M_DEVBUF); 2034 1.13 xtraeme return rv; 2035 1.1 bouyer } 2036 1.1 bouyer 2037 1.13 xtraeme static int 2038 1.1 bouyer mfi_ioctl_vol(struct mfi_softc *sc, struct bioc_vol *bv) 2039 1.1 bouyer { 2040 1.1 bouyer int i, per, rv = EINVAL; 2041 1.74 msaitoh union mfi_mbox mbox; 2042 1.1 bouyer 2043 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_vol %#x\n", 2044 1.1 bouyer DEVNAME(sc), bv->bv_volid); 2045 1.1 bouyer 2046 1.19 bouyer if (mfi_mgmt_internal(sc, MR_DCMD_LD_GET_LIST, MFI_DATA_IN, 2047 1.45 bouyer sizeof(sc->sc_ld_list), &sc->sc_ld_list, NULL, false)) 2048 1.1 bouyer goto done; 2049 1.1 bouyer 2050 1.1 bouyer i = bv->bv_volid; 2051 1.74 msaitoh memset(&mbox, 0, sizeof(mbox)); 2052 1.74 msaitoh mbox.b[0] = sc->sc_ld_list.mll_list[i].mll_ld.mld_target; 2053 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_vol target %#x\n", 2054 1.74 msaitoh DEVNAME(sc), mbox.b[0]); 2055 1.1 bouyer 2056 1.19 bouyer if (mfi_mgmt_internal(sc, MR_DCMD_LD_GET_INFO, MFI_DATA_IN, 2057 1.74 msaitoh sizeof(sc->sc_ld_details), &sc->sc_ld_details, &mbox, false)) 2058 1.1 bouyer goto done; 2059 1.1 bouyer 2060 1.1 bouyer if (bv->bv_volid >= sc->sc_ld_list.mll_no_ld) { 2061 1.1 bouyer /* go do hotspares */ 2062 1.1 bouyer rv = mfi_bio_hs(sc, bv->bv_volid, MFI_MGMT_VD, bv); 2063 1.1 bouyer goto done; 2064 1.1 bouyer } 2065 1.1 bouyer 2066 1.1 bouyer strlcpy(bv->bv_dev, sc->sc_ld[i].ld_dev, sizeof(bv->bv_dev)); 2067 1.1 bouyer 2068 1.73 msaitoh switch (sc->sc_ld_list.mll_list[i].mll_state) { 2069 1.1 bouyer case MFI_LD_OFFLINE: 2070 1.1 bouyer bv->bv_status = BIOC_SVOFFLINE; 2071 1.1 bouyer break; 2072 1.1 bouyer 2073 1.1 bouyer case MFI_LD_PART_DEGRADED: 2074 1.1 bouyer case MFI_LD_DEGRADED: 2075 1.1 bouyer bv->bv_status = BIOC_SVDEGRADED; 2076 1.1 bouyer break; 2077 1.1 bouyer 2078 1.1 bouyer case MFI_LD_ONLINE: 2079 1.1 bouyer bv->bv_status = BIOC_SVONLINE; 2080 1.1 bouyer break; 2081 1.1 bouyer 2082 1.1 bouyer default: 2083 1.1 bouyer bv->bv_status = BIOC_SVINVALID; 2084 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "%s: invalid logical disk state %#x\n", 2085 1.1 bouyer DEVNAME(sc), 2086 1.1 bouyer sc->sc_ld_list.mll_list[i].mll_state); 2087 1.1 bouyer } 2088 1.1 bouyer 2089 1.1 bouyer /* additional status can modify MFI status */ 2090 1.1 bouyer switch (sc->sc_ld_details.mld_progress.mlp_in_prog) { 2091 1.1 bouyer case MFI_LD_PROG_CC: 2092 1.1 bouyer bv->bv_status = BIOC_SVSCRUB; 2093 1.1 bouyer per = (int)sc->sc_ld_details.mld_progress.mlp_cc.mp_progress; 2094 1.1 bouyer bv->bv_percent = (per * 100) / 0xffff; 2095 1.1 bouyer bv->bv_seconds = 2096 1.1 bouyer sc->sc_ld_details.mld_progress.mlp_cc.mp_elapsed_seconds; 2097 1.1 bouyer break; 2098 1.1 bouyer 2099 1.71 msaitoh case MFI_LD_PROG_BGI: 2100 1.71 msaitoh bv->bv_status = BIOC_SVSCRUB; 2101 1.71 msaitoh per = (int)sc->sc_ld_details.mld_progress.mlp_bgi.mp_progress; 2102 1.71 msaitoh bv->bv_percent = (per * 100) / 0xffff; 2103 1.71 msaitoh bv->bv_seconds = 2104 1.71 msaitoh sc->sc_ld_details.mld_progress.mlp_bgi.mp_elapsed_seconds; 2105 1.71 msaitoh break; 2106 1.71 msaitoh 2107 1.1 bouyer case MFI_LD_PROG_FGI: 2108 1.1 bouyer case MFI_LD_PROG_RECONSTRUCT: 2109 1.1 bouyer /* nothing yet */ 2110 1.1 bouyer break; 2111 1.1 bouyer } 2112 1.1 bouyer 2113 1.1 bouyer /* 2114 1.1 bouyer * The RAID levels are determined per the SNIA DDF spec, this is only 2115 1.70 msaitoh * a subset that is valid for the MFI controller. 2116 1.1 bouyer */ 2117 1.1 bouyer bv->bv_level = sc->sc_ld_details.mld_cfg.mlc_parm.mpa_pri_raid; 2118 1.1 bouyer if (sc->sc_ld_details.mld_cfg.mlc_parm.mpa_sec_raid == 2119 1.1 bouyer MFI_DDF_SRL_SPANNED) 2120 1.1 bouyer bv->bv_level *= 10; 2121 1.1 bouyer 2122 1.1 bouyer bv->bv_nodisk = sc->sc_ld_details.mld_cfg.mlc_parm.mpa_no_drv_per_span * 2123 1.1 bouyer sc->sc_ld_details.mld_cfg.mlc_parm.mpa_span_depth; 2124 1.1 bouyer 2125 1.1 bouyer bv->bv_size = sc->sc_ld_details.mld_size * 512; /* bytes per block */ 2126 1.75 msaitoh bv->bv_stripe_size = 2127 1.75 msaitoh (512 << sc->sc_ld_details.mld_cfg.mlc_parm.mpa_stripe_size) 2128 1.75 msaitoh / 1024; /* in KB */ 2129 1.1 bouyer 2130 1.1 bouyer rv = 0; 2131 1.1 bouyer done: 2132 1.4 bouyer DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_vol done %x\n", 2133 1.4 bouyer DEVNAME(sc), rv); 2134 1.13 xtraeme return rv; 2135 1.1 bouyer } 2136 1.1 bouyer 2137 1.13 xtraeme static int 2138 1.1 bouyer mfi_ioctl_disk(struct mfi_softc *sc, struct bioc_disk *bd) 2139 1.1 bouyer { 2140 1.1 bouyer struct mfi_conf *cfg; 2141 1.1 bouyer struct mfi_array *ar; 2142 1.1 bouyer struct mfi_ld_cfg *ld; 2143 1.1 bouyer struct mfi_pd_details *pd; 2144 1.4 bouyer struct scsipi_inquiry_data *inqbuf; 2145 1.1 bouyer char vend[8+16+4+1]; 2146 1.1 bouyer int i, rv = EINVAL; 2147 1.1 bouyer int arr, vol, disk; 2148 1.1 bouyer uint32_t size; 2149 1.74 msaitoh union mfi_mbox mbox; 2150 1.1 bouyer 2151 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_disk %#x\n", 2152 1.1 bouyer DEVNAME(sc), bd->bd_diskid); 2153 1.1 bouyer 2154 1.4 bouyer pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK | M_ZERO); 2155 1.1 bouyer 2156 1.1 bouyer /* send single element command to retrieve size for full structure */ 2157 1.1 bouyer cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK); 2158 1.60 bouyer if (mfi_mgmt_internal(sc, MR_DCMD_CONF_GET, MFI_DATA_IN, 2159 1.45 bouyer sizeof *cfg, cfg, NULL, false)) 2160 1.1 bouyer goto freeme; 2161 1.1 bouyer 2162 1.1 bouyer size = cfg->mfc_size; 2163 1.1 bouyer free(cfg, M_DEVBUF); 2164 1.1 bouyer 2165 1.1 bouyer /* memory for read config */ 2166 1.13 xtraeme cfg = malloc(size, M_DEVBUF, M_WAITOK|M_ZERO); 2167 1.60 bouyer if (mfi_mgmt_internal(sc, MR_DCMD_CONF_GET, MFI_DATA_IN, 2168 1.45 bouyer size, cfg, NULL, false)) 2169 1.1 bouyer goto freeme; 2170 1.1 bouyer 2171 1.1 bouyer ar = cfg->mfc_array; 2172 1.1 bouyer 2173 1.1 bouyer /* calculate offset to ld structure */ 2174 1.1 bouyer ld = (struct mfi_ld_cfg *)( 2175 1.1 bouyer ((uint8_t *)cfg) + offsetof(struct mfi_conf, mfc_array) + 2176 1.1 bouyer cfg->mfc_array_size * cfg->mfc_no_array); 2177 1.1 bouyer 2178 1.1 bouyer vol = bd->bd_volid; 2179 1.1 bouyer 2180 1.1 bouyer if (vol >= cfg->mfc_no_ld) { 2181 1.1 bouyer /* do hotspares */ 2182 1.1 bouyer rv = mfi_bio_hs(sc, bd->bd_volid, MFI_MGMT_SD, bd); 2183 1.1 bouyer goto freeme; 2184 1.1 bouyer } 2185 1.1 bouyer 2186 1.1 bouyer /* find corresponding array for ld */ 2187 1.1 bouyer for (i = 0, arr = 0; i < vol; i++) 2188 1.1 bouyer arr += ld[i].mlc_parm.mpa_span_depth; 2189 1.1 bouyer 2190 1.1 bouyer /* offset disk into pd list */ 2191 1.1 bouyer disk = bd->bd_diskid % ld[vol].mlc_parm.mpa_no_drv_per_span; 2192 1.1 bouyer 2193 1.1 bouyer /* offset array index into the next spans */ 2194 1.1 bouyer arr += bd->bd_diskid / ld[vol].mlc_parm.mpa_no_drv_per_span; 2195 1.1 bouyer 2196 1.1 bouyer bd->bd_target = ar[arr].pd[disk].mar_enc_slot; 2197 1.1 bouyer switch (ar[arr].pd[disk].mar_pd_state){ 2198 1.1 bouyer case MFI_PD_UNCONFIG_GOOD: 2199 1.1 bouyer bd->bd_status = BIOC_SDUNUSED; 2200 1.1 bouyer break; 2201 1.1 bouyer 2202 1.1 bouyer case MFI_PD_HOTSPARE: /* XXX dedicated hotspare part of array? */ 2203 1.1 bouyer bd->bd_status = BIOC_SDHOTSPARE; 2204 1.1 bouyer break; 2205 1.1 bouyer 2206 1.1 bouyer case MFI_PD_OFFLINE: 2207 1.1 bouyer bd->bd_status = BIOC_SDOFFLINE; 2208 1.1 bouyer break; 2209 1.1 bouyer 2210 1.1 bouyer case MFI_PD_FAILED: 2211 1.1 bouyer bd->bd_status = BIOC_SDFAILED; 2212 1.1 bouyer break; 2213 1.1 bouyer 2214 1.1 bouyer case MFI_PD_REBUILD: 2215 1.1 bouyer bd->bd_status = BIOC_SDREBUILD; 2216 1.1 bouyer break; 2217 1.1 bouyer 2218 1.1 bouyer case MFI_PD_ONLINE: 2219 1.1 bouyer bd->bd_status = BIOC_SDONLINE; 2220 1.1 bouyer break; 2221 1.1 bouyer 2222 1.1 bouyer case MFI_PD_UNCONFIG_BAD: /* XXX define new state in bio */ 2223 1.1 bouyer default: 2224 1.1 bouyer bd->bd_status = BIOC_SDINVALID; 2225 1.1 bouyer break; 2226 1.1 bouyer } 2227 1.1 bouyer 2228 1.1 bouyer /* get the remaining fields */ 2229 1.74 msaitoh memset(&mbox, 0, sizeof(mbox)); 2230 1.74 msaitoh mbox.s[0] = ar[arr].pd[disk].mar_pd.mfp_id; 2231 1.4 bouyer memset(pd, 0, sizeof(*pd)); 2232 1.19 bouyer if (mfi_mgmt_internal(sc, MR_DCMD_PD_GET_INFO, MFI_DATA_IN, 2233 1.74 msaitoh sizeof *pd, pd, &mbox, false)) 2234 1.1 bouyer goto freeme; 2235 1.1 bouyer 2236 1.1 bouyer bd->bd_size = pd->mpd_size * 512; /* bytes per block */ 2237 1.1 bouyer 2238 1.1 bouyer /* if pd->mpd_enc_idx is 0 then it is not in an enclosure */ 2239 1.1 bouyer bd->bd_channel = pd->mpd_enc_idx; 2240 1.1 bouyer 2241 1.4 bouyer inqbuf = (struct scsipi_inquiry_data *)&pd->mpd_inq_data; 2242 1.1 bouyer memcpy(vend, inqbuf->vendor, sizeof vend - 1); 2243 1.1 bouyer vend[sizeof vend - 1] = '\0'; 2244 1.1 bouyer strlcpy(bd->bd_vendor, vend, sizeof(bd->bd_vendor)); 2245 1.1 bouyer 2246 1.1 bouyer /* XXX find a way to retrieve serial nr from drive */ 2247 1.1 bouyer /* XXX find a way to get bd_procdev */ 2248 1.1 bouyer 2249 1.1 bouyer rv = 0; 2250 1.1 bouyer freeme: 2251 1.1 bouyer free(pd, M_DEVBUF); 2252 1.1 bouyer free(cfg, M_DEVBUF); 2253 1.1 bouyer 2254 1.13 xtraeme return rv; 2255 1.1 bouyer } 2256 1.1 bouyer 2257 1.13 xtraeme static int 2258 1.1 bouyer mfi_ioctl_alarm(struct mfi_softc *sc, struct bioc_alarm *ba) 2259 1.1 bouyer { 2260 1.1 bouyer uint32_t opc, dir = MFI_DATA_NONE; 2261 1.1 bouyer int rv = 0; 2262 1.1 bouyer int8_t ret; 2263 1.1 bouyer 2264 1.73 msaitoh switch (ba->ba_opcode) { 2265 1.1 bouyer case BIOC_SADISABLE: 2266 1.1 bouyer opc = MR_DCMD_SPEAKER_DISABLE; 2267 1.1 bouyer break; 2268 1.1 bouyer 2269 1.1 bouyer case BIOC_SAENABLE: 2270 1.1 bouyer opc = MR_DCMD_SPEAKER_ENABLE; 2271 1.1 bouyer break; 2272 1.1 bouyer 2273 1.1 bouyer case BIOC_SASILENCE: 2274 1.1 bouyer opc = MR_DCMD_SPEAKER_SILENCE; 2275 1.1 bouyer break; 2276 1.1 bouyer 2277 1.1 bouyer case BIOC_GASTATUS: 2278 1.1 bouyer opc = MR_DCMD_SPEAKER_GET; 2279 1.1 bouyer dir = MFI_DATA_IN; 2280 1.1 bouyer break; 2281 1.1 bouyer 2282 1.1 bouyer case BIOC_SATEST: 2283 1.1 bouyer opc = MR_DCMD_SPEAKER_TEST; 2284 1.1 bouyer break; 2285 1.1 bouyer 2286 1.1 bouyer default: 2287 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_alarm biocalarm invalid " 2288 1.1 bouyer "opcode %x\n", DEVNAME(sc), ba->ba_opcode); 2289 1.13 xtraeme return EINVAL; 2290 1.1 bouyer } 2291 1.1 bouyer 2292 1.45 bouyer if (mfi_mgmt_internal(sc, opc, dir, sizeof(ret), &ret, NULL, false)) 2293 1.1 bouyer rv = EINVAL; 2294 1.1 bouyer else 2295 1.1 bouyer if (ba->ba_opcode == BIOC_GASTATUS) 2296 1.1 bouyer ba->ba_status = ret; 2297 1.1 bouyer else 2298 1.1 bouyer ba->ba_status = 0; 2299 1.1 bouyer 2300 1.13 xtraeme return rv; 2301 1.1 bouyer } 2302 1.1 bouyer 2303 1.13 xtraeme static int 2304 1.1 bouyer mfi_ioctl_blink(struct mfi_softc *sc, struct bioc_blink *bb) 2305 1.1 bouyer { 2306 1.1 bouyer int i, found, rv = EINVAL; 2307 1.74 msaitoh union mfi_mbox mbox; 2308 1.1 bouyer uint32_t cmd; 2309 1.1 bouyer struct mfi_pd_list *pd; 2310 1.1 bouyer 2311 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_blink %x\n", DEVNAME(sc), 2312 1.1 bouyer bb->bb_status); 2313 1.1 bouyer 2314 1.1 bouyer /* channel 0 means not in an enclosure so can't be blinked */ 2315 1.1 bouyer if (bb->bb_channel == 0) 2316 1.13 xtraeme return EINVAL; 2317 1.1 bouyer 2318 1.76 msaitoh pd = malloc(sizeof(*pd), M_DEVBUF, M_WAITOK); 2319 1.1 bouyer 2320 1.19 bouyer if (mfi_mgmt_internal(sc, MR_DCMD_PD_GET_LIST, MFI_DATA_IN, 2321 1.76 msaitoh sizeof(*pd), pd, NULL, false)) 2322 1.1 bouyer goto done; 2323 1.1 bouyer 2324 1.1 bouyer for (i = 0, found = 0; i < pd->mpl_no_pd; i++) 2325 1.1 bouyer if (bb->bb_channel == pd->mpl_address[i].mpa_enc_index && 2326 1.1 bouyer bb->bb_target == pd->mpl_address[i].mpa_enc_slot) { 2327 1.73 msaitoh found = 1; 2328 1.1 bouyer break; 2329 1.1 bouyer } 2330 1.1 bouyer 2331 1.1 bouyer if (!found) 2332 1.1 bouyer goto done; 2333 1.1 bouyer 2334 1.74 msaitoh memset(&mbox, 0, sizeof(mbox)); 2335 1.74 msaitoh mbox.s[0] = pd->mpl_address[i].mpa_pd_id; 2336 1.1 bouyer 2337 1.1 bouyer switch (bb->bb_status) { 2338 1.1 bouyer case BIOC_SBUNBLINK: 2339 1.1 bouyer cmd = MR_DCMD_PD_UNBLINK; 2340 1.1 bouyer break; 2341 1.1 bouyer 2342 1.1 bouyer case BIOC_SBBLINK: 2343 1.1 bouyer cmd = MR_DCMD_PD_BLINK; 2344 1.1 bouyer break; 2345 1.1 bouyer 2346 1.1 bouyer case BIOC_SBALARM: 2347 1.1 bouyer default: 2348 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_blink biocblink invalid " 2349 1.1 bouyer "opcode %x\n", DEVNAME(sc), bb->bb_status); 2350 1.1 bouyer goto done; 2351 1.1 bouyer } 2352 1.1 bouyer 2353 1.1 bouyer 2354 1.74 msaitoh if (mfi_mgmt_internal(sc, cmd, MFI_DATA_NONE, 0, NULL, &mbox, false)) 2355 1.1 bouyer goto done; 2356 1.1 bouyer 2357 1.1 bouyer rv = 0; 2358 1.1 bouyer done: 2359 1.1 bouyer free(pd, M_DEVBUF); 2360 1.13 xtraeme return rv; 2361 1.1 bouyer } 2362 1.1 bouyer 2363 1.13 xtraeme static int 2364 1.1 bouyer mfi_ioctl_setstate(struct mfi_softc *sc, struct bioc_setstate *bs) 2365 1.1 bouyer { 2366 1.1 bouyer struct mfi_pd_list *pd; 2367 1.1 bouyer int i, found, rv = EINVAL; 2368 1.74 msaitoh union mfi_mbox mbox; 2369 1.1 bouyer 2370 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_setstate %x\n", DEVNAME(sc), 2371 1.1 bouyer bs->bs_status); 2372 1.1 bouyer 2373 1.76 msaitoh pd = malloc(sizeof(*pd), M_DEVBUF, M_WAITOK); 2374 1.1 bouyer 2375 1.19 bouyer if (mfi_mgmt_internal(sc, MR_DCMD_PD_GET_LIST, MFI_DATA_IN, 2376 1.76 msaitoh sizeof(*pd), pd, NULL, false)) 2377 1.1 bouyer goto done; 2378 1.1 bouyer 2379 1.1 bouyer for (i = 0, found = 0; i < pd->mpl_no_pd; i++) 2380 1.1 bouyer if (bs->bs_channel == pd->mpl_address[i].mpa_enc_index && 2381 1.1 bouyer bs->bs_target == pd->mpl_address[i].mpa_enc_slot) { 2382 1.73 msaitoh found = 1; 2383 1.1 bouyer break; 2384 1.1 bouyer } 2385 1.1 bouyer 2386 1.1 bouyer if (!found) 2387 1.1 bouyer goto done; 2388 1.1 bouyer 2389 1.74 msaitoh memset(&mbox, 0, sizeof(mbox)); 2390 1.74 msaitoh mbox.s[0] = pd->mpl_address[i].mpa_pd_id; 2391 1.1 bouyer 2392 1.1 bouyer switch (bs->bs_status) { 2393 1.1 bouyer case BIOC_SSONLINE: 2394 1.74 msaitoh mbox.b[4] = MFI_PD_ONLINE; 2395 1.1 bouyer break; 2396 1.1 bouyer 2397 1.1 bouyer case BIOC_SSOFFLINE: 2398 1.74 msaitoh mbox.b[4] = MFI_PD_OFFLINE; 2399 1.1 bouyer break; 2400 1.1 bouyer 2401 1.1 bouyer case BIOC_SSHOTSPARE: 2402 1.74 msaitoh mbox.b[4] = MFI_PD_HOTSPARE; 2403 1.1 bouyer break; 2404 1.1 bouyer /* 2405 1.1 bouyer case BIOC_SSREBUILD: 2406 1.1 bouyer break; 2407 1.1 bouyer */ 2408 1.1 bouyer default: 2409 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_setstate invalid " 2410 1.1 bouyer "opcode %x\n", DEVNAME(sc), bs->bs_status); 2411 1.1 bouyer goto done; 2412 1.1 bouyer } 2413 1.1 bouyer 2414 1.1 bouyer 2415 1.60 bouyer if (mfi_mgmt_internal(sc, MR_DCMD_PD_SET_STATE, MFI_DATA_NONE, 2416 1.74 msaitoh 0, NULL, &mbox, false)) 2417 1.1 bouyer goto done; 2418 1.1 bouyer 2419 1.1 bouyer rv = 0; 2420 1.1 bouyer done: 2421 1.1 bouyer free(pd, M_DEVBUF); 2422 1.13 xtraeme return rv; 2423 1.1 bouyer } 2424 1.1 bouyer 2425 1.13 xtraeme static int 2426 1.1 bouyer mfi_bio_hs(struct mfi_softc *sc, int volid, int type, void *bio_hs) 2427 1.1 bouyer { 2428 1.1 bouyer struct mfi_conf *cfg; 2429 1.1 bouyer struct mfi_hotspare *hs; 2430 1.1 bouyer struct mfi_pd_details *pd; 2431 1.1 bouyer struct bioc_disk *sdhs; 2432 1.1 bouyer struct bioc_vol *vdhs; 2433 1.4 bouyer struct scsipi_inquiry_data *inqbuf; 2434 1.1 bouyer char vend[8+16+4+1]; 2435 1.1 bouyer int i, rv = EINVAL; 2436 1.1 bouyer uint32_t size; 2437 1.74 msaitoh union mfi_mbox mbox; 2438 1.1 bouyer 2439 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs %d\n", DEVNAME(sc), volid); 2440 1.1 bouyer 2441 1.1 bouyer if (!bio_hs) 2442 1.13 xtraeme return EINVAL; 2443 1.1 bouyer 2444 1.4 bouyer pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK | M_ZERO); 2445 1.1 bouyer 2446 1.1 bouyer /* send single element command to retrieve size for full structure */ 2447 1.1 bouyer cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK); 2448 1.60 bouyer if (mfi_mgmt_internal(sc, MR_DCMD_CONF_GET, MFI_DATA_IN, 2449 1.45 bouyer sizeof *cfg, cfg, NULL, false)) 2450 1.1 bouyer goto freeme; 2451 1.1 bouyer 2452 1.1 bouyer size = cfg->mfc_size; 2453 1.1 bouyer free(cfg, M_DEVBUF); 2454 1.1 bouyer 2455 1.1 bouyer /* memory for read config */ 2456 1.13 xtraeme cfg = malloc(size, M_DEVBUF, M_WAITOK|M_ZERO); 2457 1.60 bouyer if (mfi_mgmt_internal(sc, MR_DCMD_CONF_GET, MFI_DATA_IN, 2458 1.45 bouyer size, cfg, NULL, false)) 2459 1.1 bouyer goto freeme; 2460 1.1 bouyer 2461 1.1 bouyer /* calculate offset to hs structure */ 2462 1.1 bouyer hs = (struct mfi_hotspare *)( 2463 1.1 bouyer ((uint8_t *)cfg) + offsetof(struct mfi_conf, mfc_array) + 2464 1.1 bouyer cfg->mfc_array_size * cfg->mfc_no_array + 2465 1.1 bouyer cfg->mfc_ld_size * cfg->mfc_no_ld); 2466 1.1 bouyer 2467 1.1 bouyer if (volid < cfg->mfc_no_ld) 2468 1.1 bouyer goto freeme; /* not a hotspare */ 2469 1.1 bouyer 2470 1.1 bouyer if (volid > (cfg->mfc_no_ld + cfg->mfc_no_hs)) 2471 1.1 bouyer goto freeme; /* not a hotspare */ 2472 1.1 bouyer 2473 1.1 bouyer /* offset into hotspare structure */ 2474 1.1 bouyer i = volid - cfg->mfc_no_ld; 2475 1.1 bouyer 2476 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs i %d volid %d no_ld %d no_hs %d " 2477 1.1 bouyer "hs %p cfg %p id %02x\n", DEVNAME(sc), i, volid, cfg->mfc_no_ld, 2478 1.1 bouyer cfg->mfc_no_hs, hs, cfg, hs[i].mhs_pd.mfp_id); 2479 1.1 bouyer 2480 1.1 bouyer /* get pd fields */ 2481 1.74 msaitoh memset(&mbox, 0, sizeof(mbox)); 2482 1.74 msaitoh mbox.s[0] = hs[i].mhs_pd.mfp_id; 2483 1.19 bouyer if (mfi_mgmt_internal(sc, MR_DCMD_PD_GET_INFO, MFI_DATA_IN, 2484 1.74 msaitoh sizeof *pd, pd, &mbox, false)) { 2485 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs illegal PD\n", 2486 1.1 bouyer DEVNAME(sc)); 2487 1.1 bouyer goto freeme; 2488 1.1 bouyer } 2489 1.1 bouyer 2490 1.1 bouyer switch (type) { 2491 1.1 bouyer case MFI_MGMT_VD: 2492 1.1 bouyer vdhs = bio_hs; 2493 1.1 bouyer vdhs->bv_status = BIOC_SVONLINE; 2494 1.14 xtraeme vdhs->bv_size = pd->mpd_size * 512; /* bytes per block */ 2495 1.1 bouyer vdhs->bv_level = -1; /* hotspare */ 2496 1.1 bouyer vdhs->bv_nodisk = 1; 2497 1.1 bouyer break; 2498 1.1 bouyer 2499 1.1 bouyer case MFI_MGMT_SD: 2500 1.1 bouyer sdhs = bio_hs; 2501 1.1 bouyer sdhs->bd_status = BIOC_SDHOTSPARE; 2502 1.14 xtraeme sdhs->bd_size = pd->mpd_size * 512; /* bytes per block */ 2503 1.1 bouyer sdhs->bd_channel = pd->mpd_enc_idx; 2504 1.1 bouyer sdhs->bd_target = pd->mpd_enc_slot; 2505 1.4 bouyer inqbuf = (struct scsipi_inquiry_data *)&pd->mpd_inq_data; 2506 1.4 bouyer memcpy(vend, inqbuf->vendor, sizeof(vend) - 1); 2507 1.1 bouyer vend[sizeof vend - 1] = '\0'; 2508 1.1 bouyer strlcpy(sdhs->bd_vendor, vend, sizeof(sdhs->bd_vendor)); 2509 1.1 bouyer break; 2510 1.1 bouyer 2511 1.1 bouyer default: 2512 1.1 bouyer goto freeme; 2513 1.1 bouyer } 2514 1.1 bouyer 2515 1.1 bouyer DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs 6\n", DEVNAME(sc)); 2516 1.1 bouyer rv = 0; 2517 1.1 bouyer freeme: 2518 1.1 bouyer free(pd, M_DEVBUF); 2519 1.1 bouyer free(cfg, M_DEVBUF); 2520 1.1 bouyer 2521 1.13 xtraeme return rv; 2522 1.1 bouyer } 2523 1.1 bouyer 2524 1.13 xtraeme static int 2525 1.24 dyoung mfi_destroy_sensors(struct mfi_softc *sc) 2526 1.24 dyoung { 2527 1.27 dyoung if (sc->sc_sme == NULL) 2528 1.27 dyoung return 0; 2529 1.24 dyoung sysmon_envsys_unregister(sc->sc_sme); 2530 1.27 dyoung sc->sc_sme = NULL; 2531 1.24 dyoung free(sc->sc_sensor, M_DEVBUF); 2532 1.24 dyoung return 0; 2533 1.24 dyoung } 2534 1.24 dyoung 2535 1.24 dyoung static int 2536 1.1 bouyer mfi_create_sensors(struct mfi_softc *sc) 2537 1.1 bouyer { 2538 1.13 xtraeme int i; 2539 1.45 bouyer int nsensors = sc->sc_ld_cnt + 1; 2540 1.32 msaitoh int rv; 2541 1.1 bouyer 2542 1.11 xtraeme sc->sc_sme = sysmon_envsys_create(); 2543 1.11 xtraeme sc->sc_sensor = malloc(sizeof(envsys_data_t) * nsensors, 2544 1.62 chs M_DEVBUF, M_WAITOK | M_ZERO); 2545 1.6 xtraeme 2546 1.45 bouyer /* BBU */ 2547 1.45 bouyer sc->sc_sensor[0].units = ENVSYS_INDICATOR; 2548 1.45 bouyer sc->sc_sensor[0].state = ENVSYS_SINVALID; 2549 1.45 bouyer sc->sc_sensor[0].value_cur = 0; 2550 1.45 bouyer /* Enable monitoring for BBU state changes, if present */ 2551 1.45 bouyer if (sc->sc_info.mci_hw_present & MFI_INFO_HW_BBU) 2552 1.45 bouyer sc->sc_sensor[0].flags |= ENVSYS_FMONCRITICAL; 2553 1.45 bouyer snprintf(sc->sc_sensor[0].desc, 2554 1.45 bouyer sizeof(sc->sc_sensor[0].desc), "%s BBU", DEVNAME(sc)); 2555 1.45 bouyer if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[0])) 2556 1.45 bouyer goto out; 2557 1.45 bouyer 2558 1.45 bouyer for (i = 1; i < nsensors; i++) { 2559 1.11 xtraeme sc->sc_sensor[i].units = ENVSYS_DRIVE; 2560 1.35 pgoyette sc->sc_sensor[i].state = ENVSYS_SINVALID; 2561 1.36 pgoyette sc->sc_sensor[i].value_cur = ENVSYS_DRIVE_EMPTY; 2562 1.6 xtraeme /* Enable monitoring for drive state changes */ 2563 1.11 xtraeme sc->sc_sensor[i].flags |= ENVSYS_FMONSTCHANGED; 2564 1.4 bouyer /* logical drives */ 2565 1.11 xtraeme snprintf(sc->sc_sensor[i].desc, 2566 1.11 xtraeme sizeof(sc->sc_sensor[i].desc), "%s:%d", 2567 1.45 bouyer DEVNAME(sc), i - 1); 2568 1.11 xtraeme if (sysmon_envsys_sensor_attach(sc->sc_sme, 2569 1.11 xtraeme &sc->sc_sensor[i])) 2570 1.11 xtraeme goto out; 2571 1.4 bouyer } 2572 1.6 xtraeme 2573 1.11 xtraeme sc->sc_sme->sme_name = DEVNAME(sc); 2574 1.11 xtraeme sc->sc_sme->sme_cookie = sc; 2575 1.11 xtraeme sc->sc_sme->sme_refresh = mfi_sensor_refresh; 2576 1.32 msaitoh rv = sysmon_envsys_register(sc->sc_sme); 2577 1.32 msaitoh if (rv != 0) { 2578 1.43 bouyer aprint_error_dev(sc->sc_dev, 2579 1.43 bouyer "unable to register with sysmon (rv = %d)\n", rv); 2580 1.11 xtraeme goto out; 2581 1.1 bouyer } 2582 1.13 xtraeme return 0; 2583 1.11 xtraeme 2584 1.11 xtraeme out: 2585 1.11 xtraeme free(sc->sc_sensor, M_DEVBUF); 2586 1.11 xtraeme sysmon_envsys_destroy(sc->sc_sme); 2587 1.32 msaitoh sc->sc_sme = NULL; 2588 1.11 xtraeme return EINVAL; 2589 1.1 bouyer } 2590 1.1 bouyer 2591 1.13 xtraeme static void 2592 1.11 xtraeme mfi_sensor_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 2593 1.1 bouyer { 2594 1.4 bouyer struct mfi_softc *sc = sme->sme_cookie; 2595 1.1 bouyer struct bioc_vol bv; 2596 1.4 bouyer int s; 2597 1.28 bouyer int error; 2598 1.1 bouyer 2599 1.45 bouyer if (edata->sensor >= sc->sc_ld_cnt + 1) 2600 1.45 bouyer return; 2601 1.45 bouyer 2602 1.45 bouyer if (edata->sensor == 0) { 2603 1.45 bouyer /* BBU */ 2604 1.45 bouyer struct mfi_bbu_status bbu_stat; 2605 1.45 bouyer int bbu_status; 2606 1.45 bouyer if ((sc->sc_info.mci_hw_present & MFI_INFO_HW_BBU) == 0) 2607 1.45 bouyer return; 2608 1.45 bouyer 2609 1.45 bouyer KERNEL_LOCK(1, curlwp); 2610 1.45 bouyer s = splbio(); 2611 1.45 bouyer bbu_status = mfi_get_bbu(sc, &bbu_stat); 2612 1.45 bouyer splx(s); 2613 1.45 bouyer KERNEL_UNLOCK_ONE(curlwp); 2614 1.73 msaitoh switch (bbu_status) { 2615 1.45 bouyer case MFI_BBU_GOOD: 2616 1.45 bouyer edata->value_cur = 1; 2617 1.45 bouyer edata->state = ENVSYS_SVALID; 2618 1.46 bouyer if (!sc->sc_bbuok) 2619 1.46 bouyer aprint_normal_dev(sc->sc_dev, 2620 1.46 bouyer "BBU state changed to good\n"); 2621 1.45 bouyer sc->sc_bbuok = true; 2622 1.45 bouyer break; 2623 1.45 bouyer case MFI_BBU_BAD: 2624 1.45 bouyer edata->value_cur = 0; 2625 1.45 bouyer edata->state = ENVSYS_SCRITICAL; 2626 1.46 bouyer if (sc->sc_bbuok) 2627 1.46 bouyer aprint_normal_dev(sc->sc_dev, 2628 1.46 bouyer "BBU state changed to bad\n"); 2629 1.45 bouyer sc->sc_bbuok = false; 2630 1.45 bouyer break; 2631 1.45 bouyer case MFI_BBU_UNKNOWN: 2632 1.45 bouyer default: 2633 1.45 bouyer edata->value_cur = 0; 2634 1.45 bouyer edata->state = ENVSYS_SINVALID; 2635 1.45 bouyer sc->sc_bbuok = false; 2636 1.45 bouyer break; 2637 1.45 bouyer } 2638 1.11 xtraeme return; 2639 1.45 bouyer } 2640 1.1 bouyer 2641 1.22 cegger memset(&bv, 0, sizeof(bv)); 2642 1.45 bouyer bv.bv_volid = edata->sensor - 1; 2643 1.28 bouyer KERNEL_LOCK(1, curlwp); 2644 1.4 bouyer s = splbio(); 2645 1.28 bouyer error = mfi_ioctl_vol(sc, &bv); 2646 1.4 bouyer splx(s); 2647 1.28 bouyer KERNEL_UNLOCK_ONE(curlwp); 2648 1.28 bouyer if (error) 2649 1.56 christos bv.bv_status = BIOC_SVINVALID; 2650 1.1 bouyer 2651 1.56 christos bio_vol_to_envsys(edata, &bv); 2652 1.4 bouyer } 2653 1.4 bouyer 2654 1.1 bouyer #endif /* NBIO > 0 */ 2655 1.12 xtraeme 2656 1.13 xtraeme static uint32_t 2657 1.12 xtraeme mfi_xscale_fw_state(struct mfi_softc *sc) 2658 1.12 xtraeme { 2659 1.12 xtraeme return mfi_read(sc, MFI_OMSG0); 2660 1.12 xtraeme } 2661 1.30 dyoung 2662 1.13 xtraeme static void 2663 1.24 dyoung mfi_xscale_intr_dis(struct mfi_softc *sc) 2664 1.24 dyoung { 2665 1.24 dyoung mfi_write(sc, MFI_OMSK, 0); 2666 1.24 dyoung } 2667 1.24 dyoung 2668 1.24 dyoung static void 2669 1.12 xtraeme mfi_xscale_intr_ena(struct mfi_softc *sc) 2670 1.12 xtraeme { 2671 1.12 xtraeme mfi_write(sc, MFI_OMSK, MFI_ENABLE_INTR); 2672 1.12 xtraeme } 2673 1.30 dyoung 2674 1.13 xtraeme static int 2675 1.12 xtraeme mfi_xscale_intr(struct mfi_softc *sc) 2676 1.12 xtraeme { 2677 1.12 xtraeme uint32_t status; 2678 1.12 xtraeme 2679 1.12 xtraeme status = mfi_read(sc, MFI_OSTS); 2680 1.12 xtraeme if (!ISSET(status, MFI_OSTS_INTR_VALID)) 2681 1.12 xtraeme return 0; 2682 1.12 xtraeme 2683 1.12 xtraeme /* write status back to acknowledge interrupt */ 2684 1.12 xtraeme mfi_write(sc, MFI_OSTS, status); 2685 1.12 xtraeme return 1; 2686 1.12 xtraeme } 2687 1.30 dyoung 2688 1.13 xtraeme static void 2689 1.12 xtraeme mfi_xscale_post(struct mfi_softc *sc, struct mfi_ccb *ccb) 2690 1.12 xtraeme { 2691 1.14 xtraeme bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_frames), 2692 1.14 xtraeme ccb->ccb_pframe - MFIMEM_DVA(sc->sc_frames), 2693 1.14 xtraeme sc->sc_frames_size, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2694 1.14 xtraeme bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_sense), 2695 1.14 xtraeme ccb->ccb_psense - MFIMEM_DVA(sc->sc_sense), 2696 1.14 xtraeme MFI_SENSE_SIZE, BUS_DMASYNC_PREREAD); 2697 1.14 xtraeme 2698 1.12 xtraeme mfi_write(sc, MFI_IQP, (ccb->ccb_pframe >> 3) | 2699 1.12 xtraeme ccb->ccb_extra_frames); 2700 1.43 bouyer ccb->ccb_state = MFI_CCB_RUNNING; 2701 1.12 xtraeme } 2702 1.30 dyoung 2703 1.13 xtraeme static uint32_t 2704 1.12 xtraeme mfi_ppc_fw_state(struct mfi_softc *sc) 2705 1.12 xtraeme { 2706 1.12 xtraeme return mfi_read(sc, MFI_OSP); 2707 1.12 xtraeme } 2708 1.30 dyoung 2709 1.13 xtraeme static void 2710 1.24 dyoung mfi_ppc_intr_dis(struct mfi_softc *sc) 2711 1.24 dyoung { 2712 1.24 dyoung /* Taking a wild guess --dyoung */ 2713 1.24 dyoung mfi_write(sc, MFI_OMSK, ~(uint32_t)0x0); 2714 1.24 dyoung mfi_write(sc, MFI_ODC, 0xffffffff); 2715 1.24 dyoung } 2716 1.24 dyoung 2717 1.24 dyoung static void 2718 1.12 xtraeme mfi_ppc_intr_ena(struct mfi_softc *sc) 2719 1.12 xtraeme { 2720 1.12 xtraeme mfi_write(sc, MFI_ODC, 0xffffffff); 2721 1.12 xtraeme mfi_write(sc, MFI_OMSK, ~0x80000004); 2722 1.12 xtraeme } 2723 1.30 dyoung 2724 1.13 xtraeme static int 2725 1.12 xtraeme mfi_ppc_intr(struct mfi_softc *sc) 2726 1.12 xtraeme { 2727 1.12 xtraeme uint32_t status; 2728 1.30 dyoung 2729 1.12 xtraeme status = mfi_read(sc, MFI_OSTS); 2730 1.12 xtraeme if (!ISSET(status, MFI_OSTS_PPC_INTR_VALID)) 2731 1.12 xtraeme return 0; 2732 1.30 dyoung 2733 1.12 xtraeme /* write status back to acknowledge interrupt */ 2734 1.12 xtraeme mfi_write(sc, MFI_ODC, status); 2735 1.12 xtraeme return 1; 2736 1.12 xtraeme } 2737 1.30 dyoung 2738 1.13 xtraeme static void 2739 1.12 xtraeme mfi_ppc_post(struct mfi_softc *sc, struct mfi_ccb *ccb) 2740 1.12 xtraeme { 2741 1.12 xtraeme mfi_write(sc, MFI_IQP, 0x1 | ccb->ccb_pframe | 2742 1.12 xtraeme (ccb->ccb_extra_frames << 1)); 2743 1.43 bouyer ccb->ccb_state = MFI_CCB_RUNNING; 2744 1.12 xtraeme } 2745 1.33 msaitoh 2746 1.33 msaitoh u_int32_t 2747 1.33 msaitoh mfi_gen2_fw_state(struct mfi_softc *sc) 2748 1.33 msaitoh { 2749 1.33 msaitoh return (mfi_read(sc, MFI_OSP)); 2750 1.33 msaitoh } 2751 1.33 msaitoh 2752 1.33 msaitoh void 2753 1.33 msaitoh mfi_gen2_intr_dis(struct mfi_softc *sc) 2754 1.33 msaitoh { 2755 1.33 msaitoh mfi_write(sc, MFI_OMSK, 0xffffffff); 2756 1.33 msaitoh mfi_write(sc, MFI_ODC, 0xffffffff); 2757 1.33 msaitoh } 2758 1.33 msaitoh 2759 1.33 msaitoh void 2760 1.33 msaitoh mfi_gen2_intr_ena(struct mfi_softc *sc) 2761 1.33 msaitoh { 2762 1.33 msaitoh mfi_write(sc, MFI_ODC, 0xffffffff); 2763 1.33 msaitoh mfi_write(sc, MFI_OMSK, ~MFI_OSTS_GEN2_INTR_VALID); 2764 1.33 msaitoh } 2765 1.33 msaitoh 2766 1.33 msaitoh int 2767 1.33 msaitoh mfi_gen2_intr(struct mfi_softc *sc) 2768 1.33 msaitoh { 2769 1.33 msaitoh u_int32_t status; 2770 1.33 msaitoh 2771 1.33 msaitoh status = mfi_read(sc, MFI_OSTS); 2772 1.33 msaitoh if (!ISSET(status, MFI_OSTS_GEN2_INTR_VALID)) 2773 1.33 msaitoh return (0); 2774 1.33 msaitoh 2775 1.33 msaitoh /* write status back to acknowledge interrupt */ 2776 1.33 msaitoh mfi_write(sc, MFI_ODC, status); 2777 1.33 msaitoh 2778 1.33 msaitoh return (1); 2779 1.33 msaitoh } 2780 1.33 msaitoh 2781 1.33 msaitoh void 2782 1.33 msaitoh mfi_gen2_post(struct mfi_softc *sc, struct mfi_ccb *ccb) 2783 1.33 msaitoh { 2784 1.33 msaitoh mfi_write(sc, MFI_IQP, 0x1 | ccb->ccb_pframe | 2785 1.33 msaitoh (ccb->ccb_extra_frames << 1)); 2786 1.43 bouyer ccb->ccb_state = MFI_CCB_RUNNING; 2787 1.33 msaitoh } 2788 1.38 sborrill 2789 1.38 sborrill u_int32_t 2790 1.38 sborrill mfi_skinny_fw_state(struct mfi_softc *sc) 2791 1.38 sborrill { 2792 1.38 sborrill return (mfi_read(sc, MFI_OSP)); 2793 1.38 sborrill } 2794 1.38 sborrill 2795 1.38 sborrill void 2796 1.38 sborrill mfi_skinny_intr_dis(struct mfi_softc *sc) 2797 1.38 sborrill { 2798 1.38 sborrill mfi_write(sc, MFI_OMSK, 0); 2799 1.38 sborrill } 2800 1.38 sborrill 2801 1.38 sborrill void 2802 1.38 sborrill mfi_skinny_intr_ena(struct mfi_softc *sc) 2803 1.38 sborrill { 2804 1.38 sborrill mfi_write(sc, MFI_OMSK, ~0x00000001); 2805 1.38 sborrill } 2806 1.38 sborrill 2807 1.38 sborrill int 2808 1.38 sborrill mfi_skinny_intr(struct mfi_softc *sc) 2809 1.38 sborrill { 2810 1.38 sborrill u_int32_t status; 2811 1.38 sborrill 2812 1.38 sborrill status = mfi_read(sc, MFI_OSTS); 2813 1.38 sborrill if (!ISSET(status, MFI_OSTS_SKINNY_INTR_VALID)) 2814 1.38 sborrill return (0); 2815 1.38 sborrill 2816 1.38 sborrill /* write status back to acknowledge interrupt */ 2817 1.38 sborrill mfi_write(sc, MFI_OSTS, status); 2818 1.38 sborrill 2819 1.38 sborrill return (1); 2820 1.38 sborrill } 2821 1.38 sborrill 2822 1.38 sborrill void 2823 1.38 sborrill mfi_skinny_post(struct mfi_softc *sc, struct mfi_ccb *ccb) 2824 1.38 sborrill { 2825 1.38 sborrill mfi_write(sc, MFI_IQPL, 0x1 | ccb->ccb_pframe | 2826 1.38 sborrill (ccb->ccb_extra_frames << 1)); 2827 1.38 sborrill mfi_write(sc, MFI_IQPH, 0x00000000); 2828 1.43 bouyer ccb->ccb_state = MFI_CCB_RUNNING; 2829 1.43 bouyer } 2830 1.43 bouyer 2831 1.43 bouyer #define MFI_FUSION_ENABLE_INTERRUPT_MASK (0x00000008) 2832 1.43 bouyer 2833 1.43 bouyer void 2834 1.43 bouyer mfi_tbolt_intr_ena(struct mfi_softc *sc) 2835 1.43 bouyer { 2836 1.43 bouyer mfi_write(sc, MFI_OMSK, ~MFI_FUSION_ENABLE_INTERRUPT_MASK); 2837 1.43 bouyer mfi_read(sc, MFI_OMSK); 2838 1.43 bouyer } 2839 1.43 bouyer 2840 1.43 bouyer void 2841 1.43 bouyer mfi_tbolt_intr_dis(struct mfi_softc *sc) 2842 1.43 bouyer { 2843 1.43 bouyer mfi_write(sc, MFI_OMSK, 0xFFFFFFFF); 2844 1.43 bouyer mfi_read(sc, MFI_OMSK); 2845 1.43 bouyer } 2846 1.43 bouyer 2847 1.43 bouyer int 2848 1.43 bouyer mfi_tbolt_intr(struct mfi_softc *sc) 2849 1.43 bouyer { 2850 1.43 bouyer int32_t status; 2851 1.43 bouyer 2852 1.43 bouyer status = mfi_read(sc, MFI_OSTS); 2853 1.43 bouyer 2854 1.43 bouyer if (ISSET(status, 0x1)) { 2855 1.43 bouyer mfi_write(sc, MFI_OSTS, status); 2856 1.43 bouyer mfi_read(sc, MFI_OSTS); 2857 1.43 bouyer if (ISSET(status, MFI_STATE_CHANGE_INTERRUPT)) 2858 1.43 bouyer return 0; 2859 1.43 bouyer return 1; 2860 1.43 bouyer } 2861 1.43 bouyer if (!ISSET(status, MFI_FUSION_ENABLE_INTERRUPT_MASK)) 2862 1.43 bouyer return 0; 2863 1.43 bouyer mfi_read(sc, MFI_OSTS); 2864 1.43 bouyer return 1; 2865 1.43 bouyer } 2866 1.43 bouyer 2867 1.43 bouyer u_int32_t 2868 1.43 bouyer mfi_tbolt_fw_state(struct mfi_softc *sc) 2869 1.43 bouyer { 2870 1.43 bouyer return mfi_read(sc, MFI_OSP); 2871 1.43 bouyer } 2872 1.43 bouyer 2873 1.43 bouyer void 2874 1.43 bouyer mfi_tbolt_post(struct mfi_softc *sc, struct mfi_ccb *ccb) 2875 1.43 bouyer { 2876 1.43 bouyer if (sc->sc_MFA_enabled) { 2877 1.43 bouyer if ((ccb->ccb_flags & MFI_CCB_F_TBOLT) == 0) 2878 1.43 bouyer mfi_tbolt_build_mpt_ccb(ccb); 2879 1.43 bouyer mfi_write(sc, MFI_IQPL, 2880 1.43 bouyer ccb->ccb_tb_request_desc.words & 0xFFFFFFFF); 2881 1.73 msaitoh mfi_write(sc, MFI_IQPH, 2882 1.43 bouyer ccb->ccb_tb_request_desc.words >> 32); 2883 1.43 bouyer ccb->ccb_state = MFI_CCB_RUNNING; 2884 1.43 bouyer return; 2885 1.43 bouyer } 2886 1.43 bouyer uint64_t bus_add = ccb->ccb_pframe; 2887 1.43 bouyer bus_add |= (MFI_REQ_DESCRIPT_FLAGS_MFA 2888 1.43 bouyer << MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 2889 1.43 bouyer mfi_write(sc, MFI_IQPL, bus_add); 2890 1.43 bouyer mfi_write(sc, MFI_IQPH, bus_add >> 32); 2891 1.43 bouyer ccb->ccb_state = MFI_CCB_RUNNING; 2892 1.43 bouyer } 2893 1.43 bouyer 2894 1.43 bouyer static void 2895 1.43 bouyer mfi_tbolt_build_mpt_ccb(struct mfi_ccb *ccb) 2896 1.43 bouyer { 2897 1.43 bouyer union mfi_mpi2_request_descriptor *req_desc = &ccb->ccb_tb_request_desc; 2898 1.43 bouyer struct mfi_mpi2_request_raid_scsi_io *io_req = ccb->ccb_tb_io_request; 2899 1.43 bouyer struct mpi25_ieee_sge_chain64 *mpi25_ieee_chain; 2900 1.43 bouyer 2901 1.43 bouyer io_req->Function = MPI2_FUNCTION_PASSTHRU_IO_REQUEST; 2902 1.43 bouyer io_req->SGLOffset0 = 2903 1.43 bouyer offsetof(struct mfi_mpi2_request_raid_scsi_io, SGL) / 4; 2904 1.43 bouyer io_req->ChainOffset = 2905 1.43 bouyer offsetof(struct mfi_mpi2_request_raid_scsi_io, SGL) / 16; 2906 1.43 bouyer 2907 1.43 bouyer mpi25_ieee_chain = 2908 1.43 bouyer (struct mpi25_ieee_sge_chain64 *)&io_req->SGL.IeeeChain; 2909 1.43 bouyer mpi25_ieee_chain->Address = ccb->ccb_pframe; 2910 1.43 bouyer 2911 1.43 bouyer /* 2912 1.43 bouyer In MFI pass thru, nextChainOffset will always be zero to 2913 1.43 bouyer indicate the end of the chain. 2914 1.43 bouyer */ 2915 1.43 bouyer mpi25_ieee_chain->Flags= MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT 2916 1.43 bouyer | MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR; 2917 1.43 bouyer 2918 1.43 bouyer /* setting the length to the maximum length */ 2919 1.43 bouyer mpi25_ieee_chain->Length = 1024; 2920 1.43 bouyer 2921 1.43 bouyer req_desc->header.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << 2922 1.43 bouyer MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 2923 1.43 bouyer ccb->ccb_flags |= MFI_CCB_F_TBOLT; 2924 1.43 bouyer bus_dmamap_sync(ccb->ccb_sc->sc_dmat, 2925 1.73 msaitoh MFIMEM_MAP(ccb->ccb_sc->sc_tbolt_reqmsgpool), 2926 1.43 bouyer ccb->ccb_tb_pio_request - 2927 1.43 bouyer MFIMEM_DVA(ccb->ccb_sc->sc_tbolt_reqmsgpool), 2928 1.43 bouyer MEGASAS_THUNDERBOLT_NEW_MSG_SIZE, 2929 1.43 bouyer BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2930 1.43 bouyer } 2931 1.43 bouyer 2932 1.43 bouyer /* 2933 1.43 bouyer * Description: 2934 1.43 bouyer * This function will prepare message pools for the Thunderbolt controller 2935 1.43 bouyer */ 2936 1.43 bouyer static int 2937 1.43 bouyer mfi_tbolt_init_desc_pool(struct mfi_softc *sc) 2938 1.43 bouyer { 2939 1.43 bouyer uint32_t offset = 0; 2940 1.43 bouyer uint8_t *addr = MFIMEM_KVA(sc->sc_tbolt_reqmsgpool); 2941 1.43 bouyer 2942 1.67 msaitoh /* Request Descriptors alignment restrictions */ 2943 1.43 bouyer KASSERT(((uintptr_t)addr & 0xFF) == 0); 2944 1.43 bouyer 2945 1.43 bouyer /* Skip request message pool */ 2946 1.43 bouyer addr = &addr[MEGASAS_THUNDERBOLT_NEW_MSG_SIZE * (sc->sc_max_cmds + 1)]; 2947 1.43 bouyer 2948 1.43 bouyer /* Reply Frame Pool is initialized */ 2949 1.43 bouyer sc->sc_reply_frame_pool = (struct mfi_mpi2_reply_header *) addr; 2950 1.43 bouyer KASSERT(((uintptr_t)addr & 0xFF) == 0); 2951 1.43 bouyer 2952 1.43 bouyer offset = (uintptr_t)sc->sc_reply_frame_pool 2953 1.43 bouyer - (uintptr_t)MFIMEM_KVA(sc->sc_tbolt_reqmsgpool); 2954 1.43 bouyer sc->sc_reply_frame_busaddr = 2955 1.43 bouyer MFIMEM_DVA(sc->sc_tbolt_reqmsgpool) + offset; 2956 1.43 bouyer 2957 1.43 bouyer /* initializing reply address to 0xFFFFFFFF */ 2958 1.43 bouyer memset((uint8_t *)sc->sc_reply_frame_pool, 0xFF, 2959 1.43 bouyer (MEGASAS_THUNDERBOLT_REPLY_SIZE * sc->sc_reply_pool_size)); 2960 1.43 bouyer 2961 1.43 bouyer /* Skip Reply Frame Pool */ 2962 1.43 bouyer addr += MEGASAS_THUNDERBOLT_REPLY_SIZE * sc->sc_reply_pool_size; 2963 1.43 bouyer sc->sc_reply_pool_limit = (void *)addr; 2964 1.43 bouyer 2965 1.43 bouyer offset = MEGASAS_THUNDERBOLT_REPLY_SIZE * sc->sc_reply_pool_size; 2966 1.43 bouyer sc->sc_sg_frame_busaddr = sc->sc_reply_frame_busaddr + offset; 2967 1.43 bouyer 2968 1.43 bouyer /* initialize the last_reply_idx to 0 */ 2969 1.43 bouyer sc->sc_last_reply_idx = 0; 2970 1.43 bouyer offset = (sc->sc_sg_frame_busaddr + (MEGASAS_MAX_SZ_CHAIN_FRAME * 2971 1.43 bouyer sc->sc_max_cmds)) - MFIMEM_DVA(sc->sc_tbolt_reqmsgpool); 2972 1.44 bouyer KASSERT(offset <= sc->sc_tbolt_reqmsgpool->am_size); 2973 1.43 bouyer bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_tbolt_reqmsgpool), 0, 2974 1.43 bouyer MFIMEM_MAP(sc->sc_tbolt_reqmsgpool)->dm_mapsize, 2975 1.43 bouyer BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2976 1.43 bouyer return 0; 2977 1.43 bouyer } 2978 1.43 bouyer 2979 1.43 bouyer /* 2980 1.43 bouyer * This routine prepare and issue INIT2 frame to the Firmware 2981 1.43 bouyer */ 2982 1.43 bouyer 2983 1.43 bouyer static int 2984 1.43 bouyer mfi_tbolt_init_MFI_queue(struct mfi_softc *sc) 2985 1.43 bouyer { 2986 1.43 bouyer struct mpi2_ioc_init_request *mpi2IocInit; 2987 1.43 bouyer struct mfi_init_frame *mfi_init; 2988 1.43 bouyer struct mfi_ccb *ccb; 2989 1.43 bouyer bus_addr_t phyAddress; 2990 1.43 bouyer mfi_address *mfiAddressTemp; 2991 1.43 bouyer int s; 2992 1.43 bouyer char *verbuf; 2993 1.43 bouyer char wqbuf[10]; 2994 1.43 bouyer 2995 1.43 bouyer /* Check if initialization is already completed */ 2996 1.43 bouyer if (sc->sc_MFA_enabled) { 2997 1.43 bouyer return 1; 2998 1.43 bouyer } 2999 1.43 bouyer 3000 1.43 bouyer mpi2IocInit = 3001 1.43 bouyer (struct mpi2_ioc_init_request *)MFIMEM_KVA(sc->sc_tbolt_ioc_init); 3002 1.43 bouyer 3003 1.43 bouyer s = splbio(); 3004 1.43 bouyer if ((ccb = mfi_get_ccb(sc)) == NULL) { 3005 1.43 bouyer splx(s); 3006 1.43 bouyer return (EBUSY); 3007 1.43 bouyer } 3008 1.43 bouyer 3009 1.43 bouyer 3010 1.43 bouyer mfi_init = &ccb->ccb_frame->mfr_init; 3011 1.43 bouyer 3012 1.43 bouyer memset(mpi2IocInit, 0, sizeof(struct mpi2_ioc_init_request)); 3013 1.43 bouyer mpi2IocInit->Function = MPI2_FUNCTION_IOC_INIT; 3014 1.43 bouyer mpi2IocInit->WhoInit = MPI2_WHOINIT_HOST_DRIVER; 3015 1.43 bouyer 3016 1.43 bouyer /* set MsgVersion and HeaderVersion host driver was built with */ 3017 1.43 bouyer mpi2IocInit->MsgVersion = MPI2_VERSION; 3018 1.43 bouyer mpi2IocInit->HeaderVersion = MPI2_HEADER_VERSION; 3019 1.43 bouyer mpi2IocInit->SystemRequestFrameSize = MEGASAS_THUNDERBOLT_NEW_MSG_SIZE/4; 3020 1.43 bouyer mpi2IocInit->ReplyDescriptorPostQueueDepth = 3021 1.43 bouyer (uint16_t)sc->sc_reply_pool_size; 3022 1.43 bouyer mpi2IocInit->ReplyFreeQueueDepth = 0; /* Not supported by MR. */ 3023 1.43 bouyer 3024 1.43 bouyer /* Get physical address of reply frame pool */ 3025 1.43 bouyer phyAddress = sc->sc_reply_frame_busaddr; 3026 1.43 bouyer mfiAddressTemp = 3027 1.43 bouyer (mfi_address *)&mpi2IocInit->ReplyDescriptorPostQueueAddress; 3028 1.43 bouyer mfiAddressTemp->u.addressLow = (uint32_t)phyAddress; 3029 1.43 bouyer mfiAddressTemp->u.addressHigh = (uint32_t)((uint64_t)phyAddress >> 32); 3030 1.43 bouyer 3031 1.43 bouyer /* Get physical address of request message pool */ 3032 1.43 bouyer phyAddress = MFIMEM_DVA(sc->sc_tbolt_reqmsgpool); 3033 1.43 bouyer mfiAddressTemp = (mfi_address *)&mpi2IocInit->SystemRequestFrameBaseAddress; 3034 1.43 bouyer mfiAddressTemp->u.addressLow = (uint32_t)phyAddress; 3035 1.43 bouyer mfiAddressTemp->u.addressHigh = (uint32_t)((uint64_t)phyAddress >> 32); 3036 1.43 bouyer 3037 1.43 bouyer mpi2IocInit->ReplyFreeQueueAddress = 0; /* Not supported by MR. */ 3038 1.43 bouyer mpi2IocInit->TimeStamp = time_uptime; 3039 1.43 bouyer 3040 1.43 bouyer verbuf = MFIMEM_KVA(sc->sc_tbolt_verbuf); 3041 1.43 bouyer snprintf(verbuf, strlen(MEGASAS_VERSION) + 2, "%s\n", 3042 1.73 msaitoh MEGASAS_VERSION); 3043 1.43 bouyer bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_tbolt_verbuf), 0, 3044 1.43 bouyer MFIMEM_MAP(sc->sc_tbolt_verbuf)->dm_mapsize, BUS_DMASYNC_PREWRITE); 3045 1.43 bouyer mfi_init->driver_ver_lo = htole32(MFIMEM_DVA(sc->sc_tbolt_verbuf)); 3046 1.43 bouyer mfi_init->driver_ver_hi = 3047 1.43 bouyer htole32((uint64_t)MFIMEM_DVA(sc->sc_tbolt_verbuf) >> 32); 3048 1.43 bouyer 3049 1.43 bouyer bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_tbolt_ioc_init), 0, 3050 1.43 bouyer MFIMEM_MAP(sc->sc_tbolt_ioc_init)->dm_mapsize, 3051 1.43 bouyer BUS_DMASYNC_PREWRITE); 3052 1.43 bouyer /* Get the physical address of the mpi2 ioc init command */ 3053 1.43 bouyer phyAddress = MFIMEM_DVA(sc->sc_tbolt_ioc_init); 3054 1.43 bouyer mfi_init->mif_qinfo_new_addr_lo = htole32(phyAddress); 3055 1.43 bouyer mfi_init->mif_qinfo_new_addr_hi = htole32((uint64_t)phyAddress >> 32); 3056 1.43 bouyer 3057 1.43 bouyer mfi_init->mif_header.mfh_cmd = MFI_CMD_INIT; 3058 1.43 bouyer mfi_init->mif_header.mfh_data_len = sizeof(struct mpi2_ioc_init_request); 3059 1.43 bouyer if (mfi_poll(ccb) != 0) { 3060 1.43 bouyer aprint_error_dev(sc->sc_dev, "failed to send IOC init2 " 3061 1.43 bouyer "command at 0x%" PRIx64 "\n", 3062 1.43 bouyer (uint64_t)ccb->ccb_pframe); 3063 1.43 bouyer splx(s); 3064 1.43 bouyer return 1; 3065 1.43 bouyer } 3066 1.43 bouyer bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_tbolt_verbuf), 0, 3067 1.43 bouyer MFIMEM_MAP(sc->sc_tbolt_verbuf)->dm_mapsize, BUS_DMASYNC_POSTWRITE); 3068 1.43 bouyer bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_tbolt_ioc_init), 0, 3069 1.43 bouyer MFIMEM_MAP(sc->sc_tbolt_ioc_init)->dm_mapsize, 3070 1.43 bouyer BUS_DMASYNC_POSTWRITE); 3071 1.43 bouyer mfi_put_ccb(ccb); 3072 1.43 bouyer splx(s); 3073 1.43 bouyer 3074 1.43 bouyer if (mfi_init->mif_header.mfh_cmd_status == 0) { 3075 1.43 bouyer sc->sc_MFA_enabled = 1; 3076 1.43 bouyer } 3077 1.43 bouyer else { 3078 1.43 bouyer aprint_error_dev(sc->sc_dev, "Init command Failed %x\n", 3079 1.43 bouyer mfi_init->mif_header.mfh_cmd_status); 3080 1.43 bouyer return 1; 3081 1.43 bouyer } 3082 1.43 bouyer 3083 1.43 bouyer snprintf(wqbuf, sizeof(wqbuf), "%swq", DEVNAME(sc)); 3084 1.43 bouyer if (workqueue_create(&sc->sc_ldsync_wq, wqbuf, mfi_tbolt_sync_map_info, 3085 1.43 bouyer sc, PRIBIO, IPL_BIO, 0) != 0) { 3086 1.43 bouyer aprint_error_dev(sc->sc_dev, "workqueue_create failed\n"); 3087 1.43 bouyer return 1; 3088 1.43 bouyer } 3089 1.43 bouyer workqueue_enqueue(sc->sc_ldsync_wq, &sc->sc_ldsync_wk, NULL); 3090 1.43 bouyer return 0; 3091 1.43 bouyer } 3092 1.43 bouyer 3093 1.43 bouyer int 3094 1.43 bouyer mfi_tbolt_intrh(void *arg) 3095 1.43 bouyer { 3096 1.43 bouyer struct mfi_softc *sc = arg; 3097 1.43 bouyer struct mfi_ccb *ccb; 3098 1.43 bouyer union mfi_mpi2_reply_descriptor *desc; 3099 1.43 bouyer int smid, num_completed; 3100 1.43 bouyer 3101 1.43 bouyer if (!mfi_tbolt_intr(sc)) 3102 1.43 bouyer return 0; 3103 1.43 bouyer 3104 1.43 bouyer DNPRINTF(MFI_D_INTR, "%s: mfi_tbolt_intrh %#lx %#lx\n", DEVNAME(sc), 3105 1.43 bouyer (u_long)sc, (u_long)sc->sc_last_reply_idx); 3106 1.43 bouyer 3107 1.43 bouyer KASSERT(sc->sc_last_reply_idx < sc->sc_reply_pool_size); 3108 1.43 bouyer 3109 1.43 bouyer desc = (union mfi_mpi2_reply_descriptor *) 3110 1.43 bouyer ((uintptr_t)sc->sc_reply_frame_pool + 3111 1.43 bouyer sc->sc_last_reply_idx * MEGASAS_THUNDERBOLT_REPLY_SIZE); 3112 1.43 bouyer 3113 1.43 bouyer bus_dmamap_sync(sc->sc_dmat, 3114 1.73 msaitoh MFIMEM_MAP(sc->sc_tbolt_reqmsgpool), 3115 1.43 bouyer MEGASAS_THUNDERBOLT_NEW_MSG_SIZE * (sc->sc_max_cmds + 1), 3116 1.43 bouyer MEGASAS_THUNDERBOLT_REPLY_SIZE * sc->sc_reply_pool_size, 3117 1.43 bouyer BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 3118 1.43 bouyer num_completed = 0; 3119 1.43 bouyer while ((desc->header.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK) != 3120 1.43 bouyer MPI2_RPY_DESCRIPT_FLAGS_UNUSED) { 3121 1.43 bouyer smid = desc->header.SMID; 3122 1.43 bouyer KASSERT(smid > 0 && smid <= sc->sc_max_cmds); 3123 1.43 bouyer ccb = &sc->sc_ccb[smid - 1]; 3124 1.43 bouyer DNPRINTF(MFI_D_INTR, 3125 1.43 bouyer "%s: mfi_tbolt_intr SMID %#x reply_idx %#x " 3126 1.43 bouyer "desc %#" PRIx64 " ccb %p\n", DEVNAME(sc), smid, 3127 1.43 bouyer sc->sc_last_reply_idx, desc->words, ccb); 3128 1.43 bouyer KASSERT(ccb->ccb_state == MFI_CCB_RUNNING); 3129 1.43 bouyer if (ccb->ccb_flags & MFI_CCB_F_TBOLT_IO && 3130 1.43 bouyer ccb->ccb_tb_io_request->ChainOffset != 0) { 3131 1.43 bouyer bus_dmamap_sync(sc->sc_dmat, 3132 1.73 msaitoh MFIMEM_MAP(sc->sc_tbolt_reqmsgpool), 3133 1.43 bouyer ccb->ccb_tb_psg_frame - 3134 1.43 bouyer MFIMEM_DVA(sc->sc_tbolt_reqmsgpool), 3135 1.43 bouyer MEGASAS_MAX_SZ_CHAIN_FRAME, BUS_DMASYNC_POSTREAD); 3136 1.43 bouyer } 3137 1.43 bouyer if (ccb->ccb_flags & MFI_CCB_F_TBOLT_IO) { 3138 1.43 bouyer bus_dmamap_sync(sc->sc_dmat, 3139 1.73 msaitoh MFIMEM_MAP(sc->sc_tbolt_reqmsgpool), 3140 1.43 bouyer ccb->ccb_tb_pio_request - 3141 1.43 bouyer MFIMEM_DVA(sc->sc_tbolt_reqmsgpool), 3142 1.43 bouyer MEGASAS_THUNDERBOLT_NEW_MSG_SIZE, 3143 1.43 bouyer BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 3144 1.43 bouyer } 3145 1.43 bouyer if (ccb->ccb_done) 3146 1.43 bouyer ccb->ccb_done(ccb); 3147 1.43 bouyer else 3148 1.43 bouyer ccb->ccb_state = MFI_CCB_DONE; 3149 1.43 bouyer sc->sc_last_reply_idx++; 3150 1.43 bouyer if (sc->sc_last_reply_idx >= sc->sc_reply_pool_size) { 3151 1.43 bouyer sc->sc_last_reply_idx = 0; 3152 1.43 bouyer } 3153 1.43 bouyer desc->words = ~0x0; 3154 1.43 bouyer /* Get the next reply descriptor */ 3155 1.43 bouyer desc = (union mfi_mpi2_reply_descriptor *) 3156 1.43 bouyer ((uintptr_t)sc->sc_reply_frame_pool + 3157 1.43 bouyer sc->sc_last_reply_idx * MEGASAS_THUNDERBOLT_REPLY_SIZE); 3158 1.43 bouyer num_completed++; 3159 1.43 bouyer } 3160 1.43 bouyer if (num_completed == 0) 3161 1.43 bouyer return 0; 3162 1.43 bouyer 3163 1.43 bouyer bus_dmamap_sync(sc->sc_dmat, 3164 1.73 msaitoh MFIMEM_MAP(sc->sc_tbolt_reqmsgpool), 3165 1.43 bouyer MEGASAS_THUNDERBOLT_NEW_MSG_SIZE * (sc->sc_max_cmds + 1), 3166 1.43 bouyer MEGASAS_THUNDERBOLT_REPLY_SIZE * sc->sc_reply_pool_size, 3167 1.43 bouyer BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 3168 1.43 bouyer mfi_write(sc, MFI_RPI, sc->sc_last_reply_idx); 3169 1.43 bouyer return 1; 3170 1.43 bouyer } 3171 1.43 bouyer 3172 1.43 bouyer 3173 1.43 bouyer int 3174 1.43 bouyer mfi_tbolt_scsi_ld_io(struct mfi_ccb *ccb, struct scsipi_xfer *xs, 3175 1.43 bouyer uint64_t blockno, uint32_t blockcnt) 3176 1.43 bouyer { 3177 1.43 bouyer struct scsipi_periph *periph = xs->xs_periph; 3178 1.43 bouyer struct mfi_mpi2_request_raid_scsi_io *io_req; 3179 1.43 bouyer int sge_count; 3180 1.43 bouyer 3181 1.43 bouyer DNPRINTF(MFI_D_CMD, "%s: mfi_tbolt_scsi_ld_io: %d\n", 3182 1.43 bouyer device_xname(periph->periph_channel->chan_adapter->adapt_dev), 3183 1.43 bouyer periph->periph_target); 3184 1.43 bouyer 3185 1.43 bouyer if (!xs->data) 3186 1.43 bouyer return 1; 3187 1.43 bouyer 3188 1.43 bouyer ccb->ccb_done = mfi_tbolt_scsi_ld_done; 3189 1.43 bouyer ccb->ccb_xs = xs; 3190 1.43 bouyer ccb->ccb_data = xs->data; 3191 1.43 bouyer ccb->ccb_len = xs->datalen; 3192 1.43 bouyer 3193 1.43 bouyer io_req = ccb->ccb_tb_io_request; 3194 1.43 bouyer 3195 1.43 bouyer /* Just the CDB length,rest of the Flags are zero */ 3196 1.43 bouyer io_req->IoFlags = xs->cmdlen; 3197 1.43 bouyer memset(io_req->CDB.CDB32, 0, 32); 3198 1.43 bouyer memcpy(io_req->CDB.CDB32, &xs->cmdstore, xs->cmdlen); 3199 1.43 bouyer 3200 1.43 bouyer io_req->RaidContext.TargetID = periph->periph_target; 3201 1.43 bouyer io_req->RaidContext.Status = 0; 3202 1.43 bouyer io_req->RaidContext.exStatus = 0; 3203 1.43 bouyer io_req->RaidContext.timeoutValue = MFI_FUSION_FP_DEFAULT_TIMEOUT; 3204 1.43 bouyer io_req->Function = MPI2_FUNCTION_LD_IO_REQUEST; 3205 1.43 bouyer io_req->DevHandle = periph->periph_target; 3206 1.43 bouyer 3207 1.43 bouyer ccb->ccb_tb_request_desc.header.RequestFlags = 3208 1.43 bouyer (MFI_REQ_DESCRIPT_FLAGS_LD_IO << MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 3209 1.43 bouyer io_req->DataLength = blockcnt * MFI_SECTOR_LEN; 3210 1.43 bouyer 3211 1.43 bouyer if (xs->xs_control & XS_CTL_DATA_IN) { 3212 1.43 bouyer io_req->Control = MPI2_SCSIIO_CONTROL_READ; 3213 1.43 bouyer ccb->ccb_direction = MFI_DATA_IN; 3214 1.43 bouyer } else { 3215 1.43 bouyer io_req->Control = MPI2_SCSIIO_CONTROL_WRITE; 3216 1.43 bouyer ccb->ccb_direction = MFI_DATA_OUT; 3217 1.43 bouyer } 3218 1.43 bouyer 3219 1.43 bouyer sge_count = mfi_tbolt_create_sgl(ccb, 3220 1.43 bouyer (xs->xs_control & XS_CTL_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK 3221 1.43 bouyer ); 3222 1.43 bouyer if (sge_count < 0) 3223 1.43 bouyer return 1; 3224 1.43 bouyer KASSERT(sge_count <= ccb->ccb_sc->sc_max_sgl); 3225 1.43 bouyer io_req->RaidContext.numSGE = sge_count; 3226 1.43 bouyer io_req->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING; 3227 1.43 bouyer io_req->SGLOffset0 = 3228 1.43 bouyer offsetof(struct mfi_mpi2_request_raid_scsi_io, SGL) / 4; 3229 1.43 bouyer 3230 1.43 bouyer io_req->SenseBufferLowAddress = htole32(ccb->ccb_psense); 3231 1.43 bouyer io_req->SenseBufferLength = MFI_SENSE_SIZE; 3232 1.43 bouyer 3233 1.43 bouyer ccb->ccb_flags |= MFI_CCB_F_TBOLT | MFI_CCB_F_TBOLT_IO; 3234 1.43 bouyer bus_dmamap_sync(ccb->ccb_sc->sc_dmat, 3235 1.73 msaitoh MFIMEM_MAP(ccb->ccb_sc->sc_tbolt_reqmsgpool), 3236 1.43 bouyer ccb->ccb_tb_pio_request - 3237 1.43 bouyer MFIMEM_DVA(ccb->ccb_sc->sc_tbolt_reqmsgpool), 3238 1.43 bouyer MEGASAS_THUNDERBOLT_NEW_MSG_SIZE, 3239 1.43 bouyer BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 3240 1.43 bouyer 3241 1.43 bouyer return 0; 3242 1.43 bouyer } 3243 1.43 bouyer 3244 1.43 bouyer 3245 1.43 bouyer static void 3246 1.43 bouyer mfi_tbolt_scsi_ld_done(struct mfi_ccb *ccb) 3247 1.43 bouyer { 3248 1.43 bouyer struct mfi_mpi2_request_raid_scsi_io *io_req = ccb->ccb_tb_io_request; 3249 1.43 bouyer mfi_scsi_xs_done(ccb, io_req->RaidContext.Status, 3250 1.43 bouyer io_req->RaidContext.exStatus); 3251 1.43 bouyer } 3252 1.43 bouyer 3253 1.43 bouyer static int 3254 1.43 bouyer mfi_tbolt_create_sgl(struct mfi_ccb *ccb, int flags) 3255 1.43 bouyer { 3256 1.43 bouyer struct mfi_softc *sc = ccb->ccb_sc; 3257 1.43 bouyer bus_dma_segment_t *sgd; 3258 1.43 bouyer int error, i, sge_idx, sge_count; 3259 1.43 bouyer struct mfi_mpi2_request_raid_scsi_io *io_req; 3260 1.43 bouyer struct mpi25_ieee_sge_chain64 *sgl_ptr; 3261 1.43 bouyer 3262 1.43 bouyer DNPRINTF(MFI_D_DMA, "%s: mfi_tbolt_create_sgl %#lx\n", DEVNAME(sc), 3263 1.43 bouyer (u_long)ccb->ccb_data); 3264 1.43 bouyer 3265 1.43 bouyer if (!ccb->ccb_data) 3266 1.43 bouyer return -1; 3267 1.43 bouyer 3268 1.43 bouyer KASSERT(flags == BUS_DMA_NOWAIT || !cpu_intr_p()); 3269 1.43 bouyer error = bus_dmamap_load(sc->sc_datadmat, ccb->ccb_dmamap, 3270 1.43 bouyer ccb->ccb_data, ccb->ccb_len, NULL, flags); 3271 1.43 bouyer if (error) { 3272 1.43 bouyer if (error == EFBIG) 3273 1.43 bouyer aprint_error_dev(sc->sc_dev, "more than %d dma segs\n", 3274 1.43 bouyer sc->sc_max_sgl); 3275 1.43 bouyer else 3276 1.43 bouyer aprint_error_dev(sc->sc_dev, 3277 1.43 bouyer "error %d loading dma map\n", error); 3278 1.43 bouyer return -1; 3279 1.43 bouyer } 3280 1.43 bouyer 3281 1.43 bouyer io_req = ccb->ccb_tb_io_request; 3282 1.43 bouyer sgl_ptr = &io_req->SGL.IeeeChain.Chain64; 3283 1.43 bouyer sge_count = ccb->ccb_dmamap->dm_nsegs; 3284 1.43 bouyer sgd = ccb->ccb_dmamap->dm_segs; 3285 1.43 bouyer KASSERT(sge_count <= sc->sc_max_sgl); 3286 1.43 bouyer KASSERT(sge_count <= 3287 1.43 bouyer (MEGASAS_THUNDERBOLT_MAX_SGE_IN_MAINMSG - 1 + 3288 1.43 bouyer MEGASAS_THUNDERBOLT_MAX_SGE_IN_CHAINMSG)); 3289 1.43 bouyer 3290 1.43 bouyer if (sge_count > MEGASAS_THUNDERBOLT_MAX_SGE_IN_MAINMSG) { 3291 1.43 bouyer /* One element to store the chain info */ 3292 1.43 bouyer sge_idx = MEGASAS_THUNDERBOLT_MAX_SGE_IN_MAINMSG - 1; 3293 1.43 bouyer DNPRINTF(MFI_D_DMA, 3294 1.77 msaitoh "mfi sge_idx %d sge_count %d io_req paddr %jx\n", 3295 1.77 msaitoh sge_idx, sge_count, (uintmax_t)ccb->ccb_tb_pio_request); 3296 1.43 bouyer } else { 3297 1.43 bouyer sge_idx = sge_count; 3298 1.43 bouyer } 3299 1.43 bouyer 3300 1.43 bouyer for (i = 0; i < sge_idx; i++) { 3301 1.43 bouyer sgl_ptr->Address = htole64(sgd[i].ds_addr); 3302 1.43 bouyer sgl_ptr->Length = htole32(sgd[i].ds_len); 3303 1.43 bouyer sgl_ptr->Flags = 0; 3304 1.43 bouyer if (sge_idx < sge_count) { 3305 1.43 bouyer DNPRINTF(MFI_D_DMA, 3306 1.43 bouyer "sgl %p %d 0x%" PRIx64 " len 0x%" PRIx32 3307 1.43 bouyer " flags 0x%x\n", sgl_ptr, i, 3308 1.43 bouyer sgl_ptr->Address, sgl_ptr->Length, 3309 1.43 bouyer sgl_ptr->Flags); 3310 1.43 bouyer } 3311 1.43 bouyer sgl_ptr++; 3312 1.43 bouyer } 3313 1.43 bouyer io_req->ChainOffset = 0; 3314 1.43 bouyer if (sge_idx < sge_count) { 3315 1.43 bouyer struct mpi25_ieee_sge_chain64 *sg_chain; 3316 1.43 bouyer io_req->ChainOffset = MEGASAS_THUNDERBOLT_CHAIN_OFF_MAINMSG; 3317 1.43 bouyer sg_chain = sgl_ptr; 3318 1.43 bouyer /* Prepare chain element */ 3319 1.43 bouyer sg_chain->NextChainOffset = 0; 3320 1.43 bouyer sg_chain->Flags = (MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT | 3321 1.43 bouyer MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR); 3322 1.43 bouyer sg_chain->Length = (sizeof(mpi2_sge_io_union) * 3323 1.43 bouyer (sge_count - sge_idx)); 3324 1.43 bouyer sg_chain->Address = ccb->ccb_tb_psg_frame; 3325 1.43 bouyer DNPRINTF(MFI_D_DMA, 3326 1.43 bouyer "sgl %p chain 0x%" PRIx64 " len 0x%" PRIx32 3327 1.43 bouyer " flags 0x%x\n", sg_chain, sg_chain->Address, 3328 1.43 bouyer sg_chain->Length, sg_chain->Flags); 3329 1.43 bouyer sgl_ptr = &ccb->ccb_tb_sg_frame->IeeeChain.Chain64; 3330 1.43 bouyer for (; i < sge_count; i++) { 3331 1.43 bouyer sgl_ptr->Address = htole64(sgd[i].ds_addr); 3332 1.43 bouyer sgl_ptr->Length = htole32(sgd[i].ds_len); 3333 1.43 bouyer sgl_ptr->Flags = 0; 3334 1.43 bouyer DNPRINTF(MFI_D_DMA, 3335 1.43 bouyer "sgl %p %d 0x%" PRIx64 " len 0x%" PRIx32 3336 1.43 bouyer " flags 0x%x\n", sgl_ptr, i, sgl_ptr->Address, 3337 1.43 bouyer sgl_ptr->Length, sgl_ptr->Flags); 3338 1.43 bouyer sgl_ptr++; 3339 1.43 bouyer } 3340 1.43 bouyer bus_dmamap_sync(sc->sc_dmat, 3341 1.73 msaitoh MFIMEM_MAP(sc->sc_tbolt_reqmsgpool), 3342 1.43 bouyer ccb->ccb_tb_psg_frame - MFIMEM_DVA(sc->sc_tbolt_reqmsgpool), 3343 1.43 bouyer MEGASAS_MAX_SZ_CHAIN_FRAME, BUS_DMASYNC_PREREAD); 3344 1.43 bouyer } 3345 1.43 bouyer 3346 1.43 bouyer if (ccb->ccb_direction == MFI_DATA_IN) { 3347 1.43 bouyer bus_dmamap_sync(sc->sc_datadmat, ccb->ccb_dmamap, 0, 3348 1.43 bouyer ccb->ccb_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); 3349 1.43 bouyer } else { 3350 1.43 bouyer bus_dmamap_sync(sc->sc_datadmat, ccb->ccb_dmamap, 0, 3351 1.43 bouyer ccb->ccb_dmamap->dm_mapsize, BUS_DMASYNC_PREWRITE); 3352 1.43 bouyer } 3353 1.43 bouyer return sge_count; 3354 1.43 bouyer } 3355 1.43 bouyer 3356 1.43 bouyer /* 3357 1.43 bouyer * The ThunderBolt HW has an option for the driver to directly 3358 1.43 bouyer * access the underlying disks and operate on the RAID. To 3359 1.43 bouyer * do this there needs to be a capability to keep the RAID controller 3360 1.43 bouyer * and driver in sync. The FreeBSD driver does not take advantage 3361 1.43 bouyer * of this feature since it adds a lot of complexity and slows down 3362 1.43 bouyer * performance. Performance is gained by using the controller's 3363 1.43 bouyer * cache etc. 3364 1.43 bouyer * 3365 1.43 bouyer * Even though this driver doesn't access the disks directly, an 3366 1.43 bouyer * AEN like command is used to inform the RAID firmware to "sync" 3367 1.43 bouyer * with all LD's via the MFI_DCMD_LD_MAP_GET_INFO command. This 3368 1.43 bouyer * command in write mode will return when the RAID firmware has 3369 1.43 bouyer * detected a change to the RAID state. Examples of this type 3370 1.43 bouyer * of change are removing a disk. Once the command returns then 3371 1.43 bouyer * the driver needs to acknowledge this and "sync" all LD's again. 3372 1.43 bouyer * This repeats until we shutdown. Then we need to cancel this 3373 1.43 bouyer * pending command. 3374 1.43 bouyer * 3375 1.43 bouyer * If this is not done right the RAID firmware will not remove a 3376 1.43 bouyer * pulled drive and the RAID won't go degraded etc. Effectively, 3377 1.80 andvar * stopping any RAID management to functions. 3378 1.43 bouyer * 3379 1.43 bouyer * Doing another LD sync, requires the use of an event since the 3380 1.43 bouyer * driver needs to do a mfi_wait_command and can't do that in an 3381 1.43 bouyer * interrupt thread. 3382 1.43 bouyer * 3383 1.43 bouyer * The driver could get the RAID state via the MFI_DCMD_LD_MAP_GET_INFO 3384 1.68 andvar * That requires a bunch of structure and it is simpler to just do 3385 1.43 bouyer * the MFI_DCMD_LD_GET_LIST versus walking the RAID map. 3386 1.43 bouyer */ 3387 1.43 bouyer 3388 1.43 bouyer void 3389 1.43 bouyer mfi_tbolt_sync_map_info(struct work *w, void *v) 3390 1.43 bouyer { 3391 1.43 bouyer struct mfi_softc *sc = v; 3392 1.43 bouyer int i; 3393 1.43 bouyer struct mfi_ccb *ccb = NULL; 3394 1.74 msaitoh union mfi_mbox mbox; 3395 1.63 maxv struct mfi_ld *ld_sync; 3396 1.43 bouyer size_t ld_size; 3397 1.43 bouyer int s; 3398 1.43 bouyer 3399 1.43 bouyer DNPRINTF(MFI_D_SYNC, "%s: mfi_tbolt_sync_map_info\n", DEVNAME(sc)); 3400 1.43 bouyer again: 3401 1.63 maxv ld_sync = NULL; 3402 1.43 bouyer s = splbio(); 3403 1.43 bouyer if (sc->sc_ldsync_ccb != NULL) { 3404 1.43 bouyer splx(s); 3405 1.43 bouyer return; 3406 1.43 bouyer } 3407 1.43 bouyer 3408 1.43 bouyer if (mfi_mgmt_internal(sc, MR_DCMD_LD_GET_LIST, MFI_DATA_IN, 3409 1.45 bouyer sizeof(sc->sc_ld_list), &sc->sc_ld_list, NULL, false)) { 3410 1.43 bouyer aprint_error_dev(sc->sc_dev, "MR_DCMD_LD_GET_LIST failed\n"); 3411 1.43 bouyer goto err; 3412 1.43 bouyer } 3413 1.43 bouyer 3414 1.43 bouyer ld_size = sizeof(*ld_sync) * sc->sc_ld_list.mll_no_ld; 3415 1.73 msaitoh 3416 1.57 christos ld_sync = malloc(ld_size, M_DEVBUF, M_WAITOK | M_ZERO); 3417 1.43 bouyer if (ld_sync == NULL) { 3418 1.43 bouyer aprint_error_dev(sc->sc_dev, "Failed to allocate sync\n"); 3419 1.43 bouyer goto err; 3420 1.43 bouyer } 3421 1.43 bouyer for (i = 0; i < sc->sc_ld_list.mll_no_ld; i++) { 3422 1.43 bouyer ld_sync[i] = sc->sc_ld_list.mll_list[i].mll_ld; 3423 1.43 bouyer } 3424 1.43 bouyer 3425 1.43 bouyer if ((ccb = mfi_get_ccb(sc)) == NULL) { 3426 1.43 bouyer aprint_error_dev(sc->sc_dev, "Failed to get sync command\n"); 3427 1.43 bouyer goto err; 3428 1.43 bouyer } 3429 1.43 bouyer sc->sc_ldsync_ccb = ccb; 3430 1.73 msaitoh 3431 1.74 msaitoh memset(&mbox, 0, sizeof(mbox)); 3432 1.74 msaitoh mbox.b[0] = sc->sc_ld_list.mll_no_ld; 3433 1.74 msaitoh mbox.b[1] = MFI_DCMD_MBOX_PEND_FLAG; 3434 1.43 bouyer if (mfi_mgmt(ccb, NULL, MR_DCMD_LD_MAP_GET_INFO, MFI_DATA_OUT, 3435 1.74 msaitoh ld_size, ld_sync, &mbox)) { 3436 1.43 bouyer aprint_error_dev(sc->sc_dev, "Failed to create sync command\n"); 3437 1.43 bouyer goto err; 3438 1.43 bouyer } 3439 1.43 bouyer /* 3440 1.43 bouyer * we won't sleep on this command, so we have to override 3441 1.43 bouyer * the callback set up by mfi_mgmt() 3442 1.43 bouyer */ 3443 1.43 bouyer ccb->ccb_done = mfi_sync_map_complete; 3444 1.43 bouyer 3445 1.43 bouyer mfi_post(sc, ccb); 3446 1.43 bouyer splx(s); 3447 1.43 bouyer return; 3448 1.43 bouyer 3449 1.43 bouyer err: 3450 1.43 bouyer if (ld_sync) 3451 1.43 bouyer free(ld_sync, M_DEVBUF); 3452 1.43 bouyer if (ccb) 3453 1.43 bouyer mfi_put_ccb(ccb); 3454 1.43 bouyer sc->sc_ldsync_ccb = NULL; 3455 1.43 bouyer splx(s); 3456 1.43 bouyer kpause("ldsyncp", 0, hz, NULL); 3457 1.43 bouyer goto again; 3458 1.43 bouyer } 3459 1.43 bouyer 3460 1.43 bouyer static void 3461 1.43 bouyer mfi_sync_map_complete(struct mfi_ccb *ccb) 3462 1.43 bouyer { 3463 1.43 bouyer struct mfi_softc *sc = ccb->ccb_sc; 3464 1.45 bouyer bool aborted = !sc->sc_running; 3465 1.43 bouyer 3466 1.43 bouyer DNPRINTF(MFI_D_SYNC, "%s: mfi_sync_map_complete\n", 3467 1.43 bouyer DEVNAME(ccb->ccb_sc)); 3468 1.43 bouyer KASSERT(sc->sc_ldsync_ccb == ccb); 3469 1.43 bouyer mfi_mgmt_done(ccb); 3470 1.43 bouyer free(ccb->ccb_data, M_DEVBUF); 3471 1.43 bouyer if (ccb->ccb_flags & MFI_CCB_F_ERR) { 3472 1.43 bouyer aprint_error_dev(sc->sc_dev, "sync command failed\n"); 3473 1.45 bouyer aborted = true; 3474 1.43 bouyer } 3475 1.43 bouyer mfi_put_ccb(ccb); 3476 1.43 bouyer sc->sc_ldsync_ccb = NULL; 3477 1.43 bouyer 3478 1.43 bouyer /* set it up again so the driver can catch more events */ 3479 1.43 bouyer if (!aborted) { 3480 1.43 bouyer workqueue_enqueue(sc->sc_ldsync_wq, &sc->sc_ldsync_wk, NULL); 3481 1.43 bouyer } 3482 1.38 sborrill } 3483 1.47 bouyer 3484 1.47 bouyer static int 3485 1.47 bouyer mfifopen(dev_t dev, int flag, int mode, struct lwp *l) 3486 1.47 bouyer { 3487 1.47 bouyer struct mfi_softc *sc; 3488 1.47 bouyer 3489 1.47 bouyer if ((sc = device_lookup_private(&mfi_cd, minor(dev))) == NULL) 3490 1.47 bouyer return (ENXIO); 3491 1.47 bouyer return (0); 3492 1.47 bouyer } 3493 1.47 bouyer 3494 1.47 bouyer static int 3495 1.47 bouyer mfifclose(dev_t dev, int flag, int mode, struct lwp *l) 3496 1.47 bouyer { 3497 1.47 bouyer return (0); 3498 1.47 bouyer } 3499 1.47 bouyer 3500 1.47 bouyer static int 3501 1.47 bouyer mfifioctl(dev_t dev, u_long cmd, void *data, int flag, 3502 1.47 bouyer struct lwp *l) 3503 1.47 bouyer { 3504 1.47 bouyer struct mfi_softc *sc; 3505 1.47 bouyer struct mfi_ioc_packet *ioc = data; 3506 1.47 bouyer uint8_t *udata; 3507 1.47 bouyer struct mfi_ccb *ccb = NULL; 3508 1.47 bouyer int ctx, i, s, error; 3509 1.47 bouyer union mfi_sense_ptr sense_ptr; 3510 1.47 bouyer 3511 1.73 msaitoh switch (cmd) { 3512 1.47 bouyer case MFI_CMD: 3513 1.47 bouyer sc = device_lookup_private(&mfi_cd, ioc->mfi_adapter_no); 3514 1.47 bouyer break; 3515 1.47 bouyer default: 3516 1.47 bouyer return ENOTTY; 3517 1.47 bouyer } 3518 1.47 bouyer if (sc == NULL) 3519 1.47 bouyer return (ENXIO); 3520 1.47 bouyer if (sc->sc_opened) 3521 1.47 bouyer return (EBUSY); 3522 1.47 bouyer 3523 1.73 msaitoh switch (cmd) { 3524 1.47 bouyer case MFI_CMD: 3525 1.47 bouyer error = kauth_authorize_device_passthru(l->l_cred, dev, 3526 1.47 bouyer KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL, data); 3527 1.47 bouyer if (error) 3528 1.47 bouyer return error; 3529 1.47 bouyer if (ioc->mfi_sge_count > MAX_IOCTL_SGE) 3530 1.47 bouyer return EINVAL; 3531 1.47 bouyer s = splbio(); 3532 1.47 bouyer if ((ccb = mfi_get_ccb(sc)) == NULL) 3533 1.47 bouyer return ENOMEM; 3534 1.47 bouyer ccb->ccb_data = NULL; 3535 1.47 bouyer ctx = ccb->ccb_frame->mfr_header.mfh_context; 3536 1.47 bouyer memcpy(ccb->ccb_frame, ioc->mfi_frame.raw, 3537 1.47 bouyer sizeof(*ccb->ccb_frame)); 3538 1.47 bouyer ccb->ccb_frame->mfr_header.mfh_context = ctx; 3539 1.47 bouyer ccb->ccb_frame->mfr_header.mfh_scsi_status = 0; 3540 1.47 bouyer ccb->ccb_frame->mfr_header.mfh_pad0 = 0; 3541 1.47 bouyer ccb->ccb_frame_size = 3542 1.47 bouyer (sizeof(union mfi_sgl) * ioc->mfi_sge_count) + 3543 1.47 bouyer ioc->mfi_sgl_off; 3544 1.47 bouyer if (ioc->mfi_sge_count > 0) { 3545 1.47 bouyer ccb->ccb_sgl = (union mfi_sgl *) 3546 1.47 bouyer &ccb->ccb_frame->mfr_bytes[ioc->mfi_sgl_off]; 3547 1.47 bouyer } 3548 1.47 bouyer if (ccb->ccb_frame->mfr_header.mfh_flags & MFI_FRAME_DIR_READ) 3549 1.47 bouyer ccb->ccb_direction = MFI_DATA_IN; 3550 1.47 bouyer if (ccb->ccb_frame->mfr_header.mfh_flags & MFI_FRAME_DIR_WRITE) 3551 1.47 bouyer ccb->ccb_direction = MFI_DATA_OUT; 3552 1.47 bouyer ccb->ccb_len = ccb->ccb_frame->mfr_header.mfh_data_len; 3553 1.47 bouyer if (ccb->ccb_len > MAXPHYS) { 3554 1.47 bouyer error = ENOMEM; 3555 1.47 bouyer goto out; 3556 1.47 bouyer } 3557 1.47 bouyer if (ccb->ccb_len && 3558 1.47 bouyer (ccb->ccb_direction & (MFI_DATA_IN | MFI_DATA_OUT)) != 0) { 3559 1.47 bouyer udata = malloc(ccb->ccb_len, M_DEVBUF, M_WAITOK|M_ZERO); 3560 1.47 bouyer if (udata == NULL) { 3561 1.47 bouyer error = ENOMEM; 3562 1.47 bouyer goto out; 3563 1.47 bouyer } 3564 1.47 bouyer ccb->ccb_data = udata; 3565 1.47 bouyer if (ccb->ccb_direction & MFI_DATA_OUT) { 3566 1.47 bouyer for (i = 0; i < ioc->mfi_sge_count; i++) { 3567 1.47 bouyer error = copyin(ioc->mfi_sgl[i].iov_base, 3568 1.47 bouyer udata, ioc->mfi_sgl[i].iov_len); 3569 1.47 bouyer if (error) 3570 1.47 bouyer goto out; 3571 1.47 bouyer udata = &udata[ 3572 1.47 bouyer ioc->mfi_sgl[i].iov_len]; 3573 1.47 bouyer } 3574 1.47 bouyer } 3575 1.47 bouyer if (mfi_create_sgl(ccb, BUS_DMA_WAITOK)) { 3576 1.47 bouyer error = EIO; 3577 1.47 bouyer goto out; 3578 1.47 bouyer } 3579 1.47 bouyer } 3580 1.47 bouyer if (ccb->ccb_frame->mfr_header.mfh_cmd == MFI_CMD_PD_SCSI_IO) { 3581 1.47 bouyer ccb->ccb_frame->mfr_io.mif_sense_addr_lo = 3582 1.47 bouyer htole32(ccb->ccb_psense); 3583 1.47 bouyer ccb->ccb_frame->mfr_io.mif_sense_addr_hi = 0; 3584 1.47 bouyer } 3585 1.47 bouyer ccb->ccb_done = mfi_mgmt_done; 3586 1.47 bouyer mfi_post(sc, ccb); 3587 1.47 bouyer while (ccb->ccb_state != MFI_CCB_DONE) 3588 1.47 bouyer tsleep(ccb, PRIBIO, "mfi_fioc", 0); 3589 1.47 bouyer 3590 1.47 bouyer if (ccb->ccb_direction & MFI_DATA_IN) { 3591 1.47 bouyer udata = ccb->ccb_data; 3592 1.47 bouyer for (i = 0; i < ioc->mfi_sge_count; i++) { 3593 1.47 bouyer error = copyout(udata, 3594 1.47 bouyer ioc->mfi_sgl[i].iov_base, 3595 1.47 bouyer ioc->mfi_sgl[i].iov_len); 3596 1.47 bouyer if (error) 3597 1.47 bouyer goto out; 3598 1.47 bouyer udata = &udata[ 3599 1.47 bouyer ioc->mfi_sgl[i].iov_len]; 3600 1.47 bouyer } 3601 1.47 bouyer } 3602 1.47 bouyer if (ioc->mfi_sense_len) { 3603 1.47 bouyer memcpy(&sense_ptr.sense_ptr_data[0], 3604 1.47 bouyer &ioc->mfi_frame.raw[ioc->mfi_sense_off], 3605 1.47 bouyer sizeof(sense_ptr.sense_ptr_data)); 3606 1.47 bouyer error = copyout(ccb->ccb_sense, 3607 1.47 bouyer sense_ptr.user_space, 3608 1.47 bouyer sizeof(sense_ptr.sense_ptr_data)); 3609 1.47 bouyer if (error) 3610 1.47 bouyer goto out; 3611 1.47 bouyer } 3612 1.47 bouyer memcpy(ioc->mfi_frame.raw, ccb->ccb_frame, 3613 1.47 bouyer sizeof(*ccb->ccb_frame)); 3614 1.47 bouyer break; 3615 1.47 bouyer default: 3616 1.47 bouyer printf("mfifioctl unhandled cmd 0x%lx\n", cmd); 3617 1.47 bouyer return ENOTTY; 3618 1.47 bouyer } 3619 1.47 bouyer 3620 1.47 bouyer out: 3621 1.47 bouyer if (ccb->ccb_data) 3622 1.47 bouyer free(ccb->ccb_data, M_DEVBUF); 3623 1.47 bouyer if (ccb) 3624 1.47 bouyer mfi_put_ccb(ccb); 3625 1.47 bouyer splx(s); 3626 1.47 bouyer return error; 3627 1.47 bouyer } 3628