Home | History | Annotate | Line # | Download | only in mmcformat
      1  1.5   andvar /* $NetBSD: uscsi_subr.c,v 1.5 2022/05/28 21:14:57 andvar Exp $	*/
      2  1.1  reinoud 
      3  1.1  reinoud /*-
      4  1.1  reinoud  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5  1.1  reinoud  * All rights reserved.
      6  1.1  reinoud  *
      7  1.1  reinoud  * This code is derived from software contributed to The NetBSD Foundation
      8  1.1  reinoud  * by Charles M. Hannum; Jason R. Thorpe of the Numerical Aerospace
      9  1.1  reinoud  * Simulation Facility, NASA Ames Research Center.
     10  1.1  reinoud  *
     11  1.1  reinoud  * Redistribution and use in source and binary forms, with or without
     12  1.1  reinoud  * modification, are permitted provided that the following conditions
     13  1.1  reinoud  * are met:
     14  1.1  reinoud  * 1. Redistributions of source code must retain the above copyright
     15  1.1  reinoud  *    notice, this list of conditions and the following disclaimer.
     16  1.1  reinoud  * 2. Redistributions in binary form must reproduce the above copyright
     17  1.1  reinoud  *    notice, this list of conditions and the following disclaimer in the
     18  1.1  reinoud  *    documentation and/or other materials provided with the distribution.
     19  1.1  reinoud  *
     20  1.1  reinoud  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21  1.1  reinoud  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  1.1  reinoud  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  1.1  reinoud  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24  1.1  reinoud  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  1.1  reinoud  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26  1.1  reinoud  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  1.1  reinoud  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28  1.1  reinoud  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  1.1  reinoud  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  1.1  reinoud  * POSSIBILITY OF SUCH DAMAGE.
     31  1.1  reinoud  *
     32  1.1  reinoud  * Small changes, generalisations and Linux support by Reinoud Zandijk
     33  1.1  reinoud  * <reinoud (at) netbsd.org>.
     34  1.1  reinoud  *
     35  1.1  reinoud  */
     36  1.1  reinoud 
     37  1.1  reinoud 
     38  1.1  reinoud /*
     39  1.1  reinoud  * SCSI support subroutines.
     40  1.1  reinoud  */
     41  1.1  reinoud 
     42  1.1  reinoud #include <sys/param.h>
     43  1.1  reinoud #include <sys/ioctl.h>
     44  1.1  reinoud #include <err.h>
     45  1.1  reinoud #include <errno.h>
     46  1.1  reinoud #include <stdio.h>
     47  1.1  reinoud #include <stdlib.h>
     48  1.1  reinoud #include <string.h>
     49  1.1  reinoud #include <unistd.h>
     50  1.1  reinoud #include <fcntl.h>
     51  1.1  reinoud #include <sys/types.h>
     52  1.1  reinoud #include <inttypes.h>
     53  1.1  reinoud #include <assert.h>
     54  1.1  reinoud 
     55  1.1  reinoud #include "uscsilib.h"
     56  1.1  reinoud 
     57  1.1  reinoud 
     58  1.1  reinoud int uscsilib_verbose = 0;
     59  1.1  reinoud 
     60  1.1  reinoud 
     61  1.1  reinoud #ifdef USCSI_SCSIPI
     62  1.1  reinoud 	/*
     63  1.1  reinoud 	 * scsipi is a integrated SCSI and ATAPI layer under NetBSD and exists
     64  1.1  reinoud 	 * in a modified form under OpenBSD and possibly also under other
     65  1.1  reinoud 	 * operating systems.
     66  1.1  reinoud 	 */
     67  1.1  reinoud 
     68  1.1  reinoud 
     69  1.1  reinoud #include <sys/scsiio.h>
     70  1.1  reinoud #ifdef __OpenBSD__
     71  1.1  reinoud #include <scsi/uscsi_all.h>
     72  1.1  reinoud #else
     73  1.1  reinoud #include <dev/scsipi/scsipi_all.h>
     74  1.1  reinoud #endif
     75  1.1  reinoud 
     76  1.1  reinoud 
     77  1.1  reinoud int
     78  1.1  reinoud uscsi_open(struct uscsi_dev *disc)
     79  1.1  reinoud {
     80  1.1  reinoud 	struct stat dstat;
     81  1.1  reinoud 
     82  1.1  reinoud 	disc->fhandle = open(disc->dev_name, O_RDWR, 0); /* no create */
     83  1.1  reinoud 	if (disc->fhandle<0) {
     84  1.1  reinoud 		perror("Failure to open device or file");
     85  1.1  reinoud 		return ENODEV;
     86  1.1  reinoud 	}
     87  1.1  reinoud 
     88  1.1  reinoud 	if (fstat(disc->fhandle, &dstat) < 0) {
     89  1.1  reinoud 		perror("Can't stat device or file");
     90  1.1  reinoud 		uscsi_close(disc);
     91  1.1  reinoud 		return ENODEV;
     92  1.1  reinoud 	}
     93  1.1  reinoud 
     94  1.1  reinoud 	return 0;
     95  1.1  reinoud }
     96  1.1  reinoud 
     97  1.1  reinoud 
     98  1.1  reinoud int
     99  1.1  reinoud uscsi_close(struct uscsi_dev * disc)
    100  1.1  reinoud {
    101  1.1  reinoud 	close(disc->fhandle);
    102  1.1  reinoud 	disc->fhandle = -1;
    103  1.1  reinoud 
    104  1.1  reinoud 	return 0;
    105  1.1  reinoud }
    106  1.1  reinoud 
    107  1.1  reinoud 
    108  1.1  reinoud int
    109  1.1  reinoud uscsi_command(int flags, struct uscsi_dev *disc,
    110  1.1  reinoud 	void *cmd, size_t cmdlen, void *data, size_t datalen,
    111  1.1  reinoud 	uint32_t timeout, struct uscsi_sense *uscsi_sense)
    112  1.1  reinoud {
    113  1.1  reinoud 	scsireq_t req;
    114  1.1  reinoud 
    115  1.1  reinoud 	memset(&req, 0, sizeof(req));
    116  1.1  reinoud 	if (uscsi_sense)
    117  1.1  reinoud 		bzero(uscsi_sense, sizeof(struct uscsi_sense));
    118  1.1  reinoud 
    119  1.1  reinoud 	memcpy(req.cmd, cmd, cmdlen);
    120  1.1  reinoud 	req.cmdlen = cmdlen;
    121  1.1  reinoud 	req.databuf = data;
    122  1.1  reinoud 	req.datalen = datalen;
    123  1.1  reinoud 	req.timeout = timeout;
    124  1.1  reinoud 	req.flags = flags;
    125  1.1  reinoud 	req.senselen = SENSEBUFLEN;
    126  1.1  reinoud 
    127  1.1  reinoud 	if (ioctl(disc->fhandle, SCIOCCOMMAND, &req) == -1)
    128  1.1  reinoud 		err(1, "SCIOCCOMMAND");
    129  1.1  reinoud 
    130  1.1  reinoud 	if (req.retsts == SCCMD_OK)
    131  1.1  reinoud 		return 0;
    132  1.1  reinoud 
    133  1.1  reinoud 	/* Some problem; report it and exit. */
    134  1.1  reinoud 	if (req.retsts == SCCMD_TIMEOUT) {
    135  1.1  reinoud 		if (uscsilib_verbose)
    136  1.1  reinoud 			fprintf(stderr, "%s: SCSI command timed out\n",
    137  1.1  reinoud 				disc->dev_name);
    138  1.1  reinoud 		return EAGAIN;
    139  1.1  reinoud 	} else if (req.retsts == SCCMD_BUSY) {
    140  1.1  reinoud 		if (uscsilib_verbose)
    141  1.1  reinoud 			fprintf(stderr, "%s: device is busy\n",
    142  1.1  reinoud 				disc->dev_name);
    143  1.1  reinoud 		return EBUSY;
    144  1.1  reinoud 	} else if (req.retsts == SCCMD_SENSE) {
    145  1.1  reinoud 		if (uscsi_sense) {
    146  1.1  reinoud 			uscsi_sense->asc        =  req.sense[12];
    147  1.1  reinoud 			uscsi_sense->ascq       =  req.sense[13];
    148  1.1  reinoud 			uscsi_sense->skey_valid =  req.sense[15] & 128;
    149  1.1  reinoud 			uscsi_sense->sense_key  = (req.sense[16] << 8) |
    150  1.1  reinoud 						  (req.sense[17]);
    151  1.1  reinoud 		}
    152  1.1  reinoud 		if (uscsilib_verbose)
    153  1.1  reinoud 			uscsi_print_sense((char *) disc->dev_name,
    154  1.1  reinoud 				req.cmd, req.cmdlen,
    155  1.1  reinoud 				req.sense, req.senselen_used, 1);
    156  1.1  reinoud 		return EIO;
    157  1.1  reinoud 	} else
    158  1.1  reinoud 		if (uscsilib_verbose)
    159  1.1  reinoud 			fprintf(stderr, "%s: device had unknown status %x\n",
    160  1.1  reinoud 				disc->dev_name,
    161  1.1  reinoud 		  	  req.retsts);
    162  1.1  reinoud 
    163  1.1  reinoud 	return EFAULT;
    164  1.1  reinoud }
    165  1.1  reinoud 
    166  1.1  reinoud 
    167  1.1  reinoud /*
    168  1.1  reinoud  * The reasoning behind this explicit copy is for compatibility with changes
    169  1.1  reinoud  * in our uscsi_addr structure.
    170  1.1  reinoud  */
    171  1.1  reinoud int
    172  1.1  reinoud uscsi_identify(struct uscsi_dev *disc, struct uscsi_addr *saddr)
    173  1.1  reinoud {
    174  1.1  reinoud 	struct scsi_addr raddr;
    175  1.1  reinoud 	int error;
    176  1.1  reinoud 
    177  1.1  reinoud 	bzero(saddr, sizeof(struct scsi_addr));
    178  1.1  reinoud 	error = ioctl(disc->fhandle, SCIOCIDENTIFY, &raddr);
    179  1.1  reinoud 	if (error) return error;
    180  1.1  reinoud 
    181  1.1  reinoud #ifdef __NetBSD__
    182  1.1  reinoud 	/* scsi and atapi are split up like in uscsi_addr */
    183  1.1  reinoud 	if (raddr.type == 0) {
    184  1.1  reinoud 		saddr->type = USCSI_TYPE_SCSI;
    185  1.1  reinoud 		saddr->addr.scsi.scbus  = raddr.addr.scsi.scbus;
    186  1.1  reinoud 		saddr->addr.scsi.target = raddr.addr.scsi.target;
    187  1.1  reinoud 		saddr->addr.scsi.lun    = raddr.addr.scsi.lun;
    188  1.1  reinoud 	} else {
    189  1.1  reinoud 		saddr->type = USCSI_TYPE_ATAPI;
    190  1.1  reinoud 		saddr->addr.atapi.atbus = raddr.addr.atapi.atbus;
    191  1.1  reinoud 		saddr->addr.atapi.drive = raddr.addr.atapi.drive;
    192  1.1  reinoud 	}
    193  1.1  reinoud #endif
    194  1.1  reinoud #ifdef __OpenBSD__
    195  1.1  reinoud 	/* atapi's are shown as SCSI devices */
    196  1.1  reinoud 	if (raddr.type == 0) {
    197  1.1  reinoud 		saddr->type = USCSI_TYPE_SCSI;
    198  1.1  reinoud 		saddr->addr.scsi.scbus  = raddr.scbus;
    199  1.1  reinoud 		saddr->addr.scsi.target = raddr.target;
    200  1.1  reinoud 		saddr->addr.scsi.lun    = raddr.lun;
    201  1.1  reinoud 	} else {
    202  1.1  reinoud 		saddr->type = USCSI_TYPE_ATAPI;
    203  1.1  reinoud 		saddr->addr.atapi.atbus = raddr.scbus;	/* overload */
    204  1.1  reinoud 		saddr->addr.atapi.drive = raddr.target;	/* overload */
    205  1.1  reinoud 	}
    206  1.1  reinoud #endif
    207  1.1  reinoud 
    208  1.1  reinoud 	return 0;
    209  1.1  reinoud }
    210  1.1  reinoud 
    211  1.1  reinoud 
    212  1.1  reinoud int
    213  1.1  reinoud uscsi_check_for_scsi(struct uscsi_dev *disc)
    214  1.1  reinoud {
    215  1.1  reinoud 	struct uscsi_addr	saddr;
    216  1.1  reinoud 
    217  1.1  reinoud 	return uscsi_identify(disc, &saddr);
    218  1.1  reinoud }
    219  1.1  reinoud #endif	/* SCSILIB_SCSIPI */
    220  1.1  reinoud 
    221  1.1  reinoud 
    222  1.1  reinoud 
    223  1.1  reinoud 
    224  1.1  reinoud #ifdef USCSI_LINUX_SCSI
    225  1.1  reinoud 	/*
    226  1.1  reinoud 	 * Support code for Linux SCSI code. It uses the ioctl() way of
    227  1.5   andvar 	 * communicating since this is more close to the original NetBSD
    228  1.1  reinoud 	 * scsipi implementation.
    229  1.1  reinoud 	 */
    230  1.1  reinoud #include <scsi/sg.h>
    231  1.1  reinoud #include <scsi/scsi.h>
    232  1.1  reinoud 
    233  1.1  reinoud #define SENSEBUFLEN 48
    234  1.1  reinoud 
    235  1.1  reinoud 
    236  1.1  reinoud int
    237  1.1  reinoud uscsi_open(struct uscsi_dev * disc)
    238  1.1  reinoud {
    239  1.1  reinoud 	int flags;
    240  1.1  reinoud 	struct stat stat;
    241  1.1  reinoud 
    242  1.1  reinoud 	/* in Linux we are NOT allowed to open it blocking */
    243  1.1  reinoud 	/* no create! */
    244  1.1  reinoud 	disc->fhandle = open(disc->dev_name, O_RDWR | O_NONBLOCK, 0);
    245  1.1  reinoud 	if (disc->fhandle<0) {
    246  1.1  reinoud 		perror("Failure to open device or file");
    247  1.1  reinoud 		return ENODEV;
    248  1.1  reinoud 	}
    249  1.1  reinoud 
    250  1.1  reinoud 	/* explicitly mark it non blocking (again) (silly Linux) */
    251  1.1  reinoud 	flags = fcntl(disc->fhandle, F_GETFL);
    252  1.1  reinoud 	flags &= ~O_NONBLOCK;
    253  1.1  reinoud 	fcntl(disc->fhandle, F_SETFL, flags);
    254  1.1  reinoud 
    255  1.1  reinoud 	if (fstat(disc->fhandle, &stat) < 0) {
    256  1.1  reinoud 		perror("Can't stat device or file");
    257  1.1  reinoud 		uscsi_close(disc);
    258  1.1  reinoud 		return ENODEV;
    259  1.1  reinoud 	}
    260  1.1  reinoud 
    261  1.1  reinoud 	return 0;
    262  1.1  reinoud }
    263  1.1  reinoud 
    264  1.1  reinoud 
    265  1.1  reinoud int
    266  1.1  reinoud uscsi_close(struct uscsi_dev * disc)
    267  1.1  reinoud {
    268  1.1  reinoud 	close(disc->fhandle);
    269  1.1  reinoud 	disc->fhandle = -1;
    270  1.1  reinoud 
    271  1.1  reinoud 	return 0;
    272  1.1  reinoud }
    273  1.1  reinoud 
    274  1.1  reinoud 
    275  1.1  reinoud int
    276  1.1  reinoud uscsi_command(int flags, struct uscsi_dev *disc,
    277  1.1  reinoud 	void *cmd, size_t cmdlen,
    278  1.1  reinoud 	void *data, size_t datalen,
    279  1.1  reinoud 	uint32_t timeout, struct uscsi_sense *uscsi_sense)
    280  1.1  reinoud {
    281  1.1  reinoud 	struct sg_io_hdr req;
    282  1.1  reinoud 	uint8_t sense_buffer[SENSEBUFLEN];
    283  1.1  reinoud 	int error;
    284  1.1  reinoud 
    285  1.1  reinoud 	bzero(&req, sizeof(req));
    286  1.1  reinoud 	if (flags == SG_DXFER_FROM_DEV) bzero(data, datalen);
    287  1.1  reinoud 
    288  1.1  reinoud 	req.interface_id    = 'S';
    289  1.1  reinoud 	req.dxfer_direction = flags;
    290  1.1  reinoud 	req.cmd_len	    = cmdlen;
    291  1.1  reinoud 	req.mx_sb_len	    = SENSEBUFLEN;
    292  1.1  reinoud 	req.iovec_count	    = 0;
    293  1.1  reinoud 	req.dxfer_len	    = datalen;
    294  1.1  reinoud 	req.dxferp	    = data;
    295  1.1  reinoud 	req.cmdp	    = cmd;
    296  1.1  reinoud 	req.sbp		    = sense_buffer;
    297  1.1  reinoud 	req.flags	    = 0;
    298  1.1  reinoud 	req.timeout	    = timeout;
    299  1.1  reinoud 
    300  1.1  reinoud 	error = ioctl(disc->fhandle, SG_IO, &req);
    301  1.1  reinoud 
    302  1.1  reinoud 	if (req.status) {
    303  1.1  reinoud 		/* Is this OK? */
    304  1.1  reinoud 		if (uscsi_sense) {
    305  1.1  reinoud 			uscsi_sense->asc        =  sense_buffer[12];
    306  1.1  reinoud 			uscsi_sense->ascq       =  sense_buffer[13];
    307  1.1  reinoud 			uscsi_sense->skey_valid =  sense_buffer[15] & 128;
    308  1.1  reinoud 			uscsi_sense->sense_key  = (sense_buffer[16] << 8) |
    309  1.1  reinoud 						  (sense_buffer[17]);
    310  1.1  reinoud 		}
    311  1.1  reinoud 		if (uscsilib_verbose) {
    312  1.1  reinoud 			uscsi_print_sense((char *) disc->dev_name,
    313  1.1  reinoud 				cmd, cmdlen, sense_buffer, req.sb_len_wr, 1);
    314  1.1  reinoud 		}
    315  1.1  reinoud 	}
    316  1.1  reinoud 
    317  1.1  reinoud 	return error;
    318  1.1  reinoud }
    319  1.1  reinoud 
    320  1.1  reinoud 
    321  1.1  reinoud int
    322  1.1  reinoud uscsi_identify(struct uscsi_dev *disc, struct uscsi_addr *saddr)
    323  1.1  reinoud {
    324  1.1  reinoud 	struct sg_scsi_id sg_scsi_id;
    325  1.1  reinoud 	struct sg_id {
    326  1.1  reinoud 		/* target | lun << 8 | channel << 16 | low_ino << 24 */
    327  1.1  reinoud 		uint32_t tlci;
    328  1.1  reinoud 		uint32_t uniq_id;
    329  1.1  reinoud 	} sg_id;
    330  1.1  reinoud 	int emulated;
    331  1.1  reinoud 	int error;
    332  1.1  reinoud 
    333  1.1  reinoud 	/* clean result */
    334  1.1  reinoud 	bzero(saddr, sizeof(struct uscsi_addr));
    335  1.1  reinoud 
    336  1.1  reinoud 	/* check if its really SCSI or emulated SCSI (ATAPI f.e.) */
    337  1.1  reinoud 	saddr->type = USCSI_TYPE_SCSI;
    338  1.1  reinoud 	ioctl(disc->fhandle, SG_EMULATED_HOST, &emulated);
    339  1.1  reinoud 	if (emulated) saddr->type = USCSI_TYPE_ATAPI;
    340  1.1  reinoud 
    341  1.1  reinoud 	/* try 2.4 kernel or older */
    342  1.1  reinoud 	error = ioctl(disc->fhandle, SG_GET_SCSI_ID, &sg_scsi_id);
    343  1.1  reinoud 	if (!error) {
    344  1.1  reinoud 		saddr->addr.scsi.target = sg_scsi_id.scsi_id;
    345  1.1  reinoud 		saddr->addr.scsi.lun    = sg_scsi_id.lun;
    346  1.1  reinoud 		saddr->addr.scsi.scbus  = sg_scsi_id.channel;
    347  1.1  reinoud 
    348  1.1  reinoud 		return 0;
    349  1.1  reinoud 	}
    350  1.1  reinoud 
    351  1.1  reinoud 	/* 2.6 kernel or newer */
    352  1.1  reinoud  	error = ioctl(disc->fhandle, SCSI_IOCTL_GET_IDLUN, &sg_id);
    353  1.1  reinoud 	if (error) return error;
    354  1.1  reinoud 
    355  1.1  reinoud 	saddr->addr.scsi.target = (sg_id.tlci      ) & 0xff;
    356  1.1  reinoud 	saddr->addr.scsi.lun    = (sg_id.tlci >>  8) & 0xff;
    357  1.1  reinoud 	saddr->addr.scsi.scbus  = (sg_id.tlci >> 16) & 0xff;
    358  1.1  reinoud 
    359  1.1  reinoud 	return 0;
    360  1.1  reinoud }
    361  1.1  reinoud 
    362  1.1  reinoud 
    363  1.1  reinoud int uscsi_check_for_scsi(struct uscsi_dev *disc) {
    364  1.1  reinoud 	struct uscsi_addr saddr;
    365  1.1  reinoud 
    366  1.1  reinoud 	return uscsi_identify(disc, &saddr);
    367  1.1  reinoud }
    368  1.1  reinoud #endif	/* USCSI_LINUX_SCSI */
    369  1.1  reinoud 
    370  1.1  reinoud 
    371  1.1  reinoud 
    372  1.1  reinoud 
    373  1.1  reinoud #ifdef USCSI_FREEBSD_CAM
    374  1.1  reinoud 
    375  1.1  reinoud int
    376  1.1  reinoud uscsi_open(struct uscsi_dev *disc)
    377  1.1  reinoud {
    378  1.1  reinoud 	disc->devhandle = cam_open_device(disc->dev_name, O_RDWR);
    379  1.1  reinoud 
    380  1.1  reinoud 	if (disc->devhandle == NULL) {
    381  1.1  reinoud 		disc->fhandle = open(disc->dev_name, O_RDWR | O_NONBLOCK, 0);
    382  1.1  reinoud 		if (disc->fhandle < 0) {
    383  1.1  reinoud 			perror("Failure to open device or file");
    384  1.1  reinoud 			return ENODEV;
    385  1.1  reinoud 		}
    386  1.1  reinoud 	}
    387  1.1  reinoud 
    388  1.1  reinoud 	return 0;
    389  1.1  reinoud }
    390  1.1  reinoud 
    391  1.1  reinoud 
    392  1.1  reinoud int
    393  1.1  reinoud uscsi_close(struct uscsi_dev *disc)
    394  1.1  reinoud {
    395  1.1  reinoud 	if (disc->devhandle != NULL) {
    396  1.1  reinoud 		cam_close_device(disc->devhandle);
    397  1.1  reinoud 		disc->devhandle = NULL;
    398  1.1  reinoud 	} else {
    399  1.1  reinoud 		close(disc->fhandle);
    400  1.1  reinoud 		disc->fhandle = -1;
    401  1.1  reinoud 	}
    402  1.1  reinoud 
    403  1.1  reinoud 	return 0;
    404  1.1  reinoud }
    405  1.1  reinoud 
    406  1.1  reinoud 
    407  1.1  reinoud int
    408  1.1  reinoud uscsi_command(int flags, struct uscsi_dev *disc,
    409  1.1  reinoud 	void *cmd, size_t cmdlen,
    410  1.1  reinoud 	void *data, size_t datalen,
    411  1.1  reinoud 	uint32_t timeout, struct uscsi_sense *uscsi_sense)
    412  1.1  reinoud {
    413  1.1  reinoud 	struct cam_device *cam_dev;
    414  1.1  reinoud 	struct scsi_sense_data *cam_sense_data;
    415  1.1  reinoud 	union ccb ccb;
    416  1.1  reinoud 	uint32_t cam_sense;
    417  1.1  reinoud 	uint8_t *keypos;
    418  1.1  reinoud 	int camflags;
    419  1.1  reinoud 
    420  1.1  reinoud 	memset(&ccb, 0, sizeof(ccb));
    421  1.1  reinoud 	cam_dev = (struct cam_device *) disc->devhandle;
    422  1.1  reinoud 
    423  1.1  reinoud 	if (datalen == 0) flags = SCSI_NODATACMD;
    424  1.1  reinoud 	/* optional : */
    425  1.1  reinoud 	/* if (data) assert(flags == SCSI_NODATACMD); */
    426  1.1  reinoud 
    427  1.1  reinoud 	camflags = CAM_DIR_NONE;
    428  1.1  reinoud 	if (flags & SCSI_READCMD)
    429  1.1  reinoud 		camflags = CAM_DIR_IN;
    430  1.1  reinoud 	if (flags & SCSI_WRITECMD)
    431  1.1  reinoud 		camflags = CAM_DIR_OUT;
    432  1.1  reinoud 
    433  1.1  reinoud 	cam_fill_csio(
    434  1.1  reinoud 		&ccb.csio,
    435  1.1  reinoud 		0,			/* retries */
    436  1.1  reinoud 		NULL,			/* cbfcnp */
    437  1.1  reinoud 		camflags,		/* flags */
    438  1.1  reinoud 		MSG_SIMPLE_Q_TAG,	/* tag_action */
    439  1.1  reinoud 		(u_int8_t *) data,	/* data_ptr */
    440  1.1  reinoud 		datalen,		/* dxfer_len */
    441  1.1  reinoud 		SSD_FULL_SIZE,		/* sense_len */
    442  1.1  reinoud 		cmdlen,			/* cdb_len */
    443  1.1  reinoud 		timeout			/* timeout */
    444  1.1  reinoud 	);
    445  1.1  reinoud 
    446  1.1  reinoud 	/* Disable freezing the device queue */
    447  1.1  reinoud 	ccb.ccb_h.flags |= CAM_DEV_QFRZDIS;
    448  1.1  reinoud 
    449  1.1  reinoud 	memcpy(ccb.csio.cdb_io.cdb_bytes, cmd, cmdlen);
    450  1.1  reinoud 
    451  1.1  reinoud 	/* Send the command down via the CAM interface */
    452  1.1  reinoud 	if (cam_send_ccb(cam_dev, &ccb) < 0) {
    453  1.1  reinoud 		err(1, "cam_send_ccb");
    454  1.1  reinoud 	}
    455  1.1  reinoud 
    456  1.1  reinoud 	if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
    457  1.1  reinoud 		return 0;
    458  1.1  reinoud 
    459  1.1  reinoud 	/* print error using the uscsi_sense routines? */
    460  1.1  reinoud 
    461  1.1  reinoud 	cam_sense = (ccb.ccb_h.status & (CAM_STATUS_MASK | CAM_AUTOSNS_VALID));
    462  1.1  reinoud 	if (cam_sense != (CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID))
    463  1.1  reinoud 		return EFAULT;
    464  1.1  reinoud 
    465  1.1  reinoud 	/* drive responds with sense information */
    466  1.1  reinoud 	if (!uscsilib_verbose)
    467  1.1  reinoud 		return EFAULT;
    468  1.1  reinoud 
    469  1.1  reinoud 	/* print sense info */
    470  1.1  reinoud 	cam_sense_data = &ccb.csio.sense_data;
    471  1.1  reinoud 	if (uscsi_sense) {
    472  1.1  reinoud 		uscsi_sense->asc  = cam_sense_data->add_sense_code;
    473  1.1  reinoud 		uscsi_sense->ascq = cam_sense_data->add_sense_code_qual;
    474  1.1  reinoud 		keypos  = cam_sense_data->sense_key_spec;
    475  1.1  reinoud 		uscsi_sense->skey_valid =  keypos[0] & 128;
    476  1.1  reinoud 		uscsi_sense->sense_key  = (keypos[1] << 8) | (keypos[2]);
    477  1.1  reinoud 	}
    478  1.1  reinoud 
    479  1.1  reinoud 	uscsi_print_sense((char *) disc->dev_name,
    480  1.1  reinoud 		cmd, cmdlen,
    481  1.1  reinoud 		(uint8_t *) cam_sense_data, 8 + cam_sense_data->extra_len, 1);
    482  1.1  reinoud 
    483  1.1  reinoud 	return EFAULT;
    484  1.1  reinoud }
    485  1.1  reinoud 
    486  1.1  reinoud 
    487  1.1  reinoud int
    488  1.1  reinoud uscsi_identify(struct uscsi_dev *disc, struct uscsi_addr *saddr)
    489  1.1  reinoud {
    490  1.1  reinoud 	struct cam_device *cam_dev;
    491  1.1  reinoud 
    492  1.1  reinoud 	/* clean result */
    493  1.1  reinoud 	bzero(saddr, sizeof(struct uscsi_addr));
    494  1.1  reinoud 
    495  1.1  reinoud 	cam_dev = (struct cam_device *) disc->devhandle;
    496  1.1  reinoud 	if (!cam_dev) return ENODEV;
    497  1.1  reinoud 
    498  1.1  reinoud 	/* check if its really SCSI or emulated SCSI (ATAPI f.e.) ? */
    499  1.1  reinoud 	saddr->type = USCSI_TYPE_SCSI;
    500  1.1  reinoud 	saddr->addr.scsi.target = cam_dev->target_id;
    501  1.1  reinoud 	saddr->addr.scsi.lun    = cam_dev->target_lun;
    502  1.1  reinoud 	saddr->addr.scsi.scbus  = cam_dev->bus_id;
    503  1.1  reinoud 
    504  1.1  reinoud 	return 0;
    505  1.1  reinoud }
    506  1.1  reinoud 
    507  1.1  reinoud 
    508  1.1  reinoud int
    509  1.1  reinoud uscsi_check_for_scsi(struct uscsi_dev *disc)
    510  1.1  reinoud {
    511  1.1  reinoud 	struct uscsi_addr saddr;
    512  1.1  reinoud 
    513  1.1  reinoud 	return uscsi_identify(disc, &saddr);
    514  1.1  reinoud }
    515  1.1  reinoud 
    516  1.1  reinoud #endif	/* USCSI_FREEBSD_CAM */
    517  1.1  reinoud 
    518  1.1  reinoud 
    519  1.1  reinoud 
    520  1.1  reinoud /*
    521  1.3  msaitoh  * Generic SCSI functions also used by the sense printing functionality.
    522  1.4   andvar  * FreeBSD support has it already asked for by the CAM.
    523  1.1  reinoud  */
    524  1.1  reinoud 
    525  1.1  reinoud int
    526  1.1  reinoud uscsi_mode_sense(struct uscsi_dev *dev,
    527  1.1  reinoud 	uint8_t pgcode, uint8_t pctl, void *buf, size_t len)
    528  1.1  reinoud {
    529  1.1  reinoud 	scsicmd cmd;
    530  1.1  reinoud 
    531  1.2  msaitoh 	bzero(buf, len);		/* initialise receiving buffer	*/
    532  1.1  reinoud 
    533  1.1  reinoud 	bzero(cmd, SCSI_CMD_LEN);
    534  1.1  reinoud 	cmd[ 0] = 0x1a;			/* MODE SENSE			*/
    535  1.1  reinoud 	cmd[ 1] = 0;			/* -				*/
    536  1.1  reinoud 	cmd[ 2] = pgcode | pctl;	/* page code and control flags	*/
    537  1.1  reinoud 	cmd[ 3] = 0;			/* -				*/
    538  1.2  msaitoh 	cmd[ 4] = len;			/* length of receive buffer	*/
    539  1.1  reinoud 	cmd[ 5] = 0;			/* control			*/
    540  1.1  reinoud 
    541  1.1  reinoud 	return uscsi_command(SCSI_READCMD, dev, &cmd, 6, buf, len, 10000, NULL);
    542  1.1  reinoud }
    543  1.1  reinoud 
    544  1.1  reinoud 
    545  1.1  reinoud int
    546  1.1  reinoud uscsi_mode_select(struct uscsi_dev *dev,
    547  1.1  reinoud 	uint8_t byte2, void *buf, size_t len)
    548  1.1  reinoud {
    549  1.1  reinoud 	scsicmd cmd;
    550  1.1  reinoud 
    551  1.1  reinoud 	bzero(cmd, SCSI_CMD_LEN);
    552  1.1  reinoud 	cmd[ 0] = 0x15;			/* MODE SELECT			*/
    553  1.1  reinoud 	cmd[ 1] = 0x10 | byte2;		/* SCSI-2 page format select	*/
    554  1.1  reinoud 	cmd[ 4] = len;			/* length of page settings	*/
    555  1.1  reinoud 	cmd[ 5] = 0;			/* control			*/
    556  1.1  reinoud 
    557  1.1  reinoud 	return uscsi_command(SCSI_WRITECMD, dev, &cmd, 6, buf, len,
    558  1.1  reinoud 			10000, NULL);
    559  1.1  reinoud }
    560  1.1  reinoud 
    561  1.1  reinoud 
    562  1.1  reinoud int
    563  1.1  reinoud uscsi_request_sense(struct uscsi_dev *dev, void *buf, size_t len)
    564  1.1  reinoud {
    565  1.1  reinoud 	scsicmd cmd;
    566  1.1  reinoud 
    567  1.2  msaitoh 	bzero(buf, len);		/* initialise receiving buffer	*/
    568  1.1  reinoud 
    569  1.1  reinoud 	bzero(cmd, SCSI_CMD_LEN);
    570  1.1  reinoud 	cmd[ 0] = 0x03;			/* REQUEST SENSE		*/
    571  1.1  reinoud 	cmd[ 4] = len;			/* length of data to be read	*/
    572  1.1  reinoud 	cmd[ 5] = 0;			/* control			*/
    573  1.1  reinoud 
    574  1.1  reinoud 	return uscsi_command(SCSI_WRITECMD, dev, &cmd, 6, buf, len,
    575  1.1  reinoud 			10000, NULL);
    576  1.1  reinoud }
    577  1.1  reinoud 
    578  1.1  reinoud 
    579  1.1  reinoud /* end of uscsi_subr.c */
    580  1.1  reinoud 
    581