1 /* @(#)scsitransp.c	1.100 16/01/21 Copyright 1988,1995,2000-2016 J. Schilling */
2 /*#ifndef lint*/
3 static	char sccsid[] =
4 	"@(#)scsitransp.c	1.100 16/01/21 Copyright 1988,1995,2000-2016 J. Schilling";
5 /*#endif*/
6 /*
7  *	SCSI user level command transport routines (generic part).
8  *
9  *	Warning: you may change this source, but if you do that
10  *	you need to change the _scg_version and _scg_auth* string below.
11  *	You may not return "schily" for an SCG_AUTHOR request anymore.
12  *	Choose your name instead of "schily" and make clear that the version
13  *	string is related to a modified source.
14  *
15  *	Copyright (c) 1988,1995,2000-2016 J. Schilling
16  */
17 /*
18  * The contents of this file are subject to the terms of the
19  * Common Development and Distribution License, Version 1.0 only
20  * (the "License").  You may not use this file except in compliance
21  * with the License.
22  *
23  * See the file CDDL.Schily.txt in this distribution for details.
24  * A copy of the CDDL is also available via the Internet at
25  * http://www.opensource.org/licenses/cddl1.txt
26  *
27  * The following exceptions apply:
28  * CDDL �3.6 needs to be replaced by: "You may create a Larger Work by
29  * combining Covered Software with other code if all other code is governed by
30  * the terms of a license that is OSI approved (see www.opensource.org) and
31  * you may distribute the Larger Work as a single product. In such a case,
32  * You must make sure the requirements of this License are fulfilled for
33  * the Covered Software."
34  *
35  * When distributing Covered Code, include this CDDL HEADER in each
36  * file and include the License file CDDL.Schily.txt from this distribution.
37  */
38 
39 #include <schily/mconfig.h>
40 #include <schily/stdio.h>
41 #include <schily/standard.h>
42 #include <schily/stdlib.h>
43 #include <schily/unistd.h>
44 #include <schily/errno.h>
45 #include <schily/time.h>
46 #include <schily/string.h>
47 #include <schily/schily.h>
48 
49 #include <scg/scgcmd.h>
50 #include <scg/scsireg.h>
51 #include <scg/scsitransp.h>
52 #include "scgtimes.h"
53 
54 /*
55  *	Warning: you may change this source, but if you do that
56  *	you need to change the _scg_version and _scg_auth* string below.
57  *	You may not return "schily" for an SCG_AUTHOR request anymore.
58  *	Choose your name instead of "schily" and make clear that the version
59  *	string is related to a modified source.
60  */
61 LOCAL	char	_scg_version[]		= "0.9";	/* The global libscg version	*/
62 LOCAL	char	_scg_auth_schily[]	= "schily";	/* The author for this module	*/
63 
64 #define	DEFTIMEOUT	20	/* Default timeout for SCSI command transport */
65 
66 EXPORT	char	*scg_version	__PR((SCSI *scgp, int what));
67 EXPORT	int	scg__open	__PR((SCSI *scgp, char *device));
68 EXPORT	int	scg__close	__PR((SCSI *scgp));
69 EXPORT	int	scg_numbus	__PR((SCSI *scgp));
70 EXPORT	BOOL	scg_havebus	__PR((SCSI *scgp, int));
71 EXPORT	int	scg_initiator_id __PR((SCSI *scgp));
72 EXPORT	int	scg_isatapi	__PR((SCSI *scgp));
73 EXPORT	int	scg_reset	__PR((SCSI *scgp, int what));
74 EXPORT	void	*scg_getbuf	__PR((SCSI *scgp, long));
75 EXPORT	void	scg_freebuf	__PR((SCSI *scgp));
76 EXPORT	long	scg_bufsize	__PR((SCSI *scgp, long));
77 EXPORT	void	scg_setnonstderrs __PR((SCSI *scgp, const char **));
78 EXPORT	BOOL	scg_yes		__PR((char *));
79 #ifdef	nonono
80 LOCAL	void	scg_sighandler	__PR((int));
81 #endif
82 EXPORT	int	scg_cmd		__PR((SCSI *scgp));
83 EXPORT	void	scg_vhead	__PR((SCSI *scgp));
84 EXPORT	int	scg_svhead	__PR((SCSI *scgp, char *buf, int maxcnt));
85 EXPORT	int	scg_vtail	__PR((SCSI *scgp));
86 EXPORT	int	scg_svtail	__PR((SCSI *scgp, int *retp, char *buf, int maxcnt));
87 EXPORT	void	scg_vsetup	__PR((SCSI *scgp));
88 EXPORT	int	scg_getresid	__PR((SCSI *scgp));
89 EXPORT	int	scg_getdmacnt	__PR((SCSI *scgp));
90 EXPORT	BOOL	scg_cmd_err	__PR((SCSI *scgp));
91 EXPORT	void	scg_printerr	__PR((SCSI *scgp));
92 EXPORT	void	scg_fprinterr	__PR((SCSI *scgp, FILE *f));
93 EXPORT	int	scg_sprinterr	__PR((SCSI *scgp, char *buf, int maxcnt));
94 EXPORT	int	scg__sprinterr	__PR((SCSI *scgp, char *buf, int maxcnt));
95 EXPORT	void	scg_printcdb	__PR((SCSI *scgp));
96 EXPORT	int	scg_sprintcdb	__PR((SCSI *scgp, char *buf, int maxcnt));
97 EXPORT	void	scg_printwdata	__PR((SCSI *scgp));
98 EXPORT	int	scg_sprintwdata	__PR((SCSI *scgp, char *buf, int maxcnt));
99 EXPORT	void	scg_printrdata	__PR((SCSI *scgp));
100 EXPORT	int	scg_sprintrdata	__PR((SCSI *scgp, char *buf, int maxcnt));
101 EXPORT	void	scg_printresult	__PR((SCSI *scgp));
102 EXPORT	int	scg_sprintresult __PR((SCSI *scgp, char *buf, int maxcnt));
103 EXPORT	void	scg_printstatus	__PR((SCSI *scgp));
104 EXPORT	int	scg_sprintstatus __PR((SCSI *scgp, char *buf, int maxcnt));
105 EXPORT	void	scg_fprbytes	__PR((FILE *, char *, unsigned char *, int));
106 EXPORT	void	scg_fprascii	__PR((FILE *, char *, unsigned char *, int));
107 EXPORT	void	scg_prbytes	__PR((char *, unsigned char *, int));
108 EXPORT	void	scg_prascii	__PR((char *, unsigned char *, int));
109 EXPORT	int	scg_sprbytes	__PR((char *buf, int maxcnt, char *, unsigned char *, int));
110 EXPORT	int	scg_sprascii	__PR((char *buf, int maxcnt, char *, unsigned char *, int));
111 EXPORT	void	scg_fprsense	__PR((FILE *f, unsigned char *, int));
112 EXPORT	int	scg_sprsense	__PR((char *buf, int maxcnt, unsigned char *, int));
113 EXPORT	void	scg_prsense	__PR((unsigned char *, int));
114 EXPORT	int	scg_cmd_status	__PR((SCSI *scgp));
115 EXPORT	int	scg_sense_key	__PR((SCSI *scgp));
116 EXPORT	int	scg_sense_code	__PR((SCSI *scgp));
117 EXPORT	int	scg_sense_qual	__PR((SCSI *scgp));
118 EXPORT	void	scg_fprintdev	__PR((FILE *, struct scsi_inquiry *));
119 EXPORT	void	scg_printdev	__PR((struct scsi_inquiry *));
120 EXPORT	int	scg_printf	__PR((SCSI *scgp, const char *form, ...));
121 EXPORT	int	scg_errflush	__PR((SCSI *scgp));
122 EXPORT	int	scg_errfflush	__PR((SCSI *scgp, FILE *f));
123 
124 /*
125  * Return version information for the SCSI transport code.
126  * This has been introduced to make it easier to trace down problems
127  * in applications.
128  *
129  * If scgp is NULL, return general library version information.
130  * If scgp is != NULL, return version information for the low level transport.
131  */
132 EXPORT char *
scg_version(scgp,what)133 scg_version(scgp, what)
134 	SCSI	*scgp;
135 	int	what;
136 {
137 	if (scgp == (SCSI *)0) {
138 		switch (what) {
139 
140 		case SCG_VERSION:
141 			return (_scg_version);
142 		/*
143 		 * If you changed this source, you are not allowed to
144 		 * return "schily" for the SCG_AUTHOR request.
145 		 */
146 		case SCG_AUTHOR:
147 			return (_scg_auth_schily);
148 		case SCG_SCCS_ID:
149 			return (sccsid);
150 		default:
151 			return ((char *)0);
152 		}
153 	}
154 	return (SCGO_VERSION(scgp, what));
155 }
156 
157 /*
158  * Call low level SCSI open routine from transport abstraction layer.
159  */
160 EXPORT int
scg__open(scgp,device)161 scg__open(scgp, device)
162 	SCSI	*scgp;
163 	char	*device;
164 {
165 	int	ret;
166 	scg_ops_t *ops;
167 extern	scg_ops_t scg_std_ops;
168 
169 	/*
170 	 * Begin restricted code for quality assurance.
171 	 *
172 	 * Warning: you are not allowed to modify the quality ensurance code below.
173 	 *
174 	 * This restiction is introduced because this way, I hope that people
175 	 * contribute to the project instead of creating branches.
176 	 */
177 #if	!defined(IS_SCHILY_XCONFIG)
178 	printf("\nWarning: This version of libscg has not been configured via the standard\n");
179 	printf("autoconfiguration method of the Schily makefile system. There is a high risk\n");
180 	printf("that the code is not configured correctly and for this reason will not behave\n");
181 	printf("as expected.\n");
182 #endif
183 	/*
184 	 * End restricted code for quality assurance.
185 	 */
186 
187 	scgp->ops = &scg_std_ops;
188 
189 	if (device && strncmp(device, "REMOTE", 6) == 0) {
190 		ops = scg_remote();
191 		if (ops != NULL)
192 			scgp->ops = ops;
193 	}
194 
195 	ret = SCGO_OPEN(scgp, device);
196 	if (ret < 0)
197 		return (ret);
198 
199 	/*
200 	 * Now make scgp->fd valid if possible.
201 	 * Note that scg_scsibus(scgp)/scg_target(scgp)/scg_lun(scgp) may have
202 	 * changed in SCGO_OPEN().
203 	 */
204 	scg_settarget(scgp, scg_scsibus(scgp), scg_target(scgp), scg_lun(scgp));
205 	return (ret);
206 }
207 
208 /*
209  * Call low level SCSI close routine from transport abstraction layer.
210  */
211 EXPORT int
scg__close(scgp)212 scg__close(scgp)
213 	SCSI	*scgp;
214 {
215 	return (SCGO_CLOSE(scgp));
216 }
217 
218 /*
219  * Retrieve max DMA count for this target.
220  */
221 EXPORT long
scg_bufsize(scgp,amt)222 scg_bufsize(scgp, amt)
223 	SCSI	*scgp;
224 	long	amt;
225 {
226 	long	maxdma;
227 
228 	maxdma = SCGO_MAXDMA(scgp, amt);
229 	if (amt <= 0 || amt > maxdma)
230 		amt = maxdma;
231 
232 	scgp->maxdma = maxdma;	/* Max possible  */
233 	scgp->maxbuf = amt;	/* Current value */
234 
235 	return (amt);
236 }
237 
238 /*
239  * Allocate a buffer that may be used for DMA.
240  */
241 EXPORT void *
scg_getbuf(scgp,amt)242 scg_getbuf(scgp, amt)
243 	SCSI	*scgp;
244 	long	amt;
245 {
246 	void	*buf;
247 
248 	if (amt <= 0 || amt > scg_bufsize(scgp, amt))
249 		return ((void *)0);
250 
251 	buf = SCGO_GETBUF(scgp, amt);
252 	scgp->bufptr = buf;
253 	return (buf);
254 }
255 
256 /*
257  * Free DMA buffer.
258  */
259 EXPORT void
scg_freebuf(scgp)260 scg_freebuf(scgp)
261 	SCSI	*scgp;
262 {
263 	SCGO_FREEBUF(scgp);
264 	scgp->bufptr = NULL;
265 }
266 
267 /*
268  * Return the max. number of SCSI busses.
269  */
270 EXPORT BOOL
scg_numbus(scgp)271 scg_numbus(scgp)
272 	SCSI	*scgp;
273 {
274 	return (SCGO_NUMBUS(scgp));
275 }
276 
277 /*
278  * Check if 'busno' is a valid SCSI bus number.
279  */
280 EXPORT BOOL
scg_havebus(scgp,busno)281 scg_havebus(scgp, busno)
282 	SCSI	*scgp;
283 	int	busno;
284 {
285 	return (SCGO_HAVEBUS(scgp, busno));
286 }
287 
288 /*
289  * Return SCSI initiator ID for current SCSI bus if available.
290  */
291 EXPORT int
scg_initiator_id(scgp)292 scg_initiator_id(scgp)
293 	SCSI	*scgp;
294 {
295 	return (SCGO_INITIATOR_ID(scgp));
296 }
297 
298 /*
299  * Return a hint whether current SCSI target refers to a ATAPI device.
300  */
301 EXPORT int
scg_isatapi(scgp)302 scg_isatapi(scgp)
303 	SCSI	*scgp;
304 {
305 	return (SCGO_ISATAPI(scgp));
306 }
307 
308 /*
309  * Reset SCSI bus or target.
310  */
311 EXPORT int
scg_reset(scgp,what)312 scg_reset(scgp, what)
313 	SCSI	*scgp;
314 	int	what;
315 {
316 	return (SCGO_RESET(scgp, what));
317 }
318 
319 /*
320  * Set up nonstd error vector for curren target.
321  * To clear additional error table, call scg_setnonstderrs(scgp, NULL);
322  * Note: do not use this when scanning the SCSI bus.
323  */
324 EXPORT void
scg_setnonstderrs(scgp,vec)325 scg_setnonstderrs(scgp, vec)
326 	SCSI	*scgp;
327 	const char **vec;
328 {
329 	scgp->nonstderrs = vec;
330 }
331 
332 /*
333  * Simple Yes/No answer checker.
334  */
335 EXPORT BOOL
scg_yes(msg)336 scg_yes(msg)
337 	char	*msg;
338 {
339 	char okbuf[10];
340 
341 	js_printf("%s", msg);
342 	flush();
343 	if (getline(okbuf, sizeof (okbuf)) == EOF)
344 		exit(EX_BAD);
345 	if (streql(okbuf, "y") || streql(okbuf, "yes") ||
346 	    streql(okbuf, "Y") || streql(okbuf, "YES"))
347 		return (TRUE);
348 	else
349 		return (FALSE);
350 }
351 
352 #ifdef	nonono
353 LOCAL void
scg_sighandler(sig)354 scg_sighandler(sig)
355 	int	sig;
356 {
357 	js_printf("\n");
358 	if (scsi_running) {
359 		js_printf("Running command: %s\n", scsi_command);
360 		js_printf("Resetting SCSI - Bus.\n");
361 		if (scg_reset(scgp) < 0)
362 			errmsg("Cannot reset SCSI - Bus.\n");
363 	}
364 	if (scg_yes("EXIT ? "))
365 		exit(sig);
366 }
367 #endif
368 
369 /*
370  * Send a SCSI command.
371  * Do error checking and reporting depending on the values of
372  * scgp->verbose, scgp->debug and scgp->silent.
373  */
374 EXPORT int
scg_cmd(scgp)375 scg_cmd(scgp)
376 	SCSI	*scgp;
377 {
378 		int		ret;
379 	register struct	scg_cmd	*scmd = scgp->scmd;
380 
381 	/*
382 	 * Reset old error messages in scgp->errstr
383 	 */
384 	scgp->errptr = scgp->errbeg = scgp->errstr;
385 
386 	scmd->kdebug = scgp->kdebug;
387 	if (scmd->timeout == 0 || scmd->timeout < scgp->deftimeout)
388 		scmd->timeout = scgp->deftimeout;
389 	if (scgp->disre_disable)
390 		scmd->flags &= ~SCG_DISRE_ENA;
391 	if (scgp->noparity)
392 		scmd->flags |= SCG_NOPARITY;
393 
394 	scmd->u_sense.cmd_sense[0] = 0;		/* Paranioa */
395 	if (scmd->sense_len > SCG_MAX_SENSE)
396 		scmd->sense_len = SCG_MAX_SENSE;
397 	else if (scmd->sense_len < 0)
398 		scmd->sense_len = 0;
399 
400 	if (scgp->verbose) {
401 		scg_vhead(scgp);
402 		scg_errflush(scgp);
403 	}
404 
405 	if (scgp->running) {
406 		if (scgp->curcmdname) {
407 			error("Currently running '%s' command.\n",
408 							scgp->curcmdname);
409 		}
410 		raisecond("SCSI ALREADY RUNNING !!", 0L);
411 	}
412 	scgp->cb_fun = NULL;
413 	gettimeofday(scgp->cmdstart, (struct timezone *)0);
414 	scgp->curcmdname = scgp->cmdname;
415 	scgp->running = TRUE;
416 	ret = SCGO_SEND(scgp);
417 	scgp->running = FALSE;
418 	__scg_times(scgp);
419 	if (scgp->flags & SCGF_IGN_RESID)
420 		scmd->resid = 0;
421 	if (ret < 0) {
422 		if (scmd->ux_errno == 0)
423 			scmd->ux_errno = geterrno();
424 		if (scmd->error == SCG_NO_ERROR)
425 			scmd->error = SCG_FATAL;
426 		if (scgp->debug > 0) {
427 			errmsg("ret < 0 errno: %d ux_errno: %d error: %d\n",
428 					geterrno(), scmd->ux_errno, scmd->error);
429 		}
430 		if (scmd->ux_errno == EPERM && scgp->flags & SCGF_PERM_PRINT) {
431 			char	errbuf[SCSI_ERRSTR_SIZE];
432 			int	amt;
433 
434 			amt = scg__sprinterr(scgp, errbuf, sizeof (errbuf));
435 			if (amt > 0) {
436 				FILE	*f = scgp->errfile;
437 
438 				if (f == NULL)
439 					f = stderr;
440 				filewrite(f, errbuf, amt);
441 				ferrmsgno(f, scmd->ux_errno,
442 					"Cannot send SCSI cmd via ioctl.\n");
443 				fflush(f);
444 			}
445 		}
446 		/*
447 		 * Old /dev/scg versions will not allow to access targets > 7.
448 		 * Include a workaround to make this non fatal.
449 		 */
450 		if (scg_target(scgp) < 8 || scmd->ux_errno != EINVAL) {
451 
452 			if (scmd->ux_errno != EPERM ||
453 			    (scgp->flags & SCGF_PERM_PRINT) == 0) {
454 				errmsgno(scmd->ux_errno,
455 					"Cannot send SCSI cmd via ioctl.\n");
456 			}
457 			if (scgp->flags & SCGF_PERM_EXIT)
458 				comexit(scmd->ux_errno);
459 		}
460 	}
461 
462 	ret = scg_vtail(scgp);
463 	scg_errflush(scgp);
464 	if (scgp->cb_fun != NULL)
465 		(*scgp->cb_fun)(scgp->cb_arg);
466 	return (ret);
467 }
468 
469 /*
470  * Fill the head of verbose printing into the SCSI error buffer.
471  * Action depends on SCSI verbose status.
472  */
473 EXPORT void
scg_vhead(scgp)474 scg_vhead(scgp)
475 	SCSI	*scgp;
476 {
477 	scgp->errptr += scg_svhead(scgp, scgp->errptr, scg_errrsize(scgp));
478 }
479 
480 /*
481  * Fill the head of verbose printing into a buffer.
482  * Action depends on SCSI verbose status.
483  */
484 EXPORT int
scg_svhead(scgp,buf,maxcnt)485 scg_svhead(scgp, buf, maxcnt)
486 	SCSI	*scgp;
487 	char	*buf;
488 	int	maxcnt;
489 {
490 	register char	*p = buf;
491 	register int	amt;
492 
493 	if (scgp->verbose <= 0)
494 		return (0);
495 
496 	amt = js_snprintf(p, maxcnt,
497 		"\nExecuting '%s' command on Bus %d Target %d, Lun %d timeout %ds\n",
498 								/* XXX Really this ??? */
499 /*		scgp->cmdname, scg_scsibus(scgp), scg_target(scgp), scgp->scmd->cdb.g0_cdb.lun,*/
500 		scgp->cmdname, scg_scsibus(scgp), scg_target(scgp), scg_lun(scgp),
501 		scgp->scmd->timeout);
502 	if (amt < 0)
503 		return (amt);
504 	p += amt;
505 	maxcnt -= amt;
506 
507 	amt = scg_sprintcdb(scgp, p, maxcnt);
508 	if (amt < 0)
509 		return (amt);
510 	p += amt;
511 	maxcnt -= amt;
512 
513 	if (scgp->verbose > 1) {
514 		amt = scg_sprintwdata(scgp, p, maxcnt);
515 		if (amt < 0)
516 			return (amt);
517 		p += amt;
518 		maxcnt -= amt;
519 	}
520 	return (p - buf);
521 }
522 
523 /*
524  * Fill the tail of verbose printing into the SCSI error buffer.
525  * Action depends on SCSI verbose status.
526  */
527 EXPORT int
scg_vtail(scgp)528 scg_vtail(scgp)
529 	SCSI	*scgp;
530 {
531 	int	ret;
532 
533 	scgp->errptr += scg_svtail(scgp, &ret, scgp->errptr, scg_errrsize(scgp));
534 	return (ret);
535 }
536 
537 /*
538  * Fill the tail of verbose printing into a buffer.
539  * Action depends on SCSI verbose status.
540  */
541 EXPORT int
scg_svtail(scgp,retp,buf,maxcnt)542 scg_svtail(scgp, retp, buf, maxcnt)
543 	SCSI	*scgp;
544 	int	*retp;
545 	char	*buf;
546 	int	maxcnt;
547 {
548 	register char	*p = buf;
549 	register int	amt;
550 	int	ret;
551 
552 	ret = scg_cmd_err(scgp) ? -1 : 0;
553 	if (retp)
554 		*retp = ret;
555 	if (ret) {
556 		if (scgp->silent <= 0 || scgp->verbose) {
557 			amt = scg__sprinterr(scgp, p, maxcnt);
558 			if (amt < 0)
559 				return (amt);
560 			p += amt;
561 			maxcnt -= amt;
562 		}
563 	}
564 	if ((scgp->silent <= 0 || scgp->verbose) && scgp->scmd->resid) {
565 		if (scgp->scmd->resid < 0) {
566 			/*
567 			 * An operating system that does DMA the right way
568 			 * will not allow DMA overruns - it will stop DMA
569 			 * before bad things happen.
570 			 * A DMA residual count < 0 (-1) is a hint for a DMA
571 			 * overrun but does not affect the transfer count.
572 			 */
573 			amt = js_snprintf(p, maxcnt, "DMA overrun, ");
574 			if (amt < 0)
575 				return (amt);
576 			p += amt;
577 			maxcnt -= amt;
578 		}
579 		amt = js_snprintf(p, maxcnt, "resid: %d\n", scgp->scmd->resid);
580 		if (amt < 0)
581 			return (amt);
582 		p += amt;
583 		maxcnt -= amt;
584 	}
585 	if (scgp->verbose > 0 || (ret < 0 && scgp->silent <= 0)) {
586 		amt = scg_sprintresult(scgp, p, maxcnt);
587 		if (amt < 0)
588 			return (amt);
589 		p += amt;
590 		maxcnt -= amt;
591 	}
592 	return (p - buf);
593 }
594 
595 /*
596  * Set up SCSI error buffer with verbose print data.
597  * Action depends on SCSI verbose status.
598  */
599 EXPORT void
scg_vsetup(scgp)600 scg_vsetup(scgp)
601 	SCSI	*scgp;
602 {
603 	scg_vhead(scgp);
604 	scg_vtail(scgp);
605 }
606 
607 /*
608  * Return the residual DMA count for last command.
609  * If this count is < 0, then a DMA overrun occured.
610  */
611 EXPORT int
scg_getresid(scgp)612 scg_getresid(scgp)
613 	SCSI	*scgp;
614 {
615 	return (scgp->scmd->resid);
616 }
617 
618 /*
619  * Return the actual DMA count for last command.
620  */
621 EXPORT int
scg_getdmacnt(scgp)622 scg_getdmacnt(scgp)
623 	SCSI	*scgp;
624 {
625 	register struct scg_cmd *scmd = scgp->scmd;
626 
627 	if (scmd->resid < 0)
628 		return (scmd->size);
629 
630 	return (scmd->size - scmd->resid);
631 }
632 
633 /*
634  * Test if last SCSI command got an error.
635  */
636 EXPORT BOOL
scg_cmd_err(scgp)637 scg_cmd_err(scgp)
638 	SCSI	*scgp;
639 {
640 	register struct scg_cmd *cp = scgp->scmd;
641 
642 	if (cp->error != SCG_NO_ERROR ||
643 				cp->ux_errno != 0 ||
644 				*(Uchar *)&cp->scb != 0 ||
645 				cp->u_sense.cmd_sense[0] != 0)	/* Paranioa */
646 		return (TRUE);
647 	return (FALSE);
648 }
649 
650 /*
651  * Used to print error messges if the command itself has been run silently.
652  *
653  * print the following SCSI codes:
654  *
655  * -	command transport status
656  * -	CDB
657  * -	SCSI status byte
658  * -	Sense Bytes
659  * -	Decoded Sense data
660  * -	DMA status
661  * -	SCSI timing
662  *
663  * to SCSI errfile.
664  */
665 EXPORT void
scg_printerr(scgp)666 scg_printerr(scgp)
667 	SCSI	*scgp;
668 {
669 	scg_fprinterr(scgp, (FILE *)scgp->errfile);
670 }
671 
672 /*
673  * print the following SCSI codes:
674  *
675  * -	command transport status
676  * -	CDB
677  * -	SCSI status byte
678  * -	Sense Bytes
679  * -	Decoded Sense data
680  * -	DMA status
681  * -	SCSI timing
682  *
683  * to a file.
684  */
685 EXPORT void
scg_fprinterr(scgp,f)686 scg_fprinterr(scgp, f)
687 	SCSI	*scgp;
688 	FILE	*f;
689 {
690 	char	errbuf[SCSI_ERRSTR_SIZE];
691 	int	amt;
692 
693 	amt = scg_sprinterr(scgp, errbuf, sizeof (errbuf));
694 	if (amt > 0) {
695 		filewrite(f, errbuf, amt);
696 		fflush(f);
697 	}
698 }
699 
700 /*
701  * print the following SCSI codes:
702  *
703  * -	command transport status
704  * -	CDB
705  * -	SCSI status byte
706  * -	Sense Bytes
707  * -	Decoded Sense data
708  * -	DMA status
709  * -	SCSI timing
710  *
711  * into a buffer.
712  */
713 EXPORT int
scg_sprinterr(scgp,buf,maxcnt)714 scg_sprinterr(scgp, buf, maxcnt)
715 	SCSI	*scgp;
716 	char	*buf;
717 	int	maxcnt;
718 {
719 	int	amt;
720 	int	osilent = scgp->silent;
721 	int	overbose = scgp->verbose;
722 
723 	scgp->silent = 0;
724 	scgp->verbose = 0;
725 	amt = scg_svtail(scgp, NULL, buf, maxcnt);
726 	scgp->silent = osilent;
727 	scgp->verbose = overbose;
728 	return (amt);
729 }
730 
731 /*
732  * print the following SCSI codes:
733  *
734  * -	command transport status
735  * -	CDB
736  * -	SCSI status byte
737  * -	Sense Bytes
738  * -	Decoded Sense data
739  *
740  * into a buffer.
741  */
742 EXPORT int
scg__sprinterr(scgp,buf,maxcnt)743 scg__sprinterr(scgp, buf, maxcnt)
744 	SCSI	*scgp;
745 	char	*buf;
746 	int	maxcnt;
747 {
748 	register struct scg_cmd *cp = scgp->scmd;
749 	register char		*err;
750 		char		*cmdname = "SCSI command name not set by caller";
751 		char		errbuf[64];
752 	register char		*p = buf;
753 	register int		amt;
754 
755 	switch (cp->error) {
756 
757 	case SCG_NO_ERROR :	err = "no error"; break;
758 	case SCG_RETRYABLE:	err = "retryable error"; break;
759 	case SCG_FATAL    :	err = "fatal error"; break;
760 				/*
761 				 * We need to cast timeval->* to long because
762 				 * of the broken sys/time.h in Linux.
763 				 */
764 	case SCG_TIMEOUT  :	js_snprintf(errbuf, sizeof (errbuf),
765 					"cmd timeout after %ld.%03ld (%d) s",
766 					(long)scgp->cmdstop->tv_sec,
767 					(long)scgp->cmdstop->tv_usec/1000,
768 								cp->timeout);
769 				err = errbuf;
770 				break;
771 	default:		js_snprintf(errbuf, sizeof (errbuf),
772 					"error: %d", cp->error);
773 				err = errbuf;
774 	}
775 
776 	if (scgp->cmdname != NULL && scgp->cmdname[0] != '\0')
777 		cmdname = scgp->cmdname;
778 	amt = serrmsgno(cp->ux_errno, p, maxcnt, "%s: scsi sendcmd: %s\n", cmdname, err);
779 	if (amt < 0)
780 		return (amt);
781 	p += amt;
782 	maxcnt -= amt;
783 
784 	amt = scg_sprintcdb(scgp, p, maxcnt);
785 	if (amt < 0)
786 		return (amt);
787 	p += amt;
788 	maxcnt -= amt;
789 
790 	if (cp->error <= SCG_RETRYABLE) {
791 		amt = scg_sprintstatus(scgp, p, maxcnt);
792 		if (amt < 0)
793 			return (amt);
794 		p += amt;
795 		maxcnt -= amt;
796 	}
797 
798 	if (cp->scb.chk) {
799 		amt = scg_sprsense(p, maxcnt, (Uchar *)&cp->sense, cp->sense_count);
800 		if (amt < 0)
801 			return (amt);
802 		p += amt;
803 		maxcnt -= amt;
804 		amt = scg__errmsg(scgp, p, maxcnt, &cp->sense, &cp->scb, -1);
805 		if (amt < 0)
806 			return (amt);
807 		p += amt;
808 		maxcnt -= amt;
809 	}
810 	return (p - buf);
811 }
812 
813 /*
814  * XXX Do we need this function?
815  *
816  * print the SCSI Command descriptor block to XXX stderr.
817  */
818 EXPORT void
scg_printcdb(scgp)819 scg_printcdb(scgp)
820 	SCSI	*scgp;
821 {
822 	scg_prbytes("CDB: ", scgp->scmd->cdb.cmd_cdb, scgp->scmd->cdb_len);
823 }
824 
825 /*
826  * print the SCSI Command descriptor block into a buffer.
827  */
828 EXPORT int
scg_sprintcdb(scgp,buf,maxcnt)829 scg_sprintcdb(scgp, buf, maxcnt)
830 	SCSI	*scgp;
831 	char	*buf;
832 	int	maxcnt;
833 {
834 	int	cnt;
835 
836 	cnt = scg_sprbytes(buf, maxcnt, "CDB: ", scgp->scmd->cdb.cmd_cdb, scgp->scmd->cdb_len);
837 	if (cnt < 0)
838 		cnt = 0;
839 	return (cnt);
840 }
841 
842 /*
843  * XXX Do we need this function?
844  * XXX scg_printrdata() is used.
845  * XXX We need to check if we should write to stderr or better to scg->errfile
846  *
847  * print the SCSI send data to stderr.
848  */
849 EXPORT void
scg_printwdata(scgp)850 scg_printwdata(scgp)
851 	SCSI	*scgp;
852 {
853 	register struct	scg_cmd	*scmd = scgp->scmd;
854 
855 	if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) == 0) {
856 		js_fprintf(stderr, "Sending %d (0x%X) bytes of data.\n",
857 			scmd->size, scmd->size);
858 		scg_prbytes("Write Data: ",
859 			(Uchar *)scmd->addr,
860 			scmd->size > 100 ? 100 : scmd->size);
861 	}
862 }
863 
864 /*
865  * print the SCSI send data into a buffer.
866  */
867 EXPORT int
scg_sprintwdata(scgp,buf,maxcnt)868 scg_sprintwdata(scgp, buf, maxcnt)
869 	SCSI	*scgp;
870 	char	*buf;
871 	int	maxcnt;
872 {
873 	register struct	scg_cmd	*scmd = scgp->scmd;
874 	register char		*p = buf;
875 	register int		amt;
876 
877 	if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) == 0) {
878 		amt = js_snprintf(p, maxcnt,
879 			"Sending %d (0x%X) bytes of data.\n",
880 			scmd->size, scmd->size);
881 		if (amt < 0)
882 			return (amt);
883 		p += amt;
884 		maxcnt -= amt;
885 		amt = scg_sprbytes(p, maxcnt, "Write Data: ",
886 			(Uchar *)scmd->addr,
887 			scmd->size > 100 ? 100 : scmd->size);
888 		if (amt < 0)
889 			return (amt);
890 		p += amt;
891 	}
892 	return (p - buf);
893 }
894 
895 /*
896  * XXX We need to check if we should write to stderr or better to scg->errfile
897  *
898  * print the SCSI received data to stderr.
899  */
900 EXPORT void
scg_printrdata(scgp)901 scg_printrdata(scgp)
902 	SCSI	*scgp;
903 {
904 	register struct	scg_cmd	*scmd = scgp->scmd;
905 	register int		trcnt = scg_getdmacnt(scgp);
906 
907 	if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) != 0) {
908 		js_fprintf(stderr, "Got %d (0x%X), expecting %d (0x%X) bytes of data.\n",
909 			trcnt, trcnt,
910 			scmd->size, scmd->size);
911 		scg_prbytes("Received Data: ",
912 			(Uchar *)scmd->addr,
913 			trcnt > 100 ? 100 : trcnt);
914 	}
915 }
916 
917 /*
918  * print the SCSI received data into a buffer.
919  */
920 EXPORT int
scg_sprintrdata(scgp,buf,maxcnt)921 scg_sprintrdata(scgp, buf, maxcnt)
922 	SCSI	*scgp;
923 	char	*buf;
924 	int	maxcnt;
925 {
926 	register struct	scg_cmd	*scmd = scgp->scmd;
927 	register char		*p = buf;
928 	register int		amt;
929 	register int		trcnt = scg_getdmacnt(scgp);
930 
931 	if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) != 0) {
932 		amt = js_snprintf(p, maxcnt,
933 			"Got %d (0x%X), expecting %d (0x%X) bytes of data.\n",
934 			trcnt, trcnt,
935 			scmd->size, scmd->size);
936 		if (amt < 0)
937 			return (amt);
938 		p += amt;
939 		maxcnt -= amt;
940 		amt = scg_sprbytes(p, maxcnt,
941 			"Received Data: ",
942 			(Uchar *)scmd->addr,
943 			trcnt > 100 ? 100 : trcnt);
944 		if (amt < 0)
945 			return (amt);
946 		p += amt;
947 	}
948 	return (p - buf);
949 }
950 
951 /*
952  * XXX We need to check if we should write to stderr or better to scg->errfile
953  *
954  * print the SCSI timings and (depending on verbose) received data to stderr.
955  */
956 EXPORT void
scg_printresult(scgp)957 scg_printresult(scgp)
958 	SCSI	*scgp;
959 {
960 	js_fprintf(stderr, "cmd finished after %ld.%03lds timeout %ds\n",
961 		(long)scgp->cmdstop->tv_sec,
962 		(long)scgp->cmdstop->tv_usec/1000,
963 		scgp->scmd->timeout);
964 	if (scgp->verbose > 1)
965 		scg_printrdata(scgp);
966 	flush();
967 }
968 
969 /*
970  * print the SCSI timings and (depending on verbose) received data into a buffer.
971  */
972 EXPORT int
scg_sprintresult(scgp,buf,maxcnt)973 scg_sprintresult(scgp, buf, maxcnt)
974 	SCSI	*scgp;
975 	char	*buf;
976 	int	maxcnt;
977 {
978 	register char		*p = buf;
979 	register int		amt;
980 
981 	amt = js_snprintf(p, maxcnt,
982 		"cmd finished after %ld.%03lds timeout %ds\n",
983 		(long)scgp->cmdstop->tv_sec,
984 		(long)scgp->cmdstop->tv_usec/1000,
985 		scgp->scmd->timeout);
986 	if (amt < 0)
987 		return (amt);
988 	p += amt;
989 	maxcnt -= amt;
990 	if (scgp->verbose > 1) {
991 		amt = scg_sprintrdata(scgp, p, maxcnt);
992 		if (amt < 0)
993 			return (amt);
994 		p += amt;
995 	}
996 	return (p - buf);
997 }
998 
999 /*
1000  * XXX Do we need this function?
1001  *
1002  * print the SCSI status byte in human readable form to the SCSI error file.
1003  */
1004 EXPORT void
scg_printstatus(scgp)1005 scg_printstatus(scgp)
1006 	SCSI	*scgp;
1007 {
1008 	char	errbuf[SCSI_ERRSTR_SIZE];
1009 	int	amt;
1010 
1011 	amt = scg_sprintstatus(scgp, errbuf, sizeof (errbuf));
1012 	if (amt > 0) {
1013 		filewrite((FILE *)scgp->errfile, errbuf, amt);
1014 		fflush((FILE *)scgp->errfile);
1015 	}
1016 }
1017 
1018 /*
1019  * print the SCSI status byte in human readable form into a buffer.
1020  */
1021 EXPORT int
scg_sprintstatus(scgp,buf,maxcnt)1022 scg_sprintstatus(scgp, buf, maxcnt)
1023 	SCSI	*scgp;
1024 	char	*buf;
1025 	int	maxcnt;
1026 {
1027 	register struct scg_cmd *cp = scgp->scmd;
1028 		char	*err;
1029 		char	*err2 = "";
1030 	register char	*p = buf;
1031 	register int	amt;
1032 
1033 	amt = js_snprintf(p, maxcnt, "status: 0x%x ", *(Uchar *)&cp->scb);
1034 	if (amt < 0)
1035 		return (amt);
1036 	p += amt;
1037 	maxcnt -= amt;
1038 #ifdef	SCSI_EXTENDED_STATUS
1039 	if (cp->scb.ext_st1) {
1040 		amt = js_snprintf(p, maxcnt, "0x%x ", ((Uchar *)&cp->scb)[1]);
1041 		if (amt < 0)
1042 			return (amt);
1043 		p += amt;
1044 		maxcnt -= amt;
1045 	}
1046 	if (cp->scb.ext_st2) {
1047 		amt = js_snprintf(p, maxcnt, "0x%x ", ((Uchar *)&cp->scb)[2]);
1048 		if (amt < 0)
1049 			return (amt);
1050 		p += amt;
1051 		maxcnt -= amt;
1052 	}
1053 #endif
1054 	switch (*(Uchar *)&cp->scb & 036) {
1055 
1056 	case 0  : err = "GOOD STATUS";			break;
1057 	case 02 : err = "CHECK CONDITION";		break;
1058 	case 04 : err = "CONDITION MET/GOOD";		break;
1059 	case 010: err = "BUSY";				break;
1060 	case 020: err = "INTERMEDIATE GOOD STATUS";	break;
1061 	case 024: err = "INTERMEDIATE CONDITION MET/GOOD"; break;
1062 	case 030: err = "RESERVATION CONFLICT";		break;
1063 	default : err = "Reserved";			break;
1064 	}
1065 #ifdef	SCSI_EXTENDED_STATUS
1066 	if (cp->scb.ext_st1 && cp->scb.ha_er)
1067 		err2 = " host adapter detected error";
1068 #endif
1069 	amt = js_snprintf(p, maxcnt, "(%s%s)\n", err, err2);
1070 	if (amt < 0)
1071 		return (amt);
1072 	p += amt;
1073 	return (p - buf);
1074 }
1075 
1076 /*
1077  * print some bytes in hex to a file.
1078  */
1079 EXPORT void
scg_fprbytes(f,s,cp,n)1080 scg_fprbytes(f, s, cp, n)
1081 		FILE	*f;
1082 		char	*s;
1083 	register Uchar	*cp;
1084 	register int	n;
1085 {
1086 	js_fprintf(f, "%s", s);
1087 	while (--n >= 0)
1088 		js_fprintf(f, " %02X", *cp++);
1089 	js_fprintf(f, "\n");
1090 }
1091 
1092 /*
1093  * print some bytes in ascii to a file.
1094  */
1095 EXPORT void
scg_fprascii(f,s,cp,n)1096 scg_fprascii(f, s, cp, n)
1097 		FILE	*f;
1098 		char	*s;
1099 	register Uchar	*cp;
1100 	register int	n;
1101 {
1102 	register int	c;
1103 
1104 	js_fprintf(f, "%s", s);
1105 	while (--n >= 0) {
1106 		c = *cp++;
1107 		if (c >= ' ' && c < 0177)
1108 			js_fprintf(f, "%c", c);
1109 		else
1110 			js_fprintf(f, ".");
1111 	}
1112 	js_fprintf(f, "\n");
1113 }
1114 
1115 /*
1116  * XXX We need to check if we should write to stderr or better to scg->errfile
1117  *
1118  * print some bytes in hex to stderr.
1119  */
1120 EXPORT void
scg_prbytes(s,cp,n)1121 scg_prbytes(s, cp, n)
1122 		char	*s;
1123 	register Uchar	*cp;
1124 	register int	n;
1125 {
1126 	scg_fprbytes(stderr, s, cp, n);
1127 }
1128 
1129 /*
1130  * XXX We need to check if we should write to stderr or better to scg->errfile
1131  *
1132  * print some bytes in ascii to stderr.
1133  */
1134 EXPORT void
scg_prascii(s,cp,n)1135 scg_prascii(s, cp, n)
1136 		char	*s;
1137 	register Uchar	*cp;
1138 	register int	n;
1139 {
1140 	scg_fprascii(stderr, s, cp, n);
1141 }
1142 
1143 /*
1144  * print some bytes in hex into a buffer.
1145  */
1146 EXPORT int
scg_sprbytes(buf,maxcnt,s,cp,n)1147 scg_sprbytes(buf, maxcnt, s, cp, n)
1148 		char	*buf;
1149 		int	maxcnt;
1150 		char	*s;
1151 	register Uchar	*cp;
1152 	register int	n;
1153 {
1154 	register char	*p = buf;
1155 	register int	amt;
1156 
1157 	amt = js_snprintf(p, maxcnt, "%s", s);
1158 	if (amt < 0)
1159 		return (amt);
1160 	p += amt;
1161 	maxcnt -= amt;
1162 
1163 	while (--n >= 0) {
1164 		amt = js_snprintf(p, maxcnt, " %02X", *cp++);
1165 		if (amt < 0)
1166 			return (amt);
1167 		p += amt;
1168 		maxcnt -= amt;
1169 	}
1170 	amt = js_snprintf(p, maxcnt, "\n");
1171 	if (amt < 0)
1172 		return (amt);
1173 	p += amt;
1174 	return (p - buf);
1175 }
1176 
1177 /*
1178  * print some bytes in ascii into a buffer.
1179  */
1180 EXPORT int
scg_sprascii(buf,maxcnt,s,cp,n)1181 scg_sprascii(buf, maxcnt, s, cp, n)
1182 		char	*buf;
1183 		int	maxcnt;
1184 		char	*s;
1185 	register Uchar	*cp;
1186 	register int	n;
1187 {
1188 	register char	*p = buf;
1189 	register int	amt;
1190 	register int	c;
1191 
1192 	amt = js_snprintf(p, maxcnt, "%s", s);
1193 	if (amt < 0)
1194 		return (amt);
1195 	p += amt;
1196 	maxcnt -= amt;
1197 
1198 	while (--n >= 0) {
1199 		c = *cp++;
1200 		if (c >= ' ' && c < 0177)
1201 			amt = js_snprintf(p, maxcnt, "%c", c);
1202 		else
1203 			amt = js_snprintf(p, maxcnt, ".");
1204 		if (amt < 0)
1205 			return (amt);
1206 		p += amt;
1207 		maxcnt -= amt;
1208 	}
1209 	amt = js_snprintf(p, maxcnt, "\n");
1210 	if (amt < 0)
1211 		return (amt);
1212 	p += amt;
1213 	return (p - buf);
1214 }
1215 
1216 /*
1217  * print the SCSI sense data for last command in hex to a file.
1218  */
1219 EXPORT void
scg_fprsense(f,cp,n)1220 scg_fprsense(f, cp, n)
1221 	FILE	*f;
1222 	Uchar	*cp;
1223 	int	n;
1224 {
1225 	scg_fprbytes(f, "Sense Bytes:", cp, n);
1226 }
1227 
1228 /*
1229  * XXX We need to check if we should write to stderr or better to scg->errfile
1230  *
1231  * print the SCSI sense data for last command in hex to stderr.
1232  */
1233 EXPORT void
scg_prsense(cp,n)1234 scg_prsense(cp, n)
1235 	Uchar	*cp;
1236 	int	n;
1237 {
1238 	scg_fprsense(stderr, cp, n);
1239 }
1240 
1241 /*
1242  * print the SCSI sense data for last command in hex into a buffer.
1243  */
1244 EXPORT int
scg_sprsense(buf,maxcnt,cp,n)1245 scg_sprsense(buf, maxcnt, cp, n)
1246 	char	*buf;
1247 	int	maxcnt;
1248 	Uchar	*cp;
1249 	int	n;
1250 {
1251 	return (scg_sprbytes(buf, maxcnt, "Sense Bytes:", cp, n));
1252 }
1253 
1254 /*
1255  * Return the SCSI status byte for last command.
1256  */
1257 EXPORT int
scg_cmd_status(scgp)1258 scg_cmd_status(scgp)
1259 	SCSI	*scgp;
1260 {
1261 	struct scg_cmd	*cp = scgp->scmd;
1262 	int		cmdstatus = *(Uchar *)&cp->scb;
1263 
1264 	return (cmdstatus);
1265 }
1266 
1267 /*
1268  * Return the SCSI sense key for last command.
1269  */
1270 EXPORT int
scg_sense_key(scgp)1271 scg_sense_key(scgp)
1272 	SCSI	*scgp;
1273 {
1274 	register struct scg_cmd *cp = scgp->scmd;
1275 	int	key = -1;
1276 
1277 	if (!scg_cmd_err(scgp))
1278 		return (0);
1279 
1280 	if (cp->sense.code >= 0x70)
1281 		key = ((struct scsi_ext_sense *)&(cp->sense))->key;
1282 	return (key);
1283 }
1284 
1285 /*
1286  * Return the SCSI sense code for last command.
1287  */
1288 EXPORT int
scg_sense_code(scgp)1289 scg_sense_code(scgp)
1290 	SCSI	*scgp;
1291 {
1292 	register struct scg_cmd *cp = scgp->scmd;
1293 	int	code = -1;
1294 
1295 	if (!scg_cmd_err(scgp))
1296 		return (0);
1297 
1298 	if (cp->sense.code >= 0x70)
1299 		code = ((struct scsi_ext_sense *)&(cp->sense))->sense_code;
1300 	else
1301 		code = cp->sense.code;
1302 	return (code);
1303 }
1304 
1305 /*
1306  * Return the SCSI sense qualifier for last command.
1307  */
1308 EXPORT int
scg_sense_qual(scgp)1309 scg_sense_qual(scgp)
1310 	SCSI	*scgp;
1311 {
1312 	register struct scg_cmd *cp = scgp->scmd;
1313 
1314 	if (!scg_cmd_err(scgp))
1315 		return (0);
1316 
1317 	if (cp->sense.code >= 0x70)
1318 		return (((struct scsi_ext_sense *)&(cp->sense))->qual_code);
1319 	else
1320 		return (0);
1321 }
1322 
1323 /*
1324  * Print the device type from the SCSI inquiry buffer to file.
1325  */
1326 EXPORT void
scg_fprintdev(f,ip)1327 scg_fprintdev(f, ip)
1328 		FILE	*f;
1329 	struct	scsi_inquiry *ip;
1330 {
1331 	if (ip->removable)
1332 		js_fprintf(f, "Removable ");
1333 	if (ip->data_format >= 2) {
1334 		switch (ip->qualifier) {
1335 
1336 		case INQ_DEV_PRESENT:
1337 			break;
1338 		case INQ_DEV_NOTPR:
1339 			js_fprintf(f, "not present ");
1340 			break;
1341 		case INQ_DEV_RES:
1342 			js_fprintf(f, "reserved ");
1343 			break;
1344 		case INQ_DEV_NOTSUP:
1345 			if (ip->type == INQ_NODEV) {
1346 				js_fprintf(f, "unsupported\n"); return;
1347 			}
1348 			js_fprintf(f, "unsupported ");
1349 			break;
1350 		default:
1351 			js_fprintf(f, "vendor specific %d ",
1352 						(int)ip->qualifier);
1353 		}
1354 	}
1355 	switch (ip->type) {
1356 
1357 	case INQ_DASD:
1358 		js_fprintf(f, "Disk");		break;
1359 	case INQ_SEQD:
1360 		js_fprintf(f, "Tape");		break;
1361 	case INQ_PRTD:
1362 		js_fprintf(f, "Printer");	break;
1363 	case INQ_PROCD:
1364 		js_fprintf(f, "Processor");	break;
1365 	case INQ_WORM:
1366 		js_fprintf(f, "WORM");		break;
1367 	case INQ_ROMD:
1368 		js_fprintf(f, "CD-ROM");	break;
1369 	case INQ_SCAN:
1370 		js_fprintf(f, "Scanner");	break;
1371 	case INQ_OMEM:
1372 		js_fprintf(f, "Optical Storage"); break;
1373 	case INQ_JUKE:
1374 		js_fprintf(f, "Juke Box");	break;
1375 	case INQ_COMM:
1376 		js_fprintf(f, "Communication");	break;
1377 	case INQ_IT8_1:
1378 		js_fprintf(f, "IT8 1");		break;
1379 	case INQ_IT8_2:
1380 		js_fprintf(f, "IT8 2");		break;
1381 	case INQ_STARR:
1382 		js_fprintf(f, "Storage array");	break;
1383 	case INQ_ENCL:
1384 		js_fprintf(f, "Enclosure services"); break;
1385 	case INQ_SDAD:
1386 		js_fprintf(f, "Simple direct access"); break;
1387 	case INQ_OCRW:
1388 		js_fprintf(f, "Optical card r/w"); break;
1389 	case INQ_BRIDGE:
1390 		js_fprintf(f, "Bridging expander"); break;
1391 	case INQ_OSD:
1392 		js_fprintf(f, "Object based storage"); break;
1393 	case INQ_ADC:
1394 		js_fprintf(f, "Automation/Drive Interface"); break;
1395 	case INQ_WELLKNOWN:
1396 		js_fprintf(f, "Well known lun"); break;
1397 
1398 	case INQ_NODEV:
1399 		if (ip->data_format >= 2) {
1400 			js_fprintf(f, "unknown/no device");
1401 			break;
1402 		} else if (ip->qualifier == INQ_DEV_NOTSUP) {
1403 			js_fprintf(f, "unit not present");
1404 			break;
1405 		}
1406 	default:
1407 		js_fprintf(f, "unknown device type 0x%x",
1408 						(int)ip->type);
1409 	}
1410 	js_fprintf(f, "\n");
1411 }
1412 
1413 /*
1414  * Print the device type from the SCSI inquiry buffer to stdout.
1415  */
1416 EXPORT void
scg_printdev(ip)1417 scg_printdev(ip)
1418 	struct	scsi_inquiry *ip;
1419 {
1420 	scg_fprintdev(stdout, ip);
1421 }
1422 
1423 #include <schily/varargs.h>
1424 
1425 /*
1426  * print into the SCSI error buffer, adjust the next write pointer.
1427  */
1428 /* VARARGS2 */
1429 EXPORT int
1430 #ifdef	PROTOTYPES
scg_printf(SCSI * scgp,const char * form,...)1431 scg_printf(SCSI *scgp, const char *form, ...)
1432 #else
1433 scg_printf(scgp, form, va_alist)
1434 	SCSI	*scgp;
1435 	char	*form;
1436 	va_dcl
1437 #endif
1438 {
1439 	int	cnt;
1440 	va_list	args;
1441 
1442 #ifdef	PROTOTYPES
1443 	va_start(args, form);
1444 #else
1445 	va_start(args);
1446 #endif
1447 	cnt = js_snprintf(scgp->errptr, scg_errrsize(scgp), "%r", form, args);
1448 	va_end(args);
1449 
1450 	if (cnt < 0) {
1451 		scgp->errptr[0] = '\0';
1452 	} else {
1453 		scgp->errptr += cnt;
1454 	}
1455 	return (cnt);
1456 }
1457 
1458 /*
1459  * Flush the SCSI error buffer to SCSI errfile.
1460  * Clear error buffer after flushing.
1461  */
1462 EXPORT int
scg_errflush(scgp)1463 scg_errflush(scgp)
1464 	SCSI	*scgp;
1465 {
1466 	if (scgp->errfile == NULL)
1467 		return (0);
1468 
1469 	return (scg_errfflush(scgp, (FILE *)scgp->errfile));
1470 }
1471 
1472 /*
1473  * Flush the SCSI error buffer to a file.
1474  * Clear error buffer after flushing.
1475  */
1476 EXPORT int
scg_errfflush(scgp,f)1477 scg_errfflush(scgp, f)
1478 	SCSI	*scgp;
1479 	FILE	*f;
1480 {
1481 	int	cnt;
1482 
1483 	cnt = scgp->errptr - scgp->errbeg;
1484 	if (cnt > 0) {
1485 		filewrite(f, scgp->errbeg, cnt);
1486 		fflush(f);
1487 		scgp->errbeg = scgp->errptr;
1488 	}
1489 	return (cnt);
1490 }
1491