1 /*
2  *   libdi - scsipt SCSI Device Interface Library
3  *
4  *   Copyright (C) 1993-2004  Ti Kan
5  *   E-mail: xmcd@amb.org
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 2 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21 
22 /*
23  *   Silicon Graphics IRIX support
24  *
25  *   This software fragment contains code that interfaces the
26  *   application to the SGI IRIX operating system.  The names "SGI" and
27  *   "IRIX" are used here for identification purposes only.
28  *
29  *   IRIX mediad interaction added by Andrea Suatoni
30  *   E-mail: a.suatoni@telefonica.net
31  */
32 #ifndef lint
33 static char *_os_irix_c_ident_ = "@(#)os_irix.c	6.58 04/03/02";
34 #endif
35 
36 #include "common_d/appenv.h"
37 #include "common_d/util.h"
38 #include "libdi_d/libdi.h"
39 #include "libdi_d/scsipt.h"
40 
41 #if defined(sgi) && defined(DI_SCSIPT) && !defined(DEMO_ONLY)
42 
43 extern appdata_t	app_data;
44 extern FILE		*errfp;
45 extern di_client_t	*di_clinfo;
46 
47 
48 /*
49  * pthru_send
50  *	Send SCSI command to the device.
51  *
52  * Args:
53  *	devp - Device descriptor
54  *	role - Role id to send command for
55  *	cmdpt - Pointer to the SCSI command CDB
56  *	cmdlen - SCSI command size (6, 10 or 12 bytes)
57  *	datapt - Pointer to the data buffer
58  *	datalen - Data transfer size (bytes)
59  *	sensept - Pointer to the sense buffer
60  *	senselen - Size of the sense buffer
61  *	rw - Data transfer direction flag (OP_NODATA, OP_DATAIN or OP_DATAOUT)
62  *	tmout - Command timeout interval (seconds)
63  *	prnerr - Whether an error message should be displayed
64  *		 when a command fails
65  *
66  * Return:
67  *	TRUE - command completed successfully
68  *	FALSE - command failed
69  */
70 bool_t
pthru_send(di_dev_t * devp,int role,byte_t * cmdpt,size_t cmdlen,byte_t * datapt,size_t datalen,byte_t * sensept,size_t senselen,byte_t rw,int tmout,bool_t prnerr)71 pthru_send(
72 	di_dev_t	*devp,
73 	int		role,
74 	byte_t		*cmdpt,
75 	size_t		cmdlen,
76 	byte_t		*datapt,
77 	size_t		datalen,
78 	byte_t		*sensept,
79 	size_t		senselen,
80 	byte_t		rw,
81 	int		tmout,
82 	bool_t		prnerr
83 )
84 {
85 	struct dsreq		dsreq;
86 	char			*str,
87 				title[FILE_PATH_SZ + 20];
88 	req_sense_data_t	*rp,
89 				sense_data;
90 
91 	if (devp == NULL || devp->fd <= 0)
92 		return FALSE;
93 
94 	if (app_data.debug & DBG_DEVIO) {
95 		time_t	t = time(NULL);
96 
97 		(void) sprintf(title,
98 			       "%sSCSI CDB bytes (dev=%s rw=%d to=%d role=%d)",
99 			       asctime(localtime(&t)),
100 			       devp->path, rw, tmout, role);
101 		util_dbgdump(title, cmdpt, cmdlen);
102 	}
103 
104 	if (devp->role != role) {
105 		DBGPRN(DBG_DEVIO)(errfp,
106 				"%s: %s %s: %s\n%s=0x%x %s=%d\n",
107 				APPNAME, "SCSI command error on",
108 				devp->path, "I/O not enabled for role.",
109 				"Opcode", cmdpt[0],
110 				"Role", role);
111 		return FALSE;
112 	}
113 
114 	if (senselen == 0) {
115 		sensept = (byte_t *) &sense_data;
116 		senselen = sizeof(sense_data);
117 	}
118 	(void) memset(sensept, 0, senselen);
119 
120 	(void) memset(&dsreq, 0, sizeof(dsreq));
121 	(void) memset(&sense_data, 0, sizeof(sense_data));
122 
123 	/* Set up dsreq */
124 	dsreq.ds_cmdbuf = (caddr_t) cmdpt;
125 	dsreq.ds_cmdlen = cmdlen;
126 	if (datapt != NULL && datalen != 0) {
127 		if (datalen > IRIX_MAX_XFER) {
128 			DBGPRN(DBG_DEVIO)(errfp,
129 				"%s: SCSI command error on %s: "
130 				"I/O data size too large.\n",
131 				APPNAME, devp->path);
132 			return FALSE;
133 		}
134 
135 		switch (rw) {
136 		case OP_DATAIN:
137 			dsreq.ds_flags |= DSRQ_READ;
138 			break;
139 		case OP_DATAOUT:
140 			dsreq.ds_flags |= DSRQ_WRITE;
141 			break;
142 		case OP_NODATA:
143 		default:
144 			break;
145 		}
146 		dsreq.ds_databuf = (caddr_t) datapt;
147 		dsreq.ds_datalen = (ulong) datalen;
148 	}
149 	dsreq.ds_flags |= DSRQ_SENSE;
150 	dsreq.ds_sensebuf = (caddr_t) sensept;
151 	dsreq.ds_senselen = (uchar_t) senselen;
152 	dsreq.ds_time = (tmout ? tmout : DFLT_CMD_TIMEOUT) * 1000;
153 
154 	/* Send the command down via the "pass-through" interface */
155 	if (ioctl(devp->fd, DS_ENTER, &dsreq) < 0) {
156 		if (app_data.scsierr_msg && prnerr)
157 			perror("DS_ENTER ioctl failed");
158 		return FALSE;
159 	}
160 
161 	if (dsreq.ds_ret != 0) {
162 		if (app_data.scsierr_msg && prnerr) {
163 			(void) fprintf(errfp,
164 				    "%s: %s %s:\n%s=0x%x %s=0x%x %s=0x%x\n",
165 				    APPNAME,
166 				    "SCSI command error on", devp->path,
167 				    "Opcode", cmdpt[0],
168 				    "Ret", dsreq.ds_ret,
169 				    "Status", dsreq.ds_status);
170 
171 			rp = (req_sense_data_t *)(void *) sensept;
172 			str = scsipt_reqsense_keystr((int) rp->key);
173 
174 			(void) fprintf(errfp,
175 					"Sense data: Key=0x%x (%s) "
176 					"Code=0x%x Qual=0x%x\n",
177 					rp->key,
178 					str,
179 					rp->code,
180 					rp->qual);
181 		}
182 		return FALSE;
183 	}
184 
185 	return TRUE;
186 }
187 
188 
189 /*
190  * pthru_open
191  *	Open SCSI pass-through device
192  *
193  * Args:
194  *	path - device path name string
195  *
196  * Return:
197  *	Device descriptor, or NULL on failure.
198  */
199 di_dev_t *
pthru_open(char * path)200 pthru_open(char *path)
201 {
202 	di_dev_t	*devp;
203 	struct stat	stbuf;
204 	char		errstr[ERR_BUF_SZ];
205 
206 	/* Check for validity of device node */
207 	if (stat(path, &stbuf) < 0) {
208 		(void) sprintf(errstr, app_data.str_staterr, path);
209 		DI_FATAL(errstr);
210 		return NULL;
211 	}
212 
213 	if (!S_ISCHR(stbuf.st_mode)) {
214 		(void) sprintf(errstr, app_data.str_noderr, path);
215 		DI_FATAL(errstr);
216 		return NULL;
217 	}
218 
219 	if ((devp = di_devalloc(path)) == NULL) {
220 		DI_FATAL(app_data.str_nomemory);
221 		return NULL;
222 	}
223 
224 	if ((devp->fd = open(path, O_RDONLY)) < 0) {
225 		DBGPRN(DBG_DEVIO)(errfp,
226 			"Cannot open %s: errno=%d\n", path, errno);
227 		return NULL;
228 	}
229 
230 	/* Try to get an exclusive access id from mediad for this device */
231 	devp->val = mediad_get_exclusiveuse(path, "xmcd");
232 #ifdef IRIX_NEW_MEDIAD
233 	if (mediad_last_error() != 0)
234 		devp->val = -1;
235 #endif
236 
237 	return (devp);
238 }
239 
240 
241 /*
242  * pthru_close
243  *	Close SCSI pass-through device
244  *
245  * Args:
246  *	devp - Device descriptor
247  *
248  * Return:
249  *	Nothing.
250  */
251 void
pthru_close(di_dev_t * devp)252 pthru_close(di_dev_t *devp)
253 {
254 	if (devp->fd > 0) {
255 		/* Release the exclusive use for this device */
256 		if (devp->val != -1)
257 			mediad_release_exclusiveuse(devp->val);
258 
259 		(void) close(devp->fd);
260 	}
261 	di_devfree(devp);
262 }
263 
264 
265 /*
266  * pthru_enable
267  *	Enable device in this process for I/O
268  *
269  * Args:
270  *	devp - Device descriptor
271  *	role - Role id for which I/O is to be enabled
272  *
273  * Return:
274  *	Nothing.
275  */
276 void
pthru_enable(di_dev_t * devp,int role)277 pthru_enable(di_dev_t *devp, int role)
278 {
279 	devp->role = role;
280 }
281 
282 
283 /*
284  * pthru_disable
285  *	Disable device in this process for I/O
286  *
287  * Args:
288  *	devp - Device descriptor
289  *	role - Role id for which I/O is to be disabled
290  *
291  * Return:
292  *	Nothing.
293  */
294 void
pthru_disable(di_dev_t * devp,int role)295 pthru_disable(di_dev_t *devp, int role)
296 {
297 	if (devp->role == role)
298 		devp->role = 0;
299 }
300 
301 
302 /*
303  * pthru_is_enabled
304  *	Check whether device is enabled for I/O in this process
305  *
306  * Args:
307  *	role - Role id for which to check
308  *
309  * Return:
310  *	TRUE  - enabled
311  *	FALSE - disabled
312  */
313 bool_t
pthru_is_enabled(di_dev_t * devp,int role)314 pthru_is_enabled(di_dev_t *devp, int role)
315 {
316 	return ((bool_t) (devp->role == role));
317 }
318 
319 
320 /*
321  * pthru_maxfer
322  *	Return the maximum per-request data transfer length
323  *
324  * Args:
325  *	devp - Device descriptor
326  *
327  * Return:
328  *	The maximum data transfer length in bytes
329  */
330 /*ARGSUSED*/
331 size_t
pthru_maxfer(di_dev_t * devp)332 pthru_maxfer(di_dev_t *devp)
333 {
334 	return IRIX_MAX_XFER;
335 }
336 
337 
338 /*
339  * pthru_vers
340  *	Return OS Interface Module version string
341  *
342  * Args:
343  *	None.
344  *
345  * Return:
346  *	Module version text string.
347  */
348 char *
pthru_vers(void)349 pthru_vers(void)
350 {
351 	return ("OS module for SGI IRIX");
352 }
353 
354 #endif	/* sgi DI_SCSIPT DEMO_ONLY */
355 
356