2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)scsi-aix.c 1.36 04/01/14 Copyright 1997 J. Schilling */
15 * Interface for the AIX generic SCSI implementation.
17 * This is a hack, that tries to emulate the functionality
20 * Warning: you may change this source, but if you do that
21 * you need to change the _usal_version and _usal_auth* string below.
22 * You may not return "schily" for an SCG_AUTHOR request anymore.
23 * Choose your name instead of "schily" and make clear that the version
24 * string is related to a modified source.
26 * Copyright (c) 1997 J. Schilling
29 * This program is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License version 2
31 * as published by the Free Software Foundation.
33 * This program is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36 * GNU General Public License for more details.
38 * You should have received a copy of the GNU General Public License along with
39 * this program; see the file COPYING. If not, write to the Free Software
40 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
43 #include <sys/scdisk.h>
46 * Warning: you may change this source, but if you do that
47 * you need to change the _usal_version and _usal_auth* string below.
48 * You may not return "schily" for an SCG_AUTHOR request anymore.
49 * Choose your name instead of "schily" and make clear that the version
50 * string is related to a modified source.
52 static char _usal_trans_version[] = "scsi-aix.c-1.36"; /* The version for this transport*/
55 #define MAX_SCG 16 /* Max # of SCSI controllers */
60 short usalfiles[MAX_SCG][MAX_TGT][MAX_LUN];
62 #define usallocal(p) ((struct usal_local*)((p)->local))
64 #define MAX_DMA_AIX (64*1024)
66 static int do_usal_cmd(SCSI *usalp, struct usal_cmd *sp);
67 static int do_usal_sense(SCSI *usalp, struct usal_cmd *sp);
70 * Return version information for the low level SCSI transport code.
71 * This has been introduced to make it easier to trace down problems
75 usalo_version(SCSI *usalp, int what)
77 if (usalp != (SCSI *)0) {
81 return (_usal_trans_version);
83 * If you changed this source, you are not allowed to
84 * return "schily" for the SCG_AUTHOR request.
87 return (_usal_auth_cdrkit);
96 usalo_help(SCSI *usalp, FILE *f)
98 __usal_help(f, "DKIOCMD", "SCSI transport for targets known by AIX drivers",
99 "", "bus,target,lun or UNIX device", "1,2,0 or /dev/rcd0@", FALSE, TRUE);
104 usalo_open(SCSI *usalp, char *device)
106 int busno = usal_scsibus(usalp);
107 int tgt = usal_target(usalp);
108 int tlun = usal_lun(usalp);
113 register int nopen = 0;
116 if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
119 snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
120 "Illegal value for busno, target or lun '%d,%d,%d'",
125 if (usalp->local == NULL) {
126 usalp->local = malloc(sizeof (struct usal_local));
127 if (usalp->local == NULL)
130 for (b = 0; b < MAX_SCG; b++) {
131 for (t = 0; t < MAX_TGT; t++) {
132 for (l = 0; l < MAX_LUN; l++)
133 usallocal(usalp)->usalfiles[b][t][l] = (short)-1;
138 if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2))
141 if (busno >= 0 && tgt >= 0 && tlun >= 0) {
143 snprintf(devname, sizeof (devname), "/dev/rcd%d", tgt);
144 f = openx(devname, 0, 0, SC_DIAGNOSTIC);
147 snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
148 "Cannot open '%s'. Specify device number (1 for cd1) as target (1,0)",
152 usallocal(usalp)->usalfiles[busno][tgt][tlun] = f;
156 snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
157 "Unable to scan on AIX");
161 if (device != NULL && *device != '\0' && busno >= 0 && tgt >= 0 && tlun >= 0) {
162 f = openx(device, 0, 0, SC_DIAGNOSTIC);
165 snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
171 usallocal(usalp)->usalfiles[busno][tgt][tlun] = f;
172 usal_settarget(usalp, busno, tgt, tlun);
180 usalo_close(SCSI *usalp)
187 if (usalp->local== NULL)
190 for (b = 0; b < MAX_SCG; b++) {
191 for (t = 0; t < MAX_TGT; t++) {
192 for (l = 0; l < MAX_LUN; l++) {
193 f = usallocal(usalp)->usalfiles[b][t][l];
196 usallocal(usalp)->usalfiles[b][t][l] = (short)-1;
204 usalo_maxdma(SCSI *usalp, long amt)
206 return (MAX_DMA_AIX);
209 #define palign(x, a) (((char *)(x)) + ((a) - 1 - (((UIntptr_t)((x)-1))%(a))))
212 usalo_getbuf(SCSI *usalp, long amt)
214 /* assume having a modern AIX here */
216 usalp->bufbase = (void *)valloc((size_t)amt);
217 return (usalp->bufbase);
220 int pagesize = getpagesize();
222 if (usalp->debug > 0) {
223 fprintf((FILE *)usalp->errfile,
224 "usalo_getbuf: %ld bytes\n", amt);
227 * Damn AIX is a paged system but has no valloc()
229 usalp->bufbase = ret = malloc((size_t)(amt+pagesize));
232 ret = palign(ret, pagesize);
238 usalo_freebuf(SCSI *usalp)
241 free(usalp->bufbase);
242 usalp->bufbase = NULL;
246 usalo_havebus(SCSI *usalp, int busno)
251 if (busno < 0 || busno >= MAX_SCG)
254 if (usalp->local == NULL)
257 for (t = 0; t < MAX_TGT; t++) {
258 for (l = 0; l < MAX_LUN; l++)
259 if (usallocal(usalp)->usalfiles[busno][t][l] >= 0)
266 usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun)
268 if (busno < 0 || busno >= MAX_SCG ||
269 tgt < 0 || tgt >= MAX_TGT ||
270 tlun < 0 || tlun >= MAX_LUN)
273 if (usalp->local == NULL)
276 return ((int)usallocal(usalp)->usalfiles[busno][tgt][tlun]);
280 usalo_initiator_id(SCSI *usalp)
286 usalo_isatapi(SCSI *usalp)
292 usalo_reset(SCSI *usalp, int what)
294 if (what == SCG_RESET_NOP)
296 if (what != SCG_RESET_BUS) {
301 * XXX Does this reset TGT or BUS ???
303 return (ioctl(usalp->fd, SCIORESET, IDLUN(usal_target(usalp), usal_lun(usalp))));
307 do_usal_cmd(SCSI *usalp, struct usal_cmd *sp)
312 if (sp->cdb_len > 12)
313 comerrno(EX_BAD, "Can't do %d byte command.\n", sp->cdb_len);
315 fillbytes(&req, sizeof (req), '\0');
317 req.flags = SC_ASYNC;
318 if (sp->flags & SCG_RECV_DATA) {
320 } else if (sp->size > 0) {
321 req.flags |= B_WRITE;
323 req.data_length = sp->size;
324 req.buffer = sp->addr;
325 req.timeout_value = sp->timeout;
326 req.command_length = sp->cdb_len;
328 movebytes(&sp->cdb, req.scsi_cdb, 12);
330 ret = ioctl(usalp->fd, DKIOCMD, &req);
332 if (usalp->debug > 0) {
333 fprintf((FILE *)usalp->errfile, "ret: %d errno: %d (%s)\n", ret, errno, errmsgstr(errno));
334 fprintf((FILE *)usalp->errfile, "data_length: %d\n", req.data_length);
335 fprintf((FILE *)usalp->errfile, "buffer: 0x%X\n", req.buffer);
336 fprintf((FILE *)usalp->errfile, "timeout_value: %d\n", req.timeout_value);
337 fprintf((FILE *)usalp->errfile, "status_validity: %d\n", req.status_validity);
338 fprintf((FILE *)usalp->errfile, "scsi_bus_status: 0x%X\n", req.scsi_bus_status);
339 fprintf((FILE *)usalp->errfile, "adapter_status: 0x%X\n", req.adapter_status);
340 fprintf((FILE *)usalp->errfile, "adap_q_status: 0x%X\n", req.adap_q_status);
341 fprintf((FILE *)usalp->errfile, "q_tag_msg: 0x%X\n", req.q_tag_msg);
342 fprintf((FILE *)usalp->errfile, "flags: 0X%X\n", req.flags);
345 sp->ux_errno = geterrno();
347 * Check if SCSI command cound not be send at all.
349 if (sp->ux_errno == ENOTTY || sp->ux_errno == ENXIO ||
350 sp->ux_errno == EINVAL || sp->ux_errno == EACCES) {
358 sp->resid = 0; /* AIX is the same rubbish as Linux here */
360 fillbytes(&sp->scb, sizeof (sp->scb), '\0');
361 fillbytes(&sp->u_sense.cmd_sense, sizeof (sp->u_sense.cmd_sense), '\0');
363 if (req.status_validity == 0) {
364 sp->error = SCG_NO_ERROR;
367 if (req.status_validity & 1) {
368 sp->u_scb.cmd_scb[0] = req.scsi_bus_status;
369 sp->error = SCG_RETRYABLE;
371 if (req.status_validity & 2) {
372 if (req.adapter_status & SC_NO_DEVICE_RESPONSE) {
373 sp->error = SCG_FATAL;
375 } else if (req.adapter_status & SC_CMD_TIMEOUT) {
376 sp->error = SCG_TIMEOUT;
378 } else if (req.adapter_status != 0) {
379 sp->error = SCG_RETRYABLE;
387 do_usal_sense(SCSI *usalp, struct usal_cmd *sp)
390 struct usal_cmd s_cmd;
392 fillbytes((caddr_t)&s_cmd, sizeof (s_cmd), '\0');
393 s_cmd.addr = sp->u_sense.cmd_sense;
394 s_cmd.size = sp->sense_len;
395 s_cmd.flags = SCG_RECV_DATA|SCG_DISRE_ENA;
396 s_cmd.cdb_len = SC_G0_CDBLEN;
397 s_cmd.sense_len = CCS_SENSE_LEN;
398 s_cmd.cdb.g0_cdb.cmd = SC_REQUEST_SENSE;
399 s_cmd.cdb.g0_cdb.lun = sp->cdb.g0_cdb.lun;
400 s_cmd.cdb.g0_cdb.count = sp->sense_len;
401 ret = do_usal_cmd(usalp, &s_cmd);
405 if (s_cmd.u_scb.cmd_scb[0] & 02) {
406 /* XXX ??? Check condition on request Sense ??? */
408 sp->sense_count = sp->sense_len - s_cmd.resid;
413 usalo_send(SCSI *usalp)
415 struct usal_cmd *sp = usalp->scmd;
419 sp->error = SCG_FATAL;
422 ret = do_usal_cmd(usalp, sp);
425 if (sp->u_scb.cmd_scb[0] & 02)
426 ret = do_usal_sense(usalp, sp);