On Wed, 26 Oct 2016 10:26:19 +1100
Jonathan Gray <j...@jsg.id.au> wrote:
> On Tue, Oct 25, 2016 at 05:29:55PM +0900, YASUOKA Masahiko wrote:
>> I'm working on making mfii(4) bio(4) capable.
>> 
>> If you have a machine which has mfii(4), I'd like you to test the diff
>> following.  (It might be risky for production machines for this
>> moment.)
>> 
>> After the diff applied, bioctl(8) against the disk (eg. sd0) starts
>> working and also "sysctl hw.sensors.mfii0" will appear.
>> 
>> Especially if you can configure a hotspare, testing it is very
>> helpful for me since I can't use a hotspare on my test machine.
(snip)
>> +    case BIOC_SATEST:
>> +            cmd = MR_DCMD_SPEAKER_TEST;
>> +            break;
>> +    default:
>> +            return (EINVAL);
>> +    }
>> +
>> +    ccb = scsi_io_get(&sc->sc_iopool, 0);
>> +    rv = mfii_mgmt(sc, ccb, MR_DCMD_PD_SET_STATE, NULL,
>> +        &spkr, sizeof(spkr), flags | SCSI_NOSLEEP);
> 
> Should this be cmd rather than MR_DCMD_PD_SET_STATE?
> The cmd values from the switch statement are not used.

Oops.  Yes, that's right.

>> +int
>> +mfii_ioctl_blink(struct mfii_softc *sc, struct bioc_blink *bb)
(snip)
>> +    case BIOC_SBBLINK:
>> +    case BIOC_SBALARM:
>> +            cmd = MR_DCMD_PD_BLINK;
>> +            break;
>> +    default:
>> +            rv = EINVAL;
>> +            goto done;
>> +    }
>> +
>> +    ccb = scsi_io_get(&sc->sc_iopool, 0);
>> +    rv = mfii_mgmt(sc, ccb, cmd, NULL, NULL, 0, SCSI_NOSLEEP);
>> +    scsi_io_put(&sc->sc_iopool, ccb);

Passing the mbox to mfii_mgmt() was missing.

>> + done:
>> +    free(list, M_TEMP, sizeof(*list));
>> +
>> +    return (ENOTTY);
>> +}
> 
> Shouldn't this be return (rv) to return the EINVAL values?
> With rv set to 0 before the 'done' to return 0 when there is no error?

Yes, that's also right.  Thanks.

Let me update the diff.

Index: sys/dev/pci/mfii.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/mfii.c,v
retrieving revision 1.28
diff -u -p -r1.28 mfii.c
--- sys/dev/pci/mfii.c  24 Oct 2016 05:27:52 -0000      1.28
+++ sys/dev/pci/mfii.c  26 Oct 2016 03:46:15 -0000
@@ -22,9 +22,11 @@
 #include <sys/systm.h>
 #include <sys/malloc.h>
 #include <sys/device.h>
+#include <sys/dkio.h>
 #include <sys/types.h>
 #include <sys/pool.h>
 
+#include <dev/biovar.h>
 #include <dev/pci/pcidevs.h>
 #include <dev/pci/pcivar.h>
 
@@ -212,6 +214,13 @@ struct mfii_iop {
        u_int8_t sge_flag_eol;
 };
 
+struct mfii_cfg {
+       struct mfi_conf         *cfg;
+       struct mfi_array        *cfg_array;
+       struct mfi_ld_cfg       *cfg_ld;
+       struct mfi_hotspare     *cfg_hs;
+};
+
 struct mfii_softc {
        struct device           sc_dev;
        const struct mfii_iop   *sc_iop;
@@ -250,11 +259,15 @@ struct mfii_softc {
        struct scsi_iopool      sc_iopool;
 
        struct mfi_ctrl_info    sc_info;
+
+       struct ksensor          *sc_sensors;
+       struct ksensordev       sc_sensordev;
 };
 
 int            mfii_match(struct device *, void *, void *);
 void           mfii_attach(struct device *, struct device *, void *);
 int            mfii_detach(struct device *, int);
+int            mfii_scsi_ioctl(struct scsi_link *, u_long, caddr_t, int);
 
 struct cfattach mfii_ca = {
        sizeof(struct mfii_softc),
@@ -277,7 +290,7 @@ struct scsi_adapter mfii_switch = {
        scsi_minphys,
        NULL, /* probe */
        NULL, /* unprobe */
-       NULL  /* ioctl */
+       mfii_scsi_ioctl
 };
 
 void           mfii_pd_scsi_cmd(struct scsi_xfer *);
@@ -334,7 +347,26 @@ int                        mfii_scsi_cmd_cdb(struct 
mfii_soft
                            struct scsi_xfer *);
 int                    mfii_pd_scsi_cmd_cdb(struct mfii_softc *,
                            struct scsi_xfer *);
-
+int                    mfii_scsi_ioctl_cache(struct scsi_link *, u_int,
+                           struct dk_cache *);
+#if NBIO > 0
+int                    mfii_ioctl(struct device *, u_long, caddr_t);
+int                    mfii_fill_cfg(struct mfii_softc *, struct mfii_cfg *);
+int                    mfii_ioctl_inq(struct mfii_softc *, struct bioc_inq *);
+int                    mfii_ioctl_vol(struct mfii_softc *, struct bioc_vol *);
+int                    mfii_ioctl_disk(struct mfii_softc *,
+                           struct bioc_disk *);
+int                    mfii_ioctl_alarm(struct mfii_softc *,
+                           struct bioc_alarm *);
+int                    mfii_ioctl_blink(struct mfii_softc *,
+                           struct bioc_blink *);
+int                    mfii_ioctl_setstate(struct mfii_softc *,
+                           struct bioc_setstate *);
+int                    mfii_ioctl_patrol(struct mfii_softc *,
+                           struct bioc_patrol *);
+int                    mfii_create_sensors(struct mfii_softc *);
+void                   mfii_refresh_sensors(void *);
+#endif
 
 #define mfii_fw_state(_sc) mfii_read((_sc), MFI_OSP)
 
@@ -506,7 +538,8 @@ mfii_attach(struct device *parent, struc
        memset(&saa, 0, sizeof(saa));
        saa.saa_sc_link = &sc->sc_link;
 
-       config_found(&sc->sc_dev, &saa, scsiprint);
+       sc->sc_scsibus = (struct scsibus_softc *)
+           config_found(&sc->sc_dev, &saa, scsiprint);
 
        mfii_syspd(sc);
 
@@ -514,6 +547,16 @@ mfii_attach(struct device *parent, struc
        mfii_write(sc, MFI_OSTS, 0xffffffff);
        mfii_write(sc, MFI_OMSK, ~MFII_OSTS_INTR_VALID);
 
+#if NBIO > 0
+       if (bio_register(&sc->sc_dev, mfii_ioctl) != 0)
+               panic("%s: controller registration failed", DEVNAME(sc));
+
+#ifndef SMALL_KERNEL
+       if (mfii_create_sensors(sc) != 0)
+               printf("%s: unable to create sensors\n", DEVNAME(sc));
+#endif
+#endif /* NBIO > 0 */
+
        return;
 free_sgl:
        mfii_dmamem_free(sc, sc->sc_sgl);
@@ -621,6 +664,10 @@ mfii_detach(struct device *self, int fla
        if (sc->sc_ih == NULL)
                return (0);
 
+       if (sc->sc_sensors) {
+               sensordev_deinstall(&sc->sc_sensordev);
+               free(sc->sc_sensors, M_DEVBUF, sc->sc_info.mci_lds_present);
+       }
        pci_intr_disestablish(sc->sc_pc, sc->sc_ih); 
        mfii_dmamem_free(sc, sc->sc_sgl);
        mfii_dmamem_free(sc, sc->sc_requests);
@@ -1065,6 +1112,10 @@ mfii_mgmt(struct mfii_softc *sc, struct 
                hdr->mfh_flags = htole16(MFI_FRAME_DIR_WRITE);
                memcpy(dma_buf, buf, len);
                break;
+       default:
+               ccb->ccb_direction = MFII_DATA_NONE;
+               hdr->mfh_flags = htole16(MFI_FRAME_DIR_NONE);
+               break;
        }
 
        if (mfii_load_mfa(sc, ccb, &dcmd->mdf_sgl,
@@ -1098,6 +1149,12 @@ mfii_mgmt(struct mfii_softc *sc, struct 
                        memcpy(buf, dma_buf, len);
        }
 
+
+       if (hdr->mfh_cmd_status != MFI_STAT_OK)
+               printf("%s cmd=%d failed status=%d\n", __func__, opc,
+                   hdr->mfh_cmd_status);
+
+
 done:
        dma_free(dma_buf, len);
 
@@ -1796,3 +1853,797 @@ destroy:
        return (1);
 }
 
+int
+mfii_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag)
+{
+       switch (cmd) {
+       case DIOCGCACHE:
+       case DIOCSCACHE:
+               return mfii_scsi_ioctl_cache(link, cmd,
+                   (struct dk_cache *)addr);
+               break;
+       default:
+#if NBIO > 0
+               return mfii_ioctl(link->adapter_softc, cmd, addr);
+#endif
+               break;
+       }
+       return (ENOTTY);
+}
+
+int
+mfii_scsi_ioctl_cache(struct scsi_link *link, u_int cmd, struct dk_cache *dc)
+{
+       struct mfii_softc *sc = (struct mfii_softc *)link->adapter_softc;
+       struct mfi_ld_prop ldp;
+       uint8_t mbox[MFI_MBOX_SIZE];
+       struct mfii_ccb *ccb;
+       int rv, wrenable, rdenable;
+
+       memset(mbox, 0, sizeof(mbox));
+       *((uint16_t *)&mbox[0]) = htole16(link->target);
+       ccb = scsi_io_get(&sc->sc_iopool, 0);
+       rv = mfii_mgmt(sc, ccb, MR_DCMD_LD_GET_PROPERTIES, mbox,
+           &ldp, sizeof(ldp), SCSI_DATA_IN|SCSI_NOSLEEP);
+       scsi_io_put(&sc->sc_iopool, ccb);
+       if (rv != 0)
+               return (rv);
+
+       if (letoh16(sc->sc_info.mci_memory_size) > 0) {
+               wrenable = ISSET(ldp.mlp_cur_cache_policy,
+                   MR_LD_CACHE_ALLOW_WRITE_CACHE)? 1 : 0;
+               rdenable = ISSET(ldp.mlp_cur_cache_policy,
+                   MR_LD_CACHE_ALLOW_READ_CACHE)? 1 : 0;
+       } else {
+               wrenable = ISSET(ldp.mlp_diskcache_policy,
+                   MR_LD_DISK_CACHE_ENABLE)? 1 : 0;
+               rdenable = 0;
+       }
+
+       if (cmd == DIOCGCACHE) {
+               dc->wrcache = wrenable;
+               dc->rdcache = rdenable;
+               return (0);
+       }
+       if (((dc->wrcache) ? 1 : 0) == wrenable &&
+           ((dc->rdcache) ? 1 : 0) == rdenable)
+               return (0);
+
+       mbox[0] = ldp.mlp_ld.mld_target;
+       mbox[1] = ldp.mlp_ld.mld_res;
+       *(uint16_t *)&mbox[2] = ldp.mlp_ld.mld_seq;
+       if (letoh16(sc->sc_info.mci_memory_size) > 0) {
+               if (dc->rdcache)
+                       SET(ldp.mlp_cur_cache_policy,
+                           MR_LD_CACHE_ALLOW_READ_CACHE);
+               else
+                       CLR(ldp.mlp_cur_cache_policy,
+                           MR_LD_CACHE_ALLOW_READ_CACHE);
+               if (dc->wrcache)
+                       SET(ldp.mlp_cur_cache_policy,
+                           MR_LD_CACHE_ALLOW_WRITE_CACHE);
+               else
+                       CLR(ldp.mlp_cur_cache_policy,
+                           MR_LD_CACHE_ALLOW_WRITE_CACHE);
+       } else {
+               if (dc->rdcache)
+                       return (EOPNOTSUPP);
+               if (dc->wrcache)
+                       ldp.mlp_diskcache_policy = MR_LD_DISK_CACHE_ENABLE;
+               else
+                       ldp.mlp_diskcache_policy = MR_LD_DISK_CACHE_DISABLE;
+       }
+
+       ccb = scsi_io_get(&sc->sc_iopool, 0);
+       rv = mfii_mgmt(sc, ccb, MR_DCMD_LD_SET_PROPERTIES, mbox,
+           &ldp, sizeof(ldp), SCSI_DATA_OUT|SCSI_NOSLEEP);
+       scsi_io_put(&sc->sc_iopool, ccb);
+
+       return (rv);
+}
+
+#if NBIO > 0
+int
+mfii_ioctl(struct device *dev, u_long cmd, caddr_t addr)
+{
+       struct mfii_softc *sc = (struct mfii_softc *)dev;
+       int rv = ENOTTY;
+
+       switch (cmd) {
+       case BIOCINQ:
+               rv = mfii_ioctl_inq(sc, (struct bioc_inq *)addr);
+               break;
+       case BIOCVOL:
+               rv = mfii_ioctl_vol(sc, (struct bioc_vol *)addr);
+               break;
+       case BIOCDISK:
+               rv = mfii_ioctl_disk(sc, (struct bioc_disk *)addr);
+               break;
+       case BIOCALARM:
+               rv = mfii_ioctl_alarm(sc, (struct bioc_alarm *)addr);
+               break;
+       case BIOCBLINK:
+               rv = mfii_ioctl_blink(sc, (struct bioc_blink *)addr);
+               break;
+       case BIOCSETSTATE:
+               rv = mfii_ioctl_setstate(sc, (struct bioc_setstate *)addr);
+               break;
+       case BIOCPATROL:
+               rv = mfii_ioctl_patrol(sc, (struct bioc_patrol *)addr);
+               break;
+       }
+
+       return (rv);
+}
+
+int
+mfii_fill_cfg(struct mfii_softc *sc, struct mfii_cfg *cfg)
+{
+       int rv, mfc_size;
+       struct mfi_conf *mfc;
+       struct mfii_ccb *ccb;
+
+       mfc_size = sizeof(*mfc);
+ again:
+       mfc = malloc(mfc_size, M_TEMP, M_WAITOK | M_ZERO);
+       ccb = scsi_io_get(&sc->sc_iopool, 0);
+       rv = mfii_mgmt(sc, ccb, MR_DCMD_CONF_GET, NULL,
+           mfc, mfc_size, SCSI_DATA_IN|SCSI_NOSLEEP);
+       scsi_io_put(&sc->sc_iopool, ccb);
+       if (rv == 0) {
+               mfc->mfc_size = letoh32(mfc->mfc_size);
+               mfc->mfc_no_array = letoh16(mfc->mfc_no_array);
+               mfc->mfc_array_size = letoh16(mfc->mfc_array_size);
+               mfc->mfc_no_ld = letoh16(mfc->mfc_no_ld);
+               mfc->mfc_ld_size = letoh16(mfc->mfc_ld_size);
+               mfc->mfc_no_hs = letoh16(mfc->mfc_no_hs);
+               mfc->mfc_hs_size = letoh16(mfc->mfc_hs_size);
+
+               if (mfc_size < mfc->mfc_size) {
+                       int tmp = mfc->mfc_size;
+                       free(mfc, M_TEMP, mfc_size);
+                       mfc_size = tmp;
+                       goto again;
+               }
+               /* remember allocated size for free() */
+               mfc->mfc_size = mfc_size;
+
+               cfg->cfg = mfc;
+               cfg->cfg_array = (struct mfi_array *)((caddr_t)mfc +
+                   offsetof(struct mfi_conf, mfc_array));
+               cfg->cfg_ld = (struct mfi_ld_cfg *)((caddr_t)cfg->cfg_array +
+                   mfc->mfc_array_size * mfc->mfc_no_array);
+               cfg->cfg_hs = (struct mfi_hotspare *)((caddr_t)cfg->cfg_ld +
+                   mfc->mfc_ld_size * mfc->mfc_no_ld);
+
+               return (0);
+       }
+
+       free(mfc, M_TEMP, mfc_size);
+       return (rv);
+}
+
+int
+mfii_ioctl_inq(struct mfii_softc *sc, struct bioc_inq *bi)
+{
+       int rv;
+       struct mfii_cfg cfg = { .cfg = NULL };
+
+       rv = mfii_fill_cfg(sc, &cfg);
+       if (rv != 0)
+               return (rv);
+
+       bi->bi_novol = cfg.cfg->mfc_no_ld + cfg.cfg->mfc_no_hs;
+       bi->bi_nodisk = letoh16(sc->sc_info.mci_pd_disks_present);
+       strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev));
+
+       if (cfg.cfg != NULL)
+               free(cfg.cfg, M_TEMP, cfg.cfg->mfc_size);
+
+       return (0);
+}
+
+int
+mfii_ioctl_vol(struct mfii_softc *sc, struct bioc_vol *bv)
+{
+       int rv;
+       struct mfii_cfg cfg = { .cfg = NULL };
+       struct mfi_ld_cfg *ld;
+       struct mfi_ld_list *list = NULL;
+       struct scsi_link *link;
+       struct mfii_ccb *ccb;
+       uint8_t mbox[MFI_MBOX_SIZE];
+
+       if ((link = scsi_get_link(sc->sc_scsibus, bv->bv_volid, 0)) != NULL &&
+           link->device_softc != NULL) {
+               struct device *dev = link->device_softc;
+               strlcpy(bv->bv_dev, dev->dv_xname, sizeof(bv->bv_dev));
+       }
+       rv = mfii_fill_cfg(sc, &cfg);
+       if (rv != 0)
+               goto done;
+
+       if (bv->bv_volid >= cfg.cfg->mfc_no_ld) {
+               int hsid;
+               struct mfi_pd_details *pd;
+
+               hsid = bv->bv_volid - cfg.cfg->mfc_no_ld;
+               if (hsid >= cfg.cfg->mfc_no_hs)
+                       return (EINVAL);
+
+               pd = malloc(sizeof(*pd), M_TEMP, M_WAITOK | M_ZERO);
+               ccb = scsi_io_get(&sc->sc_iopool, 0);
+               memset(mbox, 0, sizeof(mbox));
+               *((uint16_t *)&mbox[0]) = cfg.cfg_hs[hsid].mhs_pd.mfp_id;
+               rv = mfii_mgmt(sc, ccb, MR_DCMD_PD_GET_INFO, mbox,
+                   pd, sizeof(*pd), SCSI_DATA_IN|SCSI_NOSLEEP);
+               scsi_io_put(&sc->sc_iopool, ccb);
+               if (rv == 0) {
+                       bv->bv_status = BIOC_SVONLINE;
+                       bv->bv_size = letoh64(pd->mpd_size) * 512;
+                       bv->bv_level = -1;
+                       bv->bv_nodisk = 1;
+               }
+               free(pd, M_TEMP, sizeof(*pd));
+
+               goto done;
+       }
+
+       list = malloc(sizeof(*list), M_TEMP, M_WAITOK | M_ZERO);
+       ccb = scsi_io_get(&sc->sc_iopool, 0);
+       rv = mfii_mgmt(sc, ccb, MR_DCMD_LD_GET_LIST, NULL,
+           list, sizeof(*list), SCSI_DATA_IN|SCSI_NOSLEEP);
+       scsi_io_put(&sc->sc_iopool, ccb);
+       if (rv != 0)
+               goto done;
+
+       if (bv->bv_volid >= letoh32(list->mll_no_ld)) {
+               rv = EINVAL;
+               goto done;
+       }
+
+       switch (list->mll_list[bv->bv_volid].mll_state) {
+       case MFI_LD_OFFLINE:
+               bv->bv_status = BIOC_SVOFFLINE;
+               break;
+       case MFI_LD_PART_DEGRADED:
+       case MFI_LD_DEGRADED:
+               bv->bv_status = BIOC_SVDEGRADED;
+               break;
+       case MFI_LD_ONLINE:
+               bv->bv_status = BIOC_SVONLINE;
+               break;
+       default:
+               bv->bv_status = BIOC_SVINVALID;
+               break;
+       }
+       bv->bv_size = letoh64(list->mll_list[bv->bv_volid].mll_size) * 512;
+
+       ld = cfg.cfg_ld + bv->bv_volid;
+       bv->bv_cache =
+           (ld->mlc_prop.mlp_cur_cache_policy & MR_LD_CACHE_WRITE_BACK)
+           ? BIOC_CVWRITEBACK : BIOC_CVWRITETHROUGH;
+
+       switch (ld->mlc_parm.mpa_pri_raid) {
+       case MFI_DDF_PRL_RAID0:
+               bv->bv_level = 0;
+               break;
+       case MFI_DDF_PRL_RAID1:
+       case MFI_DDF_PRL_RAID1E:
+               bv->bv_level = 1;
+               break;
+       case MFI_DDF_PRL_RAID3:
+               bv->bv_level = 3;
+               break;
+       case MFI_DDF_PRL_RAID4:
+               bv->bv_level = 4;
+               break;
+       case MFI_DDF_PRL_RAID5:
+       case MFI_DDF_PRL_RAID5E:
+       case MFI_DDF_PRL_RAID5EE:
+               bv->bv_level = 5;
+               break;
+       case MFI_DDF_PRL_RAID6:
+               bv->bv_level = 6;
+               break;
+       case MFI_DDF_PRL_JBOD:
+       case MFI_DDF_PRL_CONCAT:
+       default:
+               bv->bv_level = 0;
+               break;
+       }
+       bv->bv_nodisk =
+           ld->mlc_parm.mpa_no_drv_per_span * ld->mlc_parm.mpa_span_depth;
+ done:
+       free(list, M_TEMP, sizeof(*list));
+       if (cfg.cfg != NULL)
+               free(cfg.cfg, M_TEMP, cfg.cfg->mfc_size);
+
+       return (rv);
+}
+
+int
+mfii_ioctl_disk(struct mfii_softc *sc, struct bioc_disk *bd)
+{
+       int rv, spanidx, diskidx, arrayidx, pdidx;
+       struct mfii_cfg cfg = { .cfg = NULL };
+       struct mfi_ld_cfg *ld;
+       struct mfii_ccb *ccb;
+       struct scsi_inquiry_data *inq;
+       struct mfi_pd_details *pd_det = NULL;
+       uint8_t mbox[MFI_MBOX_SIZE];
+
+       rv = mfii_fill_cfg(sc, &cfg);
+       if (rv != 0)
+               goto done;
+
+       if (bd->bd_volid >= cfg.cfg->mfc_no_ld) {
+               int hsid = bd->bd_volid - cfg.cfg->mfc_no_ld;
+               if (hsid >= cfg.cfg->mfc_no_hs) {
+                       rv = EINVAL;
+                       goto done;
+               }
+               pdidx = letoh16(cfg.cfg_hs[hsid].mhs_pd.mfp_id);
+       } else {
+               ld = cfg.cfg_ld + bd->bd_volid;
+               if (ld->mlc_parm.mpa_no_drv_per_span == 0) {
+                       /* avoid dividing by 0 */
+                       rv = EIO;
+                       goto done;
+               }
+               spanidx = bd->bd_diskid / ld->mlc_parm.mpa_no_drv_per_span;
+               diskidx = bd->bd_diskid % ld->mlc_parm.mpa_no_drv_per_span;
+               if (spanidx < 0 || MFI_MAX_SPAN <= spanidx) {
+                       rv = EINVAL;
+                       goto done;
+               }
+               arrayidx = letoh16(ld->mlc_span[spanidx].mls_index);
+               if (arrayidx < 0 || cfg.cfg->mfc_no_array <= arrayidx) {
+                       rv = EINVAL;
+                       goto done;
+               }
+               pdidx = letoh16(
+                   cfg.cfg->mfc_array[arrayidx].pd[diskidx].mar_pd.mfp_id);
+       }
+
+       memset(mbox, 0, sizeof(mbox));
+       *((uint16_t *)&mbox[0]) = htole16(pdidx);
+
+       pd_det = malloc(sizeof(*pd_det), M_TEMP, M_WAITOK | M_ZERO);
+       ccb = scsi_io_get(&sc->sc_iopool, 0);
+       rv = mfii_mgmt(sc, ccb, MR_DCMD_PD_GET_INFO, mbox,
+           pd_det, sizeof(*pd_det), SCSI_DATA_IN|SCSI_NOSLEEP);
+       scsi_io_put(&sc->sc_iopool, ccb);
+       if (rv != 0)
+               goto done;
+
+       bd->bd_channel = pd_det->mpd_enc_idx;
+       bd->bd_target = pd_det->mpd_enc_slot;
+
+       switch (letoh16(pd_det->mpd_fw_state)) {
+       case MFI_PD_UNCONFIG_GOOD:
+               bd->bd_status = BIOC_SDUNUSED;
+               break;
+       case MFI_PD_UNCONFIG_BAD:
+               bd->bd_status = BIOC_SDINVALID;
+               break;
+       case MFI_PD_HOTSPARE:
+               bd->bd_status = BIOC_SDHOTSPARE;
+               break;
+       case MFI_PD_OFFLINE:
+               bd->bd_status = BIOC_SDOFFLINE;
+               break;
+       case MFI_PD_FAILED:
+               bd->bd_status = BIOC_SDFAILED;
+               break;
+       case MFI_PD_REBUILD:
+               bd->bd_status = BIOC_SDREBUILD;
+               break;
+       case MFI_PD_ONLINE:
+               bd->bd_status = BIOC_SDONLINE;
+               break;
+       case MFI_PD_COPYBACK:
+       case MFI_PD_SYSTEM:
+               bd->bd_status = BIOC_SDINVALID;
+               break;
+       }
+       bd->bd_size = letoh64(pd_det->mpd_size) * 512;
+
+       inq = (struct scsi_inquiry_data *)pd_det->mpd_inq_data;
+
+       memset(bd->bd_vendor, 0, sizeof(bd->bd_vendor));
+       memcpy(bd->bd_vendor, inq->vendor,
+           MIN(sizeof(bd->bd_vendor) - 1, sizeof(inq->vendor)));
+
+       rv = 0;
+ done:
+       free(pd_det, M_TEMP, sizeof(*pd_det));
+       if (cfg.cfg != NULL)
+               free(cfg.cfg, M_TEMP, cfg.cfg->mfc_size);
+
+       return (rv);
+}
+
+int
+mfii_ioctl_setstate(struct mfii_softc *sc, struct bioc_setstate *bs)
+{
+       int rv, i;
+       struct mfii_ccb *ccb;
+       struct mfi_pd_list *list = NULL;
+       struct mfi_pd_details *pd = NULL;
+       uint8_t mbox[MFI_MBOX_SIZE];
+
+       list = malloc(sizeof(*list), M_TEMP, M_WAITOK | M_ZERO);
+       pd = malloc(sizeof(*pd), M_TEMP, M_WAITOK | M_ZERO);
+
+       ccb = scsi_io_get(&sc->sc_iopool, 0);
+       rv = mfii_mgmt(sc, ccb, MR_DCMD_PD_GET_LIST, NULL,
+           list, sizeof(*list), SCSI_DATA_IN | SCSI_NOSLEEP);
+       scsi_io_put(&sc->sc_iopool, ccb);
+       if (rv != 0)
+               goto done;
+
+       for (i = 0; i < letoh16(list->mpl_no_pd); i++)
+               if (list->mpl_address[i].mpa_enc_index == bs->bs_channel &&
+                   list->mpl_address[i].mpa_enc_slot == bs->bs_target)
+                       break;
+       if (i >= letoh16(list->mpl_no_pd)) {
+               rv = EINVAL;
+               goto done;
+       }
+
+       memset(mbox, 0, sizeof(mbox));
+       *((uint16_t *)&mbox[0]) = list->mpl_address[i].mpa_pd_id;
+       ccb = scsi_io_get(&sc->sc_iopool, 0);
+       rv = mfii_mgmt(sc, ccb, MR_DCMD_PD_GET_INFO, mbox,
+           pd, sizeof(*pd), SCSI_DATA_IN | SCSI_NOSLEEP);
+       scsi_io_put(&sc->sc_iopool, ccb);
+       if (rv != 0)
+               goto done;
+
+       memset(mbox, 0, sizeof(mbox));
+       *((uint16_t *)&mbox[0]) = pd->mpd_pd.mfp_id;
+       *((uint16_t *)&mbox[2]) = pd->mpd_pd.mfp_seq;
+
+       switch (bs->bs_status) {
+       case BIOC_SSONLINE:
+               *((uint16_t *)&mbox[4]) = htole16(MFI_PD_ONLINE);
+               break;
+       case BIOC_SSOFFLINE:
+               *((uint16_t *)&mbox[4]) = htole16(MFI_PD_OFFLINE);
+               break;
+       case BIOC_SSHOTSPARE:
+               *((uint16_t *)&mbox[4]) = htole16(MFI_PD_HOTSPARE);
+               break;
+       case BIOC_SSREBUILD:
+               *((uint16_t *)&mbox[4]) = htole16(MFI_PD_REBUILD);
+               break;
+       default:
+               rv = EINVAL;
+               goto done;
+       }
+
+       ccb = scsi_io_get(&sc->sc_iopool, 0);
+       rv = mfii_mgmt(sc, ccb, MR_DCMD_PD_SET_STATE, mbox,
+           NULL, 0, SCSI_NOSLEEP);
+       scsi_io_put(&sc->sc_iopool, ccb);
+
+ done:
+       free(list, M_TEMP, sizeof(*list));
+       free(pd, M_TEMP, sizeof(*pd));
+
+       return (rv);
+}
+
+int
+mfii_ioctl_alarm(struct mfii_softc *sc, struct bioc_alarm *ba)
+{
+       struct mfii_ccb *ccb;
+       u_char spkr;
+       int rv, cmd, flags = 0;
+
+       if (!ISSET(letoh32(sc->sc_info.mci_hw_present), MFI_INFO_HW_ALARM))
+               return (ENXIO);
+
+       switch (ba->ba_status) {
+       case BIOC_SADISABLE:
+               cmd = MR_DCMD_SPEAKER_DISABLE;
+               break;
+       case BIOC_SAENABLE:
+               cmd = MR_DCMD_SPEAKER_ENABLE;
+               break;
+       case BIOC_SASILENCE:
+               cmd = MR_DCMD_SPEAKER_SILENCE;
+               break;
+       case BIOC_GASTATUS:
+               cmd = MR_DCMD_SPEAKER_GET;
+               flags = SCSI_DATA_IN;
+               break;
+       case BIOC_SATEST:
+               cmd = MR_DCMD_SPEAKER_TEST;
+               break;
+       default:
+               return (EINVAL);
+       }
+
+       ccb = scsi_io_get(&sc->sc_iopool, 0);
+       rv = mfii_mgmt(sc, ccb, cmd, NULL,
+           &spkr, sizeof(spkr), flags | SCSI_NOSLEEP);
+       scsi_io_put(&sc->sc_iopool, ccb);
+       if (rv != 0)
+               return (rv);
+
+       ba->ba_status = (ba->ba_status == BIOC_GASTATUS)? spkr : 0;
+
+       return (rv);
+}
+
+int
+mfii_ioctl_blink(struct mfii_softc *sc, struct bioc_blink *bb)
+{
+       struct mfi_pd_list *list = NULL;
+       struct mfii_ccb *ccb;
+       uint8_t mbox[MFI_MBOX_SIZE];
+       int rv, i, cmd;
+//mfi_ioctl_blink
+       list = malloc(sizeof(*list), M_TEMP, M_WAITOK | M_ZERO);
+
+       ccb = scsi_io_get(&sc->sc_iopool, 0);
+       rv = mfii_mgmt(sc, ccb, MR_DCMD_PD_GET_LIST, NULL,
+           list, sizeof(*list), SCSI_DATA_IN | SCSI_NOSLEEP);
+       scsi_io_put(&sc->sc_iopool, ccb);
+       if (rv != 0)
+               goto done;
+
+       for (i = 0; i < letoh16(list->mpl_no_pd); i++)
+               if (list->mpl_address[i].mpa_enc_index == bb->bb_channel &&
+                   list->mpl_address[i].mpa_enc_slot == bb->bb_target)
+                       break;
+       if (i >= letoh16(list->mpl_no_pd)) {
+               rv = EINVAL;
+               goto done;
+       }
+
+       memset(mbox, 0, sizeof(mbox));
+       *((uint16_t *)&mbox[0]) = list->mpl_address[i].mpa_pd_id;
+
+       switch (bb->bb_status) {
+       case BIOC_SBUNBLINK:
+               cmd = MR_DCMD_PD_UNBLINK;
+               break;
+       case BIOC_SBBLINK:
+       case BIOC_SBALARM:
+               cmd = MR_DCMD_PD_BLINK;
+               break;
+       default:
+               rv = EINVAL;
+               goto done;
+       }
+
+       ccb = scsi_io_get(&sc->sc_iopool, 0);
+       rv = mfii_mgmt(sc, ccb, cmd, mbox, NULL, 0, SCSI_NOSLEEP);
+       scsi_io_put(&sc->sc_iopool, ccb);
+
+ done:
+       free(list, M_TEMP, sizeof(*list));
+
+       return (rv);
+}
+
+int
+mfii_ioctl_patrol(struct mfii_softc *sc, struct bioc_patrol *bp)
+{
+       int rv = EINVAL, cmd;
+       struct mfii_ccb *ccb;
+       struct mfi_pr_properties prop;
+       struct mfi_pr_status status;
+       uint32_t time;
+
+       switch (bp->bp_opcode) {
+       case BIOC_SPSTOP:
+       case BIOC_SPSTART:
+               cmd = (bp->bp_opcode == BIOC_SPSTART)
+                   ? MR_DCMD_PR_START : MR_DCMD_PR_STOP;
+               ccb = scsi_io_get(&sc->sc_iopool, 0);
+               rv = mfii_mgmt(sc, ccb, cmd, NULL, NULL, 0, SCSI_NOSLEEP);
+               scsi_io_put(&sc->sc_iopool, ccb);
+               break;
+
+       case BIOC_GPSTATUS:
+               ccb = scsi_io_get(&sc->sc_iopool, 0);
+               rv = mfii_mgmt(sc, ccb, MR_DCMD_PR_GET_PROPERTIES, NULL,
+                   &prop, sizeof(prop), SCSI_DATA_IN | SCSI_NOSLEEP);
+               scsi_io_put(&sc->sc_iopool, ccb);
+               if (rv != 0)
+                       break;
+               ccb = scsi_io_get(&sc->sc_iopool, 0);
+               rv = mfii_mgmt(sc, ccb, MR_DCMD_PR_GET_STATUS, NULL,
+                   &status, sizeof(status), SCSI_DATA_IN | SCSI_NOSLEEP);
+               scsi_io_put(&sc->sc_iopool, ccb);
+               if (rv != 0)
+                       break;
+               ccb = scsi_io_get(&sc->sc_iopool, 0);
+               rv = mfii_mgmt(sc, ccb, MR_DCMD_TIME_SECS_GET, NULL,
+                   &time, sizeof(time), SCSI_DATA_IN | SCSI_NOSLEEP);
+               scsi_io_put(&sc->sc_iopool, ccb);
+               if (rv != 0)
+                       break;
+               time = letoh32(time);
+
+               switch (prop.op_mode) {
+               case MFI_PR_OPMODE_AUTO:
+                       bp->bp_mode = BIOC_SPMAUTO;
+                       bp->bp_autoival = letoh32(prop.exec_freq);
+                       bp->bp_autonext = letoh32(prop.next_exec);
+                       bp->bp_autonow = time;
+                       break;
+               case MFI_PR_OPMODE_MANUAL:
+                       bp->bp_mode = BIOC_SPMMANUAL;
+                       break;
+               case MFI_PR_OPMODE_DISABLED:
+                       bp->bp_mode = BIOC_SPMDISABLED;
+                       break;
+               }
+
+               switch (status.state) {
+               case MFI_PR_STATE_STOPPED:
+                       bp->bp_status = BIOC_SPSSTOPPED;
+                       break;
+               case MFI_PR_STATE_READY:
+                       bp->bp_status = BIOC_SPSREADY;
+                       break;
+               case MFI_PR_STATE_ACTIVE:
+                       bp->bp_status = BIOC_SPSACTIVE;
+                       break;
+               case MFI_PR_STATE_ABORTED:
+                       bp->bp_status = BIOC_SPSABORTED;
+                       break;
+               }
+               break;
+
+       case BIOC_SPDISABLE:
+       case BIOC_SPMANUAL:
+               ccb = scsi_io_get(&sc->sc_iopool, 0);
+               rv = mfii_mgmt(sc, ccb, MR_DCMD_PR_GET_PROPERTIES, NULL,
+                   &prop, sizeof(prop), SCSI_DATA_IN | SCSI_NOSLEEP);
+               scsi_io_put(&sc->sc_iopool, ccb);
+               if (rv != 0)
+                       break;
+               prop.op_mode = (bp->bp_opcode == BIOC_SPDISABLE)
+                   ? MFI_PR_OPMODE_DISABLED : MFI_PR_OPMODE_MANUAL;
+               ccb = scsi_io_get(&sc->sc_iopool, 0);
+               rv = mfii_mgmt(sc, ccb, MR_DCMD_PR_SET_PROPERTIES, NULL,
+                   &prop, sizeof(prop), SCSI_DATA_OUT | SCSI_NOSLEEP);
+               scsi_io_put(&sc->sc_iopool, ccb);
+               break;
+
+       case BIOC_SPAUTO:
+               ccb = scsi_io_get(&sc->sc_iopool, 0);
+               rv = mfii_mgmt(sc, ccb, MR_DCMD_PR_GET_PROPERTIES, NULL,
+                   &prop, sizeof(prop), SCSI_DATA_IN | SCSI_NOSLEEP);
+               scsi_io_put(&sc->sc_iopool, ccb);
+               if (rv != 0)
+                       break;
+               prop.op_mode = MFI_PR_OPMODE_AUTO;
+
+               ccb = scsi_io_get(&sc->sc_iopool, 0);
+               rv = mfii_mgmt(sc, ccb, MR_DCMD_TIME_SECS_GET, NULL,
+                   &time, sizeof(time), SCSI_DATA_IN | SCSI_NOSLEEP);
+               scsi_io_put(&sc->sc_iopool, ccb);
+               if (rv != 0)
+                       break;
+               time = letoh32(time);
+               if (bp->bp_autoival != 0) {
+                       if (bp->bp_autoival == -1)
+                               prop.exec_freq = htole32(0xffffffffUL);
+                       else if (bp->bp_autoival > 0)
+                               prop.exec_freq = htole32(bp->bp_autoival);
+                       else {
+                               rv = EINVAL;
+                               break;
+                       }
+               }
+               if (bp->bp_autonext != 0) {
+                       if (bp->bp_autonext > 0)
+                               prop.next_exec =
+                                   htole32(time + bp->bp_autonext);
+                       else {
+                               rv = EINVAL;
+                               break;
+                       }
+               }
+               ccb = scsi_io_get(&sc->sc_iopool, 0);
+               rv = mfii_mgmt(sc, ccb, MR_DCMD_PR_SET_PROPERTIES, NULL,
+                   &prop, sizeof(prop), SCSI_DATA_OUT | SCSI_NOSLEEP);
+               scsi_io_put(&sc->sc_iopool, ccb);
+               break;
+       }
+
+       return (rv);
+}
+
+#ifndef SMALL_KERNEL
+int
+mfii_create_sensors(struct mfii_softc *sc)
+{
+       int i, no_ld;
+       struct device *dev;
+       struct scsi_link *link;
+
+       no_ld = letoh16(sc->sc_info.mci_lds_present);
+
+       strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
+           sizeof(sc->sc_sensordev.xname));
+
+       sc->sc_sensors = mallocarray(no_ld, sizeof(struct ksensor),
+           M_DEVBUF, M_NOWAIT | M_ZERO);
+       if (sc->sc_sensors == NULL)
+               return (-1);
+
+       for (i = 0; i < no_ld; i++) {
+               if ((link = scsi_get_link(sc->sc_scsibus, i, 0)) == NULL ||
+                   link->device_softc == NULL)
+                       goto err;
+
+               dev = link->device_softc;
+               sc->sc_sensors[i].type = SENSOR_DRIVE;
+               sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
+               strlcpy(sc->sc_sensors[i].desc, dev->dv_xname,
+                   sizeof(sc->sc_sensors[i].desc));
+               sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
+       }
+
+       if (sensor_task_register(sc, mfii_refresh_sensors, 10) == NULL)
+               goto err;
+
+       sensordev_install(&sc->sc_sensordev);
+
+       return (0);
+ err:
+       free(sc->sc_sensors, M_DEVBUF, no_ld);
+
+       return (-1);
+}
+
+void
+mfii_refresh_sensors(void *arg)
+{
+       int i, rv;
+       struct mfi_ld_list *list = NULL;
+       struct mfii_softc *sc = arg;
+       struct mfii_ccb *ccb;
+
+       list = malloc(sizeof(*list), M_TEMP, M_WAITOK | M_ZERO);
+       ccb = scsi_io_get(&sc->sc_iopool, 0);
+       rv = mfii_mgmt(sc, ccb, MR_DCMD_LD_GET_LIST, NULL,
+           list, sizeof(*list), SCSI_DATA_IN|SCSI_NOSLEEP);
+       scsi_io_put(&sc->sc_iopool, ccb);
+
+       if (rv == 0) {
+               for (i = 0; i < letoh16(sc->sc_info.mci_lds_present); i++) {
+                       switch (list->mll_list[i].mll_state) {
+                       case MFI_LD_OFFLINE:
+                               sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL;
+                               sc->sc_sensors[i].status = SENSOR_S_CRIT;
+                               break;
+                       case MFI_LD_PART_DEGRADED:
+                       case MFI_LD_DEGRADED:
+                               sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL;
+                               sc->sc_sensors[i].status = SENSOR_S_WARN;
+                               break;
+                       case MFI_LD_ONLINE:
+                               sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE;
+                               sc->sc_sensors[i].status = SENSOR_S_OK;
+                               break;
+                       default:
+                               sc->sc_sensors[i].value = 0; /* unknown */
+                               sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
+                               break;
+                       }
+               }
+       }
+
+       free(list, M_TEMP, sizeof(*list));
+}
+#endif
+#endif

Reply via email to