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

SCSI/ASPI

开发平台:

MultiPlatform

  1. /* @(#)scsi-vms.c 1.14 99/09/07 Copyright 1997 J. Schilling */
  2. #ifndef lint
  3. static char __sccsid[] =
  4. "@(#)scsi-vms.c 1.14 99/09/07 Copyright 1997 J. Schilling";
  5. #endif
  6. /*
  7.  * Interface for the VMS generic SCSI implementation.
  8.  *
  9.  * This is a hack, that tries to emulate the functionality
  10.  * of the scg driver.
  11.  *
  12.  * Copyright (c) 1997 J. Schilling
  13.  */
  14. /*
  15.  * This program is free software; you can redistribute it and/or modify
  16.  * it under the terms of the GNU General Public License as published by
  17.  * the Free Software Foundation; either version 2, or (at your option)
  18.  * any later version.
  19.  *
  20.  * This program is distributed in the hope that it will be useful,
  21.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23.  * GNU General Public License for more details.
  24.  *
  25.  * You should have received a copy of the GNU General Public License
  26.  * along with this program; see the file COPYING.  If not, write to
  27.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  28.  */
  29. #include <iodef.h>
  30. #include <ssdef.h>
  31. #include <descrip.h>
  32. #include <starlet.h>
  33. #include <string.h>
  34. #include <LIB$ROUTINES.H>
  35. #define MAX_SCG  16 /* Max # of SCSI controllers */
  36. #define MAX_TGT  16
  37. #define MAX_LUN  8
  38. #define MAX_DMA_VMS (96*512)/* Check if this is not too big */
  39. #define MAX_PHSTMO_VMS 300
  40. #define MAX_DSCTMO_VMS 65535 /* max value for OpenVMS/AXP 7.1 ehh*/
  41. LOCAL int do_scsi_cmd __PR((SCSI *scgp, int f, struct scg_cmd *sp));
  42. LOCAL int do_scsi_sense __PR((SCSI *scgp, int f, struct scg_cmd *sp));
  43. #define DEVICE_NAMELEN 7
  44. struct SCSI$DESC {
  45. Uint SCSI$L_OPCODE; /* SCSI Operation Code */
  46. Uint SCSI$L_FLAGS; /* SCSI Flags Bit Map */
  47. char *SCSI$A_CMD_ADDR; /* ->SCSI command buffer */
  48. Uint SCSI$L_CMD_LEN;  /* SCSI command length, bytes */
  49. char *SCSI$A_DATA_ADDR; /* ->SCSI data buffer */
  50. Uint SCSI$L_DATA_LEN; /* SCSI data length, bytes */
  51. Uint SCSI$L_PAD_LEN;  /* SCSI pad length, bytes */
  52. Uint SCSI$L_PH_CH_TMOUT; /* SCSI phase change timeout */
  53. Uint SCSI$L_DISCON_TMOUT; /* SCSI disconnect timeout */
  54. Uint SCSI$L_RES_1; /* Reserved */
  55. Uint SCSI$L_RES_2; /* Reserved */
  56. Uint SCSI$L_RES_3; /* Reserved */
  57. Uint SCSI$L_RES_4; /* Reserved */
  58. Uint SCSI$L_RES_5; /* Reserved */
  59. Uint SCSI$L_RES_6; /* Reserved */
  60. };
  61. #ifdef __ALPHA
  62. #pragma member_alignment save
  63. #pragma nomember_alignment
  64. #endif
  65. struct SCSI$IOSB {
  66. Ushort SCSI$W_VMS_STAT; /* VMS status code */
  67. Ulong SCSI$L_IOSB_TFR_CNT; /* Actual #bytes transferred */
  68. char SCSI$B_IOSB_FILL_1;
  69. Uchar SCSI$B_IOSB_STS; /* SCSI device status */
  70. };
  71. #ifdef __ALPHA
  72. #pragma member_alignment restore
  73. #endif
  74. #define SCSI$K_GOOD_STATUS 0
  75. #define SCSI$K_CHECK_CONDITION 0x2
  76. #define SCSI$K_CONDITION_MET 0x4
  77. #define SCSI$K_BUSY 0x8
  78. #define SCSI$K_INTERMEDIATE 0x10
  79. #define SCSI$K_INTERMEDIATE_C_MET 0x14
  80. #define SCSI$K_RESERVATION_CONFLICT 0x18
  81. #define SCSI$K_COMMAND_TERMINATED 0x22
  82. #define SCSI$K_QUEUE_FULL 0x28
  83. #define SCSI$K_WRITE 0X0 /* direction of transfer=write */
  84. #define SCSI$K_READ 0X1 /* direction of transfer=read */
  85. #define SCSI$K_FL_ENAB_DIS 0X2 /* enable disconnects */
  86. #define SCSI$K_FL_ENAB_SYNC 0X4 /* enable sync */
  87. #define GK_EFN 0 /* Event flag number */
  88. static char gk_device[8]; /* XXX JS hoffentlich gibt es keinen Ueberlauf */
  89. static Ushort gk_chan;
  90. static Ushort transfer_length;
  91. static int i;
  92. static int status;
  93. static $DESCRIPTOR(gk_device_desc, gk_device);
  94. static struct SCSI$IOSB gk_iosb ;
  95. static struct SCSI$DESC gk_desc;
  96. static FILE *fp;
  97. struct scg_local {
  98. Ushort gk_chan;
  99. };
  100. #define scglocal(p) ((struct scg_local *)((p)->local)) 
  101. EXPORT int
  102. scsi_open(scgp, device, busno, tgt, tlun)
  103. SCSI *scgp;
  104. char *device;
  105. int busno;
  106. int tgt;
  107. int tlun;
  108. {
  109. char devname[DEVICE_NAMELEN];
  110. char buschar;
  111. char buschar1;
  112. if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
  113. errno = EINVAL;
  114. if (scgp->errstr)
  115. js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
  116. "Illegal value for busno, target or lun '%d,%d,%d'",
  117. busno, tgt, tlun);
  118. return (-1);
  119. }
  120. if ((device != NULL && *device != '') || (busno == -2 && tgt == -2)) {
  121. errno = EINVAL;
  122. if (scgp->errstr)
  123. js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
  124. "Open by 'devname' not supported on this OS");
  125. return (-1);
  126. }
  127. if (scgp->local == NULL) {
  128. scgp->local = malloc(sizeof(struct scg_local));
  129. if (scgp->local == NULL)
  130. return (0);
  131. }
  132. switch (busno) {
  133. case 0: buschar = 'd';
  134. buschar1 = 'a';
  135. break;
  136. case 1: buschar = 'd';
  137. buschar1 = 'b';
  138. break;
  139. case 2: buschar = 'd';
  140. buschar1 = 'c';
  141. break;
  142. case 3: buschar = 'd';
  143. buschar1 = 'd';
  144. break;
  145. case 4: buschar = 'g';
  146. buschar1 = 'a';
  147. break;
  148. case 5: buschar = 'g';
  149. buschar1 = 'b';
  150. break;
  151. case 6: buschar = 'g';
  152. buschar1 = 'c';
  153. break;
  154. case 7: buschar = 'g';
  155. buschar1 = 'd';
  156. break;
  157. default :
  158. if (scgp->errstr)
  159. js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
  160. "Wrong scsibus-# (%d)", busno);
  161. return (-1);
  162. }
  163. /* XXX JS XXX devname length snprintf ??? */
  164. sprintf(devname, "%ck%c%d0%d:", buschar, buschar1, tgt, tlun);
  165. strcpy (gk_device, devname);
  166. status = sys$assign(&gk_device_desc, &gk_chan, 0, 0);
  167. if (!(status & 1)) {
  168. printf("Unable to access scsi-device "%s"n", &gk_device[0]);
  169. return (-1);
  170. }
  171. if (scgp->debug) {
  172. fp = fopen("cdrecord_io.log","w","rfm=stmlf","rat=cr");
  173. if (fp == NULL) {
  174. perror("Failing opening i/o-logfile");
  175. exit(SS$_NORMAL);
  176. }
  177. }
  178. return (status);
  179. }
  180. EXPORT int
  181. scsi_close(scgp)
  182. SCSI *scgp;
  183. {
  184. /*
  185.  * XXX close gk_chan ???
  186.  */
  187. return (0);
  188. }
  189. LOCAL long
  190. scsi_maxdma(scgp)
  191. SCSI *scgp;
  192. {
  193. return (MAX_DMA_VMS);
  194. }
  195. EXPORT
  196. BOOL scsi_havebus(scgp, busno)
  197. SCSI *scgp;
  198. int busno;
  199. {
  200. if (gk_chan <= 0)
  201. return (FALSE);
  202. return (TRUE);
  203. }
  204. EXPORT
  205. int scsi_fileno(scgp, busno, tgt, tlun)
  206. SCSI *scgp;
  207. int busno;
  208. int tgt;
  209. int tlun;
  210. {
  211. if (gk_chan <= 0)
  212. return (-1);
  213. return (gk_chan);
  214. }
  215. EXPORT int
  216. scsi_initiator_id(scgp)
  217. SCSI *scgp;
  218. {
  219. return (-1);
  220. }
  221. EXPORT
  222. int scsi_isatapi(scgp)
  223. SCSI *scgp;
  224. {
  225. return (FALSE);
  226. }
  227. EXPORT
  228. int scsireset(scgp)
  229. SCSI *scgp;
  230. {
  231. return (-1);
  232. }
  233. EXPORT void *
  234. scsi_getbuf(scgp, amt)
  235. SCSI *scgp;
  236. long amt;
  237. {
  238. if (amt <= 0 || amt > scsi_maxdma(scgp))
  239. return ((void *)0);
  240. if (scgp->debug)
  241. printf("scsi_getbuf: %ld bytesn", amt);
  242. scgp->bufbase = malloc((size_t)(amt)); /* XXX JS XXX valloc() ??? */
  243. return (scgp->bufbase);
  244. }
  245. EXPORT void
  246. scsi_freebuf(scgp)
  247. SCSI *scgp;
  248. {
  249. if (scgp->bufbase)
  250. free(scgp->bufbase);
  251. scgp->bufbase = NULL;
  252. }
  253. LOCAL int
  254. do_scsi_cmd(scgp, f, sp)
  255. SCSI *scgp;
  256. int f;
  257. struct scg_cmd *sp;
  258. {
  259. char *cmdadr;
  260. int notcmdretry;
  261. int len;
  262. int severity;
  263. /* XXX JS XXX This cannot be OK */
  264. notcmdretry = (sp->flags & SCG_CMD_RETRY)^SCG_CMD_RETRY;
  265. /* error corrected ehh */
  266. /* XXX JS Wenn das notcmdretry Flag bei VMS auch 0x08 ist und Du darauf hoffst,
  267.    XXX Dasz ich den Wert nie aendere, dann ist das richtig.
  268.    XXX Siehe unten: Das gleiche gilt fuer SCG_RECV_DATA und SCG_DISRE_ENA !!!
  269. */
  270. cmdadr = (char *)sp->cdb.cmd_cdb;
  271. /* XXX JS XXX This cannot be OK */
  272. gk_desc.SCSI$L_FLAGS = ((sp->flags & SCG_RECV_DATA) |
  273. (sp->flags & SCG_DISRE_ENA)|
  274. notcmdretry);
  275. /* XXX siehe oben, das ist ein bitweises oder!!! */
  276. gk_desc.SCSI$A_DATA_ADDR = sp->addr;
  277. gk_desc.SCSI$L_DATA_LEN = sp->size;
  278. gk_desc.SCSI$A_CMD_ADDR = cmdadr;
  279. gk_desc.SCSI$L_CMD_LEN = sp->cdb_len;
  280. gk_desc.SCSI$L_PH_CH_TMOUT = sp->timeout;
  281. gk_desc.SCSI$L_DISCON_TMOUT = sp->timeout;
  282.         if (gk_desc.SCSI$L_PH_CH_TMOUT > MAX_PHSTMO_VMS)
  283.             gk_desc.SCSI$L_PH_CH_TMOUT = MAX_PHSTMO_VMS;
  284.         if (gk_desc.SCSI$L_DISCON_TMOUT > MAX_DSCTMO_VMS)
  285.             gk_desc.SCSI$L_DISCON_TMOUT = MAX_DSCTMO_VMS;
  286. gk_desc.SCSI$L_OPCODE = 1; /* SCSI Operation Code */
  287. gk_desc.SCSI$L_PAD_LEN = 0; /* SCSI pad length, bytes */
  288. gk_desc.SCSI$L_RES_1 = 0; /* Reserved */
  289. gk_desc.SCSI$L_RES_2 = 0; /* Reserved */
  290. gk_desc.SCSI$L_RES_3 = 0; /* Reserved */
  291. gk_desc.SCSI$L_RES_4 = 0; /* Reserved */
  292. gk_desc.SCSI$L_RES_5 = 0; /* Reserved */
  293. gk_desc.SCSI$L_RES_6 = 0; /* Reserved */
  294. if (scgp->debug) {
  295. fprintf(fp, "***********************************************************n");
  296. fprintf(fp, "SCSI VMS-I/O parametersn");
  297. fprintf(fp, "OPCODE: %d", gk_desc.SCSI$L_OPCODE);
  298. fprintf(fp, " FLAGS: %dn", gk_desc.SCSI$L_FLAGS);
  299. fprintf(fp, "CMD:");
  300. for (i = 0; i < gk_desc.SCSI$L_CMD_LEN; i++) {
  301. fprintf(fp, "%x ", sp->cdb.cmd_cdb[i]);
  302. }
  303. fprintf(fp, "n");
  304. fprintf(fp, "DATA_LEN: %dn", gk_desc.SCSI$L_DATA_LEN);
  305. fprintf(fp, "PH_CH_TMOUT: %d", gk_desc.SCSI$L_PH_CH_TMOUT);
  306. fprintf(fp, " DISCON_TMOUT: %dn", gk_desc.SCSI$L_DISCON_TMOUT);
  307. }
  308. status = sys$qiow(GK_EFN, gk_chan, IO$_DIAGNOSE, &gk_iosb, 0, 0,
  309. &gk_desc, sizeof(gk_desc), 0, 0, 0, 0);
  310. if (scgp->debug) {
  311. fprintf(fp, "qiow-status: %in", status);
  312. fprintf(fp, "VMS status code %in",gk_iosb.SCSI$W_VMS_STAT);
  313. fprintf(fp, "Actual #bytes transferred %in",gk_iosb.SCSI$L_IOSB_TFR_CNT);
  314. fprintf(fp, "SCSI device status %in",gk_iosb.SCSI$B_IOSB_STS);
  315. if (gk_iosb.SCSI$L_IOSB_TFR_CNT != gk_desc.SCSI$L_DATA_LEN) {
  316. fprintf(fp,"#bytes transferred != DATA_LENn");
  317. }
  318. }
  319. if (!(status & 1)) { /* Fehlerindikation fuer sys$qiow() */
  320. sp->ux_errno = geterrno();
  321. /* schwerwiegender nicht SCSI bedingter Fehler => return(-1) */
  322. if (sp->ux_errno == ENOTTY || sp->ux_errno == ENXIO ||
  323.     sp->ux_errno == EINVAL || sp->ux_errno == EACCES) {
  324. return (-1);
  325. }
  326. } else {
  327. sp->ux_errno = 0;
  328. }
  329. sp->resid = gk_desc.SCSI$L_DATA_LEN - gk_iosb.SCSI$L_IOSB_TFR_CNT;
  330. if (gk_iosb.SCSI$W_VMS_STAT == SS$_NORMAL &&
  331.     gk_iosb.SCSI$B_IOSB_STS == 0) {
  332. sp->error = SCG_NO_ERROR;
  333. if (scgp->debug) {
  334. fprintf(fp,"gk_iosb.SCSI$B_IOSB_STS == 0n");
  335. fprintf(fp,"sp->error %in",sp->error);
  336. fprintf(fp,"sp->resid %in",sp->resid);
  337. }
  338. return(0);
  339. }
  340. severity = gk_iosb.SCSI$W_VMS_STAT & 0x7;
  341. if (severity == 4) {
  342. sp->error = SCG_FATAL;
  343. if (scgp->debug) {
  344. fprintf(fp,"gk_iosb.SCSI$B_IOSB_STS & 2n");
  345. fprintf(fp,"gk_iosb.SCSI$W_VMS_STAT & 0x7 == SS$_FATALn");
  346. fprintf(fp,"sp->error %in",sp->error);
  347. }
  348. return (0);
  349. }
  350. if (gk_iosb.SCSI$W_VMS_STAT == SS$_TIMEOUT) {
  351. sp->error = SCG_TIMEOUT;
  352. if (scgp->debug) {
  353. fprintf(fp,"gk_iosb.SCSI$B_IOSB_STS & 2n");
  354. fprintf(fp,"gk_iosb.SCSI$W_VMS_STAT == SS$_TIMEOUTn");
  355. fprintf(fp,"sp->error %in",sp->error);
  356. }
  357. return (0);
  358. }
  359. sp->error = SCG_RETRYABLE;
  360. sp->ux_errno = EIO;
  361. sp->u_scb.cmd_scb[0] = gk_iosb.SCSI$B_IOSB_STS;
  362. if (scgp->debug) {
  363. fprintf(fp,"gk_iosb.SCSI$B_IOSB_STS & 2n");
  364. fprintf(fp,"gk_iosb.SCSI$W_VMS_STAT != 0n");
  365. fprintf(fp,"sp->error %in",sp->error);
  366. }
  367. return(0);
  368. }
  369. LOCAL int
  370. do_scsi_sense(scgp, f, sp)
  371. SCSI *scgp;
  372. int f;
  373. struct scg_cmd *sp;
  374. {
  375. int ret;
  376. struct scg_cmd s_cmd;
  377. if (sp->sense_len > SCG_MAX_SENSE)
  378. sp->sense_len = SCG_MAX_SENSE;
  379. fillbytes((caddr_t)&s_cmd, sizeof(s_cmd), '');
  380. s_cmd.addr = (char *)sp->u_sense.cmd_sense;
  381. s_cmd.size = sp->sense_len;
  382. s_cmd.flags = SCG_RECV_DATA|SCG_DISRE_ENA;
  383. s_cmd.cdb_len = SC_G0_CDBLEN;
  384. s_cmd.sense_len = CCS_SENSE_LEN;
  385. s_cmd.target = scgp->target;
  386. s_cmd.cdb.g0_cdb.cmd = SC_REQUEST_SENSE;
  387. s_cmd.cdb.g0_cdb.lun = sp->cdb.g0_cdb.lun;
  388. s_cmd.cdb.g0_cdb.count = sp->sense_len;
  389. ret = do_scsi_cmd(scgp, f, &s_cmd);
  390. if (ret < 0)
  391. return (ret);
  392. if (s_cmd.u_scb.cmd_scb[0] & 02) {
  393. /* XXX ??? Check condition on request Sense ??? */
  394. }
  395. sp->sense_count = sp->sense_len - s_cmd.resid;
  396. return (ret);
  397. }
  398. LOCAL int
  399. scsi_send(scgp, f, sp)
  400. SCSI *scgp;
  401. int f;
  402. struct scg_cmd *sp;
  403. {
  404. int ret;
  405. if (f < 0) {
  406. sp->error = SCG_FATAL;
  407. return (0);
  408. }
  409. ret = do_scsi_cmd(scgp, f, sp);
  410. if (ret < 0)
  411. return (ret);
  412. if (sp->u_scb.cmd_scb[0] & 02)
  413. ret = do_scsi_sense(scgp, f, sp);
  414. return (ret);
  415. }