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  *   HP-UX support
24  *
25  *   Author: Ti Kan
26  *   Contributing author (m68k portion): Avi Cohen Stuart
27  *   E-Mail: <avi@baan.nl>
28  *
29  *   This software fragment contains code that interfaces the
30  *   application to the HP-UX Release 9.x and 10.x operating system.
31  *   The name "HP" and "hpux" are used here for identification purposes
32  *   only.
33  */
34 #ifndef lint
35 static char *_os_hpux_c_ident_ = "@(#)os_hpux.c	6.63 04/03/02";
36 #endif
37 
38 #include "common_d/appenv.h"
39 #include "common_d/util.h"
40 #include "libdi_d/libdi.h"
41 #include "libdi_d/scsipt.h"
42 
43 #if defined(__hpux) && defined(DI_SCSIPT) && !defined(DEMO_ONLY)
44 
45 extern appdata_t	app_data;
46 extern FILE		*errfp;
47 extern di_client_t	*di_clinfo;
48 
49 #ifdef HPUX_EXCLUSIVE_OPEN
50 STATIC struct utsname	utsn;
51 #endif
52 
53 
54 /*
55  * pthru_send
56  *	Send SCSI command to the device.
57  *
58  * Args:
59  *	devp - Device descriptor
60  *	role - Role id to send command for
61  *	cmdpt - Pointer to the SCSI command CDB
62  *	cmdlen - SCSI command size (6, 10 or 12 bytes)
63  *	datapt - Pointer to the data buffer
64  *	datalen - Data transfer size (bytes)
65  *	sensept - Pointer to the sense buffer
66  *	senselen - Size of the sense buffer
67  *	rw - Data transfer direction flag (OP_NODATA, OP_DATAIN or OP_DATAOUT)
68  *	tmout - Command timeout interval (seconds)
69  *	prnerr - Whether an error message should be displayed
70  *		 when a command fails
71  *
72  * Return:
73  *	TRUE - command completed successfully
74  *	FALSE - command failed
75  */
76 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)77 pthru_send(
78 	di_dev_t	*devp,
79 	int		role,
80 	byte_t		*cmdpt,
81 	size_t		cmdlen,
82 	byte_t		*datapt,
83 	size_t		datalen,
84 	byte_t		*sensept,
85 	size_t		senselen,
86 	byte_t		rw,
87 	int		tmout,
88 	bool_t		prnerr
89 )
90 {
91 #ifdef __hp9000s300
92 	/* m68k systems */
93 	struct scsi_cmd_parms	scp;
94 	int			n,
95 				blen;
96 	byte_t			ch = 0;
97 	char			*str,
98 				title[FILE_PATH_SZ + 20];
99 	req_sense_data_t	*rp,
100 				sense_data;
101 
102 	if (devp == NULL || devp->fd <= 0)
103 		return FALSE;
104 
105 	if (app_data.debug & DBG_DEVIO) {
106 		time_t	t = time(NULL);
107 
108 		(void) sprintf(title,
109 			       "%sSCSI CDB bytes (dev=%s rw=%d to=%d role=%d)",
110 			       asctime(localtime(&t)),
111 			       devp->path, rw, tmout, role);
112 		util_dbgdump(title, cmdpt, cmdlen);
113 	}
114 
115 	if (devp->role != role) {
116 		DBGPRN(DBG_DEVIO)(errfp,
117 				"%s: %s %s: %s\n%s=0x%x %s=%d\n",
118 				APPNAME, "SCSI command error on",
119 				devp->path, "I/O not enabled for role.",
120 				"Opcode", cmdpt[0],
121 				"Role", role);
122 		return FALSE;
123 	}
124 
125 	if (senselen == 0) {
126 		sensept = (byte_t *) &sense_data;
127 		senselen = sizeof(sense_data);
128 	}
129 	(void) memset(sensept, 0, senselen);
130 
131 	if (datalen > HPUX_MAX_XFER) {
132 		DBGPRN(DBG_DEVIO)(errfp,
133 				"%s: SCSI command error on %s: "
134 				"I/O data size too large.\n",
135 				APPNAME, devp->path);
136 		return FALSE;
137 	}
138 
139 	(void) memset(&scp, 0, sizeof(scp));
140 
141 	(void) memcpy(scp.command, cmdpt, cmdlen);
142 	scp.cmd_type = cmdlen;
143 	if (rw == OP_DATAIN && datalen > 0)
144 		scp.cmd_mode = SCTL_READ;
145 	else
146 		scp.cmd_mode = 0;
147 	scp.clock_ticks = (tmout ? tmout : DFLT_CMD_TIMEOUT) * 50;
148 
149 	/* Set up for sending the SCSI command */
150 	if (ioctl(devp->fd, SIOC_SET_CMD, &scp) < 0) {
151 		if (app_data.scsierr_msg && prnerr) {
152 			(void) fprintf(errfp,
153 					"%s: %s %s:\n%s=0x%02x: "
154 					"%s (errno=%d)\n",
155 					APPNAME,
156 					"SCSI command error on", devp->path,
157 					"Opcode", cmdpt[0],
158 					"SIOC_SET_CMD failed", errno);
159 		}
160 
161 		/* Send Request Sense command */
162 		if (cmdpt[0] != OP_S_RSENSE &&
163 		    scsipt_request_sense(devp, role, sensept, senselen) &&
164 		    app_data.scsierr_msg && prnerr) {
165 			rp = (req_sense_data_t *)(void *) sensept;
166 			str = scsipt_reqsense_keystr((int) rp->key);
167 
168 			(void) fprintf(errfp,
169 				    "Sense data: Key=0x%x (%s) "
170 				    "Code=0x%x Qual=0x%x\n",
171 				    rp->key,
172 				    str,
173 				    rp->code,
174 				    rp->qual);
175 		}
176 		return FALSE;
177 	}
178 
179 	if (datalen == 0) {
180 		blen = 1;
181 		datapt = &ch;
182 	}
183 	else {
184 		blen = datalen;
185 	}
186 
187 	switch (rw) {
188 	case OP_NODATA:
189 	case OP_DATAIN:
190 		n = read(devp->fd, datapt, blen);
191 		if (n != blen && n != datalen) {
192 			if (app_data.scsierr_msg && prnerr) {
193 				perror("data read failed");
194 				return FALSE;
195 			}
196 		}
197 		break;
198 	case OP_DATAOUT:
199 		n = write(devp->fd, datapt, blen);
200 		if (n != blen && n != datalen) {
201 			if (app_data.scsierr_msg && prnerr) {
202 				perror("data write failed");
203 				return FALSE;
204 			}
205 		}
206 	default:
207 		break;
208 	}
209 
210 	return TRUE;
211 #else
212 	/* PA-RISC Systems */
213 	struct sctl_io		sctl;
214 	char			*str,
215 				title[FILE_PATH_SZ + 20];
216 
217 	if (devp == NULL || devp->fd < 0)
218 		return FALSE;
219 
220 	if (app_data.debug & DBG_DEVIO) {
221 		time_t	t = time(NULL);
222 
223 		(void) sprintf(title,
224 			       "%sSCSI CDB bytes (dev=%s rw=%d to=%d role=%d)",
225 			       asctime(localtime(&t)),
226 			       devp->path, rw, tmout, role);
227 		util_dbgdump(title, cmdpt, cmdlen);
228 	}
229 
230 	if (devp->role != role) {
231 		DBGPRN(DBG_DEVIO)(errfp,
232 				"%s: %s %s: %s\n%s=0x%x %s=%d\n",
233 				APPNAME, "SCSI command error on",
234 				devp->path, "I/O not enabled for role.",
235 				"Opcode", cmdpt[0],
236 				"Role", role);
237 		return FALSE;
238 	}
239 
240 	if (senselen > 0)
241 		(void) memset(sensept, 0, senselen);
242 
243 	if (datalen > HPUX_MAX_XFER) {
244 		DBGPRN(DBG_DEVIO)(errfp,
245 				"%s: SCSI command error on %s: "
246 				"I/O data size too large.\n",
247 				APPNAME, devp->path);
248 		return FALSE;
249 	}
250 
251 	(void) memset(&sctl, 0, sizeof(sctl));
252 
253 	/* set up sctl_io */
254 	(void) memcpy(sctl.cdb, cmdpt, cmdlen);
255 	sctl.cdb_length = cmdlen;
256 	sctl.data = datapt;
257 	sctl.data_length = (unsigned) datalen;
258 	if (rw == OP_DATAIN && datalen > 0)
259 		sctl.flags = SCTL_READ;
260 	else
261 		sctl.flags = 0;
262 	sctl.max_msecs = (tmout ? tmout : DFLT_CMD_TIMEOUT) * 1000;
263 
264 	/* Send the command down via the "pass-through" interface */
265 	if (ioctl(devp->fd, SIOC_IO, &sctl) < 0) {
266 		if (app_data.scsierr_msg && prnerr)
267 			perror("SIOC_IO ioctl failed");
268 		return FALSE;
269 	}
270 
271 	if (sctl.cdb_status != S_GOOD) {
272 		if (senselen > 0 &&
273 		    sctl.sense_status == S_GOOD && sctl.sense_xfer > 2) {
274 			if (senselen > sctl.sense_xfer)
275 				senselen = sctl.sense_xfer;
276 			(void) memcpy(sensept, &sctl.sense, senselen);
277 		}
278 
279 		if (app_data.scsierr_msg && prnerr) {
280 			(void) fprintf(errfp,
281 				    "%s: %s %s:\n%s=0x%x %s=0x%x %s=0x%x\n",
282 				    APPNAME,
283 				    "SCSI command error on", devp->path,
284 				    "Opcode", cmdpt[0],
285 				    "Cdb_status", sctl.cdb_status,
286 				    "Sense_status", sctl.sense_status);
287 
288 			if (sctl.sense_status == S_GOOD &&
289 			    sctl.sense_xfer > 2) {
290 				str = scsipt_reqsense_keystr(
291 					(int) sctl.sense[2] & 0x0f
292 				);
293 
294 				(void) fprintf(errfp,
295 					    "Sense data: Key=0x%x (%s) "
296 					    "Code=0x%x Qual=0x%x\n",
297 					    sctl.sense[2] & 0x0f,
298 					    str,
299 					    sctl.sense[12],
300 					    sctl.sense[13]);
301 			}
302 		}
303 
304 		return FALSE;
305 	}
306 
307 	return TRUE;
308 #endif	/* __hp9000s300 */
309 }
310 
311 
312 /*
313  * pthru_open
314  *	Open SCSI pass-through device
315  *
316  * Args:
317  *	path - device path name string
318  *
319  * Return:
320  *	Device descriptor, or NULL on failure.
321  */
322 di_dev_t *
pthru_open(char * path)323 pthru_open(char *path)
324 {
325 	di_dev_t	*devp;
326 	struct stat	stbuf;
327 	char		errstr[ERR_BUF_SZ];
328 
329 	/* Check for validity of device node */
330 	if (stat(path, &stbuf) < 0) {
331 		(void) sprintf(errstr, app_data.str_staterr, path);
332 		DI_FATAL(errstr);
333 		return NULL;
334 	}
335 	if (!S_ISCHR(stbuf.st_mode)) {
336 		(void) sprintf(errstr, app_data.str_noderr, path);
337 		DI_FATAL(errstr);
338 		return NULL;
339 	}
340 
341 	if ((devp = di_devalloc(path)) == NULL) {
342 		DI_FATAL(app_data.str_nomemory);
343 		return NULL;
344 	}
345 
346 #ifdef __hp9000s300
347 	/* m68k systems */
348 	if ((devp->fd = open(path, O_RDWR)) < 0) {
349 		DBGPRN(DBG_DEVIO)(errfp,
350 			"Cannot open %s: errno=%d\n", path, errno);
351 		di_devfree(devp);
352 		return NULL;
353 	}
354 
355 	/* Enable SCSI pass-through mode */
356 	{
357 		int	i = 1;
358 
359 		if (ioctl(devp->fd, SIOC_CMD_MODE, &i) < 0) {
360 			DBGPRN(DBG_DEVIO)(errfp,
361 				"Cannot set SIOC_CMD_MODE: errno=%d\n",
362 				errno);
363 			pthru_close(devp);
364 			return NULL;
365 		}
366 	}
367 #else
368 	/* PA-RISC systems */
369 	if ((devp->fd = open(path, O_RDONLY)) < 0) {
370 		DBGPRN(DBG_DEVIO)(errfp,
371 			"Cannot open %s: errno=%d\n", path, errno);
372 		di_devfree(devp);
373 		return NULL;
374 	}
375 
376 #ifdef HPUX_EXCLUSIVE_OPEN
377 	/* Find out the machine type */
378 	if (uname(&utsn) < 0) {
379 		DBGPRN(DBG_DEVIO)(errfp,
380 			"uname(2) failed (errno=%d): assume 9000/7xx\n",
381 			errno);
382 		/* Shrug: assume series 7xx */
383 		(void) strcpy(utsn.machine, "9000/7xx");
384 	}
385 
386 	/* Obtain exclusive open (on Series 700 systems only) */
387 	if (utsn.machine[5] == '7' && ioctl(devp->fd, SIOC_EXCLUSIVE, 1) < 0) {
388 		DBGPRN(DBG_DEVIO)(errfp,
389 			"Cannot set SIOC_EXCLUSIVE: errno=%d\n", errno);
390 		(void) pthru_close(devp);
391 		return NULL;
392 	}
393 #endif	/* HPUX_EXCLUSIVE_OPEN */
394 #endif	/* __hp9000s300 */
395 
396 	return (devp);
397 }
398 
399 
400 /*
401  * pthru_close
402  *	Close SCSI pass-through device
403  *
404  * Args:
405  *	devp - Device descriptor
406  *
407  * Return:
408  *	Nothing.
409  */
410 void
pthru_close(di_dev_t * devp)411 pthru_close(di_dev_t *devp)
412 {
413 	if (devp->fd > 0) {
414 #if !defined(__hp9000s300) && defined(HPUX_EXCLUSIVE_OPEN)
415 		/* Relinquish exclusive open (on Series 700 systems only) */
416 		if (utsn.machine[5] == '7')
417 			(void) ioctl(devp->fd, SIOC_EXCLUSIVE, 0);
418 #endif
419 		(void) close(devp->fd);
420 	}
421 	di_devfree(devp);
422 }
423 
424 
425 /*
426  * pthru_enable
427  *	Enable device in this process for I/O
428  *
429  * Args:
430  *	devp - Device descriptor
431  *	role - Role id for which I/O is to be enabled
432  *
433  * Return:
434  *	Nothing.
435  */
436 void
pthru_enable(di_dev_t * devp,int role)437 pthru_enable(di_dev_t *devp, int role)
438 {
439 	devp->role = role;
440 }
441 
442 
443 /*
444  * pthru_disable
445  *	Disable device in this process for I/O
446  *
447  * Args:
448  *	devp - Device descriptor
449  *	role - Role id for which I/O is to be disabled
450  *
451  * Return:
452  *	Nothing.
453  */
454 void
pthru_disable(di_dev_t * devp,int role)455 pthru_disable(di_dev_t *devp, int role)
456 {
457 	if (devp->role == role)
458 		devp->role = 0;
459 }
460 
461 
462 /*
463  * pthru_is_enabled
464  *	Check whether device is enabled for I/O in this process
465  *
466  * Args:
467  *	role - Role id for which to check
468  *
469  * Return:
470  *	TRUE  - enabled
471  *	FALSE - disabled
472  */
473 bool_t
pthru_is_enabled(di_dev_t * devp,int role)474 pthru_is_enabled(di_dev_t *devp, int role)
475 {
476 	return ((bool_t) (devp->role == role));
477 }
478 
479 
480 /*
481  * pthru_maxfer
482  *	Return the maximum per-request data transfer length
483  *
484  * Args:
485  *	devp - Device descriptor
486  *
487  * Return:
488  *	The maximum data transfer length in bytes
489  */
490 /*ARGSUSED*/
491 size_t
pthru_maxfer(di_dev_t * devp)492 pthru_maxfer(di_dev_t *devp)
493 {
494 	return HPUX_MAX_XFER;
495 }
496 
497 
498 /*
499  * pthru_vers
500  *	Return OS Interface Module version string
501  *
502  * Args:
503  *	None.
504  *
505  * Return:
506  *	Module version text string.
507  */
508 char *
pthru_vers(void)509 pthru_vers(void)
510 {
511 	return ("OS module for HP-UX");
512 }
513 
514 #endif	/* __hpux DI_SCSIPT DEMO_ONLY */
515 
516