scsi-unixware.c
上传用户:xiejiait
上传日期:2007-01-06
资源大小:881k
文件大小:15k
源码类别:

SCSI/ASPI

开发平台:

MultiPlatform

  1. /* @(#)scsi-unixware.c 1.12 00/01/26 Copyright 1998 J. Schilling, Santa Cruz Operation */
  2. #ifndef lint
  3. static char __sccsid[] =
  4. "@(#)scsi-unixware.c 1.12 00/01/26 Copyright 1998 J. Schilling, Santa Cruz Operation";
  5. #endif
  6. /*
  7.  * Interface for the SCO UnixWare SCSI implementation.
  8.  *
  9.  * Warning: you may change this source, but if you do that
  10.  * you need to change the _scg_version and _scg_auth* string below.
  11.  * You may not return "schily" for an SCG_AUTHOR request anymore.
  12.  * Choose your name instead of "schily" and make clear that the version
  13.  * string is related to a modified source.
  14.  *
  15.  * Copyright (c) 1998 J. Schilling, Santa Cruz Operation
  16.  */
  17. /*
  18.  * This program is free software; you can redistribute it and/or modify
  19.  * it under the terms of the GNU General Public License as published by
  20.  * the Free Software Foundation; either version 2, or (at your option)
  21.  * any later version.
  22.  *
  23.  * This program is distributed in the hope that it will be useful,
  24.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  25.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26.  * GNU General Public License for more details.
  27.  *
  28.  * You should have received a copy of the GNU General Public License
  29.  * along with this program; see the file COPYING.  If not, write to
  30.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  31.  */
  32. #undef sense
  33. #undef SC_PARITY
  34. #undef scb
  35. #include <sys/sysmacros.h>
  36. #include <sys/scsi.h>
  37. #include <sys/sdi_edt.h>
  38. #include <sys/sdi.h>
  39. /*
  40.  * Warning: you may change this source, but if you do that
  41.  * you need to change the _scg_version and _scg_auth* string below.
  42.  * You may not return "schily" for an SCG_AUTHOR request anymore.
  43.  * Choose your name instead of "schily" and make clear that the version
  44.  * string is related to a modified source.
  45.  */
  46. LOCAL char _scg_trans_version[] = "scsi-unixware.c-1.12"; /* The version for this transport*/
  47. /* Max. number of scg scsibusses.  The real limit would be           */
  48. /* MAX_HBA * MAX_BUS (which would be 32 * 8 on UnixWare 2.1/7.x),    */
  49. /* but given that we will hardly see such a beast, lets take 32      */
  50. #define MAX_SCG 32
  51. /* maximum defines for UnixWare 2.x/7.x from <sys/sdi_edt.h> */
  52. #define MAX_TGT MAX_EXTCS /* Max # of target id's      */
  53. #define MAX_LUN MAX_EXLUS /* Max # of lun's            */
  54. #define MAX_DMA (32*1024)
  55. #define MAXLINE 80
  56. #define MAXPATH 256
  57. #define DEV_DIR "/tmp"
  58. #define DEV_NAME "scg.s%1dt%1dl%1d"
  59. #define SCAN_HBA "%d:%d,%d,%d:%7s : %n"
  60. #define SCAN_DEV "%d,%d,%d:%7s : %n"
  61. #define PRIM_HBA "/dev/hba/hba1"
  62. #define SCSI_CFG "LC_ALL=C /etc/scsi/pdiconfig -l"
  63. typedef struct scg2sdi {
  64. int valid;
  65. int open;
  66. int atapi;
  67. int initiator;
  68. int hba;
  69. int bus;
  70. int tgt;
  71. int lun;
  72. int fd;
  73. dev_t node;
  74. dev_t major;
  75. dev_t minor;
  76. char type[20];
  77. char vend[40];
  78. char devn[32];
  79. } scg2sdi_t;
  80. LOCAL scg2sdi_t sdidevs [MAX_SCG][MAX_TGT][MAX_LUN];
  81. struct scg_local {
  82. short scgfiles[MAX_SCG][MAX_TGT][MAX_LUN];
  83. };
  84. #define scglocal(p) ((struct scg_local *)((p)->local)) 
  85. LOCAL int unixware_init __PR((SCSI *scgp));
  86. LOCAL int do_scsi_cmd __PR((SCSI *scgp, int fd, struct scg_cmd *sp));
  87. LOCAL int do_scsi_sense __PR((SCSI *scgp, int fd, struct scg_cmd *sp));
  88. /* -------------------------------------------------------------------------
  89. ** SCO UnixWare 2.1.x / UnixWare 7 provides a scsi pass-through mechanism, 
  90. ** which can be used to access any configured scsi device. 
  91. **
  92. ** NOTE: The libscg UnixWare passthrough routines have changed with 
  93. **       cdrecord-1.8 to enable the -scanbus, -load, -eject option 
  94. **  regardless of the status of media and the addressing
  95. **       scheme is now the same as used on many other platforms like
  96. **       Solaris, Linux etc.
  97. **
  98. **      ===============================================================
  99. ** RUN 'cdrecord -scanbus' TO SEE THE DEVICE ADDRESSES YOU CAN USE
  100. ** ===============================================================
  101. */
  102. /*
  103.  * Return version information for the low level SCSI transport code.
  104.  * This has been introduced to make it easier to trace down problems
  105.  * in applications.
  106.  *
  107.  */
  108. EXPORT char *
  109. scg__version(scgp, what)
  110. SCSI *scgp;
  111. int what;
  112. {
  113. if (scgp != (SCSI *)0) {
  114. switch (what) {
  115. case SCG_VERSION:
  116. return (_scg_trans_version);
  117. /*
  118.  * If you changed this source, you are not allowed to
  119.  * return "schily" for the SCG_AUTHOR request.
  120.  */
  121. case SCG_AUTHOR:
  122. return (_scg_auth_schily);
  123. case SCG_SCCS_ID:
  124. return (__sccsid);
  125. }
  126. }
  127. return ((char *)0);
  128. }
  129. /* ---------------------------------------------------------------
  130. ** This routine is introduced to create all device nodes necessary
  131. ** to access any detected scsi device. It parses the output of
  132. ** /etc/scsi/pdiconfig -l and creates passthru device node for each
  133. ** found scsi device apart from the listed hba's.
  134. **
  135. */
  136. LOCAL int 
  137. unixware_init(scgp)
  138. SCSI *scgp;
  139. {
  140. FILE *cmd;
  141. int hba = 0, bus = 0, scg = 0, tgt = 0, lun = 0;
  142. int nscg = -1, lhba = -1, lbus = 0;
  143. int atapi, fd, nopen = 0, pos = 0, len = 0;
  144. int s, t, l;
  145. char lines[MAXLINE];
  146. char class[MAXLINE];
  147. char ident[MAXLINE];
  148. char dname[MAXPATH];
  149. struct stat  stbuf;
  150. dev_t ptdev, major, minor, node;
  151. char **evsave;
  152. extern char **environ;
  153. /* Check for validity of primary hostbus adapter node */
  154. if (stat(PRIM_HBA, &stbuf) < 0) {
  155. if (scgp->errstr)
  156. js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
  157. "Can not stat() primary hba (%s)",
  158. PRIM_HBA);
  159. return (-1);
  160. }
  161. if (!S_ISCHR(stbuf.st_mode)) {
  162. if (scgp->errstr)
  163. js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
  164. "Primary hba (%s) not a character device",
  165. PRIM_HBA);
  166. return (-1);
  167. }
  168. major = getmajor(stbuf.st_rdev);
  169. /* read pdiconfig output and get all attached scsi devices ! */
  170. evsave = environ;
  171. environ = 0;
  172. if ((cmd = popen(SCSI_CFG,"r")) == NULL) {
  173. if (scgp->errstr)
  174. js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
  175. "Error popen() for "%s"",
  176. SCSI_CFG);
  177. environ = evsave;
  178. return (-1);
  179. }
  180. environ = evsave;
  181. for (;;) {
  182. if (fgets(lines, MAXLINE, cmd) == NULL) 
  183. break;
  184. memset( class, '', sizeof(class));
  185. memset( ident, '', sizeof(ident));
  186. if (lines[0] == ' ' ) {
  187. sscanf(lines, SCAN_DEV, &bus, &tgt, &lun, class, &pos);
  188. hba = lhba;
  189. } else {
  190. sscanf(lines, SCAN_HBA, &hba, &bus, &tgt, &lun, class, &pos);
  191. nscg++;
  192. lhba = hba;
  193. atapi = 0;
  194. }
  195. /* We can't sscanf() the ident string of the device     */
  196. /* as it may contain characters sscanf() will           */
  197. /* recognize as a delimiter. So do a strcpy() instead ! */
  198. len = strlen(lines) - pos - 1; /* don't copy the 'n' */
  199. strncpy(ident, &lines[pos], len);
  200. if (scgp->debug) {
  201. printf("SDI -> %d:%d,%d,%d: %-7s : %sn", 
  202. hba, bus, tgt, lun, class, ident);
  203. }
  204. if ( bus != lbus ) { 
  205. nscg++;
  206. lbus = bus;
  207. }
  208. scg = nscg;
  209. /* check whether we have a HBA or a SCSI device, don't  */
  210. /* let HBA's be valid device for cdrecord, but mark     */
  211. /* them as a controller (initiator = 1).                */
  212. if ( strstr(class, "HBA") == NULL ){
  213. sdidevs[scg][tgt][lun].valid = 1;
  214. } else {
  215. sdidevs[scg][tgt][lun].initiator = 1;
  216. }
  217. /* There is no real flag that shows a HBA as an ATAPI   */
  218. /* controller, so as we know the driver is called 'ide' */
  219. /* we can check the ident string for the occurence of it*/
  220. if ( strstr(ident, "(ide,") != NULL ){
  221. atapi = 1;
  222. }
  223. /* fill the sdidevs array with all we know now          */
  224. sdidevs[scg][tgt][lun].open  = 0;
  225. sdidevs[scg][tgt][lun].atapi = atapi;
  226. sdidevs[scg][tgt][lun].hba = hba;
  227. sdidevs[scg][tgt][lun].bus = bus;
  228. sdidevs[scg][tgt][lun].tgt = tgt;
  229. sdidevs[scg][tgt][lun].lun = lun;
  230. strcpy(sdidevs[scg][tgt][lun].type, class);
  231. strcpy(sdidevs[scg][tgt][lun].vend, ident);
  232. sprintf(sdidevs[scg][tgt][lun].devn, DEV_NAME, scg, tgt, lun);
  233. minor = SDI_MINOR(hba, tgt, lun, bus);
  234. node  = makedevice(major, minor);
  235. sdidevs[scg][tgt][lun].major = major;
  236. sdidevs[scg][tgt][lun].minor = minor;
  237. sdidevs[scg][tgt][lun].node  = node;
  238. if (scgp->debug) {
  239. printf("h = %d; b = %d, s = %d, t = %d, l = %d, a = %d, ma = %d, mi = %2d, dev = %s, id = %sn", 
  240. hba, bus, scg, tgt, lun, 
  241. sdidevs[scg][tgt][lun].atapi, 
  242. sdidevs[scg][tgt][lun].major, 
  243. sdidevs[scg][tgt][lun].minor, 
  244. sdidevs[scg][tgt][lun].devn,
  245. sdidevs[scg][tgt][lun].vend );
  246. }
  247. }
  248. if (pclose(cmd) == -1) {
  249. if (scgp->errstr)
  250. js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
  251. "Error pclose() for "%s"",
  252. SCSI_CFG);
  253. return (-1);
  254. }
  255. /* create all temporary device nodes */
  256. for (s = 0; s < MAX_SCG; s++) {
  257. for (t = 0; t < MAX_TGT; t++) {
  258. for (l = 0; l < MAX_LUN ; l++) {
  259.   if ( sdidevs[s][t][l].valid == 0) {
  260.    sdidevs[s][t][l].fd = -1;
  261.    continue;
  262.   }
  263.   /* Make pass-through interface device node */
  264.   sprintf(dname, "%s/%s", DEV_DIR, sdidevs[s][t][l].devn);
  265.   ptdev = sdidevs[s][t][l].node;
  266.   if (mknod(dname, S_IFCHR | 0700, ptdev) < 0) {
  267. if (errno == EEXIST) {
  268. unlink(dname);
  269. if (mknod(dname, S_IFCHR | 0700, ptdev) < 0) {
  270. if (scgp->errstr)
  271. js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
  272. "mknod() error for "%s"", dname);
  273. return (-1);
  274. }
  275. } else {
  276. if (scgp->errstr)
  277. js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
  278. "mknod() error for "%s"", dname);
  279. return (-1);
  280. }
  281.   }
  282.   /* Open pass-through device node */
  283.   if ((fd = open(dname, O_RDONLY)) < 0) {
  284. if (scgp->errstr)
  285. js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
  286. "can not open pass-through %s", dname);
  287. return (-1);
  288.   }
  289.   sdidevs[s][t][l].fd   = fd;
  290.   sdidevs[s][t][l].open = 1;
  291.      nopen++;
  292.   scglocal(scgp)->scgfiles[s][t][l] = (short) fd;
  293.   if (scgp->debug) {
  294. printf("s = %d, t = %d, l = %d, dev = %s, fd = %dn", 
  295.           s, t, l, 
  296. sdidevs[s][t][l].devn,
  297. sdidevs[s][t][l].fd );
  298.   }
  299. }
  300. }
  301. }
  302. return (nopen);
  303. }
  304. EXPORT int
  305. scsi_open(scgp, device, busno, tgt, tlun)
  306. SCSI *scgp;
  307. char *device;
  308. int busno;
  309. int tgt;
  310. int tlun;
  311. {
  312. int c, b, t;
  313. if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
  314. errno = EINVAL;
  315. if (scgp->errstr)
  316. js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
  317. "Illegal value for busno, target or lun '%d,%d,%d'",
  318. busno, tgt, tlun);
  319. return (-1);
  320. }
  321. if (scgp->local == NULL) {
  322. scgp->local = malloc(sizeof(struct scg_local));
  323. if (scgp->local == NULL)
  324. return (0);
  325. for (c = 0; c < MAX_SCG; c++) {
  326. for (b = 0; b < MAX_TGT; b++) {
  327. for (t = 0; t < MAX_LUN ; t++)
  328. scglocal(scgp)->scgfiles[c][b][t] = (short)-1;
  329. }
  330. }
  331. }
  332. memset(sdidevs, 0, sizeof(sdidevs)); /* init tmp_structure */
  333. if (*device != '') { /* we don't allow old dev usage */
  334. errno = EINVAL;
  335. if (scgp->errstr)
  336. js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
  337. "Open by 'devname' no longer supported on this OS");
  338. return (-1);
  339. } else { /* this is the new stuff       */
  340. /* it will do the initialisation */
  341. /* and return the number of      */
  342. /* detected devices to be used   */
  343. /* with the new addressing       */
  344. /* scheme.                       */
  345. return (unixware_init(scgp));
  346. }
  347. }
  348. EXPORT int
  349. scsi_close(scgp)
  350. SCSI *scgp;
  351. {
  352. register int f;
  353. register int b;
  354. register int t;
  355. register int l;
  356. if (scgp->local == NULL)
  357. return (-1);
  358. for (b=0; b < MAX_SCG; b++) {
  359. for (t=0; t < MAX_TGT; t++) {
  360. for (l=0; l < MAX_LUN ; l++) {
  361. f = scglocal(scgp)->scgfiles[b][t][l];
  362. if (f >= 0)
  363. close(f);
  364. sdidevs[b][t][l].fd    = -1;
  365. sdidevs[b][t][l].open  =  0;
  366. sdidevs[b][t][l].valid =  0;
  367. scglocal(scgp)->scgfiles[b][t][l] = (short)-1;
  368. }
  369. }
  370. }
  371. return (0);
  372. }
  373. LOCAL long
  374. scsi_maxdma(scgp)
  375. SCSI *scgp;
  376. {
  377. return (MAX_DMA);
  378. }
  379. EXPORT void *
  380. scsi_getbuf(scgp, amt)
  381. SCSI *scgp;
  382. long amt;
  383. {
  384. if (amt <= 0 || amt > scsi_maxdma(scgp))
  385. return ((void *)0);
  386. if (scgp->debug)
  387. printf("scsi_getbuf: %ld bytesn", amt);
  388. scgp->bufbase = (void *) valloc((size_t)(amt));
  389. return (scgp->bufbase);
  390. }
  391. EXPORT void
  392. scsi_freebuf(scgp)
  393. SCSI *scgp;
  394. {
  395. if (scgp->bufbase)
  396. free(scgp->bufbase);
  397. scgp->bufbase = NULL;
  398. }
  399. EXPORT
  400. BOOL scsi_havebus(scgp, busno)
  401. SCSI *scgp;
  402. int busno;
  403. {
  404. register int t;
  405. register int l;
  406. if (busno < 0 || busno >= MAX_SCG)
  407. return (FALSE);
  408. if (scgp->local == NULL)
  409. return (FALSE);
  410. for (t=0; t < MAX_TGT; t++) {
  411. for (l=0; l < MAX_LUN ; l++)
  412. if (scglocal(scgp)->scgfiles[busno][t][l] >= 0)
  413. return (TRUE);
  414. }
  415. return (FALSE);
  416. }
  417. EXPORT
  418. int scsi_fileno(scgp, busno, tgt, tlun)
  419. SCSI *scgp;
  420. int busno;
  421. int tgt;
  422. int tlun;
  423. {
  424. if (busno < 0 || busno >= MAX_SCG ||
  425.     tgt   < 0 || tgt   >= MAX_TGT ||
  426.     tlun  < 0 || tlun  >= MAX_LUN)
  427. return (-1);
  428. if (scgp->local == NULL)
  429. return (-1);
  430. return ((int)scglocal(scgp)->scgfiles[busno][tgt][tlun]);
  431. }
  432. EXPORT int
  433. scsi_initiator_id(scgp)
  434. SCSI *scgp;
  435. {
  436. register int t;
  437. register int l;
  438. register int busno;
  439. busno = scgp->scsibus;
  440. if (busno < 0 || busno >= MAX_SCG)
  441. return (FALSE);
  442. for (t=0; t < MAX_TGT; t++) {
  443. for (l=0; l < MAX_LUN ; l++)
  444. if (sdidevs[busno][t][l].initiator == 1){
  445. if (scgp->debug)
  446. printf("scsi_initiator_id: id = %dn", t);
  447. return (t);
  448. }
  449. }
  450. return (-1);
  451. }
  452. EXPORT
  453. int scsi_isatapi(scgp)
  454. SCSI *scgp;
  455. {
  456. /* if the new address method is used we know if this is ATAPI*/
  457. return (sdidevs[scgp->scsibus][scgp->target][scgp->lun].atapi);
  458. }
  459. EXPORT
  460. int scsireset(scgp)
  461. SCSI *scgp;
  462. {
  463. return(-1);
  464. }
  465. LOCAL int
  466. do_scsi_cmd(scgp, fd, sp)
  467. SCSI *scgp;
  468. int fd;
  469. struct scg_cmd *sp;
  470. {
  471. int ret;
  472. int i;
  473. struct sb scsi_cmd;
  474. struct scb *scbp;
  475. memset(&scsi_cmd,  0, sizeof(scsi_cmd));
  476. scsi_cmd.sb_type = ISCB_TYPE;
  477. scbp = &scsi_cmd.SCB;
  478. scbp->sc_cmdpt = (caddr_t) sp->cdb.cmd_cdb;
  479. scbp->sc_cmdsz = sp->cdb_len;
  480. scbp->sc_datapt = sp->addr;
  481. scbp->sc_datasz = sp->size;
  482. if (!(sp->flags & SCG_RECV_DATA) && (sp->size > 0))
  483. scbp->sc_mode = SCB_WRITE;
  484. else
  485. scbp->sc_mode = SCB_READ;
  486. scbp->sc_time = sp->timeout;
  487. errno = 0;
  488. for (;;) {
  489. if ((ret = ioctl(fd, SDI_SEND, &scsi_cmd)) < 0) {
  490. if (errno == EAGAIN){
  491. sleep(1);
  492. continue;
  493. }
  494. sp->ux_errno = errno;
  495. if (errno == 0)
  496. sp->ux_errno = EIO;
  497. sp->error = SCG_RETRYABLE;
  498. return (ret);
  499. }
  500. break;
  501. }
  502. memset(&sp->u_scb.Scb, 0, sizeof(sp->u_scb.Scb));
  503. sp->u_scb.cmd_scb[0] = scbp->sc_status;
  504. sp->resid = scbp->sc_resid;
  505. sp->ux_errno = errno;
  506. return (0);
  507. }
  508. LOCAL int
  509. do_scsi_sense(scgp, fd, sp)
  510. SCSI *scgp;
  511. int fd;
  512. struct scg_cmd *sp;
  513. {
  514. int ret;
  515. struct scg_cmd s_cmd;
  516. if (sp->sense_len > SCG_MAX_SENSE)
  517. sp->sense_len = SCG_MAX_SENSE;
  518. memset((caddr_t)&s_cmd, 0, sizeof(s_cmd));
  519. s_cmd.addr      = (caddr_t) sp->u_sense.cmd_sense;
  520. s_cmd.size      = sp->sense_len;
  521. s_cmd.flags     = SCG_RECV_DATA|SCG_DISRE_ENA;
  522. s_cmd.cdb_len   = SC_G0_CDBLEN;
  523. s_cmd.sense_len = CCS_SENSE_LEN;
  524. s_cmd.target    = scgp->target;
  525. s_cmd.cdb.g0_cdb.cmd   = SC_REQUEST_SENSE;
  526. s_cmd.cdb.g0_cdb.lun   = sp->cdb.g0_cdb.lun;
  527. s_cmd.cdb.g0_cdb.count = sp->sense_len;
  528. ret = do_scsi_cmd(scgp, fd, &s_cmd);
  529. if (ret < 0)
  530. return (ret);
  531. sp->sense_count = sp->sense_len - s_cmd.resid;
  532. return (ret);
  533. }
  534. LOCAL int
  535. scsi_send(scgp, fd, sp)
  536. SCSI *scgp;
  537. int fd;
  538. struct scg_cmd *sp;
  539. {
  540. int ret;
  541. if ( fd < 0 ) {
  542. sp->error = SCG_FATAL;
  543. return (0);
  544. } else {
  545. ret = do_scsi_cmd(scgp, fd, sp);
  546. if (ret < 0)
  547. return (ret);
  548. if (sp->u_scb.cmd_scb[0] & S_CKCON)
  549. ret = do_scsi_sense(scgp, fd, sp);
  550. return (ret);
  551. }
  552. }
  553. #define sense u_sense.Sense
  554. #undef SC_PARITY
  555. #define SC_PARITY 0x09
  556. #define scb u_scb.Scb