scsitransp.c
上传用户:weiliju62
上传日期:2007-01-06
资源大小:619k
文件大小:16k
源码类别:

SCSI/ASPI

开发平台:

MultiPlatform

  1. /* @(#)scsitransp.c 1.44 99/09/07 Copyright 1988,1995 J. Schilling */
  2. #ifndef lint
  3. static char sccsid[] =
  4. "@(#)scsitransp.c 1.44 99/09/07 Copyright 1988,1995 J. Schilling";
  5. #endif
  6. /*
  7.  * SCSI user level command transport routines for
  8.  * the SCSI general driver 'scg'.
  9.  *
  10.  * Copyright (c) 1988,1995 J. Schilling
  11.  */
  12. /*
  13.  * This program is free software; you can redistribute it and/or modify
  14.  * it under the terms of the GNU General Public License as published by
  15.  * the Free Software Foundation; either version 2, or (at your option)
  16.  * any later version.
  17.  *
  18.  * This program is distributed in the hope that it will be useful,
  19.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21.  * GNU General Public License for more details.
  22.  *
  23.  * You should have received a copy of the GNU General Public License
  24.  * along with this program; see the file COPYING.  If not, write to
  25.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  26.  */
  27. #include <mconfig.h>
  28. #ifdef HAVE_SYS_PARAM_H
  29. #include <sys/param.h> /* XXX nonportable to use u_char */
  30. #endif
  31. #include <stdio.h>
  32. #include <standard.h>
  33. #include <stdxlib.h>
  34. #include <unixstd.h>
  35. #include <errno.h>
  36. #include <timedefs.h>
  37. #include <sys/ioctl.h>
  38. #include <fctldefs.h>
  39. #include <scg/scgio.h>
  40. #include <scg/scsireg.h>
  41. #include <scg/scsitransp.h>
  42. #ifdef sun
  43. # define HAVE_SCG /* Currently only on SunOS/Solaris */
  44. #endif
  45. #define DEFTIMEOUT 20 /* Default timeout for SCSI command transport */
  46. /*
  47.  * Need to move this into an scg driver ioctl.
  48.  */
  49. /*#define MAX_DMA_SUN4M (1024*1024)*/
  50. #define MAX_DMA_SUN4M (124*1024) /* Currently max working size */
  51. /*#define MAX_DMA_SUN4C (126*1024)*/
  52. #define MAX_DMA_SUN4C (124*1024) /* Currently max working size */
  53. #define MAX_DMA_SUN3 (63*1024)
  54. #define MAX_DMA_SUN386 (56*1024)
  55. #define MAX_DMA_OTHER (32*1024)
  56. #define ARCH_MASK 0xF0
  57. #define ARCH_SUN2 0x00
  58. #define ARCH_SUN3 0x10
  59. #define ARCH_SUN4 0x20
  60. #define ARCH_SUN386 0x30
  61. #define ARCH_SUN3X 0x40
  62. #define ARCH_SUN4C 0x50
  63. #define ARCH_SUN4E 0x60
  64. #define ARCH_SUN4M 0x70
  65. #define ARCH_SUNX 0x80
  66. EXPORT int scsi_open __PR((SCSI *scgp, char *device, int busno, int tgt, int tlun));
  67. EXPORT int scsi_close __PR((SCSI *scgp));
  68. LOCAL long scsi_maxdma __PR((SCSI *scgp));
  69. EXPORT BOOL scsi_havebus __PR((SCSI *scgp, int));
  70. EXPORT int scsi_fileno __PR((SCSI *scgp, int, int, int));
  71. EXPORT int scsi_initiator_id __PR((SCSI *scgp));
  72. EXPORT int scsi_isatapi __PR((SCSI *scgp));
  73. EXPORT int scsireset __PR((SCSI *scgp));
  74. EXPORT void *scsi_getbuf __PR((SCSI *scgp, long));
  75. EXPORT void scsi_freebuf __PR((SCSI *scgp));
  76. EXPORT long scsi_bufsize __PR((SCSI *scgp, long));
  77. EXPORT void scsi_setnonstderrs __PR((SCSI *scgp, const char **));
  78. LOCAL BOOL scsi_yes __PR((char *));
  79. #ifdef nonono
  80. LOCAL void scsi_sighandler __PR((int));
  81. #endif
  82. EXPORT int scsicmd __PR((SCSI *scgp));
  83. EXPORT int scsigetresid __PR((SCSI *scgp));
  84. LOCAL void scsitimes __PR((SCSI *scgp));
  85. LOCAL BOOL scsierr __PR((SCSI *scgp));
  86. LOCAL int scsicheckerr __PR((SCSI *scgp));
  87. EXPORT void scsiprinterr __PR((SCSI *scgp));
  88. EXPORT void scsiprintcdb __PR((SCSI *scgp));
  89. EXPORT void scsiprintwdata __PR((SCSI *scgp));
  90. EXPORT void scsiprintrdata __PR((SCSI *scgp));
  91. EXPORT void scsiprintresult __PR((SCSI *scgp));
  92. EXPORT void scsiprintstatus __PR((SCSI *scgp));
  93. EXPORT void scsiprbytes __PR((char *, unsigned char *, int));
  94. EXPORT void scsiprsense __PR((unsigned char *, int));
  95. EXPORT int scsi_sense_key __PR((SCSI *scgp));
  96. EXPORT int scsi_sense_code __PR((SCSI *scgp));
  97. EXPORT int scsi_sense_qual __PR((SCSI *scgp));
  98. EXPORT void scsiprintdev __PR((struct scsi_inquiry *));
  99. #ifdef HAVE_SCG
  100. # include <libport.h> /* Needed for gethostid() */
  101. #ifdef sun
  102. #ifdef HAVE_SUN_DKIO_H
  103. # include <sun/dkio.h>
  104. # define dk_cinfo dk_conf
  105. # define dki_slave dkc_slave
  106. # define DKIO_GETCINFO DKIOCGCONF
  107. #endif
  108. #ifdef HAVE_SYS_DKIO_H
  109. # include <sys/dkio.h>
  110. # define DKIO_GETCINFO DKIOCINFO
  111. #endif
  112. #define TARGET(slave) ((slave >> 3) & 07)
  113. #endif /* sun */
  114. /*
  115.  * We are using a "real" /dev/scg?
  116.  */
  117. # define scsi_send(scgp, f, cmdp) ioctl((f), SCGIO_CMD, (cmdp))
  118. # define MAX_SCG 16 /* Max # of SCSI controllers */
  119. struct scg_local {
  120. int scgfiles[MAX_SCG];
  121. };
  122. #define scglocal(p) ((struct scg_local *)((p)->local)) 
  123. #define scgfiles(p) ((int *)((p)->local)) 
  124. #else
  125. /*
  126.  * We are emulating the functionality of /dev/scg? with the local
  127.  * SCSI user land implementation.
  128.  */
  129. # include "scsihack.c"
  130. #endif /* HAVE_SCG */
  131. #ifdef HAVE_SCG
  132. EXPORT int
  133. scsi_open(scgp, device, busno, tgt, tlun)
  134. SCSI *scgp;
  135. char *device;
  136. int busno;
  137. int tgt;
  138. int tlun;
  139. {
  140. register int f;
  141. register int i;
  142. register int nopen = 0;
  143. char devname[32];
  144. if (busno >= MAX_SCG) {
  145. errno = EINVAL;
  146. if (scgp->errstr)
  147. js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
  148. "Illegal value for busno '%d'", busno);
  149. return (-1);
  150. }
  151. if ((device != NULL && *device != '') || (busno == -2 && tgt == -2)) {
  152. errno = EINVAL;
  153. if (scgp->errstr)
  154. js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
  155. "Open by 'devname' not supported on this OS");
  156. return (-1);
  157. }
  158. if (scgp->local == NULL) {
  159. scgp->local = malloc(sizeof(struct scg_local));
  160. if (scgp->local == NULL) {
  161. if (scgp->errstr)
  162. js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE, "No memory for scg_local");
  163. return (0);
  164. }
  165. for (i=0; i < MAX_SCG; i++) {
  166. scgfiles(scgp)[i] = -1;
  167. }
  168. }
  169. for (i=0; i < MAX_SCG; i++) {
  170. sprintf(devname, "/dev/scg%d", i);
  171. f = open(devname, 2);
  172. if (f < 0) {
  173. if (errno != ENOENT && errno != ENXIO) {
  174. if (scgp->errstr)
  175. js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
  176. "Cannot open '%s'", devname);
  177. return (-1);
  178. }
  179. } else {
  180. nopen++;
  181. }
  182. scgfiles(scgp)[i] = f;
  183. }
  184. return (nopen);
  185. }
  186. EXPORT int
  187. scsi_close(scgp)
  188. SCSI *scgp;
  189. {
  190. register int i;
  191. if (scgfiles(scgp) == NULL)
  192. return (-1);
  193. for (i=0; i < MAX_SCG; i++) {
  194. if (scgfiles(scgp)[i] >= 0)
  195. close(scgfiles(scgp)[i]);
  196. scgfiles(scgp)[i] = -1;
  197. }
  198. return (0);
  199. }
  200. LOCAL long
  201. scsi_maxdma(scgp)
  202. SCSI *scgp;
  203. {
  204. long maxdma = 0L;
  205. #ifdef sun
  206. #if defined(__i386_) || defined(i386)
  207. return (MAX_DMA_SUN386);
  208. #else
  209. int cpu_type = gethostid() >> 24;
  210. switch (cpu_type & ARCH_MASK) {
  211. case ARCH_SUN4C:
  212. case ARCH_SUN4E:
  213. maxdma = MAX_DMA_SUN4C;
  214. break;
  215. case ARCH_SUN4M:
  216. case ARCH_SUNX:
  217. maxdma = MAX_DMA_SUN4M;
  218. break;
  219. default:
  220. maxdma = MAX_DMA_SUN3;
  221. }
  222. #endif /* sun */
  223. #else
  224. maxdma = MAX_DMA_OTHER;
  225. #endif
  226. #ifndef __SVR4
  227. /*
  228.  * SunOS 4.x allows esp hardware on VME boards and thus
  229.  * limits DMA on esp to 64k-1
  230.  */
  231. if (maxdma > MAX_DMA_SUN3)
  232. maxdma = MAX_DMA_SUN3;
  233. #endif
  234. return (maxdma);
  235. }
  236. EXPORT
  237. BOOL scsi_havebus(scgp, busno)
  238. SCSI *scgp;
  239. int busno;
  240. {
  241. if (scgfiles(scgp) == NULL)
  242. return (FALSE);
  243. return (busno < 0 || busno >= MAX_SCG) ? FALSE : (scgfiles(scgp)[busno] >= 0);
  244. }
  245. EXPORT
  246. int scsi_fileno(scgp, busno, tgt, tlun)
  247. SCSI *scgp;
  248. int busno;
  249. int tgt;
  250. int tlun;
  251. {
  252. if (scgfiles(scgp) == NULL)
  253. return (-1);
  254. return (busno < 0 || busno >= MAX_SCG) ? -1 : scgfiles(scgp)[busno];
  255. }
  256. EXPORT int
  257. scsi_initiator_id(scgp)
  258. SCSI *scgp;
  259. {
  260. int f = scsi_fileno(scgp, scgp->scsibus, scgp->target, scgp->lun);
  261. int id = -1;
  262. #ifdef DKIO_GETCINFO
  263. struct dk_cinfo conf;
  264. if (ioctl(f, DKIO_GETCINFO, &conf) < 0)
  265. return (id);
  266. if (TARGET(conf.dki_slave) != -1)
  267. id = TARGET(conf.dki_slave);
  268. #endif
  269. return (id);
  270. }
  271. EXPORT
  272. int scsi_isatapi(scgp)
  273. SCSI *scgp;
  274. {
  275. return (FALSE);
  276. }
  277. EXPORT
  278. int scsireset(scgp)
  279. SCSI *scgp;
  280. {
  281. int f = scsi_fileno(scgp, scgp->scsibus, scgp->target, scgp->lun);
  282. return (ioctl(f, SCGIORESET, 0));
  283. }
  284. EXPORT void *
  285. scsi_getbuf(scgp, amt)
  286. SCSI *scgp;
  287. long amt;
  288. {
  289. if (amt <= 0 || amt > scsi_maxdma(scgp))
  290. return ((void *)0);
  291. scgp->bufbase = (void *)valloc((size_t)amt);
  292. return (scgp->bufbase);
  293. }
  294. EXPORT void
  295. scsi_freebuf(scgp)
  296. SCSI *scgp;
  297. {
  298. if (scgp->bufbase)
  299. free(scgp->bufbase);
  300. scgp->bufbase = NULL;
  301. }
  302. #endif /* HAVE_SCG */
  303. EXPORT long
  304. scsi_bufsize(scgp, amt)
  305. SCSI *scgp;
  306. long amt;
  307. {
  308. long maxdma;
  309. maxdma = scsi_maxdma(scgp);
  310. if (amt <= 0 || amt > maxdma)
  311. return (maxdma);
  312. return (amt);
  313. }
  314. EXPORT void
  315. scsi_setnonstderrs(scgp, vec)
  316. SCSI *scgp;
  317. const char **vec;
  318. {
  319. scgp->nonstderrs = vec;
  320. }
  321. LOCAL
  322. BOOL scsi_yes(msg)
  323. char *msg;
  324. {
  325. char okbuf[10];
  326. printf("%s", msg);
  327. flush();
  328. if (getline(okbuf, sizeof(okbuf)) == EOF)
  329. exit(EX_BAD);
  330. if(streql(okbuf, "y") || streql(okbuf, "yes") ||
  331.    streql(okbuf, "Y") || streql(okbuf, "YES"))
  332. return(TRUE);
  333. else
  334. return(FALSE);
  335. }
  336. #ifdef nonono
  337. LOCAL void
  338. scsi_sighandler(sig)
  339. int sig;
  340. {
  341. printf("n");
  342. if (scsi_running) {
  343. printf("Running command: %sn", scsi_command);
  344. printf("Resetting SCSI - Bus.n");
  345. if (scsireset(scgp) < 0)
  346. errmsg("Cannot reset SCSI - Bus.n");
  347. }
  348. if (scsi_yes("EXIT ? "))
  349. exit(sig);
  350. }
  351. #endif
  352. EXPORT
  353. int scsicmd(scgp)
  354. SCSI *scgp;
  355. {
  356.  int f;
  357.  int ret;
  358. register struct scg_cmd *scmd = scgp->scmd;
  359. f = scsi_fileno(scgp, scgp->scsibus, scgp->target, scgp->lun);
  360. scmd->kdebug = scgp->kdebug;
  361. if (scmd->timeout == 0 || scmd->timeout < scgp->deftimeout)
  362. scmd->timeout = scgp->deftimeout;
  363. if (scgp->disre_disable)
  364. scmd->flags &= ~SCG_DISRE_ENA;
  365. if (scgp->noparity)
  366. scmd->flags |= SCG_NOPARITY;
  367. scmd->u_sense.cmd_sense[0] = 0; /* Paranioa */
  368. if (scgp->verbose) {
  369. printf("nExecuting '%s' command on Bus %d Target %d, Lun %d timeout %dsn",
  370. scgp->cmdname, scgp->scsibus, scgp->target, scmd->cdb.g0_cdb.lun,
  371. scmd->timeout);
  372. scsiprintcdb(scgp);
  373. if (scgp->verbose > 1)
  374. scsiprintwdata(scgp);
  375. flush();
  376. }
  377. if (scgp->running) {
  378. if (scgp->curcmdname) {
  379. error("Currently running '%s' command.n",
  380. scgp->curcmdname);
  381. }
  382. raisecond("SCSI ALREADY RUNNING !!", 0L);
  383. }
  384. gettimeofday(scgp->cmdstart, (struct timezone *)0);
  385. scgp->curcmdname = scgp->cmdname;
  386. scgp->running = TRUE;
  387. ret = scsi_send(scgp, f, scmd);
  388. scgp->running = FALSE;
  389. scsitimes(scgp);
  390. if (ret < 0) {
  391. /*
  392.  * Old /dev/scg versions will not allow to access targets > 7.
  393.  * Include a workaround to make this non fatal.
  394.  */
  395. if (scgp->target < 8 || geterrno() != EINVAL)
  396. comerr("Cannot send SCSI cmd via ioctln");
  397. if (scmd->ux_errno == 0)
  398. scmd->ux_errno = geterrno();
  399. if (scmd->error == SCG_NO_ERROR)
  400. scmd->error = SCG_FATAL;
  401. if (scgp->debug) {
  402. errmsg("ret < 0 errno: %d ux_errno: %d error: %dn",
  403. geterrno(), scmd->ux_errno, scmd->error);
  404. }
  405. }
  406. ret = scsicheckerr(scgp);
  407. if (scgp->verbose || (ret && scgp->silent <= 0)) {
  408. scsiprintresult(scgp);
  409. }
  410. return (ret);
  411. }
  412. EXPORT
  413. int scsigetresid(scgp)
  414. SCSI *scgp;
  415. {
  416. return (scgp->scmd->resid);
  417. }
  418. LOCAL
  419. void scsitimes(scgp)
  420. SCSI *scgp;
  421. {
  422. struct timeval *stp = scgp->cmdstop;
  423. gettimeofday(stp, (struct timezone *)0);
  424. stp->tv_sec -= scgp->cmdstart->tv_sec;
  425. stp->tv_usec -= scgp->cmdstart->tv_usec;
  426. while (stp->tv_usec < 0) {
  427. stp->tv_sec -= 1;
  428. stp->tv_usec += 1000000;
  429. }
  430. }
  431. LOCAL BOOL
  432. scsierr(scgp)
  433. SCSI *scgp;
  434. {
  435. register struct scg_cmd *cp = scgp->scmd;
  436. if(cp->error != SCG_NO_ERROR ||
  437. cp->ux_errno != 0 ||
  438. *(u_char *)&cp->scb != 0 ||
  439. cp->u_sense.cmd_sense[0] != 0) /* Paranioa */
  440. return (TRUE);
  441. return (FALSE);
  442. }
  443. LOCAL int
  444. scsicheckerr(scgp)
  445. SCSI *scgp;
  446. {
  447. register int ret;
  448. ret = 0;
  449. if(scsierr(scgp)) {
  450. if (!scgp->silent || scgp->verbose)
  451. scsiprinterr(scgp);
  452. ret = -1;
  453. }
  454. if ((!scgp->silent || scgp->verbose) && scgp->scmd->resid) {
  455. printf("resid: %dn", scgp->scmd->resid);
  456. flush();
  457. }
  458. return (ret);
  459. }
  460. EXPORT void
  461. scsiprinterr(scgp)
  462. SCSI *scgp;
  463. {
  464. register struct scg_cmd *cp = scgp->scmd;
  465. register char *err;
  466. char errbuf[64];
  467. switch (cp->error) {
  468. case SCG_NO_ERROR : err = "no error"; break;
  469. case SCG_RETRYABLE: err = "retryable error"; break;
  470. case SCG_FATAL    : err = "fatal error"; break;
  471. /*
  472.  * We need to cast timeval->* to long because
  473.  * of the broken sys/time.h in Linux.
  474.  */
  475. case SCG_TIMEOUT  : sprintf(errbuf,
  476. "cmd timeout after %ld.%03ld (%d) s",
  477. (long)scgp->cmdstop->tv_sec,
  478. (long)scgp->cmdstop->tv_usec/1000,
  479. cp->timeout);
  480. err = errbuf;
  481. break;
  482. default: sprintf(errbuf, "error: %d", cp->error);
  483. err = errbuf;
  484. }
  485. errmsgno(cp->ux_errno, "%s: scsi sendcmd: %sn", scgp->cmdname, err);
  486. scsiprintcdb(scgp);
  487. if (cp->error <= SCG_RETRYABLE)
  488. scsiprintstatus(scgp);
  489. if (cp->scb.chk) {
  490. scsiprsense((u_char *)&cp->sense, cp->sense_count);
  491. scsierrmsg(scgp, &cp->sense, &cp->scb, -1, scgp->nonstderrs);
  492. }
  493. flush();
  494. }
  495. EXPORT void
  496. scsiprintcdb(scgp)
  497. SCSI *scgp;
  498. {
  499. scsiprbytes("CDB: ", scgp->scmd->cdb.cmd_cdb, scgp->scmd->cdb_len);
  500. }
  501. EXPORT void
  502. scsiprintwdata(scgp)
  503. SCSI *scgp;
  504. {
  505. register struct scg_cmd *scmd = scgp->scmd;
  506. if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) == 0) {
  507. printf("Sending %d (0x%X) bytes of data.n",
  508. scmd->size, scmd->size);
  509. scsiprbytes("Write Data: ",
  510. (Uchar *)scmd->addr,
  511. scmd->size > 100 ? 100 : scmd->size);
  512. }
  513. }
  514. EXPORT void
  515. scsiprintrdata(scgp)
  516. SCSI *scgp;
  517. {
  518. register struct scg_cmd *scmd = scgp->scmd;
  519. if (scmd->size > 0 && (scmd->flags & SCG_RECV_DATA) != 0) {
  520. printf("Got %d (0x%X), expecting %d (0x%X) bytes of data.n",
  521. scmd->size-scmd->resid, scmd->size-scmd->resid,
  522. scmd->size, scmd->size);
  523. scsiprbytes("Received Data: ",
  524. (Uchar *)scmd->addr,
  525. (scmd->size-scmd->resid) > 100 ?
  526. 100 : (scmd->size-scmd->resid));
  527. }
  528. }
  529. EXPORT void
  530. scsiprintresult(scgp)
  531. SCSI *scgp;
  532. {
  533. printf("cmd finished after %ld.%03lds timeout %dsn",
  534. (long)scgp->cmdstop->tv_sec,
  535. (long)scgp->cmdstop->tv_usec/1000,
  536. scgp->scmd->timeout);
  537. if (scgp->verbose > 1)
  538. scsiprintrdata(scgp);
  539. flush();
  540. }
  541. EXPORT
  542. void scsiprintstatus(scgp)
  543. SCSI *scgp;
  544. {
  545. register struct scg_cmd *cp = scgp->scmd;
  546. error("status: 0x%x ", *(u_char *)&cp->scb);
  547. #ifdef SCSI_EXTENDED_STATUS
  548. if (cp->scb.ext_st1)
  549. error("0x%x ", ((u_char *)&cp->scb)[1]);
  550. if (cp->scb.ext_st2)
  551. error("0x%x ", ((u_char *)&cp->scb)[2]);
  552. #endif
  553. error("(");
  554. switch (*(u_char *)&cp->scb & 036) {
  555. case 0  : error("GOOD STATUS"); break;
  556. case 02 : error("CHECK CONDITION"); break;
  557. case 04 : error("CONDITION MET/GOOD"); break;
  558. case 010: error("BUSY"); break;
  559. case 020: error("INTERMEDIATE GOOD STATUS"); break;
  560. case 024: error("INTERMEDIATE CONDITION MET/GOOD"); break;
  561. case 030: error("RESERVATION CONFLICT"); break;
  562. default : error("Reserved"); break;
  563. }
  564. #ifdef SCSI_EXTENDED_STATUS
  565. if (cp->scb.ext_st1 && cp->scb.ha_er)
  566. error(" host adapter detected error");
  567. #endif
  568. error(")n");
  569. }
  570. EXPORT void
  571. scsiprbytes(s, cp, n)
  572. char *s;
  573. register u_char *cp;
  574. register int n;
  575. {
  576. printf(s);
  577. while (--n >= 0)
  578. printf(" %02X", *cp++);
  579. printf("n");
  580. }
  581. EXPORT void
  582. scsiprsense(cp, n)
  583. u_char *cp;
  584. int n;
  585. {
  586. scsiprbytes("Sense Bytes:", cp, n);
  587. }
  588. EXPORT int
  589. scsi_sense_key(scgp)
  590. SCSI *scgp;
  591. {
  592. register struct scg_cmd *cp = scgp->scmd;
  593. int key = -1;
  594. if(!scsierr(scgp))
  595. return (0);
  596. if (cp->sense.code >= 0x70)
  597. key = ((struct scsi_ext_sense*)&(cp->sense))->key;
  598. return(key);
  599. }
  600. EXPORT int
  601. scsi_sense_code(scgp)
  602. SCSI *scgp;
  603. {
  604. register struct scg_cmd *cp = scgp->scmd;
  605. int code = -1;
  606. if(!scsierr(scgp))
  607. return (0);
  608. if (cp->sense.code >= 0x70)
  609. code = ((struct scsi_ext_sense*)&(cp->sense))->sense_code;
  610. else
  611. code = cp->sense.code;
  612. return(code);
  613. }
  614. EXPORT int
  615. scsi_sense_qual(scgp)
  616. SCSI *scgp;
  617. {
  618. register struct scg_cmd *cp = scgp->scmd;
  619. if(!scsierr(scgp))
  620. return (0);
  621. if (cp->sense.code >= 0x70)
  622. return (((struct scsi_ext_sense*)&(cp->sense))->qual_code);
  623. else
  624. return (0);
  625. }
  626. EXPORT
  627. void scsiprintdev(ip)
  628. struct scsi_inquiry *ip;
  629. {
  630. if (ip->removable)
  631. printf("Removable ");
  632. if (ip->data_format >= 2) {
  633. switch (ip->qualifier) {
  634. case INQ_DEV_PRESENT: break;
  635. case INQ_DEV_NOTPR:
  636. printf("not present "); break;
  637. case INQ_DEV_RES:
  638. printf("reserved "); break;
  639. case INQ_DEV_NOTSUP:
  640. if (ip->type == INQ_NODEV) {
  641. printf("unsupportedn"); return;
  642. }
  643. printf("unsupported "); break;
  644. default:
  645. printf("vendor specific %d ", ip->qualifier);
  646. }
  647. }
  648. switch (ip->type) {
  649. case INQ_DASD:
  650. printf("Disk"); break;
  651. case INQ_SEQD:
  652. printf("Tape"); break;
  653. case INQ_PRTD:
  654. printf("Printer"); break;
  655. case INQ_PROCD:
  656. printf("Processor"); break;
  657. case INQ_WORM:
  658. printf("WORM"); break;
  659. case INQ_ROMD:
  660. printf("CD-ROM"); break;
  661. case INQ_SCAN:
  662. printf("Scanner"); break;
  663. case INQ_OMEM:
  664. printf("Optical Storage"); break;
  665. case INQ_JUKE:
  666. printf("Juke Box"); break;
  667. case INQ_COMM:
  668. printf("Communication"); break;
  669. case INQ_IT8_1:
  670. printf("IT8 1"); break;
  671. case INQ_IT8_2:
  672. printf("IT8 2"); break;
  673. case INQ_STARR:
  674. printf("Storage array"); break;
  675. case INQ_ENCL:
  676. printf("Enclosure services"); break;
  677. case INQ_NODEV:
  678. if (ip->data_format >= 2) {
  679. printf("unknown/no device");
  680. break;
  681. } else if (ip->qualifier == INQ_DEV_NOTSUP) {
  682. printf("unit not present");
  683. break;
  684. }
  685. default:
  686. printf("unknown device type 0x%x", ip->type);
  687. }
  688. printf("n");
  689. }