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$");
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) {
124233755Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
125233755Sjh			 "%s: device pathname was NULL", func_name);
12647933Smpp		return(-1);
12739209Sgibbs	}
12839209Sgibbs
12939209Sgibbs	/*
13039209Sgibbs	 * We can be rather destructive to the path string.  Make a copy of
13139209Sgibbs	 * it so we don't hose the user's string.
13239209Sgibbs	 */
13339209Sgibbs	newpath = (char *)strdup(path);
13439209Sgibbs	tmpstr = newpath;
13539209Sgibbs
13639209Sgibbs	/*
13739209Sgibbs	 * Check to see whether we have an absolute pathname.
13839209Sgibbs	 */
13939209Sgibbs	if (*tmpstr == '/') {
14039209Sgibbs		tmpstr2 = tmpstr;
14139209Sgibbs		tmpstr = (char *)rindex(tmpstr2, '/');
14239209Sgibbs		if ((tmpstr != NULL) && (*tmpstr != '\0'))
14339209Sgibbs			tmpstr++;
14439209Sgibbs	}
14539209Sgibbs
14639209Sgibbs	if (*tmpstr == '\0') {
147233755Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
148233755Sjh			 "%s: no text after slash", func_name);
14939209Sgibbs		free(newpath);
15047933Smpp		return(-1);
15139209Sgibbs	}
15239209Sgibbs
15339209Sgibbs	/*
15439209Sgibbs	 * Check to see whether the user has given us a nonrewound tape
15539209Sgibbs	 * device.
15639209Sgibbs	 */
157213682Savg	if (*tmpstr == 'n' || *tmpstr == 'e') {
158213682Savg		for (i = 0; i < sizeof(nonrewind_devs)/sizeof(char *); i++) {
159213682Savg			int len = strlen(nonrewind_devs[i]);
160213682Savg			if (strncmp(tmpstr + 1, nonrewind_devs[i], len) == 0) {
161213682Savg				if (isdigit(tmpstr[len + 1])) {
162213682Savg					tmpstr++;
163213682Savg					break;
164213682Savg				}
165213682Savg			}
16639209Sgibbs		}
16739209Sgibbs	}
16839209Sgibbs
16939209Sgibbs	/*
170213703Savg	 * We should now have just a device name and unit number.
171213703Savg	 * That means that there must be at least 2 characters.
172213703Savg	 * If we only have 1, we don't have a valid device name.
17339209Sgibbs	 */
17439209Sgibbs	if (strlen(tmpstr) < 2) {
175233755Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
176233755Sjh			 "%s: must have both device name and unit number",
177233755Sjh			 func_name);
17839209Sgibbs		free(newpath);
17947933Smpp		return(-1);
18039209Sgibbs	}
18139209Sgibbs
18239209Sgibbs	/*
18339209Sgibbs	 * If the first character of the string is a digit, then the user
18439209Sgibbs	 * has probably given us all numbers.  Point out the error.
18539209Sgibbs	 */
18639209Sgibbs	if (isdigit(*tmpstr)) {
187233755Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
188233755Sjh			 "%s: device name cannot begin with a number",
189233755Sjh			 func_name);
19039209Sgibbs		free(newpath);
19147933Smpp		return(-1);
19239209Sgibbs	}
19339209Sgibbs
19439209Sgibbs	/*
19539209Sgibbs	 * At this point, if the last character of the string isn't a
19639209Sgibbs	 * number, we know the user either didn't give us a device number,
19739209Sgibbs	 * or he gave us a device name/number format we don't recognize.
19839209Sgibbs	 */
19939209Sgibbs	if (!isdigit(tmpstr[strlen(tmpstr) - 1])) {
200233755Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
201233755Sjh			 "%s: unable to find device unit number", func_name);
20239209Sgibbs		free(newpath);
20347933Smpp		return(-1);
20439209Sgibbs	}
20539209Sgibbs
20639209Sgibbs	/*
20739209Sgibbs	 * Attempt to figure out where the device name ends and the unit
20839209Sgibbs	 * number begins.  As long as unit_offset is at least 1 less than
20939209Sgibbs	 * the length of the string, we can still potentially have a device
21039209Sgibbs	 * name at the front of the string.  When we get to something that
21139209Sgibbs	 * isn't a digit, we've hit the device name.  Because of the check
21239209Sgibbs	 * above, we know that this cannot happen when unit_offset == 1.
21339209Sgibbs	 * Therefore it is okay to decrement unit_offset -- it won't cause
21439209Sgibbs	 * us to go past the end of the character array.
21539209Sgibbs	 */
21639209Sgibbs	for (unit_offset = 1;
21739209Sgibbs	    (unit_offset < (strlen(tmpstr)))
21839209Sgibbs	    && (isdigit(tmpstr[strlen(tmpstr) - unit_offset])); unit_offset++);
21939209Sgibbs
22039209Sgibbs	unit_offset--;
22139209Sgibbs
22239209Sgibbs	/*
22339209Sgibbs	 * Grab the unit number.
22439209Sgibbs	 */
22539209Sgibbs	*unit = atoi(&tmpstr[strlen(tmpstr) - unit_offset]);
22639209Sgibbs
22739209Sgibbs	/*
22839209Sgibbs	 * Put a null in place of the first number of the unit number so
22939209Sgibbs	 * that all we have left is the device name.
23039209Sgibbs	 */
23139209Sgibbs	tmpstr[strlen(tmpstr) - unit_offset] = '\0';
23239209Sgibbs
233213682Savg	strlcpy(dev_name, tmpstr, devnamelen);
23439209Sgibbs
23539209Sgibbs	/* Clean up allocated memory */
23639209Sgibbs	free(newpath);
23739209Sgibbs
23847933Smpp	return(0);
23939209Sgibbs
24039209Sgibbs}
24139209Sgibbs
24239209Sgibbs/*
24339209Sgibbs * Backwards compatible wrapper for the real open routine.  This translates
24439209Sgibbs * a pathname into a device name and unit number for use with the real open
24539209Sgibbs * routine.
24639209Sgibbs */
24739209Sgibbsstruct cam_device *
24839209Sgibbscam_open_device(const char *path, int flags)
24939209Sgibbs{
25039209Sgibbs	int unit;
25139209Sgibbs	char dev_name[DEV_IDLEN + 1];
25239209Sgibbs
25339209Sgibbs	/*
25439209Sgibbs	 * cam_get_device() has already put an error message in cam_errbuf,
25539209Sgibbs	 * so we don't need to.
25639209Sgibbs	 */
25796559Sken	if (cam_get_device(path, dev_name, sizeof(dev_name), &unit) == -1)
25839209Sgibbs		return(NULL);
25939209Sgibbs
26039209Sgibbs	return(cam_lookup_pass(dev_name, unit, flags, path, NULL));
26139209Sgibbs}
26239209Sgibbs
26339209Sgibbs/*
26439209Sgibbs * Open the passthrough device for a given bus, target and lun, if the
26539209Sgibbs * passthrough device exists.
26639209Sgibbs */
26739209Sgibbsstruct cam_device *
26839209Sgibbscam_open_btl(path_id_t path_id, target_id_t target_id, lun_id_t target_lun,
26939209Sgibbs	     int flags, struct cam_device *device)
27039209Sgibbs{
27139209Sgibbs	union ccb ccb;
27239209Sgibbs	struct periph_match_pattern *match_pat;
27339209Sgibbs	char *func_name = "cam_open_btl";
27439209Sgibbs	int fd, bufsize;
27539209Sgibbs
27639209Sgibbs	if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
27739209Sgibbs		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
27839209Sgibbs			 "%s: couldn't open %s\n%s: %s", func_name, XPT_DEVICE,
27939209Sgibbs			 func_name, strerror(errno));
28039209Sgibbs		return(NULL);
28139209Sgibbs	}
28239209Sgibbs
28339209Sgibbs	bzero(&ccb, sizeof(union ccb));
28439209Sgibbs	ccb.ccb_h.func_code = XPT_DEV_MATCH;
285184379Smarius	ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
286184379Smarius	ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
287184379Smarius	ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
28839209Sgibbs
28939209Sgibbs	/* Setup the result buffer */
29039209Sgibbs	bufsize = sizeof(struct dev_match_result);
29139209Sgibbs	ccb.cdm.match_buf_len = bufsize;
29239209Sgibbs	ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
29339209Sgibbs	if (ccb.cdm.matches == NULL) {
29439209Sgibbs		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
29539209Sgibbs			 "%s: couldn't malloc match buffer", func_name);
29651213Sken		close(fd);
29739209Sgibbs		return(NULL);
29839209Sgibbs	}
29939209Sgibbs	ccb.cdm.num_matches = 0;
30039209Sgibbs
30139209Sgibbs	/* Setup the pattern buffer */
30239209Sgibbs	ccb.cdm.num_patterns = 1;
30339209Sgibbs	ccb.cdm.pattern_buf_len = sizeof(struct dev_match_pattern);
30439209Sgibbs	ccb.cdm.patterns = (struct dev_match_pattern *)malloc(
30539209Sgibbs		sizeof(struct dev_match_pattern));
30639209Sgibbs	if (ccb.cdm.patterns == NULL) {
30739209Sgibbs		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
30839209Sgibbs			 "%s: couldn't malloc pattern buffer", func_name);
30939209Sgibbs		free(ccb.cdm.matches);
31051213Sken		close(fd);
31139209Sgibbs		return(NULL);
31239209Sgibbs	}
31339209Sgibbs	ccb.cdm.patterns[0].type = DEV_MATCH_PERIPH;
31439209Sgibbs	match_pat = &ccb.cdm.patterns[0].pattern.periph_pattern;
31539209Sgibbs
31639209Sgibbs	/*
31739209Sgibbs	 * We're looking for the passthrough device associated with this
31839209Sgibbs	 * particular bus/target/lun.
31939209Sgibbs	 */
32039209Sgibbs	sprintf(match_pat->periph_name, "pass");
32139209Sgibbs	match_pat->path_id = path_id;
32239209Sgibbs	match_pat->target_id = target_id;
32339209Sgibbs	match_pat->target_lun = target_lun;
32439209Sgibbs	/* Now set the flags to indicate what we're looking for. */
32539209Sgibbs	match_pat->flags = PERIPH_MATCH_PATH | PERIPH_MATCH_TARGET |
32639209Sgibbs			   PERIPH_MATCH_LUN | PERIPH_MATCH_NAME;
32739209Sgibbs
32839209Sgibbs	if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
329233755Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
330233755Sjh			 "%s: CAMIOCOMMAND ioctl failed\n"
331233755Sjh			 "%s: %s", func_name, func_name, strerror(errno));
33239209Sgibbs		goto btl_bailout;
33339209Sgibbs	}
33439209Sgibbs
33539209Sgibbs	/*
33639209Sgibbs	 * Check for an outright error.
33739209Sgibbs	 */
33839209Sgibbs	if ((ccb.ccb_h.status != CAM_REQ_CMP)
33939209Sgibbs	 || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
34039209Sgibbs	   && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
341233755Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
342233755Sjh			 "%s: CAM error %#x, CDM error %d "
343233755Sjh			 "returned from XPT_DEV_MATCH ccb", func_name,
344233755Sjh			 ccb.ccb_h.status, ccb.cdm.status);
34539209Sgibbs		goto btl_bailout;
34639209Sgibbs	}
34739209Sgibbs
34839209Sgibbs	if (ccb.cdm.status == CAM_DEV_MATCH_MORE) {
349233755Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
350233755Sjh			 "%s: CDM reported more than one"
351233755Sjh			 " passthrough device at %d:%d:%d!!\n",
352233755Sjh			 func_name, path_id, target_id, target_lun);
35339209Sgibbs		goto btl_bailout;
35439209Sgibbs	}
35539209Sgibbs
35639209Sgibbs	if (ccb.cdm.num_matches == 0) {
357233755Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
358233755Sjh			 "%s: no passthrough device found at"
359233755Sjh			 " %d:%d:%d", func_name, path_id, target_id,
360233755Sjh			 target_lun);
36139209Sgibbs		goto btl_bailout;
36239209Sgibbs	}
36339209Sgibbs
36439209Sgibbs	switch(ccb.cdm.matches[0].type) {
36539209Sgibbs	case DEV_MATCH_PERIPH: {
36639209Sgibbs		int pass_unit;
36739209Sgibbs		char dev_path[256];
36839209Sgibbs		struct periph_match_result *periph_result;
36939209Sgibbs
37039209Sgibbs		periph_result = &ccb.cdm.matches[0].result.periph_result;
37139209Sgibbs		pass_unit = periph_result->unit_number;
37239209Sgibbs		free(ccb.cdm.matches);
37339209Sgibbs		free(ccb.cdm.patterns);
37451213Sken		close(fd);
37539209Sgibbs		sprintf(dev_path, "/dev/pass%d", pass_unit);
37639209Sgibbs		return(cam_real_open_device(dev_path, flags, device, NULL,
37739209Sgibbs					    NULL, 0));
37839209Sgibbs		break; /* NOTREACHED */
37939209Sgibbs	}
38039209Sgibbs	default:
381233755Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
382233755Sjh			 "%s: asked for a peripheral match, but"
383233755Sjh			 " got a bus or device match", func_name);
38439209Sgibbs		goto btl_bailout;
38539209Sgibbs		break; /* NOTREACHED */
38639209Sgibbs	}
38739209Sgibbs
38839209Sgibbsbtl_bailout:
38939209Sgibbs	free(ccb.cdm.matches);
39039209Sgibbs	free(ccb.cdm.patterns);
39151213Sken	close(fd);
39239209Sgibbs	return(NULL);
39339209Sgibbs}
39439209Sgibbs
39539209Sgibbsstruct cam_device *
39639209Sgibbscam_open_spec_device(const char *dev_name, int unit, int flags,
39739209Sgibbs		     struct cam_device *device)
39839209Sgibbs{
39939209Sgibbs	return(cam_lookup_pass(dev_name, unit, flags, NULL, device));
40039209Sgibbs}
40139209Sgibbs
40239209Sgibbsstruct cam_device *
40339209Sgibbscam_open_pass(const char *path, int flags, struct cam_device *device)
40439209Sgibbs{
40539209Sgibbs	return(cam_real_open_device(path, flags, device, path, NULL, 0));
40639209Sgibbs}
40739209Sgibbs
40839209Sgibbsstatic struct cam_device *
40939209Sgibbscam_lookup_pass(const char *dev_name, int unit, int flags,
41039209Sgibbs		const char *given_path, struct cam_device *device)
41139209Sgibbs{
412158171Smarcus	int fd;
41339209Sgibbs	union ccb ccb;
41439209Sgibbs	char dev_path[256];
41539209Sgibbs	char *func_name = "cam_lookup_pass";
41639209Sgibbs
41739209Sgibbs	/*
41839209Sgibbs	 * The flags argument above only applies to the actual passthrough
41939209Sgibbs	 * device open, not our open of the given device to find the
42039209Sgibbs	 * passthrough device.
42139209Sgibbs	 */
42239209Sgibbs	if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
42339209Sgibbs		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
42439209Sgibbs			 "%s: couldn't open %s\n%s: %s", func_name, XPT_DEVICE,
42539209Sgibbs			 func_name, strerror(errno));
42639209Sgibbs		return(NULL);
42739209Sgibbs	}
42839209Sgibbs
42939209Sgibbs	/* This isn't strictly necessary for the GETPASSTHRU ioctl. */
43039209Sgibbs	ccb.ccb_h.func_code = XPT_GDEVLIST;
43139209Sgibbs
43239209Sgibbs	/* These two are necessary for the GETPASSTHRU ioctl to work. */
43396559Sken	strlcpy(ccb.cgdl.periph_name, dev_name, sizeof(ccb.cgdl.periph_name));
43439209Sgibbs	ccb.cgdl.unit_number = unit;
43539209Sgibbs
43639209Sgibbs	/*
43739209Sgibbs	 * Attempt to get the passthrough device.  This ioctl will fail if
43840271Sken	 * the device name is null, if the device doesn't exist, or if the
43940271Sken	 * passthrough driver isn't in the kernel.
44039209Sgibbs	 */
441158171Smarcus	if (ioctl(fd, CAMGETPASSTHRU, &ccb) == -1) {
44240271Sken		char tmpstr[256];
44340271Sken
44440271Sken		/*
44540271Sken		 * If we get ENOENT from the transport layer version of
44640271Sken		 * the CAMGETPASSTHRU ioctl, it means one of two things:
44740271Sken		 * either the device name/unit number passed in doesn't
44840271Sken		 * exist, or the passthrough driver isn't in the kernel.
44940271Sken		 */
45040271Sken		if (errno == ENOENT) {
45140271Sken			snprintf(tmpstr, sizeof(tmpstr),
45240271Sken				 "\n%s: either the pass driver isn't in "
45340271Sken				 "your kernel\n%s: or %s%d doesn't exist",
45440271Sken				 func_name, func_name, dev_name, unit);
45540271Sken		}
456233755Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
45740271Sken			 "%s: CAMGETPASSTHRU ioctl failed\n"
45840271Sken			 "%s: %s%s", func_name, func_name, strerror(errno),
45940271Sken			 (errno == ENOENT) ? tmpstr : "");
46040271Sken
461158171Smarcus		close(fd);
46239209Sgibbs		return(NULL);
46339209Sgibbs	}
46439209Sgibbs
465158171Smarcus	close(fd);
466158171Smarcus
46739209Sgibbs	/*
46839209Sgibbs	 * If the ioctl returned the right status, but we got an error back
46939209Sgibbs	 * in the ccb, that means that the kernel found the device the user
47039209Sgibbs	 * passed in, but was unable to find the passthrough device for
47139209Sgibbs	 * the device the user gave us.
47239209Sgibbs	 */
47339209Sgibbs	if (ccb.cgdl.status == CAM_GDEVLIST_ERROR) {
474233755Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
475233755Sjh			 "%s: device %s%d does not exist!",
476233755Sjh			 func_name, dev_name, unit);
47739209Sgibbs		return(NULL);
47839209Sgibbs	}
47939209Sgibbs
48039209Sgibbs	sprintf(dev_path, "/dev/%s%d", ccb.cgdl.periph_name,
48139209Sgibbs		ccb.cgdl.unit_number);
48239209Sgibbs
48339209Sgibbs	return(cam_real_open_device(dev_path, flags, device, NULL,
48439209Sgibbs				    dev_name, unit));
48539209Sgibbs}
48639209Sgibbs
48739209Sgibbs/*
48839209Sgibbs * Open a given device.  The path argument isn't strictly necessary, but it
48939209Sgibbs * is copied into the cam_device structure as a convenience to the user.
49039209Sgibbs */
49139209Sgibbsstatic struct cam_device *
49239209Sgibbscam_real_open_device(const char *path, int flags, struct cam_device *device,
49339209Sgibbs		     const char *given_path, const char *given_dev_name,
49439209Sgibbs		     int given_unit_number)
49539209Sgibbs{
49639209Sgibbs	char *func_name = "cam_real_open_device";
49739209Sgibbs	union ccb ccb;
49879183Smjacob	int fd = -1, malloced_device = 0;
49939209Sgibbs
50039209Sgibbs	/*
50139209Sgibbs	 * See if the user wants us to malloc a device for him.
50239209Sgibbs	 */
50339209Sgibbs	if (device == NULL) {
50439209Sgibbs		if ((device = (struct cam_device *)malloc(
50539209Sgibbs		     sizeof(struct cam_device))) == NULL) {
506233755Sjh			snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
507233755Sjh				 "%s: device structure malloc"
508233755Sjh				 " failed\n%s: %s", func_name, func_name,
509233755Sjh				 strerror(errno));
51039209Sgibbs			return(NULL);
51139209Sgibbs		}
51279183Smjacob		device->fd = -1;
51339209Sgibbs		malloced_device = 1;
51439209Sgibbs	}
51539209Sgibbs
51639209Sgibbs	/*
51739209Sgibbs	 * If the user passed in a path, save it for him.
51839209Sgibbs	 */
51939209Sgibbs	if (given_path != NULL)
52096559Sken		strlcpy(device->device_path, given_path,
52196559Sken			sizeof(device->device_path));
52239209Sgibbs	else
52339209Sgibbs		device->device_path[0] = '\0';
52439209Sgibbs
52539209Sgibbs	/*
52639209Sgibbs	 * If the user passed in a device name and unit number pair, save
52739209Sgibbs	 * those as well.
52839209Sgibbs	 */
52939209Sgibbs	if (given_dev_name != NULL)
53096559Sken		strlcpy(device->given_dev_name, given_dev_name,
53196559Sken			sizeof(device->given_dev_name));
53239209Sgibbs	else
53339209Sgibbs		device->given_dev_name[0] = '\0';
53439209Sgibbs	device->given_unit_number = given_unit_number;
53539209Sgibbs
53639209Sgibbs	if ((fd = open(path, flags)) < 0) {
53741190Sken		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
53841190Sken			 "%s: couldn't open passthrough device %s\n"
53941190Sken			 "%s: %s", func_name, path, func_name,
54041190Sken			 strerror(errno));
54139209Sgibbs		goto crod_bailout;
54239209Sgibbs	}
54339209Sgibbs
54439209Sgibbs	device->fd = fd;
54539209Sgibbs
54639209Sgibbs	bzero(&ccb, sizeof(union ccb));
54739209Sgibbs
54839209Sgibbs	/*
54939209Sgibbs	 * Unlike the transport layer version of the GETPASSTHRU ioctl,
55039209Sgibbs	 * we don't have to set any fields.
55139209Sgibbs	 */
55239209Sgibbs	ccb.ccb_h.func_code = XPT_GDEVLIST;
55339209Sgibbs
55439209Sgibbs	/*
55539209Sgibbs	 * We're only doing this to get some information on the device in
55639209Sgibbs	 * question.  Otherwise, we'd have to pass in yet another
55739209Sgibbs	 * parameter: the passthrough driver unit number.
55839209Sgibbs	 */
55939209Sgibbs	if (ioctl(fd, CAMGETPASSTHRU, &ccb) == -1) {
56040271Sken		/*
56140271Sken		 * At this point we know the passthrough device must exist
56240271Sken		 * because we just opened it above.  The only way this
56340271Sken		 * ioctl can fail is if the ccb size is wrong.
56440271Sken		 */
565233755Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
566233755Sjh			 "%s: CAMGETPASSTHRU ioctl failed\n"
567233755Sjh			 "%s: %s", func_name, func_name, strerror(errno));
56839209Sgibbs		goto crod_bailout;
56939209Sgibbs	}
57039209Sgibbs
57139209Sgibbs	/*
57239209Sgibbs	 * If the ioctl returned the right status, but we got an error back
57339209Sgibbs	 * in the ccb, that means that the kernel found the device the user
57439209Sgibbs	 * passed in, but was unable to find the passthrough device for
57539209Sgibbs	 * the device the user gave us.
57639209Sgibbs	 */
57739209Sgibbs	if (ccb.cgdl.status == CAM_GDEVLIST_ERROR) {
578233755Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
579233755Sjh			 "%s: passthrough device does not exist!", func_name);
58039209Sgibbs		goto crod_bailout;
58139209Sgibbs	}
58239209Sgibbs
58339209Sgibbs	device->dev_unit_num = ccb.cgdl.unit_number;
58496559Sken	strlcpy(device->device_name, ccb.cgdl.periph_name,
58596559Sken		sizeof(device->device_name));
58639209Sgibbs	device->path_id = ccb.ccb_h.path_id;
58739209Sgibbs	device->target_id = ccb.ccb_h.target_id;
58839209Sgibbs	device->target_lun = ccb.ccb_h.target_lun;
58939209Sgibbs
59039209Sgibbs	ccb.ccb_h.func_code = XPT_PATH_INQ;
59139209Sgibbs	if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
592233755Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
593233755Sjh			 "%s: Path Inquiry CCB failed\n"
594233755Sjh			 "%s: %s", func_name, func_name, strerror(errno));
59539209Sgibbs		goto crod_bailout;
59639209Sgibbs	}
59796559Sken	strlcpy(device->sim_name, ccb.cpi.dev_name, sizeof(device->sim_name));
59839209Sgibbs	device->sim_unit_number = ccb.cpi.unit_number;
59939209Sgibbs	device->bus_id = ccb.cpi.bus_id;
60039209Sgibbs
60139209Sgibbs	/*
60239209Sgibbs	 * It doesn't really matter what is in the payload for a getdev
60339209Sgibbs	 * CCB, the kernel doesn't look at it.
60439209Sgibbs	 */
60539209Sgibbs	ccb.ccb_h.func_code = XPT_GDEV_TYPE;
60639209Sgibbs	if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
607233755Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
608233755Sjh			 "%s: Get Device Type CCB failed\n"
609233755Sjh			 "%s: %s", func_name, func_name, strerror(errno));
61039209Sgibbs		goto crod_bailout;
61139209Sgibbs	}
61256122Smjacob	device->pd_type = SID_TYPE(&ccb.cgd.inq_data);
61339209Sgibbs	bcopy(&ccb.cgd.inq_data, &device->inq_data,
61439209Sgibbs	      sizeof(struct scsi_inquiry_data));
61539209Sgibbs	device->serial_num_len = ccb.cgd.serial_num_len;
61639209Sgibbs	bcopy(&ccb.cgd.serial_num, &device->serial_num, device->serial_num_len);
61739209Sgibbs
61839209Sgibbs	/*
61939209Sgibbs	 * Zero the payload, the kernel does look at the flags.
62039209Sgibbs	 */
62139209Sgibbs	bzero(&(&ccb.ccb_h)[1], sizeof(struct ccb_trans_settings));
62239209Sgibbs
62339209Sgibbs	/*
62439209Sgibbs	 * Get transfer settings for this device.
62539209Sgibbs	 */
62639209Sgibbs	ccb.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
62739209Sgibbs
628163896Smjacob	ccb.cts.type = CTS_TYPE_CURRENT_SETTINGS;
62939209Sgibbs
63039209Sgibbs	if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
631233755Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
632233755Sjh			 "%s: Get Transfer Settings CCB failed\n"
633233755Sjh			 "%s: %s", func_name, func_name, strerror(errno));
63439209Sgibbs		goto crod_bailout;
63539209Sgibbs	}
636251891Sdelphij	if (ccb.cts.transport == XPORT_SPI) {
637163896Smjacob		struct ccb_trans_settings_spi *spi =
638163896Smjacob		    &ccb.cts.xport_specific.spi;
639163896Smjacob		device->sync_period = spi->sync_period;
640163896Smjacob		device->sync_offset = spi->sync_offset;
641163896Smjacob		device->bus_width = spi->bus_width;
642163896Smjacob	} else {
643163896Smjacob		device->sync_period = 0;
644163896Smjacob		device->sync_offset = 0;
645163896Smjacob		device->bus_width = 0;
646163896Smjacob	}
64739209Sgibbs
64839209Sgibbs	return(device);
64939209Sgibbs
65039209Sgibbscrod_bailout:
65139209Sgibbs
65279183Smjacob	if (fd >= 0)
65379183Smjacob		close(fd);
65479183Smjacob
65539209Sgibbs	if (malloced_device)
65639209Sgibbs		free(device);
65739209Sgibbs
65839209Sgibbs	return(NULL);
65939209Sgibbs}
66039209Sgibbs
66139209Sgibbsvoid
66239209Sgibbscam_close_device(struct cam_device *dev)
66339209Sgibbs{
66439209Sgibbs	if (dev == NULL)
66539209Sgibbs		return;
66639209Sgibbs
66739209Sgibbs	cam_close_spec_device(dev);
66839209Sgibbs
669147949Sdelphij	free(dev);
67039209Sgibbs}
67139209Sgibbs
67239209Sgibbsvoid
67339209Sgibbscam_close_spec_device(struct cam_device *dev)
67439209Sgibbs{
67539209Sgibbs	if (dev == NULL)
67639209Sgibbs		return;
67739209Sgibbs
67839209Sgibbs	if (dev->fd >= 0)
67939209Sgibbs		close(dev->fd);
68039209Sgibbs}
68139209Sgibbs
68239209Sgibbschar *
68339209Sgibbscam_path_string(struct cam_device *dev, char *str, int len)
68439209Sgibbs{
68539209Sgibbs	if (dev == NULL) {
68639209Sgibbs		snprintf(str, len, "No path");
68739209Sgibbs		return(str);
68839209Sgibbs	}
68939209Sgibbs
69039209Sgibbs	snprintf(str, len, "(%s%d:%s%d:%d:%d:%d): ",
69139209Sgibbs		 (dev->device_name[0] != '\0') ? dev->device_name : "pass",
69239209Sgibbs		 dev->dev_unit_num,
69339209Sgibbs		 (dev->sim_name[0] != '\0') ? dev->sim_name : "unknown",
69439209Sgibbs		 dev->sim_unit_number,
69539209Sgibbs		 dev->bus_id,
69639209Sgibbs		 dev->target_id,
69739209Sgibbs		 dev->target_lun);
69839209Sgibbs
69939209Sgibbs	return(str);
70039209Sgibbs}
70139209Sgibbs
70239209Sgibbs/*
70339209Sgibbs * Malloc/duplicate a CAM device structure.
70439209Sgibbs */
70539209Sgibbsstruct cam_device *
70639209Sgibbscam_device_dup(struct cam_device *device)
70739209Sgibbs{
70839209Sgibbs	char *func_name = "cam_device_dup";
70939209Sgibbs	struct cam_device *newdev;
71039209Sgibbs
71139209Sgibbs	if (device == NULL) {
712233755Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
713233755Sjh			 "%s: device is NULL", func_name);
71439209Sgibbs		return(NULL);
71539209Sgibbs	}
71639209Sgibbs
71739209Sgibbs	newdev = malloc(sizeof(struct cam_device));
718147949Sdelphij	if (newdev == NULL) {
719147949Sdelphij		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
720147949Sdelphij			"%s: couldn't malloc CAM device structure", func_name);
721147949Sdelphij		return(NULL);
722147949Sdelphij	}
72339209Sgibbs
72439209Sgibbs	bcopy(device, newdev, sizeof(struct cam_device));
72539209Sgibbs
72639209Sgibbs	return(newdev);
72739209Sgibbs}
72839209Sgibbs
72939209Sgibbs/*
73039209Sgibbs * Copy a CAM device structure.
73139209Sgibbs */
73239209Sgibbsvoid
73339209Sgibbscam_device_copy(struct cam_device *src, struct cam_device *dst)
73439209Sgibbs{
73539209Sgibbs	char *func_name = "cam_device_copy";
73639209Sgibbs
73739209Sgibbs	if (src == NULL) {
738233755Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
739233755Sjh			 "%s: source device struct was NULL", func_name);
74039209Sgibbs		return;
74139209Sgibbs	}
74239209Sgibbs
74339209Sgibbs	if (dst == NULL) {
744233755Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
745233755Sjh			 "%s: destination device struct was NULL", func_name);
74639209Sgibbs		return;
74739209Sgibbs	}
74839209Sgibbs
74939209Sgibbs	bcopy(src, dst, sizeof(struct cam_device));
75039209Sgibbs
75139209Sgibbs}
752