1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation; either version 2 of
5 * the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
15 * MA 02111-1307 USA
16 */
17/*
18 * Copyright (c) 2007 Douglas Gilbert.
19 * All rights reserved.
20 *
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions
23 * are met:
24 * 1. Redistributions of source code must retain the above copyright
25 *    notice, this list of conditions and the following disclaimer.
26 * 2. Redistributions in binary form must reproduce the above copyright
27 *    notice, this list of conditions and the following disclaimer in the
28 *    documentation and/or other materials provided with the distribution.
29 * 3. The name of the author may not be used to endorse or promote products
30 *    derived from this software without specific prior written permission.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * SUCH DAMAGE.
43 *
44 */
45
46/* version 1.00 2007/5/3 */
47
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <ctype.h>
52#include <unistd.h>
53#include <errno.h>
54#include <fcntl.h>
55#include <sys/param.h>
56
57/* Solaris headers */
58#include <sys/scsi/generic/commands.h>
59#include <sys/scsi/generic/status.h>
60#include <sys/scsi/impl/types.h>
61#include <sys/scsi/impl/uscsi.h>
62
63#include "sg_pt.h"
64#include "sg_lib.h"
65
66
67#define DEF_TIMEOUT 60       /* 60 seconds */
68
69struct sg_pt_solaris_scsi {
70    struct uscsi_cmd uscsi;
71    int max_sense_len;
72    int in_err;
73    int os_err;
74};
75
76struct sg_pt_base {
77    struct sg_pt_solaris_scsi impl;
78};
79
80
81
82/* Returns >= 0 if successful. If error in Unix returns negated errno. */
83int scsi_pt_open_device(const char * device_name, int read_only,
84                        int verbose)
85{
86    int oflags = O_NONBLOCK | O_RDWR;
87    int fd;
88
89    read_only = read_only;  /* ignore read_only, suppress warning */
90    if (verbose > 1) {
91        fprintf(stderr, "open %s with flags=0x%x\n", device_name, oflags);
92    }
93    fd = open(device_name, oflags);
94    if (fd < 0)
95        fd = -errno;
96    return fd;
97}
98
99/* Returns 0 if successful. If error in Unix returns negated errno. */
100int scsi_pt_close_device(int device_fd)
101{
102    int res;
103
104    res = close(device_fd);
105    if (res < 0)
106        res = -errno;
107    return res;
108}
109
110
111struct sg_pt_base * construct_scsi_pt_obj()
112{
113    struct sg_pt_solaris_scsi * ptp;
114
115    ptp = (struct sg_pt_solaris_scsi *)
116          malloc(sizeof(struct sg_pt_solaris_scsi));
117    if (ptp) {
118        memset(ptp, 0, sizeof(struct sg_pt_solaris_scsi));
119        ptp->uscsi.uscsi_timeout = DEF_TIMEOUT;
120        ptp->uscsi.uscsi_flags = USCSI_READ | USCSI_ISOLATE | USCSI_RQENABLE;
121        ptp->uscsi.uscsi_timeout = DEF_TIMEOUT;
122    }
123    return (struct sg_pt_base *)ptp;
124}
125
126void destruct_scsi_pt_obj(struct sg_pt_base * vp)
127{
128    struct sg_pt_solaris_scsi * ptp = &vp->impl;
129
130    if (ptp)
131        free(ptp);
132}
133
134void set_scsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb,
135                     int cdb_len)
136{
137    struct sg_pt_solaris_scsi * ptp = &vp->impl;
138
139    if (ptp->uscsi.uscsi_cdb)
140        ++ptp->in_err;
141    ptp->uscsi.uscsi_cdb = (char *)cdb;
142    ptp->uscsi.uscsi_cdblen = cdb_len;
143}
144
145void set_scsi_pt_sense(struct sg_pt_base * vp, unsigned char * sense,
146                       int max_sense_len)
147{
148    struct sg_pt_solaris_scsi * ptp = &vp->impl;
149
150    if (ptp->uscsi.uscsi_rqbuf)
151        ++ptp->in_err;
152    memset(sense, 0, max_sense_len);
153    ptp->uscsi.uscsi_rqbuf = (char *)sense;
154    ptp->uscsi.uscsi_rqlen = max_sense_len;
155    ptp->max_sense_len = max_sense_len;
156}
157
158void set_scsi_pt_data_in(struct sg_pt_base * vp,  /* from device */
159                         unsigned char * dxferp, int dxfer_len)
160{
161    struct sg_pt_solaris_scsi * ptp = &vp->impl;
162
163    if (ptp->uscsi.uscsi_bufaddr)
164        ++ptp->in_err;
165    if (dxfer_len > 0) {
166        ptp->uscsi.uscsi_bufaddr = (char *)dxferp;
167        ptp->uscsi.uscsi_buflen = dxfer_len;
168        ptp->uscsi.uscsi_flags = USCSI_READ | USCSI_ISOLATE | USCSI_RQENABLE;
169    }
170}
171
172void set_scsi_pt_data_out(struct sg_pt_base * vp,   /* to device */
173                          const unsigned char * dxferp, int dxfer_len)
174{
175    struct sg_pt_solaris_scsi * ptp = &vp->impl;
176
177    if (ptp->uscsi.uscsi_bufaddr)
178        ++ptp->in_err;
179    if (dxfer_len > 0) {
180        ptp->uscsi.uscsi_bufaddr = (char *)dxferp;
181        ptp->uscsi.uscsi_buflen = dxfer_len;
182        ptp->uscsi.uscsi_flags = USCSI_WRITE | USCSI_ISOLATE | USCSI_RQENABLE;
183    }
184}
185
186void set_scsi_pt_packet_id(struct sg_pt_base * vp, int pack_id)
187{
188    // struct sg_pt_solaris_scsi * ptp = &vp->impl;
189
190    vp = vp;          		/* ignore and suppress warning */
191    pack_id = pack_id;          /* ignore and suppress warning */
192}
193
194void set_scsi_pt_tag(struct sg_pt_base * vp, unsigned long long tag)
195{
196    // struct sg_pt_solaris_scsi * ptp = &vp->impl;
197
198    vp = vp;          		/* ignore and suppress warning */
199    tag = tag;          	/* ignore and suppress warning */
200}
201
202/* Note that task management function codes are transport specific */
203void set_scsi_pt_task_management(struct sg_pt_base * vp, int tmf_code)
204{
205    struct sg_pt_solaris_scsi * ptp = &vp->impl;
206
207    ++ptp->in_err;
208    tmf_code = tmf_code;        /* dummy to silence compiler */
209}
210
211void set_scsi_pt_task_attr(struct sg_pt_base * vp, int attribute,
212                           int priority)
213{
214    struct sg_pt_solaris_scsi * ptp = &vp->impl;
215
216    ++ptp->in_err;
217    attribute = attribute;      /* dummy to silence compiler */
218    priority = priority;        /* dummy to silence compiler */
219}
220
221int do_scsi_pt(struct sg_pt_base * vp, int fd, int time_secs, int verbose)
222{
223    struct sg_pt_solaris_scsi * ptp = &vp->impl;
224
225    if (ptp->in_err) {
226        if (verbose)
227            fprintf(stderr, "Replicated or unused set_scsi_pt... "
228                    "functions\n");
229        return SCSI_PT_DO_BAD_PARAMS;
230    }
231    if (NULL == ptp->uscsi.uscsi_cdb) {
232        if (verbose)
233            fprintf(stderr, "No SCSI command (cdb) given\n");
234        return SCSI_PT_DO_BAD_PARAMS;
235    }
236    if (time_secs > 0)
237        ptp->uscsi.uscsi_timeout = time_secs;
238
239    if (ioctl(fd, USCSICMD, &ptp->uscsi)) {
240        ptp->os_err = errno;
241	if ((EIO == ptp->os_err) && ptp->uscsi.uscsi_status) {
242	    ptp->os_err = 0;
243	    return 0;
244	}
245        if (verbose)
246            fprintf(stderr, "ioctl(USCSICMD) failed with os_err "
247                    "(errno) = %d\n", ptp->os_err);
248        return -ptp->os_err;
249    }
250    return 0;
251}
252
253int get_scsi_pt_result_category(const struct sg_pt_base * vp)
254{
255    const struct sg_pt_solaris_scsi * ptp = &vp->impl;
256    int scsi_st = ptp->uscsi.uscsi_status;
257
258    if (ptp->os_err)
259        return SCSI_PT_RESULT_OS_ERR;
260    else if ((SAM_STAT_CHECK_CONDITION == scsi_st) ||
261             (SAM_STAT_COMMAND_TERMINATED == scsi_st))
262        return SCSI_PT_RESULT_SENSE;
263    else if (scsi_st)
264        return SCSI_PT_RESULT_STATUS;
265    else
266        return SCSI_PT_RESULT_GOOD;
267}
268
269int get_scsi_pt_resid(const struct sg_pt_base * vp)
270{
271    const struct sg_pt_solaris_scsi * ptp = &vp->impl;
272
273    return ptp->uscsi.uscsi_resid;
274}
275
276int get_scsi_pt_status_response(const struct sg_pt_base * vp)
277{
278    const struct sg_pt_solaris_scsi * ptp = &vp->impl;
279
280    return ptp->uscsi.uscsi_status;
281}
282
283int get_scsi_pt_sense_len(const struct sg_pt_base * vp)
284{
285    const struct sg_pt_solaris_scsi * ptp = &vp->impl;
286    int res;
287
288    if (ptp->max_sense_len > 0) {
289        res = ptp->max_sense_len - ptp->uscsi.uscsi_rqresid;
290        return (res > 0) ? res : 0;
291    }
292    return 0;
293}
294
295int get_scsi_pt_duration_ms(const struct sg_pt_base * vp)
296{
297    // const struct sg_pt_solaris_scsi * ptp = &vp->impl;
298
299    vp = vp;          	/* ignore and suppress warning */
300    return -1;          /* not available */
301}
302
303int get_scsi_pt_transport_err(const struct sg_pt_base * vp)
304{
305    // const struct sg_pt_solaris_scsi * ptp = &vp->impl;
306
307    vp = vp;          	/* ignore and suppress warning */
308    return 0;
309}
310
311int get_scsi_pt_os_err(const struct sg_pt_base * vp)
312{
313    const struct sg_pt_solaris_scsi * ptp = &vp->impl;
314
315    return ptp->os_err;
316}
317
318char * get_scsi_pt_transport_err_str(const struct sg_pt_base * vp,
319                                     int max_b_len, char * b)
320{
321    // const struct sg_pt_solaris_scsi * ptp = &vp->impl;
322
323    vp = vp;          	/* ignore and suppress warning */
324    if (max_b_len > 0)
325        b[0] = '\0';
326
327    return b;
328}
329
330char * get_scsi_pt_os_err_str(const struct sg_pt_base * vp,
331                              int max_b_len, char * b)
332{
333    const struct sg_pt_solaris_scsi * ptp = &vp->impl;
334    const char * cp;
335
336    cp = safe_strerror(ptp->os_err);
337    strncpy(b, cp, max_b_len);
338    if ((int)strlen(cp) >= max_b_len)
339        b[max_b_len - 1] = '\0';
340    return b;
341}
342