Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / libusal / scsitransp.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
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).
6  *
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.
10  *
11  */
12
13 /* @(#)scsitransp.c     1.91 04/06/17 Copyright 1988,1995,2000-2004 J. Schilling */
14 /*#ifndef lint*/
15 static  char sccsid[] =
16         "@(#)scsitransp.c       1.91 04/06/17 Copyright 1988,1995,2000-2004 J. Schilling";
17 /*#endif*/
18 /*
19  *      SCSI user level command transport routines (generic part).
20  *
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.
26  *
27  *      Copyright (c) 1988,1995,2000-2004 J. Schilling
28  */
29 /*
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.
33  *
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.
38  *
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.
42  */
43
44 #include <mconfig.h>
45 #include <stdio.h>
46 #include <standard.h>
47 #include <stdxlib.h>
48 #include <unixstd.h>
49 #include <errno.h>
50 #include <timedefs.h>
51 #include <strdefs.h>
52 #include <schily.h>
53
54 #include <usal/usalcmd.h>
55 #include <usal/scsireg.h>
56 #include <usal/scsitransp.h>
57 #include "usaltimes.h"
58
59 #include <stdarg.h>
60
61
62 /*
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.
68  */
69 static  char    _usal_version[]         = CDRKIT_VERSION;       /* The global libusal version   */
70 static  char    _usal_auth_cdrkit[]     = "Cdrkit";     /* The author for this module   */
71
72 #define DEFTIMEOUT      20      /* Default timeout for SCSI command transport */
73
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 *);
86 #ifdef  nonono
87 static  void    usal_sighandler(int);
88 #endif
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);
131
132 /*
133  * Return version information for the SCSI transport code.
134  * This has been introduced to make it easier to trace down problems
135  * in applications.
136  *
137  * If usalp is NULL, return general library version information.
138  * If usalp is != NULL, return version information for the low level transport.
139  */
140 char *
141 usal_version(SCSI *usalp, int what)
142 {
143         if (usalp == (SCSI *)0) {
144                 switch (what) {
145
146                 case SCG_VERSION:
147                         return (_usal_version);
148                 /*
149                  * If you changed this source, you are not allowed to
150                  * return "schily" for the SCG_AUTHOR request.
151                  */
152                 case SCG_AUTHOR:
153                         return (_usal_auth_cdrkit);
154                 case SCG_SCCS_ID:
155                         return (sccsid);
156                 default:
157                         return ((char *)0);
158                 }
159         }
160         return (SCGO_VERSION(usalp, what));
161 }
162
163 /*
164  * Call low level SCSI open routine from transport abstraction layer.
165  */
166 int
167 usal__open(SCSI *usalp, char *device)
168 {
169         int     ret;
170         usal_ops_t *ops;
171 extern  usal_ops_t usal_std_ops;
172
173         usalp->ops = &usal_std_ops;
174
175         if (device && strncmp(device, "REMOTE", 6) == 0) {
176                 ops = usal_remote();
177                 if (ops != NULL)
178                         usalp->ops = ops;
179         }
180
181         ret = SCGO_OPEN(usalp, device);
182         if (ret < 0)
183                 return (ret);
184
185         /*
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().
189          */
190         usal_settarget(usalp, usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp));
191         return (ret);
192 }
193
194 /*
195  * Call low level SCSI close routine from transport abstraction layer.
196  */
197 int
198 usal__close(SCSI *usalp)
199 {
200         return (SCGO_CLOSE(usalp));
201 }
202
203 /*
204  * Retrieve max DMA count for this target.
205  */
206 long
207 usal_bufsize(SCSI *usalp, long amt)
208 {
209         long    maxdma;
210
211         maxdma = SCGO_MAXDMA(usalp, amt);
212         if (amt <= 0 || amt > maxdma)
213                 amt = maxdma;
214
215         usalp->maxdma = maxdma; /* Max possible  */
216         usalp->maxbuf = amt;    /* Current value */
217
218         return (amt);
219 }
220
221 /*
222  * Allocate a buffer that may be used for DMA.
223  */
224 void *
225 usal_getbuf(SCSI *usalp, long amt)
226 {
227         void    *buf;
228
229         if (amt <= 0 || amt > usal_bufsize(usalp, amt))
230                 return ((void *)0);
231
232         buf = SCGO_GETBUF(usalp, amt);
233         usalp->bufptr = buf;
234         return (buf);
235 }
236
237 /*
238  * Free DMA buffer.
239  */
240 void
241 usal_freebuf(SCSI *usalp)
242 {
243         SCGO_FREEBUF(usalp);
244         usalp->bufptr = NULL;
245 }
246
247 /*
248  * Check if 'busno' is a valid SCSI bus number.
249  */
250 BOOL
251 usal_havebus(SCSI *usalp, int busno)
252 {
253         return (SCGO_HAVEBUS(usalp, busno));
254 }
255
256 /*
257  * Return SCSI initiator ID for current SCSI bus if available.
258  */
259 int
260 usal_initiator_id(SCSI *usalp)
261 {
262         return (SCGO_INITIATOR_ID(usalp));
263 }
264
265 /*
266  * Return a hint whether current SCSI target refers to a ATAPI device.
267  */
268 int
269 usal_isatapi(SCSI *usalp)
270 {
271         return (SCGO_ISATAPI(usalp));
272 }
273
274 /*
275  * Reset SCSI bus or target.
276  */
277 int
278 usal_reset(SCSI *usalp, int what)
279 {
280         return (SCGO_RESET(usalp, what));
281 }
282
283 /*
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.
287  */
288 void
289 usal_setnonstderrs(SCSI *usalp, const char **vec)
290 {
291         usalp->nonstderrs = vec;
292 }
293
294 /*
295  * Simple Yes/No answer checker.
296  */
297 BOOL
298 usal_yes(char *msg)
299 {
300         char okbuf[10];
301
302         printf("%s", msg);
303         flush();
304         if (rols_getline(okbuf, sizeof (okbuf)) == EOF)
305                 exit(EX_BAD);
306         if (streql(okbuf, "y") || streql(okbuf, "yes") ||
307             streql(okbuf, "Y") || streql(okbuf, "YES"))
308                 return (TRUE);
309         else
310                 return (FALSE);
311 }
312
313 #ifdef  nonono
314 static void
315 usal_sighandler(int sig)
316 {
317         printf("\n");
318         if (scsi_running) {
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");
323         }
324         if (usal_yes("EXIT ? "))
325                 exit(sig);
326 }
327 #endif
328
329 /*
330  * Send a SCSI command.
331  * Do error checking and reporting depending on the values of
332  * usalp->verbose, usalp->debug and usalp->silent.
333  */
334 int
335 usal_cmd(SCSI *usalp)
336 {
337                 int             ret;
338         register struct usal_cmd        *scmd = usalp->scmd;
339
340         /*
341          * Reset old error messages in usalp->errstr
342          */
343         usalp->errptr = usalp->errbeg = usalp->errstr;
344
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;
350         if (usalp->noparity)
351                 scmd->flags |= SCG_NOPARITY;
352
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)
357                 scmd->sense_len = 0;
358
359         if (usalp->verbose) {
360                 usal_vhead(usalp);
361                 usal_errflush(usalp);
362         }
363
364         if (usalp->running) {
365                 if (usalp->curcmdname) {
366                         fprintf(stderr, "Currently running '%s' command.\n",
367                                                         usalp->curcmdname);
368                 }
369                 raisecond("SCSI ALREADY RUNNING !!", 0L);
370         }
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;
377         __usal_times(usalp);
378         if (ret < 0) {
379                 /*
380                  * Old /dev/usal versions will not allow to access targets > 7.
381                  * Include a workaround to make this non fatal.
382                  */
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);
392                 }
393         }
394
395         ret = usal_vtail(usalp);
396         usal_errflush(usalp);
397         if (usalp->cb_fun != NULL)
398                 (*usalp->cb_fun)(usalp->cb_arg);
399         return (ret);
400 }
401
402 /*
403  * Fill the head of verbose printing into the SCSI error buffer.
404  * Action depends on SCSI verbose status.
405  */
406 void
407 usal_vhead(SCSI *usalp)
408 {
409         usalp->errptr += usal_svhead(usalp, usalp->errptr, usal_errrsize(usalp));
410 }
411
412 /*
413  * Fill the head of verbose printing into a buffer.
414  * Action depends on SCSI verbose status.
415  */
416 int
417 usal_svhead(SCSI *usalp, char *buf, int maxcnt)
418 {
419         register char   *p = buf;
420         register int    amt;
421
422         if (usalp->verbose <= 0)
423                 return (0);
424
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);
431         if (amt < 0)
432                 return (amt);
433         p += amt;
434         maxcnt -= amt;
435
436         amt = usal_sprintcdb(usalp, p, maxcnt);
437         if (amt < 0)
438                 return (amt);
439         p += amt;
440         maxcnt -= amt;
441
442         if (usalp->verbose > 1) {
443                 amt = usal_sprintwdata(usalp, p, maxcnt);
444                 if (amt < 0)
445                         return (amt);
446                 p += amt;
447                 maxcnt -= amt;
448         }
449         return (p - buf);
450 }
451
452 /*
453  * Fill the tail of verbose printing into the SCSI error buffer.
454  * Action depends on SCSI verbose status.
455  */
456 int
457 usal_vtail(SCSI *usalp)
458 {
459         int     ret;
460
461         usalp->errptr += usal_svtail(usalp, &ret, usalp->errptr, usal_errrsize(usalp));
462         return (ret);
463 }
464
465 /*
466  * Fill the tail of verbose printing into a buffer.
467  * Action depends on SCSI verbose status.
468  */
469 int
470 usal_svtail(SCSI *usalp, int *retp, char *buf, int maxcnt)
471 {
472         register char   *p = buf;
473         register int    amt;
474         int     ret;
475
476         ret = usal_cmd_err(usalp) ? -1 : 0;
477         if (retp)
478                 *retp = ret;
479         if (ret) {
480                 if (usalp->silent <= 0 || usalp->verbose) {
481                         amt = usal__sprinterr(usalp, p, maxcnt);
482                         if (amt < 0)
483                                 return (amt);
484                         p += amt;
485                         maxcnt -= amt;
486                 }
487         }
488         if ((usalp->silent <= 0 || usalp->verbose) && usalp->scmd->resid) {
489                 if (usalp->scmd->resid < 0) {
490                         /*
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.
496                          */
497                         amt = snprintf(p, maxcnt, "DMA overrun, ");
498                         if (amt < 0)
499                                 return (amt);
500                         p += amt;
501                         maxcnt -= amt;
502                 }
503                 amt = snprintf(p, maxcnt, "resid: %d\n", usalp->scmd->resid);
504                 if (amt < 0)
505                         return (amt);
506                 p += amt;
507                 maxcnt -= amt;
508         }
509         if (usalp->verbose > 0 || (ret < 0 && usalp->silent <= 0)) {
510                 amt = usal_sprintresult(usalp, p, maxcnt);
511                 if (amt < 0)
512                         return (amt);
513                 p += amt;
514                 maxcnt -= amt;
515         }
516         return (p - buf);
517 }
518
519 /*
520  * Set up SCSI error buffer with verbose print data.
521  * Action depends on SCSI verbose status.
522  */
523 void
524 usal_vsetup(SCSI *usalp)
525 {
526         usal_vhead(usalp);
527         usal_vtail(usalp);
528 }
529
530 /*
531  * Return the residual DMA count for last command.
532  * If this count is < 0, then a DMA overrun occured.
533  */
534 int
535 usal_getresid(SCSI *usalp)
536 {
537         return (usalp->scmd->resid);
538 }
539
540 /*
541  * Return the actual DMA count for last command.
542  */
543 int
544 usal_getdmacnt(SCSI *usalp)
545 {
546         register struct usal_cmd *scmd = usalp->scmd;
547
548         if (scmd->resid < 0)
549                 return (scmd->size);
550
551         return (scmd->size - scmd->resid);
552 }
553
554 /*
555  * Test if last SCSI command got an error.
556  */
557 BOOL
558 usal_cmd_err(SCSI *usalp)
559 {
560         register struct usal_cmd *cp = usalp->scmd;
561
562         if (cp->error != SCG_NO_ERROR ||
563                                 cp->ux_errno != 0 ||
564                                 *(Uchar *)&cp->scb != 0 ||
565                                 cp->u_sense.cmd_sense[0] != 0)  /* Paranioa */
566                 return (TRUE);
567         return (FALSE);
568 }
569
570 /*
571  * Used to print error messges if the command itself has been run silently.
572  *
573  * print the following SCSI codes:
574  *
575  * -    command transport status
576  * -    CDB
577  * -    SCSI status byte
578  * -    Sense Bytes
579  * -    Decoded Sense data
580  * -    DMA status
581  * -    SCSI timing
582  *
583  * to SCSI errfile.
584  */
585 void
586 usal_printerr(SCSI *usalp)
587 {
588         usal_fprinterr(usalp, (FILE *)usalp->errfile);
589 }
590
591 /*
592  * print the following SCSI codes:
593  *
594  * -    command transport status
595  * -    CDB
596  * -    SCSI status byte
597  * -    Sense Bytes
598  * -    Decoded Sense data
599  * -    DMA status
600  * -    SCSI timing
601  *
602  * to a file.
603  */
604 void
605 usal_fprinterr(SCSI *usalp, FILE *f)
606 {
607         char    errbuf[SCSI_ERRSTR_SIZE];
608         int     amt;
609
610         amt = usal_sprinterr(usalp, errbuf, sizeof (errbuf));
611         if (amt > 0) {
612                 filewrite(f, errbuf, amt);
613                 fflush(f);
614         }
615 }
616
617 /*
618  * print the following SCSI codes:
619  *
620  * -    command transport status
621  * -    CDB
622  * -    SCSI status byte
623  * -    Sense Bytes
624  * -    Decoded Sense data
625  * -    DMA status
626  * -    SCSI timing
627  *
628  * into a buffer.
629  */
630 int
631 usal_sprinterr(SCSI *usalp, char *buf, int maxcnt)
632 {
633         int     amt;
634         int     osilent = usalp->silent;
635         int     overbose = usalp->verbose;
636
637         usalp->silent = 0;
638         usalp->verbose = 0;
639         amt = usal_svtail(usalp, NULL, buf, maxcnt);
640         usalp->silent = osilent;
641         usalp->verbose = overbose;
642         return (amt);
643 }
644
645 /*
646  * print the following SCSI codes:
647  *
648  * -    command transport status
649  * -    CDB
650  * -    SCSI status byte
651  * -    Sense Bytes
652  * -    Decoded Sense data
653  *
654  * into a buffer.
655  */
656 int
657 usal__sprinterr(SCSI *usalp, char *buf, int maxcnt)
658 {
659         register struct usal_cmd *cp = usalp->scmd;
660         register char           *err;
661                 char            *cmdname = "SCSI command name not set by caller";
662                 char            errbuf[64];
663         register char           *p = buf;
664         register int            amt;
665
666         switch (cp->error) {
667
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;
671                                 /*
672                                  * We need to cast timeval->* to long because
673                                  * of the broken sys/time.h in Linux.
674                                  */
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,
679                                                                 cp->timeout);
680                                 err = errbuf;
681                                 break;
682         default:                snprintf(errbuf, sizeof (errbuf),
683                                         "error: %d", cp->error);
684                                 err = errbuf;
685         }
686
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);
690         if (amt < 0)
691                 return (amt);
692     */
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)
695      return (amt);
696         p += amt;
697         maxcnt -= amt;
698
699         amt = usal_sprintcdb(usalp, p, maxcnt);
700         if (amt < 0)
701                 return (amt);
702         p += amt;
703         maxcnt -= amt;
704
705         if (cp->error <= SCG_RETRYABLE) {
706                 amt = usal_sprintstatus(usalp, p, maxcnt);
707                 if (amt < 0)
708                         return (amt);
709                 p += amt;
710                 maxcnt -= amt;
711         }
712
713         if (cp->scb.chk) {
714                 amt = usal_sprsense(p, maxcnt, (Uchar *)&cp->sense, cp->sense_count);
715                 if (amt < 0)
716                         return (amt);
717                 p += amt;
718                 maxcnt -= amt;
719                 amt = usal__errmsg(usalp, p, maxcnt, &cp->sense, &cp->scb, -1);
720                 if (amt < 0)
721                         return (amt);
722                 p += amt;
723                 maxcnt -= amt;
724         }
725         return (p - buf);
726 }
727
728 /*
729  * XXX Do we need this function?
730  *
731  * print the SCSI Command descriptor block to XXX stderr.
732  */
733 void
734 usal_printcdb(SCSI *usalp)
735 {
736         usal_prbytes("CDB: ", usalp->scmd->cdb.cmd_cdb, usalp->scmd->cdb_len);
737 }
738
739 /*
740  * print the SCSI Command descriptor block into a buffer.
741  */
742 int
743 usal_sprintcdb(SCSI *usalp, char *buf, int maxcnt)
744 {
745         int     cnt;
746
747         cnt = usal_sprbytes(buf, maxcnt, "CDB: ", usalp->scmd->cdb.cmd_cdb, usalp->scmd->cdb_len);
748         if (cnt < 0)
749                 cnt = 0;
750         return (cnt);
751 }
752
753 /*
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
757  *
758  * print the SCSI send data to stderr.
759  */
760 void
761 usal_printwdata(SCSI *usalp)
762 {
763         register struct usal_cmd        *scmd = usalp->scmd;
764
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: ",
769                         (Uchar *)scmd->addr,
770                         scmd->size > 100 ? 100 : scmd->size);
771         }
772 }
773
774 /*
775  * print the SCSI send data into a buffer.
776  */
777 int
778 usal_sprintwdata(SCSI *usalp, char *buf, int maxcnt)
779 {
780         register struct usal_cmd        *scmd = usalp->scmd;
781         register char           *p = buf;
782         register int            amt;
783
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);
788                 if (amt < 0)
789                         return (amt);
790                 p += amt;
791                 maxcnt -= amt;
792                 amt = usal_sprbytes(p, maxcnt, "Write Data: ",
793                         (Uchar *)scmd->addr,
794                         scmd->size > 100 ? 100 : scmd->size);
795                 if (amt < 0)
796                         return (amt);
797                 p += amt;
798         }
799         return (p - buf);
800 }
801
802 /*
803  * XXX We need to check if we should write to stderr or better to usal->errfile
804  *
805  * print the SCSI received data to stderr.
806  */
807 void
808 usal_printrdata(SCSI *usalp)
809 {
810         register struct usal_cmd        *scmd = usalp->scmd;
811         register int            trcnt = usal_getdmacnt(usalp);
812
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",
815                         trcnt, trcnt,
816                         scmd->size, scmd->size);
817                 usal_prbytes("Received Data: ",
818                         (Uchar *)scmd->addr,
819                         trcnt > 100 ? 100 : trcnt);
820         }
821 }
822
823 /*
824  * print the SCSI received data into a buffer.
825  */
826 int
827 usal_sprintrdata(SCSI *usalp, char *buf, int maxcnt)
828 {
829         register struct usal_cmd        *scmd = usalp->scmd;
830         register char           *p = buf;
831         register int            amt;
832         register int            trcnt = usal_getdmacnt(usalp);
833
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",
837                         trcnt, trcnt,
838                         scmd->size, scmd->size);
839                 if (amt < 0)
840                         return (amt);
841                 p += amt;
842                 maxcnt -= amt;
843                 amt = usal_sprbytes(p, maxcnt,
844                         "Received Data: ",
845                         (Uchar *)scmd->addr,
846                         trcnt > 100 ? 100 : trcnt);
847                 if (amt < 0)
848                         return (amt);
849                 p += amt;
850         }
851         return (p - buf);
852 }
853
854 /*
855  * XXX We need to check if we should write to stderr or better to usal->errfile
856  *
857  * print the SCSI timings and (depending on verbose) received data to stderr.
858  */
859 void
860 usal_printresult(SCSI *usalp)
861 {
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);
868         flush();
869 }
870
871 /*
872  * print the SCSI timings and (depending on verbose) received data into a buffer.
873  */
874 int
875 usal_sprintresult(SCSI *usalp, char *buf, int maxcnt)
876 {
877         register char           *p = buf;
878         register int            amt;
879
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);
885         if (amt < 0)
886                 return (amt);
887         p += amt;
888         maxcnt -= amt;
889         if (usalp->verbose > 1) {
890                 amt = usal_sprintrdata(usalp, p, maxcnt);
891                 if (amt < 0)
892                         return (amt);
893                 p += amt;
894         }
895         return (p - buf);
896 }
897
898 /*
899  * XXX Do we need this function?
900  *
901  * print the SCSI status byte in human readable form to the SCSI error file.
902  */
903 void
904 usal_printstatus(SCSI *usalp)
905 {
906         char    errbuf[SCSI_ERRSTR_SIZE];
907         int     amt;
908
909         amt = usal_sprintstatus(usalp, errbuf, sizeof (errbuf));
910         if (amt > 0) {
911                 filewrite((FILE *)usalp->errfile, errbuf, amt);
912                 fflush((FILE *)usalp->errfile);
913         }
914 }
915
916 /*
917  * print the SCSI status byte in human readable form into a buffer.
918  */
919 int
920 usal_sprintstatus(SCSI *usalp, char *buf, int maxcnt)
921 {
922         register struct usal_cmd *cp = usalp->scmd;
923                 char    *err;
924                 char    *err2 = "";
925         register char   *p = buf;
926         register int    amt;
927
928         amt = snprintf(p, maxcnt, "status: 0x%x ", *(Uchar *)&cp->scb);
929         if (amt < 0)
930                 return (amt);
931         p += amt;
932         maxcnt -= amt;
933 #ifdef  SCSI_EXTENDED_STATUS
934         if (cp->scb.ext_st1) {
935                 amt = snprintf(p, maxcnt, "0x%x ", ((Uchar *)&cp->scb)[1]);
936                 if (amt < 0)
937                         return (amt);
938                 p += amt;
939                 maxcnt -= amt;
940         }
941         if (cp->scb.ext_st2) {
942                 amt = snprintf(p, maxcnt, "0x%x ", ((Uchar *)&cp->scb)[2]);
943                 if (amt < 0)
944                         return (amt);
945                 p += amt;
946                 maxcnt -= amt;
947         }
948 #endif
949         switch (*(Uchar *)&cp->scb & 036) {
950
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;
959         }
960 #ifdef  SCSI_EXTENDED_STATUS
961         if (cp->scb.ext_st1 && cp->scb.ha_er)
962                 err2 = " host adapter detected error";
963 #endif
964         amt = snprintf(p, maxcnt, "(%s%s)\n", err, err2);
965         if (amt < 0)
966                 return (amt);
967         p += amt;
968         return (p - buf);
969 }
970
971 /*
972  * print some bytes in hex to a file.
973  */
974 void
975 usal_fprbytes(FILE *f, char *s, register Uchar *cp, register int n)
976 {
977         fprintf(f, "%s", s);
978         while (--n >= 0)
979                 fprintf(f, " %02X", *cp++);
980         fprintf(f, "\n");
981 }
982
983 /*
984  * print some bytes in ascii to a file.
985  */
986 void
987 usal_fprascii(FILE *f, char *s, register Uchar *cp, register int n)
988 {
989         register int    c;
990
991         fprintf(f, "%s", s);
992         while (--n >= 0) {
993                 c = *cp++;
994                 if (c >= ' ' && c < 0177)
995                         fprintf(f, "%c", c);
996                 else
997                         fprintf(f, ".");
998         }
999         fprintf(f, "\n");
1000 }
1001
1002 /*
1003  * XXX We need to check if we should write to stderr or better to usal->errfile
1004  *
1005  * print some bytes in hex to stderr.
1006  */
1007 void
1008 usal_prbytes(char *s, register Uchar *cp, register int n)
1009 {
1010         usal_fprbytes(stderr, s, cp, n);
1011 }
1012
1013 /*
1014  * XXX We need to check if we should write to stderr or better to usal->errfile
1015  *
1016  * print some bytes in ascii to stderr.
1017  */
1018 void
1019 usal_prascii(char *s, register Uchar *cp, register int n)
1020 {
1021         usal_fprascii(stderr, s, cp, n);
1022 }
1023
1024 /*
1025  * print some bytes in hex into a buffer.
1026  */
1027 int
1028 usal_sprbytes(char *buf, int maxcnt, char *s, register Uchar *cp, register int n)
1029 {
1030         register char   *p = buf;
1031         register int    amt;
1032
1033         amt = snprintf(p, maxcnt, "%s", s);
1034         if (amt < 0)
1035                 return (amt);
1036         p += amt;
1037         maxcnt -= amt;
1038
1039         while (--n >= 0) {
1040                 amt = snprintf(p, maxcnt, " %02X", *cp++);
1041                 if (amt < 0)
1042                         return (amt);
1043                 p += amt;
1044                 maxcnt -= amt;
1045         }
1046         amt = snprintf(p, maxcnt, "\n");
1047         if (amt < 0)
1048                 return (amt);
1049         p += amt;
1050         return (p - buf);
1051 }
1052
1053 /*
1054  * print some bytes in ascii into a buffer.
1055  */
1056 int
1057 usal_sprascii(char *buf, int maxcnt, char *s, register Uchar *cp, register int n)
1058 {
1059         register char   *p = buf;
1060         register int    amt;
1061         register int    c;
1062
1063         amt = snprintf(p, maxcnt, "%s", s);
1064         if (amt < 0)
1065                 return (amt);
1066         p += amt;
1067         maxcnt -= amt;
1068
1069         while (--n >= 0) {
1070                 c = *cp++;
1071                 if (c >= ' ' && c < 0177)
1072                         amt = snprintf(p, maxcnt, "%c", c);
1073                 else
1074                         amt = snprintf(p, maxcnt, ".");
1075                 if (amt < 0)
1076                         return (amt);
1077                 p += amt;
1078                 maxcnt -= amt;
1079         }
1080         amt = snprintf(p, maxcnt, "\n");
1081         if (amt < 0)
1082                 return (amt);
1083         p += amt;
1084         return (p - buf);
1085 }
1086
1087 /*
1088  * print the SCSI sense data for last command in hex to a file.
1089  */
1090 void
1091 usal_fprsense(FILE *f, Uchar *cp, int n)
1092 {
1093         usal_fprbytes(f, "Sense Bytes:", cp, n);
1094 }
1095
1096 /*
1097  * XXX We need to check if we should write to stderr or better to usal->errfile
1098  *
1099  * print the SCSI sense data for last command in hex to stderr.
1100  */
1101 void
1102 usal_prsense(Uchar *cp, int n)
1103 {
1104         usal_fprsense(stderr, cp, n);
1105 }
1106
1107 /*
1108  * print the SCSI sense data for last command in hex into a buffer.
1109  */
1110 int
1111 usal_sprsense(char *buf, int maxcnt, Uchar *cp, int n)
1112 {
1113         return (usal_sprbytes(buf, maxcnt, "Sense Bytes:", cp, n));
1114 }
1115
1116 /*
1117  * Return the SCSI status byte for last command.
1118  */
1119 int
1120 usal_cmd_status(SCSI *usalp)
1121 {
1122         struct usal_cmd *cp = usalp->scmd;
1123         int             cmdstatus = *(Uchar *)&cp->scb;
1124
1125         return (cmdstatus);
1126 }
1127
1128 /*
1129  * Return the SCSI sense key for last command.
1130  */
1131 int
1132 usal_sense_key(SCSI *usalp)
1133 {
1134         register struct usal_cmd *cp = usalp->scmd;
1135         int     key = -1;
1136
1137         if (!usal_cmd_err(usalp))
1138                 return (0);
1139
1140         if (cp->sense.code >= 0x70)
1141                 key = ((struct scsi_ext_sense *)&(cp->sense))->key;
1142         return (key);
1143 }
1144
1145 /*
1146  * Return all the SCSI sense table last command.
1147  */
1148 unsigned char *
1149 usal_sense_table(SCSI *usalp)
1150 {
1151         register struct usal_cmd *cp = usalp->scmd;
1152
1153         if(!usal_cmd_err(usalp))
1154                 return (0);
1155
1156         /* if (cp->sense.code >= 0x70) */
1157         return (unsigned char *) &(cp->sense);
1158 }
1159
1160
1161 /*
1162  * Return the SCSI sense code for last command.
1163  */
1164 int
1165 usal_sense_code(SCSI *usalp)
1166 {
1167         register struct usal_cmd *cp = usalp->scmd;
1168         int     code = -1;
1169
1170         if (!usal_cmd_err(usalp))
1171                 return (0);
1172
1173         if (cp->sense.code >= 0x70)
1174                 code = ((struct scsi_ext_sense *)&(cp->sense))->sense_code;
1175         else
1176                 code = cp->sense.code;
1177         return (code);
1178 }
1179
1180 /*
1181  * Return the SCSI sense qualifier for last command.
1182  */
1183 int
1184 usal_sense_qual(SCSI *usalp)
1185 {
1186         register struct usal_cmd *cp = usalp->scmd;
1187
1188         if (!usal_cmd_err(usalp))
1189                 return (0);
1190
1191         if (cp->sense.code >= 0x70)
1192                 return (((struct scsi_ext_sense *)&(cp->sense))->qual_code);
1193         else
1194                 return (0);
1195 }
1196
1197 /*
1198  * Print the device type from the SCSI inquiry buffer to file.
1199  */
1200 void
1201 usal_fprintdev(FILE *f, struct scsi_inquiry *ip)
1202 {
1203         if (ip->removable)
1204                 fprintf(f, "Removable ");
1205         if (ip->data_format >= 2) {
1206                 switch (ip->qualifier) {
1207
1208                 case INQ_DEV_PRESENT:
1209                         break;
1210                 case INQ_DEV_NOTPR:
1211                         fprintf(f, "not present ");
1212                         break;
1213                 case INQ_DEV_RES:
1214                         fprintf(f, "reserved ");
1215                         break;
1216                 case INQ_DEV_NOTSUP:
1217                         if (ip->type == INQ_NODEV) {
1218                                 fprintf(f, "unsupported\n"); return;
1219                         }
1220                         fprintf(f, "unsupported ");
1221                         break;
1222                 default:
1223                         fprintf(f, "vendor specific %d ",
1224                                                 (int)ip->qualifier);
1225                 }
1226         }
1227         switch (ip->type) {
1228
1229         case INQ_DASD:
1230                 fprintf(f, "Disk");             break;
1231         case INQ_SEQD:
1232                 fprintf(f, "Tape");             break;
1233         case INQ_PRTD:
1234                 fprintf(f, "Printer");  break;
1235         case INQ_PROCD:
1236                 fprintf(f, "Processor");        break;
1237         case INQ_WORM:
1238                 fprintf(f, "WORM");             break;
1239         case INQ_ROMD:
1240                 fprintf(f, "CD-ROM");   break;
1241         case INQ_SCAN:
1242                 fprintf(f, "Scanner");  break;
1243         case INQ_OMEM:
1244                 fprintf(f, "Optical Storage"); break;
1245         case INQ_JUKE:
1246                 fprintf(f, "Juke Box"); break;
1247         case INQ_COMM:
1248                 fprintf(f, "Communication");    break;
1249         case INQ_IT8_1:
1250                 fprintf(f, "IT8 1");            break;
1251         case INQ_IT8_2:
1252                 fprintf(f, "IT8 2");            break;
1253         case INQ_STARR:
1254                 fprintf(f, "Storage array");    break;
1255         case INQ_ENCL:
1256                 fprintf(f, "Enclosure services"); break;
1257         case INQ_SDAD:
1258                 fprintf(f, "Simple direct access"); break;
1259         case INQ_OCRW:
1260                 fprintf(f, "Optical card r/w"); break;
1261         case INQ_BRIDGE:
1262                 fprintf(f, "Bridging expander"); break;
1263         case INQ_OSD:
1264                 fprintf(f, "Object based storage"); break;
1265         case INQ_ADC:
1266                 fprintf(f, "Automation/Drive Interface"); break;
1267         case INQ_WELLKNOWN:
1268                 fprintf(f, "Well known lun"); break;
1269
1270         case INQ_NODEV:
1271                 if (ip->data_format >= 2) {
1272                         fprintf(f, "unknown/no device");
1273                         break;
1274                 } else if (ip->qualifier == INQ_DEV_NOTSUP) {
1275                         fprintf(f, "unit not present");
1276                         break;
1277                 }
1278         default:
1279                 fprintf(f, "unknown device type 0x%x",
1280                                                 (int)ip->type);
1281         }
1282         fprintf(f, "\n");
1283 }
1284
1285 /*
1286  * Print the device type from the SCSI inquiry buffer to stdout.
1287  */
1288 void
1289 usal_printdev(struct scsi_inquiry *ip)
1290 {
1291         usal_fprintdev(stdout, ip);
1292 }
1293
1294 /*
1295  * print into the SCSI error buffer, adjust the next write pointer.
1296  */
1297 /* VARARGS2 */
1298 int
1299 usal_printf(SCSI *usalp, const char *form, ...)
1300 {
1301         int     cnt;
1302         va_list args;
1303
1304         va_start(args, form);
1305         cnt = vsnprintf(usalp->errptr, usal_errrsize(usalp), form, args);
1306         va_end(args);
1307
1308         if (cnt < 0) {
1309                 usalp->errptr[0] = '\0';
1310         } else {
1311                 usalp->errptr += cnt;
1312         }
1313         return (cnt);
1314 }
1315
1316 /*
1317  * Flush the SCSI error buffer to SCSI errfile.
1318  * Clear error buffer after flushing.
1319  */
1320 int
1321 usal_errflush(SCSI *usalp)
1322 {
1323         if (usalp->errfile == NULL)
1324                 return (0);
1325
1326         return (usal_errfflush(usalp, (FILE *)usalp->errfile));
1327 }
1328
1329 /*
1330  * Flush the SCSI error buffer to a file.
1331  * Clear error buffer after flushing.
1332  */
1333 int
1334 usal_errfflush(SCSI *usalp, FILE *f)
1335 {
1336         int     cnt;
1337
1338         cnt = usalp->errptr - usalp->errbeg;
1339         if (cnt > 0) {
1340                 filewrite(f, usalp->errbeg, cnt);
1341                 fflush(f);
1342                 usalp->errbeg = usalp->errptr;
1343         }
1344         return (cnt);
1345 }