1*12126SHyon.Kim@Sun.COM /*
2*12126SHyon.Kim@Sun.COM * CDDL HEADER START
3*12126SHyon.Kim@Sun.COM *
4*12126SHyon.Kim@Sun.COM * The contents of this file are subject to the terms of the
5*12126SHyon.Kim@Sun.COM * Common Development and Distribution License (the "License").
6*12126SHyon.Kim@Sun.COM * You may not use this file except in compliance with the License.
7*12126SHyon.Kim@Sun.COM *
8*12126SHyon.Kim@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*12126SHyon.Kim@Sun.COM * or http://www.opensolaris.org/os/licensing.
10*12126SHyon.Kim@Sun.COM * See the License for the specific language governing permissions
11*12126SHyon.Kim@Sun.COM * and limitations under the License.
12*12126SHyon.Kim@Sun.COM *
13*12126SHyon.Kim@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
14*12126SHyon.Kim@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*12126SHyon.Kim@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
16*12126SHyon.Kim@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
17*12126SHyon.Kim@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
18*12126SHyon.Kim@Sun.COM *
19*12126SHyon.Kim@Sun.COM * CDDL HEADER END
20*12126SHyon.Kim@Sun.COM */
21*12126SHyon.Kim@Sun.COM
22*12126SHyon.Kim@Sun.COM /*
23*12126SHyon.Kim@Sun.COM * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24*12126SHyon.Kim@Sun.COM */
25*12126SHyon.Kim@Sun.COM
26*12126SHyon.Kim@Sun.COM #include <sys/types.h>
27*12126SHyon.Kim@Sun.COM #include <sys/stat.h>
28*12126SHyon.Kim@Sun.COM #include <sys/scsi/scsi_address.h>
29*12126SHyon.Kim@Sun.COM #include <sys/scsi/impl/usmp.h>
30*12126SHyon.Kim@Sun.COM #include <sys/libdevid.h>
31*12126SHyon.Kim@Sun.COM
32*12126SHyon.Kim@Sun.COM #include <unistd.h>
33*12126SHyon.Kim@Sun.COM #include <fcntl.h>
34*12126SHyon.Kim@Sun.COM #include <errno.h>
35*12126SHyon.Kim@Sun.COM #include <string.h>
36*12126SHyon.Kim@Sun.COM #include <strings.h>
37*12126SHyon.Kim@Sun.COM #include <stdio.h>
38*12126SHyon.Kim@Sun.COM #include <limits.h>
39*12126SHyon.Kim@Sun.COM
40*12126SHyon.Kim@Sun.COM #include <scsi/libsmp.h>
41*12126SHyon.Kim@Sun.COM #include <scsi/libsmp_plugin.h>
42*12126SHyon.Kim@Sun.COM
43*12126SHyon.Kim@Sun.COM #include <libdevinfo.h>
44*12126SHyon.Kim@Sun.COM
45*12126SHyon.Kim@Sun.COM struct usmp_dev {
46*12126SHyon.Kim@Sun.COM int ud_fd;
47*12126SHyon.Kim@Sun.COM char *ud_dev;
48*12126SHyon.Kim@Sun.COM uint64_t ud_addr;
49*12126SHyon.Kim@Sun.COM };
50*12126SHyon.Kim@Sun.COM
51*12126SHyon.Kim@Sun.COM struct di_walk_arg {
52*12126SHyon.Kim@Sun.COM dev_t dev;
53*12126SHyon.Kim@Sun.COM uint64_t addr;
54*12126SHyon.Kim@Sun.COM };
55*12126SHyon.Kim@Sun.COM
56*12126SHyon.Kim@Sun.COM static int
di_walk(di_node_t node,di_minor_t minor,void * arg)57*12126SHyon.Kim@Sun.COM di_walk(di_node_t node, di_minor_t minor, void *arg)
58*12126SHyon.Kim@Sun.COM {
59*12126SHyon.Kim@Sun.COM struct di_walk_arg *wp = arg;
60*12126SHyon.Kim@Sun.COM char *wwn;
61*12126SHyon.Kim@Sun.COM
62*12126SHyon.Kim@Sun.COM if (di_minor_spectype(minor) != S_IFCHR)
63*12126SHyon.Kim@Sun.COM return (DI_WALK_CONTINUE);
64*12126SHyon.Kim@Sun.COM
65*12126SHyon.Kim@Sun.COM if (di_minor_devt(minor) == wp->dev) {
66*12126SHyon.Kim@Sun.COM if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
67*12126SHyon.Kim@Sun.COM SCSI_ADDR_PROP_TARGET_PORT, &wwn) != 1 &&
68*12126SHyon.Kim@Sun.COM di_prop_lookup_strings(DDI_DEV_T_ANY, node,
69*12126SHyon.Kim@Sun.COM "smp-wwn", &wwn) != 1)
70*12126SHyon.Kim@Sun.COM return (DI_WALK_CONTINUE);
71*12126SHyon.Kim@Sun.COM
72*12126SHyon.Kim@Sun.COM if (scsi_wwnstr_to_wwn(wwn, &wp->addr) != DDI_SUCCESS)
73*12126SHyon.Kim@Sun.COM return (DI_WALK_CONTINUE);
74*12126SHyon.Kim@Sun.COM
75*12126SHyon.Kim@Sun.COM return (DI_WALK_TERMINATE);
76*12126SHyon.Kim@Sun.COM }
77*12126SHyon.Kim@Sun.COM
78*12126SHyon.Kim@Sun.COM return (DI_WALK_CONTINUE);
79*12126SHyon.Kim@Sun.COM }
80*12126SHyon.Kim@Sun.COM
81*12126SHyon.Kim@Sun.COM static void *
usmp_open(const void * target)82*12126SHyon.Kim@Sun.COM usmp_open(const void *target)
83*12126SHyon.Kim@Sun.COM {
84*12126SHyon.Kim@Sun.COM struct usmp_dev *dp;
85*12126SHyon.Kim@Sun.COM const char *target_name = (const char *)target;
86*12126SHyon.Kim@Sun.COM
87*12126SHyon.Kim@Sun.COM struct stat64 st;
88*12126SHyon.Kim@Sun.COM di_node_t root, smp;
89*12126SHyon.Kim@Sun.COM struct di_walk_arg walk;
90*12126SHyon.Kim@Sun.COM
91*12126SHyon.Kim@Sun.COM if ((dp = smp_zalloc(sizeof (struct usmp_dev))) == NULL)
92*12126SHyon.Kim@Sun.COM return (NULL);
93*12126SHyon.Kim@Sun.COM
94*12126SHyon.Kim@Sun.COM if ((dp->ud_dev = smp_strdup(target_name)) == NULL) {
95*12126SHyon.Kim@Sun.COM smp_free(dp);
96*12126SHyon.Kim@Sun.COM return (NULL);
97*12126SHyon.Kim@Sun.COM }
98*12126SHyon.Kim@Sun.COM
99*12126SHyon.Kim@Sun.COM if ((dp->ud_fd = open(target_name, O_RDONLY)) < 0) {
100*12126SHyon.Kim@Sun.COM (void) smp_error(ESMP_BADTARGET,
101*12126SHyon.Kim@Sun.COM "failed to open %s for reading: %s",
102*12126SHyon.Kim@Sun.COM target_name, strerror(errno));
103*12126SHyon.Kim@Sun.COM smp_free(dp->ud_dev);
104*12126SHyon.Kim@Sun.COM smp_free(dp);
105*12126SHyon.Kim@Sun.COM return (NULL);
106*12126SHyon.Kim@Sun.COM }
107*12126SHyon.Kim@Sun.COM
108*12126SHyon.Kim@Sun.COM if (fstat64(dp->ud_fd, &st) != 0) {
109*12126SHyon.Kim@Sun.COM (void) smp_error(ESMP_BADTARGET,
110*12126SHyon.Kim@Sun.COM "failed to stat %s: %s", target_name, strerror(errno));
111*12126SHyon.Kim@Sun.COM (void) close(dp->ud_fd);
112*12126SHyon.Kim@Sun.COM smp_free(dp->ud_dev);
113*12126SHyon.Kim@Sun.COM smp_free(dp);
114*12126SHyon.Kim@Sun.COM return (NULL);
115*12126SHyon.Kim@Sun.COM }
116*12126SHyon.Kim@Sun.COM
117*12126SHyon.Kim@Sun.COM if ((root = di_init("/", DINFOCACHE)) != DI_NODE_NIL) {
118*12126SHyon.Kim@Sun.COM for (smp = di_drv_first_node("smp", root); smp != DI_NODE_NIL;
119*12126SHyon.Kim@Sun.COM smp = di_drv_next_node(smp)) {
120*12126SHyon.Kim@Sun.COM bzero(&walk, sizeof (walk));
121*12126SHyon.Kim@Sun.COM walk.dev = st.st_rdev;
122*12126SHyon.Kim@Sun.COM (void) di_walk_minor(smp, NULL, 0, &walk, di_walk);
123*12126SHyon.Kim@Sun.COM if (walk.addr != 0) {
124*12126SHyon.Kim@Sun.COM dp->ud_addr = walk.addr;
125*12126SHyon.Kim@Sun.COM break;
126*12126SHyon.Kim@Sun.COM }
127*12126SHyon.Kim@Sun.COM }
128*12126SHyon.Kim@Sun.COM di_fini(root);
129*12126SHyon.Kim@Sun.COM }
130*12126SHyon.Kim@Sun.COM
131*12126SHyon.Kim@Sun.COM return (dp);
132*12126SHyon.Kim@Sun.COM }
133*12126SHyon.Kim@Sun.COM
134*12126SHyon.Kim@Sun.COM static void
usmp_close(void * private)135*12126SHyon.Kim@Sun.COM usmp_close(void *private)
136*12126SHyon.Kim@Sun.COM {
137*12126SHyon.Kim@Sun.COM struct usmp_dev *dp = (struct usmp_dev *)private;
138*12126SHyon.Kim@Sun.COM
139*12126SHyon.Kim@Sun.COM if (dp == NULL)
140*12126SHyon.Kim@Sun.COM return;
141*12126SHyon.Kim@Sun.COM
142*12126SHyon.Kim@Sun.COM if (dp->ud_fd > 0)
143*12126SHyon.Kim@Sun.COM (void) close(dp->ud_fd);
144*12126SHyon.Kim@Sun.COM
145*12126SHyon.Kim@Sun.COM smp_free(dp->ud_dev);
146*12126SHyon.Kim@Sun.COM smp_free(dp);
147*12126SHyon.Kim@Sun.COM }
148*12126SHyon.Kim@Sun.COM
149*12126SHyon.Kim@Sun.COM static int
usmp_exec(void * private,smp_action_t * ap)150*12126SHyon.Kim@Sun.COM usmp_exec(void *private, smp_action_t *ap)
151*12126SHyon.Kim@Sun.COM {
152*12126SHyon.Kim@Sun.COM struct usmp_dev *dp = (struct usmp_dev *)private;
153*12126SHyon.Kim@Sun.COM struct usmp_cmd cmd;
154*12126SHyon.Kim@Sun.COM void *req, *resp;
155*12126SHyon.Kim@Sun.COM size_t reqlen, resplen;
156*12126SHyon.Kim@Sun.COM
157*12126SHyon.Kim@Sun.COM bzero(&cmd, sizeof (cmd));
158*12126SHyon.Kim@Sun.COM
159*12126SHyon.Kim@Sun.COM smp_action_get_request_frame(ap, &req, &reqlen);
160*12126SHyon.Kim@Sun.COM smp_action_get_response_frame(ap, &resp, &resplen);
161*12126SHyon.Kim@Sun.COM
162*12126SHyon.Kim@Sun.COM ASSERT(req != NULL);
163*12126SHyon.Kim@Sun.COM ASSERT(resp != NULL);
164*12126SHyon.Kim@Sun.COM ASSERT(reqlen != 0);
165*12126SHyon.Kim@Sun.COM ASSERT(resplen != 0);
166*12126SHyon.Kim@Sun.COM
167*12126SHyon.Kim@Sun.COM cmd.usmp_req = req;
168*12126SHyon.Kim@Sun.COM cmd.usmp_reqsize = reqlen;
169*12126SHyon.Kim@Sun.COM cmd.usmp_rsp = resp;
170*12126SHyon.Kim@Sun.COM cmd.usmp_rspsize = resplen;
171*12126SHyon.Kim@Sun.COM cmd.usmp_timeout = (int)smp_action_get_timeout(ap);
172*12126SHyon.Kim@Sun.COM
173*12126SHyon.Kim@Sun.COM if (ioctl(dp->ud_fd, USMPFUNC, &cmd) < 0) {
174*12126SHyon.Kim@Sun.COM ASSERT(errno != EFAULT);
175*12126SHyon.Kim@Sun.COM switch (errno) {
176*12126SHyon.Kim@Sun.COM case EINVAL:
177*12126SHyon.Kim@Sun.COM return (smp_error(ESMP_BADFUNC, "internal usmp error"));
178*12126SHyon.Kim@Sun.COM case EPERM:
179*12126SHyon.Kim@Sun.COM return (smp_error(ESMP_PERM,
180*12126SHyon.Kim@Sun.COM "insufficient privileges"));
181*12126SHyon.Kim@Sun.COM case EIO:
182*12126SHyon.Kim@Sun.COM return (smp_error(ESMP_IO, "I/O error"));
183*12126SHyon.Kim@Sun.COM default:
184*12126SHyon.Kim@Sun.COM return (smp_error(ESMP_SYS, "usmp ioctl failed: %s",
185*12126SHyon.Kim@Sun.COM strerror(errno)));
186*12126SHyon.Kim@Sun.COM }
187*12126SHyon.Kim@Sun.COM }
188*12126SHyon.Kim@Sun.COM
189*12126SHyon.Kim@Sun.COM /*
190*12126SHyon.Kim@Sun.COM * There is no way to determine the amount of data actually transferred
191*12126SHyon.Kim@Sun.COM * so we will just place the upper bound at the allocated size.
192*12126SHyon.Kim@Sun.COM */
193*12126SHyon.Kim@Sun.COM smp_action_set_response_len(ap, resplen);
194*12126SHyon.Kim@Sun.COM
195*12126SHyon.Kim@Sun.COM return (0);
196*12126SHyon.Kim@Sun.COM }
197*12126SHyon.Kim@Sun.COM
198*12126SHyon.Kim@Sun.COM static void
usmp_target_name(void * private,char * buf,size_t len)199*12126SHyon.Kim@Sun.COM usmp_target_name(void *private, char *buf, size_t len)
200*12126SHyon.Kim@Sun.COM {
201*12126SHyon.Kim@Sun.COM struct usmp_dev *dp = (struct usmp_dev *)private;
202*12126SHyon.Kim@Sun.COM
203*12126SHyon.Kim@Sun.COM (void) strlcpy(buf, dp->ud_dev, len);
204*12126SHyon.Kim@Sun.COM }
205*12126SHyon.Kim@Sun.COM
206*12126SHyon.Kim@Sun.COM static uint64_t
usmp_target_addr(void * private)207*12126SHyon.Kim@Sun.COM usmp_target_addr(void *private)
208*12126SHyon.Kim@Sun.COM {
209*12126SHyon.Kim@Sun.COM struct usmp_dev *dp = (struct usmp_dev *)private;
210*12126SHyon.Kim@Sun.COM
211*12126SHyon.Kim@Sun.COM return (dp->ud_addr);
212*12126SHyon.Kim@Sun.COM }
213*12126SHyon.Kim@Sun.COM
214*12126SHyon.Kim@Sun.COM static const smp_engine_ops_t usmp_ops = {
215*12126SHyon.Kim@Sun.COM .seo_open = usmp_open,
216*12126SHyon.Kim@Sun.COM .seo_close = usmp_close,
217*12126SHyon.Kim@Sun.COM .seo_exec = usmp_exec,
218*12126SHyon.Kim@Sun.COM .seo_target_name = usmp_target_name,
219*12126SHyon.Kim@Sun.COM .seo_target_addr = usmp_target_addr
220*12126SHyon.Kim@Sun.COM };
221*12126SHyon.Kim@Sun.COM
222*12126SHyon.Kim@Sun.COM int
_smp_init(smp_engine_t * ep)223*12126SHyon.Kim@Sun.COM _smp_init(smp_engine_t *ep)
224*12126SHyon.Kim@Sun.COM {
225*12126SHyon.Kim@Sun.COM smp_engine_config_t config = {
226*12126SHyon.Kim@Sun.COM .sec_name = "usmp",
227*12126SHyon.Kim@Sun.COM .sec_ops = &usmp_ops
228*12126SHyon.Kim@Sun.COM };
229*12126SHyon.Kim@Sun.COM
230*12126SHyon.Kim@Sun.COM return (smp_engine_register(ep, LIBSMP_ENGINE_VERSION, &config));
231*12126SHyon.Kim@Sun.COM }
232