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