xref: /netbsd-src/sbin/scsictl/scsi_subr.c (revision 68ceb367018f11095da42ffdf2909d0ff49fe6ab)
1*68ceb367Sjakllsch /*	$NetBSD: scsi_subr.c,v 1.14 2012/02/21 02:22:54 jakllsch Exp $	*/
2c9a47c22Sthorpej 
3c9a47c22Sthorpej /*-
4c9a47c22Sthorpej  * Copyright (c) 1998 The NetBSD Foundation, Inc.
5c9a47c22Sthorpej  * All rights reserved.
6c9a47c22Sthorpej  *
7c9a47c22Sthorpej  * This code is derived from software contributed to The NetBSD Foundation
8c9a47c22Sthorpej  * by Charles M. Hannum; Jason R. Thorpe of the Numerical Aerospace
9c9a47c22Sthorpej  * Simulation Facility, NASA Ames Research Center.
10c9a47c22Sthorpej  *
11c9a47c22Sthorpej  * Redistribution and use in source and binary forms, with or without
12c9a47c22Sthorpej  * modification, are permitted provided that the following conditions
13c9a47c22Sthorpej  * are met:
14c9a47c22Sthorpej  * 1. Redistributions of source code must retain the above copyright
15c9a47c22Sthorpej  *    notice, this list of conditions and the following disclaimer.
16c9a47c22Sthorpej  * 2. Redistributions in binary form must reproduce the above copyright
17c9a47c22Sthorpej  *    notice, this list of conditions and the following disclaimer in the
18c9a47c22Sthorpej  *    documentation and/or other materials provided with the distribution.
19c9a47c22Sthorpej  *
20c9a47c22Sthorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21c9a47c22Sthorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22c9a47c22Sthorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23c9a47c22Sthorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24c9a47c22Sthorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25c9a47c22Sthorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26c9a47c22Sthorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27c9a47c22Sthorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28c9a47c22Sthorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29c9a47c22Sthorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30c9a47c22Sthorpej  * POSSIBILITY OF SUCH DAMAGE.
31c9a47c22Sthorpej  */
32c9a47c22Sthorpej 
33c9a47c22Sthorpej /*
34c9a47c22Sthorpej  * SCSI support subroutines.
35c9a47c22Sthorpej  *
36c9a47c22Sthorpej  * XXX THESE SHOULD BE IN A LIBRARY!
37c9a47c22Sthorpej  */
38c2a3b5ecSagc #include <sys/cdefs.h>
39c2a3b5ecSagc 
40c2a3b5ecSagc #ifndef lint
41*68ceb367Sjakllsch __RCSID("$NetBSD: scsi_subr.c,v 1.14 2012/02/21 02:22:54 jakllsch Exp $");
42c2a3b5ecSagc #endif
43c2a3b5ecSagc 
44c9a47c22Sthorpej 
45c9a47c22Sthorpej #include <sys/param.h>
46c9a47c22Sthorpej #include <sys/ioctl.h>
47c9a47c22Sthorpej #include <sys/scsiio.h>
48c9a47c22Sthorpej #include <err.h>
49c9a47c22Sthorpej #include <errno.h>
50c9a47c22Sthorpej #include <stdio.h>
51c9a47c22Sthorpej #include <stdlib.h>
52c9a47c22Sthorpej #include <string.h>
53c9a47c22Sthorpej #include <unistd.h>
54c9a47c22Sthorpej 
55df9803ceSthorpej #include <dev/scsipi/scsi_spc.h>
56c1425134Sthorpej 
57c9a47c22Sthorpej #include "extern.h"
58c9a47c22Sthorpej 
59bd8e0b62Sad #define	STRVIS_ISWHITE(x) ((x) == ' ' || (x) == '\0' || (x) == (u_char)'\377')
60bd8e0b62Sad 
61c9a47c22Sthorpej void
scsi_command(int fd,const void * cmd,size_t cmdlen,void * data,size_t datalen,int timeout,int flags)621355b3bbSjakllsch scsi_command(int fd, const void *cmd, size_t cmdlen,
631355b3bbSjakllsch 	void *data, size_t datalen, int timeout, int flags)
64c9a47c22Sthorpej {
65c9a47c22Sthorpej 	scsireq_t req;
66c9a47c22Sthorpej 
67c9a47c22Sthorpej 	memset(&req, 0, sizeof(req));
68c9a47c22Sthorpej 
69*68ceb367Sjakllsch 	cmdlen = MIN(cmdlen, sizeof(req.cmd));
70c9a47c22Sthorpej 	memcpy(req.cmd, cmd, cmdlen);
71c9a47c22Sthorpej 	req.cmdlen = cmdlen;
72c9a47c22Sthorpej 	req.databuf = data;
73c9a47c22Sthorpej 	req.datalen = datalen;
74c9a47c22Sthorpej 	req.timeout = timeout;
75c9a47c22Sthorpej 	req.flags = flags;
76c9a47c22Sthorpej 	req.senselen = SENSEBUFLEN;
77c9a47c22Sthorpej 
78c9a47c22Sthorpej 	if (ioctl(fd, SCIOCCOMMAND, &req) == -1)
79c9a47c22Sthorpej 		err(1, "SCIOCCOMMAND");
80c9a47c22Sthorpej 
81c9a47c22Sthorpej 	if (req.retsts == SCCMD_OK)
82c9a47c22Sthorpej 		return;
83c9a47c22Sthorpej 
84c9a47c22Sthorpej 	/* Some problem; report it and exit. */
8541194c0eSmjacob 	if (req.retsts == SCCMD_TIMEOUT)
86c9a47c22Sthorpej 		fprintf(stderr, "%s: SCSI command timed out\n", dvname);
8741194c0eSmjacob 	else if (req.retsts == SCCMD_BUSY)
88c9a47c22Sthorpej 		fprintf(stderr, "%s: device is busy\n", dvname);
8941194c0eSmjacob 	else if (req.retsts == SCCMD_SENSE)
90c9a47c22Sthorpej 		scsi_print_sense(dvname, &req, 1);
9141194c0eSmjacob 	else
92d7a359dbSsoren 		fprintf(stderr, "%s: device had unknown status %x\n", dvname,
9341194c0eSmjacob 		    req.retsts);
94c9a47c22Sthorpej 
95c9a47c22Sthorpej 	exit(1);
96c9a47c22Sthorpej }
97c9a47c22Sthorpej 
98c9a47c22Sthorpej void
scsi_mode_sense(int fd,u_int8_t pgcode,u_int8_t pctl,void * buf,size_t len)999bab889dSxtraeme scsi_mode_sense(int fd, u_int8_t pgcode, u_int8_t pctl, void *buf, size_t len)
100c1425134Sthorpej {
101df9803ceSthorpej 	struct scsi_mode_sense_6 cmd;
102c1425134Sthorpej 
103c1425134Sthorpej 	memset(&cmd, 0, sizeof(cmd));
104c1425134Sthorpej 	memset(buf, 0, len);
105c1425134Sthorpej 
106df9803ceSthorpej 	cmd.opcode = SCSI_MODE_SENSE_6;
107c1425134Sthorpej 	cmd.page = pgcode | pctl;
10876b6c930Sagc 	cmd.length = len;
109c1425134Sthorpej 
110c1425134Sthorpej 	scsi_command(fd, &cmd, sizeof(cmd), buf, len, 10000, SCCMD_READ);
111c1425134Sthorpej }
112c1425134Sthorpej 
113c1425134Sthorpej void
scsi_mode_select(int fd,u_int8_t byte2,void * buf,size_t len)1149bab889dSxtraeme scsi_mode_select(int fd, u_int8_t byte2, void *buf, size_t len)
115c1425134Sthorpej {
116df9803ceSthorpej 	struct scsi_mode_select_6 cmd;
117c1425134Sthorpej 
118c1425134Sthorpej 	memset(&cmd, 0, sizeof(cmd));
119c1425134Sthorpej 
120df9803ceSthorpej 	cmd.opcode = SCSI_MODE_SELECT_6;
121b92e8081Sthorpej 	cmd.byte2 = SMS_PF | byte2;
12276b6c930Sagc 	cmd.length = len;
123c1425134Sthorpej 
124c1425134Sthorpej 	scsi_command(fd, &cmd, sizeof(cmd), buf, len, 10000, SCCMD_WRITE);
125c1425134Sthorpej }
126c1425134Sthorpej 
127c1425134Sthorpej void
scsi_request_sense(int fd,void * buf,size_t len)1289bab889dSxtraeme scsi_request_sense(int fd, void *buf, size_t len)
12941194c0eSmjacob {
130df9803ceSthorpej 	struct scsi_request_sense cmd;
13141194c0eSmjacob 
13241194c0eSmjacob 	memset(&cmd, 0, sizeof(cmd));
13341194c0eSmjacob 	memset(buf, 0, len);
13441194c0eSmjacob 
135df9803ceSthorpej 	cmd.opcode = SCSI_REQUEST_SENSE;
13641194c0eSmjacob 	cmd.length = len;
13741194c0eSmjacob  	scsi_command(fd, &cmd, sizeof(cmd), buf, len, 10000, SCCMD_READ);
13841194c0eSmjacob }
13941194c0eSmjacob 
14041194c0eSmjacob void
scsi_strvis(char * sdst,size_t dlen,const char * ssrc,size_t slen)1419bab889dSxtraeme scsi_strvis(char *sdst, size_t dlen, const char *ssrc, size_t slen)
142c9a47c22Sthorpej {
143c9a47c22Sthorpej 	u_char *dst = (u_char *)sdst;
144c9a47c22Sthorpej 	const u_char *src = (const u_char *)ssrc;
145c9a47c22Sthorpej 
146c9a47c22Sthorpej 	/* Trim leading and trailing blanks and NULs. */
147bd8e0b62Sad 	while (slen > 0 && STRVIS_ISWHITE(src[0]))
148c9a47c22Sthorpej 		++src, --slen;
149bd8e0b62Sad 	while (slen > 0 && STRVIS_ISWHITE(src[slen - 1]))
150c9a47c22Sthorpej 		--slen;
151c9a47c22Sthorpej 
152c9a47c22Sthorpej 	while (slen > 0) {
153c9a47c22Sthorpej 		if (*src < 0x20 || *src >= 0x80) {
154c9a47c22Sthorpej 			/* non-printable characters */
155c9a47c22Sthorpej 			dlen -= 4;
156c9a47c22Sthorpej 			if (dlen < 1)
157c9a47c22Sthorpej 				break;
158c9a47c22Sthorpej 			*dst++ = '\\';
159c9a47c22Sthorpej 			*dst++ = ((*src & 0300) >> 6) + '0';
160c9a47c22Sthorpej 			*dst++ = ((*src & 0070) >> 3) + '0';
161c9a47c22Sthorpej 			*dst++ = ((*src & 0007) >> 0) + '0';
162c9a47c22Sthorpej 		} else if (*src == '\\') {
163c9a47c22Sthorpej 			/* quote characters */
164c9a47c22Sthorpej 			dlen -= 2;
165c9a47c22Sthorpej 			if (dlen < 1)
166c9a47c22Sthorpej 				break;
167c9a47c22Sthorpej 			*dst++ = '\\';
168c9a47c22Sthorpej 			*dst++ = '\\';
169c9a47c22Sthorpej 		} else {
170c9a47c22Sthorpej 			/* normal characters */
171c9a47c22Sthorpej 			if (--dlen < 1)
172c9a47c22Sthorpej 				break;
173c9a47c22Sthorpej 			*dst++ = *src;
174c9a47c22Sthorpej 		}
175c9a47c22Sthorpej 		++src, --slen;
176c9a47c22Sthorpej 	}
177c9a47c22Sthorpej 
178c9a47c22Sthorpej 	*dst++ = 0;
179c9a47c22Sthorpej }
180