1/*	$OpenBSD: mpath_sym.c,v 1.28 2022/07/02 08:50:42 visa 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#include <sys/param.h>
20#include <sys/systm.h>
21#include <sys/kernel.h>
22#include <sys/malloc.h>
23#include <sys/device.h>
24#include <sys/conf.h>
25#include <sys/queue.h>
26#include <sys/rwlock.h>
27#include <sys/pool.h>
28#include <sys/ioctl.h>
29
30#include <scsi/scsi_all.h>
31#include <scsi/scsiconf.h>
32#include <scsi/mpathvar.h>
33
34struct sym_softc {
35	struct device		sc_dev;
36	struct mpath_path	sc_path;
37};
38#define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
39
40int		sym_match(struct device *, void *, void *);
41void		sym_attach(struct device *, struct device *, void *);
42int		sym_detach(struct device *, int);
43int		sym_activate(struct device *, int);
44
45const struct cfattach sym_ca = {
46	sizeof(struct sym_softc),
47	sym_match,
48	sym_attach,
49	sym_detach,
50	sym_activate
51};
52
53struct cfdriver sym_cd = {
54	NULL,
55	"sym",
56	DV_DULL
57};
58
59void		sym_mpath_start(struct scsi_xfer *);
60int		sym_mpath_checksense(struct scsi_xfer *);
61void		sym_mpath_status(struct scsi_link *);
62
63const struct mpath_ops sym_mpath_sym_ops = {
64	"sym",
65	sym_mpath_checksense,
66	sym_mpath_status
67};
68
69const struct mpath_ops sym_mpath_asym_ops = {
70	"sym",
71	sym_mpath_checksense,
72	sym_mpath_status
73};
74
75struct sym_device {
76	char *vendor;
77	char *product;
78};
79
80struct sym_device sym_devices[] = {
81/*	  " vendor "  "     device     " */
82/*	  "01234567"  "0123456789012345" */
83	{ "TOSHIBA ", "MBF" },
84	{ "SEAGATE ", "ST" },
85	{ "SGI     ", "ST" },
86	{ "FUJITSU ", "MBD" },
87	{ "FUJITSU ", "MA" }
88};
89
90struct sym_device asym_devices[] = {
91/*	  " vendor "  "     device     " */
92/*	  "01234567"  "0123456789012345" */
93	{ "DELL    ", "MD1220          " },
94	{ "DELL    ", "MD3060e         " },
95	{ "SUN     ", "StorEdge 3510F D" },
96	{ "SUNW    ", "SUNWGS INT FCBPL" },
97	{ "Transtec", "PROVIGO1100" },
98	{ "NetBSD", "NetBSD iSCSI" }
99};
100
101int
102sym_match(struct device *parent, void *match, void *aux)
103{
104	struct scsi_attach_args *sa = aux;
105	struct scsi_inquiry_data *inq = &sa->sa_sc_link->inqdata;
106	struct sym_device *s;
107	int i;
108
109	if (mpath_path_probe(sa->sa_sc_link) != 0)
110		return (0);
111
112	for (i = 0; i < nitems(sym_devices); i++) {
113		s = &sym_devices[i];
114
115		if (bcmp(s->vendor, inq->vendor, strlen(s->vendor)) == 0 &&
116		    bcmp(s->product, inq->product, strlen(s->product)) == 0)
117			return (8);
118	}
119	for (i = 0; i < nitems(asym_devices); i++) {
120		s = &asym_devices[i];
121
122		if (bcmp(s->vendor, inq->vendor, strlen(s->vendor)) == 0 &&
123		    bcmp(s->product, inq->product, strlen(s->product)) == 0)
124			return (8);
125	}
126
127	return (0);
128}
129
130void
131sym_attach(struct device *parent, struct device *self, void *aux)
132{
133	struct sym_softc *sc = (struct sym_softc *)self;
134	struct scsi_attach_args *sa = aux;
135	struct scsi_link *link = sa->sa_sc_link;
136	struct scsi_inquiry_data *inq = &link->inqdata;
137	const struct mpath_ops *ops = &sym_mpath_sym_ops;
138	struct sym_device *s;
139	u_int id = 0;
140	int i;
141
142	printf("\n");
143
144	/* check if we're an asymmetric access device */
145	for (i = 0; i < nitems(asym_devices); i++) {
146		s = &asym_devices[i];
147
148		if (bcmp(s->vendor, inq->vendor, strlen(s->vendor)) == 0 &&
149		    bcmp(s->product, inq->product, strlen(s->product)) == 0) {
150			ops = &sym_mpath_asym_ops;
151			id = sc->sc_dev.dv_unit;
152			break;
153		}
154	}
155
156	/* init link */
157	link->device_softc = sc;
158
159	/* init path */
160	scsi_xsh_set(&sc->sc_path.p_xsh, link, sym_mpath_start);
161	sc->sc_path.p_link = link;
162
163	if (mpath_path_attach(&sc->sc_path, id, ops) != 0)
164		printf("%s: unable to attach path\n", DEVNAME(sc));
165}
166
167int
168sym_detach(struct device *self, int flags)
169{
170	return (0);
171}
172
173int
174sym_activate(struct device *self, int act)
175{
176	struct sym_softc *sc = (struct sym_softc *)self;
177
178	switch (act) {
179	case DVACT_DEACTIVATE:
180		if (sc->sc_path.p_group != NULL)
181			mpath_path_detach(&sc->sc_path);
182		break;
183	}
184	return (0);
185}
186
187void
188sym_mpath_start(struct scsi_xfer *xs)
189{
190	struct sym_softc *sc = xs->sc_link->device_softc;
191
192	mpath_start(&sc->sc_path, xs);
193}
194
195int
196sym_mpath_checksense(struct scsi_xfer *xs)
197{
198	return (MPATH_SENSE_DECLINED);
199}
200
201void
202sym_mpath_status(struct scsi_link *link)
203{
204	struct sym_softc *sc = link->device_softc;
205
206	mpath_path_status(&sc->sc_path, MPATH_S_ACTIVE);
207}
208