]> git.gag.com Git - debian/amanda/blob - contrib/gsc/gscdd.c
prepare a squeeze-targeted upload
[debian/amanda] / contrib / gsc / gscdd.c
1 /*
2  * $Id: gscdd.c,v 1.1 2001/04/15 11:12:37 ant Exp $
3  * Copyright (c) 1996, 1997 by Matthew Jacob
4  *
5  *      This software is free software; you can redistribute it and/or
6  *      modify it under the terms of the GNU Library General Public
7  *      License as published by the Free Software Foundation; version 2.
8  *
9  *      This software is distributed in the hope that it will be useful,
10  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *      Library General Public License for more details.
13  *
14  *      You should have received a copy of the GNU Library General Public
15  *      License along with this software; if not, write to the Free
16  *      Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  *
18  *      The author may be reached via electronic communications at
19  *
20  *              mjacob@feral.com
21  *
22  *      or, via United States Postal Address
23  *
24  *              Matthew Jacob
25  *              1831 Castro Street
26  *              San Francisco, CA, 94131
27  */
28
29 #include <stdio.h>
30 #include <sys/types.h>
31 #include <sys/errno.h>
32 #include <sys/sysmacros.h>
33 #include <sys/syspest.h>
34 #include <sys/ioctl.h>
35 #include <sys/i_machine.h>
36 #include <sys/systm.h>
37 #include <sys/conf.h>
38 #include <sys/devinfo.h>
39 #include <sys/lockl.h>
40 #include <sys/device.h>
41 #include <sys/uio.h>
42 #include <sys/watchdog.h>
43 #include <sys/errids.h>
44 #include <sys/trchkid.h>
45 #include <sys/priv.h>
46 #include <sys/iostat.h>
47 #include <sys/bootrecord.h>
48 #include <sys/scsi.h>
49 #include <sys/malloc.h>
50 #include <sys/sleep.h>
51 #include <sys/fp_io.h>
52 #include <sys/pin.h>
53 #include <sys/lock_alloc.h>
54 #define DD_LOCK 37
55 #include "gscdds.h"
56
57 static int strlen(char *s) { char *p = s; while (*p) p++; return p - s; }
58 static void memset(void *x, int val, size_t amt)
59 { char *p = (char *)x; while (--amt) *p++ = (char) val; }
60 static void memcpy(void *dst, void *src, size_t amt)
61  { char *dest = dst, *source = src; while (--amt) *dest++ = *source++; }
62 #define bcopy(src, dst, nbytes) memcpy(dst, src, nbytes)
63
64 /*
65  * Local Definitions
66  */
67
68 #define HKWD_GSC_DD     0x66600000
69
70 #define _COM_TRACE(b, var)      \
71         var = strlen(b); trcgenk(0, HKWD_GSC_DD, var, var, b)
72
73 #define Trace0(val, str)        \
74         if (scudebug >= val) { \
75                 int icxq; \
76                 _COM_TRACE(str, icxq); \
77         }
78 #define Trace1(val, fmt, arg1)  \
79         if (scudebug >= val) { \
80                 int icxq; char buf[256]; \
81                 (void) sprintf(buf, fmt, arg1); \
82                 _COM_TRACE(buf, icxq); \
83         }
84 #define Trace2(val, fmt, arg1, arg2)    \
85         if (scudebug >= val) { \
86                 int icxq; char buf[256]; \
87                 (void) sprintf(buf, fmt, arg1, arg2); \
88                 _COM_TRACE(buf, icxq); \
89         }
90 #define Trace3(val, fmt, arg1, arg2, arg3)      \
91         if (scudebug >= val) { \
92                 int icxq; char buf[256]; \
93                 (void) sprintf(buf, fmt, arg1, arg2, arg3); \
94                 _COM_TRACE(buf, icxq); \
95         }
96 #define Trace4(val, fmt, arg1, arg2, arg3, arg4)        \
97         if (scudebug >= val) { \
98                 int icxq; char buf[256]; \
99                 (void) sprintf(buf, fmt, arg1, arg2, arg3, arg4); \
100                 _COM_TRACE(buf, icxq); \
101         }
102
103 #define Trace5(val, fmt, arg1, arg2, arg3, arg4, arg5)  \
104         if (scudebug >= val) { \
105                 int icxq; char buf[256]; \
106                 (void) sprintf(buf, fmt, arg1, arg2, arg3, arg4, arg5); \
107                 _COM_TRACE(buf, icxq); \
108         }
109
110 #define Trace6(val, fmt, arg1, arg2, arg3, arg4, arg5, arg6)    \
111         if (scudebug >= val) { \
112                 int icxq; char buf[256]; \
113                 (void) sprintf(buf, fmt, arg1, arg2, arg3, arg4, arg5, arg6); \
114                 _COM_TRACE(buf, icxq); \
115         }
116
117 #define MJ_RTN(VAL)     simple_unlock(&sp->dd_lock); return (VAL)
118
119 typedef struct {
120     struct sc_buf scsibuf;
121     uint index;
122 } gsc_buf_t;
123
124 typedef struct {
125     Simple_lock dd_lock;
126     Simple_lock buf_lock;
127     struct file *fp;            /* file pointer */
128     gsc_buf_t cbuf;
129 #define cmdbuf cbuf.scsibuf     /* buffer for command */
130     gsc_buf_t rbuf;
131 #define rqsbuf rbuf.scsibuf     /* buffer for request sense */
132     dev_t dev;                  /* Adapter dev */
133     u_char tgt;                 /* target ID */
134     u_char lun;                 /* logical unit */
135     u_char isopen;              /* device is open */
136     u_char iscfg;               /* non-zero to show this as configured */
137     u_char unstart;             /* stop device on unconfigure */
138     u_char needresume;          /* needs an SC_RESUME with next command */
139 } gsc_softc_t;
140
141 /*
142  * External References
143  */
144 extern int copyin(void *, void *, int);
145 extern int copyout(void *, void *, int);
146 extern int devstrat(struct buf *);
147 extern int nodev(void);
148 extern void setuerror(int);
149
150
151 /*
152  * Device Driver Entry Points
153  */
154 int gsc_config(dev_t, int, struct uio *);
155 static int gsc_open(dev_t);
156 static int gsc_close(dev_t);
157 static int gsc_ioctl(dev_t, int, void *, ulong);
158 static void gscdd_intr(struct buf *);
159
160 /*
161  * Static Data
162  */
163 static int scudebug = 10;
164 static int nunits = 0;
165 static gsc_softc_t softinfo[MAX_UNITS] = { 0 };
166 lock_t config_lock = { LOCK_AVAIL };
167
168
169 /*
170  * Local Function Prototypes
171  */
172
173 static int gsopen(gsc_softc_t *);
174 static void gsclose(gsc_softc_t *, dev_t);
175 static int gsccmd(dev_t, scmd_t *, ulong);
176 static int make_rqs(gsc_softc_t *, char, char *, int, int);
177
178 /*
179  * Configuration Routines
180  */
181
182 int
183 gsc_config(dev_t devno, int cmd, struct uio * uiop)
184 {
185     struct gsc_ddsinfo ddsinfo;
186     gsc_softc_t *sp;
187     int result, i, unit;
188     extern int nodev();
189     static struct devsw gsc_dsw = {
190         gsc_open,       /* entry point for open routine */
191         gsc_close,      /* entry point for close routine */
192         nodev,          /* entry point for read routine */
193         nodev,          /* entry point for write routine */
194         gsc_ioctl,      /* entry point for ioctl routine */
195         nodev,          /* entry point for strategy routine */
196         0,              /* pointer to tty device structure */
197         nodev,          /* entry point for select routine */
198         gsc_config,     /* entry point for config routine */
199         nodev,          /* entry point for print routine */
200         nodev,          /* entry point for dump routine */
201         nodev,          /* entry point for mpx routine */
202         nodev,          /* entry point for revoke routine */
203         NULL,           /* pointer to device specific data */
204         NULL,           /* select pointer */
205         DEV_MPSAFE
206     };
207
208     if (lockl(&config_lock, LOCK_SHORT) != LOCK_SUCC) {
209         return (EINVAL);
210     }
211     unit = minor(devno);
212     if (unit < 0 || unit >= MAX_UNITS) {
213         Trace2(0, "%d: bad unit %d", __LINE__, unit);
214         result = EINVAL;
215         unlockl(&config_lock);
216         return (result);
217     }
218
219     switch (cmd) {
220     case CFG_INIT:
221         Trace2(2, "CFG_INIT: unit %d nunit %d\n", unit, nunits);
222         /*
223          * Initialize softinfo, first time around.
224          */
225         if (nunits == 0) {
226             memset(softinfo, 0, sizeof (softinfo));
227         }
228         /*
229          * Copy in DDS information
230          */
231         uiomove((caddr_t) &ddsinfo, sizeof ddsinfo, UIO_WRITE, uiop);
232         sp = &softinfo[unit];
233         if (sp->iscfg) {
234             Trace1(0, "CFG_INIT: unit %d already configd", unit);
235             result = EBUSY;
236             break;
237         }
238         lock_alloc(&sp->dd_lock, LOCK_ALLOC_PIN, DD_LOCK, -1);
239         lock_alloc(&sp->buf_lock, LOCK_ALLOC_PIN, DD_LOCK, -1);
240         simple_lock_init(&sp->dd_lock);
241         sp->dev = ddsinfo.busid;
242         sp->tgt = ddsinfo.target;
243         sp->lun = ddsinfo.lun;
244         sp->cbuf.index = sp->rbuf.index = unit;
245         /*
246          * If this is the first time through:
247          *   Add entry to the device switch table to call this driver
248          *   Pin driver code.
249          */
250         if (nunits == 0) {
251             result = devswadd(devno, &gsc_dsw);
252             if (result != 0) {
253                 Trace1(0, "CFG_INIT: devswadd result: %d", result);
254                 break;
255             }
256             result = pincode((int (*) ()) gscdd_intr);
257             if (result) {
258                 Trace1(0, "CFG_INIT: pincode result: %d", result);
259                 devswdel(devno);
260                 break;
261             }
262         }
263         sp->iscfg = 1;
264         result = gsopen(sp);
265         if (result) {
266             Trace2(0, "CFG_INIT: gsopen returns %d for unit %d", result, unit);
267             sp->iscfg = 0;
268             gsclose(sp, devno);
269             break;
270         }
271         if (nunits <= unit)
272             nunits = unit + 1;
273         sp->iscfg = 1;
274         break;
275
276     case CFG_TERM:
277         Trace1(2, "CFG_TERM unit %d", unit);
278         result = 0;
279         sp = &softinfo[unit];
280         if (sp->iscfg == 0) {
281             Trace1(0, "CFG_TERM: unit %d not already configd", unit);
282             result = ENXIO;
283             break;
284         } else if (sp->isopen) {
285             Trace1(0, "CFG_TERM: unit %d open", unit);
286             result = EBUSY;
287             break;
288         }
289         sp->iscfg = 0;  /* block further actions */
290         gsclose(sp, devno);
291         break;
292
293     default:
294         result = EINVAL;
295         break;
296     }
297     unlockl(&config_lock);
298     return (result);
299 }
300
301 /*
302  * Validate that devno is indeed for a SCSI adapter, and set up stuff for it.
303  */
304 static int
305 gsopen(gsc_softc_t * sp)
306 {
307     struct file *fp;
308     int r;
309     struct devinfo di;
310
311     Trace2(2, "gsopen: %d.%d", major(sp->dev), minor(sp->dev));
312     sp->fp = NULL;
313     r = fp_opendev(sp->dev, DREAD|DWRITE|DKERNEL, NULL, 0, &fp);
314     if (r) {
315         Trace3(0, "%d: fp_opendev unit %d=%d", __LINE__, sp->cbuf.index, r);
316         return (r);
317     }
318     r = fp_ioctl(fp, IOCINFO, (caddr_t) &di, NULL);
319     if (r) {
320         Trace3(0, "%d: fp_ioctl unit %d=%d", __LINE__, sp->cbuf.index, r);
321         (void) fp_close(fp);
322         return (r);
323     }
324     if (di.devtype != DD_BUS || di.devsubtype != DS_SCSI) {
325         Trace2(0, "%d: not SCSI bus on unit %d", __LINE__,  sp->cbuf.index);
326         (void) fp_close(fp);
327         return (r);
328     }
329     sp->fp = fp;
330     sp->unstart = 1;
331     if (fp_ioctl(sp->fp, SCIOSTART, (caddr_t) IDLUN(sp->tgt, sp->lun), NULL)) {
332         sp->unstart = 0;
333     }
334     return (0);
335 }
336
337 /*
338  * Shut down a device
339  */
340 static void
341 gsclose(gsc_softc_t *sp, dev_t devno)
342 {
343     int i;
344     if (sp->fp != NULL && sp->unstart) {
345         (void) fp_ioctl(sp->fp, SCIOSTOP, (caddr_t) IDLUN(sp->tgt, sp->lun), NULL);
346         sp->unstart = 0;
347     }
348     if (sp->fp) {
349         (void) fp_close(sp->fp);
350         sp->fp = NULL;
351     }
352     for (i = 0; i < MAX_UNITS; i++) {
353         if (softinfo[i].iscfg) {
354             Trace1(0, "gsclose: unit %d still confd", i);
355             break;
356         }
357     }
358     if (i == MAX_UNITS) {
359         Trace0(0, "gsclose: All unconfigured now");
360         (void) devswdel(devno);
361         unpincode((int (*) ()) gscdd_intr);
362     }
363 }
364
365 /*
366  * VFS entry points
367  */
368
369 static int
370 gsc_open(dev_t devno)
371 {
372     gsc_softc_t *sp;
373     int unit = minor(devno);
374
375     Trace1(2, "gsc_open: open unit %d", unit);
376     if (unit < 0 || unit >= MAX_UNITS) {
377         return (ENODEV);
378     }
379     sp = &softinfo[unit];
380     if (sp->iscfg == 0 || sp->fp == NULL) {
381         Trace2(0, "%d: bad unit (%d)", __LINE__, unit);
382         return (ENODEV);
383     }
384     simple_lock(&sp->dd_lock);
385     if (sp->isopen) {
386         simple_unlock(&sp->dd_lock);
387         return (EBUSY);
388     }
389     sp->isopen = 1;
390     simple_unlock(&sp->dd_lock);
391     return (0);
392 }
393
394 static int
395 gsc_close(dev_t dev)
396 {
397     gsc_softc_t *sp;
398     int unit = minor(dev);
399
400     Trace1(2, "gsc_close: close unit %d", unit);
401     if (unit < 0 || unit >= MAX_UNITS) {
402         return (ENODEV);
403     }
404     sp = &softinfo[unit];
405     if (sp->iscfg == 0) {
406         return (ENODEV);
407     }
408     simple_lock(&sp->dd_lock);
409     sp->isopen = 0;
410     simple_unlock(&sp->dd_lock);
411     return (0);
412 }
413
414 static int
415 gsc_ioctl(dev_t dev, int cmd, void *arg, ulong dflag)
416 {
417     switch (cmd) {
418     case GSC_CMD:
419         return (gsccmd(dev, arg, dflag));
420
421     case GSC_SETDBG:
422     {
423         int i;
424         cmd = copyin(arg, (caddr_t) &i, sizeof (int));
425         if (cmd != 0) {
426             return (cmd);
427         }
428         cmd = scudebug;
429         scudebug = i;
430         return (copyout((caddr_t) &cmd, arg, sizeof (int)));
431     }
432     default:
433         return (ENOTTY);
434     }
435 }
436
437
438 /****************************************************************************/
439
440 static int
441 gsccmd(dev_t dev, scmd_t *argcmd, ulong dflag)
442 {
443     gsc_softc_t *sp;
444     scmd_t local, *l;
445     char sbyte, albits;
446     struct sc_buf *usc;
447     struct buf *Ubp;
448     int r, r2, ival, upin, unit, rqvalid, once;
449
450     unit = minor(dev);
451     Trace2(1, "%d: cmd for unit %d", __LINE__, minor(dev));
452     if (unit < 0 || unit >= MAX_UNITS) {
453         setuerror(ENXIO);
454         return (ENXIO);
455     }
456     sp = &softinfo[unit];
457     if (sp->iscfg == 0 || sp->fp == NULL) {
458         Trace2(0, "gsccmd: bad unit %d (cfg=%d)", unit, sp->iscfg);
459         r = ENODEV;
460         setuerror(r);
461         return (r);
462     }
463     simple_lock(&sp->dd_lock);
464     l = &local;
465     if (dflag & DKERNEL) {
466         l = argcmd;
467     } else {
468         r = copyin((caddr_t) argcmd, (caddr_t) l, sizeof (scmd_t));
469         if (r != 0) {
470             Trace2(0, "%d: copyin=%d", __LINE__, r);
471             setuerror(r);
472             MJ_RTN (r);
473         }
474     }
475     Trace6(1, "%d: cdblen%d datalen%d snslen%d rw=%d tv=%d", __LINE__,
476            l->cdblen, l->datalen, l->senselen, l->rw, l->timeval);
477     sbyte = 0;
478     rqvalid = upin = r = r2 = 0;
479     usc = &sp->cmdbuf;
480     Ubp = &usc->bufstruct;
481     memset(usc, 0, sizeof (struct sc_buf));
482
483     /*
484      * Check some parameters...
485      */
486
487     if (l->cdblen > sizeof (struct sc_cmd)) {
488         r = EINVAL;
489         goto out;
490     }
491
492     /*
493      * Setup sc_buf structure
494      */
495     Ubp->b_iodone = gscdd_intr;
496     Ubp->b_dev = sp->dev;
497     Ubp->b_flags = B_BUSY | B_MPSAFE;
498     Ubp->b_resid = Ubp->b_bcount = l->datalen;
499     Ubp->b_xmemd.aspace_id = XMEM_INVAL;
500     Ubp->b_event = EVENT_NULL;
501
502     if (l->datalen) {
503         Ubp->b_un.b_addr = l->data_buf;
504         if (l->rw) {
505             Ubp->b_flags |= B_READ;
506         }
507         if (dflag & DKERNEL) {
508             r = pinu(l->data_buf, l->datalen, UIO_SYSSPACE);
509         } else {
510             r = pinu(l->data_buf, l->datalen, UIO_USERSPACE);
511         }
512         if (r) {
513             Trace2(0, "%d: pinu buf %d", __LINE__, r);
514             goto out;
515         }
516         upin++;
517         if (dflag & DKERNEL) {
518             r = xmattach(l->data_buf, l->datalen, &Ubp->b_xmemd, SYS_ADSPACE);
519         } else {
520             r = xmattach(l->data_buf, l->datalen, &Ubp->b_xmemd, USER_ADSPACE);
521         }
522         if (r != XMEM_SUCC) {
523             Trace2(0, "%d: xmattach %d", __LINE__, r);
524             r = EFAULT;
525             goto out;
526         }
527         upin++;
528         r = xmemdma(&Ubp->b_xmemd, l->data_buf, XMEM_UNHIDE);
529         if (r == XMEM_FAIL) {
530             Trace2(0, "%d: xmemdma %d", __LINE__, r);
531             r = EFAULT;
532             goto out;
533         }
534         r = 0;
535     }
536     usc->scsi_command.scsi_id = sp->tgt;
537     usc->scsi_command.scsi_length = l->cdblen;
538     if (dflag & DKERNEL) {
539         bcopy(l->cdb, (caddr_t)&usc->scsi_command.scsi_cmd, l->cdblen);
540     } else {
541         r = copyin(l->cdb, (caddr_t) & usc->scsi_command.scsi_cmd, l->cdblen);
542         if (r != 0) {
543             goto out;
544         }
545     }
546     /* Setting lun in SCSI CDB as well as sc_buf structure */
547     usc->lun = sp->lun;
548     usc->scsi_command.scsi_cmd.lun &= 0x1F;
549     usc->scsi_command.scsi_cmd.lun |= (sp->lun << 5) & 0xE0;
550     albits = usc->scsi_command.scsi_cmd.lun;
551     usc->timeout_value = l->timeval;
552     if (sp->needresume) {
553         usc->flags |= SC_RESUME;
554         sp->needresume = 0;
555     }
556
557     if (scudebug > 1) {
558         char *c = (char *) &usc->scsi_command.scsi_cmd;
559         char cdbuf[64];
560         (void) sprintf(cdbuf,
561                        "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x "
562                        "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x",
563                        c[0], c[1], c[2], c[3], c[4], c[5],
564                        c[6], c[7], c[8], c[9], c[10], c[11]);
565         Trace2(0, "%d: cdb=%s", __LINE__, cdbuf);
566     }
567
568     once = 0;
569 again:
570     Ubp->b_flags &= ~B_DONE;
571     r = devstrat(Ubp);
572     if (r == 0) {
573         ival = disable_lock(INTCLASS1, &sp->buf_lock);
574         while ((Ubp->b_flags & B_DONE) == 0) {
575             e_sleep_thread(&Ubp->b_event, &sp->buf_lock, LOCK_HANDLER);
576         }
577         unlock_enable(ival, &sp->buf_lock);
578     } else {
579         /*
580          * If ENXIO,  We never actually got started.
581          */
582         if (r == ENXIO && once == 0) {
583             once++;
584             usc->flags |= SC_RESUME|SC_DELAY_CMD;
585             goto again;
586         }
587         sp->needresume = 1;
588         Trace2(1, "%d: devstrat=%d", __LINE__, r);
589         goto out;
590     }
591
592     Trace4(1, "%d: b_flags %x b_error %d b_resid %d", __LINE__,
593            Ubp->b_flags, Ubp->b_error, Ubp->b_resid);
594     Trace5(1, "%d: sv %x st %x gc %x as %x", __LINE__,
595            usc->status_validity, usc->scsi_status,
596            usc->general_card_status, usc->adap_q_status);
597
598     if (Ubp->b_flags & B_ERROR) {
599         r = Ubp->b_error;
600         sp->needresume = 1;
601     }
602
603     if (usc->status_validity & SC_SCSI_ERROR) {
604         sbyte = (usc->scsi_status & SCSI_STATUS_MASK);
605         sp->needresume = 1;
606         if (sbyte == SC_CHECK_CONDITION && l->senselen) {
607             struct sc_buf *usl;
608             struct buf *Sbp;
609
610             r = make_rqs(sp, albits, l->sense_buf, l->senselen,
611                      (dflag & DKERNEL) != 0);
612             if (r) {
613                 Trace2(0, "%d: make_rqs=%d", __LINE__, r);
614                 goto out;
615             }
616             usl = &sp->rqsbuf;
617             Sbp = &usl->bufstruct;
618             r = devstrat(Sbp);
619             if (r == 0) {
620                 ival = disable_lock(INTCLASS1, &sp->buf_lock);
621                 while ((Sbp->b_flags & B_DONE) == 0) {
622                     e_sleep_thread(&Sbp->b_event, &sp->buf_lock, LOCK_HANDLER);
623                 }
624                 unlock_enable(ival, &sp->buf_lock);
625             } else {
626                 Trace2(0, "%d:ds=%d for rqs", __LINE__, r);
627                 goto out;
628             }
629             xmdetach(&Sbp->b_xmemd);
630             if (dflag & DKERNEL) {
631                 (void) unpinu(l->sense_buf, l->senselen, UIO_SYSSPACE);
632             } else {
633                 (void) unpinu(l->sense_buf, l->senselen, UIO_USERSPACE);
634             }
635             Trace4(1, "%d SENSE: b_flags %x b_error %d b_resid %d",
636                    __LINE__, Sbp->b_flags, Sbp->b_error,
637                    Sbp->b_resid);
638             Trace5(1, "%d: sv %x st %x gc %x as %x", __LINE__,
639                    usl->status_validity, usl->scsi_status,
640                    usl->general_card_status, usl->adap_q_status);
641             if (usl->scsi_status || usl->general_card_status) {
642                 r = EIO;
643             } else {
644                 rqvalid = 1;
645             }
646         }
647     }
648
649     if (usc->status_validity & SC_ADAPTER_ERROR) {
650         sp->needresume = 1;
651         Trace2(0, "%d: adapter error 0x%x", __LINE__,
652                usc->general_card_status);
653         Ubp->b_flags |= B_ERROR;
654         switch (usc->general_card_status) {
655         case SC_NO_DEVICE_RESPONSE:
656         case SC_HOST_IO_BUS_ERR:
657         case SC_SCSI_BUS_FAULT:
658         case SC_CMD_TIMEOUT:
659         case SC_ADAPTER_HDW_FAILURE:
660         case SC_ADAPTER_SFW_FAILURE:
661         case SC_FUSE_OR_TERMINAL_PWR:
662         case SC_SCSI_BUS_RESET:
663         default:
664             r = EIO;
665             break;
666         }
667     }
668
669     /*
670      * Log errors through errsave function
671      */
672     if (usc->status_validity & (SC_SCSI_ERROR|SC_ADAPTER_ERROR)) {
673         struct sc_error_log_df log;
674
675         memset(&log, 0, sizeof (log));
676         /*
677          * All errors are 'temporary unknown driver error'
678          */
679         log.error_id = ERRID_SCSI_ERR6;
680         (void) sprintf(log.resource_name, "gsc%d", unit);
681         memcpy(&log.scsi_command, &usc->scsi_command, sizeof (struct scsi));
682         log.status_validity = usc->status_validity;
683         log.scsi_status = usc->scsi_status;
684         log.general_card_status = usc->general_card_status;
685         if (rqvalid) {
686             int amt;
687             if (l->senselen > 128)
688                 amt = 128;
689             else
690                 amt = l->senselen;
691             (void) copyin(l->sense_buf, log.req_sense_data, amt);
692         }
693         errsave(&log, sizeof (struct sc_error_log_df));
694     }
695
696     if (dflag & DKERNEL) {
697         *l->statusp = sbyte;
698     } else {
699         r2 = copyout(&sbyte, l->statusp, 1);
700         if (r2 != 0) {
701             if (r == 0)
702                 r = r2;
703             goto out;
704         }
705     }
706 out:
707     if (l->datalen) {
708         if (upin > 1) {
709             xmdetach(&Ubp->b_xmemd);
710             upin--;
711         }
712         if (upin > 0) {
713             if (dflag & DKERNEL) {
714                 (void) unpinu(l->data_buf, l->datalen, UIO_SYSSPACE);
715             } else {
716                 (void) unpinu(l->data_buf, l->datalen, UIO_USERSPACE);
717             }
718             upin--;
719         }
720     }
721     Trace2(1, "%d: returning %d", __LINE__, r);
722     if (r)
723         setuerror(r);
724     MJ_RTN (r);
725 }
726
727 static int
728 make_rqs(gsc_softc_t * sp, char albits, char *uaddr, int ulen, int isk)
729 {
730     struct sc_buf *usl;
731     struct buf *Sbp;
732     int err, upin;
733
734     if (ulen > 255)
735         ulen = 255;
736     upin = err = 0;
737     usl = &sp->rqsbuf;
738     Sbp = &usl->bufstruct;
739     memset(usl, 0, sizeof (struct sc_buf));
740
741     Sbp->b_un.b_addr = uaddr;
742     Sbp->b_resid = Sbp->b_bcount = ulen;
743     Sbp->b_iodone = gscdd_intr;
744     Sbp->b_dev = sp->dev;
745     Sbp->b_flags = B_BUSY | B_READ | B_MPSAFE;
746     Sbp->b_event = EVENT_NULL;
747     Sbp->b_xmemd.aspace_id = XMEM_INVAL;
748
749     if (isk)
750         err = pinu(uaddr, ulen, UIO_SYSSPACE);
751     else
752         err = pinu(uaddr, ulen, UIO_USERSPACE);
753     if (err)
754         goto out;
755     upin++;
756     if (isk)
757         err = xmattach(uaddr, ulen, &Sbp->b_xmemd, SYS_ADSPACE);
758     else
759         err = xmattach(uaddr, ulen, &Sbp->b_xmemd, USER_ADSPACE);
760     if (err != XMEM_SUCC) {
761         err = EFAULT;
762         goto out;
763     }
764     upin++;
765     err = xmemdma(&Sbp->b_xmemd, Sbp->b_un.b_addr, XMEM_UNHIDE);
766     if (err == XMEM_FAIL) {
767         err = EFAULT;
768         (void) xmdetach(&Sbp->b_xmemd);
769         goto out;
770     }
771     err = 0;
772
773     usl->lun = sp->lun; /* Setting lun in sc_buf structure */
774     usl->scsi_command.scsi_id = sp->tgt;
775     usl->scsi_command.scsi_length = 6;
776     usl->scsi_command.scsi_cmd.scsi_op_code = 0x3;
777     usl->scsi_command.scsi_cmd.lun = albits & 0xE0; /*ONLY copy the lun bits*/
778     usl->scsi_command.scsi_cmd.scsi_bytes[2] = ulen;
779     usl->timeout_value = 2;
780     usl->flags = SC_RESUME;
781     sp->needresume = 0;
782
783  out:
784     if (err) {
785         if (upin > 1) {
786             xmdetach(&Sbp->b_xmemd);
787             upin--;
788         }
789         if (upin > 0) {
790             if (isk)
791                 (void) unpinu(uaddr, ulen, UIO_SYSSPACE);
792             else
793                 (void) unpinu(uaddr, ulen, UIO_USERSPACE);
794             upin--;
795         }
796     }
797     return (err);
798 }
799
800 void
801 gscdd_intr(struct buf * bp)
802 {
803     int lv;
804     gsc_softc_t *sp = &softinfo[((gsc_buf_t *)bp)->index];
805
806     lv = disable_lock(INTIODONE, &sp->buf_lock);
807     bp->b_flags |= B_DONE;
808     unlock_enable(lv, &sp->buf_lock);
809     e_wakeup(&bp->b_event);
810 }
811 /*
812  * mode: c
813  * Local variables:
814  * c-indent-level: 4
815  * c-brace-imaginary-offset: 0
816  * c-brace-offset: -4
817  * c-argdecl-indent: 4
818  * c-label-offset: -4
819  * c-continued-statement-offset: 4
820  * c-continued-brace-offset: 0
821  * End:
822  */