2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)scsitransp.c 1.91 04/06/17 Copyright 1988,1995,2000-2004 J. Schilling */
15 static char sccsid[] =
16 "@(#)scsitransp.c 1.91 04/06/17 Copyright 1988,1995,2000-2004 J. Schilling";
19 * SCSI user level command transport routines (generic part).
21 * Warning: you may change this source, but if you do that
22 * you need to change the _usal_version and _usal_auth* string below.
23 * You may not return "schily" for an SCG_AUTHOR request anymore.
24 * Choose your name instead of "schily" and make clear that the version
25 * string is related to a modified source.
27 * Copyright (c) 1988,1995,2000-2004 J. Schilling
30 * This program is free software; you can redistribute it and/or modify
31 * it under the terms of the GNU General Public License version 2
32 * as published by the Free Software Foundation.
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
39 * You should have received a copy of the GNU General Public License along with
40 * this program; see the file COPYING. If not, write to the Free Software
41 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
54 #include <usal/usalcmd.h>
55 #include <usal/scsireg.h>
56 #include <usal/scsitransp.h>
57 #include "usaltimes.h"
63 * Warning: you may change this source, but if you do that
64 * you need to change the _usal_version and _usal_auth* string below.
65 * You may not return "schily" for an SCG_AUTHOR request anymore.
66 * Choose your name instead of "schily" and make clear that the version
67 * string is related to a modified source.
69 static char _usal_version[] = CDRKIT_VERSION; /* The global libusal version */
70 static char _usal_auth_cdrkit[] = "Cdrkit"; /* The author for this module */
72 #define DEFTIMEOUT 20 /* Default timeout for SCSI command transport */
74 char *usal_version(SCSI *usalp, int what);
75 int usal__open(SCSI *usalp, char *device);
76 int usal__close(SCSI *usalp);
77 BOOL usal_havebus(SCSI *usalp, int);
78 int usal_initiator_id(SCSI *usalp);
79 int usal_isatapi(SCSI *usalp);
80 int usal_reset(SCSI *usalp, int what);
81 void *usal_getbuf(SCSI *usalp, long);
82 void usal_freebuf(SCSI *usalp);
83 long usal_bufsize(SCSI *usalp, long);
84 void usal_setnonstderrs(SCSI *usalp, const char **);
85 BOOL usal_yes(char *);
87 static void usal_sighandler(int);
89 int usal_cmd(SCSI *usalp);
90 void usal_vhead(SCSI *usalp);
91 int usal_svhead(SCSI *usalp, char *buf, int maxcnt);
92 int usal_vtail(SCSI *usalp);
93 int usal_svtail(SCSI *usalp, int *retp, char *buf, int maxcnt);
94 void usal_vsetup(SCSI *usalp);
95 int usal_getresid(SCSI *usalp);
96 int usal_getdmacnt(SCSI *usalp);
97 BOOL usal_cmd_err(SCSI *usalp);
98 void usal_printerr(SCSI *usalp);
99 void usal_fprinterr(SCSI *usalp, FILE *f);
100 int usal_sprinterr(SCSI *usalp, char *buf, int maxcnt);
101 int usal__sprinterr(SCSI *usalp, char *buf, int maxcnt);
102 void usal_printcdb(SCSI *usalp);
103 int usal_sprintcdb(SCSI *usalp, char *buf, int maxcnt);
104 void usal_printwdata(SCSI *usalp);
105 int usal_sprintwdata(SCSI *usalp, char *buf, int maxcnt);
106 void usal_printrdata(SCSI *usalp);
107 int usal_sprintrdata(SCSI *usalp, char *buf, int maxcnt);
108 void usal_printresult(SCSI *usalp);
109 int usal_sprintresult(SCSI *usalp, char *buf, int maxcnt);
110 void usal_printstatus(SCSI *usalp);
111 int usal_sprintstatus(SCSI *usalp, char *buf, int maxcnt);
112 void usal_fprbytes(FILE *, char *, unsigned char *, int);
113 void usal_fprascii(FILE *, char *, unsigned char *, int);
114 void usal_prbytes(char *, unsigned char *, int);
115 void usal_prascii(char *, unsigned char *, int);
116 int usal_sprbytes(char *buf, int maxcnt, char *, unsigned char *, int);
117 int usal_sprascii(char *buf, int maxcnt, char *, unsigned char *, int);
118 void usal_fprsense(FILE *f, unsigned char *, int);
119 int usal_sprsense(char *buf, int maxcnt, unsigned char *, int);
120 void usal_prsense(unsigned char *, int);
121 int usal_cmd_status(SCSI *usalp);
122 int usal_sense_key(SCSI *usalp);
123 int usal_sense_code(SCSI *usalp);
124 int usal_sense_qual(SCSI *usalp);
125 unsigned char *usal_sense_table(SCSI *usalp);
126 void usal_fprintdev(FILE *, struct scsi_inquiry *);
127 void usal_printdev(struct scsi_inquiry *);
128 int usal_printf(SCSI *usalp, const char *form, ...);
129 int usal_errflush(SCSI *usalp);
130 int usal_errfflush(SCSI *usalp, FILE *f);
133 * Return version information for the SCSI transport code.
134 * This has been introduced to make it easier to trace down problems
137 * If usalp is NULL, return general library version information.
138 * If usalp is != NULL, return version information for the low level transport.
141 usal_version(SCSI *usalp, int what)
143 if (usalp == (SCSI *)0) {
147 return (_usal_version);
149 * If you changed this source, you are not allowed to
150 * return "schily" for the SCG_AUTHOR request.
153 return (_usal_auth_cdrkit);
160 return (SCGO_VERSION(usalp, what));
164 * Call low level SCSI open routine from transport abstraction layer.
167 usal__open(SCSI *usalp, char *device)
171 extern usal_ops_t usal_std_ops;
173 usalp->ops = &usal_std_ops;
175 if (device && strncmp(device, "REMOTE", 6) == 0) {
181 ret = SCGO_OPEN(usalp, device);
186 * Now make usalp->fd valid if possible.
187 * Note that usal_scsibus(usalp)/usal_target(usalp)/usal_lun(usalp) may have
188 * changed in SCGO_OPEN().
190 usal_settarget(usalp, usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp));
195 * Call low level SCSI close routine from transport abstraction layer.
198 usal__close(SCSI *usalp)
200 return (SCGO_CLOSE(usalp));
204 * Retrieve max DMA count for this target.
207 usal_bufsize(SCSI *usalp, long amt)
211 maxdma = SCGO_MAXDMA(usalp, amt);
212 if (amt <= 0 || amt > maxdma)
215 usalp->maxdma = maxdma; /* Max possible */
216 usalp->maxbuf = amt; /* Current value */
222 * Allocate a buffer that may be used for DMA.
225 usal_getbuf(SCSI *usalp, long amt)
229 if (amt <= 0 || amt > usal_bufsize(usalp, amt))
232 buf = SCGO_GETBUF(usalp, amt);
241 usal_freebuf(SCSI *usalp)
244 usalp->bufptr = NULL;
248 * Check if 'busno' is a valid SCSI bus number.
251 usal_havebus(SCSI *usalp, int busno)
253 return (SCGO_HAVEBUS(usalp, busno));
257 * Return SCSI initiator ID for current SCSI bus if available.
260 usal_initiator_id(SCSI *usalp)
262 return (SCGO_INITIATOR_ID(usalp));
266 * Return a hint whether current SCSI target refers to a ATAPI device.
269 usal_isatapi(SCSI *usalp)
271 return (SCGO_ISATAPI(usalp));
275 * Reset SCSI bus or target.
278 usal_reset(SCSI *usalp, int what)
280 return (SCGO_RESET(usalp, what));
284 * Set up nonstd error vector for curren target.
285 * To clear additional error table, call usal_setnonstderrs(usalp, NULL);
286 * Note: do not use this when scanning the SCSI bus.
289 usal_setnonstderrs(SCSI *usalp, const char **vec)
291 usalp->nonstderrs = vec;
295 * Simple Yes/No answer checker.
304 if (rols_getline(okbuf, sizeof (okbuf)) == EOF)
306 if (streql(okbuf, "y") || streql(okbuf, "yes") ||
307 streql(okbuf, "Y") || streql(okbuf, "YES"))
315 usal_sighandler(int sig)
319 printf("Running command: %s\n", scsi_command);
320 printf("Resetting SCSI - Bus.\n");
321 if (usal_reset(usalp) < 0)
322 errmsg("Cannot reset SCSI - Bus.\n");
324 if (usal_yes("EXIT ? "))
330 * Send a SCSI command.
331 * Do error checking and reporting depending on the values of
332 * usalp->verbose, usalp->debug and usalp->silent.
335 usal_cmd(SCSI *usalp)
338 register struct usal_cmd *scmd = usalp->scmd;
341 * Reset old error messages in usalp->errstr
343 usalp->errptr = usalp->errbeg = usalp->errstr;
345 scmd->kdebug = usalp->kdebug;
346 if (scmd->timeout == 0 || scmd->timeout < usalp->deftimeout)
347 scmd->timeout = usalp->deftimeout;
348 if (usalp->disre_disable)
349 scmd->flags &= ~SCG_DISRE_ENA;
351 scmd->flags |= SCG_NOPARITY;
353 scmd->u_sense.cmd_sense[0] = 0; /* Paranioa */
354 if (scmd->sense_len > SCG_MAX_SENSE)
355 scmd->sense_len = SCG_MAX_SENSE;
356 else if (scmd->sense_len < 0)
359 if (usalp->verbose) {
361 usal_errflush(usalp);
364 if (usalp->running) {
365 if (usalp->curcmdname) {
366 fprintf(stderr, "Currently running '%s' command.\n",
369 raisecond("SCSI ALREADY RUNNING !!", 0L);
371 usalp->cb_fun = NULL;
372 gettimeofday(usalp->cmdstart, (struct timezone *)0);
373 usalp->curcmdname = usalp->cmdname;
374 usalp->running = TRUE;
375 ret = SCGO_SEND(usalp);
376 usalp->running = FALSE;
380 * Old /dev/usal versions will not allow to access targets > 7.
381 * Include a workaround to make this non fatal.
383 if (usal_target(usalp) < 8 || geterrno() != EINVAL)
384 comerr("Cannot send SCSI cmd via ioctl\n");
385 if (scmd->ux_errno == 0)
386 scmd->ux_errno = geterrno();
387 if (scmd->error == SCG_NO_ERROR)
388 scmd->error = SCG_FATAL;
389 if (usalp->debug > 0) {
390 errmsg("ret < 0 errno: %d ux_errno: %d error: %d\n",
391 geterrno(), scmd->ux_errno, scmd->error);
395 ret = usal_vtail(usalp);
396 usal_errflush(usalp);
397 if (usalp->cb_fun != NULL)
398 (*usalp->cb_fun)(usalp->cb_arg);
403 * Fill the head of verbose printing into the SCSI error buffer.
404 * Action depends on SCSI verbose status.
407 usal_vhead(SCSI *usalp)
409 usalp->errptr += usal_svhead(usalp, usalp->errptr, usal_errrsize(usalp));
413 * Fill the head of verbose printing into a buffer.
414 * Action depends on SCSI verbose status.
417 usal_svhead(SCSI *usalp, char *buf, int maxcnt)
419 register char *p = buf;
422 if (usalp->verbose <= 0)
425 amt = snprintf(p, maxcnt,
426 "\nExecuting '%s' command on Bus %d Target %d, Lun %d timeout %ds\n",
427 /* XXX Really this ??? */
428 /* usalp->cmdname, usal_scsibus(usalp), usal_target(usalp), usalp->scmd->cdb.g0_cdb.lun,*/
429 usalp->cmdname, usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp),
430 usalp->scmd->timeout);
436 amt = usal_sprintcdb(usalp, p, maxcnt);
442 if (usalp->verbose > 1) {
443 amt = usal_sprintwdata(usalp, p, maxcnt);
453 * Fill the tail of verbose printing into the SCSI error buffer.
454 * Action depends on SCSI verbose status.
457 usal_vtail(SCSI *usalp)
461 usalp->errptr += usal_svtail(usalp, &ret, usalp->errptr, usal_errrsize(usalp));
466 * Fill the tail of verbose printing into a buffer.
467 * Action depends on SCSI verbose status.
470 usal_svtail(SCSI *usalp, int *retp, char *buf, int maxcnt)
472 register char *p = buf;
476 ret = usal_cmd_err(usalp) ? -1 : 0;
480 if (usalp->silent <= 0 || usalp->verbose) {
481 amt = usal__sprinterr(usalp, p, maxcnt);
488 if ((usalp->silent <= 0 || usalp->verbose) && usalp->scmd->resid) {
489 if (usalp->scmd->resid < 0) {
491 * An operating system that does DMA the right way
492 * will not allow DMA overruns - it will stop DMA
493 * before bad things happen.
494 * A DMA residual count < 0 (-1) is a hint for a DMA
495 * overrun but does not affect the transfer count.
497 amt = snprintf(p, maxcnt, "DMA overrun, ");
503 amt = snprintf(p, maxcnt, "resid: %d\n", usalp->scmd->resid);
509 if (usalp->verbose > 0 || (ret < 0 && usalp->silent <= 0)) {
510 amt = usal_sprintresult(usalp, p, maxcnt);
520 * Set up SCSI error buffer with verbose print data.
521 * Action depends on SCSI verbose status.
524 usal_vsetup(SCSI *usalp)
531 * Return the residual DMA count for last command.
532 * If this count is < 0, then a DMA overrun occured.
535 usal_getresid(SCSI *usalp)
537 return (usalp->scmd->resid);
541 * Return the actual DMA count for last command.
544 usal_getdmacnt(SCSI *usalp)
546 register struct usal_cmd *scmd = usalp->scmd;
551 return (scmd->size - scmd->resid);
555 * Test if last SCSI command got an error.
558 usal_cmd_err(SCSI *usalp)
560 register struct usal_cmd *cp = usalp->scmd;
562 if (cp->error != SCG_NO_ERROR ||
564 *(Uchar *)&cp->scb != 0 ||
565 cp->u_sense.cmd_sense[0] != 0) /* Paranioa */
571 * Used to print error messges if the command itself has been run silently.
573 * print the following SCSI codes:
575 * - command transport status
579 * - Decoded Sense data
586 usal_printerr(SCSI *usalp)
588 usal_fprinterr(usalp, (FILE *)usalp->errfile);
592 * print the following SCSI codes:
594 * - command transport status
598 * - Decoded Sense data
605 usal_fprinterr(SCSI *usalp, FILE *f)
607 char errbuf[SCSI_ERRSTR_SIZE];
610 amt = usal_sprinterr(usalp, errbuf, sizeof (errbuf));
612 filewrite(f, errbuf, amt);
618 * print the following SCSI codes:
620 * - command transport status
624 * - Decoded Sense data
631 usal_sprinterr(SCSI *usalp, char *buf, int maxcnt)
634 int osilent = usalp->silent;
635 int overbose = usalp->verbose;
639 amt = usal_svtail(usalp, NULL, buf, maxcnt);
640 usalp->silent = osilent;
641 usalp->verbose = overbose;
646 * print the following SCSI codes:
648 * - command transport status
652 * - Decoded Sense data
657 usal__sprinterr(SCSI *usalp, char *buf, int maxcnt)
659 register struct usal_cmd *cp = usalp->scmd;
661 char *cmdname = "SCSI command name not set by caller";
663 register char *p = buf;
668 case SCG_NO_ERROR : err = "no error"; break;
669 case SCG_RETRYABLE: err = "retryable error"; break;
670 case SCG_FATAL : err = "fatal error"; break;
672 * We need to cast timeval->* to long because
673 * of the broken sys/time.h in Linux.
675 case SCG_TIMEOUT : snprintf(errbuf, sizeof (errbuf),
676 "cmd timeout after %ld.%03ld (%d) s",
677 (long)usalp->cmdstop->tv_sec,
678 (long)usalp->cmdstop->tv_usec/1000,
682 default: snprintf(errbuf, sizeof (errbuf),
683 "error: %d", cp->error);
687 if (usalp->cmdname != NULL && usalp->cmdname[0] != '\0')
688 cmdname = usalp->cmdname;
689 /*amt = serrmsgno(cp->ux_errno, p, maxcnt, "%s: scsi sendcmd: %s\n", cmdname, err);
693 amt=snprintf(p, maxcnt, "Errno: %d (%s), %s scsi sendcmd: %s\n", cp->ux_errno, strerror(cp->ux_errno), cmdname, err);
694 if(amt>=maxcnt || amt<0)
699 amt = usal_sprintcdb(usalp, p, maxcnt);
705 if (cp->error <= SCG_RETRYABLE) {
706 amt = usal_sprintstatus(usalp, p, maxcnt);
714 amt = usal_sprsense(p, maxcnt, (Uchar *)&cp->sense, cp->sense_count);
719 amt = usal__errmsg(usalp, p, maxcnt, &cp->sense, &cp->scb, -1);
729 * XXX Do we need this function?
731 * print the SCSI Command descriptor block to XXX stderr.
734 usal_printcdb(SCSI *usalp)
736 usal_prbytes("CDB: ", usalp->scmd->cdb.cmd_cdb, usalp->scmd->cdb_len);
740 * print the SCSI Command descriptor block into a buffer.
743 usal_sprintcdb(SCSI *usalp, char *buf, int maxcnt)
747 cnt = usal_sprbytes(buf, maxcnt, "CDB: ", usalp->scmd->cdb.cmd_cdb, usalp->scmd->cdb_len);
754 * XXX Do we need this function?
755 * XXX usal_printrdata() is used.
756 * XXX We need to check if we should write to stderr or better to usal->errfile
758 * print the SCSI send data to stderr.
761 usal_printwdata(SCSI *usalp)
763 register struct usal_cmd *scmd = usalp->scmd;
765 if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) == 0) {
766 fprintf(stderr, "Sending %d (0x%X) bytes of data.\n",
767 scmd->size, scmd->size);
768 usal_prbytes("Write Data: ",
770 scmd->size > 100 ? 100 : scmd->size);
775 * print the SCSI send data into a buffer.
778 usal_sprintwdata(SCSI *usalp, char *buf, int maxcnt)
780 register struct usal_cmd *scmd = usalp->scmd;
781 register char *p = buf;
784 if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) == 0) {
785 amt = snprintf(p, maxcnt,
786 "Sending %d (0x%X) bytes of data.\n",
787 scmd->size, scmd->size);
792 amt = usal_sprbytes(p, maxcnt, "Write Data: ",
794 scmd->size > 100 ? 100 : scmd->size);
803 * XXX We need to check if we should write to stderr or better to usal->errfile
805 * print the SCSI received data to stderr.
808 usal_printrdata(SCSI *usalp)
810 register struct usal_cmd *scmd = usalp->scmd;
811 register int trcnt = usal_getdmacnt(usalp);
813 if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) != 0) {
814 fprintf(stderr, "Got %d (0x%X), expecting %d (0x%X) bytes of data.\n",
816 scmd->size, scmd->size);
817 usal_prbytes("Received Data: ",
819 trcnt > 100 ? 100 : trcnt);
824 * print the SCSI received data into a buffer.
827 usal_sprintrdata(SCSI *usalp, char *buf, int maxcnt)
829 register struct usal_cmd *scmd = usalp->scmd;
830 register char *p = buf;
832 register int trcnt = usal_getdmacnt(usalp);
834 if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) != 0) {
835 amt = snprintf(p, maxcnt,
836 "Got %d (0x%X), expecting %d (0x%X) bytes of data.\n",
838 scmd->size, scmd->size);
843 amt = usal_sprbytes(p, maxcnt,
846 trcnt > 100 ? 100 : trcnt);
855 * XXX We need to check if we should write to stderr or better to usal->errfile
857 * print the SCSI timings and (depending on verbose) received data to stderr.
860 usal_printresult(SCSI *usalp)
862 fprintf(stderr, "cmd finished after %ld.%03lds timeout %ds\n",
863 (long)usalp->cmdstop->tv_sec,
864 (long)usalp->cmdstop->tv_usec/1000,
865 usalp->scmd->timeout);
866 if (usalp->verbose > 1)
867 usal_printrdata(usalp);
872 * print the SCSI timings and (depending on verbose) received data into a buffer.
875 usal_sprintresult(SCSI *usalp, char *buf, int maxcnt)
877 register char *p = buf;
880 amt = snprintf(p, maxcnt,
881 "cmd finished after %ld.%03lds timeout %ds\n",
882 (long)usalp->cmdstop->tv_sec,
883 (long)usalp->cmdstop->tv_usec/1000,
884 usalp->scmd->timeout);
889 if (usalp->verbose > 1) {
890 amt = usal_sprintrdata(usalp, p, maxcnt);
899 * XXX Do we need this function?
901 * print the SCSI status byte in human readable form to the SCSI error file.
904 usal_printstatus(SCSI *usalp)
906 char errbuf[SCSI_ERRSTR_SIZE];
909 amt = usal_sprintstatus(usalp, errbuf, sizeof (errbuf));
911 filewrite((FILE *)usalp->errfile, errbuf, amt);
912 fflush((FILE *)usalp->errfile);
917 * print the SCSI status byte in human readable form into a buffer.
920 usal_sprintstatus(SCSI *usalp, char *buf, int maxcnt)
922 register struct usal_cmd *cp = usalp->scmd;
925 register char *p = buf;
928 amt = snprintf(p, maxcnt, "status: 0x%x ", *(Uchar *)&cp->scb);
933 #ifdef SCSI_EXTENDED_STATUS
934 if (cp->scb.ext_st1) {
935 amt = snprintf(p, maxcnt, "0x%x ", ((Uchar *)&cp->scb)[1]);
941 if (cp->scb.ext_st2) {
942 amt = snprintf(p, maxcnt, "0x%x ", ((Uchar *)&cp->scb)[2]);
949 switch (*(Uchar *)&cp->scb & 036) {
951 case 0 : err = "GOOD STATUS"; break;
952 case 02 : err = "CHECK CONDITION"; break;
953 case 04 : err = "CONDITION MET/GOOD"; break;
954 case 010: err = "BUSY"; break;
955 case 020: err = "INTERMEDIATE GOOD STATUS"; break;
956 case 024: err = "INTERMEDIATE CONDITION MET/GOOD"; break;
957 case 030: err = "RESERVATION CONFLICT"; break;
958 default : err = "Reserved"; break;
960 #ifdef SCSI_EXTENDED_STATUS
961 if (cp->scb.ext_st1 && cp->scb.ha_er)
962 err2 = " host adapter detected error";
964 amt = snprintf(p, maxcnt, "(%s%s)\n", err, err2);
972 * print some bytes in hex to a file.
975 usal_fprbytes(FILE *f, char *s, register Uchar *cp, register int n)
979 fprintf(f, " %02X", *cp++);
984 * print some bytes in ascii to a file.
987 usal_fprascii(FILE *f, char *s, register Uchar *cp, register int n)
994 if (c >= ' ' && c < 0177)
1003 * XXX We need to check if we should write to stderr or better to usal->errfile
1005 * print some bytes in hex to stderr.
1008 usal_prbytes(char *s, register Uchar *cp, register int n)
1010 usal_fprbytes(stderr, s, cp, n);
1014 * XXX We need to check if we should write to stderr or better to usal->errfile
1016 * print some bytes in ascii to stderr.
1019 usal_prascii(char *s, register Uchar *cp, register int n)
1021 usal_fprascii(stderr, s, cp, n);
1025 * print some bytes in hex into a buffer.
1028 usal_sprbytes(char *buf, int maxcnt, char *s, register Uchar *cp, register int n)
1030 register char *p = buf;
1033 amt = snprintf(p, maxcnt, "%s", s);
1040 amt = snprintf(p, maxcnt, " %02X", *cp++);
1046 amt = snprintf(p, maxcnt, "\n");
1054 * print some bytes in ascii into a buffer.
1057 usal_sprascii(char *buf, int maxcnt, char *s, register Uchar *cp, register int n)
1059 register char *p = buf;
1063 amt = snprintf(p, maxcnt, "%s", s);
1071 if (c >= ' ' && c < 0177)
1072 amt = snprintf(p, maxcnt, "%c", c);
1074 amt = snprintf(p, maxcnt, ".");
1080 amt = snprintf(p, maxcnt, "\n");
1088 * print the SCSI sense data for last command in hex to a file.
1091 usal_fprsense(FILE *f, Uchar *cp, int n)
1093 usal_fprbytes(f, "Sense Bytes:", cp, n);
1097 * XXX We need to check if we should write to stderr or better to usal->errfile
1099 * print the SCSI sense data for last command in hex to stderr.
1102 usal_prsense(Uchar *cp, int n)
1104 usal_fprsense(stderr, cp, n);
1108 * print the SCSI sense data for last command in hex into a buffer.
1111 usal_sprsense(char *buf, int maxcnt, Uchar *cp, int n)
1113 return (usal_sprbytes(buf, maxcnt, "Sense Bytes:", cp, n));
1117 * Return the SCSI status byte for last command.
1120 usal_cmd_status(SCSI *usalp)
1122 struct usal_cmd *cp = usalp->scmd;
1123 int cmdstatus = *(Uchar *)&cp->scb;
1129 * Return the SCSI sense key for last command.
1132 usal_sense_key(SCSI *usalp)
1134 register struct usal_cmd *cp = usalp->scmd;
1137 if (!usal_cmd_err(usalp))
1140 if (cp->sense.code >= 0x70)
1141 key = ((struct scsi_ext_sense *)&(cp->sense))->key;
1146 * Return all the SCSI sense table last command.
1149 usal_sense_table(SCSI *usalp)
1151 register struct usal_cmd *cp = usalp->scmd;
1153 if(!usal_cmd_err(usalp))
1156 /* if (cp->sense.code >= 0x70) */
1157 return (unsigned char *) &(cp->sense);
1162 * Return the SCSI sense code for last command.
1165 usal_sense_code(SCSI *usalp)
1167 register struct usal_cmd *cp = usalp->scmd;
1170 if (!usal_cmd_err(usalp))
1173 if (cp->sense.code >= 0x70)
1174 code = ((struct scsi_ext_sense *)&(cp->sense))->sense_code;
1176 code = cp->sense.code;
1181 * Return the SCSI sense qualifier for last command.
1184 usal_sense_qual(SCSI *usalp)
1186 register struct usal_cmd *cp = usalp->scmd;
1188 if (!usal_cmd_err(usalp))
1191 if (cp->sense.code >= 0x70)
1192 return (((struct scsi_ext_sense *)&(cp->sense))->qual_code);
1198 * Print the device type from the SCSI inquiry buffer to file.
1201 usal_fprintdev(FILE *f, struct scsi_inquiry *ip)
1204 fprintf(f, "Removable ");
1205 if (ip->data_format >= 2) {
1206 switch (ip->qualifier) {
1208 case INQ_DEV_PRESENT:
1211 fprintf(f, "not present ");
1214 fprintf(f, "reserved ");
1216 case INQ_DEV_NOTSUP:
1217 if (ip->type == INQ_NODEV) {
1218 fprintf(f, "unsupported\n"); return;
1220 fprintf(f, "unsupported ");
1223 fprintf(f, "vendor specific %d ",
1224 (int)ip->qualifier);
1230 fprintf(f, "Disk"); break;
1232 fprintf(f, "Tape"); break;
1234 fprintf(f, "Printer"); break;
1236 fprintf(f, "Processor"); break;
1238 fprintf(f, "WORM"); break;
1240 fprintf(f, "CD-ROM"); break;
1242 fprintf(f, "Scanner"); break;
1244 fprintf(f, "Optical Storage"); break;
1246 fprintf(f, "Juke Box"); break;
1248 fprintf(f, "Communication"); break;
1250 fprintf(f, "IT8 1"); break;
1252 fprintf(f, "IT8 2"); break;
1254 fprintf(f, "Storage array"); break;
1256 fprintf(f, "Enclosure services"); break;
1258 fprintf(f, "Simple direct access"); break;
1260 fprintf(f, "Optical card r/w"); break;
1262 fprintf(f, "Bridging expander"); break;
1264 fprintf(f, "Object based storage"); break;
1266 fprintf(f, "Automation/Drive Interface"); break;
1268 fprintf(f, "Well known lun"); break;
1271 if (ip->data_format >= 2) {
1272 fprintf(f, "unknown/no device");
1274 } else if (ip->qualifier == INQ_DEV_NOTSUP) {
1275 fprintf(f, "unit not present");
1279 fprintf(f, "unknown device type 0x%x",
1286 * Print the device type from the SCSI inquiry buffer to stdout.
1289 usal_printdev(struct scsi_inquiry *ip)
1291 usal_fprintdev(stdout, ip);
1295 * print into the SCSI error buffer, adjust the next write pointer.
1299 usal_printf(SCSI *usalp, const char *form, ...)
1304 va_start(args, form);
1305 cnt = vsnprintf(usalp->errptr, usal_errrsize(usalp), form, args);
1309 usalp->errptr[0] = '\0';
1311 usalp->errptr += cnt;
1317 * Flush the SCSI error buffer to SCSI errfile.
1318 * Clear error buffer after flushing.
1321 usal_errflush(SCSI *usalp)
1323 if (usalp->errfile == NULL)
1326 return (usal_errfflush(usalp, (FILE *)usalp->errfile));
1330 * Flush the SCSI error buffer to a file.
1331 * Clear error buffer after flushing.
1334 usal_errfflush(SCSI *usalp, FILE *f)
1338 cnt = usalp->errptr - usalp->errbeg;
1340 filewrite(f, usalp->errbeg, cnt);
1342 usalp->errbeg = usalp->errptr;