2 * Contributed by HD Associates (hd@world.std.com).
3 * Copyright (c) 1992, 1993 HD Associates
5 * Berkeley style copyright. I've just snarfed it out of stdio.h:
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include <sys/types.h>
37 #include <sys/errno.h>
38 #include <sys/param.h>
39 #include <sys/malloc.h>
43 #include <scsi/scsi_all.h>
44 #include <scsi/scsiconf.h>
45 #include <scsi/scsi_generic.h>
49 #define SGOUTSTANDING 2
53 /* Use one of the implementation defined spare bits
54 * to indicate the escape op:
56 #define DSRQ_ESCAPE DSRQ_CTRL1
61 struct scsi_switch
*sc_sw
;
64 long int ad_info
; /* info about the adapter */
65 int cmdscount
; /* cmds allowed outstanding by the board */
67 struct scsi_xfer
*free_xfer
;
71 /* This is used to associate a struct dsreq and a struct buf.
78 /* I think this is a portable way to get back to the base of
79 * the enclosing structure:
81 # define DSBUF_P(BP) ((dsbuf_t *)((caddr_t)(BP) - (caddr_t)&((dsbuf_t *)0)->buf))
85 # define DSBUF_MAGIC 0xDBFACDBF
89 /* The host adapter unit is encoded in the upper 2 bits of the minor number
90 * (the SGI flag bits).
92 #error "NSG can't be > 4 unless the method of encoding the board unit changes"
97 #define SG(DEV) sgs[G_SCSI_UNIT(DEV)]
99 struct sg
*sg_new(int lun
)
101 struct sg
*sg
= (struct sg
*)malloc(sizeof(*sg
),M_TEMP
, M_NOWAIT
);
106 bzero(sg
, sizeof(struct sg
));
111 int sg_attach(ctlr
, scsi_addr
, scsi_switch
)
113 struct scsi_switch
*scsi_switch
;
117 struct scsi_xfer
*scsi_xfer
;
118 static int next_sg_unit
= 0;
120 int unit
= next_sg_unit
++;
124 printf("Too many generic SCSIs (%d > %d); reconfigure the kernel.\n",
129 "You have hit the max of 4. You will have to change the driver.\n");
134 if ((sg
= sg_new(0)) == 0)
139 sg
->sc_sw
= scsi_switch
;
142 /* This is a bit confusing. It looks like Julian calls back into the
143 * adapter to find out how many outstanding transactions it can
144 * handle. How does he handle a tape/disk combo?
147 if (sg
->sc_sw
->adapter_info
)
149 sg
->ad_info
= ( (*(sg
->sc_sw
->adapter_info
))(unit
));
150 sg
->cmdscount
= sg
->ad_info
& AD_INF_MAX_CMDS
;
151 if(sg
->cmdscount
> SGOUTSTANDING
)
152 sg
->cmdscount
= SGOUTSTANDING
;
162 scsi_xfer
= (struct scsi_xfer
*)malloc(sizeof(struct scsi_xfer
) *
163 i
, M_TEMP
, M_NOWAIT
);
167 printf("scsi_generic: Can't malloc.\n");
173 scsi_xfer
->next
= sg
->free_xfer
;
174 sg
->free_xfer
= scsi_xfer
;
180 printf(" /dev/gs%d (instance 0) generic SCSI via controller %d\n",
181 scsi_addr
, sg
->ctlr
);
183 printf(" /dev/gs%d-%d generic SCSI via controller %d\n",
184 unit
, scsi_addr
, sg
->ctlr
);
190 /* It is trivial to add support for processor target devices
191 * here - enable target mode on open and disable on close
192 * if a flag bit is set in the minor number
194 int sgopen(dev_t dev
)
202 int sgclose(dev_t dev
)
208 /* Free a scsi_xfer, wake processes waiting for it
210 void sg_free_xs(dev_t dev
, struct scsi_xfer
*xs
, int flags
)
213 struct sg
*sg
= SG(dev
);
215 if(flags
& SCSI_NOMASK
)
217 if (sg
->free_xfer_wait
)
219 printf("sg_free_xs: doing a wakeup from NOMASK mode!\n");
220 wakeup((caddr_t
)&sg
->free_xfer
);
222 xs
->next
= sg
->free_xfer
;
228 if (sg
->free_xfer_wait
)
229 wakeup((caddr_t
)&sg
->free_xfer
);
230 xs
->next
= sg
->free_xfer
;
236 /* Get ownership of a scsi_xfer
237 * If need be, sleep on it, until it comes free
239 struct scsi_xfer
*sg_get_xs(dev_t dev
, int flags
)
241 struct scsi_xfer
*xs
;
243 struct sg
*sg
= SG(dev
);
245 if(flags
& (SCSI_NOSLEEP
| SCSI_NOMASK
))
247 if (xs
= sg
->free_xfer
)
249 sg
->free_xfer
= xs
->next
;
256 while (!(xs
= sg
->free_xfer
))
258 sg
->free_xfer_wait
++; /* someone waiting! */
259 sleep((caddr_t
)&sg
->free_xfer
, PRIBIO
+1);
260 sg
->free_xfer_wait
--;
262 sg
->free_xfer
= xs
->next
;
270 /* We let the user interpret his own sense in the
273 int sg_interpret_sense(dev_t dev
, struct scsi_xfer
*xs
, int *flag_p
)
278 /* ITSDONE is really used for things that are marked one
279 * in the interrupt. I'll leave the logic in in case I want
280 * to move done processing (and therefore have a start queue)
281 * back into the interrupt.
282 * BUG: No start queue.
285 int sg_done(dev_t dev
,
286 struct scsi_xfer
*xs
)
288 xs
->flags
|= ITSDONE
;
293 int sg_submit_cmd(dev_t dev
, struct scsi_xfer
*xs
, dsreq_t
*dsreq
)
297 struct sg
*sg
= SG(dev
);
300 xs
->error
= XS_NOERROR
;
302 xs
->bp
= 0; /* This bp doesn't seem to be used except to
303 * disable sleeping in the host adapter code.
304 * "st" does set it up, though.
307 retval
= (*(sg
->sc_sw
->scsi_cmd
))(xs
);
311 case SUCCESSFULLY_QUEUED
:
312 while(!(xs
->flags
& ITSDONE
))
315 /* Fall through... */
320 dsreq
->ds_status
= xs
->status
;
326 dsreq
->ds_datasent
= dsreq
->ds_datalen
- xs
->resid
;
331 retval
= (sg_interpret_sense(dev
,xs
, (int *)0));
334 dsreq
->ds_sensesent
= sizeof(xs
->sense
);
335 dsreq
->ds_ret
= DSRT_SENSE
;
340 case XS_DRIVER_STUFFUP
:
342 dsreq
->ds_ret
= DSRT_HOST
;
343 printf("sg%d: host adapter code inconsistency\n" ,G_SCSI_UNIT(dev
));
349 dsreq
->ds_ret
= DSRT_TIMEOUT
;
356 xs
->flags
&= ~ITSDONE
;
363 printf("sg%d: unknown error category from host adapter code\n"
372 dsreq
->ds_datasent
= dsreq
->ds_datalen
- xs
->resid
;
376 case TRY_AGAIN_LATER
:
379 xs
->flags
&= ~ITSDONE
;
385 case ESCAPE_NOT_SUPPORTED
:
386 retval
= ENOSYS
; /* "Function not implemented" */
390 printf("sg%d: illegal return from host adapter code\n",
399 /* sg_escape: Do a generic SCSI escape
401 int sg_escape(dev_t dev
, int op_code
, u_char
*b
, int nb
)
405 struct scsi_generic scsi_generic
;
407 int flags
= SCSI_ESCAPE
;
409 struct scsi_xfer
*xs
;
410 struct sg
*sg
= SG(dev
);
412 xs
= sg_get_xs(dev
, flags
);
416 printf("sg_target%d: controller busy"
417 " (this should never happen)\n",G_SCSI_UNIT(dev
));
421 scsi_generic
.opcode
= op_code
;
422 bcopy(b
, scsi_generic
.bytes
, nb
);
424 /* Fill out the scsi_xfer structure
426 xs
->flags
= (flags
|INUSE
);
427 xs
->adapter
= sg
->ctlr
;
428 xs
->cmd
= &scsi_generic
;
429 xs
->targ
= G_SCSI_ID(dev
);
430 xs
->lu
= G_SCSI_LUN(dev
);
431 xs
->retries
= SG_RETRIES
;
433 xs
->when_done
= (flags
& SCSI_NOMASK
)
437 xs
->done_arg2
= (int)xs
;
441 retval
= sg_submit_cmd(dev
, xs
, 0);
443 bcopy(scsi_generic
.bytes
, b
, nb
);
445 sg_free_xs(dev
,xs
,flags
);
450 /* sg_target: Turn on / off target mode
452 int sg_target(dev_t dev
, int enable
)
455 return sg_escape(dev
, SCSI_OP_TARGET
, &b0
, 1);
459 /* This should REALLY be a select call!
460 * This is used in a stand alone system without an O/S. I didn't
461 * have the time to add select, which the system was missing,
462 * so I added this stuff to poll for the async arrival of
463 * connections for target mode.
465 int sg_poll(dev_t dev
, int *send
, int *recv
)
470 ret
= sg_escape(dev
, SCSI_OP_POLL
, (u_char
*)&s
, sizeof(s
));
480 #endif /* EMBEDDED */
482 int sg_scsi_cmd(dev_t dev
,
484 struct scsi_generic
*scsi_cmd
,
487 struct scsi_sense_data
*scsi_sense
)
492 struct scsi_xfer
*xs
;
493 struct sg
*sg
= SG(dev
);
498 dsreq
->ds_status
= 0;
499 dsreq
->ds_sensesent
= 0;
501 if (dsreq
->ds_flags
& DSRQ_READ
)
502 flags
|= SCSI_DATA_IN
;
504 if (dsreq
->ds_flags
& DSRQ_WRITE
)
505 flags
|= SCSI_DATA_OUT
;
507 if (dsreq
->ds_flags
& DSRQ_TARGET
)
508 flags
|= SCSI_TARGET
;
510 if (dsreq
->ds_flags
& DSRQ_ESCAPE
)
511 flags
|= SCSI_ESCAPE
;
514 if (dsreq
->ds_flags
& DSRQ_PHYSADDR
)
515 flags
|= SCSI_PHYSADDR
;
518 xs
= sg_get_xs(dev
, flags
);
522 printf("sg_scsi_cmd%d: controller busy"
523 " (this should never happen)\n",G_SCSI_UNIT(dev
));
528 /* Fill out the scsi_xfer structure
530 xs
->flags
|= (flags
|INUSE
);
531 xs
->adapter
= sg
->ctlr
;
532 xs
->targ
= G_SCSI_ID(dev
);
533 xs
->lu
= G_SCSI_LUN(dev
);
534 xs
->retries
= SG_RETRIES
;
535 xs
->timeout
= dsreq
->ds_time
;
537 xs
->cmdlen
= dsreq
->ds_cmdlen
;
539 xs
->datalen
= d_count
;
541 xs
->when_done
= (flags
& SCSI_NOMASK
)
545 xs
->done_arg2
= (int)xs
;
547 xs
->req_sense_length
= (dsreq
->ds_senselen
< sizeof(struct scsi_sense_data
))
549 : sizeof(struct scsi_sense_data
);
552 retval
= sg_submit_cmd(dev
, xs
, dsreq
);
554 if (dsreq
->ds_ret
== DSRT_SENSE
)
555 bcopy(&(xs
->sense
), scsi_sense
, sizeof(xs
->sense
));
557 sg_free_xs(dev
,xs
,flags
);
562 void sgerr(struct buf
*bp
, int err
)
565 bp
->b_flags
|= B_ERROR
;
572 * Should I reorganize this so it returns to physio instead
573 * of sleeping in sg_scsi_cmd? Is there any advantage, other
574 * than avoiding the probable duplicate wakeup in iodone?
576 * Don't create a block device entry point for this
577 * driver without making some fixes:
578 * you have to be able to go from the bp to the dsreq somehow.
580 void sgstrategy(struct buf
*bp
)
583 struct scsi_generic scsi_generic
;
584 struct scsi_sense_data scsi_sense
;
585 int lun
= G_SCSI_LUN(bp
->b_dev
);
587 dsbuf_t
*dsbuf
= DSBUF_P(bp
);
590 if (dsbuf
->magic
!= DSBUF_MAGIC
)
592 printf("sgstrategy: struct buf not magic.\n");
597 dsreq
= dsbuf
->dsreq
;
599 /* We're in trouble if physio tried to break up the
602 if (bp
->b_bcount
!= dsreq
->ds_datalen
)
604 printf("sgstrategy unit%d: Transfer broken up.\n",
605 G_SCSI_UNIT(bp
->b_dev
));
610 dsreq
->ds_ret
= DSRT_OK
;
612 /* Reject 0 length timeouts.
614 if (dsreq
->ds_time
== 0)
620 if (dsreq
->ds_cmdlen
> sizeof(struct scsi_generic
))
626 copyin(dsreq
->ds_cmdbuf
, (char *)&scsi_generic
, dsreq
->ds_cmdlen
);
628 /* Use device unit for the LUN. Using the one the user provided
629 * would be a huge security problem.
631 if ((dsreq
->ds_flags
& DSRQ_ESCAPE
) == 0)
632 scsi_generic
.bytes
[0] = (scsi_generic
.bytes
[0] & 0x1F) | (lun
<< 5);
634 err
= sg_scsi_cmd(bp
->b_dev
, dsreq
,
636 (u_char
*)bp
->b_un
.b_addr
,
640 if (dsreq
->ds_sensesent
)
642 if (dsreq
->ds_sensesent
> dsreq
->ds_senselen
)
643 dsreq
->ds_sensesent
= dsreq
->ds_senselen
;
645 copyout(&scsi_sense
, dsreq
->ds_sensebuf
, dsreq
->ds_sensesent
);
650 if (dsreq
->ds_ret
== DSRT_OK
)
651 dsreq
->ds_ret
= DSRT_DEVSCSI
;
657 /* This is a fake. It would be nice to know if the
658 * command was sent or not instead of pretending it was if
659 * we get this far. That would involve adding "sent" members
660 * to the xs so it could be set up down in the host adapter code.
662 dsreq
->ds_cmdsent
= dsreq
->ds_cmdlen
;
664 if (dsreq
->ds_ret
== 0)
665 dsreq
->ds_ret
= DSRT_OK
;
667 iodone(bp
); /* Shouldn't this iodone be done in the interrupt?
673 void sgminphys(struct buf
*bp
)
677 int sgioctl(dev_t dev
, int cmd
, caddr_t addr
, int f
)
686 dsreq_t
*dsreq
= (dsreq_t
*)addr
;
688 int rwflag
= (dsreq
->ds_flags
& DSRQ_READ
) ? B_READ
: B_WRITE
;
691 struct buf
*bp
= &dsbuf
.buf
;
693 bzero(&dsbuf
, sizeof(dsbuf
));
696 dsbuf
.magic
= DSBUF_MAGIC
;
698 #ifdef SCSI_PHYSADDR /* Physical memory addressing option */
699 phys
= (dsreq
->ds_flags
& DSRQ_PHYSADDR
);
706 bp
->b_un
.b_addr
= dsreq
->ds_databuf
;
707 bp
->b_bcount
= dsreq
->ds_datalen
;
709 bp
->b_flags
= rwflag
;
714 else if (dsreq
->ds_datalen
)
719 iovec
.iov_base
= dsreq
->ds_databuf
;
720 iovec
.iov_len
= dsreq
->ds_datalen
;
723 uio
.uio_resid
= dsreq
->ds_datalen
;
725 uio
.uio_segflg
= UIO_USERSPACE
;
726 uio
.uio_procp
= curproc
;
727 uio
.uio_rw
= (rwflag
== B_READ
) ? UIO_READ
: UIO_WRITE
;
728 uio
.uio_iov
= &iovec
;
731 /* if ((ret = rawio(dev, &uio, bp)) == 0)
732 ret = bp->b_error; */
749 ret
= sg_target(dev
, *(int *)addr
);