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

          Line data    Source code
       1             : /*      $OpenBSD: mpath_hds.c,v 1.21 2018/08/09 01:41:48 jmatthew Exp $ */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2011 David Gwynne <dlg@openbsd.org>
       5             :  *
       6             :  * Permission to use, copy, modify, and distribute this software for any
       7             :  * purpose with or without fee is hereby granted, provided that the above
       8             :  * copyright notice and this permission notice appear in all copies.
       9             :  *
      10             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      11             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17             :  */
      18             : 
      19             : /* Hitachi Modular Storage support for mpath(4) */
      20             : 
      21             : #include <sys/param.h>
      22             : #include <sys/systm.h>
      23             : #include <sys/kernel.h>
      24             : #include <sys/malloc.h>
      25             : #include <sys/device.h>
      26             : #include <sys/conf.h>
      27             : #include <sys/queue.h>
      28             : #include <sys/rwlock.h>
      29             : #include <sys/pool.h>
      30             : #include <sys/ioctl.h>
      31             : #include <sys/poll.h>
      32             : #include <sys/selinfo.h>
      33             : 
      34             : #include <scsi/scsi_all.h>
      35             : #include <scsi/scsiconf.h>
      36             : #include <scsi/mpathvar.h>
      37             : 
      38             : #define HDS_INQ_LDEV_OFFSET     44
      39             : #define HDS_INQ_LDEV_LEN        4
      40             : #define HDS_INQ_CTRL_OFFSET     49
      41             : #define HDS_INQ_PORT_OFFSET     50
      42             : #define HDS_INQ_TYPE_OFFSET     128
      43             : #define HDS_INQ_TYPE            0x44463030 /* "DF00" */
      44             : 
      45             : #define HDS_VPD                 0xe0
      46             : 
      47             : struct hds_vpd {
      48             :         struct scsi_vpd_hdr     hdr; /* HDS_VPD */
      49             :         u_int8_t                state;
      50             : #define HDS_VPD_VALID                   0x80
      51             : #define HDS_VPD_PREFERRED               0x40
      52             : 
      53             :         /* followed by lots of unknown stuff */
      54             : };
      55             : 
      56             : #define HDS_SYMMETRIC           0
      57             : #define HDS_ASYMMETRIC          1
      58             : 
      59             : struct hds_softc {
      60             :         struct device           sc_dev;
      61             :         struct mpath_path       sc_path;
      62             :         struct scsi_xshandler   sc_xsh;
      63             :         struct hds_vpd          *sc_vpd;
      64             :         int                     sc_mode;
      65             :         int                     sc_ctrl;
      66             : };
      67             : #define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
      68             : 
      69             : int             hds_match(struct device *, void *, void *);
      70             : void            hds_attach(struct device *, struct device *, void *);
      71             : int             hds_detach(struct device *, int);
      72             : int             hds_activate(struct device *, int);
      73             : 
      74             : struct cfattach hds_ca = {
      75             :         sizeof(struct hds_softc),
      76             :         hds_match,
      77             :         hds_attach,
      78             :         hds_detach,
      79             :         hds_activate
      80             : };
      81             : 
      82             : struct cfdriver hds_cd = {
      83             :         NULL,
      84             :         "hds",
      85             :         DV_DULL
      86             : };
      87             : 
      88             : void            hds_mpath_start(struct scsi_xfer *);
      89             : int             hds_mpath_checksense(struct scsi_xfer *);
      90             : void            hds_mpath_status(struct scsi_link *);
      91             : 
      92             : const struct mpath_ops hds_mpath_ops = {
      93             :         "hds",
      94             :         hds_mpath_checksense,
      95             :         hds_mpath_status
      96             : };
      97             : 
      98             : struct hds_device {
      99             :         char *vendor;
     100             :         char *product;
     101             : };
     102             : 
     103             : int             hds_inquiry(struct scsi_link *, int *);
     104             : int             hds_info(struct hds_softc *);
     105             : 
     106             : void            hds_status(struct scsi_xfer *);
     107             : void            hds_status_done(struct scsi_xfer *);
     108             : 
     109             : struct hds_device hds_devices[] = {
     110             : /*        " vendor "  "     device     " */
     111             : /*        "01234567"  "0123456789012345" */
     112             :         { "HITACHI ", "DF600F          " },
     113             :         { "HITACHI ", "DF600F-CM       " }
     114             : };
     115             : 
     116             : int
     117           0 : hds_match(struct device *parent, void *match, void *aux)
     118             : {
     119           0 :         struct scsi_attach_args *sa = aux;
     120           0 :         struct scsi_inquiry_data *inq = sa->sa_inqbuf;
     121           0 :         struct scsi_link *link = sa->sa_sc_link;
     122             :         struct hds_device *s;
     123           0 :         int i, mode;
     124             : 
     125           0 :         if (mpath_path_probe(sa->sa_sc_link) != 0)
     126           0 :                 return (0);
     127             : 
     128           0 :         for (i = 0; i < nitems(hds_devices); i++) {
     129           0 :                 s = &hds_devices[i];
     130             : 
     131           0 :                 if (bcmp(s->vendor, inq->vendor, strlen(s->vendor)) == 0 &&
     132           0 :                     bcmp(s->product, inq->product, strlen(s->product)) == 0 &&
     133           0 :                     hds_inquiry(link, &mode) == 0)
     134           0 :                         return (8);
     135             :         }
     136             : 
     137           0 :         return (0);
     138           0 : }
     139             : 
     140             : void
     141           0 : hds_attach(struct device *parent, struct device *self, void *aux)
     142             : {
     143           0 :         struct hds_softc *sc = (struct hds_softc *)self;
     144           0 :         struct scsi_attach_args *sa = aux;
     145           0 :         struct scsi_link *link = sa->sa_sc_link;
     146             : 
     147           0 :         printf("\n");
     148             : 
     149             :         /* init link */
     150           0 :         link->device_softc = sc;
     151             : 
     152             :         /* init path */
     153           0 :         scsi_xsh_set(&sc->sc_path.p_xsh, link, hds_mpath_start);
     154           0 :         sc->sc_path.p_link = link;
     155             : 
     156             :         /* init status handler */
     157           0 :         scsi_xsh_set(&sc->sc_xsh, link, hds_status);
     158           0 :         sc->sc_vpd = dma_alloc(sizeof(*sc->sc_vpd), PR_WAITOK);
     159             : 
     160           0 :         if (hds_inquiry(link, &sc->sc_mode) != 0) {
     161           0 :                 printf("%s: unable to query controller mode\n", DEVNAME(sc));
     162           0 :                 return;
     163             :         }
     164             : 
     165           0 :         if (hds_info(sc) != 0) {
     166           0 :                 printf("%s: unable to query path info\n", DEVNAME(sc));
     167           0 :                 return;
     168             :         }
     169             : 
     170           0 :         if (mpath_path_attach(&sc->sc_path,
     171           0 :             (sc->sc_mode == HDS_SYMMETRIC) ? 0 : sc->sc_ctrl,
     172           0 :             &hds_mpath_ops) != 0)
     173           0 :                 printf("%s: unable to attach path\n", DEVNAME(sc));
     174           0 : }
     175             : 
     176             : int
     177           0 : hds_detach(struct device *self, int flags)
     178             : {
     179           0 :         struct hds_softc *sc = (struct hds_softc *)self;
     180             : 
     181           0 :         dma_free(sc->sc_vpd, sizeof(*sc->sc_vpd));
     182             : 
     183           0 :         return (0);
     184             : }
     185             : 
     186             : int
     187           0 : hds_activate(struct device *self, int act)
     188             : {
     189           0 :         struct hds_softc *sc = (struct hds_softc *)self;
     190             :         int rv = 0;
     191             : 
     192           0 :         switch (act) {
     193             :         case DVACT_DEACTIVATE:
     194           0 :                 if (sc->sc_path.p_group != NULL)
     195           0 :                         mpath_path_detach(&sc->sc_path);
     196             :                 break;
     197             :         }
     198           0 :         return (rv);
     199             : }
     200             : 
     201             : void
     202           0 : hds_mpath_start(struct scsi_xfer *xs)
     203             : {
     204           0 :         struct hds_softc *sc = xs->sc_link->device_softc;
     205             : 
     206           0 :         mpath_start(&sc->sc_path, xs);
     207           0 : }
     208             : 
     209             : int
     210           0 : hds_mpath_checksense(struct scsi_xfer *xs)
     211             : {
     212           0 :         return (MPATH_SENSE_DECLINED);
     213             : }
     214             : 
     215             : void
     216           0 : hds_mpath_status(struct scsi_link *link)
     217             : {
     218           0 :         struct hds_softc *sc = link->device_softc;
     219             : 
     220           0 :         if (sc->sc_mode == HDS_SYMMETRIC)
     221           0 :                 mpath_path_status(&sc->sc_path, MPATH_S_ACTIVE);
     222             :         else
     223           0 :                 scsi_xsh_add(&sc->sc_xsh);
     224           0 : }
     225             : 
     226             : void
     227           0 : hds_status(struct scsi_xfer *xs)
     228             : {
     229           0 :         struct scsi_link *link = xs->sc_link;
     230           0 :         struct hds_softc *sc = link->device_softc;
     231             : 
     232           0 :         scsi_init_inquiry(xs, SI_EVPD, HDS_VPD,
     233           0 :             sc->sc_vpd, sizeof(*sc->sc_vpd));
     234             : 
     235           0 :         xs->done = hds_status_done;
     236             : 
     237           0 :         scsi_xs_exec(xs);
     238           0 : }
     239             : 
     240             : void
     241           0 : hds_status_done(struct scsi_xfer *xs)
     242             : {
     243           0 :         struct scsi_link *link = xs->sc_link;
     244           0 :         struct hds_softc *sc = link->device_softc;
     245           0 :         struct hds_vpd *vpd = sc->sc_vpd;
     246             :         int status = MPATH_S_UNKNOWN;
     247             : 
     248           0 :         if (xs->error == XS_NOERROR &&
     249           0 :             _2btol(vpd->hdr.page_length) >= sizeof(vpd->state) &&
     250           0 :             ISSET(vpd->state, HDS_VPD_VALID)) {
     251           0 :                 status = ISSET(vpd->state, HDS_VPD_PREFERRED) ?
     252             :                     MPATH_S_ACTIVE : MPATH_S_PASSIVE;
     253           0 :         }
     254             : 
     255           0 :         scsi_xs_put(xs);
     256             : 
     257           0 :         mpath_path_status(&sc->sc_path, status);
     258           0 : }
     259             : 
     260             : int
     261           0 : hds_inquiry(struct scsi_link *link, int *mode)
     262             : {
     263             :         struct scsi_xfer *xs;
     264             :         u_int8_t *buf;
     265           0 :         size_t len = link->inqdata.additional_length + 5;
     266             :         int error;
     267             : 
     268           0 :         if (len < HDS_INQ_TYPE_OFFSET + sizeof(int))
     269           0 :                 return (ENXIO);
     270             : 
     271           0 :         xs = scsi_xs_get(link, scsi_autoconf);
     272           0 :         if (xs == NULL)
     273           0 :                 return (ENOMEM);
     274             : 
     275           0 :         buf = dma_alloc(len, PR_WAITOK);
     276           0 :         scsi_init_inquiry(xs, 0, 0, buf, len);
     277           0 :         error = scsi_xs_sync(xs);
     278           0 :         scsi_xs_put(xs);
     279           0 :         if (error)
     280             :                 goto done;
     281             : 
     282           0 :         if (buf[128] == '\0')
     283           0 :                 *mode = HDS_ASYMMETRIC;
     284           0 :         else if (_4btol(&buf[HDS_INQ_TYPE_OFFSET]) == HDS_INQ_TYPE)
     285           0 :                 *mode = HDS_SYMMETRIC;
     286             :         else
     287             :                 error = ENXIO;
     288             : 
     289             : done:
     290           0 :         dma_free(buf, len);
     291           0 :         return (error);
     292           0 : }
     293             : 
     294             : int
     295           0 : hds_info(struct hds_softc *sc)
     296             : {
     297           0 :         struct scsi_link *link = sc->sc_path.p_link;
     298             :         struct scsi_xfer *xs;
     299             :         u_int8_t *buf;
     300           0 :         size_t len = link->inqdata.additional_length + 5;
     301           0 :         char ldev[9], ctrl, port;
     302             :         int error;
     303             : 
     304           0 :         xs = scsi_xs_get(link, scsi_autoconf);
     305           0 :         if (xs == NULL)
     306           0 :                 return (ENOMEM);
     307             : 
     308           0 :         buf = dma_alloc(len, PR_WAITOK);
     309           0 :         scsi_init_inquiry(xs, 0, 0, buf, len);
     310           0 :         error = scsi_xs_sync(xs);
     311           0 :         scsi_xs_put(xs);
     312           0 :         if (error)
     313             :                 goto done;
     314             : 
     315           0 :         bzero(ldev, sizeof(ldev));
     316           0 :         scsi_strvis(ldev, &buf[HDS_INQ_LDEV_OFFSET], HDS_INQ_LDEV_LEN);
     317           0 :         ctrl = buf[HDS_INQ_CTRL_OFFSET];
     318           0 :         port = buf[HDS_INQ_PORT_OFFSET];
     319             : 
     320           0 :         if (ctrl >= '0' && ctrl <= '9') {
     321           0 :                 printf("%s: ldev %s, controller %c, port %c, %s\n",
     322           0 :                     DEVNAME(sc), ldev, ctrl, port,
     323           0 :                     sc->sc_mode == HDS_SYMMETRIC ? "symmetric" : "asymmetric");
     324             : 
     325           0 :                 sc->sc_ctrl = ctrl;
     326           0 :         } else
     327             :                 error = ENXIO;
     328             : 
     329             : done:
     330           0 :         dma_free(buf, len);
     331           0 :         return (error);
     332           0 : }

Generated by: LCOV version 1.13