1 1.40 andvar /* $NetBSD: mpt_netbsd.c,v 1.40 2024/02/09 22:08:34 andvar Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /* 4 1.1 thorpej * Copyright (c) 2003 Wasabi Systems, Inc. 5 1.1 thorpej * All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 1.1 thorpej * 9 1.1 thorpej * Redistribution and use in source and binary forms, with or without 10 1.1 thorpej * modification, are permitted provided that the following conditions 11 1.1 thorpej * are met: 12 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 13 1.1 thorpej * notice, this list of conditions and the following disclaimer. 14 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 16 1.1 thorpej * documentation and/or other materials provided with the distribution. 17 1.1 thorpej * 3. All advertising materials mentioning features or use of this software 18 1.1 thorpej * must display the following acknowledgement: 19 1.1 thorpej * This product includes software developed for the NetBSD Project by 20 1.1 thorpej * Wasabi Systems, Inc. 21 1.1 thorpej * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 1.1 thorpej * or promote products derived from this software without specific prior 23 1.1 thorpej * written permission. 24 1.1 thorpej * 25 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 1.1 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 1.1 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 1.1 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 1.1 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 1.1 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 1.1 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 1.1 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 1.1 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 1.1 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE. 36 1.1 thorpej */ 37 1.1 thorpej 38 1.1 thorpej /* 39 1.1 thorpej * Copyright (c) 2000, 2001 by Greg Ansley 40 1.1 thorpej * Partially derived from Matt Jacob's ISP driver. 41 1.1 thorpej * 42 1.1 thorpej * Redistribution and use in source and binary forms, with or without 43 1.1 thorpej * modification, are permitted provided that the following conditions 44 1.1 thorpej * are met: 45 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 46 1.1 thorpej * notice immediately at the beginning of the file, without modification, 47 1.1 thorpej * this list of conditions, and the following disclaimer. 48 1.1 thorpej * 2. The name of the author may not be used to endorse or promote products 49 1.1 thorpej * derived from this software without specific prior written permission. 50 1.1 thorpej * 51 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 52 1.1 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 1.1 thorpej * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 1.1 thorpej * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 55 1.1 thorpej * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 1.1 thorpej * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 1.1 thorpej * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 1.1 thorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 1.1 thorpej * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 1.1 thorpej * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 1.1 thorpej * SUCH DAMAGE. 62 1.1 thorpej */ 63 1.1 thorpej /* 64 1.1 thorpej * Additional Copyright (c) 2002 by Matthew Jacob under same license. 65 1.1 thorpej */ 66 1.1 thorpej 67 1.1 thorpej /* 68 1.1 thorpej * mpt_netbsd.c: 69 1.1 thorpej * 70 1.1 thorpej * NetBSD-specific routines for LSI Fusion adapters. Includes some 71 1.1 thorpej * bus_dma glue, and SCSIPI glue. 72 1.1 thorpej * 73 1.1 thorpej * Adapted from the FreeBSD "mpt" driver by Jason R. Thorpe for 74 1.1 thorpej * Wasabi Systems, Inc. 75 1.12 tron * 76 1.12 tron * Additional contributions by Garrett D'Amore on behalf of TELES AG. 77 1.1 thorpej */ 78 1.7 lukem 79 1.7 lukem #include <sys/cdefs.h> 80 1.40 andvar __KERNEL_RCSID(0, "$NetBSD: mpt_netbsd.c,v 1.40 2024/02/09 22:08:34 andvar Exp $"); 81 1.26 jmcneill 82 1.26 jmcneill #include "bio.h" 83 1.1 thorpej 84 1.1 thorpej #include <dev/ic/mpt.h> /* pulls in all headers */ 85 1.20 buhrow #include <sys/scsiio.h> 86 1.1 thorpej 87 1.26 jmcneill #if NBIO > 0 88 1.26 jmcneill #include <dev/biovar.h> 89 1.26 jmcneill #endif 90 1.26 jmcneill 91 1.1 thorpej static int mpt_poll(mpt_softc_t *, struct scsipi_xfer *, int); 92 1.1 thorpej static void mpt_timeout(void *); 93 1.20 buhrow static void mpt_restart(mpt_softc_t *, request_t *); 94 1.1 thorpej static void mpt_done(mpt_softc_t *, uint32_t); 95 1.20 buhrow static int mpt_drain_queue(mpt_softc_t *); 96 1.1 thorpej static void mpt_run_xfer(mpt_softc_t *, struct scsipi_xfer *); 97 1.1 thorpej static void mpt_set_xfer_mode(mpt_softc_t *, struct scsipi_xfer_mode *); 98 1.1 thorpej static void mpt_get_xfer_mode(mpt_softc_t *, struct scsipi_periph *); 99 1.1 thorpej static void mpt_ctlop(mpt_softc_t *, void *vmsg, uint32_t); 100 1.1 thorpej static void mpt_event_notify_reply(mpt_softc_t *, MSG_EVENT_NOTIFY_REPLY *); 101 1.20 buhrow static void mpt_bus_reset(mpt_softc_t *); 102 1.1 thorpej 103 1.1 thorpej static void mpt_scsipi_request(struct scsipi_channel *, 104 1.1 thorpej scsipi_adapter_req_t, void *); 105 1.1 thorpej static void mpt_minphys(struct buf *); 106 1.20 buhrow static int mpt_ioctl(struct scsipi_channel *, u_long, void *, int, 107 1.20 buhrow struct proc *); 108 1.1 thorpej 109 1.26 jmcneill #if NBIO > 0 110 1.26 jmcneill static bool mpt_is_raid(mpt_softc_t *); 111 1.26 jmcneill static int mpt_bio_ioctl(device_t, u_long, void *); 112 1.26 jmcneill static int mpt_bio_ioctl_inq(mpt_softc_t *, struct bioc_inq *); 113 1.26 jmcneill static int mpt_bio_ioctl_vol(mpt_softc_t *, struct bioc_vol *); 114 1.26 jmcneill static int mpt_bio_ioctl_disk(mpt_softc_t *, struct bioc_disk *); 115 1.29 jmcneill static int mpt_bio_ioctl_disk_novol(mpt_softc_t *, struct bioc_disk *); 116 1.26 jmcneill #endif 117 1.26 jmcneill 118 1.1 thorpej void 119 1.1 thorpej mpt_scsipi_attach(mpt_softc_t *mpt) 120 1.1 thorpej { 121 1.1 thorpej struct scsipi_adapter *adapt = &mpt->sc_adapter; 122 1.1 thorpej struct scsipi_channel *chan = &mpt->sc_channel; 123 1.1 thorpej int maxq; 124 1.1 thorpej 125 1.1 thorpej mpt->bus = 0; /* XXX ?? */ 126 1.1 thorpej 127 1.1 thorpej maxq = (mpt->mpt_global_credits < MPT_MAX_REQUESTS(mpt)) ? 128 1.1 thorpej mpt->mpt_global_credits : MPT_MAX_REQUESTS(mpt); 129 1.1 thorpej 130 1.1 thorpej /* Fill in the scsipi_adapter. */ 131 1.1 thorpej memset(adapt, 0, sizeof(*adapt)); 132 1.18 martin adapt->adapt_dev = mpt->sc_dev; 133 1.1 thorpej adapt->adapt_nchannels = 1; 134 1.17 mhitch adapt->adapt_openings = maxq - 2; /* Reserve 2 for driver use*/ 135 1.17 mhitch adapt->adapt_max_periph = maxq - 2; 136 1.1 thorpej adapt->adapt_request = mpt_scsipi_request; 137 1.1 thorpej adapt->adapt_minphys = mpt_minphys; 138 1.20 buhrow adapt->adapt_ioctl = mpt_ioctl; 139 1.1 thorpej 140 1.1 thorpej /* Fill in the scsipi_channel. */ 141 1.1 thorpej memset(chan, 0, sizeof(*chan)); 142 1.1 thorpej chan->chan_adapter = adapt; 143 1.19 chs if (mpt->is_sas) { 144 1.19 chs chan->chan_bustype = &scsi_sas_bustype; 145 1.19 chs } else if (mpt->is_fc) { 146 1.19 chs chan->chan_bustype = &scsi_fc_bustype; 147 1.19 chs } else { 148 1.19 chs chan->chan_bustype = &scsi_bustype; 149 1.19 chs } 150 1.1 thorpej chan->chan_channel = 0; 151 1.1 thorpej chan->chan_flags = 0; 152 1.1 thorpej chan->chan_nluns = 8; 153 1.37 mlelstv chan->chan_ntargets = mpt->mpt_max_devices ? mpt->mpt_max_devices : 256; 154 1.12 tron chan->chan_id = mpt->mpt_ini_id; 155 1.1 thorpej 156 1.22 buhrow /* 157 1.22 buhrow * Save the output of the config so we can rescan the bus in case of 158 1.22 buhrow * errors 159 1.22 buhrow */ 160 1.22 buhrow mpt->sc_scsibus_dv = config_found(mpt->sc_dev, &mpt->sc_channel, 161 1.39 thorpej scsiprint, CFARGS_NONE); 162 1.26 jmcneill 163 1.26 jmcneill #if NBIO > 0 164 1.26 jmcneill if (mpt_is_raid(mpt)) { 165 1.26 jmcneill if (bio_register(mpt->sc_dev, mpt_bio_ioctl) != 0) 166 1.26 jmcneill panic("%s: controller registration failed", 167 1.26 jmcneill device_xname(mpt->sc_dev)); 168 1.26 jmcneill } 169 1.26 jmcneill #endif 170 1.1 thorpej } 171 1.1 thorpej 172 1.1 thorpej int 173 1.1 thorpej mpt_dma_mem_alloc(mpt_softc_t *mpt) 174 1.1 thorpej { 175 1.1 thorpej bus_dma_segment_t reply_seg, request_seg; 176 1.1 thorpej int reply_rseg, request_rseg; 177 1.1 thorpej bus_addr_t pptr, end; 178 1.11 christos char *vptr; 179 1.1 thorpej size_t len; 180 1.1 thorpej int error, i; 181 1.1 thorpej 182 1.1 thorpej /* Check if we have already allocated the reply memory. */ 183 1.1 thorpej if (mpt->reply != NULL) 184 1.1 thorpej return (0); 185 1.1 thorpej 186 1.1 thorpej /* 187 1.1 thorpej * Allocate the request pool. This isn't really DMA'd memory, 188 1.1 thorpej * but it's a convenient place to do it. 189 1.1 thorpej */ 190 1.1 thorpej len = sizeof(request_t) * MPT_MAX_REQUESTS(mpt); 191 1.1 thorpej mpt->request_pool = malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); 192 1.1 thorpej if (mpt->request_pool == NULL) { 193 1.18 martin aprint_error_dev(mpt->sc_dev, "unable to allocate request pool\n"); 194 1.1 thorpej return (ENOMEM); 195 1.1 thorpej } 196 1.1 thorpej 197 1.1 thorpej /* 198 1.1 thorpej * Allocate DMA resources for reply buffers. 199 1.1 thorpej */ 200 1.1 thorpej error = bus_dmamem_alloc(mpt->sc_dmat, PAGE_SIZE, PAGE_SIZE, 0, 201 1.1 thorpej &reply_seg, 1, &reply_rseg, 0); 202 1.1 thorpej if (error) { 203 1.18 martin aprint_error_dev(mpt->sc_dev, "unable to allocate reply area, error = %d\n", 204 1.14 cegger error); 205 1.1 thorpej goto fail_0; 206 1.1 thorpej } 207 1.1 thorpej 208 1.1 thorpej error = bus_dmamem_map(mpt->sc_dmat, &reply_seg, reply_rseg, PAGE_SIZE, 209 1.11 christos (void **) &mpt->reply, BUS_DMA_COHERENT/*XXX*/); 210 1.1 thorpej if (error) { 211 1.18 martin aprint_error_dev(mpt->sc_dev, "unable to map reply area, error = %d\n", 212 1.14 cegger error); 213 1.1 thorpej goto fail_1; 214 1.1 thorpej } 215 1.1 thorpej 216 1.1 thorpej error = bus_dmamap_create(mpt->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 217 1.1 thorpej 0, 0, &mpt->reply_dmap); 218 1.1 thorpej if (error) { 219 1.18 martin aprint_error_dev(mpt->sc_dev, "unable to create reply DMA map, error = %d\n", 220 1.14 cegger error); 221 1.1 thorpej goto fail_2; 222 1.1 thorpej } 223 1.1 thorpej 224 1.1 thorpej error = bus_dmamap_load(mpt->sc_dmat, mpt->reply_dmap, mpt->reply, 225 1.1 thorpej PAGE_SIZE, NULL, 0); 226 1.1 thorpej if (error) { 227 1.18 martin aprint_error_dev(mpt->sc_dev, "unable to load reply DMA map, error = %d\n", 228 1.14 cegger error); 229 1.1 thorpej goto fail_3; 230 1.1 thorpej } 231 1.1 thorpej mpt->reply_phys = mpt->reply_dmap->dm_segs[0].ds_addr; 232 1.1 thorpej 233 1.1 thorpej /* 234 1.1 thorpej * Allocate DMA resources for request buffers. 235 1.1 thorpej */ 236 1.1 thorpej error = bus_dmamem_alloc(mpt->sc_dmat, MPT_REQ_MEM_SIZE(mpt), 237 1.1 thorpej PAGE_SIZE, 0, &request_seg, 1, &request_rseg, 0); 238 1.1 thorpej if (error) { 239 1.18 martin aprint_error_dev(mpt->sc_dev, "unable to allocate request area, " 240 1.14 cegger "error = %d\n", error); 241 1.1 thorpej goto fail_4; 242 1.1 thorpej } 243 1.1 thorpej 244 1.1 thorpej error = bus_dmamem_map(mpt->sc_dmat, &request_seg, request_rseg, 245 1.11 christos MPT_REQ_MEM_SIZE(mpt), (void **) &mpt->request, 0); 246 1.1 thorpej if (error) { 247 1.18 martin aprint_error_dev(mpt->sc_dev, "unable to map request area, error = %d\n", 248 1.14 cegger error); 249 1.1 thorpej goto fail_5; 250 1.1 thorpej } 251 1.1 thorpej 252 1.1 thorpej error = bus_dmamap_create(mpt->sc_dmat, MPT_REQ_MEM_SIZE(mpt), 1, 253 1.1 thorpej MPT_REQ_MEM_SIZE(mpt), 0, 0, &mpt->request_dmap); 254 1.1 thorpej if (error) { 255 1.18 martin aprint_error_dev(mpt->sc_dev, "unable to create request DMA map, " 256 1.14 cegger "error = %d\n", error); 257 1.1 thorpej goto fail_6; 258 1.1 thorpej } 259 1.1 thorpej 260 1.1 thorpej error = bus_dmamap_load(mpt->sc_dmat, mpt->request_dmap, mpt->request, 261 1.1 thorpej MPT_REQ_MEM_SIZE(mpt), NULL, 0); 262 1.1 thorpej if (error) { 263 1.18 martin aprint_error_dev(mpt->sc_dev, "unable to load request DMA map, error = %d\n", 264 1.14 cegger error); 265 1.1 thorpej goto fail_7; 266 1.1 thorpej } 267 1.1 thorpej mpt->request_phys = mpt->request_dmap->dm_segs[0].ds_addr; 268 1.1 thorpej 269 1.1 thorpej pptr = mpt->request_phys; 270 1.11 christos vptr = (void *) mpt->request; 271 1.1 thorpej end = pptr + MPT_REQ_MEM_SIZE(mpt); 272 1.1 thorpej 273 1.1 thorpej for (i = 0; pptr < end; i++) { 274 1.1 thorpej request_t *req = &mpt->request_pool[i]; 275 1.1 thorpej req->index = i; 276 1.1 thorpej 277 1.1 thorpej /* Store location of Request Data */ 278 1.1 thorpej req->req_pbuf = pptr; 279 1.1 thorpej req->req_vbuf = vptr; 280 1.1 thorpej 281 1.1 thorpej pptr += MPT_REQUEST_AREA; 282 1.1 thorpej vptr += MPT_REQUEST_AREA; 283 1.1 thorpej 284 1.1 thorpej req->sense_pbuf = (pptr - MPT_SENSE_SIZE); 285 1.1 thorpej req->sense_vbuf = (vptr - MPT_SENSE_SIZE); 286 1.1 thorpej 287 1.5 tls error = bus_dmamap_create(mpt->sc_dmat, MAXPHYS, 288 1.5 tls MPT_SGL_MAX, MAXPHYS, 0, 0, &req->dmap); 289 1.1 thorpej if (error) { 290 1.18 martin aprint_error_dev(mpt->sc_dev, "unable to create req %d DMA map, " 291 1.14 cegger "error = %d\n", i, error); 292 1.1 thorpej goto fail_8; 293 1.1 thorpej } 294 1.1 thorpej } 295 1.1 thorpej 296 1.1 thorpej return (0); 297 1.1 thorpej 298 1.1 thorpej fail_8: 299 1.1 thorpej for (--i; i >= 0; i--) { 300 1.1 thorpej request_t *req = &mpt->request_pool[i]; 301 1.3 thorpej if (req->dmap != NULL) 302 1.3 thorpej bus_dmamap_destroy(mpt->sc_dmat, req->dmap); 303 1.1 thorpej } 304 1.1 thorpej bus_dmamap_unload(mpt->sc_dmat, mpt->request_dmap); 305 1.1 thorpej fail_7: 306 1.1 thorpej bus_dmamap_destroy(mpt->sc_dmat, mpt->request_dmap); 307 1.1 thorpej fail_6: 308 1.11 christos bus_dmamem_unmap(mpt->sc_dmat, (void *)mpt->request, PAGE_SIZE); 309 1.1 thorpej fail_5: 310 1.1 thorpej bus_dmamem_free(mpt->sc_dmat, &request_seg, request_rseg); 311 1.1 thorpej fail_4: 312 1.1 thorpej bus_dmamap_unload(mpt->sc_dmat, mpt->reply_dmap); 313 1.1 thorpej fail_3: 314 1.1 thorpej bus_dmamap_destroy(mpt->sc_dmat, mpt->reply_dmap); 315 1.1 thorpej fail_2: 316 1.11 christos bus_dmamem_unmap(mpt->sc_dmat, (void *)mpt->reply, PAGE_SIZE); 317 1.1 thorpej fail_1: 318 1.1 thorpej bus_dmamem_free(mpt->sc_dmat, &reply_seg, reply_rseg); 319 1.1 thorpej fail_0: 320 1.1 thorpej free(mpt->request_pool, M_DEVBUF); 321 1.1 thorpej 322 1.1 thorpej mpt->reply = NULL; 323 1.1 thorpej mpt->request = NULL; 324 1.1 thorpej mpt->request_pool = NULL; 325 1.1 thorpej 326 1.1 thorpej return (error); 327 1.1 thorpej } 328 1.1 thorpej 329 1.1 thorpej int 330 1.1 thorpej mpt_intr(void *arg) 331 1.1 thorpej { 332 1.1 thorpej mpt_softc_t *mpt = arg; 333 1.1 thorpej int nrepl = 0; 334 1.1 thorpej 335 1.1 thorpej if ((mpt_read(mpt, MPT_OFFSET_INTR_STATUS) & MPT_INTR_REPLY_READY) == 0) 336 1.1 thorpej return (0); 337 1.1 thorpej 338 1.21 buhrow nrepl = mpt_drain_queue(mpt); 339 1.1 thorpej return (nrepl != 0); 340 1.1 thorpej } 341 1.1 thorpej 342 1.1 thorpej void 343 1.1 thorpej mpt_prt(mpt_softc_t *mpt, const char *fmt, ...) 344 1.1 thorpej { 345 1.1 thorpej va_list ap; 346 1.1 thorpej 347 1.18 martin printf("%s: ", device_xname(mpt->sc_dev)); 348 1.1 thorpej va_start(ap, fmt); 349 1.1 thorpej vprintf(fmt, ap); 350 1.1 thorpej va_end(ap); 351 1.1 thorpej printf("\n"); 352 1.1 thorpej } 353 1.1 thorpej 354 1.1 thorpej static int 355 1.1 thorpej mpt_poll(mpt_softc_t *mpt, struct scsipi_xfer *xs, int count) 356 1.1 thorpej { 357 1.1 thorpej 358 1.1 thorpej /* Timeouts are in msec, so we loop in 1000usec cycles */ 359 1.1 thorpej while (count) { 360 1.1 thorpej mpt_intr(mpt); 361 1.1 thorpej if (xs->xs_status & XS_STS_DONE) 362 1.1 thorpej return (0); 363 1.1 thorpej delay(1000); /* only happens in boot, so ok */ 364 1.1 thorpej count--; 365 1.1 thorpej } 366 1.1 thorpej return (1); 367 1.1 thorpej } 368 1.1 thorpej 369 1.1 thorpej static void 370 1.1 thorpej mpt_timeout(void *arg) 371 1.1 thorpej { 372 1.1 thorpej request_t *req = arg; 373 1.20 buhrow struct scsipi_xfer *xs; 374 1.20 buhrow struct scsipi_periph *periph; 375 1.20 buhrow mpt_softc_t *mpt; 376 1.20 buhrow uint32_t oseq; 377 1.20 buhrow int s, nrepl = 0; 378 1.20 buhrow 379 1.21 buhrow if (req->xfer == NULL) { 380 1.20 buhrow printf("mpt_timeout: NULL xfer for request index 0x%x, sequenc 0x%x\n", 381 1.20 buhrow req->index, req->sequence); 382 1.20 buhrow return; 383 1.20 buhrow } 384 1.20 buhrow xs = req->xfer; 385 1.21 buhrow periph = xs->xs_periph; 386 1.25 chs mpt = device_private(periph->periph_channel->chan_adapter->adapt_dev); 387 1.1 thorpej scsipi_printaddr(periph); 388 1.1 thorpej printf("command timeout\n"); 389 1.1 thorpej 390 1.1 thorpej s = splbio(); 391 1.1 thorpej 392 1.1 thorpej oseq = req->sequence; 393 1.1 thorpej mpt->timeouts++; 394 1.1 thorpej if (mpt_intr(mpt)) { 395 1.1 thorpej if (req->sequence != oseq) { 396 1.22 buhrow mpt->success++; 397 1.1 thorpej mpt_prt(mpt, "recovered from command timeout"); 398 1.1 thorpej splx(s); 399 1.1 thorpej return; 400 1.1 thorpej } 401 1.1 thorpej } 402 1.20 buhrow 403 1.20 buhrow /* 404 1.22 buhrow * Ensure the IOC is really done giving us data since it appears it can 405 1.22 buhrow * sometimes fail to give us interrupts under heavy load. 406 1.20 buhrow */ 407 1.20 buhrow nrepl = mpt_drain_queue(mpt); 408 1.20 buhrow if (nrepl ) { 409 1.20 buhrow mpt_prt(mpt, "mpt_timeout: recovered %d commands",nrepl); 410 1.20 buhrow } 411 1.20 buhrow 412 1.20 buhrow if (req->sequence != oseq) { 413 1.22 buhrow mpt->success++; 414 1.20 buhrow splx(s); 415 1.20 buhrow return; 416 1.20 buhrow } 417 1.20 buhrow 418 1.1 thorpej mpt_prt(mpt, 419 1.1 thorpej "timeout on request index = 0x%x, seq = 0x%08x", 420 1.1 thorpej req->index, req->sequence); 421 1.1 thorpej mpt_check_doorbell(mpt); 422 1.1 thorpej mpt_prt(mpt, "Status 0x%08x, Mask 0x%08x, Doorbell 0x%08x", 423 1.1 thorpej mpt_read(mpt, MPT_OFFSET_INTR_STATUS), 424 1.1 thorpej mpt_read(mpt, MPT_OFFSET_INTR_MASK), 425 1.1 thorpej mpt_read(mpt, MPT_OFFSET_DOORBELL)); 426 1.1 thorpej mpt_prt(mpt, "request state: %s", mpt_req_state(req->debug)); 427 1.1 thorpej if (mpt->verbose > 1) 428 1.1 thorpej mpt_print_scsi_io_request((MSG_SCSI_IO_REQUEST *)req->req_vbuf); 429 1.1 thorpej 430 1.20 buhrow xs->error = XS_TIMEOUT; 431 1.20 buhrow splx(s); 432 1.20 buhrow mpt_restart(mpt, req); 433 1.20 buhrow } 434 1.20 buhrow 435 1.20 buhrow static void 436 1.20 buhrow mpt_restart(mpt_softc_t *mpt, request_t *req0) 437 1.20 buhrow { 438 1.20 buhrow int i, s, nreq; 439 1.20 buhrow request_t *req; 440 1.20 buhrow struct scsipi_xfer *xs; 441 1.20 buhrow 442 1.20 buhrow /* first, reset the IOC, leaving stopped so all requests are idle */ 443 1.20 buhrow if (mpt_soft_reset(mpt) != MPT_OK) { 444 1.20 buhrow mpt_prt(mpt, "soft reset failed"); 445 1.22 buhrow /* 446 1.22 buhrow * Don't try a hard reset since this mangles the PCI 447 1.22 buhrow * configuration registers. 448 1.22 buhrow */ 449 1.20 buhrow return; 450 1.20 buhrow } 451 1.1 thorpej 452 1.22 buhrow /* Freeze the channel so scsipi doesn't queue more commands. */ 453 1.20 buhrow scsipi_channel_freeze(&mpt->sc_channel, 1); 454 1.6 thorpej 455 1.22 buhrow /* Return all pending requests to scsipi and de-allocate them. */ 456 1.20 buhrow s = splbio(); 457 1.20 buhrow nreq = 0; 458 1.20 buhrow for (i = 0; i < MPT_MAX_REQUESTS(mpt); i++) { 459 1.20 buhrow req = &mpt->request_pool[i]; 460 1.20 buhrow xs = req->xfer; 461 1.20 buhrow if (xs != NULL) { 462 1.20 buhrow if (xs->datalen != 0) 463 1.20 buhrow bus_dmamap_unload(mpt->sc_dmat, req->dmap); 464 1.20 buhrow req->xfer = NULL; 465 1.20 buhrow callout_stop(&xs->xs_callout); 466 1.20 buhrow if (req != req0) { 467 1.20 buhrow nreq++; 468 1.20 buhrow xs->error = XS_REQUEUE; 469 1.20 buhrow } 470 1.20 buhrow scsipi_done(xs); 471 1.22 buhrow /* 472 1.22 buhrow * Don't need to mpt_free_request() since mpt_init() 473 1.22 buhrow * below will free all requests anyway. 474 1.22 buhrow */ 475 1.20 buhrow mpt_free_request(mpt, req); 476 1.20 buhrow } 477 1.20 buhrow } 478 1.1 thorpej splx(s); 479 1.20 buhrow if (nreq > 0) 480 1.20 buhrow mpt_prt(mpt, "re-queued %d requests", nreq); 481 1.20 buhrow 482 1.22 buhrow /* Re-initialize the IOC (which restarts it). */ 483 1.20 buhrow if (mpt_init(mpt, MPT_DB_INIT_HOST) == 0) 484 1.20 buhrow mpt_prt(mpt, "restart succeeded"); 485 1.20 buhrow /* else error message already printed */ 486 1.20 buhrow 487 1.22 buhrow /* Thaw the channel, causing scsipi to re-queue the commands. */ 488 1.20 buhrow scsipi_channel_thaw(&mpt->sc_channel, 1); 489 1.20 buhrow } 490 1.20 buhrow 491 1.22 buhrow static int 492 1.22 buhrow mpt_drain_queue(mpt_softc_t *mpt) 493 1.20 buhrow { 494 1.20 buhrow int nrepl = 0; 495 1.20 buhrow uint32_t reply; 496 1.20 buhrow 497 1.20 buhrow reply = mpt_pop_reply_queue(mpt); 498 1.20 buhrow while (reply != MPT_REPLY_EMPTY) { 499 1.20 buhrow nrepl++; 500 1.20 buhrow if (mpt->verbose > 1) { 501 1.20 buhrow if ((reply & MPT_CONTEXT_REPLY) != 0) { 502 1.20 buhrow /* Address reply; IOC has something to say */ 503 1.20 buhrow mpt_print_reply(MPT_REPLY_PTOV(mpt, reply)); 504 1.20 buhrow } else { 505 1.20 buhrow /* Context reply; all went well */ 506 1.20 buhrow mpt_prt(mpt, "context %u reply OK", reply); 507 1.20 buhrow } 508 1.20 buhrow } 509 1.20 buhrow mpt_done(mpt, reply); 510 1.20 buhrow reply = mpt_pop_reply_queue(mpt); 511 1.20 buhrow } 512 1.20 buhrow return (nrepl); 513 1.1 thorpej } 514 1.1 thorpej 515 1.1 thorpej static void 516 1.1 thorpej mpt_done(mpt_softc_t *mpt, uint32_t reply) 517 1.1 thorpej { 518 1.6 thorpej struct scsipi_xfer *xs = NULL; 519 1.1 thorpej struct scsipi_periph *periph; 520 1.1 thorpej int index; 521 1.1 thorpej request_t *req; 522 1.1 thorpej MSG_REQUEST_HEADER *mpt_req; 523 1.1 thorpej MSG_SCSI_IO_REPLY *mpt_reply; 524 1.22 buhrow int restart = 0; /* nonzero if we need to restart the IOC*/ 525 1.1 thorpej 526 1.1 thorpej if (__predict_true((reply & MPT_CONTEXT_REPLY) == 0)) { 527 1.1 thorpej /* context reply (ok) */ 528 1.1 thorpej mpt_reply = NULL; 529 1.1 thorpej index = reply & MPT_CONTEXT_MASK; 530 1.1 thorpej } else { 531 1.1 thorpej /* address reply (error) */ 532 1.1 thorpej 533 1.1 thorpej /* XXX BUS_DMASYNC_POSTREAD XXX */ 534 1.1 thorpej mpt_reply = MPT_REPLY_PTOV(mpt, reply); 535 1.24 christos if (mpt_reply != NULL) { 536 1.24 christos if (mpt->verbose > 1) { 537 1.24 christos uint32_t *pReply = (uint32_t *) mpt_reply; 538 1.9 perry 539 1.24 christos mpt_prt(mpt, "Address Reply (index %u):", 540 1.24 christos le32toh(mpt_reply->MsgContext) & 0xffff); 541 1.24 christos mpt_prt(mpt, "%08x %08x %08x %08x", pReply[0], 542 1.24 christos pReply[1], pReply[2], pReply[3]); 543 1.24 christos mpt_prt(mpt, "%08x %08x %08x %08x", pReply[4], 544 1.24 christos pReply[5], pReply[6], pReply[7]); 545 1.24 christos mpt_prt(mpt, "%08x %08x %08x %08x", pReply[8], 546 1.24 christos pReply[9], pReply[10], pReply[11]); 547 1.24 christos } 548 1.24 christos index = le32toh(mpt_reply->MsgContext); 549 1.24 christos } else 550 1.24 christos index = reply & MPT_CONTEXT_MASK; 551 1.1 thorpej } 552 1.1 thorpej 553 1.1 thorpej /* 554 1.1 thorpej * Address reply with MessageContext high bit set. 555 1.1 thorpej * This is most likely a notify message, so we try 556 1.1 thorpej * to process it, then free it. 557 1.1 thorpej */ 558 1.1 thorpej if (__predict_false((index & 0x80000000) != 0)) { 559 1.1 thorpej if (mpt_reply != NULL) 560 1.1 thorpej mpt_ctlop(mpt, mpt_reply, reply); 561 1.1 thorpej else 562 1.23 christos mpt_prt(mpt, "%s: index 0x%x, NULL reply", __func__, 563 1.23 christos index); 564 1.1 thorpej return; 565 1.1 thorpej } 566 1.1 thorpej 567 1.1 thorpej /* Did we end up with a valid index into the table? */ 568 1.1 thorpej if (__predict_false(index < 0 || index >= MPT_MAX_REQUESTS(mpt))) { 569 1.23 christos mpt_prt(mpt, "%s: invalid index (0x%x) in reply", __func__, 570 1.23 christos index); 571 1.1 thorpej return; 572 1.1 thorpej } 573 1.1 thorpej 574 1.1 thorpej req = &mpt->request_pool[index]; 575 1.1 thorpej 576 1.1 thorpej /* Make sure memory hasn't been trashed. */ 577 1.1 thorpej if (__predict_false(req->index != index)) { 578 1.23 christos mpt_prt(mpt, "%s: corrupted request_t (0x%x)", __func__, 579 1.23 christos index); 580 1.1 thorpej return; 581 1.1 thorpej } 582 1.1 thorpej 583 1.2 thorpej MPT_SYNC_REQ(mpt, req, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 584 1.1 thorpej mpt_req = req->req_vbuf; 585 1.1 thorpej 586 1.1 thorpej /* Short cut for task management replies; nothing more for us to do. */ 587 1.1 thorpej if (__predict_false(mpt_req->Function == MPI_FUNCTION_SCSI_TASK_MGMT)) { 588 1.1 thorpej if (mpt->verbose > 1) 589 1.23 christos mpt_prt(mpt, "%s: TASK MGMT", __func__); 590 1.21 buhrow KASSERT(req == mpt->mngt_req); 591 1.21 buhrow mpt->mngt_req = NULL; 592 1.1 thorpej goto done; 593 1.1 thorpej } 594 1.1 thorpej 595 1.1 thorpej if (__predict_false(mpt_req->Function == MPI_FUNCTION_PORT_ENABLE)) 596 1.1 thorpej goto done; 597 1.1 thorpej 598 1.1 thorpej /* 599 1.1 thorpej * At this point, it had better be a SCSI I/O command, but don't 600 1.1 thorpej * crash if it isn't. 601 1.1 thorpej */ 602 1.1 thorpej if (__predict_false(mpt_req->Function != 603 1.1 thorpej MPI_FUNCTION_SCSI_IO_REQUEST)) { 604 1.1 thorpej if (mpt->verbose > 1) 605 1.23 christos mpt_prt(mpt, "%s: unknown Function 0x%x (0x%x)", 606 1.23 christos __func__, mpt_req->Function, index); 607 1.1 thorpej goto done; 608 1.1 thorpej } 609 1.1 thorpej 610 1.1 thorpej /* Recover scsipi_xfer from the request structure. */ 611 1.1 thorpej xs = req->xfer; 612 1.1 thorpej 613 1.1 thorpej /* Can't have a SCSI command without a scsipi_xfer. */ 614 1.1 thorpej if (__predict_false(xs == NULL)) { 615 1.1 thorpej mpt_prt(mpt, 616 1.23 christos "%s: no scsipi_xfer, index = 0x%x, seq = 0x%08x", __func__, 617 1.1 thorpej req->index, req->sequence); 618 1.1 thorpej mpt_prt(mpt, "request state: %s", mpt_req_state(req->debug)); 619 1.1 thorpej mpt_prt(mpt, "mpt_request:"); 620 1.1 thorpej mpt_print_scsi_io_request((MSG_SCSI_IO_REQUEST *)req->req_vbuf); 621 1.1 thorpej 622 1.1 thorpej if (mpt_reply != NULL) { 623 1.1 thorpej mpt_prt(mpt, "mpt_reply:"); 624 1.1 thorpej mpt_print_reply(mpt_reply); 625 1.1 thorpej } else { 626 1.1 thorpej mpt_prt(mpt, "context reply: 0x%08x", reply); 627 1.1 thorpej } 628 1.1 thorpej goto done; 629 1.1 thorpej } 630 1.1 thorpej 631 1.1 thorpej callout_stop(&xs->xs_callout); 632 1.1 thorpej 633 1.1 thorpej periph = xs->xs_periph; 634 1.1 thorpej 635 1.1 thorpej /* 636 1.1 thorpej * If we were a data transfer, unload the map that described 637 1.1 thorpej * the data buffer. 638 1.1 thorpej */ 639 1.1 thorpej if (__predict_true(xs->datalen != 0)) { 640 1.1 thorpej bus_dmamap_sync(mpt->sc_dmat, req->dmap, 0, 641 1.1 thorpej req->dmap->dm_mapsize, 642 1.1 thorpej (xs->xs_control & XS_CTL_DATA_IN) ? BUS_DMASYNC_POSTREAD 643 1.1 thorpej : BUS_DMASYNC_POSTWRITE); 644 1.1 thorpej bus_dmamap_unload(mpt->sc_dmat, req->dmap); 645 1.1 thorpej } 646 1.1 thorpej 647 1.1 thorpej if (__predict_true(mpt_reply == NULL)) { 648 1.1 thorpej /* 649 1.1 thorpej * Context reply; report that the command was 650 1.1 thorpej * successful! 651 1.1 thorpej * 652 1.1 thorpej * Also report the xfer mode, if necessary. 653 1.1 thorpej */ 654 1.1 thorpej if (__predict_false(mpt->mpt_report_xfer_mode != 0)) { 655 1.1 thorpej if ((mpt->mpt_report_xfer_mode & 656 1.1 thorpej (1 << periph->periph_target)) != 0) 657 1.1 thorpej mpt_get_xfer_mode(mpt, periph); 658 1.1 thorpej } 659 1.1 thorpej xs->error = XS_NOERROR; 660 1.1 thorpej xs->status = SCSI_OK; 661 1.1 thorpej xs->resid = 0; 662 1.6 thorpej mpt_free_request(mpt, req); 663 1.1 thorpej scsipi_done(xs); 664 1.6 thorpej return; 665 1.1 thorpej } 666 1.1 thorpej 667 1.1 thorpej xs->status = mpt_reply->SCSIStatus; 668 1.22 buhrow switch (le16toh(mpt_reply->IOCStatus) & MPI_IOCSTATUS_MASK) { 669 1.1 thorpej case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: 670 1.1 thorpej xs->error = XS_DRIVER_STUFFUP; 671 1.23 christos mpt_prt(mpt, "%s: IOC overrun!", __func__); 672 1.1 thorpej break; 673 1.1 thorpej 674 1.1 thorpej case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: 675 1.1 thorpej /* 676 1.1 thorpej * Yikes! Tagged queue full comes through this path! 677 1.1 thorpej * 678 1.1 thorpej * So we'll change it to a status error and anything 679 1.1 thorpej * that returns status should probably be a status 680 1.1 thorpej * error as well. 681 1.1 thorpej */ 682 1.15 chs xs->resid = xs->datalen - le32toh(mpt_reply->TransferCount); 683 1.1 thorpej if (mpt_reply->SCSIState & 684 1.1 thorpej MPI_SCSI_STATE_NO_SCSI_STATUS) { 685 1.1 thorpej xs->error = XS_DRIVER_STUFFUP; 686 1.1 thorpej break; 687 1.1 thorpej } 688 1.1 thorpej /* FALLTHROUGH */ 689 1.1 thorpej case MPI_IOCSTATUS_SUCCESS: 690 1.1 thorpej case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: 691 1.1 thorpej switch (xs->status) { 692 1.1 thorpej case SCSI_OK: 693 1.1 thorpej /* Report the xfer mode, if necessary. */ 694 1.1 thorpej if ((mpt->mpt_report_xfer_mode & 695 1.1 thorpej (1 << periph->periph_target)) != 0) 696 1.1 thorpej mpt_get_xfer_mode(mpt, periph); 697 1.1 thorpej xs->resid = 0; 698 1.1 thorpej break; 699 1.1 thorpej 700 1.1 thorpej case SCSI_CHECK: 701 1.1 thorpej xs->error = XS_SENSE; 702 1.1 thorpej break; 703 1.1 thorpej 704 1.1 thorpej case SCSI_BUSY: 705 1.1 thorpej case SCSI_QUEUE_FULL: 706 1.1 thorpej xs->error = XS_BUSY; 707 1.1 thorpej break; 708 1.1 thorpej 709 1.1 thorpej default: 710 1.1 thorpej scsipi_printaddr(periph); 711 1.1 thorpej printf("invalid status code %d\n", xs->status); 712 1.1 thorpej xs->error = XS_DRIVER_STUFFUP; 713 1.1 thorpej break; 714 1.1 thorpej } 715 1.1 thorpej break; 716 1.1 thorpej 717 1.1 thorpej case MPI_IOCSTATUS_BUSY: 718 1.1 thorpej case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: 719 1.1 thorpej xs->error = XS_RESOURCE_SHORTAGE; 720 1.1 thorpej break; 721 1.1 thorpej 722 1.1 thorpej case MPI_IOCSTATUS_SCSI_INVALID_BUS: 723 1.1 thorpej case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: 724 1.1 thorpej case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: 725 1.1 thorpej xs->error = XS_SELTIMEOUT; 726 1.1 thorpej break; 727 1.1 thorpej 728 1.1 thorpej case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: 729 1.1 thorpej xs->error = XS_DRIVER_STUFFUP; 730 1.23 christos mpt_prt(mpt, "%s: IOC SCSI residual mismatch!", __func__); 731 1.20 buhrow restart = 1; 732 1.1 thorpej break; 733 1.1 thorpej 734 1.1 thorpej case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: 735 1.1 thorpej /* XXX What should we do here? */ 736 1.23 christos mpt_prt(mpt, "%s: IOC SCSI task terminated!", __func__); 737 1.20 buhrow restart = 1; 738 1.1 thorpej break; 739 1.1 thorpej 740 1.1 thorpej case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: 741 1.1 thorpej /* XXX */ 742 1.1 thorpej xs->error = XS_DRIVER_STUFFUP; 743 1.23 christos mpt_prt(mpt, "%s: IOC SCSI task failed!", __func__); 744 1.20 buhrow restart = 1; 745 1.1 thorpej break; 746 1.1 thorpej 747 1.1 thorpej case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: 748 1.1 thorpej /* XXX */ 749 1.1 thorpej xs->error = XS_DRIVER_STUFFUP; 750 1.23 christos mpt_prt(mpt, "%s: IOC task terminated!", __func__); 751 1.20 buhrow restart = 1; 752 1.1 thorpej break; 753 1.1 thorpej 754 1.1 thorpej case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: 755 1.1 thorpej /* XXX This is a bus-reset */ 756 1.1 thorpej xs->error = XS_DRIVER_STUFFUP; 757 1.23 christos mpt_prt(mpt, "%s: IOC SCSI bus reset!", __func__); 758 1.20 buhrow restart = 1; 759 1.20 buhrow break; 760 1.20 buhrow 761 1.21 buhrow case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: 762 1.20 buhrow /* 763 1.22 buhrow * FreeBSD and Linux indicate this is a phase error between 764 1.22 buhrow * the IOC and the drive itself. When this happens, the IOC 765 1.23 christos * becomes unhappy and stops processing all transactions. 766 1.23 christos * Call mpt_timeout which knows how to get the IOC back 767 1.23 christos * on its feet. 768 1.20 buhrow */ 769 1.23 christos mpt_prt(mpt, "%s: IOC indicates protocol error -- " 770 1.23 christos "recovering...", __func__); 771 1.20 buhrow xs->error = XS_TIMEOUT; 772 1.20 buhrow restart = 1; 773 1.20 buhrow 774 1.1 thorpej break; 775 1.1 thorpej 776 1.1 thorpej default: 777 1.1 thorpej /* XXX unrecognized HBA error */ 778 1.1 thorpej xs->error = XS_DRIVER_STUFFUP; 779 1.23 christos mpt_prt(mpt, "%s: IOC returned unknown code: 0x%x", __func__, 780 1.23 christos le16toh(mpt_reply->IOCStatus)); 781 1.20 buhrow restart = 1; 782 1.1 thorpej break; 783 1.1 thorpej } 784 1.9 perry 785 1.24 christos if (mpt_reply != NULL) { 786 1.24 christos if (mpt_reply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { 787 1.24 christos memcpy(&xs->sense.scsi_sense, req->sense_vbuf, 788 1.24 christos sizeof(xs->sense.scsi_sense)); 789 1.24 christos } else if (mpt_reply->SCSIState & 790 1.24 christos MPI_SCSI_STATE_AUTOSENSE_FAILED) { 791 1.24 christos /* 792 1.24 christos * This will cause the scsipi layer to issue 793 1.24 christos * a REQUEST SENSE. 794 1.24 christos */ 795 1.24 christos if (xs->status == SCSI_CHECK) 796 1.24 christos xs->error = XS_BUSY; 797 1.24 christos } 798 1.1 thorpej } 799 1.1 thorpej 800 1.1 thorpej done: 801 1.23 christos if (mpt_reply != NULL && le16toh(mpt_reply->IOCStatus) & 802 1.22 buhrow MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { 803 1.23 christos mpt_prt(mpt, "%s: IOC has error - logging...\n", __func__); 804 1.20 buhrow mpt_ctlop(mpt, mpt_reply, reply); 805 1.20 buhrow } 806 1.20 buhrow 807 1.22 buhrow /* If IOC done with this request, free it up. */ 808 1.1 thorpej if (mpt_reply == NULL || (mpt_reply->MsgFlags & 0x80) == 0) 809 1.1 thorpej mpt_free_request(mpt, req); 810 1.1 thorpej 811 1.1 thorpej /* If address reply, give the buffer back to the IOC. */ 812 1.1 thorpej if (mpt_reply != NULL) 813 1.1 thorpej mpt_free_reply(mpt, (reply << 1)); 814 1.6 thorpej 815 1.6 thorpej if (xs != NULL) 816 1.6 thorpej scsipi_done(xs); 817 1.20 buhrow 818 1.20 buhrow if (restart) { 819 1.23 christos mpt_prt(mpt, "%s: IOC fatal error: restarting...", __func__); 820 1.20 buhrow mpt_restart(mpt, NULL); 821 1.20 buhrow } 822 1.1 thorpej } 823 1.1 thorpej 824 1.1 thorpej static void 825 1.1 thorpej mpt_run_xfer(mpt_softc_t *mpt, struct scsipi_xfer *xs) 826 1.1 thorpej { 827 1.1 thorpej struct scsipi_periph *periph = xs->xs_periph; 828 1.1 thorpej request_t *req; 829 1.1 thorpej MSG_SCSI_IO_REQUEST *mpt_req; 830 1.1 thorpej int error, s; 831 1.1 thorpej 832 1.1 thorpej s = splbio(); 833 1.1 thorpej req = mpt_get_request(mpt); 834 1.1 thorpej if (__predict_false(req == NULL)) { 835 1.1 thorpej /* This should happen very infrequently. */ 836 1.1 thorpej xs->error = XS_RESOURCE_SHORTAGE; 837 1.1 thorpej scsipi_done(xs); 838 1.1 thorpej splx(s); 839 1.1 thorpej return; 840 1.1 thorpej } 841 1.1 thorpej splx(s); 842 1.1 thorpej 843 1.1 thorpej /* Link the req and the scsipi_xfer. */ 844 1.1 thorpej req->xfer = xs; 845 1.1 thorpej 846 1.1 thorpej /* Now we build the command for the IOC */ 847 1.1 thorpej mpt_req = req->req_vbuf; 848 1.1 thorpej memset(mpt_req, 0, sizeof(*mpt_req)); 849 1.1 thorpej 850 1.1 thorpej mpt_req->Function = MPI_FUNCTION_SCSI_IO_REQUEST; 851 1.1 thorpej mpt_req->Bus = mpt->bus; 852 1.1 thorpej 853 1.1 thorpej mpt_req->SenseBufferLength = 854 1.1 thorpej (sizeof(xs->sense.scsi_sense) < MPT_SENSE_SIZE) ? 855 1.1 thorpej sizeof(xs->sense.scsi_sense) : MPT_SENSE_SIZE; 856 1.1 thorpej 857 1.1 thorpej /* 858 1.1 thorpej * We use the message context to find the request structure when 859 1.1 thorpej * we get the command completion interrupt from the IOC. 860 1.1 thorpej */ 861 1.15 chs mpt_req->MsgContext = htole32(req->index); 862 1.1 thorpej 863 1.1 thorpej /* Which physical device to do the I/O on. */ 864 1.1 thorpej mpt_req->TargetID = periph->periph_target; 865 1.1 thorpej mpt_req->LUN[1] = periph->periph_lun; 866 1.1 thorpej 867 1.1 thorpej /* Set the direction of the transfer. */ 868 1.1 thorpej if (xs->xs_control & XS_CTL_DATA_IN) 869 1.1 thorpej mpt_req->Control = MPI_SCSIIO_CONTROL_READ; 870 1.1 thorpej else if (xs->xs_control & XS_CTL_DATA_OUT) 871 1.1 thorpej mpt_req->Control = MPI_SCSIIO_CONTROL_WRITE; 872 1.1 thorpej else 873 1.1 thorpej mpt_req->Control = MPI_SCSIIO_CONTROL_NODATATRANSFER; 874 1.1 thorpej 875 1.1 thorpej /* Set the queue behavior. */ 876 1.12 tron if (__predict_true((!mpt->is_scsi) || 877 1.1 thorpej (mpt->mpt_tag_enable & 878 1.1 thorpej (1 << periph->periph_target)))) { 879 1.1 thorpej switch (XS_CTL_TAGTYPE(xs)) { 880 1.1 thorpej case XS_CTL_HEAD_TAG: 881 1.1 thorpej mpt_req->Control |= MPI_SCSIIO_CONTROL_HEADOFQ; 882 1.1 thorpej break; 883 1.1 thorpej 884 1.1 thorpej #if 0 /* XXX */ 885 1.1 thorpej case XS_CTL_ACA_TAG: 886 1.1 thorpej mpt_req->Control |= MPI_SCSIIO_CONTROL_ACAQ; 887 1.1 thorpej break; 888 1.1 thorpej #endif 889 1.1 thorpej 890 1.1 thorpej case XS_CTL_ORDERED_TAG: 891 1.1 thorpej mpt_req->Control |= MPI_SCSIIO_CONTROL_ORDEREDQ; 892 1.1 thorpej break; 893 1.1 thorpej 894 1.1 thorpej case XS_CTL_SIMPLE_TAG: 895 1.1 thorpej mpt_req->Control |= MPI_SCSIIO_CONTROL_SIMPLEQ; 896 1.1 thorpej break; 897 1.1 thorpej 898 1.1 thorpej default: 899 1.12 tron if (mpt->is_scsi) 900 1.12 tron mpt_req->Control |= MPI_SCSIIO_CONTROL_UNTAGGED; 901 1.12 tron else 902 1.1 thorpej mpt_req->Control |= MPI_SCSIIO_CONTROL_SIMPLEQ; 903 1.1 thorpej break; 904 1.1 thorpej } 905 1.1 thorpej } else 906 1.1 thorpej mpt_req->Control |= MPI_SCSIIO_CONTROL_UNTAGGED; 907 1.1 thorpej 908 1.12 tron if (__predict_false(mpt->is_scsi && 909 1.1 thorpej (mpt->mpt_disc_enable & 910 1.1 thorpej (1 << periph->periph_target)) == 0)) 911 1.1 thorpej mpt_req->Control |= MPI_SCSIIO_CONTROL_NO_DISCONNECT; 912 1.1 thorpej 913 1.15 chs mpt_req->Control = htole32(mpt_req->Control); 914 1.15 chs 915 1.1 thorpej /* Copy the SCSI command block into place. */ 916 1.1 thorpej memcpy(mpt_req->CDB, xs->cmd, xs->cmdlen); 917 1.1 thorpej 918 1.1 thorpej mpt_req->CDBLength = xs->cmdlen; 919 1.15 chs mpt_req->DataLength = htole32(xs->datalen); 920 1.15 chs mpt_req->SenseBufferLowAddr = htole32(req->sense_pbuf); 921 1.1 thorpej 922 1.1 thorpej /* 923 1.1 thorpej * Map the DMA transfer. 924 1.1 thorpej */ 925 1.1 thorpej if (xs->datalen) { 926 1.1 thorpej SGE_SIMPLE32 *se; 927 1.1 thorpej 928 1.1 thorpej error = bus_dmamap_load(mpt->sc_dmat, req->dmap, xs->data, 929 1.1 thorpej xs->datalen, NULL, 930 1.1 thorpej ((xs->xs_control & XS_CTL_NOSLEEP) ? BUS_DMA_NOWAIT 931 1.1 thorpej : BUS_DMA_WAITOK) | 932 1.1 thorpej BUS_DMA_STREAMING | 933 1.1 thorpej ((xs->xs_control & XS_CTL_DATA_IN) ? BUS_DMA_READ 934 1.1 thorpej : BUS_DMA_WRITE)); 935 1.1 thorpej switch (error) { 936 1.1 thorpej case 0: 937 1.1 thorpej break; 938 1.1 thorpej 939 1.1 thorpej case ENOMEM: 940 1.1 thorpej case EAGAIN: 941 1.1 thorpej xs->error = XS_RESOURCE_SHORTAGE; 942 1.1 thorpej goto out_bad; 943 1.1 thorpej 944 1.1 thorpej default: 945 1.1 thorpej xs->error = XS_DRIVER_STUFFUP; 946 1.1 thorpej mpt_prt(mpt, "error %d loading DMA map", error); 947 1.1 thorpej out_bad: 948 1.1 thorpej s = splbio(); 949 1.1 thorpej mpt_free_request(mpt, req); 950 1.1 thorpej scsipi_done(xs); 951 1.1 thorpej splx(s); 952 1.1 thorpej return; 953 1.1 thorpej } 954 1.1 thorpej 955 1.1 thorpej if (req->dmap->dm_nsegs > MPT_NSGL_FIRST(mpt)) { 956 1.1 thorpej int seg, i, nleft = req->dmap->dm_nsegs; 957 1.1 thorpej uint32_t flags; 958 1.1 thorpej SGE_CHAIN32 *ce; 959 1.1 thorpej 960 1.1 thorpej seg = 0; 961 1.1 thorpej flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT; 962 1.1 thorpej if (xs->xs_control & XS_CTL_DATA_OUT) 963 1.1 thorpej flags |= MPI_SGE_FLAGS_HOST_TO_IOC; 964 1.1 thorpej 965 1.1 thorpej se = (SGE_SIMPLE32 *) &mpt_req->SGL; 966 1.1 thorpej for (i = 0; i < MPT_NSGL_FIRST(mpt) - 1; 967 1.1 thorpej i++, se++, seg++) { 968 1.1 thorpej uint32_t tf; 969 1.1 thorpej 970 1.1 thorpej memset(se, 0, sizeof(*se)); 971 1.15 chs se->Address = 972 1.15 chs htole32(req->dmap->dm_segs[seg].ds_addr); 973 1.1 thorpej MPI_pSGE_SET_LENGTH(se, 974 1.1 thorpej req->dmap->dm_segs[seg].ds_len); 975 1.1 thorpej tf = flags; 976 1.1 thorpej if (i == MPT_NSGL_FIRST(mpt) - 2) 977 1.1 thorpej tf |= MPI_SGE_FLAGS_LAST_ELEMENT; 978 1.1 thorpej MPI_pSGE_SET_FLAGS(se, tf); 979 1.15 chs se->FlagsLength = htole32(se->FlagsLength); 980 1.1 thorpej nleft--; 981 1.1 thorpej } 982 1.1 thorpej 983 1.1 thorpej /* 984 1.1 thorpej * Tell the IOC where to find the first chain element. 985 1.1 thorpej */ 986 1.1 thorpej mpt_req->ChainOffset = 987 1.1 thorpej ((char *)se - (char *)mpt_req) >> 2; 988 1.1 thorpej 989 1.1 thorpej /* 990 1.1 thorpej * Until we're finished with all segments... 991 1.1 thorpej */ 992 1.1 thorpej while (nleft) { 993 1.1 thorpej int ntodo; 994 1.1 thorpej 995 1.1 thorpej /* 996 1.1 thorpej * Construct the chain element that points to 997 1.1 thorpej * the next segment. 998 1.1 thorpej */ 999 1.1 thorpej ce = (SGE_CHAIN32 *) se++; 1000 1.1 thorpej if (nleft > MPT_NSGL(mpt)) { 1001 1.1 thorpej ntodo = MPT_NSGL(mpt) - 1; 1002 1.1 thorpej ce->NextChainOffset = (MPT_RQSL(mpt) - 1003 1.1 thorpej sizeof(SGE_SIMPLE32)) >> 2; 1004 1.15 chs ce->Length = htole16(MPT_NSGL(mpt) 1005 1.15 chs * sizeof(SGE_SIMPLE32)); 1006 1.1 thorpej } else { 1007 1.1 thorpej ntodo = nleft; 1008 1.1 thorpej ce->NextChainOffset = 0; 1009 1.15 chs ce->Length = htole16(ntodo 1010 1.15 chs * sizeof(SGE_SIMPLE32)); 1011 1.1 thorpej } 1012 1.15 chs ce->Address = htole32(req->req_pbuf + 1013 1.15 chs ((char *)se - (char *)mpt_req)); 1014 1.1 thorpej ce->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT; 1015 1.1 thorpej for (i = 0; i < ntodo; i++, se++, seg++) { 1016 1.1 thorpej uint32_t tf; 1017 1.1 thorpej 1018 1.1 thorpej memset(se, 0, sizeof(*se)); 1019 1.15 chs se->Address = htole32( 1020 1.15 chs req->dmap->dm_segs[seg].ds_addr); 1021 1.1 thorpej MPI_pSGE_SET_LENGTH(se, 1022 1.1 thorpej req->dmap->dm_segs[seg].ds_len); 1023 1.1 thorpej tf = flags; 1024 1.1 thorpej if (i == ntodo - 1) { 1025 1.1 thorpej tf |= 1026 1.1 thorpej MPI_SGE_FLAGS_LAST_ELEMENT; 1027 1.1 thorpej if (ce->NextChainOffset == 0) { 1028 1.1 thorpej tf |= 1029 1.1 thorpej MPI_SGE_FLAGS_END_OF_LIST | 1030 1.1 thorpej MPI_SGE_FLAGS_END_OF_BUFFER; 1031 1.1 thorpej } 1032 1.1 thorpej } 1033 1.1 thorpej MPI_pSGE_SET_FLAGS(se, tf); 1034 1.15 chs se->FlagsLength = 1035 1.15 chs htole32(se->FlagsLength); 1036 1.1 thorpej nleft--; 1037 1.1 thorpej } 1038 1.1 thorpej } 1039 1.1 thorpej bus_dmamap_sync(mpt->sc_dmat, req->dmap, 0, 1040 1.1 thorpej req->dmap->dm_mapsize, 1041 1.1 thorpej (xs->xs_control & XS_CTL_DATA_IN) ? 1042 1.1 thorpej BUS_DMASYNC_PREREAD 1043 1.1 thorpej : BUS_DMASYNC_PREWRITE); 1044 1.1 thorpej } else { 1045 1.1 thorpej int i; 1046 1.1 thorpej uint32_t flags; 1047 1.1 thorpej 1048 1.1 thorpej flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT; 1049 1.1 thorpej if (xs->xs_control & XS_CTL_DATA_OUT) 1050 1.1 thorpej flags |= MPI_SGE_FLAGS_HOST_TO_IOC; 1051 1.1 thorpej 1052 1.1 thorpej /* Copy the segments into our SG list. */ 1053 1.1 thorpej se = (SGE_SIMPLE32 *) &mpt_req->SGL; 1054 1.1 thorpej for (i = 0; i < req->dmap->dm_nsegs; 1055 1.1 thorpej i++, se++) { 1056 1.1 thorpej uint32_t tf; 1057 1.1 thorpej 1058 1.1 thorpej memset(se, 0, sizeof(*se)); 1059 1.15 chs se->Address = 1060 1.15 chs htole32(req->dmap->dm_segs[i].ds_addr); 1061 1.1 thorpej MPI_pSGE_SET_LENGTH(se, 1062 1.1 thorpej req->dmap->dm_segs[i].ds_len); 1063 1.1 thorpej tf = flags; 1064 1.1 thorpej if (i == req->dmap->dm_nsegs - 1) { 1065 1.1 thorpej tf |= 1066 1.1 thorpej MPI_SGE_FLAGS_LAST_ELEMENT | 1067 1.1 thorpej MPI_SGE_FLAGS_END_OF_BUFFER | 1068 1.1 thorpej MPI_SGE_FLAGS_END_OF_LIST; 1069 1.1 thorpej } 1070 1.1 thorpej MPI_pSGE_SET_FLAGS(se, tf); 1071 1.15 chs se->FlagsLength = htole32(se->FlagsLength); 1072 1.1 thorpej } 1073 1.1 thorpej bus_dmamap_sync(mpt->sc_dmat, req->dmap, 0, 1074 1.1 thorpej req->dmap->dm_mapsize, 1075 1.1 thorpej (xs->xs_control & XS_CTL_DATA_IN) ? 1076 1.1 thorpej BUS_DMASYNC_PREREAD 1077 1.1 thorpej : BUS_DMASYNC_PREWRITE); 1078 1.1 thorpej } 1079 1.1 thorpej } else { 1080 1.1 thorpej /* 1081 1.1 thorpej * No data to transfer; just make a single simple SGL 1082 1.1 thorpej * with zero length. 1083 1.1 thorpej */ 1084 1.1 thorpej SGE_SIMPLE32 *se = (SGE_SIMPLE32 *) &mpt_req->SGL; 1085 1.1 thorpej memset(se, 0, sizeof(*se)); 1086 1.1 thorpej MPI_pSGE_SET_FLAGS(se, 1087 1.1 thorpej (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 1088 1.1 thorpej MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST)); 1089 1.15 chs se->FlagsLength = htole32(se->FlagsLength); 1090 1.1 thorpej } 1091 1.1 thorpej 1092 1.1 thorpej if (mpt->verbose > 1) 1093 1.1 thorpej mpt_print_scsi_io_request(mpt_req); 1094 1.1 thorpej 1095 1.35 mrg if (xs->timeout == 0) { 1096 1.35 mrg mpt_prt(mpt, "mpt_run_xfer: no timeout specified for request: 0x%x\n", 1097 1.20 buhrow req->index); 1098 1.35 mrg xs->timeout = 500; 1099 1.35 mrg } 1100 1.20 buhrow 1101 1.1 thorpej s = splbio(); 1102 1.1 thorpej if (__predict_true((xs->xs_control & XS_CTL_POLL) == 0)) 1103 1.1 thorpej callout_reset(&xs->xs_callout, 1104 1.1 thorpej mstohz(xs->timeout), mpt_timeout, req); 1105 1.1 thorpej mpt_send_cmd(mpt, req); 1106 1.1 thorpej splx(s); 1107 1.1 thorpej 1108 1.1 thorpej if (__predict_true((xs->xs_control & XS_CTL_POLL) == 0)) 1109 1.1 thorpej return; 1110 1.1 thorpej 1111 1.1 thorpej /* 1112 1.1 thorpej * If we can't use interrupts, poll on completion. 1113 1.1 thorpej */ 1114 1.4 thorpej if (mpt_poll(mpt, xs, xs->timeout)) 1115 1.1 thorpej mpt_timeout(req); 1116 1.1 thorpej } 1117 1.1 thorpej 1118 1.1 thorpej static void 1119 1.1 thorpej mpt_set_xfer_mode(mpt_softc_t *mpt, struct scsipi_xfer_mode *xm) 1120 1.1 thorpej { 1121 1.1 thorpej fCONFIG_PAGE_SCSI_DEVICE_1 tmp; 1122 1.1 thorpej 1123 1.1 thorpej if (xm->xm_mode & PERIPH_CAP_TQING) 1124 1.1 thorpej mpt->mpt_tag_enable |= (1 << xm->xm_target); 1125 1.1 thorpej else 1126 1.1 thorpej mpt->mpt_tag_enable &= ~(1 << xm->xm_target); 1127 1.1 thorpej 1128 1.17 mhitch if (mpt->is_scsi) { 1129 1.17 mhitch /* 1130 1.34 jakllsch * Always allow disconnect; we don't have a way to disable 1131 1.34 jakllsch * it right now, in any case. 1132 1.34 jakllsch */ 1133 1.34 jakllsch mpt->mpt_disc_enable |= (1 << xm->xm_target); 1134 1.34 jakllsch 1135 1.34 jakllsch /* 1136 1.17 mhitch * SCSI transport settings only make any sense for 1137 1.17 mhitch * SCSI 1138 1.17 mhitch */ 1139 1.17 mhitch 1140 1.17 mhitch tmp = mpt->mpt_dev_page1[xm->xm_target]; 1141 1.1 thorpej 1142 1.17 mhitch /* 1143 1.17 mhitch * Set the wide/narrow parameter for the target. 1144 1.17 mhitch */ 1145 1.17 mhitch if (xm->xm_mode & PERIPH_CAP_WIDE16) 1146 1.17 mhitch tmp.RequestedParameters |= MPI_SCSIDEVPAGE1_RP_WIDE; 1147 1.17 mhitch else 1148 1.17 mhitch tmp.RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_WIDE; 1149 1.1 thorpej 1150 1.17 mhitch /* 1151 1.17 mhitch * Set the synchronous parameters for the target. 1152 1.17 mhitch * 1153 1.17 mhitch * XXX If we request sync transfers, we just go ahead and 1154 1.17 mhitch * XXX request the maximum available. We need finer control 1155 1.17 mhitch * XXX in order to implement Domain Validation. 1156 1.17 mhitch */ 1157 1.17 mhitch tmp.RequestedParameters &= ~(MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK | 1158 1.17 mhitch MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK | 1159 1.17 mhitch MPI_SCSIDEVPAGE1_RP_DT | MPI_SCSIDEVPAGE1_RP_QAS | 1160 1.17 mhitch MPI_SCSIDEVPAGE1_RP_IU); 1161 1.17 mhitch if (xm->xm_mode & PERIPH_CAP_SYNC) { 1162 1.17 mhitch int factor, offset, np; 1163 1.17 mhitch 1164 1.17 mhitch factor = (mpt->mpt_port_page0.Capabilities >> 8) & 0xff; 1165 1.17 mhitch offset = (mpt->mpt_port_page0.Capabilities >> 16) & 0xff; 1166 1.17 mhitch np = 0; 1167 1.17 mhitch if (factor < 0x9) { 1168 1.17 mhitch /* Ultra320 */ 1169 1.17 mhitch np |= MPI_SCSIDEVPAGE1_RP_QAS | MPI_SCSIDEVPAGE1_RP_IU; 1170 1.17 mhitch } 1171 1.17 mhitch if (factor < 0xa) { 1172 1.17 mhitch /* at least Ultra160 */ 1173 1.17 mhitch np |= MPI_SCSIDEVPAGE1_RP_DT; 1174 1.17 mhitch } 1175 1.17 mhitch np |= (factor << 8) | (offset << 16); 1176 1.17 mhitch tmp.RequestedParameters |= np; 1177 1.1 thorpej } 1178 1.17 mhitch 1179 1.17 mhitch host2mpt_config_page_scsi_device_1(&tmp); 1180 1.17 mhitch if (mpt_write_cfg_page(mpt, xm->xm_target, &tmp.Header)) { 1181 1.17 mhitch mpt_prt(mpt, "unable to write Device Page 1"); 1182 1.17 mhitch return; 1183 1.1 thorpej } 1184 1.1 thorpej 1185 1.17 mhitch if (mpt_read_cfg_page(mpt, xm->xm_target, &tmp.Header)) { 1186 1.17 mhitch mpt_prt(mpt, "unable to read back Device Page 1"); 1187 1.17 mhitch return; 1188 1.17 mhitch } 1189 1.1 thorpej 1190 1.17 mhitch mpt2host_config_page_scsi_device_1(&tmp); 1191 1.17 mhitch mpt->mpt_dev_page1[xm->xm_target] = tmp; 1192 1.17 mhitch if (mpt->verbose > 1) { 1193 1.17 mhitch mpt_prt(mpt, 1194 1.17 mhitch "SPI Target %d Page 1: RequestedParameters %x Config %x", 1195 1.17 mhitch xm->xm_target, 1196 1.17 mhitch mpt->mpt_dev_page1[xm->xm_target].RequestedParameters, 1197 1.17 mhitch mpt->mpt_dev_page1[xm->xm_target].Configuration); 1198 1.17 mhitch } 1199 1.1 thorpej } 1200 1.1 thorpej 1201 1.1 thorpej /* 1202 1.1 thorpej * Make a note that we should perform an async callback at the 1203 1.1 thorpej * end of the next successful command completion to report the 1204 1.1 thorpej * negotiated transfer mode. 1205 1.1 thorpej */ 1206 1.1 thorpej mpt->mpt_report_xfer_mode |= (1 << xm->xm_target); 1207 1.1 thorpej } 1208 1.1 thorpej 1209 1.1 thorpej static void 1210 1.1 thorpej mpt_get_xfer_mode(mpt_softc_t *mpt, struct scsipi_periph *periph) 1211 1.1 thorpej { 1212 1.1 thorpej fCONFIG_PAGE_SCSI_DEVICE_0 tmp; 1213 1.1 thorpej struct scsipi_xfer_mode xm; 1214 1.1 thorpej int period, offset; 1215 1.1 thorpej 1216 1.1 thorpej tmp = mpt->mpt_dev_page0[periph->periph_target]; 1217 1.15 chs host2mpt_config_page_scsi_device_0(&tmp); 1218 1.1 thorpej if (mpt_read_cfg_page(mpt, periph->periph_target, &tmp.Header)) { 1219 1.1 thorpej mpt_prt(mpt, "unable to read Device Page 0"); 1220 1.1 thorpej return; 1221 1.1 thorpej } 1222 1.15 chs mpt2host_config_page_scsi_device_0(&tmp); 1223 1.1 thorpej 1224 1.1 thorpej if (mpt->verbose > 1) { 1225 1.1 thorpej mpt_prt(mpt, 1226 1.1 thorpej "SPI Tgt %d Page 0: NParms %x Information %x", 1227 1.1 thorpej periph->periph_target, 1228 1.1 thorpej tmp.NegotiatedParameters, tmp.Information); 1229 1.1 thorpej } 1230 1.1 thorpej 1231 1.1 thorpej xm.xm_target = periph->periph_target; 1232 1.1 thorpej xm.xm_mode = 0; 1233 1.1 thorpej 1234 1.1 thorpej if (tmp.NegotiatedParameters & MPI_SCSIDEVPAGE0_NP_WIDE) 1235 1.1 thorpej xm.xm_mode |= PERIPH_CAP_WIDE16; 1236 1.1 thorpej 1237 1.1 thorpej period = (tmp.NegotiatedParameters >> 8) & 0xff; 1238 1.1 thorpej offset = (tmp.NegotiatedParameters >> 16) & 0xff; 1239 1.1 thorpej if (offset) { 1240 1.1 thorpej xm.xm_period = period; 1241 1.1 thorpej xm.xm_offset = offset; 1242 1.1 thorpej xm.xm_mode |= PERIPH_CAP_SYNC; 1243 1.1 thorpej } 1244 1.1 thorpej 1245 1.1 thorpej /* 1246 1.1 thorpej * Tagged queueing is all controlled by us; there is no 1247 1.1 thorpej * other setting to query. 1248 1.1 thorpej */ 1249 1.1 thorpej if (mpt->mpt_tag_enable & (1 << periph->periph_target)) 1250 1.1 thorpej xm.xm_mode |= PERIPH_CAP_TQING; 1251 1.1 thorpej 1252 1.1 thorpej /* 1253 1.1 thorpej * We're going to deliver the async event, so clear the marker. 1254 1.1 thorpej */ 1255 1.1 thorpej mpt->mpt_report_xfer_mode &= ~(1 << periph->periph_target); 1256 1.1 thorpej 1257 1.1 thorpej scsipi_async_event(&mpt->sc_channel, ASYNC_EVENT_XFER_MODE, &xm); 1258 1.1 thorpej } 1259 1.1 thorpej 1260 1.1 thorpej static void 1261 1.1 thorpej mpt_ctlop(mpt_softc_t *mpt, void *vmsg, uint32_t reply) 1262 1.1 thorpej { 1263 1.1 thorpej MSG_DEFAULT_REPLY *dmsg = vmsg; 1264 1.1 thorpej 1265 1.1 thorpej switch (dmsg->Function) { 1266 1.1 thorpej case MPI_FUNCTION_EVENT_NOTIFICATION: 1267 1.1 thorpej mpt_event_notify_reply(mpt, vmsg); 1268 1.1 thorpej mpt_free_reply(mpt, (reply << 1)); 1269 1.1 thorpej break; 1270 1.1 thorpej 1271 1.1 thorpej case MPI_FUNCTION_EVENT_ACK: 1272 1.32 hannken { 1273 1.32 hannken MSG_EVENT_ACK_REPLY *msg = vmsg; 1274 1.32 hannken int index = le32toh(msg->MsgContext) & ~0x80000000; 1275 1.1 thorpej mpt_free_reply(mpt, (reply << 1)); 1276 1.32 hannken if (index >= 0 && index < MPT_MAX_REQUESTS(mpt)) { 1277 1.32 hannken request_t *req = &mpt->request_pool[index]; 1278 1.32 hannken mpt_free_request(mpt, req); 1279 1.32 hannken } 1280 1.1 thorpej break; 1281 1.32 hannken } 1282 1.1 thorpej 1283 1.1 thorpej case MPI_FUNCTION_PORT_ENABLE: 1284 1.1 thorpej { 1285 1.1 thorpej MSG_PORT_ENABLE_REPLY *msg = vmsg; 1286 1.15 chs int index = le32toh(msg->MsgContext) & ~0x80000000; 1287 1.1 thorpej if (mpt->verbose > 1) 1288 1.1 thorpej mpt_prt(mpt, "enable port reply index %d", index); 1289 1.1 thorpej if (index >= 0 && index < MPT_MAX_REQUESTS(mpt)) { 1290 1.1 thorpej request_t *req = &mpt->request_pool[index]; 1291 1.1 thorpej req->debug = REQ_DONE; 1292 1.1 thorpej } 1293 1.1 thorpej mpt_free_reply(mpt, (reply << 1)); 1294 1.1 thorpej break; 1295 1.1 thorpej } 1296 1.1 thorpej 1297 1.1 thorpej case MPI_FUNCTION_CONFIG: 1298 1.1 thorpej { 1299 1.1 thorpej MSG_CONFIG_REPLY *msg = vmsg; 1300 1.15 chs int index = le32toh(msg->MsgContext) & ~0x80000000; 1301 1.1 thorpej if (index >= 0 && index < MPT_MAX_REQUESTS(mpt)) { 1302 1.1 thorpej request_t *req = &mpt->request_pool[index]; 1303 1.1 thorpej req->debug = REQ_DONE; 1304 1.1 thorpej req->sequence = reply; 1305 1.1 thorpej } else 1306 1.1 thorpej mpt_free_reply(mpt, (reply << 1)); 1307 1.1 thorpej break; 1308 1.1 thorpej } 1309 1.1 thorpej 1310 1.1 thorpej default: 1311 1.1 thorpej mpt_prt(mpt, "unknown ctlop: 0x%x", dmsg->Function); 1312 1.1 thorpej } 1313 1.1 thorpej } 1314 1.1 thorpej 1315 1.1 thorpej static void 1316 1.1 thorpej mpt_event_notify_reply(mpt_softc_t *mpt, MSG_EVENT_NOTIFY_REPLY *msg) 1317 1.1 thorpej { 1318 1.1 thorpej 1319 1.15 chs switch (le32toh(msg->Event)) { 1320 1.1 thorpej case MPI_EVENT_LOG_DATA: 1321 1.1 thorpej { 1322 1.1 thorpej int i; 1323 1.1 thorpej 1324 1.1 thorpej /* Some error occurrerd that the Fusion wants logged. */ 1325 1.1 thorpej mpt_prt(mpt, "EvtLogData: IOCLogInfo: 0x%08x", msg->IOCLogInfo); 1326 1.1 thorpej mpt_prt(mpt, "EvtLogData: Event Data:"); 1327 1.1 thorpej for (i = 0; i < msg->EventDataLength; i++) { 1328 1.1 thorpej if ((i % 4) == 0) 1329 1.18 martin printf("%s:\t", device_xname(mpt->sc_dev)); 1330 1.1 thorpej printf("0x%08x%c", msg->Data[i], 1331 1.1 thorpej ((i % 4) == 3) ? '\n' : ' '); 1332 1.1 thorpej } 1333 1.1 thorpej if ((i % 4) != 0) 1334 1.1 thorpej printf("\n"); 1335 1.1 thorpej break; 1336 1.1 thorpej } 1337 1.1 thorpej 1338 1.1 thorpej case MPI_EVENT_UNIT_ATTENTION: 1339 1.1 thorpej mpt_prt(mpt, "Unit Attn: Bus 0x%02x Target 0x%02x", 1340 1.1 thorpej (msg->Data[0] >> 8) & 0xff, msg->Data[0] & 0xff); 1341 1.1 thorpej break; 1342 1.1 thorpej 1343 1.1 thorpej case MPI_EVENT_IOC_BUS_RESET: 1344 1.1 thorpej /* We generated a bus reset. */ 1345 1.1 thorpej mpt_prt(mpt, "IOC Bus Reset Port %d", 1346 1.1 thorpej (msg->Data[0] >> 8) & 0xff); 1347 1.1 thorpej break; 1348 1.1 thorpej 1349 1.1 thorpej case MPI_EVENT_EXT_BUS_RESET: 1350 1.1 thorpej /* Someone else generated a bus reset. */ 1351 1.1 thorpej mpt_prt(mpt, "External Bus Reset"); 1352 1.1 thorpej /* 1353 1.1 thorpej * These replies don't return EventData like the MPI 1354 1.1 thorpej * spec says they do. 1355 1.1 thorpej */ 1356 1.1 thorpej /* XXX Send an async event? */ 1357 1.1 thorpej break; 1358 1.1 thorpej 1359 1.1 thorpej case MPI_EVENT_RESCAN: 1360 1.1 thorpej /* 1361 1.40 andvar * In general, this means a device has been added 1362 1.1 thorpej * to the loop. 1363 1.1 thorpej */ 1364 1.1 thorpej mpt_prt(mpt, "Rescan Port %d", (msg->Data[0] >> 8) & 0xff); 1365 1.1 thorpej /* XXX Send an async event? */ 1366 1.1 thorpej break; 1367 1.1 thorpej 1368 1.1 thorpej case MPI_EVENT_LINK_STATUS_CHANGE: 1369 1.1 thorpej mpt_prt(mpt, "Port %d: Link state %s", 1370 1.1 thorpej (msg->Data[1] >> 8) & 0xff, 1371 1.1 thorpej (msg->Data[0] & 0xff) == 0 ? "Failed" : "Active"); 1372 1.1 thorpej break; 1373 1.1 thorpej 1374 1.1 thorpej case MPI_EVENT_LOOP_STATE_CHANGE: 1375 1.1 thorpej switch ((msg->Data[0] >> 16) & 0xff) { 1376 1.1 thorpej case 0x01: 1377 1.1 thorpej mpt_prt(mpt, 1378 1.1 thorpej "Port %d: FC Link Event: LIP(%02x,%02x) " 1379 1.1 thorpej "(Loop Initialization)", 1380 1.1 thorpej (msg->Data[1] >> 8) & 0xff, 1381 1.1 thorpej (msg->Data[0] >> 8) & 0xff, 1382 1.1 thorpej (msg->Data[0] ) & 0xff); 1383 1.1 thorpej switch ((msg->Data[0] >> 8) & 0xff) { 1384 1.1 thorpej case 0xf7: 1385 1.1 thorpej if ((msg->Data[0] & 0xff) == 0xf7) 1386 1.1 thorpej mpt_prt(mpt, "\tDevice needs AL_PA"); 1387 1.1 thorpej else 1388 1.1 thorpej mpt_prt(mpt, "\tDevice %02x doesn't " 1389 1.1 thorpej "like FC performance", 1390 1.1 thorpej msg->Data[0] & 0xff); 1391 1.1 thorpej break; 1392 1.1 thorpej 1393 1.1 thorpej case 0xf8: 1394 1.1 thorpej if ((msg->Data[0] & 0xff) == 0xf7) 1395 1.1 thorpej mpt_prt(mpt, "\tDevice detected loop " 1396 1.1 thorpej "failure before acquiring AL_PA"); 1397 1.1 thorpej else 1398 1.1 thorpej mpt_prt(mpt, "\tDevice %02x detected " 1399 1.1 thorpej "loop failure", 1400 1.1 thorpej msg->Data[0] & 0xff); 1401 1.1 thorpej break; 1402 1.1 thorpej 1403 1.1 thorpej default: 1404 1.1 thorpej mpt_prt(mpt, "\tDevice %02x requests that " 1405 1.1 thorpej "device %02x reset itself", 1406 1.1 thorpej msg->Data[0] & 0xff, 1407 1.1 thorpej (msg->Data[0] >> 8) & 0xff); 1408 1.1 thorpej break; 1409 1.1 thorpej } 1410 1.1 thorpej break; 1411 1.1 thorpej 1412 1.1 thorpej case 0x02: 1413 1.1 thorpej mpt_prt(mpt, "Port %d: FC Link Event: LPE(%02x,%02x) " 1414 1.1 thorpej "(Loop Port Enable)", 1415 1.1 thorpej (msg->Data[1] >> 8) & 0xff, 1416 1.1 thorpej (msg->Data[0] >> 8) & 0xff, 1417 1.1 thorpej (msg->Data[0] ) & 0xff); 1418 1.1 thorpej break; 1419 1.1 thorpej 1420 1.1 thorpej case 0x03: 1421 1.1 thorpej mpt_prt(mpt, "Port %d: FC Link Event: LPB(%02x,%02x) " 1422 1.1 thorpej "(Loop Port Bypass)", 1423 1.1 thorpej (msg->Data[1] >> 8) & 0xff, 1424 1.1 thorpej (msg->Data[0] >> 8) & 0xff, 1425 1.1 thorpej (msg->Data[0] ) & 0xff); 1426 1.1 thorpej break; 1427 1.1 thorpej 1428 1.1 thorpej default: 1429 1.1 thorpej mpt_prt(mpt, "Port %d: FC Link Event: " 1430 1.1 thorpej "Unknown event (%02x %02x %02x)", 1431 1.1 thorpej (msg->Data[1] >> 8) & 0xff, 1432 1.1 thorpej (msg->Data[0] >> 16) & 0xff, 1433 1.1 thorpej (msg->Data[0] >> 8) & 0xff, 1434 1.1 thorpej (msg->Data[0] ) & 0xff); 1435 1.1 thorpej break; 1436 1.1 thorpej } 1437 1.1 thorpej break; 1438 1.1 thorpej 1439 1.1 thorpej case MPI_EVENT_LOGOUT: 1440 1.1 thorpej mpt_prt(mpt, "Port %d: FC Logout: N_PortID: %02x", 1441 1.1 thorpej (msg->Data[1] >> 8) & 0xff, msg->Data[0]); 1442 1.1 thorpej break; 1443 1.1 thorpej 1444 1.1 thorpej case MPI_EVENT_EVENT_CHANGE: 1445 1.1 thorpej /* 1446 1.1 thorpej * This is just an acknowledgement of our 1447 1.1 thorpej * mpt_send_event_request(). 1448 1.1 thorpej */ 1449 1.1 thorpej break; 1450 1.1 thorpej 1451 1.12 tron case MPI_EVENT_SAS_PHY_LINK_STATUS: 1452 1.13 tron switch ((msg->Data[0] >> 12) & 0x0f) { 1453 1.12 tron case 0x00: 1454 1.12 tron mpt_prt(mpt, "Phy %d: Link Status Unknown", 1455 1.12 tron msg->Data[0] & 0xff); 1456 1.12 tron break; 1457 1.12 tron case 0x01: 1458 1.12 tron mpt_prt(mpt, "Phy %d: Link Disabled", 1459 1.12 tron msg->Data[0] & 0xff); 1460 1.12 tron break; 1461 1.12 tron case 0x02: 1462 1.12 tron mpt_prt(mpt, "Phy %d: Failed Speed Negotiation", 1463 1.12 tron msg->Data[0] & 0xff); 1464 1.12 tron break; 1465 1.12 tron case 0x03: 1466 1.12 tron mpt_prt(mpt, "Phy %d: SATA OOB Complete", 1467 1.12 tron msg->Data[0] & 0xff); 1468 1.12 tron break; 1469 1.12 tron case 0x08: 1470 1.12 tron mpt_prt(mpt, "Phy %d: Link Rate 1.5 Gbps", 1471 1.12 tron msg->Data[0] & 0xff); 1472 1.12 tron break; 1473 1.12 tron case 0x09: 1474 1.12 tron mpt_prt(mpt, "Phy %d: Link Rate 3.0 Gbps", 1475 1.12 tron msg->Data[0] & 0xff); 1476 1.12 tron break; 1477 1.13 tron default: 1478 1.12 tron mpt_prt(mpt, "Phy %d: SAS Phy Link Status Event: " 1479 1.12 tron "Unknown event (%0x)", 1480 1.12 tron msg->Data[0] & 0xff, (msg->Data[0] >> 8) & 0xff); 1481 1.12 tron } 1482 1.12 tron break; 1483 1.12 tron 1484 1.12 tron case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: 1485 1.12 tron case MPI_EVENT_SAS_DISCOVERY: 1486 1.12 tron /* ignore these events for now */ 1487 1.12 tron break; 1488 1.12 tron 1489 1.17 mhitch case MPI_EVENT_QUEUE_FULL: 1490 1.17 mhitch /* This can get a little chatty */ 1491 1.17 mhitch if (mpt->verbose > 0) 1492 1.17 mhitch mpt_prt(mpt, "Queue Full Event"); 1493 1.17 mhitch break; 1494 1.17 mhitch 1495 1.1 thorpej default: 1496 1.1 thorpej mpt_prt(mpt, "Unknown async event: 0x%x", msg->Event); 1497 1.1 thorpej break; 1498 1.1 thorpej } 1499 1.9 perry 1500 1.1 thorpej if (msg->AckRequired) { 1501 1.1 thorpej MSG_EVENT_ACK *ackp; 1502 1.1 thorpej request_t *req; 1503 1.1 thorpej 1504 1.1 thorpej if ((req = mpt_get_request(mpt)) == NULL) { 1505 1.1 thorpej /* XXX XXX XXX XXXJRT */ 1506 1.1 thorpej panic("mpt_event_notify_reply: unable to allocate " 1507 1.1 thorpej "request structure"); 1508 1.1 thorpej } 1509 1.1 thorpej 1510 1.1 thorpej ackp = (MSG_EVENT_ACK *) req->req_vbuf; 1511 1.1 thorpej memset(ackp, 0, sizeof(*ackp)); 1512 1.1 thorpej ackp->Function = MPI_FUNCTION_EVENT_ACK; 1513 1.1 thorpej ackp->Event = msg->Event; 1514 1.1 thorpej ackp->EventContext = msg->EventContext; 1515 1.15 chs ackp->MsgContext = htole32(req->index | 0x80000000); 1516 1.1 thorpej mpt_check_doorbell(mpt); 1517 1.1 thorpej mpt_send_cmd(mpt, req); 1518 1.1 thorpej } 1519 1.1 thorpej } 1520 1.1 thorpej 1521 1.20 buhrow static void 1522 1.20 buhrow mpt_bus_reset(mpt_softc_t *mpt) 1523 1.20 buhrow { 1524 1.20 buhrow request_t *req; 1525 1.20 buhrow MSG_SCSI_TASK_MGMT *mngt_req; 1526 1.20 buhrow int s; 1527 1.20 buhrow 1528 1.20 buhrow s = splbio(); 1529 1.20 buhrow if (mpt->mngt_req) { 1530 1.20 buhrow /* request already queued; can't do more */ 1531 1.20 buhrow splx(s); 1532 1.20 buhrow return; 1533 1.20 buhrow } 1534 1.20 buhrow req = mpt_get_request(mpt); 1535 1.20 buhrow if (__predict_false(req == NULL)) { 1536 1.20 buhrow mpt_prt(mpt, "no mngt request\n"); 1537 1.20 buhrow splx(s); 1538 1.20 buhrow return; 1539 1.20 buhrow } 1540 1.20 buhrow mpt->mngt_req = req; 1541 1.20 buhrow splx(s); 1542 1.20 buhrow mngt_req = req->req_vbuf; 1543 1.20 buhrow memset(mngt_req, 0, sizeof(*mngt_req)); 1544 1.20 buhrow mngt_req->Function = MPI_FUNCTION_SCSI_TASK_MGMT; 1545 1.20 buhrow mngt_req->Bus = mpt->bus; 1546 1.20 buhrow mngt_req->TargetID = 0; 1547 1.20 buhrow mngt_req->ChainOffset = 0; 1548 1.20 buhrow mngt_req->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS; 1549 1.20 buhrow mngt_req->Reserved1 = 0; 1550 1.20 buhrow mngt_req->MsgFlags = 1551 1.20 buhrow mpt->is_fc ? MPI_SCSITASKMGMT_MSGFLAGS_LIP_RESET_OPTION : 0; 1552 1.20 buhrow mngt_req->MsgContext = req->index; 1553 1.20 buhrow mngt_req->TaskMsgContext = 0; 1554 1.20 buhrow s = splbio(); 1555 1.20 buhrow mpt_send_handshake_cmd(mpt, sizeof(*mngt_req), mngt_req); 1556 1.20 buhrow splx(s); 1557 1.20 buhrow } 1558 1.1 thorpej 1559 1.1 thorpej /***************************************************************************** 1560 1.1 thorpej * SCSI interface routines 1561 1.1 thorpej *****************************************************************************/ 1562 1.1 thorpej 1563 1.1 thorpej static void 1564 1.1 thorpej mpt_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req, 1565 1.1 thorpej void *arg) 1566 1.1 thorpej { 1567 1.1 thorpej struct scsipi_adapter *adapt = chan->chan_adapter; 1568 1.25 chs mpt_softc_t *mpt = device_private(adapt->adapt_dev); 1569 1.1 thorpej 1570 1.1 thorpej switch (req) { 1571 1.1 thorpej case ADAPTER_REQ_RUN_XFER: 1572 1.1 thorpej mpt_run_xfer(mpt, (struct scsipi_xfer *) arg); 1573 1.1 thorpej return; 1574 1.1 thorpej 1575 1.1 thorpej case ADAPTER_REQ_GROW_RESOURCES: 1576 1.1 thorpej /* Not supported. */ 1577 1.1 thorpej return; 1578 1.1 thorpej 1579 1.1 thorpej case ADAPTER_REQ_SET_XFER_MODE: 1580 1.1 thorpej mpt_set_xfer_mode(mpt, (struct scsipi_xfer_mode *) arg); 1581 1.1 thorpej return; 1582 1.1 thorpej } 1583 1.1 thorpej } 1584 1.1 thorpej 1585 1.1 thorpej static void 1586 1.1 thorpej mpt_minphys(struct buf *bp) 1587 1.1 thorpej { 1588 1.1 thorpej 1589 1.1 thorpej /* 1590 1.1 thorpej * Subtract one from the SGL limit, since we need an extra one to handle 1591 1.1 thorpej * an non-page-aligned transfer. 1592 1.1 thorpej */ 1593 1.1 thorpej #define MPT_MAX_XFER ((MPT_SGL_MAX - 1) * PAGE_SIZE) 1594 1.1 thorpej 1595 1.1 thorpej if (bp->b_bcount > MPT_MAX_XFER) 1596 1.1 thorpej bp->b_bcount = MPT_MAX_XFER; 1597 1.1 thorpej minphys(bp); 1598 1.1 thorpej } 1599 1.20 buhrow 1600 1.20 buhrow static int 1601 1.20 buhrow mpt_ioctl(struct scsipi_channel *chan, u_long cmd, void *arg, 1602 1.20 buhrow int flag, struct proc *p) 1603 1.20 buhrow { 1604 1.20 buhrow mpt_softc_t *mpt; 1605 1.20 buhrow int s; 1606 1.20 buhrow 1607 1.20 buhrow mpt = device_private(chan->chan_adapter->adapt_dev); 1608 1.20 buhrow switch (cmd) { 1609 1.20 buhrow case SCBUSIORESET: 1610 1.20 buhrow mpt_bus_reset(mpt); 1611 1.20 buhrow s = splbio(); 1612 1.20 buhrow mpt_intr(mpt); 1613 1.20 buhrow splx(s); 1614 1.20 buhrow return(0); 1615 1.20 buhrow default: 1616 1.20 buhrow return (ENOTTY); 1617 1.20 buhrow } 1618 1.20 buhrow } 1619 1.26 jmcneill 1620 1.26 jmcneill #if NBIO > 0 1621 1.26 jmcneill static fCONFIG_PAGE_IOC_2 * 1622 1.26 jmcneill mpt_get_cfg_page_ioc2(mpt_softc_t *mpt) 1623 1.26 jmcneill { 1624 1.26 jmcneill fCONFIG_PAGE_HEADER hdr; 1625 1.26 jmcneill fCONFIG_PAGE_IOC_2 *ioc2; 1626 1.26 jmcneill int rv; 1627 1.26 jmcneill 1628 1.26 jmcneill rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_IOC, 2, 0, &hdr); 1629 1.26 jmcneill if (rv) 1630 1.26 jmcneill return NULL; 1631 1.26 jmcneill 1632 1.26 jmcneill ioc2 = malloc(hdr.PageLength * 4, M_DEVBUF, M_WAITOK | M_ZERO); 1633 1.26 jmcneill if (ioc2 == NULL) 1634 1.26 jmcneill return NULL; 1635 1.26 jmcneill 1636 1.26 jmcneill memcpy(ioc2, &hdr, sizeof(hdr)); 1637 1.26 jmcneill 1638 1.26 jmcneill rv = mpt_read_cfg_page(mpt, 0, &ioc2->Header); 1639 1.26 jmcneill if (rv) 1640 1.26 jmcneill goto fail; 1641 1.26 jmcneill mpt2host_config_page_ioc_2(ioc2); 1642 1.26 jmcneill 1643 1.26 jmcneill return ioc2; 1644 1.26 jmcneill 1645 1.26 jmcneill fail: 1646 1.26 jmcneill free(ioc2, M_DEVBUF); 1647 1.26 jmcneill return NULL; 1648 1.26 jmcneill } 1649 1.26 jmcneill 1650 1.29 jmcneill static fCONFIG_PAGE_IOC_3 * 1651 1.29 jmcneill mpt_get_cfg_page_ioc3(mpt_softc_t *mpt) 1652 1.29 jmcneill { 1653 1.29 jmcneill fCONFIG_PAGE_HEADER hdr; 1654 1.29 jmcneill fCONFIG_PAGE_IOC_3 *ioc3; 1655 1.29 jmcneill int rv; 1656 1.29 jmcneill 1657 1.29 jmcneill rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_IOC, 3, 0, &hdr); 1658 1.29 jmcneill if (rv) 1659 1.29 jmcneill return NULL; 1660 1.29 jmcneill 1661 1.29 jmcneill ioc3 = malloc(hdr.PageLength * 4, M_DEVBUF, M_WAITOK | M_ZERO); 1662 1.29 jmcneill if (ioc3 == NULL) 1663 1.29 jmcneill return NULL; 1664 1.29 jmcneill 1665 1.29 jmcneill memcpy(ioc3, &hdr, sizeof(hdr)); 1666 1.29 jmcneill 1667 1.29 jmcneill rv = mpt_read_cfg_page(mpt, 0, &ioc3->Header); 1668 1.29 jmcneill if (rv) 1669 1.29 jmcneill goto fail; 1670 1.29 jmcneill 1671 1.29 jmcneill return ioc3; 1672 1.29 jmcneill 1673 1.29 jmcneill fail: 1674 1.29 jmcneill free(ioc3, M_DEVBUF); 1675 1.29 jmcneill return NULL; 1676 1.29 jmcneill } 1677 1.29 jmcneill 1678 1.29 jmcneill 1679 1.26 jmcneill static fCONFIG_PAGE_RAID_VOL_0 * 1680 1.26 jmcneill mpt_get_cfg_page_raid_vol0(mpt_softc_t *mpt, int address) 1681 1.26 jmcneill { 1682 1.26 jmcneill fCONFIG_PAGE_HEADER hdr; 1683 1.26 jmcneill fCONFIG_PAGE_RAID_VOL_0 *rvol0; 1684 1.26 jmcneill int rv; 1685 1.26 jmcneill 1686 1.26 jmcneill rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_RAID_VOLUME, 0, 1687 1.26 jmcneill address, &hdr); 1688 1.26 jmcneill if (rv) 1689 1.26 jmcneill return NULL; 1690 1.26 jmcneill 1691 1.26 jmcneill rvol0 = malloc(hdr.PageLength * 4, M_DEVBUF, M_WAITOK | M_ZERO); 1692 1.26 jmcneill if (rvol0 == NULL) 1693 1.26 jmcneill return NULL; 1694 1.26 jmcneill 1695 1.26 jmcneill memcpy(rvol0, &hdr, sizeof(hdr)); 1696 1.26 jmcneill 1697 1.26 jmcneill rv = mpt_read_cfg_page(mpt, address, &rvol0->Header); 1698 1.26 jmcneill if (rv) 1699 1.26 jmcneill goto fail; 1700 1.26 jmcneill mpt2host_config_page_raid_vol_0(rvol0); 1701 1.26 jmcneill 1702 1.26 jmcneill return rvol0; 1703 1.26 jmcneill 1704 1.26 jmcneill fail: 1705 1.26 jmcneill free(rvol0, M_DEVBUF); 1706 1.26 jmcneill return NULL; 1707 1.26 jmcneill } 1708 1.26 jmcneill 1709 1.26 jmcneill static fCONFIG_PAGE_RAID_PHYS_DISK_0 * 1710 1.26 jmcneill mpt_get_cfg_page_raid_phys_disk0(mpt_softc_t *mpt, int address) 1711 1.26 jmcneill { 1712 1.26 jmcneill fCONFIG_PAGE_HEADER hdr; 1713 1.26 jmcneill fCONFIG_PAGE_RAID_PHYS_DISK_0 *physdisk0; 1714 1.26 jmcneill int rv; 1715 1.26 jmcneill 1716 1.26 jmcneill rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_RAID_PHYSDISK, 0, 1717 1.26 jmcneill address, &hdr); 1718 1.26 jmcneill if (rv) 1719 1.26 jmcneill return NULL; 1720 1.26 jmcneill 1721 1.26 jmcneill physdisk0 = malloc(hdr.PageLength * 4, M_DEVBUF, M_WAITOK | M_ZERO); 1722 1.26 jmcneill if (physdisk0 == NULL) 1723 1.26 jmcneill return NULL; 1724 1.26 jmcneill 1725 1.26 jmcneill memcpy(physdisk0, &hdr, sizeof(hdr)); 1726 1.26 jmcneill 1727 1.26 jmcneill rv = mpt_read_cfg_page(mpt, address, &physdisk0->Header); 1728 1.26 jmcneill if (rv) 1729 1.26 jmcneill goto fail; 1730 1.26 jmcneill mpt2host_config_page_raid_phys_disk_0(physdisk0); 1731 1.26 jmcneill 1732 1.26 jmcneill return physdisk0; 1733 1.26 jmcneill 1734 1.26 jmcneill fail: 1735 1.26 jmcneill free(physdisk0, M_DEVBUF); 1736 1.26 jmcneill return NULL; 1737 1.26 jmcneill } 1738 1.26 jmcneill 1739 1.26 jmcneill static bool 1740 1.26 jmcneill mpt_is_raid(mpt_softc_t *mpt) 1741 1.26 jmcneill { 1742 1.26 jmcneill fCONFIG_PAGE_IOC_2 *ioc2; 1743 1.26 jmcneill bool is_raid = false; 1744 1.26 jmcneill 1745 1.26 jmcneill ioc2 = mpt_get_cfg_page_ioc2(mpt); 1746 1.26 jmcneill if (ioc2 == NULL) 1747 1.26 jmcneill return false; 1748 1.26 jmcneill 1749 1.26 jmcneill if (ioc2->CapabilitiesFlags != 0xdeadbeef) { 1750 1.26 jmcneill is_raid = !!(ioc2->CapabilitiesFlags & 1751 1.26 jmcneill (MPI_IOCPAGE2_CAP_FLAGS_IS_SUPPORT| 1752 1.26 jmcneill MPI_IOCPAGE2_CAP_FLAGS_IME_SUPPORT| 1753 1.26 jmcneill MPI_IOCPAGE2_CAP_FLAGS_IM_SUPPORT)); 1754 1.26 jmcneill } 1755 1.26 jmcneill 1756 1.26 jmcneill free(ioc2, M_DEVBUF); 1757 1.26 jmcneill 1758 1.26 jmcneill return is_raid; 1759 1.26 jmcneill } 1760 1.26 jmcneill 1761 1.26 jmcneill static int 1762 1.26 jmcneill mpt_bio_ioctl(device_t dev, u_long cmd, void *addr) 1763 1.26 jmcneill { 1764 1.26 jmcneill mpt_softc_t *mpt = device_private(dev); 1765 1.26 jmcneill int error, s; 1766 1.26 jmcneill 1767 1.26 jmcneill KERNEL_LOCK(1, curlwp); 1768 1.26 jmcneill s = splbio(); 1769 1.26 jmcneill 1770 1.26 jmcneill switch (cmd) { 1771 1.26 jmcneill case BIOCINQ: 1772 1.26 jmcneill error = mpt_bio_ioctl_inq(mpt, addr); 1773 1.26 jmcneill break; 1774 1.26 jmcneill case BIOCVOL: 1775 1.26 jmcneill error = mpt_bio_ioctl_vol(mpt, addr); 1776 1.26 jmcneill break; 1777 1.29 jmcneill case BIOCDISK_NOVOL: 1778 1.29 jmcneill error = mpt_bio_ioctl_disk_novol(mpt, addr); 1779 1.29 jmcneill break; 1780 1.26 jmcneill case BIOCDISK: 1781 1.26 jmcneill error = mpt_bio_ioctl_disk(mpt, addr); 1782 1.26 jmcneill break; 1783 1.26 jmcneill default: 1784 1.26 jmcneill error = EINVAL; 1785 1.26 jmcneill break; 1786 1.26 jmcneill } 1787 1.26 jmcneill 1788 1.26 jmcneill splx(s); 1789 1.26 jmcneill KERNEL_UNLOCK_ONE(curlwp); 1790 1.26 jmcneill 1791 1.26 jmcneill return error; 1792 1.26 jmcneill } 1793 1.26 jmcneill 1794 1.26 jmcneill static int 1795 1.26 jmcneill mpt_bio_ioctl_inq(mpt_softc_t *mpt, struct bioc_inq *bi) 1796 1.26 jmcneill { 1797 1.26 jmcneill fCONFIG_PAGE_IOC_2 *ioc2; 1798 1.29 jmcneill fCONFIG_PAGE_IOC_3 *ioc3; 1799 1.26 jmcneill 1800 1.26 jmcneill ioc2 = mpt_get_cfg_page_ioc2(mpt); 1801 1.26 jmcneill if (ioc2 == NULL) 1802 1.26 jmcneill return EIO; 1803 1.29 jmcneill ioc3 = mpt_get_cfg_page_ioc3(mpt); 1804 1.29 jmcneill if (ioc3 == NULL) { 1805 1.29 jmcneill free(ioc2, M_DEVBUF); 1806 1.29 jmcneill return EIO; 1807 1.29 jmcneill } 1808 1.26 jmcneill 1809 1.26 jmcneill strlcpy(bi->bi_dev, device_xname(mpt->sc_dev), sizeof(bi->bi_dev)); 1810 1.26 jmcneill bi->bi_novol = ioc2->NumActiveVolumes; 1811 1.29 jmcneill bi->bi_nodisk = ioc3->NumPhysDisks; 1812 1.26 jmcneill 1813 1.26 jmcneill free(ioc2, M_DEVBUF); 1814 1.29 jmcneill free(ioc3, M_DEVBUF); 1815 1.26 jmcneill 1816 1.26 jmcneill return 0; 1817 1.26 jmcneill } 1818 1.26 jmcneill 1819 1.26 jmcneill static int 1820 1.26 jmcneill mpt_bio_ioctl_vol(mpt_softc_t *mpt, struct bioc_vol *bv) 1821 1.26 jmcneill { 1822 1.26 jmcneill fCONFIG_PAGE_IOC_2 *ioc2 = NULL; 1823 1.26 jmcneill fCONFIG_PAGE_IOC_2_RAID_VOL *ioc2rvol; 1824 1.26 jmcneill fCONFIG_PAGE_RAID_VOL_0 *rvol0 = NULL; 1825 1.27 jmcneill struct scsipi_periph *periph; 1826 1.28 jmcneill struct scsipi_inquiry_data inqbuf; 1827 1.28 jmcneill char vendor[9], product[17], revision[5]; 1828 1.26 jmcneill int address; 1829 1.26 jmcneill 1830 1.26 jmcneill ioc2 = mpt_get_cfg_page_ioc2(mpt); 1831 1.26 jmcneill if (ioc2 == NULL) 1832 1.26 jmcneill return EIO; 1833 1.26 jmcneill 1834 1.26 jmcneill if (bv->bv_volid < 0 || bv->bv_volid >= ioc2->NumActiveVolumes) 1835 1.26 jmcneill goto fail; 1836 1.26 jmcneill 1837 1.26 jmcneill ioc2rvol = &ioc2->RaidVolume[bv->bv_volid]; 1838 1.26 jmcneill address = ioc2rvol->VolumeID | (ioc2rvol->VolumeBus << 8); 1839 1.26 jmcneill 1840 1.26 jmcneill rvol0 = mpt_get_cfg_page_raid_vol0(mpt, address); 1841 1.26 jmcneill if (rvol0 == NULL) 1842 1.26 jmcneill goto fail; 1843 1.26 jmcneill 1844 1.28 jmcneill bv->bv_dev[0] = '\0'; 1845 1.28 jmcneill bv->bv_vendor[0] = '\0'; 1846 1.28 jmcneill 1847 1.27 jmcneill periph = scsipi_lookup_periph(&mpt->sc_channel, ioc2rvol->VolumeBus, 0); 1848 1.28 jmcneill if (periph != NULL) { 1849 1.28 jmcneill if (periph->periph_dev != NULL) { 1850 1.28 jmcneill snprintf(bv->bv_dev, sizeof(bv->bv_dev), "%s", 1851 1.28 jmcneill device_xname(periph->periph_dev)); 1852 1.28 jmcneill } 1853 1.28 jmcneill memset(&inqbuf, 0, sizeof(inqbuf)); 1854 1.28 jmcneill if (scsipi_inquire(periph, &inqbuf, 1855 1.28 jmcneill XS_CTL_DISCOVERY | XS_CTL_SILENT) == 0) { 1856 1.33 christos strnvisx(vendor, sizeof(vendor), 1857 1.33 christos inqbuf.vendor, sizeof(inqbuf.vendor), 1858 1.33 christos VIS_TRIM|VIS_SAFE|VIS_OCTAL); 1859 1.33 christos strnvisx(product, sizeof(product), 1860 1.33 christos inqbuf.product, sizeof(inqbuf.product), 1861 1.33 christos VIS_TRIM|VIS_SAFE|VIS_OCTAL); 1862 1.33 christos strnvisx(revision, sizeof(revision), 1863 1.33 christos inqbuf.revision, sizeof(inqbuf.revision), 1864 1.33 christos VIS_TRIM|VIS_SAFE|VIS_OCTAL); 1865 1.28 jmcneill 1866 1.28 jmcneill snprintf(bv->bv_vendor, sizeof(bv->bv_vendor), 1867 1.28 jmcneill "%s %s %s", vendor, product, revision); 1868 1.28 jmcneill } 1869 1.28 jmcneill 1870 1.27 jmcneill snprintf(bv->bv_dev, sizeof(bv->bv_dev), "%s", 1871 1.27 jmcneill device_xname(periph->periph_dev)); 1872 1.27 jmcneill } 1873 1.26 jmcneill bv->bv_nodisk = rvol0->NumPhysDisks; 1874 1.26 jmcneill bv->bv_size = (uint64_t)rvol0->MaxLBA * 512; 1875 1.26 jmcneill bv->bv_stripe_size = rvol0->StripeSize; 1876 1.26 jmcneill bv->bv_percent = -1; 1877 1.26 jmcneill bv->bv_seconds = 0; 1878 1.26 jmcneill 1879 1.26 jmcneill switch (rvol0->VolumeStatus.State) { 1880 1.26 jmcneill case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL: 1881 1.26 jmcneill bv->bv_status = BIOC_SVONLINE; 1882 1.26 jmcneill break; 1883 1.26 jmcneill case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: 1884 1.26 jmcneill bv->bv_status = BIOC_SVDEGRADED; 1885 1.26 jmcneill break; 1886 1.26 jmcneill case MPI_RAIDVOL0_STATUS_STATE_FAILED: 1887 1.26 jmcneill bv->bv_status = BIOC_SVOFFLINE; 1888 1.26 jmcneill break; 1889 1.26 jmcneill default: 1890 1.26 jmcneill bv->bv_status = BIOC_SVINVALID; 1891 1.26 jmcneill break; 1892 1.26 jmcneill } 1893 1.26 jmcneill 1894 1.26 jmcneill switch (ioc2rvol->VolumeType) { 1895 1.26 jmcneill case MPI_RAID_VOL_TYPE_IS: 1896 1.26 jmcneill bv->bv_level = 0; 1897 1.26 jmcneill break; 1898 1.26 jmcneill case MPI_RAID_VOL_TYPE_IME: 1899 1.26 jmcneill case MPI_RAID_VOL_TYPE_IM: 1900 1.26 jmcneill bv->bv_level = 1; 1901 1.26 jmcneill break; 1902 1.26 jmcneill default: 1903 1.26 jmcneill bv->bv_level = -1; 1904 1.26 jmcneill break; 1905 1.26 jmcneill } 1906 1.26 jmcneill 1907 1.26 jmcneill free(ioc2, M_DEVBUF); 1908 1.26 jmcneill free(rvol0, M_DEVBUF); 1909 1.26 jmcneill 1910 1.26 jmcneill return 0; 1911 1.26 jmcneill 1912 1.26 jmcneill fail: 1913 1.26 jmcneill if (ioc2) free(ioc2, M_DEVBUF); 1914 1.26 jmcneill if (rvol0) free(rvol0, M_DEVBUF); 1915 1.26 jmcneill return EINVAL; 1916 1.26 jmcneill } 1917 1.26 jmcneill 1918 1.29 jmcneill static void 1919 1.29 jmcneill mpt_bio_ioctl_disk_common(mpt_softc_t *mpt, struct bioc_disk *bd, 1920 1.29 jmcneill int address) 1921 1.26 jmcneill { 1922 1.26 jmcneill fCONFIG_PAGE_RAID_PHYS_DISK_0 *phys = NULL; 1923 1.28 jmcneill char vendor_id[9], product_id[17], product_rev_level[5]; 1924 1.26 jmcneill 1925 1.26 jmcneill phys = mpt_get_cfg_page_raid_phys_disk0(mpt, address); 1926 1.26 jmcneill if (phys == NULL) 1927 1.29 jmcneill return; 1928 1.26 jmcneill 1929 1.33 christos strnvisx(vendor_id, sizeof(vendor_id), 1930 1.33 christos phys->InquiryData.VendorID, sizeof(phys->InquiryData.VendorID), 1931 1.33 christos VIS_TRIM|VIS_SAFE|VIS_OCTAL); 1932 1.33 christos strnvisx(product_id, sizeof(product_id), 1933 1.33 christos phys->InquiryData.ProductID, sizeof(phys->InquiryData.ProductID), 1934 1.33 christos VIS_TRIM|VIS_SAFE|VIS_OCTAL); 1935 1.33 christos strnvisx(product_rev_level, sizeof(product_rev_level), 1936 1.28 jmcneill phys->InquiryData.ProductRevLevel, 1937 1.33 christos sizeof(phys->InquiryData.ProductRevLevel), 1938 1.33 christos VIS_TRIM|VIS_SAFE|VIS_OCTAL); 1939 1.28 jmcneill 1940 1.28 jmcneill snprintf(bd->bd_vendor, sizeof(bd->bd_vendor), "%s %s %s", 1941 1.28 jmcneill vendor_id, product_id, product_rev_level); 1942 1.28 jmcneill strlcpy(bd->bd_serial, phys->InquiryData.Info, sizeof(bd->bd_serial)); 1943 1.28 jmcneill bd->bd_procdev[0] = '\0'; 1944 1.26 jmcneill bd->bd_channel = phys->PhysDiskBus; 1945 1.26 jmcneill bd->bd_target = phys->PhysDiskID; 1946 1.26 jmcneill bd->bd_lun = 0; 1947 1.26 jmcneill bd->bd_size = (uint64_t)phys->MaxLBA * 512; 1948 1.26 jmcneill 1949 1.26 jmcneill switch (phys->PhysDiskStatus.State) { 1950 1.26 jmcneill case MPI_PHYSDISK0_STATUS_ONLINE: 1951 1.26 jmcneill bd->bd_status = BIOC_SDONLINE; 1952 1.26 jmcneill break; 1953 1.26 jmcneill case MPI_PHYSDISK0_STATUS_MISSING: 1954 1.26 jmcneill case MPI_PHYSDISK0_STATUS_FAILED: 1955 1.26 jmcneill bd->bd_status = BIOC_SDFAILED; 1956 1.26 jmcneill break; 1957 1.26 jmcneill case MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED: 1958 1.26 jmcneill case MPI_PHYSDISK0_STATUS_FAILED_REQUESTED: 1959 1.26 jmcneill case MPI_PHYSDISK0_STATUS_OTHER_OFFLINE: 1960 1.26 jmcneill bd->bd_status = BIOC_SDOFFLINE; 1961 1.26 jmcneill break; 1962 1.26 jmcneill case MPI_PHYSDISK0_STATUS_INITIALIZING: 1963 1.26 jmcneill bd->bd_status = BIOC_SDSCRUB; 1964 1.26 jmcneill break; 1965 1.26 jmcneill case MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE: 1966 1.26 jmcneill default: 1967 1.26 jmcneill bd->bd_status = BIOC_SDINVALID; 1968 1.26 jmcneill break; 1969 1.26 jmcneill } 1970 1.26 jmcneill 1971 1.29 jmcneill free(phys, M_DEVBUF); 1972 1.29 jmcneill } 1973 1.29 jmcneill 1974 1.29 jmcneill static int 1975 1.29 jmcneill mpt_bio_ioctl_disk_novol(mpt_softc_t *mpt, struct bioc_disk *bd) 1976 1.29 jmcneill { 1977 1.30 jmcneill fCONFIG_PAGE_IOC_2 *ioc2 = NULL; 1978 1.29 jmcneill fCONFIG_PAGE_IOC_3 *ioc3 = NULL; 1979 1.30 jmcneill fCONFIG_PAGE_RAID_VOL_0 *rvol0 = NULL; 1980 1.30 jmcneill fCONFIG_PAGE_IOC_2_RAID_VOL *ioc2rvol; 1981 1.30 jmcneill int address, v, d; 1982 1.29 jmcneill 1983 1.30 jmcneill ioc2 = mpt_get_cfg_page_ioc2(mpt); 1984 1.30 jmcneill if (ioc2 == NULL) 1985 1.30 jmcneill return EIO; 1986 1.29 jmcneill ioc3 = mpt_get_cfg_page_ioc3(mpt); 1987 1.30 jmcneill if (ioc3 == NULL) { 1988 1.30 jmcneill free(ioc2, M_DEVBUF); 1989 1.29 jmcneill return EIO; 1990 1.30 jmcneill } 1991 1.29 jmcneill 1992 1.29 jmcneill if (bd->bd_diskid < 0 || bd->bd_diskid >= ioc3->NumPhysDisks) 1993 1.29 jmcneill goto fail; 1994 1.29 jmcneill 1995 1.29 jmcneill address = ioc3->PhysDisk[bd->bd_diskid].PhysDiskNum; 1996 1.29 jmcneill 1997 1.29 jmcneill mpt_bio_ioctl_disk_common(mpt, bd, address); 1998 1.29 jmcneill 1999 1.30 jmcneill bd->bd_disknovol = true; 2000 1.30 jmcneill for (v = 0; bd->bd_disknovol && v < ioc2->NumActiveVolumes; v++) { 2001 1.30 jmcneill ioc2rvol = &ioc2->RaidVolume[v]; 2002 1.30 jmcneill address = ioc2rvol->VolumeID | (ioc2rvol->VolumeBus << 8); 2003 1.30 jmcneill 2004 1.30 jmcneill rvol0 = mpt_get_cfg_page_raid_vol0(mpt, address); 2005 1.30 jmcneill if (rvol0 == NULL) 2006 1.30 jmcneill continue; 2007 1.30 jmcneill 2008 1.30 jmcneill for (d = 0; d < rvol0->NumPhysDisks; d++) { 2009 1.30 jmcneill if (rvol0->PhysDisk[d].PhysDiskNum == 2010 1.30 jmcneill ioc3->PhysDisk[bd->bd_diskid].PhysDiskNum) { 2011 1.30 jmcneill bd->bd_disknovol = false; 2012 1.31 jmcneill bd->bd_volid = v; 2013 1.30 jmcneill break; 2014 1.30 jmcneill } 2015 1.30 jmcneill } 2016 1.30 jmcneill free(rvol0, M_DEVBUF); 2017 1.30 jmcneill } 2018 1.30 jmcneill 2019 1.29 jmcneill free(ioc3, M_DEVBUF); 2020 1.30 jmcneill free(ioc2, M_DEVBUF); 2021 1.29 jmcneill 2022 1.29 jmcneill return 0; 2023 1.29 jmcneill 2024 1.29 jmcneill fail: 2025 1.29 jmcneill if (ioc3) free(ioc3, M_DEVBUF); 2026 1.30 jmcneill if (ioc2) free(ioc2, M_DEVBUF); 2027 1.29 jmcneill return EINVAL; 2028 1.29 jmcneill } 2029 1.29 jmcneill 2030 1.29 jmcneill 2031 1.29 jmcneill static int 2032 1.29 jmcneill mpt_bio_ioctl_disk(mpt_softc_t *mpt, struct bioc_disk *bd) 2033 1.29 jmcneill { 2034 1.29 jmcneill fCONFIG_PAGE_IOC_2 *ioc2 = NULL; 2035 1.29 jmcneill fCONFIG_PAGE_RAID_VOL_0 *rvol0 = NULL; 2036 1.29 jmcneill fCONFIG_PAGE_IOC_2_RAID_VOL *ioc2rvol; 2037 1.29 jmcneill int address; 2038 1.29 jmcneill 2039 1.29 jmcneill ioc2 = mpt_get_cfg_page_ioc2(mpt); 2040 1.29 jmcneill if (ioc2 == NULL) 2041 1.29 jmcneill return EIO; 2042 1.29 jmcneill 2043 1.29 jmcneill if (bd->bd_volid < 0 || bd->bd_volid >= ioc2->NumActiveVolumes) 2044 1.29 jmcneill goto fail; 2045 1.29 jmcneill 2046 1.29 jmcneill ioc2rvol = &ioc2->RaidVolume[bd->bd_volid]; 2047 1.29 jmcneill address = ioc2rvol->VolumeID | (ioc2rvol->VolumeBus << 8); 2048 1.29 jmcneill 2049 1.29 jmcneill rvol0 = mpt_get_cfg_page_raid_vol0(mpt, address); 2050 1.29 jmcneill if (rvol0 == NULL) 2051 1.29 jmcneill goto fail; 2052 1.29 jmcneill 2053 1.29 jmcneill if (bd->bd_diskid < 0 || bd->bd_diskid >= rvol0->NumPhysDisks) 2054 1.29 jmcneill goto fail; 2055 1.29 jmcneill 2056 1.29 jmcneill address = rvol0->PhysDisk[bd->bd_diskid].PhysDiskNum; 2057 1.29 jmcneill 2058 1.29 jmcneill mpt_bio_ioctl_disk_common(mpt, bd, address); 2059 1.29 jmcneill 2060 1.26 jmcneill free(ioc2, M_DEVBUF); 2061 1.26 jmcneill 2062 1.26 jmcneill return 0; 2063 1.26 jmcneill 2064 1.26 jmcneill fail: 2065 1.26 jmcneill if (ioc2) free(ioc2, M_DEVBUF); 2066 1.26 jmcneill return EINVAL; 2067 1.26 jmcneill } 2068 1.26 jmcneill #endif 2069 1.26 jmcneill 2070