LCOV - code coverage report
Current view: top level - dev/ic - mpi.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 1498 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 72 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: mpi.c,v 1.206 2018/08/14 05:22:21 jmatthew Exp $ */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2005, 2006, 2009 David Gwynne <dlg@openbsd.org>
       5             :  * Copyright (c) 2005, 2008, 2009 Marco Peereboom <marco@openbsd.org>
       6             :  *
       7             :  * Permission to use, copy, modify, and distribute this software for any
       8             :  * purpose with or without fee is hereby granted, provided that the above
       9             :  * copyright notice and this permission notice appear in all copies.
      10             :  *
      11             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      12             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      13             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      14             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      15             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      16             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      17             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      18             :  */
      19             : 
      20             : #include "bio.h"
      21             : 
      22             : #include <sys/param.h>
      23             : #include <sys/systm.h>
      24             : #include <sys/buf.h>
      25             : #include <sys/device.h>
      26             : #include <sys/malloc.h>
      27             : #include <sys/kernel.h>
      28             : #include <sys/mutex.h>
      29             : #include <sys/rwlock.h>
      30             : #include <sys/sensors.h>
      31             : #include <sys/dkio.h>
      32             : #include <sys/task.h>
      33             : 
      34             : #include <machine/bus.h>
      35             : 
      36             : #include <scsi/scsi_all.h>
      37             : #include <scsi/scsiconf.h>
      38             : 
      39             : #include <dev/biovar.h>
      40             : #include <dev/ic/mpireg.h>
      41             : #include <dev/ic/mpivar.h>
      42             : 
      43             : #ifdef MPI_DEBUG
      44             : uint32_t        mpi_debug = 0
      45             : /*                  | MPI_D_CMD */
      46             : /*                  | MPI_D_INTR */
      47             : /*                  | MPI_D_MISC */
      48             : /*                  | MPI_D_DMA */
      49             : /*                  | MPI_D_IOCTL */
      50             : /*                  | MPI_D_RW */
      51             : /*                  | MPI_D_MEM */
      52             : /*                  | MPI_D_CCB */
      53             : /*                  | MPI_D_PPR */
      54             : /*                  | MPI_D_RAID */
      55             : /*                  | MPI_D_EVT */
      56             :                 ;
      57             : #endif
      58             : 
      59             : struct cfdriver mpi_cd = {
      60             :         NULL,
      61             :         "mpi",
      62             :         DV_DULL
      63             : };
      64             : 
      65             : void                    mpi_scsi_cmd(struct scsi_xfer *);
      66             : void                    mpi_scsi_cmd_done(struct mpi_ccb *);
      67             : void                    mpi_minphys(struct buf *bp, struct scsi_link *sl);
      68             : int                     mpi_scsi_probe(struct scsi_link *);
      69             : int                     mpi_scsi_ioctl(struct scsi_link *, u_long, caddr_t,
      70             :                             int);
      71             : 
      72             : struct scsi_adapter mpi_switch = {
      73             :         mpi_scsi_cmd,
      74             :         mpi_minphys,
      75             :         mpi_scsi_probe,
      76             :         NULL,
      77             :         mpi_scsi_ioctl
      78             : };
      79             : 
      80             : struct mpi_dmamem       *mpi_dmamem_alloc(struct mpi_softc *, size_t);
      81             : void                    mpi_dmamem_free(struct mpi_softc *,
      82             :                             struct mpi_dmamem *);
      83             : int                     mpi_alloc_ccbs(struct mpi_softc *);
      84             : void                    *mpi_get_ccb(void *);
      85             : void                    mpi_put_ccb(void *, void *);
      86             : int                     mpi_alloc_replies(struct mpi_softc *);
      87             : void                    mpi_push_replies(struct mpi_softc *);
      88             : void                    mpi_push_reply(struct mpi_softc *, struct mpi_rcb *);
      89             : 
      90             : void                    mpi_start(struct mpi_softc *, struct mpi_ccb *);
      91             : int                     mpi_poll(struct mpi_softc *, struct mpi_ccb *, int);
      92             : void                    mpi_poll_done(struct mpi_ccb *);
      93             : void                    mpi_reply(struct mpi_softc *, u_int32_t);
      94             : 
      95             : void                    mpi_wait(struct mpi_softc *sc, struct mpi_ccb *);
      96             : void                    mpi_wait_done(struct mpi_ccb *);
      97             : 
      98             : int                     mpi_cfg_spi_port(struct mpi_softc *);
      99             : void                    mpi_squash_ppr(struct mpi_softc *);
     100             : void                    mpi_run_ppr(struct mpi_softc *);
     101             : int                     mpi_ppr(struct mpi_softc *, struct scsi_link *,
     102             :                             struct mpi_cfg_raid_physdisk *, int, int, int);
     103             : int                     mpi_inq(struct mpi_softc *, u_int16_t, int);
     104             : 
     105             : int                     mpi_cfg_sas(struct mpi_softc *);
     106             : int                     mpi_cfg_fc(struct mpi_softc *);
     107             : 
     108             : void                    mpi_timeout_xs(void *);
     109             : int                     mpi_load_xs(struct mpi_ccb *);
     110             : 
     111             : u_int32_t               mpi_read(struct mpi_softc *, bus_size_t);
     112             : void                    mpi_write(struct mpi_softc *, bus_size_t, u_int32_t);
     113             : int                     mpi_wait_eq(struct mpi_softc *, bus_size_t, u_int32_t,
     114             :                             u_int32_t);
     115             : int                     mpi_wait_ne(struct mpi_softc *, bus_size_t, u_int32_t,
     116             :                             u_int32_t);
     117             : 
     118             : int                     mpi_init(struct mpi_softc *);
     119             : int                     mpi_reset_soft(struct mpi_softc *);
     120             : int                     mpi_reset_hard(struct mpi_softc *);
     121             : 
     122             : int                     mpi_handshake_send(struct mpi_softc *, void *, size_t);
     123             : int                     mpi_handshake_recv_dword(struct mpi_softc *,
     124             :                             u_int32_t *);
     125             : int                     mpi_handshake_recv(struct mpi_softc *, void *, size_t);
     126             : 
     127             : void                    mpi_empty_done(struct mpi_ccb *);
     128             : 
     129             : int                     mpi_iocinit(struct mpi_softc *);
     130             : int                     mpi_iocfacts(struct mpi_softc *);
     131             : int                     mpi_portfacts(struct mpi_softc *);
     132             : int                     mpi_portenable(struct mpi_softc *);
     133             : int                     mpi_cfg_coalescing(struct mpi_softc *);
     134             : void                    mpi_get_raid(struct mpi_softc *);
     135             : int                     mpi_fwupload(struct mpi_softc *);
     136             : int                     mpi_manufacturing(struct mpi_softc *);
     137             : int                     mpi_scsi_probe_virtual(struct scsi_link *);
     138             : 
     139             : int                     mpi_eventnotify(struct mpi_softc *);
     140             : void                    mpi_eventnotify_done(struct mpi_ccb *);
     141             : void                    mpi_eventnotify_free(struct mpi_softc *,
     142             :                             struct mpi_rcb *);
     143             : void                    mpi_eventack(void *, void *);
     144             : void                    mpi_eventack_done(struct mpi_ccb *);
     145             : int                     mpi_evt_sas(struct mpi_softc *, struct mpi_rcb *);
     146             : void                    mpi_evt_sas_detach(void *, void *);
     147             : void                    mpi_evt_sas_detach_done(struct mpi_ccb *);
     148             : void                    mpi_fc_rescan(void *);
     149             : 
     150             : int                     mpi_req_cfg_header(struct mpi_softc *, u_int8_t,
     151             :                             u_int8_t, u_int32_t, int, void *);
     152             : int                     mpi_req_cfg_page(struct mpi_softc *, u_int32_t, int,
     153             :                             void *, int, void *, size_t);
     154             : 
     155             : int                     mpi_ioctl_cache(struct scsi_link *, u_long,
     156             :                             struct dk_cache *);
     157             : 
     158             : #if NBIO > 0
     159             : int             mpi_bio_get_pg0_raid(struct mpi_softc *, int);
     160             : int             mpi_ioctl(struct device *, u_long, caddr_t);
     161             : int             mpi_ioctl_inq(struct mpi_softc *, struct bioc_inq *);
     162             : int             mpi_ioctl_vol(struct mpi_softc *, struct bioc_vol *);
     163             : int             mpi_ioctl_disk(struct mpi_softc *, struct bioc_disk *);
     164             : int             mpi_ioctl_setstate(struct mpi_softc *, struct bioc_setstate *);
     165             : #ifndef SMALL_KERNEL
     166             : int             mpi_create_sensors(struct mpi_softc *);
     167             : void            mpi_refresh_sensors(void *);
     168             : #endif /* SMALL_KERNEL */
     169             : #endif /* NBIO > 0 */
     170             : 
     171             : #define DEVNAME(s)              ((s)->sc_dev.dv_xname)
     172             : 
     173             : #define dwordsof(s)             (sizeof(s) / sizeof(u_int32_t))
     174             : 
     175             : #define mpi_read_db(s)          mpi_read((s), MPI_DOORBELL)
     176             : #define mpi_write_db(s, v)      mpi_write((s), MPI_DOORBELL, (v))
     177             : #define mpi_read_intr(s)        bus_space_read_4((s)->sc_iot, (s)->sc_ioh, \
     178             :                                     MPI_INTR_STATUS)
     179             : #define mpi_write_intr(s, v)    mpi_write((s), MPI_INTR_STATUS, (v))
     180             : #define mpi_pop_reply(s)        bus_space_read_4((s)->sc_iot, (s)->sc_ioh, \
     181             :                                     MPI_REPLY_QUEUE)
     182             : #define mpi_push_reply_db(s, v) bus_space_write_4((s)->sc_iot, (s)->sc_ioh, \
     183             :                                     MPI_REPLY_QUEUE, (v))       
     184             : 
     185             : #define mpi_wait_db_int(s)      mpi_wait_ne((s), MPI_INTR_STATUS, \
     186             :                                     MPI_INTR_STATUS_DOORBELL, 0)
     187             : #define mpi_wait_db_ack(s)      mpi_wait_eq((s), MPI_INTR_STATUS, \
     188             :                                     MPI_INTR_STATUS_IOCDOORBELL, 0)
     189             : 
     190             : #define MPI_PG_EXTENDED         (1<<0)
     191             : #define MPI_PG_POLL             (1<<1)
     192             : #define MPI_PG_FMT              "\020" "\002POLL" "\001EXTENDED"
     193             : 
     194             : #define mpi_cfg_header(_s, _t, _n, _a, _h) \
     195             :         mpi_req_cfg_header((_s), (_t), (_n), (_a), \
     196             :             MPI_PG_POLL, (_h))
     197             : #define mpi_ecfg_header(_s, _t, _n, _a, _h) \
     198             :         mpi_req_cfg_header((_s), (_t), (_n), (_a), \
     199             :             MPI_PG_POLL|MPI_PG_EXTENDED, (_h))
     200             : 
     201             : #define mpi_cfg_page(_s, _a, _h, _r, _p, _l) \
     202             :         mpi_req_cfg_page((_s), (_a), MPI_PG_POLL, \
     203             :             (_h), (_r), (_p), (_l))
     204             : #define mpi_ecfg_page(_s, _a, _h, _r, _p, _l) \
     205             :         mpi_req_cfg_page((_s), (_a), MPI_PG_POLL|MPI_PG_EXTENDED, \
     206             :             (_h), (_r), (_p), (_l))
     207             : 
     208             : static inline void
     209           0 : mpi_dvatosge(struct mpi_sge *sge, u_int64_t dva)
     210             : {
     211           0 :         htolem32(&sge->sg_addr_lo, dva);
     212           0 :         htolem32(&sge->sg_addr_hi, dva >> 32);
     213           0 : }
     214             : 
     215             : int
     216           0 : mpi_attach(struct mpi_softc *sc)
     217             : {
     218           0 :         struct scsibus_attach_args      saa;
     219             :         struct mpi_ccb                  *ccb;
     220             : 
     221           0 :         printf("\n");
     222             : 
     223           0 :         rw_init(&sc->sc_lock, "mpi_lock");
     224           0 :         task_set(&sc->sc_evt_rescan, mpi_fc_rescan, sc);
     225             : 
     226             :         /* disable interrupts */
     227           0 :         mpi_write(sc, MPI_INTR_MASK,
     228             :             MPI_INTR_MASK_REPLY | MPI_INTR_MASK_DOORBELL);
     229             : 
     230           0 :         if (mpi_init(sc) != 0) {
     231           0 :                 printf("%s: unable to initialise\n", DEVNAME(sc));
     232           0 :                 return (1);
     233             :         }
     234             : 
     235           0 :         if (mpi_iocfacts(sc) != 0) {
     236           0 :                 printf("%s: unable to get iocfacts\n", DEVNAME(sc));
     237           0 :                 return (1);
     238             :         }
     239             : 
     240           0 :         if (mpi_alloc_ccbs(sc) != 0) {
     241             :                 /* error already printed */
     242           0 :                 return (1);
     243             :         }
     244             : 
     245           0 :         if (mpi_alloc_replies(sc) != 0) {
     246           0 :                 printf("%s: unable to allocate reply space\n", DEVNAME(sc));
     247           0 :                 goto free_ccbs;
     248             :         }
     249             : 
     250           0 :         if (mpi_iocinit(sc) != 0) {
     251           0 :                 printf("%s: unable to send iocinit\n", DEVNAME(sc));
     252           0 :                 goto free_ccbs;
     253             :         }
     254             : 
     255             :         /* spin until we're operational */
     256           0 :         if (mpi_wait_eq(sc, MPI_DOORBELL, MPI_DOORBELL_STATE,
     257           0 :             MPI_DOORBELL_STATE_OPER) != 0) {
     258           0 :                 printf("%s: state: 0x%08x\n", DEVNAME(sc),
     259           0 :                     mpi_read_db(sc) & MPI_DOORBELL_STATE);
     260           0 :                 printf("%s: operational state timeout\n", DEVNAME(sc));
     261           0 :                 goto free_ccbs;
     262             :         }
     263             : 
     264           0 :         mpi_push_replies(sc);
     265             : 
     266           0 :         if (mpi_portfacts(sc) != 0) {
     267           0 :                 printf("%s: unable to get portfacts\n", DEVNAME(sc));
     268           0 :                 goto free_replies;
     269             :         }
     270             : 
     271           0 :         if (mpi_cfg_coalescing(sc) != 0) {
     272           0 :                 printf("%s: unable to configure coalescing\n", DEVNAME(sc));
     273           0 :                 goto free_replies;
     274             :         }
     275             : 
     276           0 :         switch (sc->sc_porttype) {
     277             :         case MPI_PORTFACTS_PORTTYPE_SAS:
     278           0 :                 SIMPLEQ_INIT(&sc->sc_evt_scan_queue);
     279           0 :                 mtx_init(&sc->sc_evt_scan_mtx, IPL_BIO);
     280           0 :                 scsi_ioh_set(&sc->sc_evt_scan_handler, &sc->sc_iopool,
     281             :                     mpi_evt_sas_detach, sc);
     282             :                 /* FALLTHROUGH */
     283             :         case MPI_PORTFACTS_PORTTYPE_FC:
     284           0 :                 if (mpi_eventnotify(sc) != 0) {
     285           0 :                         printf("%s: unable to enable events\n", DEVNAME(sc));
     286           0 :                         goto free_replies;
     287             :                 }
     288             :                 break;
     289             :         }
     290             : 
     291           0 :         if (mpi_portenable(sc) != 0) {
     292           0 :                 printf("%s: unable to enable port\n", DEVNAME(sc));
     293           0 :                 goto free_replies;
     294             :         }
     295             : 
     296           0 :         if (mpi_fwupload(sc) != 0) {
     297           0 :                 printf("%s: unable to upload firmware\n", DEVNAME(sc));
     298           0 :                 goto free_replies;
     299             :         }
     300             : 
     301           0 :         if (mpi_manufacturing(sc) != 0) {
     302           0 :                 printf("%s: unable to fetch manufacturing info\n", DEVNAME(sc));              goto free_replies;
     303             :         }
     304             : 
     305           0 :         switch (sc->sc_porttype) {
     306             :         case MPI_PORTFACTS_PORTTYPE_SCSI:
     307           0 :                 if (mpi_cfg_spi_port(sc) != 0) {
     308           0 :                         printf("%s: unable to configure spi\n", DEVNAME(sc));
     309           0 :                         goto free_replies;
     310             :                 }
     311           0 :                 mpi_squash_ppr(sc);
     312           0 :                 break;
     313             :         case MPI_PORTFACTS_PORTTYPE_SAS:
     314           0 :                 if (mpi_cfg_sas(sc) != 0) {
     315           0 :                         printf("%s: unable to configure sas\n", DEVNAME(sc));
     316           0 :                         goto free_replies;
     317             :                 }
     318             :                 break;
     319             :         case MPI_PORTFACTS_PORTTYPE_FC:
     320           0 :                 if (mpi_cfg_fc(sc) != 0) {
     321           0 :                         printf("%s: unable to configure fc\n", DEVNAME(sc));
     322           0 :                         goto free_replies;
     323             :                 }
     324             :                 break;
     325             :         }
     326             : 
     327             :         /* get raid pages */
     328           0 :         mpi_get_raid(sc);
     329             : #if NBIO > 0
     330           0 :         if (sc->sc_flags & MPI_F_RAID) {
     331           0 :                 if (bio_register(&sc->sc_dev, mpi_ioctl) != 0)
     332           0 :                         panic("%s: controller registration failed",
     333           0 :                             DEVNAME(sc));
     334             :                 else {
     335           0 :                         if (mpi_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_IOC,
     336           0 :                             2, 0, &sc->sc_cfg_hdr) != 0) {
     337           0 :                                 panic("%s: can't get IOC page 2 hdr",
     338           0 :                                     DEVNAME(sc));
     339             :                         }
     340             : 
     341           0 :                         sc->sc_vol_page = mallocarray(sc->sc_cfg_hdr.page_length,
     342             :                             4, M_TEMP, M_WAITOK | M_CANFAIL);
     343           0 :                         if (sc->sc_vol_page == NULL) {
     344           0 :                                 panic("%s: can't get memory for IOC page 2, "
     345           0 :                                     "bio disabled", DEVNAME(sc));
     346             :                         }
     347             : 
     348           0 :                         if (mpi_cfg_page(sc, 0, &sc->sc_cfg_hdr, 1,
     349             :                             sc->sc_vol_page,
     350           0 :                             sc->sc_cfg_hdr.page_length * 4) != 0) {
     351           0 :                                 panic("%s: can't get IOC page 2", DEVNAME(sc));
     352             :                         }
     353             : 
     354           0 :                         sc->sc_vol_list = (struct mpi_cfg_raid_vol *)
     355           0 :                             (sc->sc_vol_page + 1);
     356             :  
     357           0 :                         sc->sc_ioctl = mpi_ioctl;
     358             :                 }
     359           0 :         }
     360             : #endif /* NBIO > 0 */
     361             : 
     362             :         /* we should be good to go now, attach scsibus */
     363           0 :         sc->sc_link.adapter = &mpi_switch;
     364           0 :         sc->sc_link.adapter_softc = sc;
     365           0 :         sc->sc_link.adapter_target = sc->sc_target;
     366           0 :         sc->sc_link.adapter_buswidth = sc->sc_buswidth;
     367           0 :         sc->sc_link.openings = MAX(sc->sc_maxcmds / sc->sc_buswidth, 16);
     368           0 :         sc->sc_link.pool = &sc->sc_iopool;
     369             : 
     370           0 :         memset(&saa, 0, sizeof(saa));
     371           0 :         saa.saa_sc_link = &sc->sc_link;
     372             : 
     373             :         /* config_found() returns the scsibus attached to us */
     374           0 :         sc->sc_scsibus = (struct scsibus_softc *) config_found(&sc->sc_dev,
     375             :             &saa, scsiprint);
     376             : 
     377             :         /* do domain validation */
     378           0 :         if (sc->sc_porttype == MPI_PORTFACTS_PORTTYPE_SCSI)
     379           0 :                 mpi_run_ppr(sc);
     380             : 
     381             :         /* enable interrupts */
     382           0 :         mpi_write(sc, MPI_INTR_MASK, MPI_INTR_MASK_DOORBELL);
     383             : 
     384             : #if NBIO > 0
     385             : #ifndef SMALL_KERNEL
     386           0 :         mpi_create_sensors(sc);
     387             : #endif /* SMALL_KERNEL */
     388             : #endif /* NBIO > 0 */
     389             : 
     390           0 :         return (0);
     391             : 
     392             : free_replies:
     393           0 :         bus_dmamap_sync(sc->sc_dmat, MPI_DMA_MAP(sc->sc_replies), 0,
     394             :             sc->sc_repq * MPI_REPLY_SIZE, BUS_DMASYNC_POSTREAD);
     395           0 :         mpi_dmamem_free(sc, sc->sc_replies);
     396             : free_ccbs:
     397           0 :         while ((ccb = mpi_get_ccb(sc)) != NULL)
     398           0 :                 bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
     399           0 :         mpi_dmamem_free(sc, sc->sc_requests);
     400           0 :         free(sc->sc_ccbs, M_DEVBUF, 0);
     401             : 
     402           0 :         return(1);
     403           0 : }
     404             : 
     405             : int
     406           0 : mpi_cfg_spi_port(struct mpi_softc *sc)
     407             : {
     408           0 :         struct mpi_cfg_hdr              hdr;
     409           0 :         struct mpi_cfg_spi_port_pg1     port;
     410             : 
     411           0 :         if (mpi_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_SCSI_SPI_PORT, 1, 0x0,
     412           0 :             &hdr) != 0)
     413           0 :                 return (1);
     414             : 
     415           0 :         if (mpi_cfg_page(sc, 0x0, &hdr, 1, &port, sizeof(port)) != 0)
     416           0 :                 return (1);
     417             : 
     418             :         DNPRINTF(MPI_D_MISC, "%s: mpi_cfg_spi_port_pg1\n", DEVNAME(sc));
     419             :         DNPRINTF(MPI_D_MISC, "%s:  port_scsi_id: %d port_resp_ids 0x%04x\n",
     420             :             DEVNAME(sc), port.port_scsi_id, letoh16(port.port_resp_ids));
     421             :         DNPRINTF(MPI_D_MISC, "%s:  on_bus_timer_value: 0x%08x\n", DEVNAME(sc),
     422             :             letoh32(port.port_scsi_id));
     423             :         DNPRINTF(MPI_D_MISC, "%s:  target_config: 0x%02x id_config: 0x%04x\n",
     424             :             DEVNAME(sc), port.target_config, letoh16(port.id_config));
     425             : 
     426           0 :         if (port.port_scsi_id == sc->sc_target &&
     427           0 :             port.port_resp_ids == htole16(1 << sc->sc_target) &&
     428           0 :             port.on_bus_timer_value != htole32(0x0))
     429           0 :                 return (0);
     430             : 
     431             :         DNPRINTF(MPI_D_MISC, "%s: setting port scsi id to %d\n", DEVNAME(sc),
     432             :             sc->sc_target);
     433           0 :         port.port_scsi_id = sc->sc_target;
     434           0 :         port.port_resp_ids = htole16(1 << sc->sc_target);
     435           0 :         port.on_bus_timer_value = htole32(0x07000000); /* XXX magic */
     436             : 
     437           0 :         if (mpi_cfg_page(sc, 0x0, &hdr, 0, &port, sizeof(port)) != 0) {
     438           0 :                 printf("%s: unable to configure port scsi id\n", DEVNAME(sc));
     439           0 :                 return (1);
     440             :         }
     441             : 
     442           0 :         return (0);
     443           0 : }
     444             : 
     445             : void
     446           0 : mpi_squash_ppr(struct mpi_softc *sc)
     447             : {
     448           0 :         struct mpi_cfg_hdr              hdr;
     449           0 :         struct mpi_cfg_spi_dev_pg1      page;
     450             :         int                             i;
     451             : 
     452             :         DNPRINTF(MPI_D_PPR, "%s: mpi_squash_ppr\n", DEVNAME(sc));
     453             : 
     454           0 :         for (i = 0; i < sc->sc_buswidth; i++) {
     455           0 :                 if (mpi_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_SCSI_SPI_DEV,
     456           0 :                     1, i, &hdr) != 0)
     457           0 :                         return;
     458             : 
     459           0 :                 if (mpi_cfg_page(sc, i, &hdr, 1, &page, sizeof(page)) != 0)
     460           0 :                         return;
     461             : 
     462             :                 DNPRINTF(MPI_D_PPR, "%s:  target: %d req_params1: 0x%02x "
     463             :                     "req_offset: 0x%02x req_period: 0x%02x "
     464             :                     "req_params2: 0x%02x conf: 0x%08x\n", DEVNAME(sc), i,
     465             :                     page.req_params1, page.req_offset, page.req_period,
     466             :                     page.req_params2, letoh32(page.configuration));
     467             : 
     468           0 :                 page.req_params1 = 0x0;
     469           0 :                 page.req_offset = 0x0;
     470           0 :                 page.req_period = 0x0;
     471           0 :                 page.req_params2 = 0x0;
     472           0 :                 page.configuration = htole32(0x0);
     473             : 
     474           0 :                 if (mpi_cfg_page(sc, i, &hdr, 0, &page, sizeof(page)) != 0)
     475           0 :                         return;
     476             :         }
     477           0 : }
     478             : 
     479             : void
     480           0 : mpi_run_ppr(struct mpi_softc *sc)
     481             : {
     482           0 :         struct mpi_cfg_hdr              hdr;
     483           0 :         struct mpi_cfg_spi_port_pg0     port_pg;
     484             :         struct mpi_cfg_ioc_pg3          *physdisk_pg;
     485             :         struct mpi_cfg_raid_physdisk    *physdisk_list, *physdisk;
     486             :         size_t                          pagelen;
     487             :         struct scsi_link                *link;
     488             :         int                             i, tries;
     489             : 
     490           0 :         if (mpi_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_SCSI_SPI_PORT, 0, 0x0,
     491           0 :             &hdr) != 0) {
     492             :                 DNPRINTF(MPI_D_PPR, "%s: mpi_run_ppr unable to fetch header\n",
     493             :                     DEVNAME(sc));
     494           0 :                 return;
     495             :         }
     496             : 
     497           0 :         if (mpi_cfg_page(sc, 0x0, &hdr, 1, &port_pg, sizeof(port_pg)) != 0) {
     498             :                 DNPRINTF(MPI_D_PPR, "%s: mpi_run_ppr unable to fetch page\n",
     499             :                     DEVNAME(sc));
     500           0 :                 return;
     501             :         }
     502             : 
     503           0 :         for (i = 0; i < sc->sc_buswidth; i++) {
     504           0 :                 link = scsi_get_link(sc->sc_scsibus, i, 0);
     505           0 :                 if (link == NULL)
     506             :                         continue;
     507             : 
     508             :                 /* do not ppr volumes */
     509           0 :                 if (link->flags & SDEV_VIRTUAL)
     510             :                         continue;
     511             : 
     512             :                 tries = 0;
     513           0 :                 while (mpi_ppr(sc, link, NULL, port_pg.min_period,
     514           0 :                     port_pg.max_offset, tries) == EAGAIN)
     515           0 :                         tries++;
     516             :         }
     517             : 
     518           0 :         if ((sc->sc_flags & MPI_F_RAID) == 0)
     519           0 :                 return;
     520             : 
     521           0 :         if (mpi_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_IOC, 3, 0x0,
     522           0 :             &hdr) != 0) {
     523             :                 DNPRINTF(MPI_D_RAID|MPI_D_PPR, "%s: mpi_run_ppr unable to "
     524             :                     "fetch ioc pg 3 header\n", DEVNAME(sc));
     525           0 :                 return;
     526             :         }
     527             : 
     528           0 :         pagelen = hdr.page_length * 4; /* dwords to bytes */
     529           0 :         physdisk_pg = malloc(pagelen, M_TEMP, M_WAITOK|M_CANFAIL);
     530           0 :         if (physdisk_pg == NULL) {
     531             :                 DNPRINTF(MPI_D_RAID|MPI_D_PPR, "%s: mpi_run_ppr unable to "
     532             :                     "allocate ioc pg 3\n", DEVNAME(sc));
     533           0 :                 return;
     534             :         }
     535           0 :         physdisk_list = (struct mpi_cfg_raid_physdisk *)(physdisk_pg + 1);
     536             : 
     537           0 :         if (mpi_cfg_page(sc, 0, &hdr, 1, physdisk_pg, pagelen) != 0) {
     538             :                 DNPRINTF(MPI_D_PPR|MPI_D_PPR, "%s: mpi_run_ppr unable to "
     539             :                     "fetch ioc page 3\n", DEVNAME(sc));
     540             :                 goto out;
     541             :         }
     542             : 
     543             :         DNPRINTF(MPI_D_PPR|MPI_D_PPR, "%s:  no_phys_disks: %d\n", DEVNAME(sc),
     544             :             physdisk_pg->no_phys_disks);
     545             : 
     546           0 :         for (i = 0; i < physdisk_pg->no_phys_disks; i++) {
     547           0 :                 physdisk = &physdisk_list[i];
     548             : 
     549             :                 DNPRINTF(MPI_D_PPR|MPI_D_PPR, "%s:  id: %d bus: %d ioc: %d "
     550             :                     "num: %d\n", DEVNAME(sc), physdisk->phys_disk_id,
     551             :                     physdisk->phys_disk_bus, physdisk->phys_disk_ioc,
     552             :                     physdisk->phys_disk_num);
     553             : 
     554           0 :                 if (physdisk->phys_disk_ioc != sc->sc_ioc_number)
     555             :                         continue;
     556             : 
     557             :                 tries = 0;
     558           0 :                 while (mpi_ppr(sc, NULL, physdisk, port_pg.min_period,
     559           0 :                     port_pg.max_offset, tries) == EAGAIN)
     560           0 :                         tries++;
     561             :         }
     562             : 
     563             : out:
     564           0 :         free(physdisk_pg, M_TEMP, pagelen);
     565           0 : }
     566             : 
     567             : int
     568           0 : mpi_ppr(struct mpi_softc *sc, struct scsi_link *link,
     569             :     struct mpi_cfg_raid_physdisk *physdisk, int period, int offset, int try)
     570             : {
     571           0 :         struct mpi_cfg_hdr              hdr0, hdr1;
     572           0 :         struct mpi_cfg_spi_dev_pg0      pg0;
     573           0 :         struct mpi_cfg_spi_dev_pg1      pg1;
     574             :         u_int32_t                       address;
     575             :         int                             id;
     576             :         int                             raid = 0;
     577             : 
     578             :         DNPRINTF(MPI_D_PPR, "%s: mpi_ppr period: %d offset: %d try: %d "
     579             :             "link quirks: 0x%x\n", DEVNAME(sc), period, offset, try,
     580             :             link->quirks);
     581             : 
     582           0 :         if (try >= 3)
     583           0 :                 return (EIO);
     584             : 
     585           0 :         if (physdisk == NULL) {
     586           0 :                 if ((link->inqdata.device & SID_TYPE) == T_PROCESSOR)
     587           0 :                         return (EIO);
     588             : 
     589           0 :                 address = link->target;
     590             :                 id = link->target;
     591           0 :         } else {
     592             :                 raid = 1;
     593           0 :                 address = (physdisk->phys_disk_bus << 8) |
     594           0 :                     (physdisk->phys_disk_id);
     595           0 :                 id = physdisk->phys_disk_num;
     596             :         }
     597             : 
     598           0 :         if (mpi_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_SCSI_SPI_DEV, 0,
     599           0 :             address, &hdr0) != 0) {
     600             :                 DNPRINTF(MPI_D_PPR, "%s: mpi_ppr unable to fetch header 0\n",
     601             :                     DEVNAME(sc));
     602           0 :                 return (EIO);
     603             :         }
     604             : 
     605           0 :         if (mpi_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_SCSI_SPI_DEV, 1,
     606           0 :             address, &hdr1) != 0) {
     607             :                 DNPRINTF(MPI_D_PPR, "%s: mpi_ppr unable to fetch header 1\n",
     608             :                     DEVNAME(sc));
     609           0 :                 return (EIO);
     610             :         }
     611             : 
     612             : #ifdef MPI_DEBUG
     613             :         if (mpi_cfg_page(sc, address, &hdr0, 1, &pg0, sizeof(pg0)) != 0) {
     614             :                 DNPRINTF(MPI_D_PPR, "%s: mpi_ppr unable to fetch page 0\n",
     615             :                     DEVNAME(sc));
     616             :                 return (EIO);
     617             :         }
     618             : 
     619             :         DNPRINTF(MPI_D_PPR, "%s: mpi_ppr dev pg 0 neg_params1: 0x%02x "
     620             :             "neg_offset: %d neg_period: 0x%02x neg_params2: 0x%02x "
     621             :             "info: 0x%08x\n", DEVNAME(sc), pg0.neg_params1, pg0.neg_offset,
     622             :             pg0.neg_period, pg0.neg_params2, letoh32(pg0.information));
     623             : #endif
     624             : 
     625           0 :         if (mpi_cfg_page(sc, address, &hdr1, 1, &pg1, sizeof(pg1)) != 0) {
     626             :                 DNPRINTF(MPI_D_PPR, "%s: mpi_ppr unable to fetch page 1\n",
     627             :                     DEVNAME(sc));
     628           0 :                 return (EIO);
     629             :         }
     630             : 
     631             :         DNPRINTF(MPI_D_PPR, "%s: mpi_ppr dev pg 1 req_params1: 0x%02x "
     632             :             "req_offset: 0x%02x req_period: 0x%02x req_params2: 0x%02x "
     633             :             "conf: 0x%08x\n", DEVNAME(sc), pg1.req_params1, pg1.req_offset,
     634             :             pg1.req_period, pg1.req_params2, letoh32(pg1.configuration));
     635             : 
     636           0 :         pg1.req_params1 = 0;
     637           0 :         pg1.req_offset = offset;
     638           0 :         pg1.req_period = period;
     639           0 :         pg1.req_params2 &= ~MPI_CFG_SPI_DEV_1_REQPARAMS_WIDTH;
     640             : 
     641           0 :         if (raid || !(link->quirks & SDEV_NOSYNC)) {
     642           0 :                 pg1.req_params2 |= MPI_CFG_SPI_DEV_1_REQPARAMS_WIDTH_WIDE;
     643             : 
     644           0 :                 switch (try) {
     645             :                 case 0: /* U320 */
     646             :                         break;
     647             :                 case 1: /* U160 */
     648           0 :                         pg1.req_period = 0x09;
     649           0 :                         break;
     650             :                 case 2: /* U80 */
     651           0 :                         pg1.req_period = 0x0a;
     652           0 :                         break;
     653             :                 }
     654             : 
     655           0 :                 if (pg1.req_period < 0x09) {
     656             :                         /* Ultra320: enable QAS & PACKETIZED */
     657           0 :                         pg1.req_params1 |= MPI_CFG_SPI_DEV_1_REQPARAMS_QAS |
     658             :                             MPI_CFG_SPI_DEV_1_REQPARAMS_PACKETIZED;
     659           0 :                 }
     660           0 :                 if (pg1.req_period < 0xa) {
     661             :                         /* >= Ultra160: enable dual xfers */
     662           0 :                         pg1.req_params1 |=
     663             :                             MPI_CFG_SPI_DEV_1_REQPARAMS_DUALXFERS;
     664           0 :                 }
     665             :         }
     666             : 
     667             :         DNPRINTF(MPI_D_PPR, "%s: mpi_ppr dev pg 1 req_params1: 0x%02x "
     668             :             "req_offset: 0x%02x req_period: 0x%02x req_params2: 0x%02x "
     669             :             "conf: 0x%08x\n", DEVNAME(sc), pg1.req_params1, pg1.req_offset,
     670             :             pg1.req_period, pg1.req_params2, letoh32(pg1.configuration));
     671             : 
     672           0 :         if (mpi_cfg_page(sc, address, &hdr1, 0, &pg1, sizeof(pg1)) != 0) {
     673             :                 DNPRINTF(MPI_D_PPR, "%s: mpi_ppr unable to write page 1\n",
     674             :                     DEVNAME(sc));
     675           0 :                 return (EIO);
     676             :         }
     677             : 
     678           0 :         if (mpi_cfg_page(sc, address, &hdr1, 1, &pg1, sizeof(pg1)) != 0) {
     679             :                 DNPRINTF(MPI_D_PPR, "%s: mpi_ppr unable to read page 1\n",
     680             :                     DEVNAME(sc));
     681           0 :                 return (EIO);
     682             :         }
     683             : 
     684             :         DNPRINTF(MPI_D_PPR, "%s: mpi_ppr dev pg 1 req_params1: 0x%02x "
     685             :             "req_offset: 0x%02x req_period: 0x%02x req_params2: 0x%02x "
     686             :             "conf: 0x%08x\n", DEVNAME(sc), pg1.req_params1, pg1.req_offset,
     687             :             pg1.req_period, pg1.req_params2, letoh32(pg1.configuration));
     688             : 
     689           0 :         if (mpi_inq(sc, id, raid) != 0) {
     690             :                 DNPRINTF(MPI_D_PPR, "%s: mpi_ppr unable to do inquiry against "
     691             :                     "target %d\n", DEVNAME(sc), link->target);
     692           0 :                 return (EIO);
     693             :         }
     694             : 
     695           0 :         if (mpi_cfg_page(sc, address, &hdr0, 1, &pg0, sizeof(pg0)) != 0) {
     696             :                 DNPRINTF(MPI_D_PPR, "%s: mpi_ppr unable to read page 0 after "
     697             :                     "inquiry\n", DEVNAME(sc));
     698           0 :                 return (EIO);
     699             :         }
     700             : 
     701             :         DNPRINTF(MPI_D_PPR, "%s: mpi_ppr dev pg 0 neg_params1: 0x%02x "
     702             :             "neg_offset: %d neg_period: 0x%02x neg_params2: 0x%02x "
     703             :             "info: 0x%08x\n", DEVNAME(sc), pg0.neg_params1, pg0.neg_offset,
     704             :             pg0.neg_period, pg0.neg_params2, letoh32(pg0.information));
     705             : 
     706           0 :         if (!(lemtoh32(&pg0.information) & 0x07) && (try == 0)) {
     707             :                 DNPRINTF(MPI_D_PPR, "%s: mpi_ppr U320 ppr rejected\n",
     708             :                     DEVNAME(sc));
     709           0 :                 return (EAGAIN);
     710             :         }
     711             : 
     712           0 :         if ((((lemtoh32(&pg0.information) >> 8) & 0xff) > 0x09) && (try == 1)) {
     713             :                 DNPRINTF(MPI_D_PPR, "%s: mpi_ppr U160 ppr rejected\n",
     714             :                     DEVNAME(sc));
     715           0 :                 return (EAGAIN);
     716             :         }
     717             : 
     718           0 :         if (lemtoh32(&pg0.information) & 0x0e) {
     719             :                 DNPRINTF(MPI_D_PPR, "%s: mpi_ppr ppr rejected: %0x\n",
     720             :                     DEVNAME(sc), lemtoh32(&pg0.information));
     721           0 :                 return (EAGAIN);
     722             :         }
     723             : 
     724           0 :         switch(pg0.neg_period) {
     725             :         case 0x08:
     726             :                 period = 160;
     727           0 :                 break;
     728             :         case 0x09:
     729             :                 period = 80;
     730           0 :                 break;
     731             :         case 0x0a:
     732             :                 period = 40;
     733           0 :                 break;
     734             :         case 0x0b:
     735             :                 period = 20;
     736           0 :                 break;
     737             :         case 0x0c:
     738             :                 period = 10;
     739           0 :                 break;
     740             :         default:
     741             :                 period = 0;
     742           0 :                 break;
     743             :         }
     744             : 
     745           0 :         printf("%s: %s %d %s at %dMHz width %dbit offset %d "
     746           0 :             "QAS %d DT %d IU %d\n", DEVNAME(sc), raid ? "phys disk" : "target",
     747           0 :             id, period ? "Sync" : "Async", period,
     748           0 :             (pg0.neg_params2 & MPI_CFG_SPI_DEV_0_NEGPARAMS_WIDTH_WIDE) ? 16 : 8,
     749           0 :             pg0.neg_offset,
     750           0 :             (pg0.neg_params1 & MPI_CFG_SPI_DEV_0_NEGPARAMS_QAS) ? 1 : 0,
     751           0 :             (pg0.neg_params1 & MPI_CFG_SPI_DEV_0_NEGPARAMS_DUALXFERS) ? 1 : 0,
     752           0 :             (pg0.neg_params1 & MPI_CFG_SPI_DEV_0_NEGPARAMS_PACKETIZED) ? 1 : 0);
     753             : 
     754           0 :         return (0);
     755           0 : }
     756             : 
     757             : int
     758           0 : mpi_inq(struct mpi_softc *sc, u_int16_t target, int physdisk)
     759             : {
     760             :         struct mpi_ccb                  *ccb;
     761           0 :         struct scsi_inquiry             inq;
     762             :         struct inq_bundle {
     763             :                 struct mpi_msg_scsi_io          io;
     764             :                 struct mpi_sge                  sge;
     765             :                 struct scsi_inquiry_data        inqbuf;
     766             :                 struct scsi_sense_data          sense;
     767             :         } __packed                      *bundle;
     768             :         struct mpi_msg_scsi_io          *io;
     769             :         struct mpi_sge                  *sge;
     770             : 
     771             :         DNPRINTF(MPI_D_PPR, "%s: mpi_inq\n", DEVNAME(sc));
     772             : 
     773           0 :         memset(&inq, 0, sizeof(inq));
     774           0 :         inq.opcode = INQUIRY;
     775           0 :         _lto2b(sizeof(struct scsi_inquiry_data), inq.length);
     776             : 
     777           0 :         ccb = scsi_io_get(&sc->sc_iopool, SCSI_NOSLEEP);
     778           0 :         if (ccb == NULL)
     779           0 :                 return (1);
     780             : 
     781           0 :         ccb->ccb_done = mpi_empty_done;
     782             : 
     783           0 :         bundle = ccb->ccb_cmd;
     784           0 :         io = &bundle->io;
     785           0 :         sge = &bundle->sge;
     786             : 
     787           0 :         io->function = physdisk ? MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH :
     788             :             MPI_FUNCTION_SCSI_IO_REQUEST;
     789             :         /*
     790             :          * bus is always 0
     791             :          * io->bus = htole16(sc->sc_bus);
     792             :          */
     793           0 :         io->target_id = target;
     794             : 
     795           0 :         io->cdb_length = sizeof(inq);
     796           0 :         io->sense_buf_len = sizeof(struct scsi_sense_data);
     797           0 :         io->msg_flags = MPI_SCSIIO_SENSE_BUF_ADDR_WIDTH_64;
     798             : 
     799             :         /*
     800             :          * always lun 0
     801             :          * io->lun[0] = htobe16(link->lun);
     802             :          */
     803             : 
     804           0 :         io->direction = MPI_SCSIIO_DIR_READ;
     805           0 :         io->tagging = MPI_SCSIIO_ATTR_NO_DISCONNECT;
     806             : 
     807           0 :         memcpy(io->cdb, &inq, sizeof(inq));
     808             : 
     809           0 :         htolem32(&io->data_length, sizeof(struct scsi_inquiry_data));
     810             : 
     811           0 :         htolem32(&io->sense_buf_low_addr, ccb->ccb_cmd_dva +
     812             :             offsetof(struct inq_bundle, sense));
     813             : 
     814           0 :         htolem32(&sge->sg_hdr, MPI_SGE_FL_TYPE_SIMPLE | MPI_SGE_FL_SIZE_64 |
     815             :             MPI_SGE_FL_LAST | MPI_SGE_FL_EOB | MPI_SGE_FL_EOL |
     816             :             (u_int32_t)sizeof(inq));
     817             : 
     818           0 :         mpi_dvatosge(sge, ccb->ccb_cmd_dva +
     819             :             offsetof(struct inq_bundle, inqbuf));
     820             : 
     821           0 :         if (mpi_poll(sc, ccb, 5000) != 0)
     822           0 :                 return (1);
     823             : 
     824           0 :         if (ccb->ccb_rcb != NULL)
     825           0 :                 mpi_push_reply(sc, ccb->ccb_rcb);
     826             : 
     827           0 :         scsi_io_put(&sc->sc_iopool, ccb);
     828             : 
     829           0 :         return (0);
     830           0 : }
     831             : 
     832             : int
     833           0 : mpi_cfg_sas(struct mpi_softc *sc)
     834             : {
     835           0 :         struct mpi_ecfg_hdr             ehdr;
     836             :         struct mpi_cfg_sas_iou_pg1      *pg;
     837             :         size_t                          pagelen;
     838             :         int                             rv = 0;
     839             : 
     840           0 :         if (mpi_ecfg_header(sc, MPI_CONFIG_REQ_EXTPAGE_TYPE_SAS_IO_UNIT, 1, 0,
     841           0 :             &ehdr) != 0)
     842           0 :                 return (0);
     843             : 
     844           0 :         pagelen = lemtoh16(&ehdr.ext_page_length) * 4;
     845           0 :         pg = malloc(pagelen, M_TEMP, M_NOWAIT | M_ZERO);
     846           0 :         if (pg == NULL)
     847           0 :                 return (ENOMEM);
     848             : 
     849           0 :         if (mpi_ecfg_page(sc, 0, &ehdr, 1, pg, pagelen) != 0)
     850             :                 goto out;
     851             : 
     852           0 :         if (pg->max_sata_q_depth != 32) {
     853           0 :                 pg->max_sata_q_depth = 32;
     854             : 
     855           0 :                 if (mpi_ecfg_page(sc, 0, &ehdr, 0, pg, pagelen) != 0)
     856             :                         goto out;
     857             :         }
     858             : 
     859             : out:
     860           0 :         free(pg, M_TEMP, pagelen);
     861           0 :         return (rv);
     862           0 : }
     863             : 
     864             : int
     865           0 : mpi_cfg_fc(struct mpi_softc *sc)
     866             : {
     867           0 :         struct mpi_cfg_hdr              hdr;
     868           0 :         struct mpi_cfg_fc_port_pg0      pg0;
     869           0 :         struct mpi_cfg_fc_port_pg1      pg1;
     870             : 
     871           0 :         if (mpi_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_FC_PORT, 0, 0,
     872           0 :             &hdr) != 0) {
     873           0 :                 printf("%s: unable to fetch FC port header 0\n", DEVNAME(sc));
     874           0 :                 return (1);
     875             :         }
     876             : 
     877           0 :         if (mpi_cfg_page(sc, 0, &hdr, 1, &pg0, sizeof(pg0)) != 0) {
     878           0 :                 printf("%s: unable to fetch FC port page 0\n", DEVNAME(sc));
     879           0 :                 return (1);
     880             :         }
     881             : 
     882           0 :         sc->sc_link.port_wwn = letoh64(pg0.wwpn);
     883           0 :         sc->sc_link.node_wwn = letoh64(pg0.wwnn);
     884             : 
     885             :         /* configure port config more to our liking */
     886           0 :         if (mpi_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_FC_PORT, 1, 0,
     887           0 :             &hdr) != 0) {
     888           0 :                 printf("%s: unable to fetch FC port header 1\n", DEVNAME(sc));
     889           0 :                 return (1);
     890             :         }
     891             : 
     892           0 :         if (mpi_cfg_page(sc, 0, &hdr, 1, &pg1, sizeof(pg1)) != 0) {
     893           0 :                 printf("%s: unable to fetch FC port page 1\n", DEVNAME(sc));
     894           0 :                 return (1);
     895             :         }
     896             : 
     897           0 :         SET(pg1.flags, htole32(MPI_CFG_FC_PORT_0_FLAGS_IMMEDIATE_ERROR |
     898             :             MPI_CFG_FC_PORT_0_FLAGS_VERBOSE_RESCAN));
     899             : 
     900           0 :         if (mpi_cfg_page(sc, 0, &hdr, 0, &pg1, sizeof(pg1)) != 0) {
     901           0 :                 printf("%s: unable to set FC port page 1\n", DEVNAME(sc));
     902           0 :                 return (1);
     903             :         }
     904             : 
     905           0 :         return (0);
     906           0 : }
     907             : 
     908             : void
     909           0 : mpi_detach(struct mpi_softc *sc)
     910             : {
     911             : 
     912           0 : }
     913             : 
     914             : int
     915           0 : mpi_intr(void *arg)
     916             : {
     917           0 :         struct mpi_softc                *sc = arg;
     918             :         u_int32_t                       reg;
     919             :         int                             rv = 0;
     920             : 
     921           0 :         if ((mpi_read_intr(sc) & MPI_INTR_STATUS_REPLY) == 0)
     922           0 :                 return (rv);
     923             : 
     924           0 :         while ((reg = mpi_pop_reply(sc)) != 0xffffffff) {
     925           0 :                 mpi_reply(sc, reg);
     926             :                 rv = 1;
     927             :         }
     928             : 
     929           0 :         return (rv);
     930           0 : }
     931             : 
     932             : void
     933           0 : mpi_reply(struct mpi_softc *sc, u_int32_t reg)
     934             : {
     935             :         struct mpi_ccb                  *ccb;
     936             :         struct mpi_rcb                  *rcb = NULL;
     937             :         struct mpi_msg_reply            *reply = NULL;
     938             :         u_int32_t                       reply_dva;
     939             :         int                             id;
     940             :         int                             i;
     941             : 
     942             :         DNPRINTF(MPI_D_INTR, "%s: mpi_reply reg: 0x%08x\n", DEVNAME(sc), reg);
     943             : 
     944           0 :         if (reg & MPI_REPLY_QUEUE_ADDRESS) {
     945           0 :                 reply_dva = (reg & MPI_REPLY_QUEUE_ADDRESS_MASK) << 1;
     946           0 :                 i = (reply_dva - (u_int32_t)MPI_DMA_DVA(sc->sc_replies)) /
     947             :                     MPI_REPLY_SIZE;
     948           0 :                 rcb = &sc->sc_rcbs[i];
     949             : 
     950           0 :                 bus_dmamap_sync(sc->sc_dmat,
     951             :                     MPI_DMA_MAP(sc->sc_replies), rcb->rcb_offset,
     952             :                     MPI_REPLY_SIZE, BUS_DMASYNC_POSTREAD);
     953             : 
     954           0 :                 reply = rcb->rcb_reply;
     955             : 
     956           0 :                 id = lemtoh32(&reply->msg_context);
     957           0 :         } else {
     958           0 :                 switch (reg & MPI_REPLY_QUEUE_TYPE_MASK) {
     959             :                 case MPI_REPLY_QUEUE_TYPE_INIT:
     960           0 :                         id = reg & MPI_REPLY_QUEUE_CONTEXT;
     961             :                         break;
     962             : 
     963             :                 default:
     964           0 :                         panic("%s: unsupported context reply",
     965           0 :                             DEVNAME(sc));
     966             :                 }
     967             :         }
     968             : 
     969             :         DNPRINTF(MPI_D_INTR, "%s: mpi_reply id: %d reply: %p\n",
     970             :             DEVNAME(sc), id, reply);
     971             : 
     972           0 :         ccb = &sc->sc_ccbs[id];
     973             : 
     974           0 :         bus_dmamap_sync(sc->sc_dmat, MPI_DMA_MAP(sc->sc_requests),
     975             :             ccb->ccb_offset, MPI_REQUEST_SIZE,
     976             :             BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
     977           0 :         ccb->ccb_state = MPI_CCB_READY;
     978           0 :         ccb->ccb_rcb = rcb;
     979             : 
     980           0 :         ccb->ccb_done(ccb);
     981           0 : }
     982             : 
     983             : struct mpi_dmamem *
     984           0 : mpi_dmamem_alloc(struct mpi_softc *sc, size_t size)
     985             : {
     986             :         struct mpi_dmamem               *mdm;
     987           0 :         int                             nsegs;
     988             : 
     989           0 :         mdm = malloc(sizeof(struct mpi_dmamem), M_DEVBUF, M_NOWAIT | M_ZERO);
     990           0 :         if (mdm == NULL)
     991           0 :                 return (NULL);
     992             : 
     993           0 :         mdm->mdm_size = size;
     994             : 
     995           0 :         if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
     996           0 :             BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &mdm->mdm_map) != 0)
     997             :                 goto mdmfree;
     998             : 
     999           0 :         if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &mdm->mdm_seg,
    1000           0 :             1, &nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO) != 0)
    1001             :                 goto destroy;
    1002             : 
    1003           0 :         if (bus_dmamem_map(sc->sc_dmat, &mdm->mdm_seg, nsegs, size,
    1004           0 :             &mdm->mdm_kva, BUS_DMA_NOWAIT) != 0)
    1005             :                 goto free;
    1006             : 
    1007           0 :         if (bus_dmamap_load(sc->sc_dmat, mdm->mdm_map, mdm->mdm_kva, size,
    1008           0 :             NULL, BUS_DMA_NOWAIT) != 0)
    1009             :                 goto unmap;
    1010             : 
    1011             :         DNPRINTF(MPI_D_MEM, "%s: mpi_dmamem_alloc size: %d mdm: %#x "
    1012             :             "map: %#x nsegs: %d segs: %#x kva: %x\n",
    1013             :             DEVNAME(sc), size, mdm->mdm_map, nsegs, mdm->mdm_seg, mdm->mdm_kva);
    1014             : 
    1015           0 :         return (mdm);
    1016             : 
    1017             : unmap:
    1018           0 :         bus_dmamem_unmap(sc->sc_dmat, mdm->mdm_kva, size);
    1019             : free:
    1020           0 :         bus_dmamem_free(sc->sc_dmat, &mdm->mdm_seg, 1);
    1021             : destroy:
    1022           0 :         bus_dmamap_destroy(sc->sc_dmat, mdm->mdm_map);
    1023             : mdmfree:
    1024           0 :         free(mdm, M_DEVBUF, sizeof *mdm);
    1025             : 
    1026           0 :         return (NULL);
    1027           0 : }
    1028             : 
    1029             : void
    1030           0 : mpi_dmamem_free(struct mpi_softc *sc, struct mpi_dmamem *mdm)
    1031             : {
    1032             :         DNPRINTF(MPI_D_MEM, "%s: mpi_dmamem_free %#x\n", DEVNAME(sc), mdm);
    1033             : 
    1034           0 :         bus_dmamap_unload(sc->sc_dmat, mdm->mdm_map);
    1035           0 :         bus_dmamem_unmap(sc->sc_dmat, mdm->mdm_kva, mdm->mdm_size);
    1036           0 :         bus_dmamem_free(sc->sc_dmat, &mdm->mdm_seg, 1);
    1037           0 :         bus_dmamap_destroy(sc->sc_dmat, mdm->mdm_map);
    1038           0 :         free(mdm, M_DEVBUF, sizeof *mdm);
    1039           0 : }
    1040             : 
    1041             : int
    1042           0 : mpi_alloc_ccbs(struct mpi_softc *sc)
    1043             : {
    1044             :         struct mpi_ccb                  *ccb;
    1045             :         u_int8_t                        *cmd;
    1046             :         int                             i;
    1047             : 
    1048           0 :         SLIST_INIT(&sc->sc_ccb_free);
    1049           0 :         mtx_init(&sc->sc_ccb_mtx, IPL_BIO);
    1050             : 
    1051           0 :         sc->sc_ccbs = mallocarray(sc->sc_maxcmds, sizeof(struct mpi_ccb),
    1052             :             M_DEVBUF, M_WAITOK | M_CANFAIL | M_ZERO);
    1053           0 :         if (sc->sc_ccbs == NULL) {
    1054           0 :                 printf("%s: unable to allocate ccbs\n", DEVNAME(sc));
    1055           0 :                 return (1);
    1056             :         }
    1057             : 
    1058           0 :         sc->sc_requests = mpi_dmamem_alloc(sc,
    1059           0 :             MPI_REQUEST_SIZE * sc->sc_maxcmds);
    1060           0 :         if (sc->sc_requests == NULL) {
    1061           0 :                 printf("%s: unable to allocate ccb dmamem\n", DEVNAME(sc));
    1062           0 :                 goto free_ccbs;
    1063             :         }
    1064           0 :         cmd = MPI_DMA_KVA(sc->sc_requests);
    1065           0 :         memset(cmd, 0, MPI_REQUEST_SIZE * sc->sc_maxcmds);
    1066             : 
    1067           0 :         for (i = 0; i < sc->sc_maxcmds; i++) {
    1068           0 :                 ccb = &sc->sc_ccbs[i];
    1069             : 
    1070           0 :                 if (bus_dmamap_create(sc->sc_dmat, MAXPHYS,
    1071             :                     sc->sc_max_sgl_len, MAXPHYS, 0,
    1072             :                     BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
    1073           0 :                     &ccb->ccb_dmamap) != 0) {
    1074           0 :                         printf("%s: unable to create dma map\n", DEVNAME(sc));
    1075             :                         goto free_maps;
    1076             :                 }
    1077             : 
    1078           0 :                 ccb->ccb_sc = sc;
    1079           0 :                 ccb->ccb_id = i;
    1080           0 :                 ccb->ccb_offset = MPI_REQUEST_SIZE * i;
    1081           0 :                 ccb->ccb_state = MPI_CCB_READY;
    1082             : 
    1083           0 :                 ccb->ccb_cmd = &cmd[ccb->ccb_offset];
    1084           0 :                 ccb->ccb_cmd_dva = (u_int32_t)MPI_DMA_DVA(sc->sc_requests) +
    1085           0 :                     ccb->ccb_offset;
    1086             : 
    1087             :                 DNPRINTF(MPI_D_CCB, "%s: mpi_alloc_ccbs(%d) ccb: %#x map: %#x "
    1088             :                     "sc: %#x id: %#x offs: %#x cmd: %#x dva: %#x\n",
    1089             :                     DEVNAME(sc), i, ccb, ccb->ccb_dmamap, ccb->ccb_sc,
    1090             :                     ccb->ccb_id, ccb->ccb_offset, ccb->ccb_cmd,
    1091             :                     ccb->ccb_cmd_dva);
    1092             : 
    1093           0 :                 mpi_put_ccb(sc, ccb);
    1094             :         }
    1095             : 
    1096           0 :         scsi_iopool_init(&sc->sc_iopool, sc, mpi_get_ccb, mpi_put_ccb);
    1097             : 
    1098           0 :         return (0);
    1099             : 
    1100             : free_maps:
    1101           0 :         while ((ccb = mpi_get_ccb(sc)) != NULL)
    1102           0 :                 bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
    1103             : 
    1104           0 :         mpi_dmamem_free(sc, sc->sc_requests);
    1105             : free_ccbs:
    1106           0 :         free(sc->sc_ccbs, M_DEVBUF, 0);
    1107             : 
    1108           0 :         return (1);
    1109           0 : }
    1110             : 
    1111             : void *
    1112           0 : mpi_get_ccb(void *xsc)
    1113             : {
    1114           0 :         struct mpi_softc                *sc = xsc;
    1115             :         struct mpi_ccb                  *ccb;
    1116             : 
    1117           0 :         mtx_enter(&sc->sc_ccb_mtx);
    1118           0 :         ccb = SLIST_FIRST(&sc->sc_ccb_free);
    1119           0 :         if (ccb != NULL) {
    1120           0 :                 SLIST_REMOVE_HEAD(&sc->sc_ccb_free, ccb_link);
    1121           0 :                 ccb->ccb_state = MPI_CCB_READY;
    1122           0 :         }
    1123           0 :         mtx_leave(&sc->sc_ccb_mtx);
    1124             : 
    1125             :         DNPRINTF(MPI_D_CCB, "%s: mpi_get_ccb %p\n", DEVNAME(sc), ccb);
    1126             : 
    1127           0 :         return (ccb);
    1128             : }
    1129             : 
    1130             : void
    1131           0 : mpi_put_ccb(void *xsc, void *io)
    1132             : {
    1133           0 :         struct mpi_softc                *sc = xsc;
    1134           0 :         struct mpi_ccb                  *ccb = io;
    1135             : 
    1136             :         DNPRINTF(MPI_D_CCB, "%s: mpi_put_ccb %p\n", DEVNAME(sc), ccb);
    1137             : 
    1138             : #ifdef DIAGNOSTIC
    1139           0 :         if (ccb->ccb_state == MPI_CCB_FREE)
    1140           0 :                 panic("mpi_put_ccb: double free");
    1141             : #endif
    1142             : 
    1143           0 :         ccb->ccb_state = MPI_CCB_FREE;
    1144           0 :         ccb->ccb_cookie = NULL;
    1145           0 :         ccb->ccb_done = NULL;
    1146           0 :         memset(ccb->ccb_cmd, 0, MPI_REQUEST_SIZE);
    1147           0 :         mtx_enter(&sc->sc_ccb_mtx);
    1148           0 :         SLIST_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_link);
    1149           0 :         mtx_leave(&sc->sc_ccb_mtx);
    1150           0 : }
    1151             : 
    1152             : int
    1153           0 : mpi_alloc_replies(struct mpi_softc *sc)
    1154             : {
    1155             :         DNPRINTF(MPI_D_MISC, "%s: mpi_alloc_replies\n", DEVNAME(sc));
    1156             : 
    1157           0 :         sc->sc_rcbs = mallocarray(sc->sc_repq, sizeof(struct mpi_rcb), M_DEVBUF,
    1158             :             M_WAITOK|M_CANFAIL);
    1159           0 :         if (sc->sc_rcbs == NULL)
    1160           0 :                 return (1);
    1161             : 
    1162           0 :         sc->sc_replies = mpi_dmamem_alloc(sc, sc->sc_repq * MPI_REPLY_SIZE);
    1163           0 :         if (sc->sc_replies == NULL) {
    1164           0 :                 free(sc->sc_rcbs, M_DEVBUF, 0);
    1165           0 :                 return (1);
    1166             :         }
    1167             : 
    1168           0 :         return (0);
    1169           0 : }
    1170             : 
    1171             : void
    1172           0 : mpi_push_reply(struct mpi_softc *sc, struct mpi_rcb *rcb)
    1173             : {
    1174           0 :         bus_dmamap_sync(sc->sc_dmat, MPI_DMA_MAP(sc->sc_replies),
    1175             :             rcb->rcb_offset, MPI_REPLY_SIZE, BUS_DMASYNC_PREREAD);
    1176           0 :         mpi_push_reply_db(sc, rcb->rcb_reply_dva);
    1177           0 : }
    1178             : 
    1179             : void
    1180           0 : mpi_push_replies(struct mpi_softc *sc)
    1181             : {
    1182             :         struct mpi_rcb                  *rcb;
    1183           0 :         char                            *kva = MPI_DMA_KVA(sc->sc_replies);
    1184             :         int                             i;
    1185             : 
    1186           0 :         bus_dmamap_sync(sc->sc_dmat, MPI_DMA_MAP(sc->sc_replies), 0,
    1187             :             sc->sc_repq * MPI_REPLY_SIZE, BUS_DMASYNC_PREREAD);
    1188             : 
    1189           0 :         for (i = 0; i < sc->sc_repq; i++) {
    1190           0 :                 rcb = &sc->sc_rcbs[i];
    1191             : 
    1192           0 :                 rcb->rcb_reply = kva + MPI_REPLY_SIZE * i;
    1193           0 :                 rcb->rcb_offset = MPI_REPLY_SIZE * i;
    1194           0 :                 rcb->rcb_reply_dva = (u_int32_t)MPI_DMA_DVA(sc->sc_replies) +
    1195             :                     MPI_REPLY_SIZE * i;
    1196           0 :                 mpi_push_reply_db(sc, rcb->rcb_reply_dva);
    1197             :         }
    1198           0 : }
    1199             : 
    1200             : void
    1201           0 : mpi_start(struct mpi_softc *sc, struct mpi_ccb *ccb)
    1202             : {
    1203             :         struct mpi_msg_request *msg;
    1204             : 
    1205             :         DNPRINTF(MPI_D_RW, "%s: mpi_start %#x\n", DEVNAME(sc),
    1206             :             ccb->ccb_cmd_dva);
    1207             : 
    1208           0 :         msg = ccb->ccb_cmd;
    1209           0 :         htolem32(&msg->msg_context, ccb->ccb_id);
    1210             : 
    1211           0 :         bus_dmamap_sync(sc->sc_dmat, MPI_DMA_MAP(sc->sc_requests),
    1212             :             ccb->ccb_offset, MPI_REQUEST_SIZE,
    1213             :             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
    1214             : 
    1215           0 :         ccb->ccb_state = MPI_CCB_QUEUED;
    1216           0 :         bus_space_write_4(sc->sc_iot, sc->sc_ioh,
    1217             :             MPI_REQ_QUEUE, ccb->ccb_cmd_dva);
    1218           0 : }
    1219             : 
    1220             : int
    1221           0 : mpi_poll(struct mpi_softc *sc, struct mpi_ccb *ccb, int timeout)
    1222             : {
    1223             :         void                            (*done)(struct mpi_ccb *);
    1224             :         void                            *cookie;
    1225           0 :         int                             rv = 1;
    1226             :         u_int32_t                       reg;
    1227             : 
    1228             :         DNPRINTF(MPI_D_INTR, "%s: mpi_poll timeout %d\n", DEVNAME(sc),
    1229             :             timeout);
    1230             : 
    1231           0 :         done = ccb->ccb_done;
    1232           0 :         cookie = ccb->ccb_cookie;
    1233             : 
    1234           0 :         ccb->ccb_done = mpi_poll_done;
    1235           0 :         ccb->ccb_cookie = &rv;
    1236             : 
    1237           0 :         mpi_start(sc, ccb);
    1238           0 :         while (rv == 1) {
    1239           0 :                 reg = mpi_pop_reply(sc);
    1240           0 :                 if (reg == 0xffffffff) {
    1241           0 :                         if (timeout-- == 0) {
    1242           0 :                                 printf("%s: timeout\n", DEVNAME(sc));
    1243           0 :                                 goto timeout;
    1244             :                         }
    1245             : 
    1246           0 :                         delay(1000);
    1247           0 :                         continue;
    1248             :                 }
    1249             : 
    1250           0 :                 mpi_reply(sc, reg);
    1251             :         }
    1252             : 
    1253           0 :         ccb->ccb_cookie = cookie;
    1254           0 :         done(ccb);
    1255             : 
    1256             : timeout:
    1257           0 :         return (rv);
    1258           0 : }
    1259             : 
    1260             : void
    1261           0 : mpi_poll_done(struct mpi_ccb *ccb)
    1262             : {
    1263           0 :         int                             *rv = ccb->ccb_cookie;
    1264             : 
    1265           0 :         *rv = 0;
    1266           0 : }
    1267             : 
    1268             : void
    1269           0 : mpi_wait(struct mpi_softc *sc, struct mpi_ccb *ccb)
    1270             : {
    1271           0 :         struct mutex                    cookie = MUTEX_INITIALIZER(IPL_BIO);
    1272             :         void                            (*done)(struct mpi_ccb *);
    1273             : 
    1274           0 :         done = ccb->ccb_done;
    1275           0 :         ccb->ccb_done = mpi_wait_done;
    1276           0 :         ccb->ccb_cookie = &cookie;
    1277             : 
    1278             :         /* XXX this will wait forever for the ccb to complete */
    1279             : 
    1280           0 :         mpi_start(sc, ccb);
    1281             : 
    1282           0 :         mtx_enter(&cookie);
    1283           0 :         while (ccb->ccb_cookie != NULL)
    1284           0 :                 msleep(ccb, &cookie, PRIBIO, "mpiwait", 0);
    1285           0 :         mtx_leave(&cookie);
    1286             : 
    1287           0 :         done(ccb);
    1288           0 : }
    1289             : 
    1290             : void
    1291           0 : mpi_wait_done(struct mpi_ccb *ccb)
    1292             : {
    1293           0 :         struct mutex                    *cookie = ccb->ccb_cookie;
    1294             : 
    1295           0 :         mtx_enter(cookie);
    1296           0 :         ccb->ccb_cookie = NULL;
    1297           0 :         wakeup_one(ccb);
    1298           0 :         mtx_leave(cookie);
    1299           0 : }
    1300             : 
    1301             : void
    1302           0 : mpi_scsi_cmd(struct scsi_xfer *xs)
    1303             : {
    1304           0 :         struct scsi_link                *link = xs->sc_link;
    1305           0 :         struct mpi_softc                *sc = link->adapter_softc;
    1306             :         struct mpi_ccb                  *ccb;
    1307             :         struct mpi_ccb_bundle           *mcb;
    1308             :         struct mpi_msg_scsi_io          *io;
    1309             : 
    1310             :         DNPRINTF(MPI_D_CMD, "%s: mpi_scsi_cmd\n", DEVNAME(sc));
    1311             : 
    1312           0 :         KERNEL_UNLOCK();
    1313             : 
    1314           0 :         if (xs->cmdlen > MPI_CDB_LEN) {
    1315             :                 DNPRINTF(MPI_D_CMD, "%s: CBD too big %d\n",
    1316             :                     DEVNAME(sc), xs->cmdlen);
    1317           0 :                 memset(&xs->sense, 0, sizeof(xs->sense));
    1318           0 :                 xs->sense.error_code = SSD_ERRCODE_VALID | SSD_ERRCODE_CURRENT;
    1319           0 :                 xs->sense.flags = SKEY_ILLEGAL_REQUEST;
    1320           0 :                 xs->sense.add_sense_code = 0x20;
    1321           0 :                 xs->error = XS_SENSE;
    1322           0 :                 goto done;
    1323             :         }
    1324             : 
    1325           0 :         ccb = xs->io;
    1326             : 
    1327             :         DNPRINTF(MPI_D_CMD, "%s: ccb_id: %d xs->flags: 0x%x\n",
    1328             :             DEVNAME(sc), ccb->ccb_id, xs->flags);
    1329             : 
    1330           0 :         ccb->ccb_cookie = xs;
    1331           0 :         ccb->ccb_done = mpi_scsi_cmd_done;
    1332             : 
    1333           0 :         mcb = ccb->ccb_cmd;
    1334           0 :         io = &mcb->mcb_io;
    1335             : 
    1336           0 :         io->function = MPI_FUNCTION_SCSI_IO_REQUEST;
    1337             :         /*
    1338             :          * bus is always 0
    1339             :          * io->bus = htole16(sc->sc_bus);
    1340             :          */
    1341           0 :         io->target_id = link->target;
    1342             : 
    1343           0 :         io->cdb_length = xs->cmdlen;
    1344           0 :         io->sense_buf_len = sizeof(xs->sense);
    1345           0 :         io->msg_flags = MPI_SCSIIO_SENSE_BUF_ADDR_WIDTH_64;
    1346             : 
    1347           0 :         htobem16(&io->lun[0], link->lun);
    1348             : 
    1349           0 :         switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
    1350             :         case SCSI_DATA_IN:
    1351           0 :                 io->direction = MPI_SCSIIO_DIR_READ;
    1352           0 :                 break;
    1353             :         case SCSI_DATA_OUT:
    1354           0 :                 io->direction = MPI_SCSIIO_DIR_WRITE;
    1355           0 :                 break;
    1356             :         default:
    1357           0 :                 io->direction = MPI_SCSIIO_DIR_NONE;
    1358           0 :                 break;
    1359             :         }
    1360             : 
    1361           0 :         if (sc->sc_porttype != MPI_PORTFACTS_PORTTYPE_SCSI &&
    1362           0 :             (link->quirks & SDEV_NOTAGS))
    1363           0 :                 io->tagging = MPI_SCSIIO_ATTR_UNTAGGED;
    1364             :         else 
    1365           0 :                 io->tagging = MPI_SCSIIO_ATTR_SIMPLE_Q;
    1366             : 
    1367           0 :         memcpy(io->cdb, xs->cmd, xs->cmdlen);
    1368             : 
    1369           0 :         htolem32(&io->data_length, xs->datalen);
    1370             : 
    1371           0 :         htolem32(&io->sense_buf_low_addr, ccb->ccb_cmd_dva +
    1372             :             offsetof(struct mpi_ccb_bundle, mcb_sense));
    1373             : 
    1374           0 :         if (mpi_load_xs(ccb) != 0)
    1375             :                 goto stuffup;
    1376             : 
    1377           0 :         timeout_set(&xs->stimeout, mpi_timeout_xs, ccb);
    1378             : 
    1379           0 :         if (xs->flags & SCSI_POLL) {
    1380           0 :                 if (mpi_poll(sc, ccb, xs->timeout) != 0)
    1381             :                         goto stuffup;
    1382             :         } else
    1383           0 :                 mpi_start(sc, ccb);
    1384             : 
    1385           0 :         KERNEL_LOCK();
    1386           0 :         return;
    1387             : 
    1388             : stuffup:
    1389           0 :         xs->error = XS_DRIVER_STUFFUP;
    1390             : done:
    1391           0 :         KERNEL_LOCK();
    1392           0 :         scsi_done(xs);
    1393           0 : }
    1394             : 
    1395             : void
    1396           0 : mpi_scsi_cmd_done(struct mpi_ccb *ccb)
    1397             : {
    1398           0 :         struct mpi_softc                *sc = ccb->ccb_sc;
    1399           0 :         struct scsi_xfer                *xs = ccb->ccb_cookie;
    1400           0 :         struct mpi_ccb_bundle           *mcb = ccb->ccb_cmd;
    1401           0 :         bus_dmamap_t                    dmap = ccb->ccb_dmamap;
    1402             :         struct mpi_msg_scsi_io_error    *sie;
    1403             : 
    1404           0 :         if (xs->datalen != 0) {
    1405           0 :                 bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
    1406             :                     (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
    1407             :                     BUS_DMASYNC_POSTWRITE);
    1408             : 
    1409           0 :                 bus_dmamap_unload(sc->sc_dmat, dmap);
    1410           0 :         }
    1411             : 
    1412             :         /* timeout_del */
    1413           0 :         xs->error = XS_NOERROR;
    1414           0 :         xs->resid = 0;
    1415             : 
    1416           0 :         if (ccb->ccb_rcb == NULL) {
    1417             :                 /* no scsi error, we're ok so drop out early */
    1418           0 :                 xs->status = SCSI_OK;
    1419           0 :                 KERNEL_LOCK();
    1420           0 :                 scsi_done(xs);
    1421           0 :                 KERNEL_UNLOCK();
    1422           0 :                 return;
    1423             :         }
    1424             : 
    1425           0 :         sie = ccb->ccb_rcb->rcb_reply;
    1426             : 
    1427             :         DNPRINTF(MPI_D_CMD, "%s: mpi_scsi_cmd_done xs cmd: 0x%02x len: %d "
    1428             :             "flags 0x%x\n", DEVNAME(sc), xs->cmd->opcode, xs->datalen,
    1429             :             xs->flags);
    1430             :         DNPRINTF(MPI_D_CMD, "%s:  target_id: %d bus: %d msg_length: %d "
    1431             :             "function: 0x%02x\n", DEVNAME(sc), sie->target_id, sie->bus,
    1432             :             sie->msg_length, sie->function);
    1433             :         DNPRINTF(MPI_D_CMD, "%s:  cdb_length: %d sense_buf_length: %d "
    1434             :             "msg_flags: 0x%02x\n", DEVNAME(sc), sie->cdb_length,
    1435             :             sie->sense_buf_len, sie->msg_flags);
    1436             :         DNPRINTF(MPI_D_CMD, "%s:  msg_context: 0x%08x\n", DEVNAME(sc),
    1437             :             letoh32(sie->msg_context));
    1438             :         DNPRINTF(MPI_D_CMD, "%s:  scsi_status: 0x%02x scsi_state: 0x%02x "
    1439             :             "ioc_status: 0x%04x\n", DEVNAME(sc), sie->scsi_status,
    1440             :             sie->scsi_state, letoh16(sie->ioc_status));
    1441             :         DNPRINTF(MPI_D_CMD, "%s:  ioc_loginfo: 0x%08x\n", DEVNAME(sc),
    1442             :             letoh32(sie->ioc_loginfo));
    1443             :         DNPRINTF(MPI_D_CMD, "%s:  transfer_count: %d\n", DEVNAME(sc),
    1444             :             letoh32(sie->transfer_count));
    1445             :         DNPRINTF(MPI_D_CMD, "%s:  sense_count: %d\n", DEVNAME(sc),
    1446             :             letoh32(sie->sense_count));
    1447             :         DNPRINTF(MPI_D_CMD, "%s:  response_info: 0x%08x\n", DEVNAME(sc),
    1448             :             letoh32(sie->response_info));
    1449             :         DNPRINTF(MPI_D_CMD, "%s:  tag: 0x%04x\n", DEVNAME(sc),
    1450             :             letoh16(sie->tag));
    1451             : 
    1452           0 :         if (sie->scsi_state & MPI_SCSIIO_ERR_STATE_NO_SCSI_STATUS)
    1453           0 :                 xs->status = SCSI_TERMINATED;
    1454             :         else
    1455           0 :                 xs->status = sie->scsi_status;
    1456           0 :         xs->resid = 0;
    1457             : 
    1458           0 :         switch (lemtoh16(&sie->ioc_status)) {
    1459             :         case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
    1460           0 :                 xs->resid = xs->datalen - lemtoh32(&sie->transfer_count);
    1461             :                 /* FALLTHROUGH */
    1462             :         case MPI_IOCSTATUS_SUCCESS:
    1463             :         case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:
    1464           0 :                 switch (xs->status) {
    1465             :                 case SCSI_OK:
    1466           0 :                         xs->error = XS_NOERROR;
    1467           0 :                         break;
    1468             : 
    1469             :                 case SCSI_CHECK:
    1470           0 :                         xs->error = XS_SENSE;
    1471           0 :                         break;
    1472             : 
    1473             :                 case SCSI_BUSY:
    1474             :                 case SCSI_QUEUE_FULL:
    1475           0 :                         xs->error = XS_BUSY;
    1476           0 :                         break;
    1477             : 
    1478             :                 default:
    1479           0 :                         xs->error = XS_DRIVER_STUFFUP;
    1480           0 :                         break;
    1481             :                 }
    1482             :                 break;
    1483             : 
    1484             :         case MPI_IOCSTATUS_BUSY:
    1485             :         case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
    1486           0 :                 xs->error = XS_BUSY;
    1487           0 :                 break;
    1488             : 
    1489             :         case MPI_IOCSTATUS_SCSI_INVALID_BUS:
    1490             :         case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
    1491             :         case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
    1492           0 :                 xs->error = XS_SELTIMEOUT;
    1493           0 :                 break;
    1494             : 
    1495             :         case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
    1496             :         case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
    1497           0 :                 xs->error = XS_RESET;
    1498           0 :                 break;
    1499             : 
    1500             :         default:
    1501           0 :                 xs->error = XS_DRIVER_STUFFUP;
    1502           0 :                 break;
    1503             :         }
    1504             : 
    1505           0 :         if (sie->scsi_state & MPI_SCSIIO_ERR_STATE_AUTOSENSE_VALID)
    1506           0 :                 memcpy(&xs->sense, &mcb->mcb_sense, sizeof(xs->sense));
    1507             : 
    1508             :         DNPRINTF(MPI_D_CMD, "%s:  xs err: 0x%02x status: %d\n", DEVNAME(sc),
    1509             :             xs->error, xs->status);
    1510             : 
    1511           0 :         mpi_push_reply(sc, ccb->ccb_rcb);
    1512           0 :         KERNEL_LOCK();
    1513           0 :         scsi_done(xs);
    1514           0 :         KERNEL_UNLOCK();
    1515           0 : }
    1516             : 
    1517             : void
    1518           0 : mpi_timeout_xs(void *arg)
    1519             : {
    1520             :         /* XXX */
    1521           0 : }
    1522             : 
    1523             : int
    1524           0 : mpi_load_xs(struct mpi_ccb *ccb)
    1525             : {
    1526           0 :         struct mpi_softc                *sc = ccb->ccb_sc;
    1527           0 :         struct scsi_xfer                *xs = ccb->ccb_cookie;
    1528           0 :         struct mpi_ccb_bundle           *mcb = ccb->ccb_cmd;
    1529           0 :         struct mpi_msg_scsi_io          *io = &mcb->mcb_io;
    1530             :         struct mpi_sge                  *sge = NULL;
    1531           0 :         struct mpi_sge                  *nsge = &mcb->mcb_sgl[0];
    1532             :         struct mpi_sge                  *ce = NULL, *nce;
    1533           0 :         bus_dmamap_t                    dmap = ccb->ccb_dmamap;
    1534             :         u_int32_t                       addr, flags;
    1535             :         int                             i, error;
    1536             : 
    1537           0 :         if (xs->datalen == 0) {
    1538           0 :                 htolem32(&nsge->sg_hdr, MPI_SGE_FL_TYPE_SIMPLE |
    1539             :                     MPI_SGE_FL_LAST | MPI_SGE_FL_EOB | MPI_SGE_FL_EOL);
    1540           0 :                 return (0);
    1541             :         }
    1542             : 
    1543           0 :         error = bus_dmamap_load(sc->sc_dmat, dmap,
    1544             :             xs->data, xs->datalen, NULL, BUS_DMA_STREAMING |
    1545             :             ((xs->flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK));
    1546           0 :         if (error) {
    1547           0 :                 printf("%s: error %d loading dmamap\n", DEVNAME(sc), error);
    1548           0 :                 return (1);
    1549             :         }
    1550             : 
    1551             :         flags = MPI_SGE_FL_TYPE_SIMPLE | MPI_SGE_FL_SIZE_64;
    1552           0 :         if (xs->flags & SCSI_DATA_OUT)
    1553           0 :                 flags |= MPI_SGE_FL_DIR_OUT;
    1554             : 
    1555           0 :         if (dmap->dm_nsegs > sc->sc_first_sgl_len) {
    1556           0 :                 ce = &mcb->mcb_sgl[sc->sc_first_sgl_len - 1];
    1557           0 :                 io->chain_offset = (u_int32_t *)ce - (u_int32_t *)io;
    1558           0 :         }
    1559             : 
    1560           0 :         for (i = 0; i < dmap->dm_nsegs; i++) {
    1561             : 
    1562           0 :                 if (nsge == ce) {
    1563           0 :                         nsge++;
    1564           0 :                         sge->sg_hdr |= htole32(MPI_SGE_FL_LAST);
    1565             : 
    1566           0 :                         if ((dmap->dm_nsegs - i) > sc->sc_chain_len) {
    1567           0 :                                 nce = &nsge[sc->sc_chain_len - 1];
    1568           0 :                                 addr = (u_int32_t *)nce - (u_int32_t *)nsge;
    1569           0 :                                 addr = addr << 16 |
    1570           0 :                                     sizeof(struct mpi_sge) * sc->sc_chain_len;
    1571           0 :                         } else {
    1572             :                                 nce = NULL;
    1573           0 :                                 addr = sizeof(struct mpi_sge) *
    1574           0 :                                     (dmap->dm_nsegs - i);
    1575             :                         }
    1576             : 
    1577           0 :                         ce->sg_hdr = htole32(MPI_SGE_FL_TYPE_CHAIN |
    1578             :                             MPI_SGE_FL_SIZE_64 | addr);
    1579             : 
    1580           0 :                         mpi_dvatosge(ce, ccb->ccb_cmd_dva +
    1581           0 :                             ((u_int8_t *)nsge - (u_int8_t *)mcb));
    1582             : 
    1583             :                         ce = nce;
    1584           0 :                 }
    1585             : 
    1586             :                 DNPRINTF(MPI_D_DMA, "%s:  %d: %d 0x%016llx\n", DEVNAME(sc),
    1587             :                     i, dmap->dm_segs[i].ds_len,
    1588             :                     (u_int64_t)dmap->dm_segs[i].ds_addr);
    1589             : 
    1590           0 :                 sge = nsge++;
    1591             : 
    1592           0 :                 sge->sg_hdr = htole32(flags | dmap->dm_segs[i].ds_len);
    1593           0 :                 mpi_dvatosge(sge, dmap->dm_segs[i].ds_addr);
    1594             :         }
    1595             : 
    1596             :         /* terminate list */
    1597           0 :         sge->sg_hdr |= htole32(MPI_SGE_FL_LAST | MPI_SGE_FL_EOB |
    1598             :             MPI_SGE_FL_EOL);
    1599             : 
    1600           0 :         bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
    1601             :             (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
    1602             :             BUS_DMASYNC_PREWRITE);
    1603             : 
    1604           0 :         return (0);
    1605           0 : }
    1606             : 
    1607             : void
    1608           0 : mpi_minphys(struct buf *bp, struct scsi_link *sl)
    1609             : {
    1610             :         /* XXX */
    1611           0 :         if (bp->b_bcount > MAXPHYS)
    1612           0 :                 bp->b_bcount = MAXPHYS;
    1613           0 :         minphys(bp);
    1614           0 : }
    1615             : 
    1616             : int
    1617           0 : mpi_scsi_probe_virtual(struct scsi_link *link)
    1618             : {
    1619           0 :         struct mpi_softc                *sc = link->adapter_softc;
    1620           0 :         struct mpi_cfg_hdr              hdr;
    1621             :         struct mpi_cfg_raid_vol_pg0     *rp0;
    1622             :         int                             len;
    1623             :         int                             rv;
    1624             : 
    1625           0 :         if (!ISSET(sc->sc_flags, MPI_F_RAID))
    1626           0 :                 return (0);
    1627             : 
    1628           0 :         if (link->lun > 0)
    1629           0 :                 return (0);
    1630             : 
    1631           0 :         rv = mpi_req_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_RAID_VOL,
    1632           0 :             0, link->target, MPI_PG_POLL, &hdr);
    1633           0 :         if (rv != 0)
    1634           0 :                 return (0);
    1635             : 
    1636           0 :         len = hdr.page_length * 4;
    1637           0 :         rp0 = malloc(len, M_TEMP, M_NOWAIT);
    1638           0 :         if (rp0 == NULL)
    1639           0 :                 return (ENOMEM);
    1640             : 
    1641           0 :         rv = mpi_req_cfg_page(sc, link->target, MPI_PG_POLL, &hdr, 1, rp0, len);
    1642           0 :         if (rv == 0)
    1643           0 :                 SET(link->flags, SDEV_VIRTUAL);
    1644             : 
    1645           0 :         free(rp0, M_TEMP, len);
    1646           0 :         return (0);
    1647           0 : }
    1648             : 
    1649             : int
    1650           0 : mpi_scsi_probe(struct scsi_link *link)
    1651             : {
    1652           0 :         struct mpi_softc                *sc = link->adapter_softc;
    1653           0 :         struct mpi_ecfg_hdr             ehdr;
    1654           0 :         struct mpi_cfg_sas_dev_pg0      pg0;
    1655             :         u_int32_t                       address;
    1656             :         int                             rv;
    1657             : 
    1658           0 :         rv = mpi_scsi_probe_virtual(link);
    1659           0 :         if (rv != 0)
    1660           0 :                 return (rv);
    1661             : 
    1662           0 :         if (ISSET(link->flags, SDEV_VIRTUAL))
    1663           0 :                 return (0);
    1664             : 
    1665           0 :         if (sc->sc_porttype != MPI_PORTFACTS_PORTTYPE_SAS)
    1666           0 :                 return (0);
    1667             : 
    1668           0 :         address = MPI_CFG_SAS_DEV_ADDR_BUS | link->target;
    1669             : 
    1670           0 :         if (mpi_ecfg_header(sc, MPI_CONFIG_REQ_EXTPAGE_TYPE_SAS_DEVICE, 0,
    1671           0 :             address, &ehdr) != 0)
    1672           0 :                 return (EIO);
    1673             : 
    1674           0 :         if (mpi_ecfg_page(sc, address, &ehdr, 1, &pg0, sizeof(pg0)) != 0)
    1675           0 :                 return (0);
    1676             : 
    1677             :         DNPRINTF(MPI_D_MISC, "%s: mpi_scsi_probe sas dev pg 0 for target %d:\n",
    1678             :             DEVNAME(sc), link->target);
    1679             :         DNPRINTF(MPI_D_MISC, "%s:  slot: 0x%04x enc_handle: 0x%04x\n",
    1680             :             DEVNAME(sc), letoh16(pg0.slot), letoh16(pg0.enc_handle));
    1681             :         DNPRINTF(MPI_D_MISC, "%s:  sas_addr: 0x%016llx\n", DEVNAME(sc),
    1682             :             letoh64(pg0.sas_addr));
    1683             :         DNPRINTF(MPI_D_MISC, "%s:  parent_dev_handle: 0x%04x phy_num: 0x%02x "
    1684             :             "access_status: 0x%02x\n", DEVNAME(sc),
    1685             :             letoh16(pg0.parent_dev_handle), pg0.phy_num, pg0.access_status);
    1686             :         DNPRINTF(MPI_D_MISC, "%s:  dev_handle: 0x%04x "
    1687             :             "bus: 0x%02x target: 0x%02x\n", DEVNAME(sc),
    1688             :             letoh16(pg0.dev_handle), pg0.bus, pg0.target);
    1689             :         DNPRINTF(MPI_D_MISC, "%s:  device_info: 0x%08x\n", DEVNAME(sc),
    1690             :             letoh32(pg0.device_info));
    1691             :         DNPRINTF(MPI_D_MISC, "%s:  flags: 0x%04x physical_port: 0x%02x\n",
    1692             :             DEVNAME(sc), letoh16(pg0.flags), pg0.physical_port);
    1693             : 
    1694           0 :         if (ISSET(lemtoh32(&pg0.device_info),
    1695             :             MPI_CFG_SAS_DEV_0_DEVINFO_ATAPI_DEVICE)) {
    1696             :                 DNPRINTF(MPI_D_MISC, "%s: target %d is an ATAPI device\n",
    1697             :                     DEVNAME(sc), link->target);
    1698           0 :                 link->flags |= SDEV_ATAPI;
    1699           0 :                 link->quirks |= SDEV_ONLYBIG;
    1700           0 :         }
    1701             : 
    1702           0 :         return (0);
    1703           0 : }
    1704             : 
    1705             : u_int32_t
    1706           0 : mpi_read(struct mpi_softc *sc, bus_size_t r)
    1707             : {
    1708             :         u_int32_t                       rv;
    1709             : 
    1710           0 :         bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
    1711             :             BUS_SPACE_BARRIER_READ);
    1712           0 :         rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, r);
    1713             : 
    1714             :         DNPRINTF(MPI_D_RW, "%s: mpi_read %#x %#x\n", DEVNAME(sc), r, rv);
    1715             : 
    1716           0 :         return (rv);
    1717             : }
    1718             : 
    1719             : void
    1720           0 : mpi_write(struct mpi_softc *sc, bus_size_t r, u_int32_t v)
    1721             : {
    1722             :         DNPRINTF(MPI_D_RW, "%s: mpi_write %#x %#x\n", DEVNAME(sc), r, v);
    1723             : 
    1724           0 :         bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v);
    1725           0 :         bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
    1726             :             BUS_SPACE_BARRIER_WRITE);
    1727           0 : }
    1728             : 
    1729             : int
    1730           0 : mpi_wait_eq(struct mpi_softc *sc, bus_size_t r, u_int32_t mask,
    1731             :     u_int32_t target)
    1732             : {
    1733             :         int                             i;
    1734             : 
    1735             :         DNPRINTF(MPI_D_RW, "%s: mpi_wait_eq %#x %#x %#x\n", DEVNAME(sc), r,
    1736             :             mask, target);
    1737             : 
    1738           0 :         for (i = 0; i < 10000; i++) {
    1739           0 :                 if ((mpi_read(sc, r) & mask) == target)
    1740           0 :                         return (0);
    1741           0 :                 delay(1000);
    1742             :         }
    1743             : 
    1744           0 :         return (1);
    1745           0 : }
    1746             : 
    1747             : int
    1748           0 : mpi_wait_ne(struct mpi_softc *sc, bus_size_t r, u_int32_t mask,
    1749             :     u_int32_t target)
    1750             : {
    1751             :         int                             i;
    1752             : 
    1753             :         DNPRINTF(MPI_D_RW, "%s: mpi_wait_ne %#x %#x %#x\n", DEVNAME(sc), r,
    1754             :             mask, target);
    1755             : 
    1756           0 :         for (i = 0; i < 10000; i++) {
    1757           0 :                 if ((mpi_read(sc, r) & mask) != target)
    1758           0 :                         return (0);
    1759           0 :                 delay(1000);
    1760             :         }
    1761             : 
    1762           0 :         return (1);
    1763           0 : }
    1764             : 
    1765             : int
    1766           0 : mpi_init(struct mpi_softc *sc)
    1767             : {
    1768             :         u_int32_t                       db;
    1769             :         int                             i;
    1770             : 
    1771             :         /* spin until the IOC leaves the RESET state */
    1772           0 :         if (mpi_wait_ne(sc, MPI_DOORBELL, MPI_DOORBELL_STATE,
    1773           0 :             MPI_DOORBELL_STATE_RESET) != 0) {
    1774             :                 DNPRINTF(MPI_D_MISC, "%s: mpi_init timeout waiting to leave "
    1775             :                     "reset state\n", DEVNAME(sc));
    1776           0 :                 return (1);
    1777             :         }
    1778             : 
    1779             :         /* check current ownership */
    1780           0 :         db = mpi_read_db(sc);
    1781           0 :         if ((db & MPI_DOORBELL_WHOINIT) == MPI_DOORBELL_WHOINIT_PCIPEER) {
    1782             :                 DNPRINTF(MPI_D_MISC, "%s: mpi_init initialised by pci peer\n",
    1783             :                     DEVNAME(sc));
    1784           0 :                 return (0);
    1785             :         }
    1786             : 
    1787           0 :         for (i = 0; i < 5; i++) {
    1788           0 :                 switch (db & MPI_DOORBELL_STATE) {
    1789             :                 case MPI_DOORBELL_STATE_READY:
    1790             :                         DNPRINTF(MPI_D_MISC, "%s: mpi_init ioc is ready\n",
    1791             :                             DEVNAME(sc));
    1792           0 :                         return (0);
    1793             : 
    1794             :                 case MPI_DOORBELL_STATE_OPER:
    1795             :                 case MPI_DOORBELL_STATE_FAULT:
    1796             :                         DNPRINTF(MPI_D_MISC, "%s: mpi_init ioc is being "
    1797             :                             "reset\n" , DEVNAME(sc));
    1798           0 :                         if (mpi_reset_soft(sc) != 0)
    1799           0 :                                 mpi_reset_hard(sc);
    1800             :                         break;
    1801             : 
    1802             :                 case MPI_DOORBELL_STATE_RESET:
    1803             :                         DNPRINTF(MPI_D_MISC, "%s: mpi_init waiting to come "
    1804             :                             "out of reset\n", DEVNAME(sc));
    1805           0 :                         if (mpi_wait_ne(sc, MPI_DOORBELL, MPI_DOORBELL_STATE,
    1806           0 :                             MPI_DOORBELL_STATE_RESET) != 0)
    1807           0 :                                 return (1);
    1808             :                         break;
    1809             :                 }
    1810           0 :                 db = mpi_read_db(sc);
    1811             :         }
    1812             : 
    1813           0 :         return (1);
    1814           0 : }
    1815             : 
    1816             : int
    1817           0 : mpi_reset_soft(struct mpi_softc *sc)
    1818             : {
    1819             :         DNPRINTF(MPI_D_MISC, "%s: mpi_reset_soft\n", DEVNAME(sc));
    1820             : 
    1821           0 :         if (mpi_read_db(sc) & MPI_DOORBELL_INUSE)
    1822           0 :                 return (1);
    1823             : 
    1824           0 :         mpi_write_db(sc,
    1825             :             MPI_DOORBELL_FUNCTION(MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET));
    1826           0 :         if (mpi_wait_eq(sc, MPI_INTR_STATUS,
    1827           0 :             MPI_INTR_STATUS_IOCDOORBELL, 0) != 0)
    1828           0 :                 return (1);
    1829             : 
    1830           0 :         if (mpi_wait_eq(sc, MPI_DOORBELL, MPI_DOORBELL_STATE,
    1831           0 :             MPI_DOORBELL_STATE_READY) != 0)
    1832           0 :                 return (1);
    1833             : 
    1834           0 :         return (0);
    1835           0 : }
    1836             : 
    1837             : int
    1838           0 : mpi_reset_hard(struct mpi_softc *sc)
    1839             : {
    1840             :         DNPRINTF(MPI_D_MISC, "%s: mpi_reset_hard\n", DEVNAME(sc));
    1841             : 
    1842             :         /* enable diagnostic register */
    1843           0 :         mpi_write(sc, MPI_WRITESEQ, 0xff);
    1844           0 :         mpi_write(sc, MPI_WRITESEQ, MPI_WRITESEQ_1);
    1845           0 :         mpi_write(sc, MPI_WRITESEQ, MPI_WRITESEQ_2);
    1846           0 :         mpi_write(sc, MPI_WRITESEQ, MPI_WRITESEQ_3);
    1847           0 :         mpi_write(sc, MPI_WRITESEQ, MPI_WRITESEQ_4);
    1848           0 :         mpi_write(sc, MPI_WRITESEQ, MPI_WRITESEQ_5);
    1849             : 
    1850             :         /* reset ioc */
    1851           0 :         mpi_write(sc, MPI_HOSTDIAG, MPI_HOSTDIAG_RESET_ADAPTER);
    1852             : 
    1853           0 :         delay(10000);
    1854             : 
    1855             :         /* disable diagnostic register */
    1856           0 :         mpi_write(sc, MPI_WRITESEQ, 0xff);
    1857             : 
    1858             :         /* restore pci bits? */
    1859             : 
    1860             :         /* firmware bits? */
    1861           0 :         return (0);
    1862             : }
    1863             : 
    1864             : int
    1865           0 : mpi_handshake_send(struct mpi_softc *sc, void *buf, size_t dwords)
    1866             : {
    1867           0 :         u_int32_t                               *query = buf;
    1868             :         int                                     i;
    1869             : 
    1870             :         /* make sure the doorbell is not in use. */
    1871           0 :         if (mpi_read_db(sc) & MPI_DOORBELL_INUSE)
    1872           0 :                 return (1);
    1873             : 
    1874             :         /* clear pending doorbell interrupts */
    1875           0 :         if (mpi_read_intr(sc) & MPI_INTR_STATUS_DOORBELL)
    1876           0 :                 mpi_write_intr(sc, 0);
    1877             : 
    1878             :         /*
    1879             :          * first write the doorbell with the handshake function and the
    1880             :          * dword count.
    1881             :          */
    1882           0 :         mpi_write_db(sc, MPI_DOORBELL_FUNCTION(MPI_FUNCTION_HANDSHAKE) |
    1883             :             MPI_DOORBELL_DWORDS(dwords));
    1884             : 
    1885             :         /*
    1886             :          * the doorbell used bit will be set because a doorbell function has
    1887             :          * started. Wait for the interrupt and then ack it.
    1888             :          */
    1889           0 :         if (mpi_wait_db_int(sc) != 0)
    1890           0 :                 return (1);
    1891           0 :         mpi_write_intr(sc, 0);
    1892             : 
    1893             :         /* poll for the acknowledgement. */
    1894           0 :         if (mpi_wait_db_ack(sc) != 0)
    1895           0 :                 return (1);
    1896             : 
    1897             :         /* write the query through the doorbell. */
    1898           0 :         for (i = 0; i < dwords; i++) {
    1899           0 :                 mpi_write_db(sc, htole32(query[i]));
    1900           0 :                 if (mpi_wait_db_ack(sc) != 0)
    1901           0 :                         return (1);
    1902             :         }
    1903             : 
    1904           0 :         return (0);
    1905           0 : }
    1906             : 
    1907             : int
    1908           0 : mpi_handshake_recv_dword(struct mpi_softc *sc, u_int32_t *dword)
    1909             : {
    1910           0 :         u_int16_t                               *words = (u_int16_t *)dword;
    1911             :         int                                     i;
    1912             : 
    1913           0 :         for (i = 0; i < 2; i++) {
    1914           0 :                 if (mpi_wait_db_int(sc) != 0)
    1915           0 :                         return (1);
    1916           0 :                 words[i] = letoh16(mpi_read_db(sc) & MPI_DOORBELL_DATA_MASK);
    1917           0 :                 mpi_write_intr(sc, 0);
    1918             :         }
    1919             : 
    1920           0 :         return (0);
    1921           0 : }
    1922             : 
    1923             : int
    1924           0 : mpi_handshake_recv(struct mpi_softc *sc, void *buf, size_t dwords)
    1925             : {
    1926           0 :         struct mpi_msg_reply                    *reply = buf;
    1927           0 :         u_int32_t                               *dbuf = buf, dummy;
    1928             :         int                                     i;
    1929             : 
    1930             :         /* get the first dword so we can read the length out of the header. */
    1931           0 :         if (mpi_handshake_recv_dword(sc, &dbuf[0]) != 0)
    1932           0 :                 return (1);
    1933             : 
    1934             :         DNPRINTF(MPI_D_CMD, "%s: mpi_handshake_recv dwords: %d reply: %d\n",
    1935             :             DEVNAME(sc), dwords, reply->msg_length);
    1936             : 
    1937             :         /*
    1938             :          * the total length, in dwords, is in the message length field of the
    1939             :          * reply header.
    1940             :          */
    1941           0 :         for (i = 1; i < MIN(dwords, reply->msg_length); i++) {
    1942           0 :                 if (mpi_handshake_recv_dword(sc, &dbuf[i]) != 0)
    1943           0 :                         return (1);
    1944             :         }
    1945             : 
    1946             :         /* if there's extra stuff to come off the ioc, discard it */
    1947           0 :         while (i++ < reply->msg_length) {
    1948           0 :                 if (mpi_handshake_recv_dword(sc, &dummy) != 0)
    1949           0 :                         return (1);
    1950             :                 DNPRINTF(MPI_D_CMD, "%s: mpi_handshake_recv dummy read: "
    1951             :                     "0x%08x\n", DEVNAME(sc), dummy);
    1952             :         }
    1953             : 
    1954             :         /* wait for the doorbell used bit to be reset and clear the intr */
    1955           0 :         if (mpi_wait_db_int(sc) != 0)
    1956           0 :                 return (1);
    1957           0 :         mpi_write_intr(sc, 0);
    1958             : 
    1959           0 :         return (0);
    1960           0 : }
    1961             : 
    1962             : void
    1963           0 : mpi_empty_done(struct mpi_ccb *ccb)
    1964             : {
    1965             :         /* nothing to do */
    1966           0 : }
    1967             : 
    1968             : int
    1969           0 : mpi_iocfacts(struct mpi_softc *sc)
    1970             : {
    1971           0 :         struct mpi_msg_iocfacts_request         ifq;
    1972           0 :         struct mpi_msg_iocfacts_reply           ifp;
    1973             : 
    1974             :         DNPRINTF(MPI_D_MISC, "%s: mpi_iocfacts\n", DEVNAME(sc));
    1975             : 
    1976           0 :         memset(&ifq, 0, sizeof(ifq));
    1977           0 :         memset(&ifp, 0, sizeof(ifp));
    1978             : 
    1979           0 :         ifq.function = MPI_FUNCTION_IOC_FACTS;
    1980           0 :         ifq.chain_offset = 0;
    1981           0 :         ifq.msg_flags = 0;
    1982           0 :         ifq.msg_context = htole32(0xdeadbeef);
    1983             : 
    1984           0 :         if (mpi_handshake_send(sc, &ifq, dwordsof(ifq)) != 0) {
    1985             :                 DNPRINTF(MPI_D_MISC, "%s: mpi_iocfacts send failed\n",
    1986             :                     DEVNAME(sc));
    1987           0 :                 return (1);
    1988             :         }
    1989             : 
    1990           0 :         if (mpi_handshake_recv(sc, &ifp, dwordsof(ifp)) != 0) {
    1991             :                 DNPRINTF(MPI_D_MISC, "%s: mpi_iocfacts recv failed\n",
    1992             :                     DEVNAME(sc));
    1993           0 :                 return (1);
    1994             :         }
    1995             : 
    1996             :         DNPRINTF(MPI_D_MISC, "%s:  func: 0x%02x len: %d msgver: %d.%d\n",
    1997             :             DEVNAME(sc), ifp.function, ifp.msg_length,
    1998             :             ifp.msg_version_maj, ifp.msg_version_min);
    1999             :         DNPRINTF(MPI_D_MISC, "%s:  msgflags: 0x%02x iocnumber: 0x%02x "
    2000             :             "hdrver: %d.%d\n", DEVNAME(sc), ifp.msg_flags,
    2001             :             ifp.ioc_number, ifp.header_version_maj,
    2002             :             ifp.header_version_min);
    2003             :         DNPRINTF(MPI_D_MISC, "%s:  message context: 0x%08x\n", DEVNAME(sc),
    2004             :             letoh32(ifp.msg_context));
    2005             :         DNPRINTF(MPI_D_MISC, "%s:  iocstatus: 0x%04x ioexcept: 0x%04x\n",
    2006             :             DEVNAME(sc), letoh16(ifp.ioc_status),
    2007             :             letoh16(ifp.ioc_exceptions));
    2008             :         DNPRINTF(MPI_D_MISC, "%s:  iocloginfo: 0x%08x\n", DEVNAME(sc),
    2009             :             letoh32(ifp.ioc_loginfo));
    2010             :         DNPRINTF(MPI_D_MISC, "%s:  flags: 0x%02x blocksize: %d whoinit: 0x%02x "
    2011             :             "maxchdepth: %d\n", DEVNAME(sc), ifp.flags,
    2012             :             ifp.block_size, ifp.whoinit, ifp.max_chain_depth);
    2013             :         DNPRINTF(MPI_D_MISC, "%s:  reqfrsize: %d replyqdepth: %d\n",
    2014             :             DEVNAME(sc), letoh16(ifp.request_frame_size),
    2015             :             letoh16(ifp.reply_queue_depth));
    2016             :         DNPRINTF(MPI_D_MISC, "%s:  productid: 0x%04x\n", DEVNAME(sc),
    2017             :             letoh16(ifp.product_id));
    2018             :         DNPRINTF(MPI_D_MISC, "%s:  hostmfahiaddr: 0x%08x\n", DEVNAME(sc),
    2019             :             letoh32(ifp.current_host_mfa_hi_addr));
    2020             :         DNPRINTF(MPI_D_MISC, "%s:  event_state: 0x%02x number_of_ports: %d "
    2021             :             "global_credits: %d\n",
    2022             :             DEVNAME(sc), ifp.event_state, ifp.number_of_ports,
    2023             :             letoh16(ifp.global_credits));
    2024             :         DNPRINTF(MPI_D_MISC, "%s:  sensebufhiaddr: 0x%08x\n", DEVNAME(sc),
    2025             :             letoh32(ifp.current_sense_buffer_hi_addr));
    2026             :         DNPRINTF(MPI_D_MISC, "%s:  maxbus: %d maxdev: %d replyfrsize: %d\n",
    2027             :             DEVNAME(sc), ifp.max_buses, ifp.max_devices,
    2028             :             letoh16(ifp.current_reply_frame_size));
    2029             :         DNPRINTF(MPI_D_MISC, "%s:  fw_image_size: %d\n", DEVNAME(sc),
    2030             :             letoh32(ifp.fw_image_size));
    2031             :         DNPRINTF(MPI_D_MISC, "%s:  ioc_capabilities: 0x%08x\n", DEVNAME(sc),
    2032             :             letoh32(ifp.ioc_capabilities));
    2033             :         DNPRINTF(MPI_D_MISC, "%s:  fw_version: %d.%d fw_version_unit: 0x%02x "
    2034             :             "fw_version_dev: 0x%02x\n", DEVNAME(sc),
    2035             :             ifp.fw_version_maj, ifp.fw_version_min,
    2036             :             ifp.fw_version_unit, ifp.fw_version_dev);
    2037             :         DNPRINTF(MPI_D_MISC, "%s:  hi_priority_queue_depth: 0x%04x\n",
    2038             :             DEVNAME(sc), letoh16(ifp.hi_priority_queue_depth));
    2039             :         DNPRINTF(MPI_D_MISC, "%s:  host_page_buffer_sge: hdr: 0x%08x "
    2040             :             "addr 0x%08lx%08lx\n", DEVNAME(sc),
    2041             :             letoh32(ifp.host_page_buffer_sge.sg_hdr),
    2042             :             letoh32(ifp.host_page_buffer_sge.sg_addr_hi),
    2043             :             letoh32(ifp.host_page_buffer_sge.sg_addr_lo));
    2044             : 
    2045           0 :         sc->sc_fw_maj = ifp.fw_version_maj;
    2046           0 :         sc->sc_fw_min = ifp.fw_version_min;
    2047           0 :         sc->sc_fw_unit = ifp.fw_version_unit;
    2048           0 :         sc->sc_fw_dev = ifp.fw_version_dev;
    2049             : 
    2050           0 :         sc->sc_maxcmds = lemtoh16(&ifp.global_credits);
    2051           0 :         sc->sc_maxchdepth = ifp.max_chain_depth;
    2052           0 :         sc->sc_ioc_number = ifp.ioc_number;
    2053           0 :         if (sc->sc_flags & MPI_F_SPI)
    2054           0 :                 sc->sc_buswidth = 16;
    2055             :         else
    2056           0 :                 sc->sc_buswidth =
    2057           0 :                     (ifp.max_devices == 0) ? 256 : ifp.max_devices;
    2058           0 :         if (ifp.flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
    2059           0 :                 sc->sc_fw_len = lemtoh32(&ifp.fw_image_size);
    2060             : 
    2061           0 :         sc->sc_repq = MIN(MPI_REPLYQ_DEPTH, lemtoh16(&ifp.reply_queue_depth));
    2062             : 
    2063             :         /*
    2064             :          * you can fit sg elements on the end of the io cmd if they fit in the
    2065             :          * request frame size.
    2066             :          */
    2067           0 :         sc->sc_first_sgl_len = ((lemtoh16(&ifp.request_frame_size) * 4) -
    2068           0 :             sizeof(struct mpi_msg_scsi_io)) / sizeof(struct mpi_sge);
    2069             :         DNPRINTF(MPI_D_MISC, "%s:   first sgl len: %d\n", DEVNAME(sc),
    2070             :             sc->sc_first_sgl_len);
    2071             : 
    2072           0 :         sc->sc_chain_len = (lemtoh16(&ifp.request_frame_size) * 4) /
    2073             :             sizeof(struct mpi_sge);
    2074             :         DNPRINTF(MPI_D_MISC, "%s:   chain len: %d\n", DEVNAME(sc),
    2075             :             sc->sc_chain_len);
    2076             : 
    2077             :         /* the sgl tailing the io cmd loses an entry to the chain element. */
    2078           0 :         sc->sc_max_sgl_len = MPI_MAX_SGL - 1;
    2079             :         /* the sgl chains lose an entry for each chain element */
    2080           0 :         sc->sc_max_sgl_len -= (MPI_MAX_SGL - sc->sc_first_sgl_len) /
    2081           0 :             sc->sc_chain_len;
    2082             :         DNPRINTF(MPI_D_MISC, "%s:   max sgl len: %d\n", DEVNAME(sc),
    2083             :             sc->sc_max_sgl_len);
    2084             : 
    2085             :         /* XXX we're ignoring the max chain depth */
    2086             : 
    2087           0 :         return (0);
    2088           0 : }
    2089             : 
    2090             : int
    2091           0 : mpi_iocinit(struct mpi_softc *sc)
    2092             : {
    2093           0 :         struct mpi_msg_iocinit_request          iiq;
    2094           0 :         struct mpi_msg_iocinit_reply            iip;
    2095             :         u_int32_t                               hi_addr;
    2096             : 
    2097             :         DNPRINTF(MPI_D_MISC, "%s: mpi_iocinit\n", DEVNAME(sc));
    2098             : 
    2099           0 :         memset(&iiq, 0, sizeof(iiq));
    2100           0 :         memset(&iip, 0, sizeof(iip));
    2101             : 
    2102           0 :         iiq.function = MPI_FUNCTION_IOC_INIT;
    2103           0 :         iiq.whoinit = MPI_WHOINIT_HOST_DRIVER;
    2104             : 
    2105           0 :         iiq.max_devices = (sc->sc_buswidth == 256) ? 0 : sc->sc_buswidth;
    2106           0 :         iiq.max_buses = 1;
    2107             : 
    2108           0 :         iiq.msg_context = htole32(0xd00fd00f);
    2109             : 
    2110           0 :         iiq.reply_frame_size = htole16(MPI_REPLY_SIZE);
    2111             : 
    2112           0 :         hi_addr = (u_int32_t)(MPI_DMA_DVA(sc->sc_requests) >> 32);
    2113           0 :         htolem32(&iiq.host_mfa_hi_addr, hi_addr);
    2114           0 :         htolem32(&iiq.sense_buffer_hi_addr, hi_addr);
    2115             : 
    2116           0 :         iiq.msg_version_maj = 0x01;
    2117           0 :         iiq.msg_version_min = 0x02;
    2118             : 
    2119           0 :         iiq.hdr_version_unit = 0x0d;
    2120           0 :         iiq.hdr_version_dev = 0x00;
    2121             : 
    2122           0 :         if (mpi_handshake_send(sc, &iiq, dwordsof(iiq)) != 0) {
    2123             :                 DNPRINTF(MPI_D_MISC, "%s: mpi_iocinit send failed\n",
    2124             :                     DEVNAME(sc));
    2125           0 :                 return (1);
    2126             :         }
    2127             : 
    2128           0 :         if (mpi_handshake_recv(sc, &iip, dwordsof(iip)) != 0) {
    2129             :                 DNPRINTF(MPI_D_MISC, "%s: mpi_iocinit recv failed\n",
    2130             :                     DEVNAME(sc));
    2131           0 :                 return (1);
    2132             :         }
    2133             : 
    2134             :         DNPRINTF(MPI_D_MISC, "%s:  function: 0x%02x msg_length: %d "
    2135             :             "whoinit: 0x%02x\n", DEVNAME(sc), iip.function,
    2136             :             iip.msg_length, iip.whoinit);
    2137             :         DNPRINTF(MPI_D_MISC, "%s:  msg_flags: 0x%02x max_buses: %d "
    2138             :             "max_devices: %d flags: 0x%02x\n", DEVNAME(sc), iip.msg_flags,
    2139             :             iip.max_buses, iip.max_devices, iip.flags);
    2140             :         DNPRINTF(MPI_D_MISC, "%s:  msg_context: 0x%08x\n", DEVNAME(sc),
    2141             :             letoh32(iip.msg_context));
    2142             :         DNPRINTF(MPI_D_MISC, "%s:  ioc_status: 0x%04x\n", DEVNAME(sc),
    2143             :             letoh16(iip.ioc_status));
    2144             :         DNPRINTF(MPI_D_MISC, "%s:  ioc_loginfo: 0x%08x\n", DEVNAME(sc),
    2145             :             letoh32(iip.ioc_loginfo));
    2146             : 
    2147           0 :         return (0);
    2148           0 : }
    2149             : 
    2150             : int
    2151           0 : mpi_portfacts(struct mpi_softc *sc)
    2152             : {
    2153             :         struct mpi_ccb                          *ccb;
    2154             :         struct mpi_msg_portfacts_request        *pfq;
    2155             :         volatile struct mpi_msg_portfacts_reply *pfp;
    2156             :         int                                     rv = 1;
    2157             : 
    2158             :         DNPRINTF(MPI_D_MISC, "%s: mpi_portfacts\n", DEVNAME(sc));
    2159             : 
    2160           0 :         ccb = scsi_io_get(&sc->sc_iopool, SCSI_NOSLEEP);
    2161           0 :         if (ccb == NULL) {
    2162             :                 DNPRINTF(MPI_D_MISC, "%s: mpi_portfacts ccb_get\n",
    2163             :                     DEVNAME(sc));
    2164           0 :                 return (rv);
    2165             :         }
    2166             : 
    2167           0 :         ccb->ccb_done = mpi_empty_done;
    2168           0 :         pfq = ccb->ccb_cmd;
    2169             : 
    2170           0 :         pfq->function = MPI_FUNCTION_PORT_FACTS;
    2171           0 :         pfq->chain_offset = 0;
    2172           0 :         pfq->msg_flags = 0;
    2173           0 :         pfq->port_number = 0;
    2174             : 
    2175           0 :         if (mpi_poll(sc, ccb, 50000) != 0) {
    2176             :                 DNPRINTF(MPI_D_MISC, "%s: mpi_portfacts poll\n", DEVNAME(sc));
    2177             :                 goto err;
    2178             :         }
    2179             : 
    2180           0 :         if (ccb->ccb_rcb == NULL) {
    2181             :                 DNPRINTF(MPI_D_MISC, "%s: empty portfacts reply\n",
    2182             :                     DEVNAME(sc));
    2183             :                 goto err;
    2184             :         }
    2185           0 :         pfp = ccb->ccb_rcb->rcb_reply;
    2186             : 
    2187             :         DNPRINTF(MPI_D_MISC, "%s:  function: 0x%02x msg_length: %d\n",
    2188             :             DEVNAME(sc), pfp->function, pfp->msg_length);
    2189             :         DNPRINTF(MPI_D_MISC, "%s:  msg_flags: 0x%02x port_number: %d\n",
    2190             :             DEVNAME(sc), pfp->msg_flags, pfp->port_number);
    2191             :         DNPRINTF(MPI_D_MISC, "%s:  msg_context: 0x%08x\n", DEVNAME(sc),
    2192             :             letoh32(pfp->msg_context));
    2193             :         DNPRINTF(MPI_D_MISC, "%s:  ioc_status: 0x%04x\n", DEVNAME(sc),
    2194             :             letoh16(pfp->ioc_status));
    2195             :         DNPRINTF(MPI_D_MISC, "%s:  ioc_loginfo: 0x%08x\n", DEVNAME(sc),
    2196             :             letoh32(pfp->ioc_loginfo));
    2197             :         DNPRINTF(MPI_D_MISC, "%s:  max_devices: %d port_type: 0x%02x\n",
    2198             :             DEVNAME(sc), letoh16(pfp->max_devices), pfp->port_type);
    2199             :         DNPRINTF(MPI_D_MISC, "%s:  protocol_flags: 0x%04x port_scsi_id: %d\n",
    2200             :             DEVNAME(sc), letoh16(pfp->protocol_flags),
    2201             :             letoh16(pfp->port_scsi_id));
    2202             :         DNPRINTF(MPI_D_MISC, "%s:  max_persistent_ids: %d "
    2203             :             "max_posted_cmd_buffers: %d\n", DEVNAME(sc),
    2204             :             letoh16(pfp->max_persistent_ids),
    2205             :             letoh16(pfp->max_posted_cmd_buffers));
    2206             :         DNPRINTF(MPI_D_MISC, "%s:  max_lan_buckets: %d\n", DEVNAME(sc),
    2207             :             letoh16(pfp->max_lan_buckets));
    2208             : 
    2209           0 :         sc->sc_porttype = pfp->port_type;
    2210           0 :         if (sc->sc_target == -1)
    2211           0 :                 sc->sc_target = lemtoh16(&pfp->port_scsi_id);
    2212             : 
    2213           0 :         mpi_push_reply(sc, ccb->ccb_rcb);
    2214           0 :         rv = 0;
    2215             : err:
    2216           0 :         scsi_io_put(&sc->sc_iopool, ccb);
    2217             : 
    2218           0 :         return (rv);
    2219           0 : }
    2220             : 
    2221             : int
    2222           0 : mpi_cfg_coalescing(struct mpi_softc *sc)
    2223             : {
    2224           0 :         struct mpi_cfg_hdr              hdr;
    2225           0 :         struct mpi_cfg_ioc_pg1          pg;
    2226             :         u_int32_t                       flags;
    2227             : 
    2228           0 :         if (mpi_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_IOC, 1, 0, &hdr) != 0) {
    2229             :                 DNPRINTF(MPI_D_MISC, "%s: unable to fetch IOC page 1 header\n",
    2230             :                     DEVNAME(sc));
    2231           0 :                 return (1);
    2232             :         }
    2233             : 
    2234           0 :         if (mpi_cfg_page(sc, 0, &hdr, 1, &pg, sizeof(pg)) != 0) {
    2235             :                 DNPRINTF(MPI_D_MISC, "%s: unable to fetch IOC page 1\n",
    2236             :                     DEVNAME(sc));
    2237           0 :                 return (1);
    2238             :         }
    2239             : 
    2240             :         DNPRINTF(MPI_D_MISC, "%s: IOC page 1\n", DEVNAME(sc));
    2241             :         DNPRINTF(MPI_D_MISC, "%s:  flags: 0x%08x\n", DEVNAME(sc),
    2242             :             letoh32(pg.flags));
    2243             :         DNPRINTF(MPI_D_MISC, "%s:  coalescing_timeout: %d\n", DEVNAME(sc),
    2244             :             letoh32(pg.coalescing_timeout));
    2245             :         DNPRINTF(MPI_D_MISC, "%s:  coalescing_depth: %d pci_slot_num: %d\n",
    2246             :             DEVNAME(sc), pg.coalescing_depth, pg.pci_slot_num);
    2247             : 
    2248           0 :         flags = lemtoh32(&pg.flags);
    2249           0 :         if (!ISSET(flags, MPI_CFG_IOC_1_REPLY_COALESCING))
    2250           0 :                 return (0);
    2251             : 
    2252           0 :         CLR(pg.flags, htole32(MPI_CFG_IOC_1_REPLY_COALESCING));
    2253           0 :         if (mpi_cfg_page(sc, 0, &hdr, 0, &pg, sizeof(pg)) != 0) {
    2254             :                 DNPRINTF(MPI_D_MISC, "%s: unable to clear coalescing\n",
    2255             :                     DEVNAME(sc));
    2256           0 :                 return (1);
    2257             :         }
    2258             : 
    2259           0 :         return (0);
    2260           0 : }
    2261             : 
    2262             : int
    2263           0 : mpi_eventnotify(struct mpi_softc *sc)
    2264             : {
    2265             :         struct mpi_ccb                          *ccb;
    2266             :         struct mpi_msg_event_request            *enq;
    2267             : 
    2268           0 :         ccb = scsi_io_get(&sc->sc_iopool, SCSI_NOSLEEP);
    2269           0 :         if (ccb == NULL) {
    2270             :                 DNPRINTF(MPI_D_MISC, "%s: mpi_eventnotify ccb_get\n",
    2271             :                     DEVNAME(sc));
    2272           0 :                 return (1);
    2273             :         }
    2274             : 
    2275           0 :         sc->sc_evt_ccb = ccb;
    2276           0 :         SIMPLEQ_INIT(&sc->sc_evt_ack_queue);
    2277           0 :         mtx_init(&sc->sc_evt_ack_mtx, IPL_BIO);
    2278           0 :         scsi_ioh_set(&sc->sc_evt_ack_handler, &sc->sc_iopool,
    2279           0 :             mpi_eventack, sc);
    2280             : 
    2281           0 :         ccb->ccb_done = mpi_eventnotify_done;
    2282           0 :         enq = ccb->ccb_cmd;
    2283             : 
    2284           0 :         enq->function = MPI_FUNCTION_EVENT_NOTIFICATION;
    2285           0 :         enq->chain_offset = 0;
    2286           0 :         enq->event_switch = MPI_EVENT_SWITCH_ON;
    2287             : 
    2288           0 :         mpi_start(sc, ccb);
    2289           0 :         return (0);
    2290           0 : }
    2291             : 
    2292             : void
    2293           0 : mpi_eventnotify_done(struct mpi_ccb *ccb)
    2294             : {
    2295           0 :         struct mpi_softc                        *sc = ccb->ccb_sc;
    2296           0 :         struct mpi_rcb                          *rcb = ccb->ccb_rcb;
    2297           0 :         struct mpi_msg_event_reply              *enp = rcb->rcb_reply;
    2298             : 
    2299             :         DNPRINTF(MPI_D_EVT, "%s: mpi_eventnotify_done\n", DEVNAME(sc));
    2300             : 
    2301             :         DNPRINTF(MPI_D_EVT, "%s:  function: 0x%02x msg_length: %d "
    2302             :             "data_length: %d\n", DEVNAME(sc), enp->function, enp->msg_length,
    2303             :             letoh16(enp->data_length));
    2304             :         DNPRINTF(MPI_D_EVT, "%s:  ack_required: %d msg_flags 0x%02x\n",
    2305             :             DEVNAME(sc), enp->ack_required, enp->msg_flags);
    2306             :         DNPRINTF(MPI_D_EVT, "%s:  msg_context: 0x%08x\n", DEVNAME(sc),
    2307             :             letoh32(enp->msg_context));
    2308             :         DNPRINTF(MPI_D_EVT, "%s:  ioc_status: 0x%04x\n", DEVNAME(sc),
    2309             :             letoh16(enp->ioc_status));
    2310             :         DNPRINTF(MPI_D_EVT, "%s:  ioc_loginfo: 0x%08x\n", DEVNAME(sc),
    2311             :             letoh32(enp->ioc_loginfo));
    2312             :         DNPRINTF(MPI_D_EVT, "%s:  event: 0x%08x\n", DEVNAME(sc),
    2313             :             letoh32(enp->event));
    2314             :         DNPRINTF(MPI_D_EVT, "%s:  event_context: 0x%08x\n", DEVNAME(sc),
    2315             :             letoh32(enp->event_context));
    2316             : 
    2317           0 :         switch (lemtoh32(&enp->event)) {
    2318             :         /* ignore these */
    2319             :         case MPI_EVENT_EVENT_CHANGE:
    2320             :         case MPI_EVENT_SAS_PHY_LINK_STATUS:
    2321             :                 break;
    2322             : 
    2323             :         case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
    2324           0 :                 if (sc->sc_scsibus == NULL)
    2325             :                         break;
    2326             : 
    2327           0 :                 if (mpi_evt_sas(sc, rcb) != 0) {
    2328             :                         /* reply is freed later on */
    2329           0 :                         return;
    2330             :                 }
    2331             :                 break;
    2332             : 
    2333             :         case MPI_EVENT_RESCAN:
    2334           0 :                 if (sc->sc_scsibus != NULL &&
    2335           0 :                     sc->sc_porttype == MPI_PORTFACTS_PORTTYPE_FC)
    2336           0 :                         task_add(systq, &sc->sc_evt_rescan);
    2337             :                 break;
    2338             : 
    2339             :         default:
    2340             :                 DNPRINTF(MPI_D_EVT, "%s:  unhandled event 0x%02x\n",
    2341             :                     DEVNAME(sc), lemtoh32(&enp->event));
    2342             :                 break;
    2343             :         }
    2344             : 
    2345           0 :         mpi_eventnotify_free(sc, rcb);
    2346           0 : }
    2347             : 
    2348             : void
    2349           0 : mpi_eventnotify_free(struct mpi_softc *sc, struct mpi_rcb *rcb)
    2350             : {
    2351           0 :         struct mpi_msg_event_reply              *enp = rcb->rcb_reply;
    2352             : 
    2353           0 :         if (enp->ack_required) {
    2354           0 :                 mtx_enter(&sc->sc_evt_ack_mtx);
    2355           0 :                 SIMPLEQ_INSERT_TAIL(&sc->sc_evt_ack_queue, rcb, rcb_link);
    2356           0 :                 mtx_leave(&sc->sc_evt_ack_mtx);
    2357           0 :                 scsi_ioh_add(&sc->sc_evt_ack_handler);
    2358           0 :         } else
    2359           0 :                 mpi_push_reply(sc, rcb);
    2360           0 : }
    2361             : 
    2362             : int
    2363           0 : mpi_evt_sas(struct mpi_softc *sc, struct mpi_rcb *rcb)
    2364             : {
    2365             :         struct mpi_evt_sas_change               *ch;
    2366             :         u_int8_t                                *data;
    2367             : 
    2368           0 :         data = rcb->rcb_reply;
    2369           0 :         data += sizeof(struct mpi_msg_event_reply);
    2370           0 :         ch = (struct mpi_evt_sas_change *)data;
    2371             : 
    2372           0 :         if (ch->bus != 0)
    2373           0 :                 return (0);
    2374             : 
    2375           0 :         switch (ch->reason) {
    2376             :         case MPI_EVT_SASCH_REASON_ADDED:
    2377             :         case MPI_EVT_SASCH_REASON_NO_PERSIST_ADDED:
    2378           0 :                 KERNEL_LOCK();
    2379           0 :                 if (scsi_req_probe(sc->sc_scsibus, ch->target, -1) != 0) {
    2380           0 :                         printf("%s: unable to request attach of %d\n",
    2381           0 :                             DEVNAME(sc), ch->target);
    2382           0 :                 }
    2383           0 :                 KERNEL_UNLOCK();
    2384           0 :                 break;
    2385             : 
    2386             :         case MPI_EVT_SASCH_REASON_NOT_RESPONDING:
    2387           0 :                 KERNEL_LOCK();
    2388           0 :                 scsi_activate(sc->sc_scsibus, ch->target, -1, DVACT_DEACTIVATE);
    2389           0 :                 KERNEL_UNLOCK();
    2390             : 
    2391           0 :                 mtx_enter(&sc->sc_evt_scan_mtx);
    2392           0 :                 SIMPLEQ_INSERT_TAIL(&sc->sc_evt_scan_queue, rcb, rcb_link);
    2393           0 :                 mtx_leave(&sc->sc_evt_scan_mtx);
    2394           0 :                 scsi_ioh_add(&sc->sc_evt_scan_handler);
    2395             : 
    2396             :                 /* we'll handle event ack later on */
    2397           0 :                 return (1);
    2398             : 
    2399             :         case MPI_EVT_SASCH_REASON_SMART_DATA:
    2400             :         case MPI_EVT_SASCH_REASON_UNSUPPORTED:
    2401             :         case MPI_EVT_SASCH_REASON_INTERNAL_RESET:
    2402             :                 break;
    2403             :         default:
    2404           0 :                 printf("%s: unknown reason for SAS device status change: "
    2405           0 :                     "0x%02x\n", DEVNAME(sc), ch->reason);
    2406           0 :                 break;
    2407             :         }
    2408             : 
    2409           0 :         return (0);
    2410           0 : }
    2411             : 
    2412             : void
    2413           0 : mpi_evt_sas_detach(void *cookie, void *io)
    2414             : {
    2415           0 :         struct mpi_softc                        *sc = cookie;
    2416           0 :         struct mpi_ccb                          *ccb = io;
    2417             :         struct mpi_rcb                          *rcb, *next;
    2418             :         struct mpi_msg_event_reply              *enp;
    2419             :         struct mpi_evt_sas_change               *ch;
    2420             :         struct mpi_msg_scsi_task_request        *str;
    2421             : 
    2422             :         DNPRINTF(MPI_D_EVT, "%s: event sas detach handler\n", DEVNAME(sc));
    2423             : 
    2424           0 :         mtx_enter(&sc->sc_evt_scan_mtx);
    2425           0 :         rcb = SIMPLEQ_FIRST(&sc->sc_evt_scan_queue);
    2426           0 :         if (rcb != NULL) {
    2427           0 :                 next = SIMPLEQ_NEXT(rcb, rcb_link);
    2428           0 :                 SIMPLEQ_REMOVE_HEAD(&sc->sc_evt_scan_queue, rcb_link);
    2429             :         }
    2430           0 :         mtx_leave(&sc->sc_evt_scan_mtx);
    2431             : 
    2432           0 :         if (rcb == NULL) {
    2433           0 :                 scsi_io_put(&sc->sc_iopool, ccb);
    2434           0 :                 return;
    2435             :         }
    2436             : 
    2437           0 :         enp = rcb->rcb_reply;
    2438           0 :         ch = (struct mpi_evt_sas_change *)(enp + 1);
    2439             : 
    2440           0 :         ccb->ccb_done = mpi_evt_sas_detach_done;
    2441           0 :         str = ccb->ccb_cmd;
    2442             : 
    2443           0 :         str->target_id = ch->target;
    2444           0 :         str->bus = 0;
    2445           0 :         str->function = MPI_FUNCTION_SCSI_TASK_MGMT;
    2446             : 
    2447           0 :         str->task_type = MPI_MSG_SCSI_TASK_TYPE_TARGET_RESET;
    2448             : 
    2449           0 :         mpi_eventnotify_free(sc, rcb);
    2450             : 
    2451           0 :         mpi_start(sc, ccb);
    2452             : 
    2453           0 :         if (next != NULL)
    2454           0 :                 scsi_ioh_add(&sc->sc_evt_scan_handler);
    2455           0 : }
    2456             : 
    2457             : void
    2458           0 : mpi_evt_sas_detach_done(struct mpi_ccb *ccb)
    2459             : {
    2460           0 :         struct mpi_softc                        *sc = ccb->ccb_sc;
    2461           0 :         struct mpi_msg_scsi_task_reply          *r = ccb->ccb_rcb->rcb_reply;
    2462             : 
    2463           0 :         KERNEL_LOCK();
    2464           0 :         if (scsi_req_detach(sc->sc_scsibus, r->target_id, -1,
    2465           0 :             DETACH_FORCE) != 0) {
    2466           0 :                 printf("%s: unable to request detach of %d\n",
    2467           0 :                     DEVNAME(sc), r->target_id);
    2468           0 :         }
    2469           0 :         KERNEL_UNLOCK();
    2470             : 
    2471           0 :         mpi_push_reply(sc, ccb->ccb_rcb);
    2472           0 :         scsi_io_put(&sc->sc_iopool, ccb);
    2473           0 : }
    2474             : 
    2475             : void
    2476           0 : mpi_fc_rescan(void *xsc)
    2477             : {
    2478           0 :         struct mpi_softc                        *sc = xsc;
    2479           0 :         struct mpi_cfg_hdr                      hdr;
    2480           0 :         struct mpi_cfg_fc_device_pg0            pg;
    2481             :         struct scsi_link                        *link;
    2482           0 :         u_int8_t                                devmap[256 / NBBY];
    2483             :         u_int32_t                               id = 0xffffff;
    2484             :         int                                     i;
    2485             : 
    2486           0 :         memset(devmap, 0, sizeof(devmap));
    2487             : 
    2488           0 :         do {
    2489           0 :                 if (mpi_req_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_FC_DEV, 0,
    2490           0 :                     id, 0, &hdr) != 0) {
    2491           0 :                         printf("%s: header get for rescan of 0x%08x failed\n",
    2492           0 :                             DEVNAME(sc), id);
    2493           0 :                         return;
    2494             :                 }
    2495             : 
    2496           0 :                 memset(&pg, 0, sizeof(pg));
    2497           0 :                 if (mpi_req_cfg_page(sc, id, 0, &hdr, 1, &pg, sizeof(pg)) != 0)
    2498             :                         break;
    2499             : 
    2500           0 :                 if (ISSET(pg.flags, MPI_CFG_FC_DEV_0_FLAGS_BUSADDR_VALID) &&
    2501           0 :                     pg.current_bus == 0)
    2502           0 :                         setbit(devmap, pg.current_target_id);
    2503             : 
    2504           0 :                 id = lemtoh32(&pg.port_id);
    2505           0 :         } while (id <= 0xff0000);
    2506             : 
    2507           0 :         for (i = 0; i < sc->sc_buswidth; i++) {
    2508           0 :                 link = scsi_get_link(sc->sc_scsibus, i, 0);
    2509             : 
    2510           0 :                 if (isset(devmap, i)) {
    2511           0 :                         if (link == NULL)
    2512           0 :                                 scsi_probe_target(sc->sc_scsibus, i);
    2513             :                 } else {
    2514           0 :                         if (link != NULL) {
    2515           0 :                                 scsi_activate(sc->sc_scsibus, i, -1,
    2516             :                                     DVACT_DEACTIVATE);
    2517           0 :                                 scsi_detach_target(sc->sc_scsibus, i,
    2518             :                                     DETACH_FORCE);
    2519           0 :                         }
    2520             :                 }
    2521             :         }
    2522           0 : }
    2523             : 
    2524             : void
    2525           0 : mpi_eventack(void *cookie, void *io)
    2526             : {
    2527           0 :         struct mpi_softc                        *sc = cookie;
    2528           0 :         struct mpi_ccb                          *ccb = io;
    2529             :         struct mpi_rcb                          *rcb, *next;
    2530             :         struct mpi_msg_event_reply              *enp;
    2531             :         struct mpi_msg_eventack_request         *eaq;
    2532             : 
    2533             :         DNPRINTF(MPI_D_EVT, "%s: event ack\n", DEVNAME(sc));
    2534             : 
    2535           0 :         mtx_enter(&sc->sc_evt_ack_mtx);
    2536           0 :         rcb = SIMPLEQ_FIRST(&sc->sc_evt_ack_queue);
    2537           0 :         if (rcb != NULL) {
    2538           0 :                 next = SIMPLEQ_NEXT(rcb, rcb_link);
    2539           0 :                 SIMPLEQ_REMOVE_HEAD(&sc->sc_evt_ack_queue, rcb_link);
    2540             :         }
    2541           0 :         mtx_leave(&sc->sc_evt_ack_mtx);
    2542             : 
    2543           0 :         if (rcb == NULL) {
    2544           0 :                 scsi_io_put(&sc->sc_iopool, ccb);
    2545           0 :                 return;
    2546             :         }
    2547             : 
    2548           0 :         enp = rcb->rcb_reply;
    2549             : 
    2550           0 :         ccb->ccb_done = mpi_eventack_done;
    2551           0 :         eaq = ccb->ccb_cmd;
    2552             : 
    2553           0 :         eaq->function = MPI_FUNCTION_EVENT_ACK;
    2554             : 
    2555           0 :         eaq->event = enp->event;
    2556           0 :         eaq->event_context = enp->event_context;
    2557             : 
    2558           0 :         mpi_push_reply(sc, rcb);
    2559           0 :         mpi_start(sc, ccb);
    2560             : 
    2561           0 :         if (next != NULL)
    2562           0 :                 scsi_ioh_add(&sc->sc_evt_ack_handler);
    2563           0 : }
    2564             : 
    2565             : void
    2566           0 : mpi_eventack_done(struct mpi_ccb *ccb)
    2567             : {
    2568           0 :         struct mpi_softc                        *sc = ccb->ccb_sc;
    2569             : 
    2570             :         DNPRINTF(MPI_D_EVT, "%s: event ack done\n", DEVNAME(sc));
    2571             : 
    2572           0 :         mpi_push_reply(sc, ccb->ccb_rcb);
    2573           0 :         scsi_io_put(&sc->sc_iopool, ccb);
    2574           0 : }
    2575             : 
    2576             : int
    2577           0 : mpi_portenable(struct mpi_softc *sc)
    2578             : {
    2579             :         struct mpi_ccb                          *ccb;
    2580             :         struct mpi_msg_portenable_request       *peq;
    2581             :         int                                     rv = 0;
    2582             : 
    2583             :         DNPRINTF(MPI_D_MISC, "%s: mpi_portenable\n", DEVNAME(sc));
    2584             : 
    2585           0 :         ccb = scsi_io_get(&sc->sc_iopool, SCSI_NOSLEEP);
    2586           0 :         if (ccb == NULL) {
    2587             :                 DNPRINTF(MPI_D_MISC, "%s: mpi_portenable ccb_get\n",
    2588             :                     DEVNAME(sc));
    2589           0 :                 return (1);
    2590             :         }
    2591             : 
    2592           0 :         ccb->ccb_done = mpi_empty_done;
    2593           0 :         peq = ccb->ccb_cmd;
    2594             : 
    2595           0 :         peq->function = MPI_FUNCTION_PORT_ENABLE;
    2596           0 :         peq->port_number = 0;
    2597             : 
    2598           0 :         if (mpi_poll(sc, ccb, 50000) != 0) {
    2599             :                 DNPRINTF(MPI_D_MISC, "%s: mpi_portenable poll\n", DEVNAME(sc));
    2600           0 :                 return (1);
    2601             :         }
    2602             : 
    2603           0 :         if (ccb->ccb_rcb == NULL) {
    2604             :                 DNPRINTF(MPI_D_MISC, "%s: empty portenable reply\n",
    2605             :                     DEVNAME(sc));
    2606             :                 rv = 1;
    2607           0 :         } else
    2608           0 :                 mpi_push_reply(sc, ccb->ccb_rcb);
    2609             : 
    2610           0 :         scsi_io_put(&sc->sc_iopool, ccb);
    2611             : 
    2612           0 :         return (rv);
    2613           0 : }
    2614             : 
    2615             : int
    2616           0 : mpi_fwupload(struct mpi_softc *sc)
    2617             : {
    2618             :         struct mpi_ccb                          *ccb;
    2619             :         struct {
    2620             :                 struct mpi_msg_fwupload_request         req;
    2621             :                 struct mpi_sge                          sge;
    2622             :         } __packed                              *bundle;
    2623             :         struct mpi_msg_fwupload_reply           *upp;
    2624             :         int                                     rv = 0;
    2625             : 
    2626           0 :         if (sc->sc_fw_len == 0)
    2627           0 :                 return (0);
    2628             : 
    2629             :         DNPRINTF(MPI_D_MISC, "%s: mpi_fwupload\n", DEVNAME(sc));
    2630             : 
    2631           0 :         sc->sc_fw = mpi_dmamem_alloc(sc, sc->sc_fw_len);
    2632           0 :         if (sc->sc_fw == NULL) {
    2633             :                 DNPRINTF(MPI_D_MISC, "%s: mpi_fwupload unable to allocate %d\n",
    2634             :                     DEVNAME(sc), sc->sc_fw_len);
    2635           0 :                 return (1);
    2636             :         }
    2637             : 
    2638           0 :         ccb = scsi_io_get(&sc->sc_iopool, SCSI_NOSLEEP);
    2639           0 :         if (ccb == NULL) {
    2640             :                 DNPRINTF(MPI_D_MISC, "%s: mpi_fwupload ccb_get\n",
    2641             :                     DEVNAME(sc));
    2642             :                 goto err;
    2643             :         }
    2644             : 
    2645           0 :         ccb->ccb_done = mpi_empty_done;
    2646           0 :         bundle = ccb->ccb_cmd;
    2647             : 
    2648           0 :         bundle->req.function = MPI_FUNCTION_FW_UPLOAD;
    2649             : 
    2650           0 :         bundle->req.image_type = MPI_FWUPLOAD_IMAGETYPE_IOC_FW;
    2651             : 
    2652           0 :         bundle->req.tce.details_length = 12;
    2653           0 :         htolem32(&bundle->req.tce.image_size, sc->sc_fw_len);
    2654             : 
    2655           0 :         htolem32(&bundle->sge.sg_hdr, MPI_SGE_FL_TYPE_SIMPLE |
    2656             :             MPI_SGE_FL_SIZE_64 | MPI_SGE_FL_LAST | MPI_SGE_FL_EOB |
    2657             :             MPI_SGE_FL_EOL | (u_int32_t)sc->sc_fw_len);
    2658           0 :         mpi_dvatosge(&bundle->sge, MPI_DMA_DVA(sc->sc_fw));
    2659             : 
    2660           0 :         if (mpi_poll(sc, ccb, 50000) != 0) {
    2661             :                 DNPRINTF(MPI_D_MISC, "%s: mpi_cfg_header poll\n", DEVNAME(sc));
    2662             :                 goto err;
    2663             :         }
    2664             : 
    2665           0 :         if (ccb->ccb_rcb == NULL)
    2666           0 :                 panic("%s: unable to do fw upload", DEVNAME(sc));
    2667           0 :         upp = ccb->ccb_rcb->rcb_reply;
    2668             : 
    2669           0 :         if (lemtoh16(&upp->ioc_status) != MPI_IOCSTATUS_SUCCESS)
    2670           0 :                 rv = 1;
    2671             : 
    2672           0 :         mpi_push_reply(sc, ccb->ccb_rcb);
    2673           0 :         scsi_io_put(&sc->sc_iopool, ccb);
    2674             : 
    2675           0 :         return (rv);
    2676             : 
    2677             : err:
    2678           0 :         mpi_dmamem_free(sc, sc->sc_fw);
    2679           0 :         return (1);
    2680           0 : }
    2681             : 
    2682             : int
    2683           0 : mpi_manufacturing(struct mpi_softc *sc)
    2684             : {
    2685           0 :         char board_name[33];
    2686           0 :         struct mpi_cfg_hdr hdr;
    2687             :         struct mpi_cfg_manufacturing_pg0 *pg;
    2688             :         size_t pagelen;
    2689             :         int rv = 1;
    2690             : 
    2691           0 :         if (mpi_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_MANUFACTURING,
    2692           0 :             0, 0, &hdr) != 0)
    2693           0 :                 return (1);
    2694             : 
    2695           0 :         pagelen = hdr.page_length * 4; /* dwords to bytes */
    2696           0 :         if (pagelen < sizeof(*pg))
    2697           0 :                 return (1);
    2698             : 
    2699           0 :         pg = malloc(pagelen, M_TEMP, M_WAITOK|M_CANFAIL);
    2700           0 :         if (pg == NULL)
    2701           0 :                 return (1);
    2702             : 
    2703           0 :         if (mpi_cfg_page(sc, 0, &hdr, 1, pg, pagelen) != 0)
    2704             :                 goto out;
    2705             : 
    2706           0 :         scsi_strvis(board_name, pg->board_name, sizeof(pg->board_name));
    2707             : 
    2708           0 :         printf("%s: %s, firmware %d.%d.%d.%d\n", DEVNAME(sc), board_name,
    2709           0 :             sc->sc_fw_maj, sc->sc_fw_min, sc->sc_fw_unit, sc->sc_fw_dev);
    2710             : 
    2711           0 :         rv = 0;
    2712             : 
    2713             : out:
    2714           0 :         free(pg, M_TEMP, pagelen);
    2715           0 :         return (rv);
    2716           0 : }
    2717             : 
    2718             : void
    2719           0 : mpi_get_raid(struct mpi_softc *sc)
    2720             : {
    2721           0 :         struct mpi_cfg_hdr              hdr;
    2722             :         struct mpi_cfg_ioc_pg2          *vol_page;
    2723             :         size_t                          pagelen;
    2724             :         u_int32_t                       capabilities;
    2725             : 
    2726             :         DNPRINTF(MPI_D_RAID, "%s: mpi_get_raid\n", DEVNAME(sc));
    2727             : 
    2728           0 :         if (mpi_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_IOC, 2, 0, &hdr) != 0) {
    2729             :                 DNPRINTF(MPI_D_RAID, "%s: mpi_get_raid unable to fetch header"
    2730             :                     "for IOC page 2\n", DEVNAME(sc));
    2731           0 :                 return;
    2732             :         }
    2733             : 
    2734           0 :         pagelen = hdr.page_length * 4; /* dwords to bytes */
    2735           0 :         vol_page = malloc(pagelen, M_TEMP, M_WAITOK|M_CANFAIL);
    2736           0 :         if (vol_page == NULL) {
    2737             :                 DNPRINTF(MPI_D_RAID, "%s: mpi_get_raid unable to allocate "
    2738             :                     "space for ioc config page 2\n", DEVNAME(sc));
    2739           0 :                 return;
    2740             :         }
    2741             : 
    2742           0 :         if (mpi_cfg_page(sc, 0, &hdr, 1, vol_page, pagelen) != 0) {
    2743             :                 DNPRINTF(MPI_D_RAID, "%s: mpi_get_raid unable to fetch IOC "
    2744             :                     "page 2\n", DEVNAME(sc));
    2745             :                 goto out;
    2746             :         }
    2747             : 
    2748           0 :         capabilities = lemtoh32(&vol_page->capabilities);
    2749             : 
    2750             :         DNPRINTF(MPI_D_RAID, "%s:  capabilities: 0x08%x\n", DEVNAME(sc),
    2751             :             letoh32(vol_page->capabilities));
    2752             :         DNPRINTF(MPI_D_RAID, "%s:  active_vols: %d max_vols: %d "
    2753             :             "active_physdisks: %d max_physdisks: %d\n", DEVNAME(sc),
    2754             :             vol_page->active_vols, vol_page->max_vols,
    2755             :             vol_page->active_physdisks, vol_page->max_physdisks);
    2756             : 
    2757             :         /* don't walk list if there are no RAID capability */
    2758           0 :         if (capabilities == 0xdeadbeef) {
    2759           0 :                 printf("%s: deadbeef in raid configuration\n", DEVNAME(sc));
    2760           0 :                 goto out;
    2761             :         }
    2762             : 
    2763           0 :         if (ISSET(capabilities, MPI_CFG_IOC_2_CAPABILITIES_RAID))
    2764           0 :                 sc->sc_flags |= MPI_F_RAID;
    2765             : 
    2766             : out:
    2767           0 :         free(vol_page, M_TEMP, pagelen);
    2768           0 : }
    2769             : 
    2770             : int
    2771           0 : mpi_req_cfg_header(struct mpi_softc *sc, u_int8_t type, u_int8_t number,
    2772             :     u_int32_t address, int flags, void *p)
    2773             : {
    2774             :         struct mpi_ccb                          *ccb;
    2775             :         struct mpi_msg_config_request           *cq;
    2776             :         struct mpi_msg_config_reply             *cp;
    2777           0 :         struct mpi_cfg_hdr                      *hdr = p;
    2778           0 :         struct mpi_ecfg_hdr                     *ehdr = p;
    2779             :         int                                     etype = 0;
    2780             :         int                                     rv = 0;
    2781             : 
    2782             :         DNPRINTF(MPI_D_MISC, "%s: mpi_req_cfg_header type: %#x number: %x "
    2783             :             "address: 0x%08x flags: 0x%b\n", DEVNAME(sc), type, number,
    2784             :             address, flags, MPI_PG_FMT);
    2785             : 
    2786           0 :         ccb = scsi_io_get(&sc->sc_iopool,
    2787           0 :             ISSET(flags, MPI_PG_POLL) ? SCSI_NOSLEEP : 0);
    2788           0 :         if (ccb == NULL) {
    2789             :                 DNPRINTF(MPI_D_MISC, "%s: mpi_cfg_header ccb_get\n",
    2790             :                     DEVNAME(sc));
    2791           0 :                 return (1);
    2792             :         }
    2793             : 
    2794           0 :         if (ISSET(flags, MPI_PG_EXTENDED)) {
    2795           0 :                 etype = type;
    2796             :                 type = MPI_CONFIG_REQ_PAGE_TYPE_EXTENDED;
    2797           0 :         }
    2798             : 
    2799           0 :         cq = ccb->ccb_cmd;
    2800             : 
    2801           0 :         cq->function = MPI_FUNCTION_CONFIG;
    2802             : 
    2803           0 :         cq->action = MPI_CONFIG_REQ_ACTION_PAGE_HEADER;
    2804             : 
    2805           0 :         cq->config_header.page_number = number;
    2806           0 :         cq->config_header.page_type = type;
    2807           0 :         cq->ext_page_type = etype;
    2808           0 :         htolem32(&cq->page_address, address);
    2809           0 :         htolem32(&cq->page_buffer.sg_hdr, MPI_SGE_FL_TYPE_SIMPLE |
    2810             :             MPI_SGE_FL_LAST | MPI_SGE_FL_EOB | MPI_SGE_FL_EOL);
    2811             : 
    2812           0 :         ccb->ccb_done = mpi_empty_done;
    2813           0 :         if (ISSET(flags, MPI_PG_POLL)) {
    2814           0 :                 if (mpi_poll(sc, ccb, 50000) != 0) {
    2815             :                         DNPRINTF(MPI_D_MISC, "%s: mpi_cfg_header poll\n",
    2816             :                             DEVNAME(sc));
    2817           0 :                         return (1);
    2818             :                 }
    2819             :         } else
    2820           0 :                 mpi_wait(sc, ccb);
    2821             : 
    2822           0 :         if (ccb->ccb_rcb == NULL)
    2823           0 :                 panic("%s: unable to fetch config header", DEVNAME(sc));
    2824           0 :         cp = ccb->ccb_rcb->rcb_reply;
    2825             : 
    2826             :         DNPRINTF(MPI_D_MISC, "%s:  action: 0x%02x msg_length: %d function: "
    2827             :             "0x%02x\n", DEVNAME(sc), cp->action, cp->msg_length, cp->function);
    2828             :         DNPRINTF(MPI_D_MISC, "%s:  ext_page_length: %d ext_page_type: 0x%02x "
    2829             :             "msg_flags: 0x%02x\n", DEVNAME(sc),
    2830             :             letoh16(cp->ext_page_length), cp->ext_page_type,
    2831             :             cp->msg_flags);
    2832             :         DNPRINTF(MPI_D_MISC, "%s:  msg_context: 0x%08x\n", DEVNAME(sc),
    2833             :             letoh32(cp->msg_context));
    2834             :         DNPRINTF(MPI_D_MISC, "%s:  ioc_status: 0x%04x\n", DEVNAME(sc),
    2835             :             letoh16(cp->ioc_status));
    2836             :         DNPRINTF(MPI_D_MISC, "%s:  ioc_loginfo: 0x%08x\n", DEVNAME(sc),
    2837             :             letoh32(cp->ioc_loginfo));
    2838             :         DNPRINTF(MPI_D_MISC, "%s:  page_version: 0x%02x page_length: %d "
    2839             :             "page_number: 0x%02x page_type: 0x%02x\n", DEVNAME(sc),
    2840             :             cp->config_header.page_version,
    2841             :             cp->config_header.page_length,
    2842             :             cp->config_header.page_number,
    2843             :             cp->config_header.page_type);
    2844             : 
    2845           0 :         if (lemtoh16(&cp->ioc_status) != MPI_IOCSTATUS_SUCCESS)
    2846           0 :                 rv = 1;
    2847           0 :         else if (ISSET(flags, MPI_PG_EXTENDED)) {
    2848           0 :                 memset(ehdr, 0, sizeof(*ehdr));
    2849           0 :                 ehdr->page_version = cp->config_header.page_version;
    2850           0 :                 ehdr->page_number = cp->config_header.page_number;
    2851           0 :                 ehdr->page_type = cp->config_header.page_type;
    2852           0 :                 ehdr->ext_page_length = cp->ext_page_length;
    2853           0 :                 ehdr->ext_page_type = cp->ext_page_type;
    2854           0 :         } else
    2855           0 :                 *hdr = cp->config_header;
    2856             : 
    2857           0 :         mpi_push_reply(sc, ccb->ccb_rcb);
    2858           0 :         scsi_io_put(&sc->sc_iopool, ccb);
    2859             : 
    2860           0 :         return (rv);
    2861           0 : }
    2862             : 
    2863             : int
    2864           0 : mpi_req_cfg_page(struct mpi_softc *sc, u_int32_t address, int flags,
    2865             :     void *p, int read, void *page, size_t len)
    2866             : {
    2867             :         struct mpi_ccb                          *ccb;
    2868             :         struct mpi_msg_config_request           *cq;
    2869             :         struct mpi_msg_config_reply             *cp;
    2870           0 :         struct mpi_cfg_hdr                      *hdr = p;
    2871           0 :         struct mpi_ecfg_hdr                     *ehdr = p;
    2872             :         char                                    *kva;
    2873             :         int                                     page_length;
    2874             :         int                                     rv = 0;
    2875             : 
    2876             :         DNPRINTF(MPI_D_MISC, "%s: mpi_cfg_page address: %d read: %d type: %x\n",
    2877             :             DEVNAME(sc), address, read, hdr->page_type);
    2878             : 
    2879           0 :         page_length = ISSET(flags, MPI_PG_EXTENDED) ?
    2880           0 :             lemtoh16(&ehdr->ext_page_length) : hdr->page_length;
    2881             : 
    2882           0 :         if (len > MPI_REQUEST_SIZE - sizeof(struct mpi_msg_config_request) ||
    2883           0 :             len < page_length * 4)
    2884           0 :                 return (1);
    2885             : 
    2886           0 :         ccb = scsi_io_get(&sc->sc_iopool,
    2887           0 :             ISSET(flags, MPI_PG_POLL) ? SCSI_NOSLEEP : 0);
    2888           0 :         if (ccb == NULL) {
    2889             :                 DNPRINTF(MPI_D_MISC, "%s: mpi_cfg_page ccb_get\n", DEVNAME(sc));
    2890           0 :                 return (1);
    2891             :         }
    2892             : 
    2893           0 :         cq = ccb->ccb_cmd;
    2894             : 
    2895           0 :         cq->function = MPI_FUNCTION_CONFIG;
    2896             : 
    2897           0 :         cq->action = (read ? MPI_CONFIG_REQ_ACTION_PAGE_READ_CURRENT :
    2898             :             MPI_CONFIG_REQ_ACTION_PAGE_WRITE_CURRENT);
    2899             : 
    2900           0 :         if (ISSET(flags, MPI_PG_EXTENDED)) {
    2901           0 :                 cq->config_header.page_version = ehdr->page_version;
    2902           0 :                 cq->config_header.page_number = ehdr->page_number;
    2903           0 :                 cq->config_header.page_type = ehdr->page_type;
    2904           0 :                 cq->ext_page_len = ehdr->ext_page_length;
    2905           0 :                 cq->ext_page_type = ehdr->ext_page_type;
    2906           0 :         } else
    2907           0 :                 cq->config_header = *hdr;
    2908           0 :         cq->config_header.page_type &= MPI_CONFIG_REQ_PAGE_TYPE_MASK;
    2909           0 :         htolem32(&cq->page_address, address);
    2910           0 :         htolem32(&cq->page_buffer.sg_hdr, MPI_SGE_FL_TYPE_SIMPLE |
    2911             :             MPI_SGE_FL_LAST | MPI_SGE_FL_EOB | MPI_SGE_FL_EOL |
    2912             :             (page_length * 4) |
    2913             :             (read ? MPI_SGE_FL_DIR_IN : MPI_SGE_FL_DIR_OUT));
    2914             : 
    2915             :         /* bounce the page via the request space to avoid more bus_dma games */
    2916           0 :         mpi_dvatosge(&cq->page_buffer, ccb->ccb_cmd_dva +
    2917             :             sizeof(struct mpi_msg_config_request));
    2918             : 
    2919           0 :         kva = ccb->ccb_cmd;
    2920           0 :         kva += sizeof(struct mpi_msg_config_request);
    2921           0 :         if (!read)
    2922           0 :                 memcpy(kva, page, len);
    2923             : 
    2924           0 :         ccb->ccb_done = mpi_empty_done;
    2925           0 :         if (ISSET(flags, MPI_PG_POLL)) {
    2926           0 :                 if (mpi_poll(sc, ccb, 50000) != 0) {
    2927             :                         DNPRINTF(MPI_D_MISC, "%s: mpi_cfg_header poll\n",
    2928             :                             DEVNAME(sc));
    2929           0 :                         return (1);
    2930             :                 }
    2931             :         } else
    2932           0 :                 mpi_wait(sc, ccb);
    2933             : 
    2934           0 :         if (ccb->ccb_rcb == NULL) {
    2935           0 :                 scsi_io_put(&sc->sc_iopool, ccb);
    2936           0 :                 return (1);
    2937             :         }
    2938           0 :         cp = ccb->ccb_rcb->rcb_reply;
    2939             : 
    2940             :         DNPRINTF(MPI_D_MISC, "%s:  action: 0x%02x msg_length: %d function: "
    2941             :             "0x%02x\n", DEVNAME(sc), cp->action, cp->msg_length, cp->function);
    2942             :         DNPRINTF(MPI_D_MISC, "%s:  ext_page_length: %d ext_page_type: 0x%02x "
    2943             :             "msg_flags: 0x%02x\n", DEVNAME(sc),
    2944             :             letoh16(cp->ext_page_length), cp->ext_page_type,
    2945             :             cp->msg_flags);
    2946             :         DNPRINTF(MPI_D_MISC, "%s:  msg_context: 0x%08x\n", DEVNAME(sc),
    2947             :             letoh32(cp->msg_context));
    2948             :         DNPRINTF(MPI_D_MISC, "%s:  ioc_status: 0x%04x\n", DEVNAME(sc),
    2949             :             letoh16(cp->ioc_status));
    2950             :         DNPRINTF(MPI_D_MISC, "%s:  ioc_loginfo: 0x%08x\n", DEVNAME(sc),
    2951             :             letoh32(cp->ioc_loginfo));
    2952             :         DNPRINTF(MPI_D_MISC, "%s:  page_version: 0x%02x page_length: %d "
    2953             :             "page_number: 0x%02x page_type: 0x%02x\n", DEVNAME(sc),
    2954             :             cp->config_header.page_version,
    2955             :             cp->config_header.page_length,
    2956             :             cp->config_header.page_number,
    2957             :             cp->config_header.page_type);
    2958             : 
    2959           0 :         if (lemtoh16(&cp->ioc_status) != MPI_IOCSTATUS_SUCCESS)
    2960           0 :                 rv = 1;
    2961           0 :         else if (read)
    2962           0 :                 memcpy(page, kva, len);
    2963             : 
    2964           0 :         mpi_push_reply(sc, ccb->ccb_rcb);
    2965           0 :         scsi_io_put(&sc->sc_iopool, ccb);
    2966             : 
    2967           0 :         return (rv);
    2968           0 : }
    2969             : 
    2970             : int
    2971           0 : mpi_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag)
    2972             : {
    2973           0 :         struct mpi_softc        *sc = (struct mpi_softc *)link->adapter_softc;
    2974             : 
    2975             :         DNPRINTF(MPI_D_IOCTL, "%s: mpi_scsi_ioctl\n", DEVNAME(sc));
    2976             : 
    2977           0 :         switch (cmd) {
    2978             :         case DIOCGCACHE:
    2979             :         case DIOCSCACHE:
    2980           0 :                 if (ISSET(link->flags, SDEV_VIRTUAL)) {
    2981           0 :                         return (mpi_ioctl_cache(link, cmd,
    2982           0 :                             (struct dk_cache *)addr));
    2983             :                 }
    2984             :                 break;
    2985             : 
    2986             :         default:
    2987           0 :                 if (sc->sc_ioctl)
    2988           0 :                         return (sc->sc_ioctl(link->adapter_softc, cmd, addr));
    2989             : 
    2990             :                 break;
    2991             :         }
    2992             : 
    2993           0 :         return (ENOTTY);
    2994           0 : }
    2995             : 
    2996             : int
    2997           0 : mpi_ioctl_cache(struct scsi_link *link, u_long cmd, struct dk_cache *dc)
    2998             : {
    2999           0 :         struct mpi_softc        *sc = (struct mpi_softc *)link->adapter_softc;
    3000             :         struct mpi_ccb          *ccb;
    3001             :         int                     len, rv;
    3002           0 :         struct mpi_cfg_hdr      hdr;
    3003             :         struct mpi_cfg_raid_vol_pg0 *rpg0;
    3004             :         int                     enabled;
    3005             :         struct mpi_msg_raid_action_request *req;
    3006             :         struct mpi_msg_raid_action_reply *rep;
    3007           0 :         struct mpi_raid_settings settings;
    3008             : 
    3009           0 :         rv = mpi_req_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_RAID_VOL, 0,
    3010           0 :             link->target, MPI_PG_POLL, &hdr);
    3011           0 :         if (rv != 0)
    3012           0 :                 return (EIO);
    3013             : 
    3014           0 :         len = sizeof(*rpg0) + sc->sc_vol_page->max_physdisks *
    3015             :             sizeof(struct mpi_cfg_raid_vol_pg0_physdisk);
    3016           0 :         rpg0 = malloc(len, M_TEMP, M_NOWAIT);
    3017           0 :         if (rpg0 == NULL)
    3018           0 :                 return (ENOMEM);
    3019             : 
    3020           0 :         if (mpi_req_cfg_page(sc, link->target, MPI_PG_POLL, &hdr, 1,
    3021           0 :             rpg0, len) != 0) {
    3022             :                 DNPRINTF(MPI_D_RAID, "%s: can't get RAID vol cfg page 0\n",
    3023             :                     DEVNAME(sc));
    3024             :                 rv = EIO;
    3025           0 :                 goto done;
    3026             :         }
    3027             : 
    3028           0 :         enabled = ISSET(lemtoh16(&rpg0->settings.volume_settings),
    3029             :             MPI_CFG_RAID_VOL_0_SETTINGS_WRITE_CACHE_EN) ? 1 : 0;
    3030             : 
    3031           0 :         if (cmd == DIOCGCACHE) {
    3032           0 :                 dc->wrcache = enabled;
    3033           0 :                 dc->rdcache = 0;
    3034           0 :                 goto done;
    3035             :         } /* else DIOCSCACHE */
    3036             : 
    3037           0 :         if (dc->rdcache) {
    3038             :                 rv = EOPNOTSUPP;
    3039           0 :                 goto done;
    3040             :         }
    3041             : 
    3042           0 :         if (((dc->wrcache) ? 1 : 0) == enabled)
    3043             :                 goto done;
    3044             : 
    3045           0 :         settings = rpg0->settings;
    3046           0 :         if (dc->wrcache) {
    3047           0 :                 SET(settings.volume_settings,
    3048             :                     htole16(MPI_CFG_RAID_VOL_0_SETTINGS_WRITE_CACHE_EN));
    3049           0 :         } else {
    3050           0 :                 CLR(settings.volume_settings,
    3051             :                     htole16(MPI_CFG_RAID_VOL_0_SETTINGS_WRITE_CACHE_EN));
    3052             :         }
    3053             : 
    3054           0 :         ccb = scsi_io_get(&sc->sc_iopool, SCSI_NOSLEEP);
    3055           0 :         if (ccb == NULL) {
    3056             :                 rv = ENOMEM;
    3057           0 :                 goto done;
    3058             :         }
    3059             : 
    3060           0 :         req = ccb->ccb_cmd;
    3061           0 :         req->function = MPI_FUNCTION_RAID_ACTION;
    3062           0 :         req->action = MPI_MSG_RAID_ACTION_CH_VOL_SETTINGS;
    3063           0 :         req->vol_id = rpg0->volume_id;
    3064           0 :         req->vol_bus = rpg0->volume_bus;
    3065             : 
    3066           0 :         memcpy(&req->data_word, &settings, sizeof(req->data_word));
    3067           0 :         ccb->ccb_done = mpi_empty_done;
    3068           0 :         if (mpi_poll(sc, ccb, 50000) != 0) {
    3069             :                 rv = EIO;
    3070           0 :                 goto done;
    3071             :         }
    3072             : 
    3073           0 :         rep = (struct mpi_msg_raid_action_reply *)ccb->ccb_rcb;
    3074           0 :         if (rep == NULL)
    3075           0 :                 panic("%s: raid volume settings change failed", DEVNAME(sc));
    3076             : 
    3077           0 :         switch (lemtoh16(&rep->action_status)) {
    3078             :         case MPI_RAID_ACTION_STATUS_OK:
    3079             :                 rv = 0;
    3080           0 :                 break;
    3081             :         default:
    3082             :                 rv = EIO;
    3083           0 :                 break;
    3084             :         }
    3085             : 
    3086           0 :         mpi_push_reply(sc, ccb->ccb_rcb);
    3087           0 :         scsi_io_put(&sc->sc_iopool, ccb);
    3088             : 
    3089             : done:
    3090           0 :         free(rpg0, M_TEMP, len);
    3091           0 :         return (rv);
    3092           0 : }
    3093             : 
    3094             : #if NBIO > 0
    3095             : int
    3096           0 : mpi_bio_get_pg0_raid(struct mpi_softc *sc, int id)
    3097             : {
    3098             :         int                     len, rv = EINVAL;
    3099             :         u_int32_t               address;
    3100           0 :         struct mpi_cfg_hdr      hdr;
    3101             :         struct mpi_cfg_raid_vol_pg0 *rpg0;
    3102             : 
    3103             :         /* get IOC page 2 */
    3104           0 :         if (mpi_req_cfg_page(sc, 0, 0, &sc->sc_cfg_hdr, 1, sc->sc_vol_page,
    3105           0 :             sc->sc_cfg_hdr.page_length * 4) != 0) {
    3106             :                 DNPRINTF(MPI_D_IOCTL, "%s: mpi_bio_get_pg0_raid unable to "
    3107             :                     "fetch IOC page 2\n", DEVNAME(sc));
    3108             :                 goto done;
    3109             :         }
    3110             : 
    3111             :         /* XXX return something else than EINVAL to indicate within hs range */
    3112           0 :         if (id > sc->sc_vol_page->active_vols) {
    3113             :                 DNPRINTF(MPI_D_IOCTL, "%s: mpi_bio_get_pg0_raid invalid vol "
    3114             :                     "id: %d\n", DEVNAME(sc), id);
    3115             :                 goto done;
    3116             :         }
    3117             : 
    3118             :         /* replace current buffer with new one */
    3119           0 :         len = sizeof *rpg0 + sc->sc_vol_page->max_physdisks *
    3120             :             sizeof(struct mpi_cfg_raid_vol_pg0_physdisk);
    3121           0 :         rpg0 = malloc(len, M_DEVBUF, M_WAITOK | M_CANFAIL);
    3122           0 :         if (rpg0 == NULL) {
    3123           0 :                 printf("%s: can't get memory for RAID page 0, "
    3124           0 :                     "bio disabled\n", DEVNAME(sc));
    3125           0 :                 goto done;
    3126             :         }
    3127           0 :         if (sc->sc_rpg0)
    3128           0 :                 free(sc->sc_rpg0, M_DEVBUF, 0);
    3129           0 :         sc->sc_rpg0 = rpg0;
    3130             : 
    3131             :         /* get raid vol page 0 */
    3132           0 :         address = sc->sc_vol_list[id].vol_id |
    3133           0 :             (sc->sc_vol_list[id].vol_bus << 8);
    3134           0 :         if (mpi_req_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_RAID_VOL, 0,
    3135           0 :             address, 0, &hdr) != 0)
    3136             :                 goto done;
    3137           0 :         if (mpi_req_cfg_page(sc, address, 0, &hdr, 1, rpg0, len)) {
    3138             :                 DNPRINTF(MPI_D_RAID, "%s: can't get RAID vol cfg page 0\n",
    3139             :                     DEVNAME(sc));
    3140             :                 goto done;
    3141             :         }
    3142             : 
    3143           0 :         rv = 0;
    3144             : done:
    3145           0 :         return (rv);
    3146           0 : }
    3147             : 
    3148             : int
    3149           0 : mpi_ioctl(struct device *dev, u_long cmd, caddr_t addr)
    3150             : {
    3151           0 :         struct mpi_softc        *sc = (struct mpi_softc *)dev;
    3152             :         int error = 0;
    3153             : 
    3154             :         DNPRINTF(MPI_D_IOCTL, "%s: mpi_ioctl ", DEVNAME(sc));
    3155             : 
    3156             :         /* make sure we have bio enabled */
    3157           0 :         if (sc->sc_ioctl != mpi_ioctl)
    3158           0 :                 return (EINVAL);
    3159             : 
    3160           0 :         rw_enter_write(&sc->sc_lock);
    3161             : 
    3162           0 :         switch (cmd) {
    3163             :         case BIOCINQ:
    3164             :                 DNPRINTF(MPI_D_IOCTL, "inq\n");
    3165           0 :                 error = mpi_ioctl_inq(sc, (struct bioc_inq *)addr);
    3166           0 :                 break;
    3167             : 
    3168             :         case BIOCVOL:
    3169             :                 DNPRINTF(MPI_D_IOCTL, "vol\n");
    3170           0 :                 error = mpi_ioctl_vol(sc, (struct bioc_vol *)addr);
    3171           0 :                 break;
    3172             : 
    3173             :         case BIOCDISK:
    3174             :                 DNPRINTF(MPI_D_IOCTL, "disk\n");
    3175           0 :                 error = mpi_ioctl_disk(sc, (struct bioc_disk *)addr);
    3176           0 :                 break;
    3177             : 
    3178             :         case BIOCALARM:
    3179             :                 DNPRINTF(MPI_D_IOCTL, "alarm\n");
    3180             :                 break;
    3181             : 
    3182             :         case BIOCBLINK:
    3183             :                 DNPRINTF(MPI_D_IOCTL, "blink\n");
    3184             :                 break;
    3185             : 
    3186             :         case BIOCSETSTATE:
    3187             :                 DNPRINTF(MPI_D_IOCTL, "setstate\n");
    3188           0 :                 error = mpi_ioctl_setstate(sc, (struct bioc_setstate *)addr);
    3189           0 :                 break;
    3190             : 
    3191             :         default:
    3192             :                 DNPRINTF(MPI_D_IOCTL, " invalid ioctl\n");
    3193             :                 error = ENOTTY;
    3194           0 :         }
    3195             : 
    3196           0 :         rw_exit_write(&sc->sc_lock);
    3197             : 
    3198           0 :         return (error);
    3199           0 : }
    3200             : 
    3201             : int
    3202           0 : mpi_ioctl_inq(struct mpi_softc *sc, struct bioc_inq *bi)
    3203             : {
    3204           0 :         if (!(sc->sc_flags & MPI_F_RAID)) {
    3205           0 :                 bi->bi_novol = 0;
    3206           0 :                 bi->bi_nodisk = 0;
    3207           0 :         }
    3208             : 
    3209           0 :         if (mpi_cfg_page(sc, 0, &sc->sc_cfg_hdr, 1, sc->sc_vol_page,
    3210           0 :             sc->sc_cfg_hdr.page_length * 4) != 0) {
    3211             :                 DNPRINTF(MPI_D_IOCTL, "%s: mpi_get_raid unable to fetch IOC "
    3212             :                     "page 2\n", DEVNAME(sc));
    3213           0 :                 return (EINVAL);
    3214             :         }
    3215             : 
    3216             :         DNPRINTF(MPI_D_IOCTL, "%s:  active_vols: %d max_vols: %d "
    3217             :             "active_physdisks: %d max_physdisks: %d\n", DEVNAME(sc),
    3218             :             sc->sc_vol_page->active_vols, sc->sc_vol_page->max_vols,
    3219             :             sc->sc_vol_page->active_physdisks, sc->sc_vol_page->max_physdisks);
    3220             : 
    3221           0 :         bi->bi_novol = sc->sc_vol_page->active_vols;
    3222           0 :         bi->bi_nodisk = sc->sc_vol_page->active_physdisks;
    3223           0 :         strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev));
    3224             : 
    3225           0 :         return (0);
    3226           0 : }
    3227             : 
    3228             : int
    3229           0 : mpi_ioctl_vol(struct mpi_softc *sc, struct bioc_vol *bv)
    3230             : {
    3231             :         int                     i, vol, id, rv = EINVAL;
    3232             :         struct device           *dev;
    3233             :         struct scsi_link        *link;
    3234             :         struct mpi_cfg_raid_vol_pg0 *rpg0;
    3235             :         char                    *vendp;
    3236             : 
    3237           0 :         id = bv->bv_volid;
    3238           0 :         if (mpi_bio_get_pg0_raid(sc, id))
    3239             :                 goto done;
    3240             : 
    3241           0 :         if (id > sc->sc_vol_page->active_vols)
    3242           0 :                 return (EINVAL); /* XXX deal with hot spares */
    3243             : 
    3244           0 :         rpg0 = sc->sc_rpg0;
    3245           0 :         if (rpg0 == NULL)
    3246             :                 goto done;
    3247             : 
    3248             :         /* determine status */
    3249           0 :         switch (rpg0->volume_state) {
    3250             :         case MPI_CFG_RAID_VOL_0_STATE_OPTIMAL:
    3251           0 :                 bv->bv_status = BIOC_SVONLINE;
    3252           0 :                 break;
    3253             :         case MPI_CFG_RAID_VOL_0_STATE_DEGRADED:
    3254           0 :                 bv->bv_status = BIOC_SVDEGRADED;
    3255           0 :                 break;
    3256             :         case MPI_CFG_RAID_VOL_0_STATE_FAILED:
    3257             :         case MPI_CFG_RAID_VOL_0_STATE_MISSING:
    3258           0 :                 bv->bv_status = BIOC_SVOFFLINE;
    3259           0 :                 break;
    3260             :         default:
    3261           0 :                 bv->bv_status = BIOC_SVINVALID;
    3262           0 :         }
    3263             : 
    3264             :         /* override status if scrubbing or something */
    3265           0 :         if (rpg0->volume_status & MPI_CFG_RAID_VOL_0_STATUS_RESYNCING)
    3266           0 :                 bv->bv_status = BIOC_SVREBUILD;
    3267             : 
    3268           0 :         bv->bv_size = (uint64_t)lemtoh32(&rpg0->max_lba) * 512;
    3269             : 
    3270           0 :         switch (sc->sc_vol_list[id].vol_type) {
    3271             :         case MPI_CFG_RAID_TYPE_RAID_IS:
    3272           0 :                 bv->bv_level = 0;
    3273           0 :                 break;
    3274             :         case MPI_CFG_RAID_TYPE_RAID_IME:
    3275             :         case MPI_CFG_RAID_TYPE_RAID_IM:
    3276           0 :                 bv->bv_level = 1;
    3277           0 :                 break;
    3278             :         case MPI_CFG_RAID_TYPE_RAID_5:
    3279           0 :                 bv->bv_level = 5;
    3280           0 :                 break;
    3281             :         case MPI_CFG_RAID_TYPE_RAID_6:
    3282           0 :                 bv->bv_level = 6;
    3283           0 :                 break;
    3284             :         case MPI_CFG_RAID_TYPE_RAID_10:
    3285           0 :                 bv->bv_level = 10;
    3286           0 :                 break;
    3287             :         case MPI_CFG_RAID_TYPE_RAID_50:
    3288           0 :                 bv->bv_level = 50;
    3289           0 :                 break;
    3290             :         default:
    3291           0 :                 bv->bv_level = -1;
    3292           0 :         }
    3293             : 
    3294           0 :         bv->bv_nodisk = rpg0->num_phys_disks;
    3295             : 
    3296           0 :         for (i = 0, vol = -1; i < sc->sc_buswidth; i++) {
    3297           0 :                 link = scsi_get_link(sc->sc_scsibus, i, 0);
    3298           0 :                 if (link == NULL)
    3299             :                         continue;
    3300             : 
    3301             :                 /* skip if not a virtual disk */
    3302           0 :                 if (!(link->flags & SDEV_VIRTUAL))
    3303             :                         continue;
    3304             : 
    3305           0 :                 vol++;
    3306             :                 /* are we it? */
    3307           0 :                 if (vol == bv->bv_volid) {
    3308           0 :                         dev = link->device_softc;
    3309           0 :                         vendp = link->inqdata.vendor;
    3310           0 :                         memcpy(bv->bv_vendor, vendp, sizeof bv->bv_vendor);
    3311           0 :                         bv->bv_vendor[sizeof(bv->bv_vendor) - 1] = '\0';
    3312           0 :                         strlcpy(bv->bv_dev, dev->dv_xname, sizeof bv->bv_dev);
    3313           0 :                         break;
    3314             :                 }
    3315             :         }
    3316           0 :         rv = 0;
    3317             : done:
    3318           0 :         return (rv);
    3319           0 : }
    3320             : 
    3321             : int
    3322           0 : mpi_ioctl_disk(struct mpi_softc *sc, struct bioc_disk *bd)
    3323             : {
    3324             :         int                     pdid, id, rv = EINVAL;
    3325             :         u_int32_t               address;
    3326           0 :         struct mpi_cfg_hdr      hdr;
    3327             :         struct mpi_cfg_raid_vol_pg0 *rpg0;
    3328             :         struct mpi_cfg_raid_vol_pg0_physdisk *physdisk;
    3329           0 :         struct mpi_cfg_raid_physdisk_pg0 pdpg0;
    3330             : 
    3331           0 :         id = bd->bd_volid;
    3332           0 :         if (mpi_bio_get_pg0_raid(sc, id))
    3333             :                 goto done;
    3334             : 
    3335           0 :         if (id > sc->sc_vol_page->active_vols)
    3336           0 :                 return (EINVAL); /* XXX deal with hot spares */
    3337             : 
    3338           0 :         rpg0 = sc->sc_rpg0;
    3339           0 :         if (rpg0 == NULL)
    3340             :                 goto done;
    3341             : 
    3342           0 :         pdid = bd->bd_diskid;
    3343           0 :         if (pdid > rpg0->num_phys_disks)
    3344             :                 goto done;
    3345           0 :         physdisk = (struct mpi_cfg_raid_vol_pg0_physdisk *)(rpg0 + 1);
    3346           0 :         physdisk += pdid;
    3347             : 
    3348             :         /* get raid phys disk page 0 */
    3349           0 :         address = physdisk->phys_disk_num;
    3350           0 :         if (mpi_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_RAID_PD, 0, address,
    3351           0 :             &hdr) != 0)
    3352             :                 goto done;
    3353           0 :         if (mpi_cfg_page(sc, address, &hdr, 1, &pdpg0, sizeof pdpg0)) {
    3354           0 :                 bd->bd_status = BIOC_SDFAILED;
    3355           0 :                 return (0);
    3356             :         }
    3357           0 :         bd->bd_channel = pdpg0.phys_disk_bus;
    3358           0 :         bd->bd_target = pdpg0.phys_disk_id;
    3359           0 :         bd->bd_lun = 0;
    3360           0 :         bd->bd_size = (uint64_t)lemtoh32(&pdpg0.max_lba) * 512;
    3361           0 :         strlcpy(bd->bd_vendor, (char *)pdpg0.vendor_id, sizeof(bd->bd_vendor));
    3362             : 
    3363           0 :         switch (pdpg0.phys_disk_state) {
    3364             :         case MPI_CFG_RAID_PHYDISK_0_STATE_ONLINE:
    3365           0 :                 bd->bd_status = BIOC_SDONLINE;
    3366           0 :                 break;
    3367             :         case MPI_CFG_RAID_PHYDISK_0_STATE_MISSING:
    3368             :         case MPI_CFG_RAID_PHYDISK_0_STATE_FAILED:
    3369           0 :                 bd->bd_status = BIOC_SDFAILED;
    3370           0 :                 break;
    3371             :         case MPI_CFG_RAID_PHYDISK_0_STATE_HOSTFAIL:
    3372             :         case MPI_CFG_RAID_PHYDISK_0_STATE_OTHER:
    3373             :         case MPI_CFG_RAID_PHYDISK_0_STATE_OFFLINE:
    3374           0 :                 bd->bd_status = BIOC_SDOFFLINE;
    3375           0 :                 break;
    3376             :         case MPI_CFG_RAID_PHYDISK_0_STATE_INIT:
    3377           0 :                 bd->bd_status = BIOC_SDSCRUB;
    3378           0 :                 break;
    3379             :         case MPI_CFG_RAID_PHYDISK_0_STATE_INCOMPAT:
    3380             :         default:
    3381           0 :                 bd->bd_status = BIOC_SDINVALID;
    3382           0 :                 break;
    3383             :         }
    3384             : 
    3385             :         /* XXX figure this out */
    3386             :         /* bd_serial[32]; */
    3387             :         /* bd_procdev[16]; */
    3388             : 
    3389           0 :         rv = 0;
    3390             : done:
    3391           0 :         return (rv);
    3392           0 : }
    3393             : 
    3394             : int
    3395           0 : mpi_ioctl_setstate(struct mpi_softc *sc, struct bioc_setstate *bs)
    3396             : {
    3397           0 :         return (ENOTTY);
    3398             : }
    3399             : 
    3400             : #ifndef SMALL_KERNEL
    3401             : int
    3402           0 : mpi_create_sensors(struct mpi_softc *sc)
    3403             : {
    3404             :         struct device           *dev;
    3405             :         struct scsi_link        *link;
    3406             :         int                     i, vol, nsensors;
    3407             : 
    3408             :         /* count volumes */
    3409           0 :         for (i = 0, vol = 0; i < sc->sc_buswidth; i++) {
    3410           0 :                 link = scsi_get_link(sc->sc_scsibus, i, 0);
    3411           0 :                 if (link == NULL)
    3412             :                         continue;
    3413             :                 /* skip if not a virtual disk */
    3414           0 :                 if (!(link->flags & SDEV_VIRTUAL))
    3415             :                         continue;
    3416             :                 
    3417           0 :                 vol++;
    3418           0 :         }
    3419           0 :         if (vol == 0)
    3420           0 :                 return (0);
    3421             : 
    3422           0 :         sc->sc_sensors = mallocarray(vol, sizeof(struct ksensor),
    3423             :             M_DEVBUF, M_NOWAIT | M_ZERO);
    3424           0 :         if (sc->sc_sensors == NULL)
    3425           0 :                 return (1);
    3426             :         nsensors = vol;
    3427             : 
    3428           0 :         strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
    3429             :             sizeof(sc->sc_sensordev.xname));
    3430             : 
    3431           0 :         for (i = 0, vol= 0; i < sc->sc_buswidth; i++) {
    3432           0 :                 link = scsi_get_link(sc->sc_scsibus, i, 0);
    3433           0 :                 if (link == NULL)
    3434             :                         continue;
    3435             :                 /* skip if not a virtual disk */
    3436           0 :                 if (!(link->flags & SDEV_VIRTUAL))
    3437             :                         continue;
    3438             : 
    3439           0 :                 dev = link->device_softc;
    3440           0 :                 strlcpy(sc->sc_sensors[vol].desc, dev->dv_xname,
    3441             :                     sizeof(sc->sc_sensors[vol].desc));
    3442           0 :                 sc->sc_sensors[vol].type = SENSOR_DRIVE;
    3443           0 :                 sc->sc_sensors[vol].status = SENSOR_S_UNKNOWN;
    3444           0 :                 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[vol]);
    3445             : 
    3446           0 :                 vol++;
    3447           0 :         }
    3448             : 
    3449           0 :         if (sensor_task_register(sc, mpi_refresh_sensors, 10) == NULL)
    3450             :                 goto bad;
    3451             : 
    3452           0 :         sensordev_install(&sc->sc_sensordev);
    3453             : 
    3454           0 :         return (0);
    3455             : 
    3456             : bad:
    3457           0 :         free(sc->sc_sensors, M_DEVBUF, nsensors * sizeof(struct ksensor));
    3458           0 :         return (1);
    3459           0 : }
    3460             : 
    3461             : void
    3462           0 : mpi_refresh_sensors(void *arg)
    3463             : {
    3464             :         int                     i, vol;
    3465             :         struct scsi_link        *link;
    3466           0 :         struct mpi_softc        *sc = arg;
    3467             :         struct mpi_cfg_raid_vol_pg0 *rpg0;
    3468             : 
    3469           0 :         rw_enter_write(&sc->sc_lock);
    3470             : 
    3471           0 :         for (i = 0, vol = 0; i < sc->sc_buswidth; i++) {
    3472           0 :                 link = scsi_get_link(sc->sc_scsibus, i, 0);
    3473           0 :                 if (link == NULL)
    3474             :                         continue;
    3475             :                 /* skip if not a virtual disk */
    3476           0 :                 if (!(link->flags & SDEV_VIRTUAL))
    3477             :                         continue;
    3478             : 
    3479           0 :                 if (mpi_bio_get_pg0_raid(sc, vol))
    3480             :                         continue;
    3481             : 
    3482           0 :                 rpg0 = sc->sc_rpg0;
    3483           0 :                 if (rpg0 == NULL)
    3484             :                         goto done;
    3485             : 
    3486             :                 /* determine status */
    3487           0 :                 switch (rpg0->volume_state) {
    3488             :                 case MPI_CFG_RAID_VOL_0_STATE_OPTIMAL:
    3489           0 :                         sc->sc_sensors[vol].value = SENSOR_DRIVE_ONLINE;
    3490           0 :                         sc->sc_sensors[vol].status = SENSOR_S_OK;
    3491           0 :                         break;
    3492             :                 case MPI_CFG_RAID_VOL_0_STATE_DEGRADED:
    3493           0 :                         sc->sc_sensors[vol].value = SENSOR_DRIVE_PFAIL;
    3494           0 :                         sc->sc_sensors[vol].status = SENSOR_S_WARN;
    3495           0 :                         break;
    3496             :                 case MPI_CFG_RAID_VOL_0_STATE_FAILED:
    3497             :                 case MPI_CFG_RAID_VOL_0_STATE_MISSING:
    3498           0 :                         sc->sc_sensors[vol].value = SENSOR_DRIVE_FAIL;
    3499           0 :                         sc->sc_sensors[vol].status = SENSOR_S_CRIT;
    3500           0 :                         break;
    3501             :                 default:
    3502           0 :                         sc->sc_sensors[vol].value = 0; /* unknown */
    3503           0 :                         sc->sc_sensors[vol].status = SENSOR_S_UNKNOWN;
    3504           0 :                 }
    3505             : 
    3506             :                 /* override status if scrubbing or something */
    3507           0 :                 if (rpg0->volume_status & MPI_CFG_RAID_VOL_0_STATUS_RESYNCING) {
    3508           0 :                         sc->sc_sensors[vol].value = SENSOR_DRIVE_REBUILD;
    3509           0 :                         sc->sc_sensors[vol].status = SENSOR_S_WARN;
    3510           0 :                 }
    3511             : 
    3512           0 :                 vol++;
    3513           0 :         }
    3514             : done:
    3515           0 :         rw_exit_write(&sc->sc_lock);
    3516           0 : }
    3517             : #endif /* SMALL_KERNEL */
    3518             : #endif /* NBIO > 0 */

Generated by: LCOV version 1.13