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