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