Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / libusal / scsi-next.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-next.c      1.32 04/01/15 Copyright 1997 J. Schilling */
14 /*
15  *      Interface for the NeXT Step generic SCSI implementation.
16  *
17  *      This is a hack, that tries to emulate the functionality
18  *      of the usal driver.
19  *
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.
25  *
26  *      Copyright (c) 1997 J. Schilling
27  */
28 /*
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.
32  *
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.
37  *
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.
41  */
42
43 #include <bsd/dev/scsireg.h>
44
45 /*
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.
51  */
52 static  char    _usal_trans_version[] = "scsi-next.c-1.32";     /* The version for this transport*/
53
54 #define MAX_SCG         16      /* Max # of SCSI controllers */
55 #define MAX_TGT         16
56 #define MAX_LUN         8
57
58 struct usal_local {
59         short   usalfiles[MAX_SCG][MAX_TGT][MAX_LUN];
60         int     usalfile;
61         int     max_scsibus;
62         int     cur_scsibus;
63         int     cur_target;
64         int     cur_lun;
65 };
66 #define usallocal(p)    ((struct usal_local *)((p)->local))
67
68 /*#define       MAX_DMA_NEXT    (32*1024)*/
69 #define MAX_DMA_NEXT    (64*1024)       /* Check if this is not too big */
70
71
72 static  BOOL    usal_setup(SCSI *usalp, int busno, int tgt, int tlun, BOOL ex);
73
74 /*
75  * Return version information for the low level SCSI transport code.
76  * This has been introduced to make it easier to trace down problems
77  * in applications.
78  */
79 static char *
80 usalo_version(SCSI *usalp, int what)
81 {
82         if (usalp != (SCSI *)0) {
83                 switch (what) {
84
85                 case SCG_VERSION:
86                         return (_usal_trans_version);
87                 /*
88                  * If you changed this source, you are not allowed to
89                  * return "schily" for the SCG_AUTHOR request.
90                  */
91                 case SCG_AUTHOR:
92                         return (_usal_auth_cdrkit);
93                 case SCG_SCCS_ID:
94                         return (__sccsid);
95                 }
96         }
97         return ((char *)0);
98 }
99
100 static int
101 usalo_help(SCSI *usalp, FILE *f)
102 {
103         __usal_help(f, "SGIOCREQ", "Generic SCSI",
104                 "", "bus,target,lun", "1,2,0", TRUE, FALSE);
105         return (0);
106 }
107
108 static int
109 usalo_open(SCSI *usalp, char *device)
110 {
111                 int     busno   = usal_scsibus(usalp);
112                 int     tgt     = usal_target(usalp);
113                 int     tlun    = usal_lun(usalp);
114         register int    f;
115         register int    i;
116         char            devname[64];
117
118         if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
119                 errno = EINVAL;
120                 if (usalp->errstr)
121                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
122                                 "Illegal value for busno, target or lun '%d,%d,%d'",
123                                 busno, tgt, tlun);
124                 return (-1);
125         }
126
127         if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2)) {
128                 errno = EINVAL;
129                 if (usalp->errstr)
130                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
131                                 "Open by 'devname' not supported on this OS");
132                 return (-1);
133         }
134
135         if (usalp->local == NULL) {
136                 usalp->local = malloc(sizeof (struct usal_local));
137                 if (usalp->local == NULL)
138                         return (0);
139
140                 usallocal(usalp)->usalfile              = -1;
141                 usallocal(usalp)->max_scsibus   = -1;
142                 usallocal(usalp)->cur_scsibus   = -1;
143                 usallocal(usalp)->cur_target    = -1;
144                 usallocal(usalp)->cur_lun               = -1;
145         }
146
147         for (i = 0; i < 4; i++) {
148                 snprintf(devname, sizeof (devname), "/dev/sg%d", i);
149                 f = open(devname, O_RDWR);
150                 if (usalp->debug > 0)
151                         errmsg("open(devname: '%s') : %d\n", devname, f);
152                 if (f < 0)
153                         continue;
154                 usallocal(usalp)->usalfile = f;
155                 break;
156
157         }
158         if (f >= 0) {
159                 if (usallocal(usalp)->max_scsibus < 0) {
160                         for (i = 0; i < MAX_SCG; i++) {
161                                 if (!SCGO_HAVEBUS(usalp, i))
162                                         break;
163                         }
164                         usallocal(usalp)->max_scsibus = i;
165                 }
166                 if (usalp->debug > 0) {
167                         fprintf((FILE *)usalp->errfile,
168                                 "maxbus: %d\n", usallocal(usalp)->max_scsibus);
169                 }
170                 if (usallocal(usalp)->max_scsibus <= 0) {
171                         usallocal(usalp)->max_scsibus = 1;
172                         usallocal(usalp)->cur_scsibus = 0;
173                 }
174
175                 ioctl(f, SGIOCENAS);
176                 if (busno > 0 && tgt > 0 && tlun > 0)
177                         usal_setup(usalp, busno, tgt, tlun, TRUE);
178                 return (1);
179         }
180         if (usalp->errstr)
181                 snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
182                         "Cannot open '/dev/sg*'");
183         return (0);
184 }
185
186 static int
187 usalo_close(SCSI *usalp)
188 {
189         if (usalp->local == NULL)
190                 return (-1);
191
192         if (usallocal(usalp)->usalfile >= 0)
193                 close(usallocal(usalp)->usalfile);
194         usallocal(usalp)->usalfile = -1;
195         return (0);
196 }
197
198 static BOOL
199 usal_setup(SCSI *usalp, int busno, int tgt, int tlun, BOOL ex)
200 {
201         scsi_adr_t sadr;
202
203         sadr.sa_target = tgt;
204         sadr.sa_lun = tlun;
205
206         if (usalp->debug > 0) {
207                 fprintf((FILE *)usalp->errfile,
208                         "usal_setup curbus %d -> %d\n", usallocal(usalp)->cur_scsibus, busno);
209         }
210
211         if (usalp->debug > 0 && ((usallocal(usalp)->cur_scsibus < 0 || usallocal(usalp)->cur_scsibus != busno)))
212                 fprintf((FILE *)usalp->errfile, "setting SCSI bus to: %d\n", busno);
213         if ((usallocal(usalp)->cur_scsibus < 0 || usallocal(usalp)->cur_scsibus != busno) &&
214                                 ioctl(usallocal(usalp)->usalfile, SGIOCCNTR, &busno) < 0) {
215
216                 usallocal(usalp)->cur_scsibus = -1;     /* Driver is in undefined state */
217                 if (ex)
218 /*                      comerr("Cannot set SCSI bus\n");*/
219                         errmsg("Cannot set SCSI bus\n");
220                 return (FALSE);
221         }
222         usallocal(usalp)->cur_scsibus   = busno;
223
224         if (usalp->debug > 0) {
225                 fprintf((FILE *)usalp->errfile,
226                         "setting target/lun to: %d/%d\n", tgt, tlun);
227         }
228         if (ioctl(usallocal(usalp)->usalfile, SGIOCSTL, &sadr) < 0) {
229                 if (ex)
230                         comerr("Cannot set SCSI address\n");
231                 return (FALSE);
232         }
233         usallocal(usalp)->cur_scsibus   = busno;
234         usallocal(usalp)->cur_target    = tgt;
235         usallocal(usalp)->cur_lun               = tlun;
236         return (TRUE);
237 }
238
239 static long
240 usalo_maxdma(SCSI *usalp, long amt)
241 {
242         long maxdma = MAX_DMA_NEXT;
243 #ifdef  SGIOCMAXDMA
244         int  m;
245
246         if (ioctl(usallocal(usalp)->usalfile, SGIOCMAXDMA, &m) >= 0) {
247                 maxdma = m;
248                 if (usalp->debug > 0) {
249                         fprintf((FILE *)usalp->errfile,
250                                 "maxdma: %d\n", maxdma);
251                 }
252         }
253 #endif
254         return (maxdma);
255 }
256 #ifdef  XXX
257 #define SGIOCENAS       _IO('s', 2)                     /* enable autosense */
258 #define SGIOCDAS        _IO('s', 3)                     /* disable autosense */
259 #define SGIOCRST        _IO('s', 4)                     /* reset SCSI bus */
260 #define SGIOCCNTR       _IOW('s', 6, int)               /* select controller */
261 #define SGIOCGAS        _IOR('s', 7, int)               /* get autosense */
262 #define SGIOCMAXDMA     _IOR('s', 8, int)               /* max DMA size */
263 #define SGIOCNUMTARGS   _IOR('s', 9, int)               /* # of targets/bus */
264 #endif
265
266 static void *
267 usalo_getbuf(SCSI *usalp, long amt)
268 {
269         if (usalp->debug > 0) {
270                 fprintf((FILE *)usalp->errfile,
271                         "usalo_getbuf: %ld bytes\n", amt);
272         }
273         usalp->bufbase = valloc((size_t)(amt));
274         return (usalp->bufbase);
275 }
276
277 static void
278 usalo_freebuf(SCSI *usalp)
279 {
280         if (usalp->bufbase)
281                 free(usalp->bufbase);
282         usalp->bufbase = NULL;
283 }
284
285 static BOOL
286 usalo_havebus(SCSI *usalp, int busno)
287 {
288         if (busno < 0 || busno >= MAX_SCG)
289                 return (FALSE);
290
291         if (usalp->local == NULL)
292                 return (FALSE);
293
294         if (usallocal(usalp)->max_scsibus > 0 && busno >= usallocal(usalp)->max_scsibus)
295                 return (FALSE);
296
297         return (usal_setup(usalp, busno, 0, 0, FALSE));
298 }
299
300 static int
301 usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun)
302 {
303         if (busno < 0 || busno >= MAX_SCG ||
304             tgt < 0 || tgt >= MAX_TGT ||
305             tlun < 0 || tlun >= MAX_LUN)
306                 return (-1);
307         if (usallocal(usalp)->max_scsibus > 0 && busno >= usallocal(usalp)->max_scsibus)
308                 return (-1);
309
310         if (usalp->local == NULL)
311                 return (-1);
312
313         if ((busno != usallocal(usalp)->cur_scsibus) || (tgt != usallocal(usalp)->cur_target) || (tlun != usallocal(usalp)->cur_lun)) {
314                 if (!usal_setup(usalp, busno, tgt, tlun, FALSE))
315                         return (-1);
316         }
317         return (usallocal(usalp)->usalfile);
318 }
319
320 static int
321 usalo_initiator_id(SCSI *usalp)
322 {
323         return (-1);
324 }
325
326 static int
327 usalo_isatapi(SCSI *usalp)
328 {
329         return (FALSE);
330 }
331
332 static int
333 usalo_reset(SCSI *usalp, int what)
334 {
335         if (what == SCG_RESET_NOP)
336                 return (0);
337         if (what != SCG_RESET_BUS) {
338                 errno = EINVAL;
339                 return (-1);
340         }
341         return (ioctl(usalp->fd, SGIOCRST, 0));
342 }
343
344 static int
345 usalo_send(SCSI *usalp)
346 {
347         struct usal_cmd *sp = usalp->scmd;
348         struct scsi_req req;
349         register long   *lp1;
350         register long   *lp2;
351         int             ret = 0;
352
353         if (usalp->fd < 0 || (sp->cdb_len > sizeof (req.sr_cdb))) {
354                 sp->error = SCG_FATAL;
355                 sp->ux_errno = EIO;
356                 return (0);
357         }
358         fillbytes(&req, sizeof (req), '\0');
359         movebytes(sp->cdb.cmd_cdb, &req.sr_cdb, sp->cdb_len);
360         if (sp->size) {
361                 req.sr_dma_dir = SR_DMA_WR;
362                 if (sp->flags & SCG_RECV_DATA)
363                         req.sr_dma_dir = SR_DMA_RD;
364         }
365         req.sr_addr = sp->addr;
366         req.sr_dma_max = sp->size;
367         req.sr_ioto = sp->timeout;
368         if (ioctl(usalp->fd, SGIOCREQ, (void *)&req) < 0) {
369                 ret  = -1;
370                 sp->ux_errno = geterrno();
371                 if (sp->ux_errno != ENOTTY)
372                         ret = 0;
373         } else {
374                 sp->ux_errno = 0;
375         }
376         if (usalp->debug > 0) {
377                 fprintf((FILE *)usalp->errfile, "dma_dir:     %X\n", req.sr_dma_dir);
378                 fprintf((FILE *)usalp->errfile, "dma_addr:    %X\n", req.sr_addr);
379                 fprintf((FILE *)usalp->errfile, "io_time:     %d\n", req.sr_ioto);
380                 fprintf((FILE *)usalp->errfile, "io_status:   %d\n", req.sr_io_status);
381                 fprintf((FILE *)usalp->errfile, "scsi_status: %X\n", req.sr_scsi_status);
382                 fprintf((FILE *)usalp->errfile, "dma_xfer:    %d\n", req.sr_dma_xfr);
383         }
384         sp->u_scb.cmd_scb[0] = req.sr_scsi_status;
385         sp->sense_count = sizeof (esense_reply_t);
386         if (sp->sense_count > sp->sense_len)
387                 sp->sense_count = sp->sense_len;
388         if (sp->sense_count > SCG_MAX_SENSE)
389                 sp->sense_count = SCG_MAX_SENSE;
390         if (sp->sense_count < 0)
391                 sp->sense_count = 0;
392         movebytes(&req.sr_esense, sp->u_sense.cmd_sense, sp->sense_count);
393         sp->resid = sp->size - req.sr_dma_xfr;
394
395         switch (req.sr_io_status) {
396
397         case SR_IOST_GOOD:      sp->error = SCG_NO_ERROR;       break;
398
399         case SR_IOST_CHKSNV:    sp->sense_count = 0;
400         case SR_IOST_CHKSV:     sp->error = SCG_RETRYABLE;
401                                 break;
402
403         case SR_IOST_SELTO:
404         case SR_IOST_DMAOR:
405                                 sp->error = SCG_FATAL;          break;
406
407         case SR_IOST_IOTO:      sp->error = SCG_TIMEOUT;        break;
408
409         case SR_IOST_PERM:
410         case SR_IOST_NOPEN:
411                                 sp->error = SCG_FATAL;
412                                 ret = (-1);
413                                 break;
414
415         default:                sp->error = SCG_RETRYABLE;      break;
416
417         }
418         return (ret);
419 }