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

SCSI/ASPI

开发平台:

MultiPlatform

  1. /* @(#)scsi-unixware.c 1.7 99/09/07 Copyright 1998 J. Schilling, Santa Cruz Operation */
  2. #ifndef lint
  3. static char __sccsid[] =
  4. "@(#)scsi-unixware.c 1.7 99/09/07 Copyright 1998 J. Schilling, Santa Cruz Operation";
  5. #endif
  6. /*
  7.  * Interface for the SCO UnixWare SCSI implementation.
  8.  *
  9.  * Copyright (c) 1998 J. Schilling, Santa Cruz Operation
  10.  */
  11. /*
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2, or (at your option)
  15.  * any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; see the file COPYING.  If not, write to
  24.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  */
  26. #undef sense
  27. #include <sys/scsi.h>
  28. #include <sys/sdi_edt.h>
  29. #include <sys/sdi.h>
  30. #define MAX_SCG 16 /* Max # of cdrom devices */
  31. #define MAX_TGT 16 /* Not really needed      */
  32. #define MAX_LUN 8 /* Not really needed      */
  33. #define MAX_DMA (32*1024)
  34. #define TMP_DIR "/tmp"
  35. struct scg_local {
  36. short scgfiles[MAX_SCG][MAX_TGT][MAX_LUN];
  37. };
  38. #define scglocal(p) ((struct scg_local *)((p)->local)) 
  39. /* -------------------------------------------------------------------------
  40. ** SCO UnixWare 2.1.x / UnixWare 7 provide a scsi pass-through mechanism, 
  41. ** which can be used to access any configured scsi device. 
  42. **
  43. ** Devices to use: /dev/rcdrom/cdrom1 ... /dev/rcdrom/cdromx
  44. **
  45. ** Using these device special nodes, does work on UnixWare 2 and UnixWare 7
  46. ** and helps us getting around a problem with a lacking parameter in 
  47. ** cdrecord - the controller numbe. 
  48. **
  49. ** We could use the controller number, scsibus, target and lun to 
  50. ** open a device special node like /dev/rcdrom/c0b0t5l0, but this would 
  51. ** need the controller number as an additional parameter in the device
  52. ** specification of cdrecord.
  53. **
  54. ** Therefore is more convinient and also consistent to the OpenServer port
  55. ** to use the scsibus number as the index into the numbers of configured
  56. ** cdrom devices, using device special nodes like /dev/rcdrom/cdrom1.
  57. **
  58. ** One difference in this methodology compared to OpenServer is that 
  59. ** UnixWare start with number 1 as the first cdrom device, as OpenServer
  60. ** starts with 0.
  61. **
  62. ** The choosen interfacing hides all info like scsibus, target id and 
  63. ** lun from the user, so we really don't need the information about this, 
  64. ** just the name of the special device node to open this device for sending
  65. ** all SDI_SEND's.
  66. **
  67. ** Therefore we can use the scsibus as the index into the special device
  68. ** nodes of all CD-ROM devices, as all CD-ROM devices have an additional
  69. ** "/dev/rcrom/cdromX" as their device node, with X being the number of 
  70. ** the CD-ROM device.
  71. **
  72. ** By default, if you installed from a CD-ROM device, you will have 
  73. ** a "/dev/rcdrom/cdrom1" device. If you installed the CD-Writer as an 
  74. ** additional device, you will need to use the appropiate number to access it.
  75. **
  76. ** For example: 
  77. ** 
  78. **   busno = 1  means
  79. **
  80. **   /dev/rcdrom/cdrom1 is opened for sending cmds via the SDI_SEND ioctl.
  81. **
  82. **
  83. ** The alternative method to specify the target device is to use the
  84. ** the full device name instead of the scsibus.
  85. **
  86. ** For example:
  87. **
  88. **  cdrecord dev=/dev/rcdrom/cdrom1:5,0 
  89. **
  90. **  will also open /dev/rcdrom/cdrom1 to access the CD-Writer.
  91. **
  92. **
  93. */
  94. EXPORT int
  95. scsi_open(scgp, device, busno, tgt, tlun)
  96. SCSI *scgp;
  97. char *device;
  98. int busno;
  99. int tgt;
  100. int tlun;
  101. {
  102. int c, b, t;
  103. char devname[256];
  104. char *cdr_dev;
  105. int fd;
  106. dev_t ptdev;
  107. struct stat stbuf;
  108. if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
  109. errno = EINVAL;
  110. if (scgp->errstr)
  111. js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
  112. "Illegal value for busno, target or lun '%d,%d,%d'",
  113. busno, tgt, tlun);
  114. return (-1);
  115. }
  116. if (scgp->local == NULL) {
  117. scgp->local = malloc(sizeof(struct scg_local));
  118. if (scgp->local == NULL)
  119. return (0);
  120. for (c = 0; c < MAX_SCG; c++) {
  121. for (b = 0; b < MAX_TGT; b++) {
  122. for (t = 0; t < MAX_LUN ; t++)
  123. scglocal(scgp)->scgfiles[c][b][t] = (short)-1;
  124. }
  125. }
  126. }
  127. if (*device != '') {
  128. cdr_dev = device;
  129. } else {
  130. sprintf(devname, "/dev/rcdrom/cdrom%d", busno);
  131. cdr_dev = devname;
  132. }
  133. if (busno < 0        || tgt <   0      || tlun < 0 || 
  134.     busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
  135.     printf("cdrecord: dev=%d,%d,%d invalidn", busno, tgt, tlun);
  136.     return -1;
  137. }
  138. /* Check for validity of device node */
  139. if (stat(cdr_dev, &stbuf) < 0) {
  140. return (-1);
  141. }
  142. if (!S_ISCHR(stbuf.st_mode)) {
  143. return (-1);
  144. }
  145. /* Open CD-Writer device */
  146. if ((fd = open(cdr_dev, O_RDONLY)) < 0) {
  147. printf("cdrecord: ");
  148. switch (errno) {
  149. case EIO: printf("Check media in %s !n", cdr_dev);
  150.   break;
  151. default : perror(cdr_dev);
  152. }
  153. return (-1);
  154. }
  155. /* Get pass-through interface device number */
  156. if (ioctl(fd, B_GETDEV, &ptdev) < 0) {
  157. printf("cdrecord: get pass-through device B_GETDEV ioctl failed: errno = %dn", errno);
  158. close(fd);
  159. return (-1);
  160. }
  161. close(fd);
  162. /* Make pass-through interface device node */
  163. sprintf(devname, "%s/cdrecord.%x", TMP_DIR, (int) ptdev);
  164. if (mknod(devname, S_IFCHR | 0700, ptdev) < 0) {
  165. if (errno == EEXIST) {
  166. unlink(devname);
  167. if (mknod(devname, S_IFCHR | 0700, ptdev) < 0) {
  168. printf("cdrecord: Cannot mknod %s: errno = %dn",
  169. devname, errno);
  170. return (-1);
  171. }
  172. }
  173. else {
  174. printf("cdrecord: Cannot mknod %s: errno = %dn",
  175. devname, errno);
  176. return (-1);
  177. }
  178. }
  179. /* Open pass-through device node */
  180. if ((fd = open(devname, O_RDONLY)) < 0) {
  181. printf("cdrecord: Cannot open pass-through %s: errno = %dn", devname, errno);
  182. return (-1);
  183. }
  184. scglocal(scgp)->scgfiles[busno][tgt][tlun] = fd;
  185. return (1);
  186. }
  187. EXPORT int
  188. scsi_close(scgp)
  189. SCSI *scgp;
  190. {
  191. register int f;
  192. register int b;
  193. register int t;
  194. register int l;
  195. if (scgp->local == NULL)
  196. return (-1);
  197. for (b=0; b < MAX_SCG; b++) {
  198. for (t=0; t < MAX_TGT; t++) {
  199. for (l=0; l < MAX_LUN ; l++)
  200. f = scglocal(scgp)->scgfiles[b][t][l];
  201. if (f >= 0)
  202. close(f);
  203. scglocal(scgp)->scgfiles[b][t][l] = (short)-1;
  204. }
  205. }
  206. return (0);
  207. }
  208. LOCAL long
  209. scsi_maxdma(scgp)
  210. SCSI *scgp;
  211. {
  212. return (MAX_DMA);
  213. }
  214. EXPORT void *
  215. scsi_getbuf(scgp, amt)
  216. SCSI *scgp;
  217. long amt;
  218. {
  219. if (amt <= 0 || amt > scsi_maxdma(scgp))
  220. return ((void *)0);
  221. if (scgp->debug)
  222. printf("scsi_getbuf: %ld bytesn", amt);
  223. scgp->bufbase = (void *) valloc((size_t)(amt));
  224. return (scgp->bufbase);
  225. }
  226. EXPORT void
  227. scsi_freebuf(scgp)
  228. SCSI *scgp;
  229. {
  230. if (scgp->bufbase)
  231. free(scgp->bufbase);
  232. scgp->bufbase = NULL;
  233. }
  234. EXPORT
  235. BOOL scsi_havebus(scgp, busno)
  236. SCSI *scgp;
  237. int busno;
  238. {
  239. register int t;
  240. register int l;
  241. if (busno < 0 || busno >= MAX_SCG)
  242. return (FALSE);
  243. if (scgp->local == NULL)
  244. return (FALSE);
  245. for (t=0; t < MAX_TGT; t++) {
  246. for (l=0; l < MAX_LUN ; l++)
  247. if (scglocal(scgp)->scgfiles[busno][t][l] >= 0)
  248. return (TRUE);
  249. }
  250. return (FALSE);
  251. }
  252. EXPORT
  253. int scsi_fileno(scgp, busno, tgt, tlun)
  254. SCSI *scgp;
  255. int busno;
  256. int tgt;
  257. int tlun;
  258. {
  259. if (busno < 0 || busno >= MAX_SCG ||
  260.     tgt   < 0 || tgt   >= MAX_TGT ||
  261.     tlun  < 0 || tlun  >= MAX_LUN)
  262. return (-1);
  263. if (scgp->local == NULL)
  264. return (-1);
  265. return ((int)scglocal(scgp)->scgfiles[busno][tgt][tlun]);
  266. }
  267. EXPORT int
  268. scsi_initiator_id(scgp)
  269. SCSI *scgp;
  270. {
  271. return (-1);
  272. }
  273. EXPORT
  274. int scsi_isatapi(scgp)
  275. SCSI *scgp;
  276. {
  277. /* We do not know if the device we opened is either ATAPI or SCSI */
  278. return (-1);
  279. }
  280. EXPORT
  281. int scsireset(scgp)
  282. SCSI *scgp;
  283. {
  284. return(-1);
  285. }
  286. LOCAL int
  287. do_scsi_cmd(scgp, fd, sp)
  288. SCSI *scgp;
  289. int fd;
  290. struct scg_cmd *sp;
  291. {
  292. int ret;
  293. int i;
  294. struct sb scsi_cmd;
  295. struct scb *scbp;
  296. memset(&scsi_cmd,  0, sizeof(scsi_cmd));
  297. scsi_cmd.sb_type = ISCB_TYPE;
  298. scbp = &scsi_cmd.SCB;
  299. scbp->sc_cmdpt = (caddr_t) sp->cdb.cmd_cdb;
  300. scbp->sc_cmdsz = sp->cdb_len;
  301. scbp->sc_datapt = sp->addr;
  302. scbp->sc_datasz = sp->size;
  303. if (!(sp->flags & SCG_RECV_DATA) && (sp->size > 0))
  304. scbp->sc_mode = SCB_WRITE;
  305. else
  306. scbp->sc_mode = SCB_READ;
  307. scbp->sc_time = sp->timeout;
  308. errno = 0;
  309. for (;;) {
  310. if ((ret = ioctl(fd, SDI_SEND, &scsi_cmd)) < 0) {
  311. if (errno == EAGAIN){
  312. sleep(1);
  313. continue;
  314. }
  315. sp->ux_errno = errno;
  316. if (errno == 0)
  317. sp->ux_errno = EIO;
  318. sp->error = SCG_RETRYABLE;
  319. return (ret);
  320. }
  321. break;
  322. }
  323. memset(&sp->u_scb.Scb, 0, sizeof(sp->u_scb.Scb));
  324. sp->u_scb.cmd_scb[0] = scbp->sc_status;
  325. sp->resid = scbp->sc_resid;
  326. sp->ux_errno = errno;
  327. return 0;
  328. }
  329. LOCAL int
  330. do_scsi_sense(scgp, fd, sp)
  331. SCSI *scgp;
  332. int fd;
  333. struct scg_cmd *sp;
  334. {
  335. int ret;
  336. struct scg_cmd s_cmd;
  337. if (sp->sense_len > SCG_MAX_SENSE)
  338. sp->sense_len = SCG_MAX_SENSE;
  339. memset((caddr_t)&s_cmd, 0, sizeof(s_cmd));
  340. s_cmd.addr      = (caddr_t) sp->u_sense.cmd_sense;
  341. s_cmd.size      = sp->sense_len;
  342. s_cmd.flags     = SCG_RECV_DATA|SCG_DISRE_ENA;
  343. s_cmd.cdb_len   = SC_G0_CDBLEN;
  344. s_cmd.sense_len = CCS_SENSE_LEN;
  345. s_cmd.target    = scgp->target;
  346. s_cmd.cdb.g0_cdb.cmd   = SC_REQUEST_SENSE;
  347. s_cmd.cdb.g0_cdb.lun   = sp->cdb.g0_cdb.lun;
  348. s_cmd.cdb.g0_cdb.count = sp->sense_len;
  349. ret = do_scsi_cmd(scgp, fd, &s_cmd);
  350. if (ret < 0)
  351. return (ret);
  352. sp->sense_count = sp->sense_len - s_cmd.resid;
  353. return (ret);
  354. }
  355. LOCAL int
  356. scsi_send(scgp, fd, sp)
  357. SCSI *scgp;
  358. int fd;
  359. struct scg_cmd *sp;
  360. {
  361. int ret;
  362. ret = do_scsi_cmd(scgp, fd, sp);
  363. if (ret < 0)
  364. return (ret);
  365. if (sp->u_scb.cmd_scb[0] & S_CKCON)
  366. ret = do_scsi_sense(scgp, fd, sp);
  367. return (ret);
  368. }
  369. #define sense u_sense.Sense