LCOV - code coverage report
Current view: top level - scsi - mpath_rdac.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 115 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_rdac.c,v 1.23 2015/03/14 03:38:52 jsg Exp $ */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2010 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             : /* Redundant Disk Array Controller 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             : struct rdac_common_mode_page {
      39             :         u_int8_t        controller_serial[16];
      40             :         u_int8_t        alt_controller_serial[16];
      41             :         u_int8_t        mode[2];
      42             :         u_int8_t        alt_mode[2];
      43             :         u_int8_t        timeout;
      44             :         u_int8_t        options;
      45             : };
      46             : 
      47             : /*
      48             :  * RDAC VPD pages
      49             :  */
      50             : #define RDAC_VPD_HDWVER         0xc0    /* Hardware Version */
      51             : #define RDAC_VPD_SERNUM         0xc1    /* Serial Numbers */
      52             : #define RDAC_VPD_SFWVER         0xc2
      53             : #define RDAC_VPD_FEAPAR         0xc3    /* Feature Parameters */
      54             : #define RDAC_VPD_SUBSYS         0xc4
      55             : #define RDAC_VPD_HSTINT         0xc5
      56             : #define RDAC_VPD_DGM            0xc6
      57             : #define RDAC_VPD_HSTINT2        0xc7
      58             : #define RDAC_VPD_EXTDEVID       0xc8
      59             : #define RDAC_VPD_VOLACCESSCTL   0xc9
      60             : 
      61             : struct rdac_vpd_hdwver {
      62             :         struct scsi_vpd_hdr     hdr; /* RDAC_VPD_HDWVER */
      63             :         u_int8_t                pg_id[4];
      64             : #define RDAC_VPD_ID_HDWVER              0x68777234 /* "hwr4" */
      65             :         u_int8_t                num_channels;
      66             :         u_int8_t                flags;
      67             :         u_int8_t                proc_memory_size;
      68             :         u_int8_t                _reserved1[5];
      69             :         u_int8_t                board_name[64];
      70             :         u_int8_t                board_part_number[16];
      71             :         u_int8_t                schematic_number[12];
      72             :         u_int8_t                schematic_revision[4];
      73             :         u_int8_t                serial_number[16];
      74             :         u_int8_t                _reserved2[16];
      75             :         u_int8_t                date_manufactured[8];
      76             :         u_int8_t                board_revision[2];
      77             :         u_int8_t                board_identifier[4];
      78             : };
      79             : 
      80             : struct rdac_vpd_subsys {
      81             :         struct scsi_vpd_hdr     hdr; /* RDAC_VPD_SUBSYS */
      82             :         u_int8_t                pg_id[4];
      83             : #define RDAC_VPD_ID_SUBSYS              0x73756273 /* "subs" */
      84             :         u_int8_t                subsystem_id[16];
      85             :         u_int8_t                subsystem_revision[4];
      86             :         u_int8_t                controller_slot_id[2];
      87             :         u_int8_t                _reserved[2];
      88             : };
      89             : 
      90             : struct rdac_vpd_extdevid {
      91             :         struct scsi_vpd_hdr     hdr; /* RDAC_VPD_EXTDEVID */
      92             :         u_int8_t                pg_id[4];
      93             : #define RDAC_VPD_ID_EXTDEVID            0x65646964 /* "edid" */
      94             :         u_int8_t                _reserved[3];
      95             :         u_int8_t                vol_id_len;
      96             :         u_int8_t                vol_id[16];
      97             :         u_int8_t                vol_label_len;
      98             :         u_int8_t                vol_label[60];
      99             :         u_int8_t                array_id_len;
     100             :         u_int8_t                array_id[16];
     101             :         u_int8_t                array_label_len;
     102             :         u_int8_t                array_label[60];
     103             :         u_int8_t                lun[8];
     104             : };
     105             : 
     106             : struct rdac_vpd_volaccessctl {
     107             :         struct scsi_vpd_hdr     hdr; /* RDAC_VPD_VOLACCESSCTL */
     108             :         u_int8_t                pg_id[4];
     109             : #define RDAC_VPD_ID_VOLACCESSCTL        0x76616331 /* "vac1" */
     110             :         u_int8_t                avtcvp;
     111             : #define RDAC_VOLACCESSCTL_OWNER         0x01
     112             : #define RDAC_VOLACCESSCTL_AVT           0x70
     113             :         u_int8_t                _reserved1;
     114             :         u_int8_t                asym_access_state_cur;
     115             :         u_int8_t                vendor_specific_cur;
     116             :         u_int8_t                _reserved[36];
     117             : };
     118             : 
     119             : struct rdac_softc {
     120             :         struct device           sc_dev;
     121             :         struct mpath_path       sc_path;
     122             :         struct scsi_xshandler   sc_xsh;
     123             :         struct rdac_vpd_volaccessctl *sc_pg;
     124             : };
     125             : #define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
     126             : 
     127             : int             rdac_match(struct device *, void *, void *);
     128             : void            rdac_attach(struct device *, struct device *, void *);
     129             : int             rdac_detach(struct device *, int);
     130             : int             rdac_activate(struct device *, int);
     131             : 
     132             : struct cfattach rdac_ca = {
     133             :         sizeof(struct rdac_softc),
     134             :         rdac_match,
     135             :         rdac_attach,
     136             :         rdac_detach,
     137             :         rdac_activate
     138             : };
     139             : 
     140             : struct cfdriver rdac_cd = {
     141             :         NULL,
     142             :         "rdac",
     143             :         DV_DULL
     144             : };
     145             : 
     146             : void            rdac_mpath_start(struct scsi_xfer *);
     147             : int             rdac_mpath_checksense(struct scsi_xfer *);
     148             : void            rdac_mpath_status(struct scsi_link *);
     149             : 
     150             : const struct mpath_ops rdac_mpath_ops = {
     151             :         "rdac",
     152             :         rdac_mpath_checksense,
     153             :         rdac_mpath_status
     154             : };
     155             : 
     156             : int             rdac_extdevid(struct rdac_softc *);
     157             : int             rdac_groupid(struct rdac_softc *);
     158             : 
     159             : void            rdac_status(struct scsi_xfer *);
     160             : void            rdac_status_done(struct scsi_xfer *);
     161             : 
     162             : struct rdac_device {
     163             :         char *vendor;
     164             :         char *product;
     165             : };
     166             : 
     167             : struct rdac_device rdac_devices[] = {
     168             : /*        " vendor "  "     device     " */
     169             : /*        "01234567"  "0123456789012345" */
     170             :         { "SUN     ", "CSM200_" },
     171             :         { "DELL    ", "MD3000          " },
     172             :         { "DELL    ", "MD3000i         " },
     173             :         { "DELL    ", "MD32xx          " },
     174             :         { "DELL    ", "MD32xxi         " }
     175             : };
     176             : 
     177             : int
     178           0 : rdac_match(struct device *parent, void *match, void *aux)
     179             : {
     180           0 :         struct scsi_attach_args *sa = aux;
     181           0 :         struct scsi_inquiry_data *inq = sa->sa_inqbuf;
     182             :         struct rdac_device *s;
     183             :         int i;
     184             : 
     185           0 :         if (mpath_path_probe(sa->sa_sc_link) != 0)
     186           0 :                 return (0);
     187             : 
     188           0 :         for (i = 0; i < nitems(rdac_devices); i++) {
     189           0 :                 s = &rdac_devices[i];
     190             : 
     191           0 :                 if (bcmp(s->vendor, inq->vendor, strlen(s->vendor)) == 0 &&
     192           0 :                     bcmp(s->product, inq->product, strlen(s->product)) == 0)
     193           0 :                         return (8);
     194             :         }
     195             : 
     196           0 :         return (0);
     197           0 : }
     198             : 
     199             : void
     200           0 : rdac_attach(struct device *parent, struct device *self, void *aux)
     201             : {
     202           0 :         struct rdac_softc *sc = (struct rdac_softc *)self;
     203           0 :         struct scsi_attach_args *sa = aux;
     204           0 :         struct scsi_link *link = sa->sa_sc_link;
     205             :         int id;
     206             : 
     207           0 :         printf("\n");
     208             : 
     209             :         /* init link */
     210           0 :         link->device_softc = sc;
     211             : 
     212             :         /* init path */
     213           0 :         scsi_xsh_set(&sc->sc_path.p_xsh, link, rdac_mpath_start);
     214           0 :         sc->sc_path.p_link = link;
     215             : 
     216             :         /* init status handler */
     217           0 :         scsi_xsh_set(&sc->sc_xsh, link, rdac_status);
     218           0 :         sc->sc_pg = dma_alloc(sizeof(*sc->sc_pg), PR_WAITOK);
     219             : 
     220             :         /* let's go */
     221           0 :         if (rdac_extdevid(sc) != 0)
     222           0 :                 return;
     223             : 
     224           0 :         id = rdac_groupid(sc);
     225           0 :         if (id == -1) {
     226             :                 /* error printed by rdac_groupid */
     227           0 :                 return;
     228             :         }
     229             : 
     230           0 :         if (mpath_path_attach(&sc->sc_path, id, &rdac_mpath_ops) != 0)
     231           0 :                 printf("%s: unable to attach path\n", DEVNAME(sc));
     232           0 : }
     233             : 
     234             : int
     235           0 : rdac_detach(struct device *self, int flags)
     236             : {
     237           0 :         struct rdac_softc *sc = (struct rdac_softc *)self;
     238             : 
     239           0 :         dma_free(sc->sc_pg, sizeof(*sc->sc_pg));
     240             : 
     241           0 :         return (0);
     242             : }
     243             : 
     244             : int
     245           0 : rdac_activate(struct device *self, int act)
     246             : {
     247           0 :         struct rdac_softc *sc = (struct rdac_softc *)self;
     248             :         int rv = 0;
     249             : 
     250           0 :         switch (act) {
     251             :         case DVACT_DEACTIVATE:
     252           0 :                 if (scsi_xsh_del(&sc->sc_xsh))
     253           0 :                         mpath_path_status(&sc->sc_path, MPATH_S_UNKNOWN);
     254           0 :                 if (sc->sc_path.p_group != NULL)
     255           0 :                         mpath_path_detach(&sc->sc_path);
     256             :                 break;
     257             :         }
     258           0 :         return (rv);
     259             : }
     260             : 
     261             : void
     262           0 : rdac_mpath_start(struct scsi_xfer *xs)
     263             : {
     264           0 :         struct rdac_softc *sc = xs->sc_link->device_softc;
     265             : 
     266           0 :         mpath_start(&sc->sc_path, xs);
     267           0 : }
     268             : 
     269             : int
     270           0 : rdac_mpath_checksense(struct scsi_xfer *xs)
     271             : {
     272           0 :         struct scsi_sense_data *sense = &xs->sense;
     273             :         u_int8_t skey;
     274             : 
     275           0 :         if ((sense->error_code & SSD_ERRCODE) != SSD_ERRCODE_CURRENT)
     276           0 :                 return (MPATH_SENSE_DECLINED);
     277             : 
     278           0 :         skey = sense->flags & SSD_KEY;
     279             : 
     280             :         /* i wish i knew what the magic numbers meant */
     281             : 
     282             :         /* invalid request due to current lu ownership */
     283           0 :         if (skey == SKEY_ILLEGAL_REQUEST && ASC_ASCQ(sense) == 0x9401)
     284           0 :                 return (MPATH_SENSE_FAILOVER);
     285             : 
     286           0 :         if (skey == SKEY_UNIT_ATTENTION && ASC_ASCQ(sense) == 0x8b02)
     287           0 :                 return (MPATH_SENSE_FAILOVER);
     288             : 
     289           0 :         return (MPATH_SENSE_DECLINED);
     290           0 : }
     291             : 
     292             : void
     293           0 : rdac_mpath_status(struct scsi_link *link)
     294             : {
     295           0 :         struct rdac_softc *sc = link->device_softc;
     296             : 
     297           0 :         scsi_xsh_add(&sc->sc_xsh);
     298           0 : }
     299             : 
     300             : void
     301           0 : rdac_status(struct scsi_xfer *xs)
     302             : {
     303           0 :         struct scsi_link *link = xs->sc_link;
     304           0 :         struct rdac_softc *sc = link->device_softc;
     305             : 
     306           0 :         scsi_init_inquiry(xs, SI_EVPD, RDAC_VPD_VOLACCESSCTL,
     307           0 :             sc->sc_pg, sizeof(*sc->sc_pg));
     308             : 
     309           0 :         xs->done = rdac_status_done;
     310             : 
     311           0 :         scsi_xs_exec(xs);
     312           0 : }
     313             : 
     314             : void
     315           0 : rdac_status_done(struct scsi_xfer *xs)
     316             : {
     317           0 :         struct scsi_link *link = xs->sc_link;
     318           0 :         struct rdac_softc *sc = link->device_softc;
     319           0 :         struct rdac_vpd_volaccessctl *pg = sc->sc_pg;
     320             :         int status = MPATH_S_UNKNOWN;
     321             : 
     322           0 :         if (xs->error == XS_NOERROR &&
     323           0 :             _4btol(pg->pg_id) == RDAC_VPD_ID_VOLACCESSCTL) {
     324           0 :                 status = (ISSET(pg->avtcvp, RDAC_VOLACCESSCTL_AVT) ||
     325           0 :                     ISSET(pg->avtcvp, RDAC_VOLACCESSCTL_OWNER)) ?
     326             :                     MPATH_S_ACTIVE : MPATH_S_PASSIVE;
     327           0 :         }
     328             : 
     329           0 :         scsi_xs_put(xs);
     330           0 :         mpath_path_status(&sc->sc_path, status);
     331           0 : }
     332             : 
     333             : int
     334           0 : rdac_groupid(struct rdac_softc *sc)
     335             : {
     336             :         struct rdac_vpd_subsys *pg;
     337             :         int rv = -1;
     338             : 
     339           0 :         pg = dma_alloc(sizeof(*pg), PR_WAITOK | PR_ZERO);
     340             : 
     341           0 :         if (scsi_inquire_vpd(sc->sc_path.p_link, pg, sizeof(*pg),
     342           0 :             RDAC_VPD_SUBSYS, scsi_autoconf) != 0) {
     343           0 :                 printf("%s: unable to fetch subsys vpd page\n", DEVNAME(sc));
     344           0 :                 goto done;
     345             :         }
     346             : 
     347           0 :         if (_4btol(pg->pg_id) != RDAC_VPD_ID_SUBSYS) {
     348           0 :                 printf("%s: subsys page is invalid\n", DEVNAME(sc));
     349           0 :                 goto done;
     350             :         }
     351             : 
     352           0 :         rv = _2btol(pg->controller_slot_id);
     353             : 
     354             : done:
     355           0 :         dma_free(pg, sizeof(*pg));
     356           0 :         return (rv);
     357             : }
     358             : 
     359             : int
     360           0 : rdac_extdevid(struct rdac_softc *sc)
     361             : {
     362             :         struct rdac_vpd_extdevid *pg;
     363           0 :         char array[31];
     364           0 :         char vol[31];
     365             :         int i;
     366             :         int rv = 1;
     367             : 
     368           0 :         pg = dma_alloc(sizeof(*pg), PR_WAITOK | PR_ZERO);
     369             : 
     370           0 :         if (scsi_inquire_vpd(sc->sc_path.p_link, pg, sizeof(*pg),
     371           0 :             RDAC_VPD_EXTDEVID, scsi_autoconf) != 0) {
     372           0 :                 printf("%s: unable to fetch extdevid vpd page\n", DEVNAME(sc));
     373           0 :                 goto done;
     374             :         }
     375             : 
     376           0 :         if (_4btol(pg->pg_id) != RDAC_VPD_ID_EXTDEVID) {
     377           0 :                 printf("%s: extdevid page is invalid\n", DEVNAME(sc));
     378           0 :                 goto done;
     379             :         }
     380             : 
     381           0 :         memset(array, 0, sizeof(array));
     382           0 :         for (i = 0; i < sizeof(pg->array_label) / 2; i++)
     383           0 :                 array[i] = pg->array_label[i * 2 + 1];
     384             : 
     385           0 :         memset(vol, 0, sizeof(vol));
     386           0 :         for (i = 0; i < sizeof(pg->vol_label) / 2; i++)
     387           0 :                 vol[i] = pg->vol_label[i * 2 + 1];
     388             : 
     389           0 :         printf("%s: array %s, volume %s\n", DEVNAME(sc), array, vol);
     390             : 
     391           0 :         rv = 0;
     392             : done:
     393           0 :         dma_free(pg, sizeof(*pg));
     394           0 :         return (rv);
     395           0 : }

Generated by: LCOV version 1.13