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