camlib.c revision 47933
139209Sgibbs/* 239209Sgibbs * Copyright (c) 1997, 1998 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 * 2547933Smpp * $Id: camlib.c,v 1.4 1998/11/15 23:17:39 ken Exp $ 2639209Sgibbs */ 2739209Sgibbs 2839209Sgibbs#include <sys/types.h> 2939209Sgibbs#include <sys/param.h> 3039209Sgibbs#include <stdio.h> 3139209Sgibbs#include <stdlib.h> 3239209Sgibbs#include <string.h> 3339209Sgibbs#include <fcntl.h> 3439209Sgibbs#include <unistd.h> 3539209Sgibbs#include <errno.h> 3639209Sgibbs#include <ctype.h> 3739209Sgibbs 3839209Sgibbs#include <cam/cam.h> 3939209Sgibbs#include <cam/scsi/scsi_all.h> 4039209Sgibbs#include <cam/cam_ccb.h> 4139209Sgibbs#include <cam/scsi/scsi_pass.h> 4239209Sgibbs#include "camlib.h" 4339209Sgibbs 4439209Sgibbsstruct cam_devequiv { 4539209Sgibbs char *given_dev; 4639209Sgibbs char *real_dev; 4739209Sgibbs}; 4839209Sgibbs 4939209Sgibbsstruct cam_devequiv devmatchtable[] = { 5039209Sgibbs {"sd", "da"}, 5139209Sgibbs {"st", "sa"} 5239209Sgibbs}; 5339209Sgibbs 5439209Sgibbschar cam_errbuf[CAM_ERRBUF_SIZE]; 5539209Sgibbs 5639209Sgibbsstatic struct cam_device *cam_real_open_device(const char *path, int flags, 5739209Sgibbs struct cam_device *device, 5839209Sgibbs const char *given_path, 5939209Sgibbs const char *given_dev_name, 6039209Sgibbs int given_unit_number); 6139209Sgibbsstatic struct cam_device *cam_lookup_pass(const char *dev_name, int unit, 6239209Sgibbs int flags, const char *given_path, 6339209Sgibbs struct cam_device *device); 6439209Sgibbs 6539209Sgibbs/* 6639209Sgibbs * Send a ccb to a passthrough device. 6739209Sgibbs */ 6839209Sgibbsint 6939209Sgibbscam_send_ccb(struct cam_device *device, union ccb *ccb) 7039209Sgibbs{ 7139209Sgibbs return(ioctl(device->fd, CAMIOCOMMAND, ccb)); 7239209Sgibbs} 7339209Sgibbs 7439209Sgibbs/* 7539209Sgibbs * Malloc a CCB, zero out the header and set its path, target and lun ids. 7639209Sgibbs */ 7739209Sgibbsunion ccb * 7839209Sgibbscam_getccb(struct cam_device *dev) 7939209Sgibbs{ 8039209Sgibbs union ccb *ccb; 8139209Sgibbs 8239209Sgibbs ccb = (union ccb *)malloc(sizeof(union ccb)); 8339209Sgibbs if (ccb != NULL) { 8439209Sgibbs bzero(&ccb->ccb_h, sizeof(struct ccb_hdr)); 8539209Sgibbs ccb->ccb_h.path_id = dev->path_id; 8639209Sgibbs ccb->ccb_h.target_id = dev->target_id; 8739209Sgibbs ccb->ccb_h.target_lun = dev->target_lun; 8839209Sgibbs } 8939209Sgibbs 9039209Sgibbs return(ccb); 9139209Sgibbs} 9239209Sgibbs 9339209Sgibbs/* 9439209Sgibbs * Free a CCB. 9539209Sgibbs */ 9639209Sgibbsvoid 9739209Sgibbscam_freeccb(union ccb *ccb) 9839209Sgibbs{ 9939209Sgibbs if (ccb != NULL) 10039209Sgibbs free(ccb); 10139209Sgibbs} 10239209Sgibbs 10339209Sgibbs/* 10439209Sgibbs * Take a device name or path passed in by the user, and attempt to figure 10539209Sgibbs * out the device name and unit number. Some possible device name formats are: 10639209Sgibbs * /dev/foo0a 10739209Sgibbs * /dev/rfoo0a 10839209Sgibbs * /dev/rfoos2c 10939209Sgibbs * foo0 11039209Sgibbs * foo0a 11139209Sgibbs * rfoo0 11239209Sgibbs * rfoo0a 11339209Sgibbs * nrfoo0 11439209Sgibbs * 11539209Sgibbs * If the caller passes in an old style device name like 'sd' or 'st', 11639209Sgibbs * it will be converted to the new style device name based upon devmatchtable 11739209Sgibbs * above. 11839209Sgibbs * 11939209Sgibbs * Input parameters: device name/path, length of devname string 12039209Sgibbs * Output: device name, unit number 12139209Sgibbs * Return values: returns 0 for success, -1 for failure 12239209Sgibbs */ 12339209Sgibbsint 12439209Sgibbscam_get_device(const char *path, char *dev_name, int devnamelen, int *unit) 12539209Sgibbs{ 12639209Sgibbs char *func_name = "cam_get_device"; 12739209Sgibbs char *tmpstr, *tmpstr2; 12839209Sgibbs char *newpath; 12939209Sgibbs int unit_offset; 13039209Sgibbs int i, found = 0; 13139209Sgibbs 13239209Sgibbs 13339209Sgibbs if (path == NULL) { 13439209Sgibbs sprintf(cam_errbuf, "%s: device pathname was NULL", func_name); 13547933Smpp return(-1); 13639209Sgibbs } 13739209Sgibbs 13839209Sgibbs /* 13939209Sgibbs * We can be rather destructive to the path string. Make a copy of 14039209Sgibbs * it so we don't hose the user's string. 14139209Sgibbs */ 14239209Sgibbs newpath = (char *)strdup(path); 14339209Sgibbs tmpstr = newpath; 14439209Sgibbs 14539209Sgibbs /* Get rid of any leading white space */ 14639209Sgibbs while (isspace(*tmpstr) && (*tmpstr != '\0')) 14739209Sgibbs tmpstr++; 14839209Sgibbs 14939209Sgibbs /* 15039209Sgibbs * Check to see whether we have an absolute pathname. 15139209Sgibbs */ 15239209Sgibbs if (*tmpstr == '/') { 15339209Sgibbs tmpstr2 = tmpstr; 15439209Sgibbs tmpstr = (char *)rindex(tmpstr2, '/'); 15539209Sgibbs if ((tmpstr != NULL) && (*tmpstr != '\0')) 15639209Sgibbs tmpstr++; 15739209Sgibbs } 15839209Sgibbs 15939209Sgibbs if (*tmpstr == '\0') { 16039209Sgibbs sprintf(cam_errbuf, "%s: no text after slash", func_name); 16139209Sgibbs free(newpath); 16247933Smpp return(-1); 16339209Sgibbs } 16439209Sgibbs 16539209Sgibbs /* 16639209Sgibbs * Check to see whether the user has given us a nonrewound tape 16739209Sgibbs * device. 16839209Sgibbs */ 16939209Sgibbs if (*tmpstr == 'n') 17039209Sgibbs tmpstr++; 17139209Sgibbs 17239209Sgibbs if (*tmpstr == '\0') { 17339209Sgibbs sprintf(cam_errbuf, "%s: no text after leading 'n'", func_name); 17439209Sgibbs free(newpath); 17547933Smpp return(-1); 17639209Sgibbs } 17739209Sgibbs 17839209Sgibbs /* 17939209Sgibbs * See if the user has given us a character device. 18039209Sgibbs */ 18139209Sgibbs if (*tmpstr == 'r') 18239209Sgibbs tmpstr++; 18339209Sgibbs 18439209Sgibbs if (*tmpstr == '\0') { 18539209Sgibbs sprintf(cam_errbuf, "%s: no text after leading 'r'", func_name); 18639209Sgibbs free(newpath); 18747933Smpp return(-1); 18839209Sgibbs } 18939209Sgibbs 19039209Sgibbs /* 19139209Sgibbs * Try to get rid of any trailing white space or partition letters. 19239209Sgibbs */ 19339209Sgibbs tmpstr2 = &tmpstr[strlen(tmpstr) - 1]; 19439209Sgibbs 19539209Sgibbs while ((*tmpstr2 != '\0') && (tmpstr2 > tmpstr) &&(!isdigit(*tmpstr2))){ 19639209Sgibbs *tmpstr2 = '\0'; 19739209Sgibbs tmpstr2--; 19839209Sgibbs } 19939209Sgibbs 20039209Sgibbs /* 20139209Sgibbs * Check to see whether we have been given a partition with a slice 20239209Sgibbs * name. If so, get rid of the slice name/number. 20339209Sgibbs */ 20439209Sgibbs if (strlen(tmpstr) > 3) { 20539209Sgibbs /* 20639209Sgibbs * Basically, we're looking for a string that ends in the 20739209Sgibbs * following general manner: 1s1 -- a number, the letter 20839209Sgibbs * s, and then another number. This indicates that the 20939209Sgibbs * user has given us a slice. We substitute nulls for the 21039209Sgibbs * s and the slice number. 21139209Sgibbs */ 21239209Sgibbs if ((isdigit(tmpstr[strlen(tmpstr) - 1])) 21339209Sgibbs && (tmpstr[strlen(tmpstr) - 2] == 's') 21439209Sgibbs && (isdigit(tmpstr[strlen(tmpstr) - 3]))) { 21539209Sgibbs tmpstr[strlen(tmpstr) - 1] = '\0'; 21639209Sgibbs tmpstr[strlen(tmpstr) - 1] = '\0'; 21739209Sgibbs } 21839209Sgibbs } 21939209Sgibbs 22039209Sgibbs /* 22139209Sgibbs * After we nuke off the slice, we should have just a device name 22239209Sgibbs * and unit number. That means there must be at least 2 22339209Sgibbs * characters. If we only have 1, we don't have a valid device name. 22439209Sgibbs */ 22539209Sgibbs if (strlen(tmpstr) < 2) { 22639209Sgibbs sprintf(cam_errbuf, 22739209Sgibbs "%s: must have both device name and unit number", 22839209Sgibbs func_name); 22939209Sgibbs free(newpath); 23047933Smpp return(-1); 23139209Sgibbs } 23239209Sgibbs 23339209Sgibbs /* 23439209Sgibbs * If the first character of the string is a digit, then the user 23539209Sgibbs * has probably given us all numbers. Point out the error. 23639209Sgibbs */ 23739209Sgibbs if (isdigit(*tmpstr)) { 23839209Sgibbs sprintf(cam_errbuf, 23939209Sgibbs "%s: device name cannot begin with a number", 24039209Sgibbs func_name); 24139209Sgibbs free(newpath); 24247933Smpp return(-1); 24339209Sgibbs } 24439209Sgibbs 24539209Sgibbs /* 24639209Sgibbs * At this point, if the last character of the string isn't a 24739209Sgibbs * number, we know the user either didn't give us a device number, 24839209Sgibbs * or he gave us a device name/number format we don't recognize. 24939209Sgibbs */ 25039209Sgibbs if (!isdigit(tmpstr[strlen(tmpstr) - 1])) { 25139209Sgibbs sprintf(cam_errbuf, "%s: unable to find device unit number", 25239209Sgibbs func_name); 25339209Sgibbs free(newpath); 25447933Smpp return(-1); 25539209Sgibbs } 25639209Sgibbs 25739209Sgibbs /* 25839209Sgibbs * Attempt to figure out where the device name ends and the unit 25939209Sgibbs * number begins. As long as unit_offset is at least 1 less than 26039209Sgibbs * the length of the string, we can still potentially have a device 26139209Sgibbs * name at the front of the string. When we get to something that 26239209Sgibbs * isn't a digit, we've hit the device name. Because of the check 26339209Sgibbs * above, we know that this cannot happen when unit_offset == 1. 26439209Sgibbs * Therefore it is okay to decrement unit_offset -- it won't cause 26539209Sgibbs * us to go past the end of the character array. 26639209Sgibbs */ 26739209Sgibbs for (unit_offset = 1; 26839209Sgibbs (unit_offset < (strlen(tmpstr))) 26939209Sgibbs && (isdigit(tmpstr[strlen(tmpstr) - unit_offset])); unit_offset++); 27039209Sgibbs 27139209Sgibbs unit_offset--; 27239209Sgibbs 27339209Sgibbs /* 27439209Sgibbs * Grab the unit number. 27539209Sgibbs */ 27639209Sgibbs *unit = atoi(&tmpstr[strlen(tmpstr) - unit_offset]); 27739209Sgibbs 27839209Sgibbs /* 27939209Sgibbs * Put a null in place of the first number of the unit number so 28039209Sgibbs * that all we have left is the device name. 28139209Sgibbs */ 28239209Sgibbs tmpstr[strlen(tmpstr) - unit_offset] = '\0'; 28339209Sgibbs 28439209Sgibbs /* 28539209Sgibbs * Look through our equivalency table and see if the device name 28639209Sgibbs * the user gave us is an old style device name. If so, translate 28739209Sgibbs * it to the new style device name. 28839209Sgibbs */ 28939209Sgibbs for (i = 0;i < (sizeof(devmatchtable)/sizeof(struct cam_devequiv));i++){ 29039209Sgibbs if (strcmp(tmpstr, devmatchtable[i].given_dev) == 0) { 29139209Sgibbs strncpy(dev_name,devmatchtable[i].real_dev, devnamelen); 29239209Sgibbs found = 1; 29339209Sgibbs break; 29439209Sgibbs } 29539209Sgibbs } 29639209Sgibbs if (found == 0) 29739209Sgibbs strncpy(dev_name, tmpstr, devnamelen); 29839209Sgibbs 29939209Sgibbs /* Make sure we pass back a null-terminated string */ 30039209Sgibbs dev_name[devnamelen - 1] = '\0'; 30139209Sgibbs 30239209Sgibbs /* Clean up allocated memory */ 30339209Sgibbs free(newpath); 30439209Sgibbs 30547933Smpp return(0); 30639209Sgibbs 30739209Sgibbs} 30839209Sgibbs 30939209Sgibbs/* 31039209Sgibbs * Backwards compatible wrapper for the real open routine. This translates 31139209Sgibbs * a pathname into a device name and unit number for use with the real open 31239209Sgibbs * routine. 31339209Sgibbs */ 31439209Sgibbsstruct cam_device * 31539209Sgibbscam_open_device(const char *path, int flags) 31639209Sgibbs{ 31739209Sgibbs int unit; 31839209Sgibbs char dev_name[DEV_IDLEN + 1]; 31939209Sgibbs 32039209Sgibbs /* 32139209Sgibbs * cam_get_device() has already put an error message in cam_errbuf, 32239209Sgibbs * so we don't need to. 32339209Sgibbs */ 32447933Smpp if (cam_get_device(path, dev_name, DEV_IDLEN + 1, &unit) == -1) 32539209Sgibbs return(NULL); 32639209Sgibbs 32739209Sgibbs return(cam_lookup_pass(dev_name, unit, flags, path, NULL)); 32839209Sgibbs} 32939209Sgibbs 33039209Sgibbs/* 33139209Sgibbs * Open the passthrough device for a given bus, target and lun, if the 33239209Sgibbs * passthrough device exists. 33339209Sgibbs */ 33439209Sgibbsstruct cam_device * 33539209Sgibbscam_open_btl(path_id_t path_id, target_id_t target_id, lun_id_t target_lun, 33639209Sgibbs int flags, struct cam_device *device) 33739209Sgibbs{ 33839209Sgibbs union ccb ccb; 33939209Sgibbs struct periph_match_pattern *match_pat; 34039209Sgibbs char *func_name = "cam_open_btl"; 34139209Sgibbs int fd, bufsize; 34239209Sgibbs 34339209Sgibbs if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) { 34439209Sgibbs snprintf(cam_errbuf, CAM_ERRBUF_SIZE, 34539209Sgibbs "%s: couldn't open %s\n%s: %s", func_name, XPT_DEVICE, 34639209Sgibbs func_name, strerror(errno)); 34739209Sgibbs return(NULL); 34839209Sgibbs } 34939209Sgibbs 35039209Sgibbs bzero(&ccb, sizeof(union ccb)); 35139209Sgibbs ccb.ccb_h.func_code = XPT_DEV_MATCH; 35239209Sgibbs 35339209Sgibbs /* Setup the result buffer */ 35439209Sgibbs bufsize = sizeof(struct dev_match_result); 35539209Sgibbs ccb.cdm.match_buf_len = bufsize; 35639209Sgibbs ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize); 35739209Sgibbs if (ccb.cdm.matches == NULL) { 35839209Sgibbs snprintf(cam_errbuf, CAM_ERRBUF_SIZE, 35939209Sgibbs "%s: couldn't malloc match buffer", func_name); 36039209Sgibbs return(NULL); 36139209Sgibbs } 36239209Sgibbs ccb.cdm.num_matches = 0; 36339209Sgibbs 36439209Sgibbs /* Setup the pattern buffer */ 36539209Sgibbs ccb.cdm.num_patterns = 1; 36639209Sgibbs ccb.cdm.pattern_buf_len = sizeof(struct dev_match_pattern); 36739209Sgibbs ccb.cdm.patterns = (struct dev_match_pattern *)malloc( 36839209Sgibbs sizeof(struct dev_match_pattern)); 36939209Sgibbs if (ccb.cdm.patterns == NULL) { 37039209Sgibbs snprintf(cam_errbuf, CAM_ERRBUF_SIZE, 37139209Sgibbs "%s: couldn't malloc pattern buffer", func_name); 37239209Sgibbs free(ccb.cdm.matches); 37339209Sgibbs return(NULL); 37439209Sgibbs } 37539209Sgibbs ccb.cdm.patterns[0].type = DEV_MATCH_PERIPH; 37639209Sgibbs match_pat = &ccb.cdm.patterns[0].pattern.periph_pattern; 37739209Sgibbs 37839209Sgibbs /* 37939209Sgibbs * We're looking for the passthrough device associated with this 38039209Sgibbs * particular bus/target/lun. 38139209Sgibbs */ 38239209Sgibbs sprintf(match_pat->periph_name, "pass"); 38339209Sgibbs match_pat->path_id = path_id; 38439209Sgibbs match_pat->target_id = target_id; 38539209Sgibbs match_pat->target_lun = target_lun; 38639209Sgibbs /* Now set the flags to indicate what we're looking for. */ 38739209Sgibbs match_pat->flags = PERIPH_MATCH_PATH | PERIPH_MATCH_TARGET | 38839209Sgibbs PERIPH_MATCH_LUN | PERIPH_MATCH_NAME; 38939209Sgibbs 39039209Sgibbs if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 39139209Sgibbs sprintf(cam_errbuf, "%s: CAMIOCOMMAND ioctl failed\n" 39239209Sgibbs "%s: %s", func_name, func_name, strerror(errno)); 39339209Sgibbs goto btl_bailout; 39439209Sgibbs } 39539209Sgibbs 39639209Sgibbs /* 39739209Sgibbs * Check for an outright error. 39839209Sgibbs */ 39939209Sgibbs if ((ccb.ccb_h.status != CAM_REQ_CMP) 40039209Sgibbs || ((ccb.cdm.status != CAM_DEV_MATCH_LAST) 40139209Sgibbs && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) { 40239209Sgibbs sprintf(cam_errbuf, "%s: CAM error %#x, CDM error %d " 40339209Sgibbs "returned from XPT_DEV_MATCH ccb", func_name, 40439209Sgibbs ccb.ccb_h.status, ccb.cdm.status); 40539209Sgibbs goto btl_bailout; 40639209Sgibbs } 40739209Sgibbs 40839209Sgibbs if (ccb.cdm.status == CAM_DEV_MATCH_MORE) { 40939209Sgibbs sprintf(cam_errbuf, "%s: CDM reported more than one" 41039209Sgibbs " passthrough device at %d:%d:%d!!\n", 41139209Sgibbs func_name, path_id, target_id, target_lun); 41239209Sgibbs goto btl_bailout; 41339209Sgibbs } 41439209Sgibbs 41539209Sgibbs if (ccb.cdm.num_matches == 0) { 41639209Sgibbs sprintf(cam_errbuf, "%s: no passthrough device found at" 41739209Sgibbs " %d:%d:%d", func_name, path_id, target_id, 41839209Sgibbs target_lun); 41939209Sgibbs goto btl_bailout; 42039209Sgibbs } 42139209Sgibbs 42239209Sgibbs switch(ccb.cdm.matches[0].type) { 42339209Sgibbs case DEV_MATCH_PERIPH: { 42439209Sgibbs int pass_unit; 42539209Sgibbs char dev_path[256]; 42639209Sgibbs struct periph_match_result *periph_result; 42739209Sgibbs 42839209Sgibbs periph_result = &ccb.cdm.matches[0].result.periph_result; 42939209Sgibbs pass_unit = periph_result->unit_number; 43039209Sgibbs free(ccb.cdm.matches); 43139209Sgibbs free(ccb.cdm.patterns); 43239209Sgibbs sprintf(dev_path, "/dev/pass%d", pass_unit); 43339209Sgibbs return(cam_real_open_device(dev_path, flags, device, NULL, 43439209Sgibbs NULL, 0)); 43539209Sgibbs break; /* NOTREACHED */ 43639209Sgibbs } 43739209Sgibbs default: 43839209Sgibbs sprintf(cam_errbuf, "%s: asked for a peripheral match, but" 43939209Sgibbs " got a bus or device match??!!", func_name); 44039209Sgibbs goto btl_bailout; 44139209Sgibbs break; /* NOTREACHED */ 44239209Sgibbs } 44339209Sgibbs 44439209Sgibbsbtl_bailout: 44539209Sgibbs free(ccb.cdm.matches); 44639209Sgibbs free(ccb.cdm.patterns); 44739209Sgibbs return(NULL); 44839209Sgibbs} 44939209Sgibbs 45039209Sgibbsstruct cam_device * 45139209Sgibbscam_open_spec_device(const char *dev_name, int unit, int flags, 45239209Sgibbs struct cam_device *device) 45339209Sgibbs{ 45439209Sgibbs return(cam_lookup_pass(dev_name, unit, flags, NULL, device)); 45539209Sgibbs} 45639209Sgibbs 45739209Sgibbsstruct cam_device * 45839209Sgibbscam_open_pass(const char *path, int flags, struct cam_device *device) 45939209Sgibbs{ 46039209Sgibbs return(cam_real_open_device(path, flags, device, path, NULL, 0)); 46139209Sgibbs} 46239209Sgibbs 46339209Sgibbsstatic struct cam_device * 46439209Sgibbscam_lookup_pass(const char *dev_name, int unit, int flags, 46539209Sgibbs const char *given_path, struct cam_device *device) 46639209Sgibbs{ 46739209Sgibbs int fd; 46839209Sgibbs union ccb ccb; 46939209Sgibbs char dev_path[256]; 47039209Sgibbs char *func_name = "cam_lookup_pass"; 47139209Sgibbs 47239209Sgibbs /* 47339209Sgibbs * The flags argument above only applies to the actual passthrough 47439209Sgibbs * device open, not our open of the given device to find the 47539209Sgibbs * passthrough device. 47639209Sgibbs */ 47739209Sgibbs if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) { 47839209Sgibbs snprintf(cam_errbuf, CAM_ERRBUF_SIZE, 47939209Sgibbs "%s: couldn't open %s\n%s: %s", func_name, XPT_DEVICE, 48039209Sgibbs func_name, strerror(errno)); 48139209Sgibbs return(NULL); 48239209Sgibbs } 48339209Sgibbs 48439209Sgibbs /* This isn't strictly necessary for the GETPASSTHRU ioctl. */ 48539209Sgibbs ccb.ccb_h.func_code = XPT_GDEVLIST; 48639209Sgibbs 48739209Sgibbs /* These two are necessary for the GETPASSTHRU ioctl to work. */ 48839209Sgibbs strncpy(ccb.cgdl.periph_name, dev_name, DEV_IDLEN - 1); 48939209Sgibbs ccb.cgdl.periph_name[DEV_IDLEN - 1] = '\0'; 49039209Sgibbs ccb.cgdl.unit_number = unit; 49139209Sgibbs 49239209Sgibbs /* 49339209Sgibbs * Attempt to get the passthrough device. This ioctl will fail if 49440271Sken * the device name is null, if the device doesn't exist, or if the 49540271Sken * passthrough driver isn't in the kernel. 49639209Sgibbs */ 49739209Sgibbs if (ioctl(fd, CAMGETPASSTHRU, &ccb) == -1) { 49840271Sken char tmpstr[256]; 49940271Sken 50040271Sken /* 50140271Sken * If we get ENOENT from the transport layer version of 50240271Sken * the CAMGETPASSTHRU ioctl, it means one of two things: 50340271Sken * either the device name/unit number passed in doesn't 50440271Sken * exist, or the passthrough driver isn't in the kernel. 50540271Sken */ 50640271Sken if (errno == ENOENT) { 50740271Sken snprintf(tmpstr, sizeof(tmpstr), 50840271Sken "\n%s: either the pass driver isn't in " 50940271Sken "your kernel\n%s: or %s%d doesn't exist", 51040271Sken func_name, func_name, dev_name, unit); 51140271Sken } 51240271Sken snprintf(cam_errbuf, sizeof(cam_errbuf), 51340271Sken "%s: CAMGETPASSTHRU ioctl failed\n" 51440271Sken "%s: %s%s", func_name, func_name, strerror(errno), 51540271Sken (errno == ENOENT) ? tmpstr : ""); 51640271Sken 51739209Sgibbs return(NULL); 51839209Sgibbs } 51939209Sgibbs 52039209Sgibbs close(fd); 52139209Sgibbs 52239209Sgibbs /* 52339209Sgibbs * If the ioctl returned the right status, but we got an error back 52439209Sgibbs * in the ccb, that means that the kernel found the device the user 52539209Sgibbs * passed in, but was unable to find the passthrough device for 52639209Sgibbs * the device the user gave us. 52739209Sgibbs */ 52839209Sgibbs if (ccb.cgdl.status == CAM_GDEVLIST_ERROR) { 52939209Sgibbs sprintf(cam_errbuf, "%s: device %s%d does not exist", 53039209Sgibbs func_name, dev_name, unit); 53139209Sgibbs return(NULL); 53239209Sgibbs } 53339209Sgibbs 53439209Sgibbs sprintf(dev_path, "/dev/%s%d", ccb.cgdl.periph_name, 53539209Sgibbs ccb.cgdl.unit_number); 53639209Sgibbs 53739209Sgibbs return(cam_real_open_device(dev_path, flags, device, NULL, 53839209Sgibbs dev_name, unit)); 53939209Sgibbs} 54039209Sgibbs 54139209Sgibbs/* 54239209Sgibbs * Open a given device. The path argument isn't strictly necessary, but it 54339209Sgibbs * is copied into the cam_device structure as a convenience to the user. 54439209Sgibbs */ 54539209Sgibbsstatic struct cam_device * 54639209Sgibbscam_real_open_device(const char *path, int flags, struct cam_device *device, 54739209Sgibbs const char *given_path, const char *given_dev_name, 54839209Sgibbs int given_unit_number) 54939209Sgibbs{ 55039209Sgibbs char newpath[MAXPATHLEN+1]; 55139209Sgibbs char *func_name = "cam_real_open_device"; 55239209Sgibbs union ccb ccb; 55339209Sgibbs int fd, malloced_device = 0; 55439209Sgibbs 55539209Sgibbs /* 55639209Sgibbs * See if the user wants us to malloc a device for him. 55739209Sgibbs */ 55839209Sgibbs if (device == NULL) { 55939209Sgibbs if ((device = (struct cam_device *)malloc( 56039209Sgibbs sizeof(struct cam_device))) == NULL) { 56139209Sgibbs sprintf(cam_errbuf, "%s: device structure malloc" 56239209Sgibbs " failed\n%s: %s", func_name, func_name, 56339209Sgibbs strerror(errno)); 56439209Sgibbs return(NULL); 56539209Sgibbs } 56639209Sgibbs malloced_device = 1; 56739209Sgibbs } 56839209Sgibbs 56939209Sgibbs /* 57039209Sgibbs * If the user passed in a path, save it for him. 57139209Sgibbs */ 57239209Sgibbs if (given_path != NULL) 57339209Sgibbs strncpy(device->device_path, given_path, MAXPATHLEN + 1); 57439209Sgibbs else 57539209Sgibbs device->device_path[0] = '\0'; 57639209Sgibbs 57739209Sgibbs /* 57839209Sgibbs * If the user passed in a device name and unit number pair, save 57939209Sgibbs * those as well. 58039209Sgibbs */ 58139209Sgibbs if (given_dev_name != NULL) 58239209Sgibbs strncpy(device->given_dev_name, given_dev_name, DEV_IDLEN); 58339209Sgibbs else 58439209Sgibbs device->given_dev_name[0] = '\0'; 58539209Sgibbs device->given_unit_number = given_unit_number; 58639209Sgibbs 58739209Sgibbs if ((fd = open(path, flags)) < 0) { 58841190Sken snprintf(cam_errbuf, CAM_ERRBUF_SIZE, 58941190Sken "%s: couldn't open passthrough device %s\n" 59041190Sken "%s: %s", func_name, path, func_name, 59141190Sken strerror(errno)); 59239209Sgibbs goto crod_bailout; 59339209Sgibbs } 59439209Sgibbs 59539209Sgibbs device->fd = fd; 59639209Sgibbs 59739209Sgibbs bzero(&ccb, sizeof(union ccb)); 59839209Sgibbs 59939209Sgibbs /* 60039209Sgibbs * Unlike the transport layer version of the GETPASSTHRU ioctl, 60139209Sgibbs * we don't have to set any fields. 60239209Sgibbs */ 60339209Sgibbs ccb.ccb_h.func_code = XPT_GDEVLIST; 60439209Sgibbs 60539209Sgibbs /* 60639209Sgibbs * We're only doing this to get some information on the device in 60739209Sgibbs * question. Otherwise, we'd have to pass in yet another 60839209Sgibbs * parameter: the passthrough driver unit number. 60939209Sgibbs */ 61039209Sgibbs if (ioctl(fd, CAMGETPASSTHRU, &ccb) == -1) { 61140271Sken /* 61240271Sken * At this point we know the passthrough device must exist 61340271Sken * because we just opened it above. The only way this 61440271Sken * ioctl can fail is if the ccb size is wrong. 61540271Sken */ 61639209Sgibbs sprintf(cam_errbuf, "%s: CAMGETPASSTHRU ioctl failed\n" 61739209Sgibbs "%s: %s", func_name, func_name, strerror(errno)); 61839209Sgibbs goto crod_bailout; 61939209Sgibbs } 62039209Sgibbs 62139209Sgibbs /* 62239209Sgibbs * If the ioctl returned the right status, but we got an error back 62339209Sgibbs * in the ccb, that means that the kernel found the device the user 62439209Sgibbs * passed in, but was unable to find the passthrough device for 62539209Sgibbs * the device the user gave us. 62639209Sgibbs */ 62739209Sgibbs if (ccb.cgdl.status == CAM_GDEVLIST_ERROR) { 62839209Sgibbs sprintf(cam_errbuf, "%s: passthrough device does not exist??!!", 62939209Sgibbs func_name); 63039209Sgibbs goto crod_bailout; 63139209Sgibbs } 63239209Sgibbs 63339209Sgibbs device->dev_unit_num = ccb.cgdl.unit_number; 63439209Sgibbs strcpy(device->device_name, ccb.cgdl.periph_name); 63539209Sgibbs device->path_id = ccb.ccb_h.path_id; 63639209Sgibbs device->target_id = ccb.ccb_h.target_id; 63739209Sgibbs device->target_lun = ccb.ccb_h.target_lun; 63839209Sgibbs 63939209Sgibbs ccb.ccb_h.func_code = XPT_PATH_INQ; 64039209Sgibbs if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 64139209Sgibbs sprintf(cam_errbuf, "%s: Path Inquiry CCB failed\n" 64239209Sgibbs "%s: %s", func_name, func_name, strerror(errno)); 64339209Sgibbs goto crod_bailout; 64439209Sgibbs } 64539209Sgibbs strncpy(device->sim_name, ccb.cpi.dev_name, SIM_IDLEN); 64639209Sgibbs device->sim_unit_number = ccb.cpi.unit_number; 64739209Sgibbs device->bus_id = ccb.cpi.bus_id; 64839209Sgibbs 64939209Sgibbs /* 65039209Sgibbs * It doesn't really matter what is in the payload for a getdev 65139209Sgibbs * CCB, the kernel doesn't look at it. 65239209Sgibbs */ 65339209Sgibbs ccb.ccb_h.func_code = XPT_GDEV_TYPE; 65439209Sgibbs if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 65539209Sgibbs sprintf(cam_errbuf, "%s: Get Device Type CCB failed\n" 65639209Sgibbs "%s: %s", func_name, func_name, strerror(errno)); 65739209Sgibbs goto crod_bailout; 65839209Sgibbs } 65939209Sgibbs device->pd_type = ccb.cgd.pd_type; 66039209Sgibbs bcopy(&ccb.cgd.inq_data, &device->inq_data, 66139209Sgibbs sizeof(struct scsi_inquiry_data)); 66239209Sgibbs device->serial_num_len = ccb.cgd.serial_num_len; 66339209Sgibbs bcopy(&ccb.cgd.serial_num, &device->serial_num, device->serial_num_len); 66439209Sgibbs 66539209Sgibbs /* 66639209Sgibbs * Zero the payload, the kernel does look at the flags. 66739209Sgibbs */ 66839209Sgibbs bzero(&(&ccb.ccb_h)[1], sizeof(struct ccb_trans_settings)); 66939209Sgibbs 67039209Sgibbs /* 67139209Sgibbs * Get transfer settings for this device. 67239209Sgibbs */ 67339209Sgibbs ccb.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 67439209Sgibbs 67539209Sgibbs ccb.cts.flags = CCB_TRANS_CURRENT_SETTINGS; 67639209Sgibbs 67739209Sgibbs if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 67839209Sgibbs sprintf(cam_errbuf, "%s: Get Transfer Settings CCB failed\n" 67939209Sgibbs "%s: %s", func_name, func_name, strerror(errno)); 68039209Sgibbs goto crod_bailout; 68139209Sgibbs } 68239209Sgibbs device->sync_period = ccb.cts.sync_period; 68339209Sgibbs device->sync_offset = ccb.cts.sync_offset; 68439209Sgibbs device->bus_width = ccb.cts.bus_width; 68539209Sgibbs 68639209Sgibbs return(device); 68739209Sgibbs 68839209Sgibbscrod_bailout: 68939209Sgibbs 69039209Sgibbs if (malloced_device) 69139209Sgibbs free(device); 69239209Sgibbs 69339209Sgibbs return(NULL); 69439209Sgibbs} 69539209Sgibbs 69639209Sgibbsvoid 69739209Sgibbscam_close_device(struct cam_device *dev) 69839209Sgibbs{ 69939209Sgibbs if (dev == NULL) 70039209Sgibbs return; 70139209Sgibbs 70239209Sgibbs cam_close_spec_device(dev); 70339209Sgibbs 70439209Sgibbs if (dev != NULL) 70539209Sgibbs free(dev); 70639209Sgibbs} 70739209Sgibbs 70839209Sgibbsvoid 70939209Sgibbscam_close_spec_device(struct cam_device *dev) 71039209Sgibbs{ 71139209Sgibbs if (dev == NULL) 71239209Sgibbs return; 71339209Sgibbs 71439209Sgibbs if (dev->fd >= 0) 71539209Sgibbs close(dev->fd); 71639209Sgibbs} 71739209Sgibbs 71839209Sgibbschar * 71939209Sgibbscam_path_string(struct cam_device *dev, char *str, int len) 72039209Sgibbs{ 72139209Sgibbs if (dev == NULL) { 72239209Sgibbs snprintf(str, len, "No path"); 72339209Sgibbs return(str); 72439209Sgibbs } 72539209Sgibbs 72639209Sgibbs snprintf(str, len, "(%s%d:%s%d:%d:%d:%d): ", 72739209Sgibbs (dev->device_name[0] != '\0') ? dev->device_name : "pass", 72839209Sgibbs dev->dev_unit_num, 72939209Sgibbs (dev->sim_name[0] != '\0') ? dev->sim_name : "unknown", 73039209Sgibbs dev->sim_unit_number, 73139209Sgibbs dev->bus_id, 73239209Sgibbs dev->target_id, 73339209Sgibbs dev->target_lun); 73439209Sgibbs 73539209Sgibbs return(str); 73639209Sgibbs} 73739209Sgibbs 73839209Sgibbs/* 73939209Sgibbs * Malloc/duplicate a CAM device structure. 74039209Sgibbs */ 74139209Sgibbsstruct cam_device * 74239209Sgibbscam_device_dup(struct cam_device *device) 74339209Sgibbs{ 74439209Sgibbs char *func_name = "cam_device_dup"; 74539209Sgibbs struct cam_device *newdev; 74639209Sgibbs 74739209Sgibbs if (device == NULL) { 74839209Sgibbs sprintf(cam_errbuf, "%s: device is NULL", func_name); 74939209Sgibbs return(NULL); 75039209Sgibbs } 75139209Sgibbs 75239209Sgibbs newdev = malloc(sizeof(struct cam_device)); 75339209Sgibbs 75439209Sgibbs bcopy(device, newdev, sizeof(struct cam_device)); 75539209Sgibbs 75639209Sgibbs return(newdev); 75739209Sgibbs} 75839209Sgibbs 75939209Sgibbs/* 76039209Sgibbs * Copy a CAM device structure. 76139209Sgibbs */ 76239209Sgibbsvoid 76339209Sgibbscam_device_copy(struct cam_device *src, struct cam_device *dst) 76439209Sgibbs{ 76539209Sgibbs char *func_name = "cam_device_copy"; 76639209Sgibbs 76739209Sgibbs if (src == NULL) { 76839209Sgibbs sprintf(cam_errbuf, "%s: source device struct was NULL", 76939209Sgibbs func_name); 77039209Sgibbs return; 77139209Sgibbs } 77239209Sgibbs 77339209Sgibbs if (dst == NULL) { 77439209Sgibbs sprintf(cam_errbuf, "%s: destination device struct was NULL", 77539209Sgibbs func_name); 77639209Sgibbs return; 77739209Sgibbs } 77839209Sgibbs 77939209Sgibbs bcopy(src, dst, sizeof(struct cam_device)); 78039209Sgibbs 78139209Sgibbs} 782