15e53a4f9SPedro F. Giffuni /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
35e53a4f9SPedro F. Giffuni *
494606104SKenneth D. Merry * Copyright (c) 1997, 1998, 1999, 2002 Kenneth D. Merry.
5f736a450SJustin T. Gibbs * All rights reserved.
6f736a450SJustin T. Gibbs *
7f736a450SJustin T. Gibbs * Redistribution and use in source and binary forms, with or without
8f736a450SJustin T. Gibbs * modification, are permitted provided that the following conditions
9f736a450SJustin T. Gibbs * are met:
10f736a450SJustin T. Gibbs * 1. Redistributions of source code must retain the above copyright
11f736a450SJustin T. Gibbs * notice, this list of conditions and the following disclaimer.
12f736a450SJustin T. Gibbs * 2. The name of the author may not be used to endorse or promote products
13f736a450SJustin T. Gibbs * derived from this software without specific prior written permission.
14f736a450SJustin T. Gibbs *
15f736a450SJustin T. Gibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16f736a450SJustin T. Gibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17f736a450SJustin T. Gibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18f736a450SJustin T. Gibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19f736a450SJustin T. Gibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20f736a450SJustin T. Gibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21f736a450SJustin T. Gibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22f736a450SJustin T. Gibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23f736a450SJustin T. Gibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24f736a450SJustin T. Gibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25f736a450SJustin T. Gibbs * SUCH DAMAGE.
26f736a450SJustin T. Gibbs */
27f736a450SJustin T. Gibbs
28f736a450SJustin T. Gibbs #include <sys/types.h>
29f736a450SJustin T. Gibbs #include <sys/param.h>
300812ee3aSAlan Somers #include <assert.h>
31f736a450SJustin T. Gibbs #include <stdio.h>
32f736a450SJustin T. Gibbs #include <stdlib.h>
33169a84ddSNathan Whitehorn #include <stdint.h>
34f736a450SJustin T. Gibbs #include <string.h>
35f736a450SJustin T. Gibbs #include <fcntl.h>
36f736a450SJustin T. Gibbs #include <unistd.h>
37f736a450SJustin T. Gibbs #include <errno.h>
38f736a450SJustin T. Gibbs #include <ctype.h>
39f736a450SJustin T. Gibbs
40f736a450SJustin T. Gibbs #include <cam/cam.h>
41f736a450SJustin T. Gibbs #include <cam/scsi/scsi_all.h>
42f736a450SJustin T. Gibbs #include <cam/cam_ccb.h>
43f736a450SJustin T. Gibbs #include <cam/scsi/scsi_pass.h>
44f736a450SJustin T. Gibbs #include "camlib.h"
45f736a450SJustin T. Gibbs
46f736a450SJustin T. Gibbs
475bcc8fafSAndriy Gapon static const char *nonrewind_devs[] = {
485bcc8fafSAndriy Gapon "sa"
49f736a450SJustin T. Gibbs };
50f736a450SJustin T. Gibbs
51f736a450SJustin T. Gibbs char cam_errbuf[CAM_ERRBUF_SIZE];
52f736a450SJustin T. Gibbs
53f736a450SJustin T. Gibbs static struct cam_device *cam_real_open_device(const char *path, int flags,
54f736a450SJustin T. Gibbs struct cam_device *device,
55f736a450SJustin T. Gibbs const char *given_path,
56f736a450SJustin T. Gibbs const char *given_dev_name,
57f736a450SJustin T. Gibbs int given_unit_number);
58f736a450SJustin T. Gibbs static struct cam_device *cam_lookup_pass(const char *dev_name, int unit,
59f736a450SJustin T. Gibbs int flags, const char *given_path,
60f736a450SJustin T. Gibbs struct cam_device *device);
61f736a450SJustin T. Gibbs
62f736a450SJustin T. Gibbs /*
63f736a450SJustin T. Gibbs * Send a ccb to a passthrough device.
64f736a450SJustin T. Gibbs */
65f736a450SJustin T. Gibbs int
cam_send_ccb(struct cam_device * device,union ccb * ccb)66f736a450SJustin T. Gibbs cam_send_ccb(struct cam_device *device, union ccb *ccb)
67f736a450SJustin T. Gibbs {
68f736a450SJustin T. Gibbs return(ioctl(device->fd, CAMIOCOMMAND, ccb));
69f736a450SJustin T. Gibbs }
70f736a450SJustin T. Gibbs
71f736a450SJustin T. Gibbs /*
72f736a450SJustin T. Gibbs * Malloc a CCB, zero out the header and set its path, target and lun ids.
73f736a450SJustin T. Gibbs */
74f736a450SJustin T. Gibbs union ccb *
cam_getccb(struct cam_device * dev)75f736a450SJustin T. Gibbs cam_getccb(struct cam_device *dev)
76f736a450SJustin T. Gibbs {
77f736a450SJustin T. Gibbs union ccb *ccb;
78f736a450SJustin T. Gibbs
793e404b8cSEdward Tomasz Napierala ccb = calloc(1, sizeof(*ccb));
80f736a450SJustin T. Gibbs if (ccb != NULL) {
81f736a450SJustin T. Gibbs ccb->ccb_h.path_id = dev->path_id;
82f736a450SJustin T. Gibbs ccb->ccb_h.target_id = dev->target_id;
83f736a450SJustin T. Gibbs ccb->ccb_h.target_lun = dev->target_lun;
84f736a450SJustin T. Gibbs }
85f736a450SJustin T. Gibbs
86f736a450SJustin T. Gibbs return(ccb);
87f736a450SJustin T. Gibbs }
88f736a450SJustin T. Gibbs
89f736a450SJustin T. Gibbs /*
90f736a450SJustin T. Gibbs * Free a CCB.
91f736a450SJustin T. Gibbs */
92f736a450SJustin T. Gibbs void
cam_freeccb(union ccb * ccb)93f736a450SJustin T. Gibbs cam_freeccb(union ccb *ccb)
94f736a450SJustin T. Gibbs {
95f736a450SJustin T. Gibbs free(ccb);
96f736a450SJustin T. Gibbs }
97f736a450SJustin T. Gibbs
98f736a450SJustin T. Gibbs /*
99f736a450SJustin T. Gibbs * Take a device name or path passed in by the user, and attempt to figure
100f736a450SJustin T. Gibbs * out the device name and unit number. Some possible device name formats are:
1015bcc8fafSAndriy Gapon * /dev/foo0
102f736a450SJustin T. Gibbs * foo0
1035bcc8fafSAndriy Gapon * nfoo0
104f736a450SJustin T. Gibbs *
1055bcc8fafSAndriy Gapon * Some peripheral drivers create separate device nodes with 'n' prefix for
1065bcc8fafSAndriy Gapon * non-rewind operations. Currently only sa(4) tape driver has this feature.
1075bcc8fafSAndriy Gapon * We extract pure peripheral name as device name for this special case.
108f736a450SJustin T. Gibbs *
109f736a450SJustin T. Gibbs * Input parameters: device name/path, length of devname string
110f736a450SJustin T. Gibbs * Output: device name, unit number
111f736a450SJustin T. Gibbs * Return values: returns 0 for success, -1 for failure
112f736a450SJustin T. Gibbs */
113f736a450SJustin T. Gibbs int
cam_get_device(const char * path,char * dev_name,int devnamelen,int * unit)114f736a450SJustin T. Gibbs cam_get_device(const char *path, char *dev_name, int devnamelen, int *unit)
115f736a450SJustin T. Gibbs {
116f736a450SJustin T. Gibbs char *tmpstr, *tmpstr2;
117f736a450SJustin T. Gibbs char *newpath;
118f736a450SJustin T. Gibbs int unit_offset;
1195bcc8fafSAndriy Gapon int i;
120f736a450SJustin T. Gibbs
121f736a450SJustin T. Gibbs if (path == NULL) {
12233193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
123c9bac21cSEnji Cooper "%s: device pathname was NULL", __func__);
1243d416122SMike Pritchard return(-1);
125f736a450SJustin T. Gibbs }
126f736a450SJustin T. Gibbs
127f736a450SJustin T. Gibbs /*
1281abf1e8cSAndriy Gapon * Resolve the given path to a real device path in case we are given
1291abf1e8cSAndriy Gapon * an alias or other symbolic link. If the path cannot be resolved
1301abf1e8cSAndriy Gapon * then try to parse it as is.
131f736a450SJustin T. Gibbs */
1321abf1e8cSAndriy Gapon newpath = realpath(path, NULL);
1331abf1e8cSAndriy Gapon if (newpath == NULL)
1341abf1e8cSAndriy Gapon newpath = strdup(path);
1350812ee3aSAlan Somers if (newpath == NULL)
1360812ee3aSAlan Somers return (-1);
1370812ee3aSAlan Somers
138f736a450SJustin T. Gibbs tmpstr = newpath;
139f736a450SJustin T. Gibbs
140f736a450SJustin T. Gibbs /*
141f736a450SJustin T. Gibbs * Check to see whether we have an absolute pathname.
142f736a450SJustin T. Gibbs */
143f736a450SJustin T. Gibbs if (*tmpstr == '/') {
144f736a450SJustin T. Gibbs tmpstr2 = tmpstr;
145b3608ae1SEd Schouten tmpstr = strrchr(tmpstr2, '/');
1460812ee3aSAlan Somers /* We know that tmpstr2 contains a '/', so strrchr can't fail */
1470812ee3aSAlan Somers assert(tmpstr != NULL && *tmpstr != '\0');
148f736a450SJustin T. Gibbs tmpstr++;
149f736a450SJustin T. Gibbs }
150f736a450SJustin T. Gibbs
151f736a450SJustin T. Gibbs if (*tmpstr == '\0') {
15233193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
153c9bac21cSEnji Cooper "%s: no text after slash", __func__);
154f736a450SJustin T. Gibbs free(newpath);
1553d416122SMike Pritchard return(-1);
156f736a450SJustin T. Gibbs }
157f736a450SJustin T. Gibbs
158f736a450SJustin T. Gibbs /*
159f736a450SJustin T. Gibbs * Check to see whether the user has given us a nonrewound tape
160f736a450SJustin T. Gibbs * device.
161f736a450SJustin T. Gibbs */
1625bcc8fafSAndriy Gapon if (*tmpstr == 'n' || *tmpstr == 'e') {
1635bcc8fafSAndriy Gapon for (i = 0; i < sizeof(nonrewind_devs)/sizeof(char *); i++) {
1645bcc8fafSAndriy Gapon int len = strlen(nonrewind_devs[i]);
1655bcc8fafSAndriy Gapon if (strncmp(tmpstr + 1, nonrewind_devs[i], len) == 0) {
1665bcc8fafSAndriy Gapon if (isdigit(tmpstr[len + 1])) {
167f736a450SJustin T. Gibbs tmpstr++;
1685bcc8fafSAndriy Gapon break;
169f736a450SJustin T. Gibbs }
170f736a450SJustin T. Gibbs }
171f736a450SJustin T. Gibbs }
172f736a450SJustin T. Gibbs }
173f736a450SJustin T. Gibbs
174f736a450SJustin T. Gibbs /*
17584803238SAndriy Gapon * We should now have just a device name and unit number.
17684803238SAndriy Gapon * That means that there must be at least 2 characters.
17784803238SAndriy Gapon * If we only have 1, we don't have a valid device name.
178f736a450SJustin T. Gibbs */
179f736a450SJustin T. Gibbs if (strlen(tmpstr) < 2) {
18033193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
181f736a450SJustin T. Gibbs "%s: must have both device name and unit number",
182c9bac21cSEnji Cooper __func__);
183f736a450SJustin T. Gibbs free(newpath);
1843d416122SMike Pritchard return(-1);
185f736a450SJustin T. Gibbs }
186f736a450SJustin T. Gibbs
187f736a450SJustin T. Gibbs /*
188f736a450SJustin T. Gibbs * If the first character of the string is a digit, then the user
189f736a450SJustin T. Gibbs * has probably given us all numbers. Point out the error.
190f736a450SJustin T. Gibbs */
191f736a450SJustin T. Gibbs if (isdigit(*tmpstr)) {
19233193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
193f736a450SJustin T. Gibbs "%s: device name cannot begin with a number",
194c9bac21cSEnji Cooper __func__);
195f736a450SJustin T. Gibbs free(newpath);
1963d416122SMike Pritchard return(-1);
197f736a450SJustin T. Gibbs }
198f736a450SJustin T. Gibbs
199f736a450SJustin T. Gibbs /*
200f736a450SJustin T. Gibbs * At this point, if the last character of the string isn't a
201f736a450SJustin T. Gibbs * number, we know the user either didn't give us a device number,
202f736a450SJustin T. Gibbs * or he gave us a device name/number format we don't recognize.
203f736a450SJustin T. Gibbs */
204f736a450SJustin T. Gibbs if (!isdigit(tmpstr[strlen(tmpstr) - 1])) {
20533193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
206c9bac21cSEnji Cooper "%s: unable to find device unit number", __func__);
207f736a450SJustin T. Gibbs free(newpath);
2083d416122SMike Pritchard return(-1);
209f736a450SJustin T. Gibbs }
210f736a450SJustin T. Gibbs
211f736a450SJustin T. Gibbs /*
212f736a450SJustin T. Gibbs * Attempt to figure out where the device name ends and the unit
213f736a450SJustin T. Gibbs * number begins. As long as unit_offset is at least 1 less than
214f736a450SJustin T. Gibbs * the length of the string, we can still potentially have a device
215f736a450SJustin T. Gibbs * name at the front of the string. When we get to something that
216f736a450SJustin T. Gibbs * isn't a digit, we've hit the device name. Because of the check
217f736a450SJustin T. Gibbs * above, we know that this cannot happen when unit_offset == 1.
218f736a450SJustin T. Gibbs * Therefore it is okay to decrement unit_offset -- it won't cause
219f736a450SJustin T. Gibbs * us to go past the end of the character array.
220f736a450SJustin T. Gibbs */
221f736a450SJustin T. Gibbs for (unit_offset = 1;
222f736a450SJustin T. Gibbs (unit_offset < (strlen(tmpstr)))
223f736a450SJustin T. Gibbs && (isdigit(tmpstr[strlen(tmpstr) - unit_offset])); unit_offset++);
224f736a450SJustin T. Gibbs
225f736a450SJustin T. Gibbs unit_offset--;
226f736a450SJustin T. Gibbs
227f736a450SJustin T. Gibbs /*
228f736a450SJustin T. Gibbs * Grab the unit number.
229f736a450SJustin T. Gibbs */
230f736a450SJustin T. Gibbs *unit = atoi(&tmpstr[strlen(tmpstr) - unit_offset]);
231f736a450SJustin T. Gibbs
232f736a450SJustin T. Gibbs /*
233f736a450SJustin T. Gibbs * Put a null in place of the first number of the unit number so
234f736a450SJustin T. Gibbs * that all we have left is the device name.
235f736a450SJustin T. Gibbs */
236f736a450SJustin T. Gibbs tmpstr[strlen(tmpstr) - unit_offset] = '\0';
237f736a450SJustin T. Gibbs
23894606104SKenneth D. Merry strlcpy(dev_name, tmpstr, devnamelen);
239f736a450SJustin T. Gibbs
240f736a450SJustin T. Gibbs /* Clean up allocated memory */
241f736a450SJustin T. Gibbs free(newpath);
242f736a450SJustin T. Gibbs
2433d416122SMike Pritchard return(0);
244f736a450SJustin T. Gibbs
245f736a450SJustin T. Gibbs }
246f736a450SJustin T. Gibbs
247f736a450SJustin T. Gibbs /*
248f736a450SJustin T. Gibbs * Backwards compatible wrapper for the real open routine. This translates
249f736a450SJustin T. Gibbs * a pathname into a device name and unit number for use with the real open
250f736a450SJustin T. Gibbs * routine.
251f736a450SJustin T. Gibbs */
252f736a450SJustin T. Gibbs struct cam_device *
cam_open_device(const char * path,int flags)253f736a450SJustin T. Gibbs cam_open_device(const char *path, int flags)
254f736a450SJustin T. Gibbs {
255f736a450SJustin T. Gibbs int unit;
256f736a450SJustin T. Gibbs char dev_name[DEV_IDLEN + 1];
257f736a450SJustin T. Gibbs
258f736a450SJustin T. Gibbs /*
259f736a450SJustin T. Gibbs * cam_get_device() has already put an error message in cam_errbuf,
260f736a450SJustin T. Gibbs * so we don't need to.
261f736a450SJustin T. Gibbs */
26294606104SKenneth D. Merry if (cam_get_device(path, dev_name, sizeof(dev_name), &unit) == -1)
263f736a450SJustin T. Gibbs return(NULL);
264f736a450SJustin T. Gibbs
265f736a450SJustin T. Gibbs return(cam_lookup_pass(dev_name, unit, flags, path, NULL));
266f736a450SJustin T. Gibbs }
267f736a450SJustin T. Gibbs
268f736a450SJustin T. Gibbs /*
269f736a450SJustin T. Gibbs * Open the passthrough device for a given bus, target and lun, if the
270f736a450SJustin T. Gibbs * passthrough device exists.
271f736a450SJustin T. Gibbs */
272f736a450SJustin T. Gibbs struct cam_device *
cam_open_btl(path_id_t path_id,target_id_t target_id,lun_id_t target_lun,int flags,struct cam_device * device)273f736a450SJustin T. Gibbs cam_open_btl(path_id_t path_id, target_id_t target_id, lun_id_t target_lun,
274f736a450SJustin T. Gibbs int flags, struct cam_device *device)
275f736a450SJustin T. Gibbs {
276f736a450SJustin T. Gibbs union ccb ccb;
277f736a450SJustin T. Gibbs struct periph_match_pattern *match_pat;
278f736a450SJustin T. Gibbs int fd, bufsize;
279f736a450SJustin T. Gibbs
280f736a450SJustin T. Gibbs if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
28133193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
282c9bac21cSEnji Cooper "%s: couldn't open %s\n%s: %s", __func__, XPT_DEVICE,
283c9bac21cSEnji Cooper __func__, strerror(errno));
284f736a450SJustin T. Gibbs return(NULL);
285f736a450SJustin T. Gibbs }
286f736a450SJustin T. Gibbs
287f736a450SJustin T. Gibbs bzero(&ccb, sizeof(union ccb));
288f736a450SJustin T. Gibbs ccb.ccb_h.func_code = XPT_DEV_MATCH;
28925ea4c84SMarius Strobl ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
29025ea4c84SMarius Strobl ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
29125ea4c84SMarius Strobl ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
292f736a450SJustin T. Gibbs
293f736a450SJustin T. Gibbs /* Setup the result buffer */
294f736a450SJustin T. Gibbs bufsize = sizeof(struct dev_match_result);
295f736a450SJustin T. Gibbs ccb.cdm.match_buf_len = bufsize;
296f736a450SJustin T. Gibbs ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
297f736a450SJustin T. Gibbs if (ccb.cdm.matches == NULL) {
29833193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
299c9bac21cSEnji Cooper "%s: couldn't malloc match buffer", __func__);
300661d7edfSKenneth D. Merry close(fd);
301f736a450SJustin T. Gibbs return(NULL);
302f736a450SJustin T. Gibbs }
303f736a450SJustin T. Gibbs ccb.cdm.num_matches = 0;
304f736a450SJustin T. Gibbs
305f736a450SJustin T. Gibbs /* Setup the pattern buffer */
306f736a450SJustin T. Gibbs ccb.cdm.num_patterns = 1;
307f736a450SJustin T. Gibbs ccb.cdm.pattern_buf_len = sizeof(struct dev_match_pattern);
308f736a450SJustin T. Gibbs ccb.cdm.patterns = (struct dev_match_pattern *)malloc(
309f736a450SJustin T. Gibbs sizeof(struct dev_match_pattern));
310f736a450SJustin T. Gibbs if (ccb.cdm.patterns == NULL) {
31133193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
312c9bac21cSEnji Cooper "%s: couldn't malloc pattern buffer", __func__);
313f736a450SJustin T. Gibbs free(ccb.cdm.matches);
3144056f956SEnji Cooper ccb.cdm.matches = NULL;
315661d7edfSKenneth D. Merry close(fd);
316f736a450SJustin T. Gibbs return(NULL);
317f736a450SJustin T. Gibbs }
318f736a450SJustin T. Gibbs ccb.cdm.patterns[0].type = DEV_MATCH_PERIPH;
319f736a450SJustin T. Gibbs match_pat = &ccb.cdm.patterns[0].pattern.periph_pattern;
320f736a450SJustin T. Gibbs
321f736a450SJustin T. Gibbs /*
322f736a450SJustin T. Gibbs * We're looking for the passthrough device associated with this
323f736a450SJustin T. Gibbs * particular bus/target/lun.
324f736a450SJustin T. Gibbs */
325f736a450SJustin T. Gibbs sprintf(match_pat->periph_name, "pass");
326f736a450SJustin T. Gibbs match_pat->path_id = path_id;
327f736a450SJustin T. Gibbs match_pat->target_id = target_id;
328f736a450SJustin T. Gibbs match_pat->target_lun = target_lun;
329f736a450SJustin T. Gibbs /* Now set the flags to indicate what we're looking for. */
330f736a450SJustin T. Gibbs match_pat->flags = PERIPH_MATCH_PATH | PERIPH_MATCH_TARGET |
331f736a450SJustin T. Gibbs PERIPH_MATCH_LUN | PERIPH_MATCH_NAME;
332f736a450SJustin T. Gibbs
333f736a450SJustin T. Gibbs if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
33433193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
33575a0cc3bSJaakko Heinonen "%s: CAMIOCOMMAND ioctl failed\n"
336c9bac21cSEnji Cooper "%s: %s", __func__, __func__, strerror(errno));
337f736a450SJustin T. Gibbs goto btl_bailout;
338f736a450SJustin T. Gibbs }
339f736a450SJustin T. Gibbs
340f736a450SJustin T. Gibbs /*
341f736a450SJustin T. Gibbs * Check for an outright error.
342f736a450SJustin T. Gibbs */
343f736a450SJustin T. Gibbs if ((ccb.ccb_h.status != CAM_REQ_CMP)
344f736a450SJustin T. Gibbs || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
345f736a450SJustin T. Gibbs && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
34633193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
34775a0cc3bSJaakko Heinonen "%s: CAM error %#x, CDM error %d "
348c9bac21cSEnji Cooper "returned from XPT_DEV_MATCH ccb", __func__,
349f736a450SJustin T. Gibbs ccb.ccb_h.status, ccb.cdm.status);
350f736a450SJustin T. Gibbs goto btl_bailout;
351f736a450SJustin T. Gibbs }
352f736a450SJustin T. Gibbs
353f736a450SJustin T. Gibbs if (ccb.cdm.status == CAM_DEV_MATCH_MORE) {
35433193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
35575a0cc3bSJaakko Heinonen "%s: CDM reported more than one"
356abe83505SNathan Whitehorn " passthrough device at %d:%d:%jx!!\n",
357c9bac21cSEnji Cooper __func__, path_id, target_id, (uintmax_t)target_lun);
358f736a450SJustin T. Gibbs goto btl_bailout;
359f736a450SJustin T. Gibbs }
360f736a450SJustin T. Gibbs
361f736a450SJustin T. Gibbs if (ccb.cdm.num_matches == 0) {
36233193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
36375a0cc3bSJaakko Heinonen "%s: no passthrough device found at"
364c9bac21cSEnji Cooper " %d:%d:%jx", __func__, path_id, target_id,
365abe83505SNathan Whitehorn (uintmax_t)target_lun);
366f736a450SJustin T. Gibbs goto btl_bailout;
367f736a450SJustin T. Gibbs }
368f736a450SJustin T. Gibbs
369f736a450SJustin T. Gibbs switch(ccb.cdm.matches[0].type) {
370f736a450SJustin T. Gibbs case DEV_MATCH_PERIPH: {
371f736a450SJustin T. Gibbs int pass_unit;
372f736a450SJustin T. Gibbs char dev_path[256];
373f736a450SJustin T. Gibbs struct periph_match_result *periph_result;
374f736a450SJustin T. Gibbs
375f736a450SJustin T. Gibbs periph_result = &ccb.cdm.matches[0].result.periph_result;
376f736a450SJustin T. Gibbs pass_unit = periph_result->unit_number;
377f736a450SJustin T. Gibbs free(ccb.cdm.matches);
3784056f956SEnji Cooper ccb.cdm.matches = NULL;
379f736a450SJustin T. Gibbs free(ccb.cdm.patterns);
3804056f956SEnji Cooper ccb.cdm.patterns = NULL;
381661d7edfSKenneth D. Merry close(fd);
382f736a450SJustin T. Gibbs sprintf(dev_path, "/dev/pass%d", pass_unit);
383f736a450SJustin T. Gibbs return(cam_real_open_device(dev_path, flags, device, NULL,
384f736a450SJustin T. Gibbs NULL, 0));
385f736a450SJustin T. Gibbs break; /* NOTREACHED */
386f736a450SJustin T. Gibbs }
387f736a450SJustin T. Gibbs default:
38833193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
38975a0cc3bSJaakko Heinonen "%s: asked for a peripheral match, but"
390c9bac21cSEnji Cooper " got a bus or device match", __func__);
391f736a450SJustin T. Gibbs goto btl_bailout;
392f736a450SJustin T. Gibbs break; /* NOTREACHED */
393f736a450SJustin T. Gibbs }
394f736a450SJustin T. Gibbs
395f736a450SJustin T. Gibbs btl_bailout:
396f736a450SJustin T. Gibbs free(ccb.cdm.matches);
3974056f956SEnji Cooper ccb.cdm.matches = NULL;
398f736a450SJustin T. Gibbs free(ccb.cdm.patterns);
3994056f956SEnji Cooper ccb.cdm.patterns = NULL;
400661d7edfSKenneth D. Merry close(fd);
401f736a450SJustin T. Gibbs return(NULL);
402f736a450SJustin T. Gibbs }
403f736a450SJustin T. Gibbs
404f736a450SJustin T. Gibbs struct cam_device *
cam_open_spec_device(const char * dev_name,int unit,int flags,struct cam_device * device)405f736a450SJustin T. Gibbs cam_open_spec_device(const char *dev_name, int unit, int flags,
406f736a450SJustin T. Gibbs struct cam_device *device)
407f736a450SJustin T. Gibbs {
408f736a450SJustin T. Gibbs return(cam_lookup_pass(dev_name, unit, flags, NULL, device));
409f736a450SJustin T. Gibbs }
410f736a450SJustin T. Gibbs
411f736a450SJustin T. Gibbs struct cam_device *
cam_open_pass(const char * path,int flags,struct cam_device * device)412f736a450SJustin T. Gibbs cam_open_pass(const char *path, int flags, struct cam_device *device)
413f736a450SJustin T. Gibbs {
414f736a450SJustin T. Gibbs return(cam_real_open_device(path, flags, device, path, NULL, 0));
415f736a450SJustin T. Gibbs }
416f736a450SJustin T. Gibbs
417f736a450SJustin T. Gibbs static struct cam_device *
cam_lookup_pass(const char * dev_name,int unit,int flags,const char * given_path,struct cam_device * device)418f736a450SJustin T. Gibbs cam_lookup_pass(const char *dev_name, int unit, int flags,
419f736a450SJustin T. Gibbs const char *given_path, struct cam_device *device)
420f736a450SJustin T. Gibbs {
421a7a6dfbdSJoe Marcus Clarke int fd;
422f736a450SJustin T. Gibbs union ccb ccb;
423f736a450SJustin T. Gibbs char dev_path[256];
424f736a450SJustin T. Gibbs
425f736a450SJustin T. Gibbs /*
426f736a450SJustin T. Gibbs * The flags argument above only applies to the actual passthrough
427f736a450SJustin T. Gibbs * device open, not our open of the given device to find the
428f736a450SJustin T. Gibbs * passthrough device.
429f736a450SJustin T. Gibbs */
430f736a450SJustin T. Gibbs if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
43133193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
432c9bac21cSEnji Cooper "%s: couldn't open %s\n%s: %s", __func__, XPT_DEVICE,
433c9bac21cSEnji Cooper __func__, strerror(errno));
434f736a450SJustin T. Gibbs return(NULL);
435f736a450SJustin T. Gibbs }
436f736a450SJustin T. Gibbs
437f736a450SJustin T. Gibbs /* This isn't strictly necessary for the GETPASSTHRU ioctl. */
438f736a450SJustin T. Gibbs ccb.ccb_h.func_code = XPT_GDEVLIST;
439f736a450SJustin T. Gibbs
440f736a450SJustin T. Gibbs /* These two are necessary for the GETPASSTHRU ioctl to work. */
44194606104SKenneth D. Merry strlcpy(ccb.cgdl.periph_name, dev_name, sizeof(ccb.cgdl.periph_name));
442f736a450SJustin T. Gibbs ccb.cgdl.unit_number = unit;
443f736a450SJustin T. Gibbs
444f736a450SJustin T. Gibbs /*
445f736a450SJustin T. Gibbs * Attempt to get the passthrough device. This ioctl will fail if
446621a60d4SKenneth D. Merry * the device name is null, if the device doesn't exist, or if the
447621a60d4SKenneth D. Merry * passthrough driver isn't in the kernel.
448f736a450SJustin T. Gibbs */
449a7a6dfbdSJoe Marcus Clarke if (ioctl(fd, CAMGETPASSTHRU, &ccb) == -1) {
450621a60d4SKenneth D. Merry char tmpstr[256];
451621a60d4SKenneth D. Merry
452621a60d4SKenneth D. Merry /*
453621a60d4SKenneth D. Merry * If we get ENOENT from the transport layer version of
454621a60d4SKenneth D. Merry * the CAMGETPASSTHRU ioctl, it means one of two things:
455621a60d4SKenneth D. Merry * either the device name/unit number passed in doesn't
456621a60d4SKenneth D. Merry * exist, or the passthrough driver isn't in the kernel.
457621a60d4SKenneth D. Merry */
458621a60d4SKenneth D. Merry if (errno == ENOENT) {
459621a60d4SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr),
460621a60d4SKenneth D. Merry "\n%s: either the pass driver isn't in "
461621a60d4SKenneth D. Merry "your kernel\n%s: or %s%d doesn't exist",
462c9bac21cSEnji Cooper __func__, __func__, dev_name, unit);
463621a60d4SKenneth D. Merry }
46433193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
465621a60d4SKenneth D. Merry "%s: CAMGETPASSTHRU ioctl failed\n"
466c9bac21cSEnji Cooper "%s: %s%s", __func__, __func__, strerror(errno),
467621a60d4SKenneth D. Merry (errno == ENOENT) ? tmpstr : "");
468621a60d4SKenneth D. Merry
469a7a6dfbdSJoe Marcus Clarke close(fd);
470f736a450SJustin T. Gibbs return(NULL);
471f736a450SJustin T. Gibbs }
472f736a450SJustin T. Gibbs
473a7a6dfbdSJoe Marcus Clarke close(fd);
474a7a6dfbdSJoe Marcus Clarke
475f736a450SJustin T. Gibbs /*
476f736a450SJustin T. Gibbs * If the ioctl returned the right status, but we got an error back
477f736a450SJustin T. Gibbs * in the ccb, that means that the kernel found the device the user
478f736a450SJustin T. Gibbs * passed in, but was unable to find the passthrough device for
479f736a450SJustin T. Gibbs * the device the user gave us.
480f736a450SJustin T. Gibbs */
481f736a450SJustin T. Gibbs if (ccb.cgdl.status == CAM_GDEVLIST_ERROR) {
48233193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
48375a0cc3bSJaakko Heinonen "%s: device %s%d does not exist!",
484c9bac21cSEnji Cooper __func__, dev_name, unit);
485f736a450SJustin T. Gibbs return(NULL);
486f736a450SJustin T. Gibbs }
487f736a450SJustin T. Gibbs
488f736a450SJustin T. Gibbs sprintf(dev_path, "/dev/%s%d", ccb.cgdl.periph_name,
489f736a450SJustin T. Gibbs ccb.cgdl.unit_number);
490f736a450SJustin T. Gibbs
491f736a450SJustin T. Gibbs return(cam_real_open_device(dev_path, flags, device, NULL,
492f736a450SJustin T. Gibbs dev_name, unit));
493f736a450SJustin T. Gibbs }
494f736a450SJustin T. Gibbs
495f736a450SJustin T. Gibbs /*
496f736a450SJustin T. Gibbs * Open a given device. The path argument isn't strictly necessary, but it
497f736a450SJustin T. Gibbs * is copied into the cam_device structure as a convenience to the user.
498f736a450SJustin T. Gibbs */
499f736a450SJustin T. Gibbs static struct cam_device *
cam_real_open_device(const char * path,int flags,struct cam_device * device,const char * given_path,const char * given_dev_name,int given_unit_number)500f736a450SJustin T. Gibbs cam_real_open_device(const char *path, int flags, struct cam_device *device,
501f736a450SJustin T. Gibbs const char *given_path, const char *given_dev_name,
502f736a450SJustin T. Gibbs int given_unit_number)
503f736a450SJustin T. Gibbs {
504f736a450SJustin T. Gibbs union ccb ccb;
5053d09a65dSMatt Jacob int fd = -1, malloced_device = 0;
506f736a450SJustin T. Gibbs
507f736a450SJustin T. Gibbs /*
508f736a450SJustin T. Gibbs * See if the user wants us to malloc a device for him.
509f736a450SJustin T. Gibbs */
510f736a450SJustin T. Gibbs if (device == NULL) {
511f736a450SJustin T. Gibbs if ((device = (struct cam_device *)malloc(
512f736a450SJustin T. Gibbs sizeof(struct cam_device))) == NULL) {
51333193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
51475a0cc3bSJaakko Heinonen "%s: device structure malloc"
515c9bac21cSEnji Cooper " failed\n%s: %s", __func__, __func__,
516f736a450SJustin T. Gibbs strerror(errno));
517f736a450SJustin T. Gibbs return(NULL);
518f736a450SJustin T. Gibbs }
5193d09a65dSMatt Jacob device->fd = -1;
520f736a450SJustin T. Gibbs malloced_device = 1;
521f736a450SJustin T. Gibbs }
522f736a450SJustin T. Gibbs
523f736a450SJustin T. Gibbs /*
524f736a450SJustin T. Gibbs * If the user passed in a path, save it for him.
525f736a450SJustin T. Gibbs */
526f736a450SJustin T. Gibbs if (given_path != NULL)
52794606104SKenneth D. Merry strlcpy(device->device_path, given_path,
52894606104SKenneth D. Merry sizeof(device->device_path));
529f736a450SJustin T. Gibbs else
530f736a450SJustin T. Gibbs device->device_path[0] = '\0';
531f736a450SJustin T. Gibbs
532f736a450SJustin T. Gibbs /*
533f736a450SJustin T. Gibbs * If the user passed in a device name and unit number pair, save
534f736a450SJustin T. Gibbs * those as well.
535f736a450SJustin T. Gibbs */
536f736a450SJustin T. Gibbs if (given_dev_name != NULL)
53794606104SKenneth D. Merry strlcpy(device->given_dev_name, given_dev_name,
53894606104SKenneth D. Merry sizeof(device->given_dev_name));
539f736a450SJustin T. Gibbs else
540f736a450SJustin T. Gibbs device->given_dev_name[0] = '\0';
541f736a450SJustin T. Gibbs device->given_unit_number = given_unit_number;
542f736a450SJustin T. Gibbs
543f736a450SJustin T. Gibbs if ((fd = open(path, flags)) < 0) {
54433193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
545b735c714SKenneth D. Merry "%s: couldn't open passthrough device %s\n"
546c9bac21cSEnji Cooper "%s: %s", __func__, path, __func__,
547f736a450SJustin T. Gibbs strerror(errno));
548f736a450SJustin T. Gibbs goto crod_bailout;
549f736a450SJustin T. Gibbs }
550f736a450SJustin T. Gibbs
551f736a450SJustin T. Gibbs device->fd = fd;
552f736a450SJustin T. Gibbs
553f736a450SJustin T. Gibbs bzero(&ccb, sizeof(union ccb));
554f736a450SJustin T. Gibbs
555f736a450SJustin T. Gibbs /*
556f736a450SJustin T. Gibbs * Unlike the transport layer version of the GETPASSTHRU ioctl,
557f736a450SJustin T. Gibbs * we don't have to set any fields.
558f736a450SJustin T. Gibbs */
559f736a450SJustin T. Gibbs ccb.ccb_h.func_code = XPT_GDEVLIST;
560f736a450SJustin T. Gibbs
561f736a450SJustin T. Gibbs /*
562f736a450SJustin T. Gibbs * We're only doing this to get some information on the device in
563f736a450SJustin T. Gibbs * question. Otherwise, we'd have to pass in yet another
564f736a450SJustin T. Gibbs * parameter: the passthrough driver unit number.
565f736a450SJustin T. Gibbs */
566f736a450SJustin T. Gibbs if (ioctl(fd, CAMGETPASSTHRU, &ccb) == -1) {
567621a60d4SKenneth D. Merry /*
568621a60d4SKenneth D. Merry * At this point we know the passthrough device must exist
569621a60d4SKenneth D. Merry * because we just opened it above. The only way this
570621a60d4SKenneth D. Merry * ioctl can fail is if the ccb size is wrong.
571621a60d4SKenneth D. Merry */
57233193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
57375a0cc3bSJaakko Heinonen "%s: CAMGETPASSTHRU ioctl failed\n"
574c9bac21cSEnji Cooper "%s: %s", __func__, __func__, strerror(errno));
575f736a450SJustin T. Gibbs goto crod_bailout;
576f736a450SJustin T. Gibbs }
577f736a450SJustin T. Gibbs
578f736a450SJustin T. Gibbs /*
579f736a450SJustin T. Gibbs * If the ioctl returned the right status, but we got an error back
580f736a450SJustin T. Gibbs * in the ccb, that means that the kernel found the device the user
581f736a450SJustin T. Gibbs * passed in, but was unable to find the passthrough device for
582f736a450SJustin T. Gibbs * the device the user gave us.
583f736a450SJustin T. Gibbs */
584f736a450SJustin T. Gibbs if (ccb.cgdl.status == CAM_GDEVLIST_ERROR) {
58533193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
586c9bac21cSEnji Cooper "%s: passthrough device does not exist!", __func__);
587f736a450SJustin T. Gibbs goto crod_bailout;
588f736a450SJustin T. Gibbs }
589f736a450SJustin T. Gibbs
590f736a450SJustin T. Gibbs device->dev_unit_num = ccb.cgdl.unit_number;
59194606104SKenneth D. Merry strlcpy(device->device_name, ccb.cgdl.periph_name,
59294606104SKenneth D. Merry sizeof(device->device_name));
593f736a450SJustin T. Gibbs device->path_id = ccb.ccb_h.path_id;
594f736a450SJustin T. Gibbs device->target_id = ccb.ccb_h.target_id;
595f736a450SJustin T. Gibbs device->target_lun = ccb.ccb_h.target_lun;
596f736a450SJustin T. Gibbs
597f736a450SJustin T. Gibbs ccb.ccb_h.func_code = XPT_PATH_INQ;
598f736a450SJustin T. Gibbs if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
59933193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
60075a0cc3bSJaakko Heinonen "%s: Path Inquiry CCB failed\n"
601c9bac21cSEnji Cooper "%s: %s", __func__, __func__, strerror(errno));
602f736a450SJustin T. Gibbs goto crod_bailout;
603f736a450SJustin T. Gibbs }
60494606104SKenneth D. Merry strlcpy(device->sim_name, ccb.cpi.dev_name, sizeof(device->sim_name));
605f736a450SJustin T. Gibbs device->sim_unit_number = ccb.cpi.unit_number;
606f736a450SJustin T. Gibbs device->bus_id = ccb.cpi.bus_id;
607f736a450SJustin T. Gibbs
608f736a450SJustin T. Gibbs /*
609f736a450SJustin T. Gibbs * It doesn't really matter what is in the payload for a getdev
610f736a450SJustin T. Gibbs * CCB, the kernel doesn't look at it.
611f736a450SJustin T. Gibbs */
612f736a450SJustin T. Gibbs ccb.ccb_h.func_code = XPT_GDEV_TYPE;
613f736a450SJustin T. Gibbs if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
61433193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
61575a0cc3bSJaakko Heinonen "%s: Get Device Type CCB failed\n"
616c9bac21cSEnji Cooper "%s: %s", __func__, __func__, strerror(errno));
617f736a450SJustin T. Gibbs goto crod_bailout;
618f736a450SJustin T. Gibbs }
61931faeddfSMatt Jacob device->pd_type = SID_TYPE(&ccb.cgd.inq_data);
620f736a450SJustin T. Gibbs bcopy(&ccb.cgd.inq_data, &device->inq_data,
621f736a450SJustin T. Gibbs sizeof(struct scsi_inquiry_data));
622f736a450SJustin T. Gibbs device->serial_num_len = ccb.cgd.serial_num_len;
623f736a450SJustin T. Gibbs bcopy(&ccb.cgd.serial_num, &device->serial_num, device->serial_num_len);
624f736a450SJustin T. Gibbs
625f736a450SJustin T. Gibbs /*
626f736a450SJustin T. Gibbs * Zero the payload, the kernel does look at the flags.
627f736a450SJustin T. Gibbs */
62895320aceSDon Lewis CCB_CLEAR_ALL_EXCEPT_HDR(&ccb.cts);
629f736a450SJustin T. Gibbs
630f736a450SJustin T. Gibbs /*
631f736a450SJustin T. Gibbs * Get transfer settings for this device.
632f736a450SJustin T. Gibbs */
633f736a450SJustin T. Gibbs ccb.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
634f736a450SJustin T. Gibbs
635bd3fd815SMatt Jacob ccb.cts.type = CTS_TYPE_CURRENT_SETTINGS;
636f736a450SJustin T. Gibbs
637f736a450SJustin T. Gibbs if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
63833193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
63975a0cc3bSJaakko Heinonen "%s: Get Transfer Settings CCB failed\n"
640c9bac21cSEnji Cooper "%s: %s", __func__, __func__, strerror(errno));
641f736a450SJustin T. Gibbs goto crod_bailout;
642f736a450SJustin T. Gibbs }
64321d1182eSXin LI if (ccb.cts.transport == XPORT_SPI) {
644bd3fd815SMatt Jacob struct ccb_trans_settings_spi *spi =
645bd3fd815SMatt Jacob &ccb.cts.xport_specific.spi;
646bd3fd815SMatt Jacob device->sync_period = spi->sync_period;
647bd3fd815SMatt Jacob device->sync_offset = spi->sync_offset;
648bd3fd815SMatt Jacob device->bus_width = spi->bus_width;
649bd3fd815SMatt Jacob } else {
650bd3fd815SMatt Jacob device->sync_period = 0;
651bd3fd815SMatt Jacob device->sync_offset = 0;
652bd3fd815SMatt Jacob device->bus_width = 0;
653bd3fd815SMatt Jacob }
654f736a450SJustin T. Gibbs
655f736a450SJustin T. Gibbs return(device);
656f736a450SJustin T. Gibbs
657f736a450SJustin T. Gibbs crod_bailout:
658f736a450SJustin T. Gibbs
6593d09a65dSMatt Jacob if (fd >= 0)
6603d09a65dSMatt Jacob close(fd);
6613d09a65dSMatt Jacob
662f736a450SJustin T. Gibbs if (malloced_device)
663f736a450SJustin T. Gibbs free(device);
664f736a450SJustin T. Gibbs
665f736a450SJustin T. Gibbs return(NULL);
666f736a450SJustin T. Gibbs }
667f736a450SJustin T. Gibbs
668f736a450SJustin T. Gibbs void
cam_close_device(struct cam_device * dev)669f736a450SJustin T. Gibbs cam_close_device(struct cam_device *dev)
670f736a450SJustin T. Gibbs {
671f736a450SJustin T. Gibbs if (dev == NULL)
672f736a450SJustin T. Gibbs return;
673f736a450SJustin T. Gibbs
674f736a450SJustin T. Gibbs cam_close_spec_device(dev);
675f736a450SJustin T. Gibbs
676f736a450SJustin T. Gibbs free(dev);
677f736a450SJustin T. Gibbs }
678f736a450SJustin T. Gibbs
679f736a450SJustin T. Gibbs void
cam_close_spec_device(struct cam_device * dev)680f736a450SJustin T. Gibbs cam_close_spec_device(struct cam_device *dev)
681f736a450SJustin T. Gibbs {
682f736a450SJustin T. Gibbs if (dev == NULL)
683f736a450SJustin T. Gibbs return;
684f736a450SJustin T. Gibbs
685211d8666SEnji Cooper if (dev->fd >= 0) {
686f736a450SJustin T. Gibbs close(dev->fd);
687211d8666SEnji Cooper dev->fd = -1;
688211d8666SEnji Cooper }
689f736a450SJustin T. Gibbs }
690f736a450SJustin T. Gibbs
691f736a450SJustin T. Gibbs char *
cam_path_string(struct cam_device * dev,char * str,int len)692f736a450SJustin T. Gibbs cam_path_string(struct cam_device *dev, char *str, int len)
693f736a450SJustin T. Gibbs {
694f736a450SJustin T. Gibbs if (dev == NULL) {
695f736a450SJustin T. Gibbs snprintf(str, len, "No path");
696f736a450SJustin T. Gibbs return(str);
697f736a450SJustin T. Gibbs }
698f736a450SJustin T. Gibbs
699abe83505SNathan Whitehorn snprintf(str, len, "(%s%d:%s%d:%d:%d:%jx): ",
700f736a450SJustin T. Gibbs (dev->device_name[0] != '\0') ? dev->device_name : "pass",
701f736a450SJustin T. Gibbs dev->dev_unit_num,
702f736a450SJustin T. Gibbs (dev->sim_name[0] != '\0') ? dev->sim_name : "unknown",
703f736a450SJustin T. Gibbs dev->sim_unit_number,
704f736a450SJustin T. Gibbs dev->bus_id,
705f736a450SJustin T. Gibbs dev->target_id,
706abe83505SNathan Whitehorn (uintmax_t)dev->target_lun);
707f736a450SJustin T. Gibbs
708f736a450SJustin T. Gibbs return(str);
709f736a450SJustin T. Gibbs }
710f736a450SJustin T. Gibbs
711f736a450SJustin T. Gibbs /*
712f736a450SJustin T. Gibbs * Malloc/duplicate a CAM device structure.
713f736a450SJustin T. Gibbs */
714f736a450SJustin T. Gibbs struct cam_device *
cam_device_dup(struct cam_device * device)715f736a450SJustin T. Gibbs cam_device_dup(struct cam_device *device)
716f736a450SJustin T. Gibbs {
717f736a450SJustin T. Gibbs struct cam_device *newdev;
718f736a450SJustin T. Gibbs
719f736a450SJustin T. Gibbs if (device == NULL) {
72033193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
721c9bac21cSEnji Cooper "%s: device is NULL", __func__);
722f736a450SJustin T. Gibbs return (NULL);
723f736a450SJustin T. Gibbs }
724f736a450SJustin T. Gibbs
725f736a450SJustin T. Gibbs newdev = malloc(sizeof(struct cam_device));
726ae73eb3aSXin LI if (newdev == NULL) {
72733193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
728c9bac21cSEnji Cooper "%s: couldn't malloc CAM device structure", __func__);
729ae73eb3aSXin LI return (NULL);
730ae73eb3aSXin LI }
731f736a450SJustin T. Gibbs
732f736a450SJustin T. Gibbs bcopy(device, newdev, sizeof(struct cam_device));
733f736a450SJustin T. Gibbs
734f736a450SJustin T. Gibbs return(newdev);
735f736a450SJustin T. Gibbs }
736f736a450SJustin T. Gibbs
737f736a450SJustin T. Gibbs /*
738f736a450SJustin T. Gibbs * Copy a CAM device structure.
739f736a450SJustin T. Gibbs */
740f736a450SJustin T. Gibbs void
cam_device_copy(struct cam_device * src,struct cam_device * dst)741f736a450SJustin T. Gibbs cam_device_copy(struct cam_device *src, struct cam_device *dst)
742f736a450SJustin T. Gibbs {
743f736a450SJustin T. Gibbs
744f736a450SJustin T. Gibbs if (src == NULL) {
74533193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
746c9bac21cSEnji Cooper "%s: source device struct was NULL", __func__);
747f736a450SJustin T. Gibbs return;
748f736a450SJustin T. Gibbs }
749f736a450SJustin T. Gibbs
750f736a450SJustin T. Gibbs if (dst == NULL) {
75133193da2SEnji Cooper snprintf(cam_errbuf, nitems(cam_errbuf),
752c9bac21cSEnji Cooper "%s: destination device struct was NULL", __func__);
753f736a450SJustin T. Gibbs return;
754f736a450SJustin T. Gibbs }
755f736a450SJustin T. Gibbs
756f736a450SJustin T. Gibbs bcopy(src, dst, sizeof(struct cam_device));
757f736a450SJustin T. Gibbs
758f736a450SJustin T. Gibbs }
759