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>
33259204Snwhitehorn#include <stdint.h>
3439209Sgibbs#include <string.h>
3539209Sgibbs#include <fcntl.h>
3639209Sgibbs#include <unistd.h>
3739209Sgibbs#include <errno.h>
3839209Sgibbs#include <ctype.h>
3939209Sgibbs
4039209Sgibbs#include <cam/cam.h>
4139209Sgibbs#include <cam/scsi/scsi_all.h>
4239209Sgibbs#include <cam/cam_ccb.h>
4339209Sgibbs#include <cam/scsi/scsi_pass.h>
4439209Sgibbs#include "camlib.h"
4539209Sgibbs
4639209Sgibbs
47213682Savgstatic const char *nonrewind_devs[] = {
48213682Savg	"sa"
4939209Sgibbs};
5039209Sgibbs
5139209Sgibbschar cam_errbuf[CAM_ERRBUF_SIZE];
5239209Sgibbs
5339209Sgibbsstatic struct cam_device *cam_real_open_device(const char *path, int flags,
5439209Sgibbs					       struct cam_device *device,
5539209Sgibbs					       const char *given_path,
5639209Sgibbs					       const char *given_dev_name,
5739209Sgibbs					       int given_unit_number);
5839209Sgibbsstatic struct cam_device *cam_lookup_pass(const char *dev_name, int unit,
5939209Sgibbs					  int flags, const char *given_path,
6039209Sgibbs					  struct cam_device *device);
6139209Sgibbs
6239209Sgibbs/*
6339209Sgibbs * Send a ccb to a passthrough device.
6439209Sgibbs */
6539209Sgibbsint
6639209Sgibbscam_send_ccb(struct cam_device *device, union ccb *ccb)
6739209Sgibbs{
6839209Sgibbs	return(ioctl(device->fd, CAMIOCOMMAND, ccb));
6939209Sgibbs}
7039209Sgibbs
7139209Sgibbs/*
7239209Sgibbs * Malloc a CCB, zero out the header and set its path, target and lun ids.
7339209Sgibbs */
7439209Sgibbsunion ccb *
7539209Sgibbscam_getccb(struct cam_device *dev)
7639209Sgibbs{
7739209Sgibbs	union ccb *ccb;
7839209Sgibbs
7939209Sgibbs	ccb = (union ccb *)malloc(sizeof(union ccb));
8039209Sgibbs	if (ccb != NULL) {
8139209Sgibbs		bzero(&ccb->ccb_h, sizeof(struct ccb_hdr));
8239209Sgibbs		ccb->ccb_h.path_id = dev->path_id;
8339209Sgibbs		ccb->ccb_h.target_id = dev->target_id;
8439209Sgibbs		ccb->ccb_h.target_lun = dev->target_lun;
8539209Sgibbs	}
8639209Sgibbs
8739209Sgibbs	return(ccb);
8839209Sgibbs}
8939209Sgibbs
9039209Sgibbs/*
9139209Sgibbs * Free a CCB.
9239209Sgibbs */
9339209Sgibbsvoid
9439209Sgibbscam_freeccb(union ccb *ccb)
9539209Sgibbs{
96147949Sdelphij	free(ccb);
9739209Sgibbs}
9839209Sgibbs
9939209Sgibbs/*
10039209Sgibbs * Take a device name or path passed in by the user, and attempt to figure
10139209Sgibbs * out the device name and unit number.  Some possible device name formats are:
102213682Savg * /dev/foo0
10339209Sgibbs * foo0
104213682Savg * nfoo0
10539209Sgibbs *
106213682Savg * Some peripheral drivers create separate device nodes with 'n' prefix for
107213682Savg * non-rewind operations.  Currently only sa(4) tape driver has this feature.
108213682Savg * We extract pure peripheral name as device name for this special case.
109213682Savg *
11039209Sgibbs * Input parameters:  device name/path, length of devname string
11139209Sgibbs * Output:            device name, unit number
11239209Sgibbs * Return values:     returns 0 for success, -1 for failure
11339209Sgibbs */
11439209Sgibbsint
11539209Sgibbscam_get_device(const char *path, char *dev_name, int devnamelen, int *unit)
11639209Sgibbs{
11739209Sgibbs	char *func_name = "cam_get_device";
11839209Sgibbs	char *tmpstr, *tmpstr2;
11939209Sgibbs	char *newpath;
12039209Sgibbs	int unit_offset;
121213682Savg	int i;
12239209Sgibbs
12339209Sgibbs
12439209Sgibbs	if (path == NULL) {
125232450Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
126232450Sjh			 "%s: device pathname was NULL", func_name);
12747933Smpp		return(-1);
12839209Sgibbs	}
12939209Sgibbs
13039209Sgibbs	/*
13139209Sgibbs	 * We can be rather destructive to the path string.  Make a copy of
13239209Sgibbs	 * it so we don't hose the user's string.
13339209Sgibbs	 */
13439209Sgibbs	newpath = (char *)strdup(path);
13539209Sgibbs	tmpstr = newpath;
13639209Sgibbs
13739209Sgibbs	/*
13839209Sgibbs	 * Check to see whether we have an absolute pathname.
13939209Sgibbs	 */
14039209Sgibbs	if (*tmpstr == '/') {
14139209Sgibbs		tmpstr2 = tmpstr;
142229403Sed		tmpstr = strrchr(tmpstr2, '/');
14339209Sgibbs		if ((tmpstr != NULL) && (*tmpstr != '\0'))
14439209Sgibbs			tmpstr++;
14539209Sgibbs	}
14639209Sgibbs
14739209Sgibbs	if (*tmpstr == '\0') {
148232450Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
149232450Sjh			 "%s: no text after slash", func_name);
15039209Sgibbs		free(newpath);
15147933Smpp		return(-1);
15239209Sgibbs	}
15339209Sgibbs
15439209Sgibbs	/*
15539209Sgibbs	 * Check to see whether the user has given us a nonrewound tape
15639209Sgibbs	 * device.
15739209Sgibbs	 */
158213682Savg	if (*tmpstr == 'n' || *tmpstr == 'e') {
159213682Savg		for (i = 0; i < sizeof(nonrewind_devs)/sizeof(char *); i++) {
160213682Savg			int len = strlen(nonrewind_devs[i]);
161213682Savg			if (strncmp(tmpstr + 1, nonrewind_devs[i], len) == 0) {
162213682Savg				if (isdigit(tmpstr[len + 1])) {
163213682Savg					tmpstr++;
164213682Savg					break;
165213682Savg				}
166213682Savg			}
16739209Sgibbs		}
16839209Sgibbs	}
16939209Sgibbs
17039209Sgibbs	/*
171213703Savg	 * We should now have just a device name and unit number.
172213703Savg	 * That means that there must be at least 2 characters.
173213703Savg	 * If we only have 1, we don't have a valid device name.
17439209Sgibbs	 */
17539209Sgibbs	if (strlen(tmpstr) < 2) {
176232450Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
177232450Sjh			 "%s: must have both device name and unit number",
178232450Sjh			 func_name);
17939209Sgibbs		free(newpath);
18047933Smpp		return(-1);
18139209Sgibbs	}
18239209Sgibbs
18339209Sgibbs	/*
18439209Sgibbs	 * If the first character of the string is a digit, then the user
18539209Sgibbs	 * has probably given us all numbers.  Point out the error.
18639209Sgibbs	 */
18739209Sgibbs	if (isdigit(*tmpstr)) {
188232450Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
189232450Sjh			 "%s: device name cannot begin with a number",
190232450Sjh			 func_name);
19139209Sgibbs		free(newpath);
19247933Smpp		return(-1);
19339209Sgibbs	}
19439209Sgibbs
19539209Sgibbs	/*
19639209Sgibbs	 * At this point, if the last character of the string isn't a
19739209Sgibbs	 * number, we know the user either didn't give us a device number,
19839209Sgibbs	 * or he gave us a device name/number format we don't recognize.
19939209Sgibbs	 */
20039209Sgibbs	if (!isdigit(tmpstr[strlen(tmpstr) - 1])) {
201232450Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
202232450Sjh			 "%s: unable to find device unit number", func_name);
20339209Sgibbs		free(newpath);
20447933Smpp		return(-1);
20539209Sgibbs	}
20639209Sgibbs
20739209Sgibbs	/*
20839209Sgibbs	 * Attempt to figure out where the device name ends and the unit
20939209Sgibbs	 * number begins.  As long as unit_offset is at least 1 less than
21039209Sgibbs	 * the length of the string, we can still potentially have a device
21139209Sgibbs	 * name at the front of the string.  When we get to something that
21239209Sgibbs	 * isn't a digit, we've hit the device name.  Because of the check
21339209Sgibbs	 * above, we know that this cannot happen when unit_offset == 1.
21439209Sgibbs	 * Therefore it is okay to decrement unit_offset -- it won't cause
21539209Sgibbs	 * us to go past the end of the character array.
21639209Sgibbs	 */
21739209Sgibbs	for (unit_offset = 1;
21839209Sgibbs	    (unit_offset < (strlen(tmpstr)))
21939209Sgibbs	    && (isdigit(tmpstr[strlen(tmpstr) - unit_offset])); unit_offset++);
22039209Sgibbs
22139209Sgibbs	unit_offset--;
22239209Sgibbs
22339209Sgibbs	/*
22439209Sgibbs	 * Grab the unit number.
22539209Sgibbs	 */
22639209Sgibbs	*unit = atoi(&tmpstr[strlen(tmpstr) - unit_offset]);
22739209Sgibbs
22839209Sgibbs	/*
22939209Sgibbs	 * Put a null in place of the first number of the unit number so
23039209Sgibbs	 * that all we have left is the device name.
23139209Sgibbs	 */
23239209Sgibbs	tmpstr[strlen(tmpstr) - unit_offset] = '\0';
23339209Sgibbs
234213682Savg	strlcpy(dev_name, tmpstr, devnamelen);
23539209Sgibbs
23639209Sgibbs	/* Clean up allocated memory */
23739209Sgibbs	free(newpath);
23839209Sgibbs
23947933Smpp	return(0);
24039209Sgibbs
24139209Sgibbs}
24239209Sgibbs
24339209Sgibbs/*
24439209Sgibbs * Backwards compatible wrapper for the real open routine.  This translates
24539209Sgibbs * a pathname into a device name and unit number for use with the real open
24639209Sgibbs * routine.
24739209Sgibbs */
24839209Sgibbsstruct cam_device *
24939209Sgibbscam_open_device(const char *path, int flags)
25039209Sgibbs{
25139209Sgibbs	int unit;
25239209Sgibbs	char dev_name[DEV_IDLEN + 1];
25339209Sgibbs
25439209Sgibbs	/*
25539209Sgibbs	 * cam_get_device() has already put an error message in cam_errbuf,
25639209Sgibbs	 * so we don't need to.
25739209Sgibbs	 */
25896559Sken	if (cam_get_device(path, dev_name, sizeof(dev_name), &unit) == -1)
25939209Sgibbs		return(NULL);
26039209Sgibbs
26139209Sgibbs	return(cam_lookup_pass(dev_name, unit, flags, path, NULL));
26239209Sgibbs}
26339209Sgibbs
26439209Sgibbs/*
26539209Sgibbs * Open the passthrough device for a given bus, target and lun, if the
26639209Sgibbs * passthrough device exists.
26739209Sgibbs */
26839209Sgibbsstruct cam_device *
26939209Sgibbscam_open_btl(path_id_t path_id, target_id_t target_id, lun_id_t target_lun,
27039209Sgibbs	     int flags, struct cam_device *device)
27139209Sgibbs{
27239209Sgibbs	union ccb ccb;
27339209Sgibbs	struct periph_match_pattern *match_pat;
27439209Sgibbs	char *func_name = "cam_open_btl";
27539209Sgibbs	int fd, bufsize;
27639209Sgibbs
27739209Sgibbs	if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
27839209Sgibbs		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
27939209Sgibbs			 "%s: couldn't open %s\n%s: %s", func_name, XPT_DEVICE,
28039209Sgibbs			 func_name, strerror(errno));
28139209Sgibbs		return(NULL);
28239209Sgibbs	}
28339209Sgibbs
28439209Sgibbs	bzero(&ccb, sizeof(union ccb));
28539209Sgibbs	ccb.ccb_h.func_code = XPT_DEV_MATCH;
286184379Smarius	ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
287184379Smarius	ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
288184379Smarius	ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
28939209Sgibbs
29039209Sgibbs	/* Setup the result buffer */
29139209Sgibbs	bufsize = sizeof(struct dev_match_result);
29239209Sgibbs	ccb.cdm.match_buf_len = bufsize;
29339209Sgibbs	ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
29439209Sgibbs	if (ccb.cdm.matches == NULL) {
29539209Sgibbs		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
29639209Sgibbs			 "%s: couldn't malloc match buffer", func_name);
29751213Sken		close(fd);
29839209Sgibbs		return(NULL);
29939209Sgibbs	}
30039209Sgibbs	ccb.cdm.num_matches = 0;
30139209Sgibbs
30239209Sgibbs	/* Setup the pattern buffer */
30339209Sgibbs	ccb.cdm.num_patterns = 1;
30439209Sgibbs	ccb.cdm.pattern_buf_len = sizeof(struct dev_match_pattern);
30539209Sgibbs	ccb.cdm.patterns = (struct dev_match_pattern *)malloc(
30639209Sgibbs		sizeof(struct dev_match_pattern));
30739209Sgibbs	if (ccb.cdm.patterns == NULL) {
30839209Sgibbs		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
30939209Sgibbs			 "%s: couldn't malloc pattern buffer", func_name);
31039209Sgibbs		free(ccb.cdm.matches);
31151213Sken		close(fd);
31239209Sgibbs		return(NULL);
31339209Sgibbs	}
31439209Sgibbs	ccb.cdm.patterns[0].type = DEV_MATCH_PERIPH;
31539209Sgibbs	match_pat = &ccb.cdm.patterns[0].pattern.periph_pattern;
31639209Sgibbs
31739209Sgibbs	/*
31839209Sgibbs	 * We're looking for the passthrough device associated with this
31939209Sgibbs	 * particular bus/target/lun.
32039209Sgibbs	 */
32139209Sgibbs	sprintf(match_pat->periph_name, "pass");
32239209Sgibbs	match_pat->path_id = path_id;
32339209Sgibbs	match_pat->target_id = target_id;
32439209Sgibbs	match_pat->target_lun = target_lun;
32539209Sgibbs	/* Now set the flags to indicate what we're looking for. */
32639209Sgibbs	match_pat->flags = PERIPH_MATCH_PATH | PERIPH_MATCH_TARGET |
32739209Sgibbs			   PERIPH_MATCH_LUN | PERIPH_MATCH_NAME;
32839209Sgibbs
32939209Sgibbs	if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
330232450Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
331232450Sjh			 "%s: CAMIOCOMMAND ioctl failed\n"
332232450Sjh			 "%s: %s", func_name, func_name, strerror(errno));
33339209Sgibbs		goto btl_bailout;
33439209Sgibbs	}
33539209Sgibbs
33639209Sgibbs	/*
33739209Sgibbs	 * Check for an outright error.
33839209Sgibbs	 */
33939209Sgibbs	if ((ccb.ccb_h.status != CAM_REQ_CMP)
34039209Sgibbs	 || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
34139209Sgibbs	   && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
342232450Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
343232450Sjh			 "%s: CAM error %#x, CDM error %d "
344232450Sjh			 "returned from XPT_DEV_MATCH ccb", func_name,
345232450Sjh			 ccb.ccb_h.status, ccb.cdm.status);
34639209Sgibbs		goto btl_bailout;
34739209Sgibbs	}
34839209Sgibbs
34939209Sgibbs	if (ccb.cdm.status == CAM_DEV_MATCH_MORE) {
350232450Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
351232450Sjh			 "%s: CDM reported more than one"
352259204Snwhitehorn			 " passthrough device at %d:%d:%jx!!\n",
353259204Snwhitehorn			 func_name, path_id, target_id, (uintmax_t)target_lun);
35439209Sgibbs		goto btl_bailout;
35539209Sgibbs	}
35639209Sgibbs
35739209Sgibbs	if (ccb.cdm.num_matches == 0) {
358232450Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
359232450Sjh			 "%s: no passthrough device found at"
360259204Snwhitehorn			 " %d:%d:%jx", func_name, path_id, target_id,
361259204Snwhitehorn			 (uintmax_t)target_lun);
36239209Sgibbs		goto btl_bailout;
36339209Sgibbs	}
36439209Sgibbs
36539209Sgibbs	switch(ccb.cdm.matches[0].type) {
36639209Sgibbs	case DEV_MATCH_PERIPH: {
36739209Sgibbs		int pass_unit;
36839209Sgibbs		char dev_path[256];
36939209Sgibbs		struct periph_match_result *periph_result;
37039209Sgibbs
37139209Sgibbs		periph_result = &ccb.cdm.matches[0].result.periph_result;
37239209Sgibbs		pass_unit = periph_result->unit_number;
37339209Sgibbs		free(ccb.cdm.matches);
37439209Sgibbs		free(ccb.cdm.patterns);
37551213Sken		close(fd);
37639209Sgibbs		sprintf(dev_path, "/dev/pass%d", pass_unit);
37739209Sgibbs		return(cam_real_open_device(dev_path, flags, device, NULL,
37839209Sgibbs					    NULL, 0));
37939209Sgibbs		break; /* NOTREACHED */
38039209Sgibbs	}
38139209Sgibbs	default:
382232450Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
383232450Sjh			 "%s: asked for a peripheral match, but"
384232450Sjh			 " got a bus or device match", func_name);
38539209Sgibbs		goto btl_bailout;
38639209Sgibbs		break; /* NOTREACHED */
38739209Sgibbs	}
38839209Sgibbs
38939209Sgibbsbtl_bailout:
39039209Sgibbs	free(ccb.cdm.matches);
39139209Sgibbs	free(ccb.cdm.patterns);
39251213Sken	close(fd);
39339209Sgibbs	return(NULL);
39439209Sgibbs}
39539209Sgibbs
39639209Sgibbsstruct cam_device *
39739209Sgibbscam_open_spec_device(const char *dev_name, int unit, int flags,
39839209Sgibbs		     struct cam_device *device)
39939209Sgibbs{
40039209Sgibbs	return(cam_lookup_pass(dev_name, unit, flags, NULL, device));
40139209Sgibbs}
40239209Sgibbs
40339209Sgibbsstruct cam_device *
40439209Sgibbscam_open_pass(const char *path, int flags, struct cam_device *device)
40539209Sgibbs{
40639209Sgibbs	return(cam_real_open_device(path, flags, device, path, NULL, 0));
40739209Sgibbs}
40839209Sgibbs
40939209Sgibbsstatic struct cam_device *
41039209Sgibbscam_lookup_pass(const char *dev_name, int unit, int flags,
41139209Sgibbs		const char *given_path, struct cam_device *device)
41239209Sgibbs{
413158171Smarcus	int fd;
41439209Sgibbs	union ccb ccb;
41539209Sgibbs	char dev_path[256];
41639209Sgibbs	char *func_name = "cam_lookup_pass";
41739209Sgibbs
41839209Sgibbs	/*
41939209Sgibbs	 * The flags argument above only applies to the actual passthrough
42039209Sgibbs	 * device open, not our open of the given device to find the
42139209Sgibbs	 * passthrough device.
42239209Sgibbs	 */
42339209Sgibbs	if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
42439209Sgibbs		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
42539209Sgibbs			 "%s: couldn't open %s\n%s: %s", func_name, XPT_DEVICE,
42639209Sgibbs			 func_name, strerror(errno));
42739209Sgibbs		return(NULL);
42839209Sgibbs	}
42939209Sgibbs
43039209Sgibbs	/* This isn't strictly necessary for the GETPASSTHRU ioctl. */
43139209Sgibbs	ccb.ccb_h.func_code = XPT_GDEVLIST;
43239209Sgibbs
43339209Sgibbs	/* These two are necessary for the GETPASSTHRU ioctl to work. */
43496559Sken	strlcpy(ccb.cgdl.periph_name, dev_name, sizeof(ccb.cgdl.periph_name));
43539209Sgibbs	ccb.cgdl.unit_number = unit;
43639209Sgibbs
43739209Sgibbs	/*
43839209Sgibbs	 * Attempt to get the passthrough device.  This ioctl will fail if
43940271Sken	 * the device name is null, if the device doesn't exist, or if the
44040271Sken	 * passthrough driver isn't in the kernel.
44139209Sgibbs	 */
442158171Smarcus	if (ioctl(fd, CAMGETPASSTHRU, &ccb) == -1) {
44340271Sken		char tmpstr[256];
44440271Sken
44540271Sken		/*
44640271Sken		 * If we get ENOENT from the transport layer version of
44740271Sken		 * the CAMGETPASSTHRU ioctl, it means one of two things:
44840271Sken		 * either the device name/unit number passed in doesn't
44940271Sken		 * exist, or the passthrough driver isn't in the kernel.
45040271Sken		 */
45140271Sken		if (errno == ENOENT) {
45240271Sken			snprintf(tmpstr, sizeof(tmpstr),
45340271Sken				 "\n%s: either the pass driver isn't in "
45440271Sken				 "your kernel\n%s: or %s%d doesn't exist",
45540271Sken				 func_name, func_name, dev_name, unit);
45640271Sken		}
457232450Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
45840271Sken			 "%s: CAMGETPASSTHRU ioctl failed\n"
45940271Sken			 "%s: %s%s", func_name, func_name, strerror(errno),
46040271Sken			 (errno == ENOENT) ? tmpstr : "");
46140271Sken
462158171Smarcus		close(fd);
46339209Sgibbs		return(NULL);
46439209Sgibbs	}
46539209Sgibbs
466158171Smarcus	close(fd);
467158171Smarcus
46839209Sgibbs	/*
46939209Sgibbs	 * If the ioctl returned the right status, but we got an error back
47039209Sgibbs	 * in the ccb, that means that the kernel found the device the user
47139209Sgibbs	 * passed in, but was unable to find the passthrough device for
47239209Sgibbs	 * the device the user gave us.
47339209Sgibbs	 */
47439209Sgibbs	if (ccb.cgdl.status == CAM_GDEVLIST_ERROR) {
475232450Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
476232450Sjh			 "%s: device %s%d does not exist!",
477232450Sjh			 func_name, dev_name, unit);
47839209Sgibbs		return(NULL);
47939209Sgibbs	}
48039209Sgibbs
48139209Sgibbs	sprintf(dev_path, "/dev/%s%d", ccb.cgdl.periph_name,
48239209Sgibbs		ccb.cgdl.unit_number);
48339209Sgibbs
48439209Sgibbs	return(cam_real_open_device(dev_path, flags, device, NULL,
48539209Sgibbs				    dev_name, unit));
48639209Sgibbs}
48739209Sgibbs
48839209Sgibbs/*
48939209Sgibbs * Open a given device.  The path argument isn't strictly necessary, but it
49039209Sgibbs * is copied into the cam_device structure as a convenience to the user.
49139209Sgibbs */
49239209Sgibbsstatic struct cam_device *
49339209Sgibbscam_real_open_device(const char *path, int flags, struct cam_device *device,
49439209Sgibbs		     const char *given_path, const char *given_dev_name,
49539209Sgibbs		     int given_unit_number)
49639209Sgibbs{
49739209Sgibbs	char *func_name = "cam_real_open_device";
49839209Sgibbs	union ccb ccb;
49979183Smjacob	int fd = -1, malloced_device = 0;
50039209Sgibbs
50139209Sgibbs	/*
50239209Sgibbs	 * See if the user wants us to malloc a device for him.
50339209Sgibbs	 */
50439209Sgibbs	if (device == NULL) {
50539209Sgibbs		if ((device = (struct cam_device *)malloc(
50639209Sgibbs		     sizeof(struct cam_device))) == NULL) {
507232450Sjh			snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
508232450Sjh				 "%s: device structure malloc"
509232450Sjh				 " failed\n%s: %s", func_name, func_name,
510232450Sjh				 strerror(errno));
51139209Sgibbs			return(NULL);
51239209Sgibbs		}
51379183Smjacob		device->fd = -1;
51439209Sgibbs		malloced_device = 1;
51539209Sgibbs	}
51639209Sgibbs
51739209Sgibbs	/*
51839209Sgibbs	 * If the user passed in a path, save it for him.
51939209Sgibbs	 */
52039209Sgibbs	if (given_path != NULL)
52196559Sken		strlcpy(device->device_path, given_path,
52296559Sken			sizeof(device->device_path));
52339209Sgibbs	else
52439209Sgibbs		device->device_path[0] = '\0';
52539209Sgibbs
52639209Sgibbs	/*
52739209Sgibbs	 * If the user passed in a device name and unit number pair, save
52839209Sgibbs	 * those as well.
52939209Sgibbs	 */
53039209Sgibbs	if (given_dev_name != NULL)
53196559Sken		strlcpy(device->given_dev_name, given_dev_name,
53296559Sken			sizeof(device->given_dev_name));
53339209Sgibbs	else
53439209Sgibbs		device->given_dev_name[0] = '\0';
53539209Sgibbs	device->given_unit_number = given_unit_number;
53639209Sgibbs
53739209Sgibbs	if ((fd = open(path, flags)) < 0) {
53841190Sken		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
53941190Sken			 "%s: couldn't open passthrough device %s\n"
54041190Sken			 "%s: %s", func_name, path, func_name,
54141190Sken			 strerror(errno));
54239209Sgibbs		goto crod_bailout;
54339209Sgibbs	}
54439209Sgibbs
54539209Sgibbs	device->fd = fd;
54639209Sgibbs
54739209Sgibbs	bzero(&ccb, sizeof(union ccb));
54839209Sgibbs
54939209Sgibbs	/*
55039209Sgibbs	 * Unlike the transport layer version of the GETPASSTHRU ioctl,
55139209Sgibbs	 * we don't have to set any fields.
55239209Sgibbs	 */
55339209Sgibbs	ccb.ccb_h.func_code = XPT_GDEVLIST;
55439209Sgibbs
55539209Sgibbs	/*
55639209Sgibbs	 * We're only doing this to get some information on the device in
55739209Sgibbs	 * question.  Otherwise, we'd have to pass in yet another
55839209Sgibbs	 * parameter: the passthrough driver unit number.
55939209Sgibbs	 */
56039209Sgibbs	if (ioctl(fd, CAMGETPASSTHRU, &ccb) == -1) {
56140271Sken		/*
56240271Sken		 * At this point we know the passthrough device must exist
56340271Sken		 * because we just opened it above.  The only way this
56440271Sken		 * ioctl can fail is if the ccb size is wrong.
56540271Sken		 */
566232450Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
567232450Sjh			 "%s: CAMGETPASSTHRU ioctl failed\n"
568232450Sjh			 "%s: %s", func_name, func_name, strerror(errno));
56939209Sgibbs		goto crod_bailout;
57039209Sgibbs	}
57139209Sgibbs
57239209Sgibbs	/*
57339209Sgibbs	 * If the ioctl returned the right status, but we got an error back
57439209Sgibbs	 * in the ccb, that means that the kernel found the device the user
57539209Sgibbs	 * passed in, but was unable to find the passthrough device for
57639209Sgibbs	 * the device the user gave us.
57739209Sgibbs	 */
57839209Sgibbs	if (ccb.cgdl.status == CAM_GDEVLIST_ERROR) {
579232450Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
580232450Sjh			 "%s: passthrough device does not exist!", func_name);
58139209Sgibbs		goto crod_bailout;
58239209Sgibbs	}
58339209Sgibbs
58439209Sgibbs	device->dev_unit_num = ccb.cgdl.unit_number;
58596559Sken	strlcpy(device->device_name, ccb.cgdl.periph_name,
58696559Sken		sizeof(device->device_name));
58739209Sgibbs	device->path_id = ccb.ccb_h.path_id;
58839209Sgibbs	device->target_id = ccb.ccb_h.target_id;
58939209Sgibbs	device->target_lun = ccb.ccb_h.target_lun;
59039209Sgibbs
59139209Sgibbs	ccb.ccb_h.func_code = XPT_PATH_INQ;
59239209Sgibbs	if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
593232450Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
594232450Sjh			 "%s: Path Inquiry CCB failed\n"
595232450Sjh			 "%s: %s", func_name, func_name, strerror(errno));
59639209Sgibbs		goto crod_bailout;
59739209Sgibbs	}
59896559Sken	strlcpy(device->sim_name, ccb.cpi.dev_name, sizeof(device->sim_name));
59939209Sgibbs	device->sim_unit_number = ccb.cpi.unit_number;
60039209Sgibbs	device->bus_id = ccb.cpi.bus_id;
60139209Sgibbs
60239209Sgibbs	/*
60339209Sgibbs	 * It doesn't really matter what is in the payload for a getdev
60439209Sgibbs	 * CCB, the kernel doesn't look at it.
60539209Sgibbs	 */
60639209Sgibbs	ccb.ccb_h.func_code = XPT_GDEV_TYPE;
60739209Sgibbs	if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
608232450Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
609232450Sjh			 "%s: Get Device Type CCB failed\n"
610232450Sjh			 "%s: %s", func_name, func_name, strerror(errno));
61139209Sgibbs		goto crod_bailout;
61239209Sgibbs	}
61356122Smjacob	device->pd_type = SID_TYPE(&ccb.cgd.inq_data);
61439209Sgibbs	bcopy(&ccb.cgd.inq_data, &device->inq_data,
61539209Sgibbs	      sizeof(struct scsi_inquiry_data));
61639209Sgibbs	device->serial_num_len = ccb.cgd.serial_num_len;
61739209Sgibbs	bcopy(&ccb.cgd.serial_num, &device->serial_num, device->serial_num_len);
61839209Sgibbs
61939209Sgibbs	/*
62039209Sgibbs	 * Zero the payload, the kernel does look at the flags.
62139209Sgibbs	 */
62239209Sgibbs	bzero(&(&ccb.ccb_h)[1], sizeof(struct ccb_trans_settings));
62339209Sgibbs
62439209Sgibbs	/*
62539209Sgibbs	 * Get transfer settings for this device.
62639209Sgibbs	 */
62739209Sgibbs	ccb.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
62839209Sgibbs
629163896Smjacob	ccb.cts.type = CTS_TYPE_CURRENT_SETTINGS;
63039209Sgibbs
63139209Sgibbs	if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
632232450Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
633232450Sjh			 "%s: Get Transfer Settings CCB failed\n"
634232450Sjh			 "%s: %s", func_name, func_name, strerror(errno));
63539209Sgibbs		goto crod_bailout;
63639209Sgibbs	}
637251349Sdelphij	if (ccb.cts.transport == XPORT_SPI) {
638163896Smjacob		struct ccb_trans_settings_spi *spi =
639163896Smjacob		    &ccb.cts.xport_specific.spi;
640163896Smjacob		device->sync_period = spi->sync_period;
641163896Smjacob		device->sync_offset = spi->sync_offset;
642163896Smjacob		device->bus_width = spi->bus_width;
643163896Smjacob	} else {
644163896Smjacob		device->sync_period = 0;
645163896Smjacob		device->sync_offset = 0;
646163896Smjacob		device->bus_width = 0;
647163896Smjacob	}
64839209Sgibbs
64939209Sgibbs	return(device);
65039209Sgibbs
65139209Sgibbscrod_bailout:
65239209Sgibbs
65379183Smjacob	if (fd >= 0)
65479183Smjacob		close(fd);
65579183Smjacob
65639209Sgibbs	if (malloced_device)
65739209Sgibbs		free(device);
65839209Sgibbs
65939209Sgibbs	return(NULL);
66039209Sgibbs}
66139209Sgibbs
66239209Sgibbsvoid
66339209Sgibbscam_close_device(struct cam_device *dev)
66439209Sgibbs{
66539209Sgibbs	if (dev == NULL)
66639209Sgibbs		return;
66739209Sgibbs
66839209Sgibbs	cam_close_spec_device(dev);
66939209Sgibbs
670147949Sdelphij	free(dev);
67139209Sgibbs}
67239209Sgibbs
67339209Sgibbsvoid
67439209Sgibbscam_close_spec_device(struct cam_device *dev)
67539209Sgibbs{
67639209Sgibbs	if (dev == NULL)
67739209Sgibbs		return;
67839209Sgibbs
67939209Sgibbs	if (dev->fd >= 0)
68039209Sgibbs		close(dev->fd);
68139209Sgibbs}
68239209Sgibbs
68339209Sgibbschar *
68439209Sgibbscam_path_string(struct cam_device *dev, char *str, int len)
68539209Sgibbs{
68639209Sgibbs	if (dev == NULL) {
68739209Sgibbs		snprintf(str, len, "No path");
68839209Sgibbs		return(str);
68939209Sgibbs	}
69039209Sgibbs
691259204Snwhitehorn	snprintf(str, len, "(%s%d:%s%d:%d:%d:%jx): ",
69239209Sgibbs		 (dev->device_name[0] != '\0') ? dev->device_name : "pass",
69339209Sgibbs		 dev->dev_unit_num,
69439209Sgibbs		 (dev->sim_name[0] != '\0') ? dev->sim_name : "unknown",
69539209Sgibbs		 dev->sim_unit_number,
69639209Sgibbs		 dev->bus_id,
69739209Sgibbs		 dev->target_id,
698259204Snwhitehorn		 (uintmax_t)dev->target_lun);
69939209Sgibbs
70039209Sgibbs	return(str);
70139209Sgibbs}
70239209Sgibbs
70339209Sgibbs/*
70439209Sgibbs * Malloc/duplicate a CAM device structure.
70539209Sgibbs */
70639209Sgibbsstruct cam_device *
70739209Sgibbscam_device_dup(struct cam_device *device)
70839209Sgibbs{
70939209Sgibbs	char *func_name = "cam_device_dup";
71039209Sgibbs	struct cam_device *newdev;
71139209Sgibbs
71239209Sgibbs	if (device == NULL) {
713232450Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
714232450Sjh			 "%s: device is NULL", func_name);
71539209Sgibbs		return(NULL);
71639209Sgibbs	}
71739209Sgibbs
71839209Sgibbs	newdev = malloc(sizeof(struct cam_device));
719147949Sdelphij	if (newdev == NULL) {
720147949Sdelphij		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
721147949Sdelphij			"%s: couldn't malloc CAM device structure", func_name);
722147949Sdelphij		return(NULL);
723147949Sdelphij	}
72439209Sgibbs
72539209Sgibbs	bcopy(device, newdev, sizeof(struct cam_device));
72639209Sgibbs
72739209Sgibbs	return(newdev);
72839209Sgibbs}
72939209Sgibbs
73039209Sgibbs/*
73139209Sgibbs * Copy a CAM device structure.
73239209Sgibbs */
73339209Sgibbsvoid
73439209Sgibbscam_device_copy(struct cam_device *src, struct cam_device *dst)
73539209Sgibbs{
73639209Sgibbs	char *func_name = "cam_device_copy";
73739209Sgibbs
73839209Sgibbs	if (src == NULL) {
739232450Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
740232450Sjh			 "%s: source device struct was NULL", func_name);
74139209Sgibbs		return;
74239209Sgibbs	}
74339209Sgibbs
74439209Sgibbs	if (dst == NULL) {
745232450Sjh		snprintf(cam_errbuf, CAM_ERRBUF_SIZE,
746232450Sjh			 "%s: destination device struct was NULL", func_name);
74739209Sgibbs		return;
74839209Sgibbs	}
74939209Sgibbs
75039209Sgibbs	bcopy(src, dst, sizeof(struct cam_device));
75139209Sgibbs
75239209Sgibbs}
753