/* * This file has been modified for the cdrkit suite. * * The behaviour and appearence of the program code below can differ to a major * extent from the version distributed by the original author(s). * * For details, see Changelog file distributed with the cdrkit package. If you * received this file from another source then ask the distributing person for * a log of modifications. * */ /* @(#)scsitransp.c 1.91 04/06/17 Copyright 1988,1995,2000-2004 J. Schilling */ /*#ifndef lint*/ static char sccsid[] = "@(#)scsitransp.c 1.91 04/06/17 Copyright 1988,1995,2000-2004 J. Schilling"; /*#endif*/ /* * SCSI user level command transport routines (generic part). * * Warning: you may change this source, but if you do that * you need to change the _usal_version and _usal_auth* string below. * You may not return "schily" for an SCG_AUTHOR request anymore. * Choose your name instead of "schily" and make clear that the version * string is related to a modified source. * * Copyright (c) 1988,1995,2000-2004 J. Schilling */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * this program; see the file COPYING. If not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "usaltimes.h" #include /* * Warning: you may change this source, but if you do that * you need to change the _usal_version and _usal_auth* string below. * You may not return "schily" for an SCG_AUTHOR request anymore. * Choose your name instead of "schily" and make clear that the version * string is related to a modified source. */ static char _usal_version[] = CDRKIT_VERSION; /* The global libusal version */ static char _usal_auth_cdrkit[] = "Cdrkit"; /* The author for this module */ #define DEFTIMEOUT 20 /* Default timeout for SCSI command transport */ char *usal_version(SCSI *usalp, int what); int usal__open(SCSI *usalp, char *device); int usal__close(SCSI *usalp); BOOL usal_havebus(SCSI *usalp, int); int usal_initiator_id(SCSI *usalp); int usal_isatapi(SCSI *usalp); int usal_reset(SCSI *usalp, int what); void *usal_getbuf(SCSI *usalp, long); void usal_freebuf(SCSI *usalp); long usal_bufsize(SCSI *usalp, long); void usal_setnonstderrs(SCSI *usalp, const char **); BOOL usal_yes(char *); #ifdef nonono static void usal_sighandler(int); #endif int usal_cmd(SCSI *usalp); void usal_vhead(SCSI *usalp); int usal_svhead(SCSI *usalp, char *buf, int maxcnt); int usal_vtail(SCSI *usalp); int usal_svtail(SCSI *usalp, int *retp, char *buf, int maxcnt); void usal_vsetup(SCSI *usalp); int usal_getresid(SCSI *usalp); int usal_getdmacnt(SCSI *usalp); BOOL usal_cmd_err(SCSI *usalp); void usal_printerr(SCSI *usalp); void usal_fprinterr(SCSI *usalp, FILE *f); int usal_sprinterr(SCSI *usalp, char *buf, int maxcnt); int usal__sprinterr(SCSI *usalp, char *buf, int maxcnt); void usal_printcdb(SCSI *usalp); int usal_sprintcdb(SCSI *usalp, char *buf, int maxcnt); void usal_printwdata(SCSI *usalp); int usal_sprintwdata(SCSI *usalp, char *buf, int maxcnt); void usal_printrdata(SCSI *usalp); int usal_sprintrdata(SCSI *usalp, char *buf, int maxcnt); void usal_printresult(SCSI *usalp); int usal_sprintresult(SCSI *usalp, char *buf, int maxcnt); void usal_printstatus(SCSI *usalp); int usal_sprintstatus(SCSI *usalp, char *buf, int maxcnt); void usal_fprbytes(FILE *, char *, unsigned char *, int); void usal_fprascii(FILE *, char *, unsigned char *, int); void usal_prbytes(char *, unsigned char *, int); void usal_prascii(char *, unsigned char *, int); int usal_sprbytes(char *buf, int maxcnt, char *, unsigned char *, int); int usal_sprascii(char *buf, int maxcnt, char *, unsigned char *, int); void usal_fprsense(FILE *f, unsigned char *, int); int usal_sprsense(char *buf, int maxcnt, unsigned char *, int); void usal_prsense(unsigned char *, int); int usal_cmd_status(SCSI *usalp); int usal_sense_key(SCSI *usalp); int usal_sense_code(SCSI *usalp); int usal_sense_qual(SCSI *usalp); unsigned char *usal_sense_table(SCSI *usalp); void usal_fprintdev(FILE *, struct scsi_inquiry *); void usal_printdev(struct scsi_inquiry *); int usal_printf(SCSI *usalp, const char *form, ...); int usal_errflush(SCSI *usalp); int usal_errfflush(SCSI *usalp, FILE *f); /* * Return version information for the SCSI transport code. * This has been introduced to make it easier to trace down problems * in applications. * * If usalp is NULL, return general library version information. * If usalp is != NULL, return version information for the low level transport. */ char * usal_version(SCSI *usalp, int what) { if (usalp == (SCSI *)0) { switch (what) { case SCG_VERSION: return (_usal_version); /* * If you changed this source, you are not allowed to * return "schily" for the SCG_AUTHOR request. */ case SCG_AUTHOR: return (_usal_auth_cdrkit); case SCG_SCCS_ID: return (sccsid); default: return ((char *)0); } } return (SCGO_VERSION(usalp, what)); } /* * Call low level SCSI open routine from transport abstraction layer. */ int usal__open(SCSI *usalp, char *device) { int ret; usal_ops_t *ops; extern usal_ops_t usal_std_ops; usalp->ops = &usal_std_ops; if (device && strncmp(device, "REMOTE", 6) == 0) { ops = usal_remote(); if (ops != NULL) usalp->ops = ops; } ret = SCGO_OPEN(usalp, device); if (ret < 0) return (ret); /* * Now make usalp->fd valid if possible. * Note that usal_scsibus(usalp)/usal_target(usalp)/usal_lun(usalp) may have * changed in SCGO_OPEN(). */ usal_settarget(usalp, usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp)); return (ret); } /* * Call low level SCSI close routine from transport abstraction layer. */ int usal__close(SCSI *usalp) { return (SCGO_CLOSE(usalp)); } /* * Retrieve max DMA count for this target. */ long usal_bufsize(SCSI *usalp, long amt) { long maxdma; maxdma = SCGO_MAXDMA(usalp, amt); if (amt <= 0 || amt > maxdma) amt = maxdma; usalp->maxdma = maxdma; /* Max possible */ usalp->maxbuf = amt; /* Current value */ return (amt); } /* * Allocate a buffer that may be used for DMA. */ void * usal_getbuf(SCSI *usalp, long amt) { void *buf; if (amt <= 0 || amt > usal_bufsize(usalp, amt)) return ((void *)0); buf = SCGO_GETBUF(usalp, amt); usalp->bufptr = buf; return (buf); } /* * Free DMA buffer. */ void usal_freebuf(SCSI *usalp) { SCGO_FREEBUF(usalp); usalp->bufptr = NULL; } /* * Check if 'busno' is a valid SCSI bus number. */ BOOL usal_havebus(SCSI *usalp, int busno) { return (SCGO_HAVEBUS(usalp, busno)); } /* * Return SCSI initiator ID for current SCSI bus if available. */ int usal_initiator_id(SCSI *usalp) { return (SCGO_INITIATOR_ID(usalp)); } /* * Return a hint whether current SCSI target refers to a ATAPI device. */ int usal_isatapi(SCSI *usalp) { return (SCGO_ISATAPI(usalp)); } /* * Reset SCSI bus or target. */ int usal_reset(SCSI *usalp, int what) { return (SCGO_RESET(usalp, what)); } /* * Set up nonstd error vector for curren target. * To clear additional error table, call usal_setnonstderrs(usalp, NULL); * Note: do not use this when scanning the SCSI bus. */ void usal_setnonstderrs(SCSI *usalp, const char **vec) { usalp->nonstderrs = vec; } /* * Simple Yes/No answer checker. */ BOOL usal_yes(char *msg) { char okbuf[10]; printf("%s", msg); flush(); if (rols_getline(okbuf, sizeof (okbuf)) == EOF) exit(EX_BAD); if (streql(okbuf, "y") || streql(okbuf, "yes") || streql(okbuf, "Y") || streql(okbuf, "YES")) return (TRUE); else return (FALSE); } #ifdef nonono static void usal_sighandler(int sig) { printf("\n"); if (scsi_running) { printf("Running command: %s\n", scsi_command); printf("Resetting SCSI - Bus.\n"); if (usal_reset(usalp) < 0) errmsg("Cannot reset SCSI - Bus.\n"); } if (usal_yes("EXIT ? ")) exit(sig); } #endif /* * Send a SCSI command. * Do error checking and reporting depending on the values of * usalp->verbose, usalp->debug and usalp->silent. */ int usal_cmd(SCSI *usalp) { int ret; register struct usal_cmd *scmd = usalp->scmd; /* * Reset old error messages in usalp->errstr */ usalp->errptr = usalp->errbeg = usalp->errstr; scmd->kdebug = usalp->kdebug; if (scmd->timeout == 0 || scmd->timeout < usalp->deftimeout) scmd->timeout = usalp->deftimeout; if (usalp->disre_disable) scmd->flags &= ~SCG_DISRE_ENA; if (usalp->noparity) scmd->flags |= SCG_NOPARITY; scmd->u_sense.cmd_sense[0] = 0; /* Paranioa */ if (scmd->sense_len > SCG_MAX_SENSE) scmd->sense_len = SCG_MAX_SENSE; else if (scmd->sense_len < 0) scmd->sense_len = 0; if (usalp->verbose) { usal_vhead(usalp); usal_errflush(usalp); } if (usalp->running) { if (usalp->curcmdname) { fprintf(stderr, "Currently running '%s' command.\n", usalp->curcmdname); } raisecond("SCSI ALREADY RUNNING !!", 0L); } usalp->cb_fun = NULL; gettimeofday(usalp->cmdstart, (struct timezone *)0); usalp->curcmdname = usalp->cmdname; usalp->running = TRUE; ret = SCGO_SEND(usalp); usalp->running = FALSE; __usal_times(usalp); if (ret < 0) { /* * Old /dev/usal versions will not allow to access targets > 7. * Include a workaround to make this non fatal. */ if (usal_target(usalp) < 8 || geterrno() != EINVAL) comerr("Cannot send SCSI cmd via ioctl\n"); if (scmd->ux_errno == 0) scmd->ux_errno = geterrno(); if (scmd->error == SCG_NO_ERROR) scmd->error = SCG_FATAL; if (usalp->debug > 0) { errmsg("ret < 0 errno: %d ux_errno: %d error: %d\n", geterrno(), scmd->ux_errno, scmd->error); } } ret = usal_vtail(usalp); usal_errflush(usalp); if (usalp->cb_fun != NULL) (*usalp->cb_fun)(usalp->cb_arg); return (ret); } /* * Fill the head of verbose printing into the SCSI error buffer. * Action depends on SCSI verbose status. */ void usal_vhead(SCSI *usalp) { usalp->errptr += usal_svhead(usalp, usalp->errptr, usal_errrsize(usalp)); } /* * Fill the head of verbose printing into a buffer. * Action depends on SCSI verbose status. */ int usal_svhead(SCSI *usalp, char *buf, int maxcnt) { register char *p = buf; register int amt; if (usalp->verbose <= 0) return (0); amt = snprintf(p, maxcnt, "\nExecuting '%s' command on Bus %d Target %d, Lun %d timeout %ds\n", /* XXX Really this ??? */ /* usalp->cmdname, usal_scsibus(usalp), usal_target(usalp), usalp->scmd->cdb.g0_cdb.lun,*/ usalp->cmdname, usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp), usalp->scmd->timeout); if (amt < 0) return (amt); p += amt; maxcnt -= amt; amt = usal_sprintcdb(usalp, p, maxcnt); if (amt < 0) return (amt); p += amt; maxcnt -= amt; if (usalp->verbose > 1) { amt = usal_sprintwdata(usalp, p, maxcnt); if (amt < 0) return (amt); p += amt; maxcnt -= amt; } return (p - buf); } /* * Fill the tail of verbose printing into the SCSI error buffer. * Action depends on SCSI verbose status. */ int usal_vtail(SCSI *usalp) { int ret; usalp->errptr += usal_svtail(usalp, &ret, usalp->errptr, usal_errrsize(usalp)); return (ret); } /* * Fill the tail of verbose printing into a buffer. * Action depends on SCSI verbose status. */ int usal_svtail(SCSI *usalp, int *retp, char *buf, int maxcnt) { register char *p = buf; register int amt; int ret; ret = usal_cmd_err(usalp) ? -1 : 0; if (retp) *retp = ret; if (ret) { if (usalp->silent <= 0 || usalp->verbose) { amt = usal__sprinterr(usalp, p, maxcnt); if (amt < 0) return (amt); p += amt; maxcnt -= amt; } } if ((usalp->silent <= 0 || usalp->verbose) && usalp->scmd->resid) { if (usalp->scmd->resid < 0) { /* * An operating system that does DMA the right way * will not allow DMA overruns - it will stop DMA * before bad things happen. * A DMA residual count < 0 (-1) is a hint for a DMA * overrun but does not affect the transfer count. */ amt = snprintf(p, maxcnt, "DMA overrun, "); if (amt < 0) return (amt); p += amt; maxcnt -= amt; } amt = snprintf(p, maxcnt, "resid: %d\n", usalp->scmd->resid); if (amt < 0) return (amt); p += amt; maxcnt -= amt; } if (usalp->verbose > 0 || (ret < 0 && usalp->silent <= 0)) { amt = usal_sprintresult(usalp, p, maxcnt); if (amt < 0) return (amt); p += amt; maxcnt -= amt; } return (p - buf); } /* * Set up SCSI error buffer with verbose print data. * Action depends on SCSI verbose status. */ void usal_vsetup(SCSI *usalp) { usal_vhead(usalp); usal_vtail(usalp); } /* * Return the residual DMA count for last command. * If this count is < 0, then a DMA overrun occured. */ int usal_getresid(SCSI *usalp) { return (usalp->scmd->resid); } /* * Return the actual DMA count for last command. */ int usal_getdmacnt(SCSI *usalp) { register struct usal_cmd *scmd = usalp->scmd; if (scmd->resid < 0) return (scmd->size); return (scmd->size - scmd->resid); } /* * Test if last SCSI command got an error. */ BOOL usal_cmd_err(SCSI *usalp) { register struct usal_cmd *cp = usalp->scmd; if (cp->error != SCG_NO_ERROR || cp->ux_errno != 0 || *(Uchar *)&cp->scb != 0 || cp->u_sense.cmd_sense[0] != 0) /* Paranioa */ return (TRUE); return (FALSE); } /* * Used to print error messges if the command itself has been run silently. * * print the following SCSI codes: * * - command transport status * - CDB * - SCSI status byte * - Sense Bytes * - Decoded Sense data * - DMA status * - SCSI timing * * to SCSI errfile. */ void usal_printerr(SCSI *usalp) { usal_fprinterr(usalp, (FILE *)usalp->errfile); } /* * print the following SCSI codes: * * - command transport status * - CDB * - SCSI status byte * - Sense Bytes * - Decoded Sense data * - DMA status * - SCSI timing * * to a file. */ void usal_fprinterr(SCSI *usalp, FILE *f) { char errbuf[SCSI_ERRSTR_SIZE]; int amt; amt = usal_sprinterr(usalp, errbuf, sizeof (errbuf)); if (amt > 0) { filewrite(f, errbuf, amt); fflush(f); } } /* * print the following SCSI codes: * * - command transport status * - CDB * - SCSI status byte * - Sense Bytes * - Decoded Sense data * - DMA status * - SCSI timing * * into a buffer. */ int usal_sprinterr(SCSI *usalp, char *buf, int maxcnt) { int amt; int osilent = usalp->silent; int overbose = usalp->verbose; usalp->silent = 0; usalp->verbose = 0; amt = usal_svtail(usalp, NULL, buf, maxcnt); usalp->silent = osilent; usalp->verbose = overbose; return (amt); } /* * print the following SCSI codes: * * - command transport status * - CDB * - SCSI status byte * - Sense Bytes * - Decoded Sense data * * into a buffer. */ int usal__sprinterr(SCSI *usalp, char *buf, int maxcnt) { register struct usal_cmd *cp = usalp->scmd; register char *err; char *cmdname = "SCSI command name not set by caller"; char errbuf[64]; register char *p = buf; register int amt; switch (cp->error) { case SCG_NO_ERROR : err = "no error"; break; case SCG_RETRYABLE: err = "retryable error"; break; case SCG_FATAL : err = "fatal error"; break; /* * We need to cast timeval->* to long because * of the broken sys/time.h in Linux. */ case SCG_TIMEOUT : snprintf(errbuf, sizeof (errbuf), "cmd timeout after %ld.%03ld (%d) s", (long)usalp->cmdstop->tv_sec, (long)usalp->cmdstop->tv_usec/1000, cp->timeout); err = errbuf; break; default: snprintf(errbuf, sizeof (errbuf), "error: %d", cp->error); err = errbuf; } if (usalp->cmdname != NULL && usalp->cmdname[0] != '\0') cmdname = usalp->cmdname; /*amt = serrmsgno(cp->ux_errno, p, maxcnt, "%s: scsi sendcmd: %s\n", cmdname, err); if (amt < 0) return (amt); */ amt=snprintf(p, maxcnt, "Errno: %d (%s), %s scsi sendcmd: %s\n", cp->ux_errno, strerror(cp->ux_errno), cmdname, err); if(amt>=maxcnt || amt<0) return (amt); p += amt; maxcnt -= amt; amt = usal_sprintcdb(usalp, p, maxcnt); if (amt < 0) return (amt); p += amt; maxcnt -= amt; if (cp->error <= SCG_RETRYABLE) { amt = usal_sprintstatus(usalp, p, maxcnt); if (amt < 0) return (amt); p += amt; maxcnt -= amt; } if (cp->scb.chk) { amt = usal_sprsense(p, maxcnt, (Uchar *)&cp->sense, cp->sense_count); if (amt < 0) return (amt); p += amt; maxcnt -= amt; amt = usal__errmsg(usalp, p, maxcnt, &cp->sense, &cp->scb, -1); if (amt < 0) return (amt); p += amt; maxcnt -= amt; } return (p - buf); } /* * XXX Do we need this function? * * print the SCSI Command descriptor block to XXX stderr. */ void usal_printcdb(SCSI *usalp) { usal_prbytes("CDB: ", usalp->scmd->cdb.cmd_cdb, usalp->scmd->cdb_len); } /* * print the SCSI Command descriptor block into a buffer. */ int usal_sprintcdb(SCSI *usalp, char *buf, int maxcnt) { int cnt; cnt = usal_sprbytes(buf, maxcnt, "CDB: ", usalp->scmd->cdb.cmd_cdb, usalp->scmd->cdb_len); if (cnt < 0) cnt = 0; return (cnt); } /* * XXX Do we need this function? * XXX usal_printrdata() is used. * XXX We need to check if we should write to stderr or better to usal->errfile * * print the SCSI send data to stderr. */ void usal_printwdata(SCSI *usalp) { register struct usal_cmd *scmd = usalp->scmd; if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) == 0) { fprintf(stderr, "Sending %d (0x%X) bytes of data.\n", scmd->size, scmd->size); usal_prbytes("Write Data: ", (Uchar *)scmd->addr, scmd->size > 100 ? 100 : scmd->size); } } /* * print the SCSI send data into a buffer. */ int usal_sprintwdata(SCSI *usalp, char *buf, int maxcnt) { register struct usal_cmd *scmd = usalp->scmd; register char *p = buf; register int amt; if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) == 0) { amt = snprintf(p, maxcnt, "Sending %d (0x%X) bytes of data.\n", scmd->size, scmd->size); if (amt < 0) return (amt); p += amt; maxcnt -= amt; amt = usal_sprbytes(p, maxcnt, "Write Data: ", (Uchar *)scmd->addr, scmd->size > 100 ? 100 : scmd->size); if (amt < 0) return (amt); p += amt; } return (p - buf); } /* * XXX We need to check if we should write to stderr or better to usal->errfile * * print the SCSI received data to stderr. */ void usal_printrdata(SCSI *usalp) { register struct usal_cmd *scmd = usalp->scmd; register int trcnt = usal_getdmacnt(usalp); if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) != 0) { fprintf(stderr, "Got %d (0x%X), expecting %d (0x%X) bytes of data.\n", trcnt, trcnt, scmd->size, scmd->size); usal_prbytes("Received Data: ", (Uchar *)scmd->addr, trcnt > 100 ? 100 : trcnt); } } /* * print the SCSI received data into a buffer. */ int usal_sprintrdata(SCSI *usalp, char *buf, int maxcnt) { register struct usal_cmd *scmd = usalp->scmd; register char *p = buf; register int amt; register int trcnt = usal_getdmacnt(usalp); if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) != 0) { amt = snprintf(p, maxcnt, "Got %d (0x%X), expecting %d (0x%X) bytes of data.\n", trcnt, trcnt, scmd->size, scmd->size); if (amt < 0) return (amt); p += amt; maxcnt -= amt; amt = usal_sprbytes(p, maxcnt, "Received Data: ", (Uchar *)scmd->addr, trcnt > 100 ? 100 : trcnt); if (amt < 0) return (amt); p += amt; } return (p - buf); } /* * XXX We need to check if we should write to stderr or better to usal->errfile * * print the SCSI timings and (depending on verbose) received data to stderr. */ void usal_printresult(SCSI *usalp) { fprintf(stderr, "cmd finished after %ld.%03lds timeout %ds\n", (long)usalp->cmdstop->tv_sec, (long)usalp->cmdstop->tv_usec/1000, usalp->scmd->timeout); if (usalp->verbose > 1) usal_printrdata(usalp); flush(); } /* * print the SCSI timings and (depending on verbose) received data into a buffer. */ int usal_sprintresult(SCSI *usalp, char *buf, int maxcnt) { register char *p = buf; register int amt; amt = snprintf(p, maxcnt, "cmd finished after %ld.%03lds timeout %ds\n", (long)usalp->cmdstop->tv_sec, (long)usalp->cmdstop->tv_usec/1000, usalp->scmd->timeout); if (amt < 0) return (amt); p += amt; maxcnt -= amt; if (usalp->verbose > 1) { amt = usal_sprintrdata(usalp, p, maxcnt); if (amt < 0) return (amt); p += amt; } return (p - buf); } /* * XXX Do we need this function? * * print the SCSI status byte in human readable form to the SCSI error file. */ void usal_printstatus(SCSI *usalp) { char errbuf[SCSI_ERRSTR_SIZE]; int amt; amt = usal_sprintstatus(usalp, errbuf, sizeof (errbuf)); if (amt > 0) { filewrite((FILE *)usalp->errfile, errbuf, amt); fflush((FILE *)usalp->errfile); } } /* * print the SCSI status byte in human readable form into a buffer. */ int usal_sprintstatus(SCSI *usalp, char *buf, int maxcnt) { register struct usal_cmd *cp = usalp->scmd; char *err; char *err2 = ""; register char *p = buf; register int amt; amt = snprintf(p, maxcnt, "status: 0x%x ", *(Uchar *)&cp->scb); if (amt < 0) return (amt); p += amt; maxcnt -= amt; #ifdef SCSI_EXTENDED_STATUS if (cp->scb.ext_st1) { amt = snprintf(p, maxcnt, "0x%x ", ((Uchar *)&cp->scb)[1]); if (amt < 0) return (amt); p += amt; maxcnt -= amt; } if (cp->scb.ext_st2) { amt = snprintf(p, maxcnt, "0x%x ", ((Uchar *)&cp->scb)[2]); if (amt < 0) return (amt); p += amt; maxcnt -= amt; } #endif switch (*(Uchar *)&cp->scb & 036) { case 0 : err = "GOOD STATUS"; break; case 02 : err = "CHECK CONDITION"; break; case 04 : err = "CONDITION MET/GOOD"; break; case 010: err = "BUSY"; break; case 020: err = "INTERMEDIATE GOOD STATUS"; break; case 024: err = "INTERMEDIATE CONDITION MET/GOOD"; break; case 030: err = "RESERVATION CONFLICT"; break; default : err = "Reserved"; break; } #ifdef SCSI_EXTENDED_STATUS if (cp->scb.ext_st1 && cp->scb.ha_er) err2 = " host adapter detected error"; #endif amt = snprintf(p, maxcnt, "(%s%s)\n", err, err2); if (amt < 0) return (amt); p += amt; return (p - buf); } /* * print some bytes in hex to a file. */ void usal_fprbytes(FILE *f, char *s, register Uchar *cp, register int n) { fprintf(f, "%s", s); while (--n >= 0) fprintf(f, " %02X", *cp++); fprintf(f, "\n"); } /* * print some bytes in ascii to a file. */ void usal_fprascii(FILE *f, char *s, register Uchar *cp, register int n) { register int c; fprintf(f, "%s", s); while (--n >= 0) { c = *cp++; if (c >= ' ' && c < 0177) fprintf(f, "%c", c); else fprintf(f, "."); } fprintf(f, "\n"); } /* * XXX We need to check if we should write to stderr or better to usal->errfile * * print some bytes in hex to stderr. */ void usal_prbytes(char *s, register Uchar *cp, register int n) { usal_fprbytes(stderr, s, cp, n); } /* * XXX We need to check if we should write to stderr or better to usal->errfile * * print some bytes in ascii to stderr. */ void usal_prascii(char *s, register Uchar *cp, register int n) { usal_fprascii(stderr, s, cp, n); } /* * print some bytes in hex into a buffer. */ int usal_sprbytes(char *buf, int maxcnt, char *s, register Uchar *cp, register int n) { register char *p = buf; register int amt; amt = snprintf(p, maxcnt, "%s", s); if (amt < 0) return (amt); p += amt; maxcnt -= amt; while (--n >= 0) { amt = snprintf(p, maxcnt, " %02X", *cp++); if (amt < 0) return (amt); p += amt; maxcnt -= amt; } amt = snprintf(p, maxcnt, "\n"); if (amt < 0) return (amt); p += amt; return (p - buf); } /* * print some bytes in ascii into a buffer. */ int usal_sprascii(char *buf, int maxcnt, char *s, register Uchar *cp, register int n) { register char *p = buf; register int amt; register int c; amt = snprintf(p, maxcnt, "%s", s); if (amt < 0) return (amt); p += amt; maxcnt -= amt; while (--n >= 0) { c = *cp++; if (c >= ' ' && c < 0177) amt = snprintf(p, maxcnt, "%c", c); else amt = snprintf(p, maxcnt, "."); if (amt < 0) return (amt); p += amt; maxcnt -= amt; } amt = snprintf(p, maxcnt, "\n"); if (amt < 0) return (amt); p += amt; return (p - buf); } /* * print the SCSI sense data for last command in hex to a file. */ void usal_fprsense(FILE *f, Uchar *cp, int n) { usal_fprbytes(f, "Sense Bytes:", cp, n); } /* * XXX We need to check if we should write to stderr or better to usal->errfile * * print the SCSI sense data for last command in hex to stderr. */ void usal_prsense(Uchar *cp, int n) { usal_fprsense(stderr, cp, n); } /* * print the SCSI sense data for last command in hex into a buffer. */ int usal_sprsense(char *buf, int maxcnt, Uchar *cp, int n) { return (usal_sprbytes(buf, maxcnt, "Sense Bytes:", cp, n)); } /* * Return the SCSI status byte for last command. */ int usal_cmd_status(SCSI *usalp) { struct usal_cmd *cp = usalp->scmd; int cmdstatus = *(Uchar *)&cp->scb; return (cmdstatus); } /* * Return the SCSI sense key for last command. */ int usal_sense_key(SCSI *usalp) { register struct usal_cmd *cp = usalp->scmd; int key = -1; if (!usal_cmd_err(usalp)) return (0); if (cp->sense.code >= 0x70) key = ((struct scsi_ext_sense *)&(cp->sense))->key; return (key); } /* * Return all the SCSI sense table last command. */ unsigned char * usal_sense_table(SCSI *usalp) { register struct usal_cmd *cp = usalp->scmd; if(!usal_cmd_err(usalp)) return (0); /* if (cp->sense.code >= 0x70) */ return (unsigned char *) &(cp->sense); } /* * Return the SCSI sense code for last command. */ int usal_sense_code(SCSI *usalp) { register struct usal_cmd *cp = usalp->scmd; int code = -1; if (!usal_cmd_err(usalp)) return (0); if (cp->sense.code >= 0x70) code = ((struct scsi_ext_sense *)&(cp->sense))->sense_code; else code = cp->sense.code; return (code); } /* * Return the SCSI sense qualifier for last command. */ int usal_sense_qual(SCSI *usalp) { register struct usal_cmd *cp = usalp->scmd; if (!usal_cmd_err(usalp)) return (0); if (cp->sense.code >= 0x70) return (((struct scsi_ext_sense *)&(cp->sense))->qual_code); else return (0); } /* * Print the device type from the SCSI inquiry buffer to file. */ void usal_fprintdev(FILE *f, struct scsi_inquiry *ip) { if (ip->removable) fprintf(f, "Removable "); if (ip->data_format >= 2) { switch (ip->qualifier) { case INQ_DEV_PRESENT: break; case INQ_DEV_NOTPR: fprintf(f, "not present "); break; case INQ_DEV_RES: fprintf(f, "reserved "); break; case INQ_DEV_NOTSUP: if (ip->type == INQ_NODEV) { fprintf(f, "unsupported\n"); return; } fprintf(f, "unsupported "); break; default: fprintf(f, "vendor specific %d ", (int)ip->qualifier); } } switch (ip->type) { case INQ_DASD: fprintf(f, "Disk"); break; case INQ_SEQD: fprintf(f, "Tape"); break; case INQ_PRTD: fprintf(f, "Printer"); break; case INQ_PROCD: fprintf(f, "Processor"); break; case INQ_WORM: fprintf(f, "WORM"); break; case INQ_ROMD: fprintf(f, "CD-ROM"); break; case INQ_SCAN: fprintf(f, "Scanner"); break; case INQ_OMEM: fprintf(f, "Optical Storage"); break; case INQ_JUKE: fprintf(f, "Juke Box"); break; case INQ_COMM: fprintf(f, "Communication"); break; case INQ_IT8_1: fprintf(f, "IT8 1"); break; case INQ_IT8_2: fprintf(f, "IT8 2"); break; case INQ_STARR: fprintf(f, "Storage array"); break; case INQ_ENCL: fprintf(f, "Enclosure services"); break; case INQ_SDAD: fprintf(f, "Simple direct access"); break; case INQ_OCRW: fprintf(f, "Optical card r/w"); break; case INQ_BRIDGE: fprintf(f, "Bridging expander"); break; case INQ_OSD: fprintf(f, "Object based storage"); break; case INQ_ADC: fprintf(f, "Automation/Drive Interface"); break; case INQ_WELLKNOWN: fprintf(f, "Well known lun"); break; case INQ_NODEV: if (ip->data_format >= 2) { fprintf(f, "unknown/no device"); break; } else if (ip->qualifier == INQ_DEV_NOTSUP) { fprintf(f, "unit not present"); break; } default: fprintf(f, "unknown device type 0x%x", (int)ip->type); } fprintf(f, "\n"); } /* * Print the device type from the SCSI inquiry buffer to stdout. */ void usal_printdev(struct scsi_inquiry *ip) { usal_fprintdev(stdout, ip); } /* * print into the SCSI error buffer, adjust the next write pointer. */ /* VARARGS2 */ int usal_printf(SCSI *usalp, const char *form, ...) { int cnt; va_list args; va_start(args, form); cnt = vsnprintf(usalp->errptr, usal_errrsize(usalp), form, args); va_end(args); if (cnt < 0) { usalp->errptr[0] = '\0'; } else { usalp->errptr += cnt; } return (cnt); } /* * Flush the SCSI error buffer to SCSI errfile. * Clear error buffer after flushing. */ int usal_errflush(SCSI *usalp) { if (usalp->errfile == NULL) return (0); return (usal_errfflush(usalp, (FILE *)usalp->errfile)); } /* * Flush the SCSI error buffer to a file. * Clear error buffer after flushing. */ int usal_errfflush(SCSI *usalp, FILE *f) { int cnt; cnt = usalp->errptr - usalp->errbeg; if (cnt > 0) { filewrite(f, usalp->errbeg, cnt); fflush(f); usalp->errbeg = usalp->errptr; } return (cnt); }