camlib.c revision 213682
139209Sgibbs/*
296559Sken * Copyright (c) 1997, 1998, 1999, 2002 Kenneth D. Merry.
339209Sgibbs * All rights reserved.
439209Sgibbs *
539209Sgibbs * Redistribution and use in source and binary forms, with or without
639209Sgibbs * modification, are permitted provided that the following conditions
739209Sgibbs * are met:
839209Sgibbs * 1. Redistributions of source code must retain the above copyright
939209Sgibbs *    notice, this list of conditions and the following disclaimer.
1039209Sgibbs * 2. The name of the author may not be used to endorse or promote products
1139209Sgibbs *    derived from this software without specific prior written permission.
1239209Sgibbs *
1339209Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1439209Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1539209Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1639209Sgibbs * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1739209Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1839209Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1939209Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2039209Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2139209Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2239209Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2339209Sgibbs * SUCH DAMAGE.
2439209Sgibbs */
2539209Sgibbs
2684199Sdillon#include <sys/cdefs.h>
2784199Sdillon__FBSDID("$FreeBSD: head/lib/libcam/camlib.c 213682 2010-10-11 09:27:37Z avg $");
2884199Sdillon
2939209Sgibbs#include <sys/types.h>
3039209Sgibbs#include <sys/param.h>
3139209Sgibbs#include <stdio.h>
3239209Sgibbs#include <stdlib.h>
3339209Sgibbs#include <string.h>
3439209Sgibbs#include <fcntl.h>
3539209Sgibbs#include <unistd.h>
3639209Sgibbs#include <errno.h>
3739209Sgibbs#include <ctype.h>
3839209Sgibbs
3939209Sgibbs#include <cam/cam.h>
4039209Sgibbs#include <cam/scsi/scsi_all.h>
4139209Sgibbs#include <cam/cam_ccb.h>
4239209Sgibbs#include <cam/scsi/scsi_pass.h>
4339209Sgibbs#include "camlib.h"
4439209Sgibbs
4539209Sgibbs
46213682Savgstatic const char *nonrewind_devs[] = {
47213682Savg	"sa"
4839209Sgibbs};
4939209Sgibbs
5039209Sgibbschar cam_errbuf[CAM_ERRBUF_SIZE];
5139209Sgibbs
5239209Sgibbsstatic struct cam_device *cam_real_open_device(const char *path, int flags,
5339209Sgibbs					       struct cam_device *device,
5439209Sgibbs					       const char *given_path,
5539209Sgibbs					       const char *given_dev_name,
5639209Sgibbs					       int given_unit_number);
5739209Sgibbsstatic struct cam_device *cam_lookup_pass(const char *dev_name, int unit,
5839209Sgibbs					  int flags, const char *given_path,
5939209Sgibbs					  struct cam_device *device);
6039209Sgibbs
6139209Sgibbs/*
6239209Sgibbs * Send a ccb to a passthrough device.
6339209Sgibbs */
6439209Sgibbsint
6539209Sgibbscam_send_ccb(struct cam_device *device, union ccb *ccb)
6639209Sgibbs{
6739209Sgibbs	return(ioctl(device->fd, CAMIOCOMMAND, ccb));
6839209Sgibbs}
6939209Sgibbs
7039209Sgibbs/*
7139209Sgibbs * Malloc a CCB, zero out the header and set its path, target and lun ids.
7239209Sgibbs */
7339209Sgibbsunion ccb *
7439209Sgibbscam_getccb(struct cam_device *dev)
7539209Sgibbs{
7639209Sgibbs	union ccb *ccb;
7739209Sgibbs
7839209Sgibbs	ccb = (union ccb *)malloc(sizeof(union ccb));
7939209Sgibbs	if (ccb != NULL) {
8039209Sgibbs		bzero(&ccb->ccb_h, sizeof(struct ccb_hdr));
8139209Sgibbs		ccb->ccb_h.path_id = dev->path_id;
8239209Sgibbs		ccb->ccb_h.target_id = dev->target_id;
8339209Sgibbs		ccb->ccb_h.target_lun = dev->target_lun;
8439209Sgibbs	}
8539209Sgibbs
8639209Sgibbs	return(ccb);
8739209Sgibbs}
8839209Sgibbs
8939209Sgibbs/*
9039209Sgibbs * Free a CCB.
9139209Sgibbs */
9239209Sgibbsvoid
9339209Sgibbscam_freeccb(union ccb *ccb)
9439209Sgibbs{
95147949Sdelphij	free(ccb);
9639209Sgibbs}
9739209Sgibbs
9839209Sgibbs/*
9939209Sgibbs * Take a device name or path passed in by the user, and attempt to figure
10039209Sgibbs * out the device name and unit number.  Some possible device name formats are:
101213682Savg * /dev/foo0
10239209Sgibbs * foo0
103213682Savg * nfoo0
10439209Sgibbs *
105213682Savg * Some peripheral drivers create separate device nodes with 'n' prefix for
106213682Savg * non-rewind operations.  Currently only sa(4) tape driver has this feature.
107213682Savg * We extract pure peripheral name as device name for this special case.
108213682Savg *
10939209Sgibbs * Input parameters:  device name/path, length of devname string
11039209Sgibbs * Output:            device name, unit number
11139209Sgibbs * Return values:     returns 0 for success, -1 for failure
11239209Sgibbs */
11339209Sgibbsint
11439209Sgibbscam_get_device(const char *path, char *dev_name, int devnamelen, int *unit)
11539209Sgibbs{
11639209Sgibbs	char *func_name = "cam_get_device";
11739209Sgibbs	char *tmpstr, *tmpstr2;
11839209Sgibbs	char *newpath;
11939209Sgibbs	int unit_offset;
120213682Savg	int i;
12139209Sgibbs
12239209Sgibbs
12339209Sgibbs	if (path == NULL) {
12439209Sgibbs		sprintf(cam_errbuf, "%s: device pathname was NULL", func_name);
12547933Smpp		return(-1);
12639209Sgibbs	}
12739209Sgibbs
12839209Sgibbs	/*
12939209Sgibbs	 * We can be rather destructive to the path string.  Make a copy of
13039209Sgibbs	 * it so we don't hose the user's string.
13139209Sgibbs	 */
13239209Sgibbs	newpath = (char *)strdup(path);
13339209Sgibbs	tmpstr = newpath;
13439209Sgibbs
13539209Sgibbs	/*
13639209Sgibbs	 * Check to see whether we have an absolute pathname.
13739209Sgibbs	 */
13839209Sgibbs	if (*tmpstr == '/') {
13939209Sgibbs		tmpstr2 = tmpstr;
14039209Sgibbs		tmpstr = (char *)rindex(tmpstr2, '/');
14139209Sgibbs		if ((tmpstr != NULL) && (*tmpstr != '\0'))
14239209Sgibbs			tmpstr++;
14339209Sgibbs	}
14439209Sgibbs
14539209Sgibbs	if (*tmpstr == '\0') {
14639209Sgibbs		sprintf(cam_errbuf, "%s: no text after slash", func_name);
14739209Sgibbs		free(newpath);
14847933Smpp		return(-1);
14939209Sgibbs	}
15039209Sgibbs
15139209Sgibbs	/*
15239209Sgibbs	 * Check to see whether the user has given us a nonrewound tape
15339209Sgibbs	 * device.
15439209Sgibbs	 */
155213682Savg	if (*tmpstr == 'n' || *tmpstr == 'e') {
156213682Savg		for (i = 0; i < sizeof(nonrewind_devs)/sizeof(char *); i++) {
157213682Savg			int len = strlen(nonrewind_devs[i]);
158213682Savg			if (strncmp(tmpstr + 1, nonrewind_devs[i], len) == 0) {
159213682Savg				if (isdigit(tmpstr[len + 1])) {
160213682Savg					tmpstr++;
161213682Savg					break;
162213682Savg				}
163213682Savg			}
16439209Sgibbs		}
16539209Sgibbs	}
16639209Sgibbs
16739209Sgibbs	/*
16839209Sgibbs	 * After we nuke off the slice, we should have just a device name
16939209Sgibbs	 * and unit number.  That means there must be at least 2
17039209Sgibbs	 * characters.  If we only have 1, we don't have a valid device name.
17139209Sgibbs	 */
17239209Sgibbs	if (strlen(tmpstr) < 2) {
17339209Sgibbs		sprintf(cam_errbuf,
17439209Sgibbs			"%s: must have both device name and unit number",
17539209Sgibbs			func_name);
17639209Sgibbs		free(newpath);
17747933Smpp		return(-1);
17839209Sgibbs	}
17939209Sgibbs
18039209Sgibbs	/*
18139209Sgibbs	 * If the first character of the string is a digit, then the user
18239209Sgibbs	 * has probably given us all numbers.  Point out the error.
18339209Sgibbs	 */
18439209Sgibbs	if (isdigit(*tmpstr)) {
18539209Sgibbs		sprintf(cam_errbuf,
18639209Sgibbs			"%s: device name cannot begin with a number",
18739209Sgibbs			func_name);
18839209Sgibbs		free(newpath);
18947933Smpp		return(-1);
19039209Sgibbs	}
19139209Sgibbs
19239209Sgibbs	/*
19339209Sgibbs	 * At this point, if the last character of the string isn't a
19439209Sgibbs	 * number, we know the user either didn't give us a device number,
19539209Sgibbs	 * or he gave us a device name/number format we don't recognize.
19639209Sgibbs	 */
19739209Sgibbs	if (!isdigit(tmpstr[strlen(tmpstr) - 1])) {
19839209Sgibbs		sprintf(cam_errbuf, "%s: unable to find device unit number",
19939209Sgibbs			func_name);
20039209Sgibbs		free(newpath);
20147933Smpp		return(-1);
20239209Sgibbs	}
20339209Sgibbs
20439209Sgibbs	/*
20539209Sgibbs	 * Attempt to figure out where the device name ends and the unit
20639209Sgibbs	 * number begins.  As long as unit_offset is at least 1 less than
20739209Sgibbs	 * the length of the string, we can still potentially have a device
20839209Sgibbs	 * name at the front of the string.  When we get to something that
20939209Sgibbs	 * isn't a digit, we've hit the device name.  Because of the check
21039209Sgibbs	 * above, we know that this cannot happen when unit_offset == 1.
21139209Sgibbs	 * Therefore it is okay to decrement unit_offset -- it won't cause
21239209Sgibbs	 * us to go past the end of the character array.
21339209Sgibbs	 */
21439209Sgibbs	for (unit_offset = 1;
21539209Sgibbs	    (unit_offset < (strlen(tmpstr)))
21639209Sgibbs	    && (isdigit(tmpstr[strlen(tmpstr) - unit_offset])); unit_offset++);
21739209Sgibbs
21839209Sgibbs	unit_offset--;
21939209Sgibbs
22039209Sgibbs	/*
22139209Sgibbs	 * Grab the unit number.
22239209Sgibbs	 */
22339209Sgibbs	*unit = atoi(&tmpstr[strlen(tmpstr) - unit_offset]);
22439209Sgibbs
22539209Sgibbs	/*
22639209Sgibbs	 * Put a null in place of the first number of the unit number so
22739209Sgibbs	 * that all we have left is the device name.
22839209Sgibbs	 */
22939209Sgibbs	tmpstr[strlen(tmpstr) - unit_offset] = '\0';
23039209Sgibbs
231213682Savg	strlcpy(dev_name, tmpstr, devnamelen);
23239209Sgibbs
23339209Sgibbs	/* Clean up allocated memory */
23439209Sgibbs	free(newpath);
23539209Sgibbs
23647933Smpp	return(0);
23739209Sgibbs
23839209Sgibbs}
23939209Sgibbs
24039209Sgibbs/*
24139209Sgibbs * Backwards compatible wrapper for the real open routine.  This translates
24239209Sgibbs * a pathname into a device name and unit number for use with the real open
24339209Sgibbs * routine.
24439209Sgibbs */
24539209Sgibbsstruct cam_device *
24639209Sgibbscam_open_device(const char *path, int flags)
24739209Sgibbs{
24839209Sgibbs	int unit;
24939209Sgibbs	char dev_name[DEV_IDLEN + 1];
25039209Sgibbs
25139209Sgibbs	/*
25239209Sgibbs	 * cam_get_device() has already put an error message in cam_errbuf,
25339209Sgibbs	 * so we don't need to.
25439209Sgibbs	 */
25596559Sken	if (cam_get_device(path, dev_name, sizeof(dev_name), &unit) == -1)
25639209Sgibbs		return(NULL);
25739209Sgibbs
25839209Sgibbs	return(cam_lookup_pass(dev_name, unit, flags, path, NULL));
25939209Sgibbs}
26039209Sgibbs
26139209Sgibbs/*
26239209Sgibbs * Open the passthrough device for a given bus, target and lun, if the
26339209Sgibbs * passthrough device exists.
26439209Sgibbs */
26539209Sgibbsstruct cam_device *
26639209Sgibbscam_open_btl(path_id_t path_id, target_id_t target_id, lun_id_t target_lun,
26739209Sgibbs	     int flags, struct cam_device *device)
26839209Sgibbs{
26939209Sgibbs	union ccb ccb;
27039209Sgibbs	struct periph_match_pattern *match_pat;
27139209Sgibbs	char *func_name = "cam_open_btl";
27239209Sgibbs	int fd, bufsize;
27339209Sgibbs
27439209Sgibbs	if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
27539209Sgibbs		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
27639209Sgibbs			 "%s: couldn't open %s\n%s: %s", func_name, XPT_DEVICE,
27739209Sgibbs			 func_name, strerror(errno));
27839209Sgibbs		return(NULL);
27939209Sgibbs	}
28039209Sgibbs
28139209Sgibbs	bzero(&ccb, sizeof(union ccb));
28239209Sgibbs	ccb.ccb_h.func_code = XPT_DEV_MATCH;
283184379Smarius	ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
284184379Smarius	ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
285184379Smarius	ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
28639209Sgibbs
28739209Sgibbs	/* Setup the result buffer */
28839209Sgibbs	bufsize = sizeof(struct dev_match_result);
28939209Sgibbs	ccb.cdm.match_buf_len = bufsize;
29039209Sgibbs	ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
29139209Sgibbs	if (ccb.cdm.matches == NULL) {
29239209Sgibbs		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
29339209Sgibbs			 "%s: couldn't malloc match buffer", func_name);
29451213Sken		close(fd);
29539209Sgibbs		return(NULL);
29639209Sgibbs	}
29739209Sgibbs	ccb.cdm.num_matches = 0;
29839209Sgibbs
29939209Sgibbs	/* Setup the pattern buffer */
30039209Sgibbs	ccb.cdm.num_patterns = 1;
30139209Sgibbs	ccb.cdm.pattern_buf_len = sizeof(struct dev_match_pattern);
30239209Sgibbs	ccb.cdm.patterns = (struct dev_match_pattern *)malloc(
30339209Sgibbs		sizeof(struct dev_match_pattern));
30439209Sgibbs	if (ccb.cdm.patterns == NULL) {
30539209Sgibbs		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
30639209Sgibbs			 "%s: couldn't malloc pattern buffer", func_name);
30739209Sgibbs		free(ccb.cdm.matches);
30851213Sken		close(fd);
30939209Sgibbs		return(NULL);
31039209Sgibbs	}
31139209Sgibbs	ccb.cdm.patterns[0].type = DEV_MATCH_PERIPH;
31239209Sgibbs	match_pat = &ccb.cdm.patterns[0].pattern.periph_pattern;
31339209Sgibbs
31439209Sgibbs	/*
31539209Sgibbs	 * We're looking for the passthrough device associated with this
31639209Sgibbs	 * particular bus/target/lun.
31739209Sgibbs	 */
31839209Sgibbs	sprintf(match_pat->periph_name, "pass");
31939209Sgibbs	match_pat->path_id = path_id;
32039209Sgibbs	match_pat->target_id = target_id;
32139209Sgibbs	match_pat->target_lun = target_lun;
32239209Sgibbs	/* Now set the flags to indicate what we're looking for. */
32339209Sgibbs	match_pat->flags = PERIPH_MATCH_PATH | PERIPH_MATCH_TARGET |
32439209Sgibbs			   PERIPH_MATCH_LUN | PERIPH_MATCH_NAME;
32539209Sgibbs
32639209Sgibbs	if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
32739209Sgibbs		sprintf(cam_errbuf, "%s: CAMIOCOMMAND ioctl failed\n"
32839209Sgibbs			"%s: %s", func_name, func_name, strerror(errno));
32939209Sgibbs		goto btl_bailout;
33039209Sgibbs	}
33139209Sgibbs
33239209Sgibbs	/*
33339209Sgibbs	 * Check for an outright error.
33439209Sgibbs	 */
33539209Sgibbs	if ((ccb.ccb_h.status != CAM_REQ_CMP)
33639209Sgibbs	 || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
33739209Sgibbs	   && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
33839209Sgibbs		sprintf(cam_errbuf, "%s: CAM error %#x, CDM error %d "
33939209Sgibbs			"returned from XPT_DEV_MATCH ccb", func_name,
34039209Sgibbs			ccb.ccb_h.status, ccb.cdm.status);
34139209Sgibbs		goto btl_bailout;
34239209Sgibbs	}
34339209Sgibbs
34439209Sgibbs	if (ccb.cdm.status == CAM_DEV_MATCH_MORE) {
34539209Sgibbs		sprintf(cam_errbuf, "%s: CDM reported more than one"
34639209Sgibbs			" passthrough device at %d:%d:%d!!\n",
34739209Sgibbs			func_name, path_id, target_id, target_lun);
34839209Sgibbs		goto btl_bailout;
34939209Sgibbs	}
35039209Sgibbs
35139209Sgibbs	if (ccb.cdm.num_matches == 0) {
35239209Sgibbs		sprintf(cam_errbuf, "%s: no passthrough device found at"
35339209Sgibbs			" %d:%d:%d", func_name, path_id, target_id,
35439209Sgibbs			target_lun);
35539209Sgibbs		goto btl_bailout;
35639209Sgibbs	}
35739209Sgibbs
35839209Sgibbs	switch(ccb.cdm.matches[0].type) {
35939209Sgibbs	case DEV_MATCH_PERIPH: {
36039209Sgibbs		int pass_unit;
36139209Sgibbs		char dev_path[256];
36239209Sgibbs		struct periph_match_result *periph_result;
36339209Sgibbs
36439209Sgibbs		periph_result = &ccb.cdm.matches[0].result.periph_result;
36539209Sgibbs		pass_unit = periph_result->unit_number;
36639209Sgibbs		free(ccb.cdm.matches);
36739209Sgibbs		free(ccb.cdm.patterns);
36851213Sken		close(fd);
36939209Sgibbs		sprintf(dev_path, "/dev/pass%d", pass_unit);
37039209Sgibbs		return(cam_real_open_device(dev_path, flags, device, NULL,
37139209Sgibbs					    NULL, 0));
37239209Sgibbs		break; /* NOTREACHED */
37339209Sgibbs	}
37439209Sgibbs	default:
37539209Sgibbs		sprintf(cam_errbuf, "%s: asked for a peripheral match, but"
376132843Sscottl			" got a bus or device match", func_name);
37739209Sgibbs		goto btl_bailout;
37839209Sgibbs		break; /* NOTREACHED */
37939209Sgibbs	}
38039209Sgibbs
38139209Sgibbsbtl_bailout:
38239209Sgibbs	free(ccb.cdm.matches);
38339209Sgibbs	free(ccb.cdm.patterns);
38451213Sken	close(fd);
38539209Sgibbs	return(NULL);
38639209Sgibbs}
38739209Sgibbs
38839209Sgibbsstruct cam_device *
38939209Sgibbscam_open_spec_device(const char *dev_name, int unit, int flags,
39039209Sgibbs		     struct cam_device *device)
39139209Sgibbs{
39239209Sgibbs	return(cam_lookup_pass(dev_name, unit, flags, NULL, device));
39339209Sgibbs}
39439209Sgibbs
39539209Sgibbsstruct cam_device *
39639209Sgibbscam_open_pass(const char *path, int flags, struct cam_device *device)
39739209Sgibbs{
39839209Sgibbs	return(cam_real_open_device(path, flags, device, path, NULL, 0));
39939209Sgibbs}
40039209Sgibbs
40139209Sgibbsstatic struct cam_device *
40239209Sgibbscam_lookup_pass(const char *dev_name, int unit, int flags,
40339209Sgibbs		const char *given_path, struct cam_device *device)
40439209Sgibbs{
405158171Smarcus	int fd;
40639209Sgibbs	union ccb ccb;
40739209Sgibbs	char dev_path[256];
40839209Sgibbs	char *func_name = "cam_lookup_pass";
40939209Sgibbs
41039209Sgibbs	/*
41139209Sgibbs	 * The flags argument above only applies to the actual passthrough
41239209Sgibbs	 * device open, not our open of the given device to find the
41339209Sgibbs	 * passthrough device.
41439209Sgibbs	 */
41539209Sgibbs	if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
41639209Sgibbs		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
41739209Sgibbs			 "%s: couldn't open %s\n%s: %s", func_name, XPT_DEVICE,
41839209Sgibbs			 func_name, strerror(errno));
41939209Sgibbs		return(NULL);
42039209Sgibbs	}
42139209Sgibbs
42239209Sgibbs	/* This isn't strictly necessary for the GETPASSTHRU ioctl. */
42339209Sgibbs	ccb.ccb_h.func_code = XPT_GDEVLIST;
42439209Sgibbs
42539209Sgibbs	/* These two are necessary for the GETPASSTHRU ioctl to work. */
42696559Sken	strlcpy(ccb.cgdl.periph_name, dev_name, sizeof(ccb.cgdl.periph_name));
42739209Sgibbs	ccb.cgdl.unit_number = unit;
42839209Sgibbs
42939209Sgibbs	/*
43039209Sgibbs	 * Attempt to get the passthrough device.  This ioctl will fail if
43140271Sken	 * the device name is null, if the device doesn't exist, or if the
43240271Sken	 * passthrough driver isn't in the kernel.
43339209Sgibbs	 */
434158171Smarcus	if (ioctl(fd, CAMGETPASSTHRU, &ccb) == -1) {
43540271Sken		char tmpstr[256];
43640271Sken
43740271Sken		/*
43840271Sken		 * If we get ENOENT from the transport layer version of
43940271Sken		 * the CAMGETPASSTHRU ioctl, it means one of two things:
44040271Sken		 * either the device name/unit number passed in doesn't
44140271Sken		 * exist, or the passthrough driver isn't in the kernel.
44240271Sken		 */
44340271Sken		if (errno == ENOENT) {
44440271Sken			snprintf(tmpstr, sizeof(tmpstr),
44540271Sken				 "\n%s: either the pass driver isn't in "
44640271Sken				 "your kernel\n%s: or %s%d doesn't exist",
44740271Sken				 func_name, func_name, dev_name, unit);
44840271Sken		}
44940271Sken		snprintf(cam_errbuf, sizeof(cam_errbuf),
45040271Sken			 "%s: CAMGETPASSTHRU ioctl failed\n"
45140271Sken			 "%s: %s%s", func_name, func_name, strerror(errno),
45240271Sken			 (errno == ENOENT) ? tmpstr : "");
45340271Sken
454158171Smarcus		close(fd);
45539209Sgibbs		return(NULL);
45639209Sgibbs	}
45739209Sgibbs
458158171Smarcus	close(fd);
459158171Smarcus
46039209Sgibbs	/*
46139209Sgibbs	 * If the ioctl returned the right status, but we got an error back
46239209Sgibbs	 * in the ccb, that means that the kernel found the device the user
46339209Sgibbs	 * passed in, but was unable to find the passthrough device for
46439209Sgibbs	 * the device the user gave us.
46539209Sgibbs	 */
46639209Sgibbs	if (ccb.cgdl.status == CAM_GDEVLIST_ERROR) {
467132843Sscottl		sprintf(cam_errbuf, "%s: device %s%d does not exist!",
46839209Sgibbs			func_name, dev_name, unit);
46939209Sgibbs		return(NULL);
47039209Sgibbs	}
47139209Sgibbs
47239209Sgibbs	sprintf(dev_path, "/dev/%s%d", ccb.cgdl.periph_name,
47339209Sgibbs		ccb.cgdl.unit_number);
47439209Sgibbs
47539209Sgibbs	return(cam_real_open_device(dev_path, flags, device, NULL,
47639209Sgibbs				    dev_name, unit));
47739209Sgibbs}
47839209Sgibbs
47939209Sgibbs/*
48039209Sgibbs * Open a given device.  The path argument isn't strictly necessary, but it
48139209Sgibbs * is copied into the cam_device structure as a convenience to the user.
48239209Sgibbs */
48339209Sgibbsstatic struct cam_device *
48439209Sgibbscam_real_open_device(const char *path, int flags, struct cam_device *device,
48539209Sgibbs		     const char *given_path, const char *given_dev_name,
48639209Sgibbs		     int given_unit_number)
48739209Sgibbs{
48839209Sgibbs	char *func_name = "cam_real_open_device";
48939209Sgibbs	union ccb ccb;
49079183Smjacob	int fd = -1, malloced_device = 0;
49139209Sgibbs
49239209Sgibbs	/*
49339209Sgibbs	 * See if the user wants us to malloc a device for him.
49439209Sgibbs	 */
49539209Sgibbs	if (device == NULL) {
49639209Sgibbs		if ((device = (struct cam_device *)malloc(
49739209Sgibbs		     sizeof(struct cam_device))) == NULL) {
49839209Sgibbs			sprintf(cam_errbuf, "%s: device structure malloc"
49939209Sgibbs				" failed\n%s: %s", func_name, func_name,
50039209Sgibbs				strerror(errno));
50139209Sgibbs			return(NULL);
50239209Sgibbs		}
50379183Smjacob		device->fd = -1;
50439209Sgibbs		malloced_device = 1;
50539209Sgibbs	}
50639209Sgibbs
50739209Sgibbs	/*
50839209Sgibbs	 * If the user passed in a path, save it for him.
50939209Sgibbs	 */
51039209Sgibbs	if (given_path != NULL)
51196559Sken		strlcpy(device->device_path, given_path,
51296559Sken			sizeof(device->device_path));
51339209Sgibbs	else
51439209Sgibbs		device->device_path[0] = '\0';
51539209Sgibbs
51639209Sgibbs	/*
51739209Sgibbs	 * If the user passed in a device name and unit number pair, save
51839209Sgibbs	 * those as well.
51939209Sgibbs	 */
52039209Sgibbs	if (given_dev_name != NULL)
52196559Sken		strlcpy(device->given_dev_name, given_dev_name,
52296559Sken			sizeof(device->given_dev_name));
52339209Sgibbs	else
52439209Sgibbs		device->given_dev_name[0] = '\0';
52539209Sgibbs	device->given_unit_number = given_unit_number;
52639209Sgibbs
52739209Sgibbs	if ((fd = open(path, flags)) < 0) {
52841190Sken		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
52941190Sken			 "%s: couldn't open passthrough device %s\n"
53041190Sken			 "%s: %s", func_name, path, func_name,
53141190Sken			 strerror(errno));
53239209Sgibbs		goto crod_bailout;
53339209Sgibbs	}
53439209Sgibbs
53539209Sgibbs	device->fd = fd;
53639209Sgibbs
53739209Sgibbs	bzero(&ccb, sizeof(union ccb));
53839209Sgibbs
53939209Sgibbs	/*
54039209Sgibbs	 * Unlike the transport layer version of the GETPASSTHRU ioctl,
54139209Sgibbs	 * we don't have to set any fields.
54239209Sgibbs	 */
54339209Sgibbs	ccb.ccb_h.func_code = XPT_GDEVLIST;
54439209Sgibbs
54539209Sgibbs	/*
54639209Sgibbs	 * We're only doing this to get some information on the device in
54739209Sgibbs	 * question.  Otherwise, we'd have to pass in yet another
54839209Sgibbs	 * parameter: the passthrough driver unit number.
54939209Sgibbs	 */
55039209Sgibbs	if (ioctl(fd, CAMGETPASSTHRU, &ccb) == -1) {
55140271Sken		/*
55240271Sken		 * At this point we know the passthrough device must exist
55340271Sken		 * because we just opened it above.  The only way this
55440271Sken		 * ioctl can fail is if the ccb size is wrong.
55540271Sken		 */
55639209Sgibbs		sprintf(cam_errbuf, "%s: CAMGETPASSTHRU ioctl failed\n"
55739209Sgibbs			"%s: %s", func_name, func_name, strerror(errno));
55839209Sgibbs		goto crod_bailout;
55939209Sgibbs	}
56039209Sgibbs
56139209Sgibbs	/*
56239209Sgibbs	 * If the ioctl returned the right status, but we got an error back
56339209Sgibbs	 * in the ccb, that means that the kernel found the device the user
56439209Sgibbs	 * passed in, but was unable to find the passthrough device for
56539209Sgibbs	 * the device the user gave us.
56639209Sgibbs	 */
56739209Sgibbs	if (ccb.cgdl.status == CAM_GDEVLIST_ERROR) {
568132843Sscottl		sprintf(cam_errbuf, "%s: passthrough device does not exist!",
56939209Sgibbs			func_name);
57039209Sgibbs		goto crod_bailout;
57139209Sgibbs	}
57239209Sgibbs
57339209Sgibbs	device->dev_unit_num = ccb.cgdl.unit_number;
57496559Sken	strlcpy(device->device_name, ccb.cgdl.periph_name,
57596559Sken		sizeof(device->device_name));
57639209Sgibbs	device->path_id = ccb.ccb_h.path_id;
57739209Sgibbs	device->target_id = ccb.ccb_h.target_id;
57839209Sgibbs	device->target_lun = ccb.ccb_h.target_lun;
57939209Sgibbs
58039209Sgibbs	ccb.ccb_h.func_code = XPT_PATH_INQ;
58139209Sgibbs	if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
58239209Sgibbs		sprintf(cam_errbuf, "%s: Path Inquiry CCB failed\n"
58339209Sgibbs			"%s: %s", func_name, func_name, strerror(errno));
58439209Sgibbs		goto crod_bailout;
58539209Sgibbs	}
58696559Sken	strlcpy(device->sim_name, ccb.cpi.dev_name, sizeof(device->sim_name));
58739209Sgibbs	device->sim_unit_number = ccb.cpi.unit_number;
58839209Sgibbs	device->bus_id = ccb.cpi.bus_id;
58939209Sgibbs
59039209Sgibbs	/*
59139209Sgibbs	 * It doesn't really matter what is in the payload for a getdev
59239209Sgibbs	 * CCB, the kernel doesn't look at it.
59339209Sgibbs	 */
59439209Sgibbs	ccb.ccb_h.func_code = XPT_GDEV_TYPE;
59539209Sgibbs	if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
59639209Sgibbs		sprintf(cam_errbuf, "%s: Get Device Type CCB failed\n"
59739209Sgibbs			"%s: %s", func_name, func_name, strerror(errno));
59839209Sgibbs		goto crod_bailout;
59939209Sgibbs	}
60056122Smjacob	device->pd_type = SID_TYPE(&ccb.cgd.inq_data);
60139209Sgibbs	bcopy(&ccb.cgd.inq_data, &device->inq_data,
60239209Sgibbs	      sizeof(struct scsi_inquiry_data));
60339209Sgibbs	device->serial_num_len = ccb.cgd.serial_num_len;
60439209Sgibbs	bcopy(&ccb.cgd.serial_num, &device->serial_num, device->serial_num_len);
60539209Sgibbs
60639209Sgibbs	/*
60739209Sgibbs	 * Zero the payload, the kernel does look at the flags.
60839209Sgibbs	 */
60939209Sgibbs	bzero(&(&ccb.ccb_h)[1], sizeof(struct ccb_trans_settings));
61039209Sgibbs
61139209Sgibbs	/*
61239209Sgibbs	 * Get transfer settings for this device.
61339209Sgibbs	 */
61439209Sgibbs	ccb.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
61539209Sgibbs
616163896Smjacob	ccb.cts.type = CTS_TYPE_CURRENT_SETTINGS;
61739209Sgibbs
61839209Sgibbs	if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
61939209Sgibbs		sprintf(cam_errbuf, "%s: Get Transfer Settings CCB failed\n"
62039209Sgibbs			"%s: %s", func_name, func_name, strerror(errno));
62139209Sgibbs		goto crod_bailout;
62239209Sgibbs	}
623163896Smjacob	if (ccb.cts.protocol == XPORT_SPI) {
624163896Smjacob		struct ccb_trans_settings_spi *spi =
625163896Smjacob		    &ccb.cts.xport_specific.spi;
626163896Smjacob		device->sync_period = spi->sync_period;
627163896Smjacob		device->sync_offset = spi->sync_offset;
628163896Smjacob		device->bus_width = spi->bus_width;
629163896Smjacob	} else {
630163896Smjacob		device->sync_period = 0;
631163896Smjacob		device->sync_offset = 0;
632163896Smjacob		device->bus_width = 0;
633163896Smjacob	}
63439209Sgibbs
63539209Sgibbs	return(device);
63639209Sgibbs
63739209Sgibbscrod_bailout:
63839209Sgibbs
63979183Smjacob	if (fd >= 0)
64079183Smjacob		close(fd);
64179183Smjacob
64239209Sgibbs	if (malloced_device)
64339209Sgibbs		free(device);
64439209Sgibbs
64539209Sgibbs	return(NULL);
64639209Sgibbs}
64739209Sgibbs
64839209Sgibbsvoid
64939209Sgibbscam_close_device(struct cam_device *dev)
65039209Sgibbs{
65139209Sgibbs	if (dev == NULL)
65239209Sgibbs		return;
65339209Sgibbs
65439209Sgibbs	cam_close_spec_device(dev);
65539209Sgibbs
656147949Sdelphij	free(dev);
65739209Sgibbs}
65839209Sgibbs
65939209Sgibbsvoid
66039209Sgibbscam_close_spec_device(struct cam_device *dev)
66139209Sgibbs{
66239209Sgibbs	if (dev == NULL)
66339209Sgibbs		return;
66439209Sgibbs
66539209Sgibbs	if (dev->fd >= 0)
66639209Sgibbs		close(dev->fd);
66739209Sgibbs}
66839209Sgibbs
66939209Sgibbschar *
67039209Sgibbscam_path_string(struct cam_device *dev, char *str, int len)
67139209Sgibbs{
67239209Sgibbs	if (dev == NULL) {
67339209Sgibbs		snprintf(str, len, "No path");
67439209Sgibbs		return(str);
67539209Sgibbs	}
67639209Sgibbs
67739209Sgibbs	snprintf(str, len, "(%s%d:%s%d:%d:%d:%d): ",
67839209Sgibbs		 (dev->device_name[0] != '\0') ? dev->device_name : "pass",
67939209Sgibbs		 dev->dev_unit_num,
68039209Sgibbs		 (dev->sim_name[0] != '\0') ? dev->sim_name : "unknown",
68139209Sgibbs		 dev->sim_unit_number,
68239209Sgibbs		 dev->bus_id,
68339209Sgibbs		 dev->target_id,
68439209Sgibbs		 dev->target_lun);
68539209Sgibbs
68639209Sgibbs	return(str);
68739209Sgibbs}
68839209Sgibbs
68939209Sgibbs/*
69039209Sgibbs * Malloc/duplicate a CAM device structure.
69139209Sgibbs */
69239209Sgibbsstruct cam_device *
69339209Sgibbscam_device_dup(struct cam_device *device)
69439209Sgibbs{
69539209Sgibbs	char *func_name = "cam_device_dup";
69639209Sgibbs	struct cam_device *newdev;
69739209Sgibbs
69839209Sgibbs	if (device == NULL) {
69939209Sgibbs		sprintf(cam_errbuf, "%s: device is NULL", func_name);
70039209Sgibbs		return(NULL);
70139209Sgibbs	}
70239209Sgibbs
70339209Sgibbs	newdev = malloc(sizeof(struct cam_device));
704147949Sdelphij	if (newdev == NULL) {
705147949Sdelphij		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
706147949Sdelphij			"%s: couldn't malloc CAM device structure", func_name);
707147949Sdelphij		return(NULL);
708147949Sdelphij	}
70939209Sgibbs
71039209Sgibbs	bcopy(device, newdev, sizeof(struct cam_device));
71139209Sgibbs
71239209Sgibbs	return(newdev);
71339209Sgibbs}
71439209Sgibbs
71539209Sgibbs/*
71639209Sgibbs * Copy a CAM device structure.
71739209Sgibbs */
71839209Sgibbsvoid
71939209Sgibbscam_device_copy(struct cam_device *src, struct cam_device *dst)
72039209Sgibbs{
72139209Sgibbs	char *func_name = "cam_device_copy";
72239209Sgibbs
72339209Sgibbs	if (src == NULL) {
72439209Sgibbs		sprintf(cam_errbuf, "%s: source device struct was NULL",
72539209Sgibbs			func_name);
72639209Sgibbs		return;
72739209Sgibbs	}
72839209Sgibbs
72939209Sgibbs	if (dst == NULL) {
73039209Sgibbs		sprintf(cam_errbuf, "%s: destination device struct was NULL",
73139209Sgibbs			func_name);
73239209Sgibbs		return;
73339209Sgibbs	}
73439209Sgibbs
73539209Sgibbs	bcopy(src, dst, sizeof(struct cam_device));
73639209Sgibbs
73739209Sgibbs}
738