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