/* $NetBSD: scsi_subr.c,v 1.14 2012/02/21 02:22:54 jakllsch Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Charles M. Hannum; Jason R. Thorpe of the Numerical Aerospace * Simulation Facility, NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * SCSI support subroutines. * * XXX THESE SHOULD BE IN A LIBRARY! */ #include #ifndef lint __RCSID("$NetBSD: scsi_subr.c,v 1.14 2012/02/21 02:22:54 jakllsch Exp $"); #endif #include #include #include #include #include #include #include #include #include #include #include "extern.h" #define STRVIS_ISWHITE(x) ((x) == ' ' || (x) == '\0' || (x) == (u_char)'\377') void scsi_command(int fd, const void *cmd, size_t cmdlen, void *data, size_t datalen, int timeout, int flags) { scsireq_t req; memset(&req, 0, sizeof(req)); cmdlen = MIN(cmdlen, sizeof(req.cmd)); memcpy(req.cmd, cmd, cmdlen); req.cmdlen = cmdlen; req.databuf = data; req.datalen = datalen; req.timeout = timeout; req.flags = flags; req.senselen = SENSEBUFLEN; if (ioctl(fd, SCIOCCOMMAND, &req) == -1) err(1, "SCIOCCOMMAND"); if (req.retsts == SCCMD_OK) return; /* Some problem; report it and exit. */ if (req.retsts == SCCMD_TIMEOUT) fprintf(stderr, "%s: SCSI command timed out\n", dvname); else if (req.retsts == SCCMD_BUSY) fprintf(stderr, "%s: device is busy\n", dvname); else if (req.retsts == SCCMD_SENSE) scsi_print_sense(dvname, &req, 1); else fprintf(stderr, "%s: device had unknown status %x\n", dvname, req.retsts); exit(1); } void scsi_mode_sense(int fd, u_int8_t pgcode, u_int8_t pctl, void *buf, size_t len) { struct scsi_mode_sense_6 cmd; memset(&cmd, 0, sizeof(cmd)); memset(buf, 0, len); cmd.opcode = SCSI_MODE_SENSE_6; cmd.page = pgcode | pctl; cmd.length = len; scsi_command(fd, &cmd, sizeof(cmd), buf, len, 10000, SCCMD_READ); } void scsi_mode_select(int fd, u_int8_t byte2, void *buf, size_t len) { struct scsi_mode_select_6 cmd; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = SCSI_MODE_SELECT_6; cmd.byte2 = SMS_PF | byte2; cmd.length = len; scsi_command(fd, &cmd, sizeof(cmd), buf, len, 10000, SCCMD_WRITE); } void scsi_request_sense(int fd, void *buf, size_t len) { struct scsi_request_sense cmd; memset(&cmd, 0, sizeof(cmd)); memset(buf, 0, len); cmd.opcode = SCSI_REQUEST_SENSE; cmd.length = len; scsi_command(fd, &cmd, sizeof(cmd), buf, len, 10000, SCCMD_READ); } void scsi_strvis(char *sdst, size_t dlen, const char *ssrc, size_t slen) { u_char *dst = (u_char *)sdst; const u_char *src = (const u_char *)ssrc; /* Trim leading and trailing blanks and NULs. */ while (slen > 0 && STRVIS_ISWHITE(src[0])) ++src, --slen; while (slen > 0 && STRVIS_ISWHITE(src[slen - 1])) --slen; while (slen > 0) { if (*src < 0x20 || *src >= 0x80) { /* non-printable characters */ dlen -= 4; if (dlen < 1) break; *dst++ = '\\'; *dst++ = ((*src & 0300) >> 6) + '0'; *dst++ = ((*src & 0070) >> 3) + '0'; *dst++ = ((*src & 0007) >> 0) + '0'; } else if (*src == '\\') { /* quote characters */ dlen -= 2; if (dlen < 1) break; *dst++ = '\\'; *dst++ = '\\'; } else { /* normal characters */ if (--dlen < 1) break; *dst++ = *src; } ++src, --slen; } *dst++ = 0; }