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