Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / libusal / scsi-sgi.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
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).
6  *
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.
10  *
11  */
12
13 /* @(#)scsi-sgi.c       1.36 04/01/15 Copyright 1997 J. Schilling */
14 /*
15  *      Interface for the SGI generic SCSI implementation.
16  *
17  *      First Hacky implementation
18  *      (needed libds, did not support bus scanning and had no error checking)
19  *      from "Frank van Beek" <frank@neogeo.nl>
20  *
21  *      Actual implementation supports all usal features.
22  *
23  *      Warning: you may change this source, but if you do that
24  *      you need to change the _usal_version and _usal_auth* string below.
25  *      You may not return "schily" for an SCG_AUTHOR request anymore.
26  *      Choose your name instead of "schily" and make clear that the version
27  *      string is related to a modified source.
28  *
29  *      Copyright (c) 1997 J. Schilling
30  */
31 /*
32  * This program is free software; you can redistribute it and/or modify
33  * it under the terms of the GNU General Public License version 2
34  * as published by the Free Software Foundation.
35  *
36  * This program is distributed in the hope that it will be useful,
37  * but WITHOUT ANY WARRANTY; without even the implied warranty of
38  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
39  * GNU General Public License for more details.
40  *
41  * You should have received a copy of the GNU General Public License along with
42  * this program; see the file COPYING.  If not, write to the Free Software
43  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
44  */
45
46 #include <dslib.h>
47
48 /*
49  *      Warning: you may change this source, but if you do that
50  *      you need to change the _usal_version and _usal_auth* string below.
51  *      You may not return "schily" for an SCG_AUTHOR request anymore.
52  *      Choose your name instead of "schily" and make clear that the version
53  *      string is related to a modified source.
54  */
55 static  char    _usal_trans_version[] = "scsi-sgi.c-1.36";      /* The version for this transport*/
56
57 #ifdef  USE_DSLIB
58
59 struct dsreq * dsp = 0;
60 #define MAX_SCG         1       /* Max # of SCSI controllers */
61
62 #else
63
64 #define MAX_SCG         16      /* Max # of SCSI controllers */
65 #define MAX_TGT         16
66 #define MAX_LUN         8
67
68 struct usal_local {
69         short   usalfiles[MAX_SCG][MAX_TGT][MAX_LUN];
70 };
71 #define usallocal(p)    ((struct usal_local *)((p)->local))
72
73 #endif
74
75 #define MAX_DMA_SGI     (256*1024)      /* Check if this is not too big */
76
77
78 #ifndef USE_DSLIB
79 static  int     usal_sendreq(SCSI *usalp, struct usal_cmd *sp, struct dsreq *dsp);
80 #endif
81
82
83 /*
84  * Return version information for the low level SCSI transport code.
85  * This has been introduced to make it easier to trace down problems
86  * in applications.
87  */
88 static char *
89 usalo_version(SCSI *usalp, int what)
90 {
91         if (usalp != (SCSI *)0) {
92                 switch (what) {
93
94                 case SCG_VERSION:
95                         return (_usal_trans_version);
96                 /*
97                  * If you changed this source, you are not allowed to
98                  * return "schily" for the SCG_AUTHOR request.
99                  */
100                 case SCG_AUTHOR:
101                         return (_usal_auth_cdrkit);
102                 case SCG_SCCS_ID:
103                         return (__sccsid);
104                 }
105         }
106         return ((char *)0);
107 }
108
109 static int
110 usalo_help(SCSI *usalp, FILE *f)
111 {
112         __usal_help(f, "DS", "Generic SCSI",
113                 "", "bus,target,lun", "1,2,0", TRUE, FALSE);
114         return (0);
115 }
116
117 static int
118 usalo_open(SCSI *usalp, char *device)
119 {
120                 int     busno   = usal_scsibus(usalp);
121                 int     tgt     = usal_target(usalp);
122                 int     tlun    = usal_lun(usalp);
123         register int    f;
124         register int    b;
125         register int    t;
126         register int    l;
127         register int    nopen = 0;
128         char            devname[64];
129
130         if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
131                 errno = EINVAL;
132                 if (usalp->errstr)
133                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
134                                 "Illegal value for busno, target or lun '%d,%d,%d'",
135                                 busno, tgt, tlun);
136                 return (-1);
137         }
138
139         if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2)) {
140                 errno = EINVAL;
141                 if (usalp->errstr)
142                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
143                                 "Open by 'devname' not supported on this OS");
144                 return (-1);
145         }
146
147         if (usalp->local == NULL) {
148                 usalp->local = malloc(sizeof (struct usal_local));
149                 if (usalp->local == NULL)
150                         return (0);
151
152                 for (b = 0; b < MAX_SCG; b++) {
153                         for (t = 0; t < MAX_TGT; t++) {
154                                 for (l = 0; l < MAX_LUN; l++)
155                                         usallocal(usalp)->usalfiles[b][t][l] = (short)-1;
156                         }
157                 }
158         }
159
160         if (busno >= 0 && tgt >= 0 && tlun >= 0) {
161
162                 snprintf(devname, sizeof (devname),
163                                 "/dev/scsi/sc%dd%dl%d", busno, tgt, tlun);
164 #ifdef  USE_DSLIB
165                 dsp = dsopen(devname, O_RDWR);
166                 if (dsp == 0)
167                         return (-1);
168 #else
169                 f = open(devname, O_RDWR);
170                 if (f < 0) {
171                         if (usalp->errstr)
172                                 snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
173                                         "Cannot open '%s'",
174                                         devname);
175                         return (-1);
176                 }
177                 usallocal(usalp)->usalfiles[busno][tgt][tlun] = f;
178 #endif
179                 return (1);
180         } else {
181 #ifdef  USE_DSLIB
182                 return (-1);
183 #else
184                 for (b = 0; b < MAX_SCG; b++) {
185                         for (t = 0; t < MAX_TGT; t++) {
186 /*                              for (l = 0; l < MAX_LUN; l++) {*/
187                                 for (l = 0; l < 1; l++) {
188                                         snprintf(devname, sizeof (devname),
189                                                         "/dev/scsi/sc%dd%dl%d", b, t, l);
190                                         f = open(devname, O_RDWR);
191                                         if (f >= 0) {
192                                                 usallocal(usalp)->usalfiles[b][t][l] = (short)f;
193                                                 nopen++;
194                                         }
195                                 }
196                         }
197                 }
198 #endif
199         }
200         return (nopen);
201 }
202
203 static int
204 usalo_close(SCSI *usalp)
205 {
206 #ifndef USE_DSLIB
207         register int    f;
208         register int    b;
209         register int    t;
210         register int    l;
211
212         if (usalp->local == NULL)
213                 return (-1);
214
215         for (b = 0; b < MAX_SCG; b++) {
216                 for (t = 0; t < MAX_TGT; t++) {
217                         for (l = 0; l < MAX_LUN; l++) {
218                                 f = usallocal(usalp)->usalfiles[b][t][l];
219                                 if (f >= 0)
220                                         close(f);
221                                 usallocal(usalp)->usalfiles[b][t][l] = (short)-1;
222                         }
223                 }
224         }
225 #else
226         dsclose(dsp);
227 #endif
228         return (0);
229 }
230
231 static long
232 usalo_maxdma(SCSI *usalp, long amt)
233 {
234         return (MAX_DMA_SGI);
235 }
236
237 static void *
238 usalo_getbuf(SCSI *usalp, long amt)
239 {
240         if (usalp->debug > 0) {
241                 fprintf((FILE *)usalp->errfile,
242                                 "usalo_getbuf: %ld bytes\n", amt);
243         }
244         usalp->bufbase = valloc((size_t)(amt));
245         return (usalp->bufbase);
246 }
247
248 static void
249 usalo_freebuf(SCSI *usalp)
250 {
251         if (usalp->bufbase)
252                 free(usalp->bufbase);
253         usalp->bufbase = NULL;
254 }
255
256 static BOOL
257 usalo_havebus(SCSI *usalp, int busno)
258 {
259         register int    t;
260         register int    l;
261
262         if (busno < 0 || busno >= MAX_SCG)
263                 return (FALSE);
264
265         if (usalp->local == NULL)
266                 return (FALSE);
267
268         for (t = 0; t < MAX_TGT; t++) {
269                 for (l = 0; l < MAX_LUN; l++)
270                         if (usallocal(usalp)->usalfiles[busno][t][l] >= 0)
271                                 return (TRUE);
272         }
273         return (FALSE);
274 }
275
276 static int
277 usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun)
278 {
279 #ifdef  USE_DSLIB
280         if (dsp == NULL)
281                 return (-1);
282         return (getfd(dsp));
283 #else
284         if (busno < 0 || busno >= MAX_SCG ||
285             tgt < 0 || tgt >= MAX_TGT ||
286             tlun < 0 || tlun >= MAX_LUN)
287                 return (-1);
288
289         if (usalp->local == NULL)
290                 return (-1);
291
292         return ((int)usallocal(usalp)->usalfiles[busno][tgt][tlun]);
293 #endif
294 }
295
296 static int
297 usalo_initiator_id(SCSI *usalp)
298 {
299         return (-1);
300 }
301
302 static int
303 usalo_isatapi(SCSI *usalp)
304 {
305         return (FALSE);
306 }
307
308 static int
309 usalo_reset(SCSI *usalp, int what)
310 {
311         /*
312          * Do we have a SCSI reset on SGI?
313          */
314 #ifdef  DS_RESET
315         if (what == SCG_RESET_NOP)
316                 return (0);
317         if (what != SCG_RESET_BUS) {
318                 errno = EINVAL;
319                 return (-1);
320         }
321         /*
322          * XXX Does this reset TGT or BUS ???
323          */
324         return (ioctl(usalp->fd, DS_RESET, 0));
325 #else
326         return (-1);
327 #endif
328 }
329
330 #ifndef USE_DSLIB
331 static int
332 usal_sendreq(SCSI *usalp, struct usal_cmd *sp, struct dsreq *dsp)
333 {
334         int     ret;
335         int     retries = 4;
336         Uchar   status;
337
338 /*      if ((sp->flags & SCG_CMD_RETRY) == 0)*/
339 /*              retries = 0;*/
340
341         while (--retries > 0) {
342                 ret = ioctl(usalp->fd, DS_ENTER, dsp);
343                 if (ret < 0)  {
344                         RET(dsp) = DSRT_DEVSCSI;
345                         return (-1);
346                 }
347                 /*
348                  * SGI implementattion botch!!!
349                  * If a target does not select the bus,
350                  * the return code is DSRT_TIMEOUT
351                  */
352                 if (RET(dsp) == DSRT_TIMEOUT) {
353                         struct timeval to;
354
355                         to.tv_sec = TIME(dsp)/1000;
356                         to.tv_usec = TIME(dsp)%1000;
357                         __usal_times(usalp);
358
359                         if (sp->cdb.g0_cdb.cmd == SC_TEST_UNIT_READY &&
360                             usalp->cmdstop->tv_sec < to.tv_sec ||
361                             (usalp->cmdstop->tv_sec == to.tv_sec &&
362                                 usalp->cmdstop->tv_usec < to.tv_usec)) {
363
364                                 RET(dsp) = DSRT_NOSEL;
365                                 return (-1);
366                         }
367                 }
368                 if (RET(dsp) == DSRT_NOSEL)
369                         continue;               /* retry noselect 3X */
370
371                 status = STATUS(dsp);
372                 switch (status) {
373
374                 case 0x08:              /*  BUSY */
375                 case 0x18:              /*  RESERV CONFLICT */
376                         if (retries > 0)
377                                 sleep(2);
378                         continue;
379                 case 0x00:              /*  GOOD */
380                 case 0x02:              /*  CHECK CONDITION */
381                 case 0x10:              /*  INTERM/GOOD */
382                 default:
383                         return (status);
384                 }
385         }
386         return (-1);    /* failed retry limit */
387 }
388 #endif
389
390 static int
391 usalo_send(SCSI *usalp)
392 {
393         struct usal_cmd *sp = usalp->scmd;
394         int     ret;
395         int     i;
396         int     amt = sp->cdb_len;
397         int flags;
398 #ifndef USE_DSLIB
399         struct dsreq    ds;
400         struct dsreq    *dsp = &ds;
401
402         dsp->ds_iovbuf = 0;
403         dsp->ds_iovlen = 0;
404 #endif
405
406         if (usalp->fd < 0) {
407                 sp->error = SCG_FATAL;
408                 return (0);
409         }
410
411         flags = DSRQ_SENSE;
412         if (sp->flags & SCG_RECV_DATA)
413                 flags |= DSRQ_READ;
414         else if (sp->size > 0)
415                 flags |= DSRQ_WRITE;
416
417         dsp->ds_flags   = flags;
418         dsp->ds_link    = 0;
419         dsp->ds_synch   = 0;
420         dsp->ds_ret     = 0;
421
422         DATABUF(dsp)    = sp->addr;
423         DATALEN(dsp)    = sp->size;
424         CMDBUF(dsp)     = (void *) &sp->cdb;
425         CMDLEN(dsp)     = sp->cdb_len;
426         SENSEBUF(dsp)   = (caddr_t)sp->u_sense.cmd_sense;
427         SENSELEN(dsp)   = sizeof (sp->u_sense.cmd_sense);
428         TIME(dsp)       = (sp->timeout * 1000) + 100;
429
430         errno           = 0;
431         sp->ux_errno    = 0;
432         sp->sense_count = 0;
433
434 #ifdef  USE_DSLIB
435         ret = doscsireq(usalp->fd, dsp);
436 #else
437         ret = usal_sendreq(usalp, sp, dsp);
438 #endif
439
440         if (RET(dsp) != DSRT_DEVSCSI)
441                 ret = 0;
442
443         if (RET(dsp)) {
444                 if (RET(dsp) == DSRT_SHORT) {
445                         sp->resid = DATALEN(dsp)- DATASENT(dsp);
446                 } else if (errno) {
447                         sp->ux_errno = errno;
448                 } else {
449                         sp->ux_errno = EIO;
450                 }
451
452                 sp->u_scb.cmd_scb[0] = STATUS(dsp);
453
454                 sp->sense_count = SENSESENT(dsp);
455                 if (sp->sense_count > SCG_MAX_SENSE)
456                         sp->sense_count = SCG_MAX_SENSE;
457
458         }
459         switch (RET(dsp)) {
460
461         default:
462                 sp->error = SCG_RETRYABLE;      break;
463
464         case 0:                 /* OK                                   */
465         case DSRT_SHORT:        /* not implemented                       */
466                 sp->error = SCG_NO_ERROR;       break;
467
468         case DSRT_UNIMPL:       /* not implemented                      */
469         case DSRT_REVCODE:      /* software obsolete must recompile     */
470         case DSRT_NOSEL:
471                 sp->u_scb.cmd_scb[0] = 0;
472                 sp->error = SCG_FATAL;          break;
473
474         case DSRT_TIMEOUT:
475                 sp->u_scb.cmd_scb[0] = 0;
476                 sp->error = SCG_TIMEOUT;        break;
477         }
478         return (ret);
479 }