Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / libusal / scsi-os2.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-os2.c       1.25 04/01/15 Copyright 1998 J. Schilling, C. Wohlgemuth */
14 /*
15  *      Interface for the OS/2 ASPI-Router ASPIROUT.SYS ((c) D. Dorau).
16  *              This additional driver is a prerequisite for using cdrecord.
17  *              Get it from HOBBES or LEO.
18  *
19  *      Warning: you may change this source, but if you do that
20  *      you need to change the _usal_version and _usal_auth* string below.
21  *      You may not return "schily" for an SCG_AUTHOR request anymore.
22  *      Choose your name instead of "schily" and make clear that the version
23  *      string is related to a modified source.
24  *
25  *      XXX it currently uses static SRB and for this reason is not reentrant
26  *
27  *      Copyright (c) 1998 J. Schilling
28  *      Copyright (c) 1998 C. Wohlgemuth for this interface.
29  */
30 /*
31  * This program is free software; you can redistribute it and/or modify
32  * it under the terms of the GNU General Public License version 2
33  * as published by the Free Software Foundation.
34  *
35  * This program is distributed in the hope that it will be useful,
36  * but WITHOUT ANY WARRANTY; without even the implied warranty of
37  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38  * GNU General Public License for more details.
39  *
40  * You should have received a copy of the GNU General Public License along with
41  * this program; see the file COPYING.  If not, write to the Free Software
42  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
43  */
44
45 #undef  sense
46
47 /*#define       DEBUG*/
48
49 /* For AspiRouter */
50 #include "usal/srb_os2.h"
51
52 /*
53  *      Warning: you may change this source, but if you do that
54  *      you need to change the _usal_version and _usal_auth* string below.
55  *      You may not return "schily" for an SCG_AUTHOR request anymore.
56  *      Choose your name instead of "schily" and make clear that the version
57  *      string is related to a modified source.
58  */
59 static  char    _usal_trans_version[] = "scsi-os2.c-1.25";      /* The version for this transport*/
60
61 #define FILE_OPEN                       0x0001
62 #define OPEN_SHARE_DENYREADWRITE        0x0010
63 #define OPEN_ACCESS_READWRITE           0x0002
64 #define DC_SEM_SHARED                   0x01
65 #define OBJ_TILE                        0x0040
66 #define PAG_READ                        0x0001
67 #define PAG_WRITE                       0x0002
68 #define PAG_COMMIT                      0x0010
69
70 typedef unsigned long LHANDLE;
71 typedef unsigned long ULONG;
72 typedef unsigned char *PSZ;
73 typedef unsigned short USHORT;
74 typedef unsigned char UCHAR;
75
76 typedef LHANDLE HFILE;
77 typedef ULONG   HEV;
78
79 #define MAX_SCG         16      /* Max # of SCSI controllers */
80 #define MAX_TGT         16
81 #define MAX_LUN         8
82
83 struct usal_local {
84         int     dummy;
85 };
86 #define usallocal(p)    ((struct usal_local *)((p)->local))
87
88 #define MAX_DMA_OS2     (63*1024) /* ASPI-Router allows up to 64k */
89
90 static  void    *buffer         = NULL;
91 static  HFILE   driver_handle   = 0;
92 static  HEV     postSema        = 0;
93
94 static  BOOL    open_driver(SCSI *usalp);
95 static  BOOL    close_driver(void);
96 static  ULONG   wait_post(ULONG ulTimeOut);
97 static  BOOL    init_buffer(void* mem);
98 static  void    exit_func(void);
99 static  void    set_error(SRB *srb, struct usal_cmd *sp);
100
101
102 static void
103 exit_func()
104 {
105         if (!close_driver())
106                 fprintf(stderr, "Cannot close OS/2-ASPI-Router!\n");
107 }
108
109 /*
110  * Return version information for the low level SCSI transport code.
111  * This has been introduced to make it easier to trace down problems
112  * in applications.
113  */
114 static char *
115 usalo_version(SCSI *usalp, int what)
116 {
117         if (usalp != (SCSI *)0) {
118                 switch (what) {
119
120                 case SCG_VERSION:
121                         return (_usal_trans_version);
122                 /*
123                  * If you changed this source, you are not allowed to
124                  * return "schily" for the SCG_AUTHOR request.
125                  */
126                 case SCG_AUTHOR:
127                         return (_usal_auth_cdrkit);
128                 case SCG_SCCS_ID:
129                         return (__sccsid);
130                 }
131         }
132         return ((char *)0);
133 }
134
135 static int
136 usalo_help(SCSI *usalp, FILE *f)
137 {
138         __usal_help(f, "ASPI", "Generic transport independent SCSI",
139                 "", "bus,target,lun", "1,2,0", TRUE, FALSE);
140         return (0);
141 }
142
143 static int
144 usalo_open(SCSI *usalp, char *device)
145 {
146         int     busno   = usal_scsibus(usalp);
147         int     tgt     = usal_target(usalp);
148         int     tlun    = usal_lun(usalp);
149
150         if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
151                 errno = EINVAL;
152                 if (usalp->errstr)
153                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
154                                 "Illegal value for busno, target or lun '%d,%d,%d'",
155                                 busno, tgt, tlun);
156                 return (-1);
157         }
158
159         if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2)) {
160                 errno = EINVAL;
161                 if (usalp->errstr)
162                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
163                                 "Open by 'devname' not supported on this OS");
164                 return (-1);
165         }
166
167         if (usalp->local == NULL) {
168                 usalp->local = malloc(sizeof (struct usal_local));
169                 if (usalp->local == NULL)
170                         return (0);
171         }
172
173         if (!open_driver(usalp))        /* Try to open ASPI-Router */
174                 return (-1);
175         atexit(exit_func);      /* Install Exit Function which closes the ASPI-Router */
176
177         /*
178          * Success after all
179          */
180         return (1);
181 }
182
183 static int
184 usalo_close(SCSI *usalp)
185 {
186         exit_func();
187         return (0);
188 }
189
190 static long
191 usalo_maxdma(SCSI *cgp, long amt)
192 {
193         long maxdma = MAX_DMA_OS2;
194         return (maxdma);
195 }
196
197 static void *
198 usalo_getbuf(SCSI *usalp, long amt)
199 {
200         ULONG rc;
201
202 #ifdef DEBUG
203         fprintf((FILE *)usalp->errfile, "usalo_getbuf: %ld bytes\n", amt);
204 #endif
205         rc = DosAllocMem(&buffer, amt, OBJ_TILE | PAG_READ | PAG_WRITE | PAG_COMMIT);
206
207         if (rc) {
208                 fprintf((FILE *)usalp->errfile, "Cannot allocate buffer.\n");
209                 return ((void *)0);
210         }
211         usalp->bufbase = buffer;
212
213 #ifdef DEBUG
214         fprintf((FILE *)usalp->errfile, "Buffer allocated at: 0x%x\n", usalp->bufbase);
215 #endif
216
217         /* Lock memory */
218         if (init_buffer(usalp->bufbase))
219                 return (usalp->bufbase);
220
221         fprintf((FILE *)usalp->errfile, "Cannot lock memory buffer.\n");
222         return ((void *)0); /* Error */
223 }
224
225 static void
226 usalo_freebuf(SCSI *usalp)
227 {
228         if (usalp->bufbase && DosFreeMem(usalp->bufbase)) {
229                 fprintf((FILE *)usalp->errfile,
230                 "Cannot free buffer memory for ASPI-Router!\n"); /* Free our memory buffer if not already done */
231         }
232         if (buffer == usalp->bufbase)
233                 buffer = NULL;
234         usalp->bufbase = NULL;
235 }
236
237 static BOOL
238 usalo_havebus(SCSI *usalp, int busno)
239 {
240         register int    t;
241         register int    l;
242
243         if (busno < 0 || busno >= MAX_SCG)
244                 return (FALSE);
245
246         return (TRUE);
247 }
248
249 static int
250 usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun)
251 {
252         if (busno < 0 || busno >= MAX_SCG ||
253             tgt < 0 || tgt >= MAX_TGT ||
254             tlun < 0 || tlun >= MAX_LUN)
255                 return (-1);
256
257         /*
258          * Return fake
259          */
260         return (1);
261 }
262
263
264 static int
265 usalo_initiator_id(SCSI *usalp)
266 {
267         return (-1);
268 }
269
270 static int
271 usalo_isatapi(SCSI *usalp)
272 {
273         return (FALSE);
274 }
275
276
277 static int
278 usalo_reset(SCSI *usalp, int what)
279 {
280         ULONG   rc;                             /* return value */
281         ULONG   cbreturn;
282         ULONG   cbParam;
283         BOOL    success;
284 static  SRB     SRBlock;                        /* XXX makes it non reentrant */
285
286         if (what == SCG_RESET_NOP)
287                 return (0);
288         if (what != SCG_RESET_BUS) {
289                 errno = EINVAL;
290                 return (-1);
291         }
292         /*
293          * XXX Does this reset TGT or BUS ???
294          */
295         SRBlock.cmd             = SRB_Reset;            /* reset device         */
296         SRBlock.ha_num          = usal_scsibus(usalp);  /* host adapter number  */
297         SRBlock.flags           = SRB_Post;             /* posting enabled      */
298         SRBlock.u.res.target    = usal_target(usalp);   /* target id            */
299         SRBlock.u.res.lun       = usal_lun(usalp);      /* target LUN           */
300
301         rc = DosDevIOCtl(driver_handle, 0x92, 0x02, (void*) &SRBlock, sizeof (SRB), &cbParam,
302                         (void*) &SRBlock, sizeof (SRB), &cbreturn);
303         if (rc) {
304                 fprintf((FILE *)usalp->errfile,
305                                 "DosDevIOCtl() failed in resetDevice.\n");
306                 return (1);                     /* DosDevIOCtl failed */
307         } else {
308                 success = wait_post(40000);     /** wait for SRB being processed */
309                 if (success)
310                         return (2);
311         }
312         if (SRBlock.status != SRB_Done)
313                 return (3);
314 #ifdef DEBUG
315         fprintf((FILE *)usalp->errfile,
316                 "resetDevice of host: %d target: %d lun: %d successful.\n", usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp));
317         fprintf((FILE *)usalp->errfile,
318                 "SRBlock.ha_status: 0x%x, SRBlock.target_status: 0x%x, SRBlock.satus: 0x%x\n",
319                                 SRBlock.u.cmd.ha_status, SRBlock.u.cmd.target_status, SRBlock.status);
320 #endif
321         return (0);
322 }
323
324 /*
325  * Set error flags
326  */
327 static void
328 set_error(SRB *srb, struct usal_cmd *sp)
329 {
330         switch (srb->status) {
331
332         case SRB_InvalidCmd:            /* 0x80 Invalid SCSI request        */
333         case SRB_InvalidHA:             /* 0x81 Invalid host adapter number */
334         case SRB_BadDevice:             /* 0x82 SCSI device not installed   */
335                 sp->error = SCG_FATAL;
336                 sp->ux_errno = EINVAL;  /* Should we ever return != EIO     */
337                 sp->ux_errno = EIO;
338                 break;
339
340
341         case SRB_Busy:                  /* 0x00 SCSI request in progress    */
342         case SRB_Aborted:               /* 0x02 SCSI aborted by host        */
343         case SRB_BadAbort:              /* 0x03 Unable to abort SCSI request */
344         case SRB_Error:                 /* 0x04 SCSI request completed with error */
345         default:
346                 sp->error = SCG_RETRYABLE;
347                 sp->ux_errno = EIO;
348                 break;
349         }
350 }
351
352 static int
353 usalo_send(SCSI *usalp)
354 {
355         struct usal_cmd *sp = usalp->scmd;
356         ULONG   rc;                             /* return value */
357 static  SRB     SRBlock;                        /* XXX makes it non reentrant */
358         Ulong   cbreturn;
359         Ulong   cbParam;
360         UCHAR*  ptr;
361
362         if (usalp->fd < 0) {                    /* Set in usalo_open() */
363                 sp->error = SCG_FATAL;
364                 return (0);
365         }
366
367         if (sp->cdb_len > sizeof (SRBlock.u.cmd.cdb_st)) { /* commandsize too big */
368                 sp->error = SCG_FATAL;
369                 sp->ux_errno = EINVAL;
370                 fprintf((FILE *)usalp->errfile,
371                         "sp->cdb_len > SRBlock.u.cmd.cdb_st. Fatal error in usalo_send, exiting...\n");
372                 return (-1);
373         }
374
375         /* clear command block */
376         fillbytes((caddr_t)&SRBlock.u.cmd.cdb_st, sizeof (SRBlock.u.cmd.cdb_st), '\0');
377         /* copy cdrecord command into SRB */
378         movebytes(&sp->cdb, &SRBlock.u.cmd.cdb_st, sp->cdb_len);
379
380         /* Build SRB command block */
381         SRBlock.cmd = SRB_Command;
382         SRBlock.ha_num = usal_scsibus(usalp);   /* host adapter number */
383
384         SRBlock.flags = SRB_Post;               /* flags */
385
386         SRBlock.u.cmd.target    = usal_target(usalp); /* Target SCSI ID */
387         SRBlock.u.cmd.lun       = usal_lun(usalp); /* Target SCSI LUN */
388         SRBlock.u.cmd.data_len  = sp->size;     /* # of bytes transferred */
389         SRBlock.u.cmd.data_ptr  = 0;            /* pointer to data buffer */
390         SRBlock.u.cmd.sense_len = sp->sense_len; /* length of sense buffer */
391
392         SRBlock.u.cmd.link_ptr  = 0;            /* pointer to next SRB */
393         SRBlock.u.cmd.cdb_len   = sp->cdb_len;  /* SCSI command length */
394
395         /* Specify direction */
396         if (sp->flags & SCG_RECV_DATA) {
397                 SRBlock.flags |= SRB_Read;
398         } else {
399                 if (sp->size > 0) {
400                         SRBlock.flags |= SRB_Write;
401                         if (usalp->bufbase != sp->addr) { /* Copy only if data not in ASPI-Mem */
402                                 movebytes(sp->addr, usalp->bufbase, sp->size);
403                         }
404                 } else {
405                         SRBlock.flags |= SRB_NoTransfer;
406                 }
407         }
408         sp->error       = SCG_NO_ERROR;
409         sp->sense_count = 0;
410         sp->u_scb.cmd_scb[0] = 0;
411         sp->resid       = 0;
412
413         /* execute SCSI command */
414         rc = DosDevIOCtl(driver_handle, 0x92, 0x02,
415                         (void*) &SRBlock, sizeof (SRB), &cbParam,
416                         (void*) &SRBlock, sizeof (SRB), &cbreturn);
417
418         if (rc) {               /* An error occured */
419                 fprintf((FILE *)usalp->errfile,
420                                 "DosDevIOCtl() in sendCommand failed.\n");
421                 sp->error = SCG_FATAL;
422                 sp->ux_errno = EIO;     /* Später vielleicht errno einsetzen */
423                 return (rc);
424         } else {
425                 /* Wait until the command is processed */
426                 rc = wait_post(sp->timeout*1000);
427                 if (rc) {       /* An error occured */
428                         if (rc == 640) {
429                                 /* Timeout */
430                                 sp->error = SCG_TIMEOUT;
431                                 sp->ux_errno = EIO;
432                                 fprintf((FILE *)usalp->errfile,
433                                                 "Timeout during SCSI-Command.\n");
434                                 return (1);
435                         }
436                         sp->error = SCG_FATAL;
437                         sp->ux_errno = EIO;
438                         fprintf((FILE *)usalp->errfile,
439                                         "Fatal Error during DosWaitEventSem().\n");
440                         return (1);
441                 }
442
443                 /* The command is processed */
444                 if (SRBlock.status == SRB_Done) {       /* succesful completion */
445 #ifdef DEBUG
446                         fprintf((FILE *)usalp->errfile,
447                                 "Command successful finished. SRBlock.status=0x%x\n\n", SRBlock.status);
448 #endif
449                         sp->sense_count = 0;
450                         sp->resid = 0;
451                         if (sp->flags & SCG_RECV_DATA) {        /* We read data */
452                                 if (sp->addr && sp->size) {
453                                         if (usalp->bufbase != sp->addr) /* Copy only if data not in ASPI-Mem */
454                                                 movebytes(usalp->bufbase, sp->addr, SRBlock.u.cmd.data_len);
455                                         ptr = (UCHAR*)sp->addr;
456                                         sp->resid = sp->size - SRBlock.u.cmd.data_len; /*nicht übertragene bytes. Korrekt berechnet???*/
457                                 }
458                         }       /* end of if (sp->flags & SCG_RECV_DATA) */
459                         if (SRBlock.u.cmd.target_status == SRB_CheckStatus) { /* Sense data valid */
460                                 sp->sense_count = (int)SRBlock.u.cmd.sense_len;
461                                 if (sp->sense_count > sp->sense_len)
462                                         sp->sense_count = sp->sense_len;
463
464                                 ptr = (UCHAR*)&SRBlock.u.cmd.cdb_st;
465                                 ptr += SRBlock.u.cmd.cdb_len;
466
467                                 fillbytes(&sp->u_sense.Sense, sizeof (sp->u_sense.Sense), '\0');
468                                 movebytes(ptr, &sp->u_sense.Sense, sp->sense_len);
469
470                                 sp->u_scb.cmd_scb[0] = SRBlock.u.cmd.target_status;
471                                 sp->ux_errno = EIO;     /* Später differenzieren? */
472                         }
473                         return (0);
474                 }
475                 /* SCSI-Error occured */
476                 set_error(&SRBlock, sp);
477
478                 if (SRBlock.u.cmd.target_status == SRB_CheckStatus) {   /* Sense data valid */
479                         sp->sense_count = (int)SRBlock.u.cmd.sense_len;
480                         if (sp->sense_count > sp->sense_len)
481                                 sp->sense_count = sp->sense_len;
482
483                         ptr = (UCHAR*)&SRBlock.u.cmd.cdb_st;
484                         ptr += SRBlock.u.cmd.cdb_len;
485
486                         fillbytes(&sp->u_sense.Sense, sizeof (sp->u_sense.Sense), '\0');
487                         movebytes(ptr, &sp->u_sense.Sense, sp->sense_len);
488
489                         sp->u_scb.cmd_scb[0] = SRBlock.u.cmd.target_status;
490                 }
491                 if (sp->flags & SCG_RECV_DATA) {
492                         if (sp->addr && sp->size) {
493                                 if (usalp->bufbase != sp->addr) /* Copy only if data not in ASPI-Mem */
494                                         movebytes(usalp->bufbase, sp->addr, SRBlock.u.cmd.data_len);
495                         }
496                 }
497 #ifdef  really
498                 sp->resid       = SRBlock.u.cmd.data_len; /* XXXXX Got no Data ????? */
499 #else
500                 sp->resid       = sp->size - SRBlock.u.cmd.data_len;
501 #endif
502                 return (1);
503         }
504 }
505
506 /***************************************************************************
507  *                                                                         *
508  *  BOOL open_driver()                                                     *
509  *                                                                         *
510  *  Opens the ASPI Router device driver and sets device_handle.            *
511  *  Returns:                                                               *
512  *    TRUE - Success                                                       *
513  *    FALSE - Unsuccessful opening of device driver                        *
514  *                                                                         *
515  *  Preconditions: ASPI Router driver has be loaded                        *
516  *                                                                         *
517  ***************************************************************************/
518 static BOOL
519 open_driver(SCSI *usalp)
520 {
521         ULONG   rc;                     /* return value */
522         ULONG   ActionTaken;            /* return value */
523         USHORT  openSemaReturn;         /* return value */
524         ULONG   cbreturn;
525         ULONG   cbParam;
526
527         if (driver_handle)              /* ASPI-Router already opened   */
528                 return (TRUE);
529
530         rc = DosOpen((PSZ) "aspirou$",  /* open driver*/
531                         &driver_handle,
532                         &ActionTaken,
533                         0,
534                         0,
535                         FILE_OPEN,
536                         OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE,
537                         NULL);
538         if (rc) {
539                 fprintf((FILE *)usalp->errfile,
540                                 "Cannot open ASPI-Router!\n");
541
542                 return (FALSE);         /* opening failed -> return false*/
543         }
544
545         /* Init semaphore */
546         if (DosCreateEventSem(NULL, &postSema,  /* create event semaphore */
547                                 DC_SEM_SHARED, 0)) {
548                 DosClose(driver_handle);
549                 fprintf((FILE *)usalp->errfile,
550                                 "Cannot create event semaphore!\n");
551
552                 return (FALSE);
553         }
554         rc = DosDevIOCtl(driver_handle, 0x92, 0x03,     /* pass semaphore handle */
555                         (void*) &postSema, sizeof (HEV), /* to driver            */
556                         &cbParam, (void*) &openSemaReturn,
557                         sizeof (USHORT), &cbreturn);
558
559         if (rc||openSemaReturn) {                       /* Error */
560                 DosCloseEventSem(postSema);
561                 DosClose(driver_handle);
562                 return (FALSE);
563         }
564         return (TRUE);
565 }
566
567 /***************************************************************************
568  *                                                                         *
569  *  BOOL close_driver()                                                    *
570  *                                                                         *
571  *  Closes the device driver                                               *
572  *  Returns:                                                               *
573  *    TRUE - Success                                                       *
574  *    FALSE - Unsuccessful closing of device driver                        *
575  *                                                                         *
576  *  Preconditions: ASPI Router driver has be opened with open_driver       *
577  *                                                                         *
578  ***************************************************************************/
579 static BOOL
580 close_driver()
581 {
582         ULONG rc;                               /* return value */
583
584         if (driver_handle) {
585                 rc = DosClose(driver_handle);
586                 if (rc)
587                         return (FALSE);         /* closing failed -> return false */
588                 driver_handle = 0;
589                 if (DosCloseEventSem(postSema))
590                         fprintf(stderr, "Cannot close event semaphore!\n");
591                 if (buffer && DosFreeMem(buffer)) {
592                         fprintf(stderr,
593                         "Cannot free buffer memory for ASPI-Router!\n"); /* Free our memory buffer if not already done */
594                 }
595                 buffer = NULL;
596         }
597         return (TRUE);
598 }
599
600 static ULONG
601 wait_post(ULONG ulTimeOut)
602 {
603         ULONG count = 0;
604         ULONG rc;                                       /* return value */
605
606 /*      rc = DosWaitEventSem(postSema, -1);*/           /* wait forever*/
607         rc = DosWaitEventSem(postSema, ulTimeOut);
608         DosResetEventSem(postSema, &count);
609         return (rc);
610 }
611
612 static BOOL
613 init_buffer(void *mem)
614 {
615         ULONG   rc;                                     /* return value */
616         USHORT lockSegmentReturn;                       /* return value */
617         Ulong   cbreturn;
618         Ulong   cbParam;
619
620         rc = DosDevIOCtl(driver_handle, 0x92, 0x04,     /* pass buffers pointer */
621                         (void*) mem, sizeof (void*),    /* to driver */
622                         &cbParam, (void*) &lockSegmentReturn,
623                         sizeof (USHORT), &cbreturn);
624         if (rc)
625                 return (FALSE);                         /* DosDevIOCtl failed */
626         if (lockSegmentReturn)
627                 return (FALSE);                         /* Driver could not lock segment */
628         return (TRUE);
629 }
630 #define sense   u_sense.Sense