xref: /freebsd/lib/libcam/camlib.c (revision a2f733ab)
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