1 /* $NetBSD: dpti.c,v 1.41 2009/05/12 12:14:18 cegger Exp $ */
4 * Copyright (c) 2001, 2007 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Copyright (c) 1996-2000 Distributed Processing Technology Corporation
34 * Copyright (c) 2000 Adaptec Corporation
35 * All rights reserved.
37 * TERMS AND CONDITIONS OF USE
39 * Redistribution and use in source form, with or without modification, are
40 * permitted provided that redistributions of source code must retain the
41 * above copyright notice, this list of conditions and the following disclaimer.
43 * This software is provided `as is' by Adaptec and any express or implied
44 * warranties, including, but not limited to, the implied warranties of
45 * merchantability and fitness for a particular purpose, are disclaimed. In no
46 * event shall Adaptec be liable for any direct, indirect, incidental, special,
47 * exemplary or consequential damages (including, but not limited to,
48 * procurement of substitute goods or services; loss of use, data, or profits;
49 * or business interruptions) however caused and on any theory of liability,
50 * whether in contract, strict liability, or tort (including negligence or
51 * otherwise) arising in any way out of the use of this driver software, even
52 * if advised of the possibility of such damage.
56 * Adaptec/DPT I2O control interface.
59 #include <sys/cdefs.h>
60 __KERNEL_RCSID(0, "$NetBSD: dpti.c,v 1.41 2009/05/12 12:14:18 cegger Exp $");
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/kernel.h>
65 #include <sys/device.h>
66 #include <sys/queue.h>
68 #include <sys/endian.h>
69 #include <sys/malloc.h>
71 #include <sys/ioctl.h>
72 #include <sys/kauth.h>
74 #include <uvm/uvm_extern.h>
78 #include <machine/pio.h>
79 #include <machine/cputypes.h>
82 #include <dev/i2o/i2o.h>
83 #include <dev/i2o/i2odpt.h>
84 #include <dev/i2o/iopio.h>
85 #include <dev/i2o/iopvar.h>
86 #include <dev/i2o/dptivar.h>
89 #define DPRINTF(x) printf x
94 static struct dpt_sig dpti_sig
= {
95 { 'd', 'P', 't', 'S', 'i', 'G'},
99 #elif defined(__powerpc__)
101 #elif defined(__alpha__)
103 #elif defined(__mips__)
105 #elif defined(__sparc64__)
108 #if defined(__i386__)
109 PROC_386
| PROC_486
| PROC_PENTIUM
| PROC_SEXIUM
,
116 OS_FREE_BSD
, /* XXX */
128 "" /* Will be filled later */
131 void dpti_attach(device_t
, device_t
, void *);
132 int dpti_blinkled(struct dpti_softc
*);
133 int dpti_ctlrinfo(struct dpti_softc
*, int, void *);
134 int dpti_match(device_t
, cfdata_t
, void *);
135 int dpti_passthrough(struct dpti_softc
*, void *, struct proc
*);
136 int dpti_sysinfo(struct dpti_softc
*, int, void *);
138 dev_type_open(dptiopen
);
139 dev_type_ioctl(dptiioctl
);
141 const struct cdevsw dpti_cdevsw
= {
142 dptiopen
, nullclose
, noread
, nowrite
, dptiioctl
,
143 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_OTHER
,
146 extern struct cfdriver dpti_cd
;
148 CFATTACH_DECL(dpti
, sizeof(struct dpti_softc
),
149 dpti_match
, dpti_attach
, NULL
, NULL
);
152 dpti_match(device_t parent
, cfdata_t match
, void *aux
)
154 struct iop_attach_args
*ia
;
155 struct iop_softc
*iop
;
158 iop
= (struct iop_softc
*)parent
;
160 if (ia
->ia_class
!= I2O_CLASS_ANY
|| ia
->ia_tid
!= I2O_TID_IOP
)
163 if (le16toh(iop
->sc_status
.orgid
) != I2O_ORG_DPT
)
170 dpti_attach(device_t parent
, device_t self
, void *aux
)
172 struct iop_softc
*iop
;
173 struct dpti_softc
*sc
;
175 struct i2o_param_op_results pr
;
176 struct i2o_param_read_results prr
;
177 struct i2o_dpt_param_exec_iop_buffers dib
;
181 sc
= device_private(self
);
182 iop
= device_private(parent
);
185 * Tell the world what we are. The description in the signature
186 * must be no more than 46 bytes long (see dptivar.h).
188 printf(": DPT/Adaptec RAID management interface\n");
189 snprintf(dpti_sig
.dsDescription
, sizeof(dpti_sig
.dsDescription
),
190 "NetBSD %s I2O OSM", osrelease
);
192 rv
= iop_field_get_all(iop
, I2O_TID_IOP
,
193 I2O_DPT_PARAM_EXEC_IOP_BUFFERS
, ¶m
,
194 sizeof(param
), NULL
);
198 sc
->sc_blinkled
= le32toh(param
.dib
.serialoutputoff
) + 8;
202 dptiopen(dev_t dev
, int flag
, int mode
,
206 if (device_lookup(&dpti_cd
, minor(dev
)) == NULL
)
213 dptiioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
215 struct iop_softc
*iop
;
216 struct dpti_softc
*sc
;
218 int i
, size
, rv
, linux
;
220 sc
= device_lookup_private(&dpti_cd
, minor(dev
));
221 iop
= (struct iop_softc
*)device_parent(&sc
->sc_dv
);
224 if (cmd
== PTIOCLINUX
) {
225 pt
= (struct ioctl_pt
*)data
;
226 size
= IOCPARM_LEN(pt
->com
);
227 cmd
= pt
->com
& 0xffff;
231 size
= IOCPARM_LEN(cmd
);
238 if (size
> sizeof(dpti_sig
))
239 size
= sizeof(dpti_sig
);
240 memcpy(data
, &dpti_sig
, size
);
244 rv
= dpti_ctlrinfo(sc
, size
, data
);
248 rv
= dpti_sysinfo(sc
, size
, data
);
252 if ((i
= dpti_blinkled(sc
)) == -1)
256 rv
= copyout(&i
, *(void **)data
, sizeof(i
));
263 case DPT_TARGET_BUSY
:
265 * XXX This is here to stop linux_machdepioctl() from
266 * whining about an unknown ioctl.
272 rv
= kauth_authorize_device_passthru(l
->l_cred
, dev
,
273 KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL
, data
);
277 if (sc
->sc_nactive
++ >= 2)
278 tsleep(&sc
->sc_nactive
, PRIBIO
, "dptislp", 0);
281 rv
= dpti_passthrough(sc
, data
, l
->l_proc
);
283 rv
= dpti_passthrough(sc
, *(void **)data
, l
->l_proc
);
286 wakeup_one(&sc
->sc_nactive
);
289 case DPT_I2ORESETCMD
:
290 printf("%s: I2ORESETCMD not implemented\n",
291 device_xname(&sc
->sc_dv
));
295 case DPT_I2ORESCANCMD
:
296 mutex_enter(&iop
->sc_conflock
);
297 rv
= iop_reconfigure(iop
, 0);
298 mutex_exit(&iop
->sc_conflock
);
310 dpti_blinkled(struct dpti_softc
*sc
)
312 struct iop_softc
*iop
;
315 iop
= (struct iop_softc
*)device_parent(&sc
->sc_dv
);
317 v
= bus_space_read_1(iop
->sc_iot
, iop
->sc_ioh
, sc
->sc_blinkled
+ 0);
319 v
= bus_space_read_1(iop
->sc_iot
, iop
->sc_ioh
,
320 sc
->sc_blinkled
+ 1);
328 dpti_ctlrinfo(struct dpti_softc
*sc
, int size
, void *data
)
330 struct dpt_ctlrinfo info
;
331 struct iop_softc
*iop
;
334 iop
= (struct iop_softc
*)device_parent(&sc
->sc_dv
);
336 memset(&info
, 0, sizeof(info
));
338 info
.length
= sizeof(info
) - sizeof(u_int16_t
);
339 info
.drvrHBAnum
= device_unit(&sc
->sc_dv
);
340 info
.baseAddr
= iop
->sc_memaddr
;
341 if ((i
= dpti_blinkled(sc
)) == -1)
344 info
.pciBusNum
= iop
->sc_pcibus
;
345 info
.pciDeviceNum
= iop
->sc_pcidev
;
346 info
.hbaFlags
= FLG_OSD_PCI_VALID
| FLG_OSD_DMA
| FLG_OSD_I2O
;
347 info
.Interrupt
= 10; /* XXX */
349 if (size
> sizeof(char)) {
350 memcpy(data
, &info
, min(sizeof(info
), size
));
353 rv
= copyout(&info
, *(void **)data
, sizeof(info
));
359 dpti_sysinfo(struct dpti_softc
*sc
, int size
, void *data
)
361 struct dpt_sysinfo info
;
367 memset(&info
, 0, sizeof(info
));
385 info
.processorFamily
= dpti_sig
.dsProcessorFamily
;
388 * Get the conventional memory size from CMOS.
395 info
.conventionalMemSize
= j
;
398 * Get the extended memory size from CMOS.
405 info
.extendedMemSize
= j
;
409 info
.processorType
= PROC_386
;
412 info
.processorType
= PROC_486
;
415 info
.processorType
= PROC_PENTIUM
;
419 info
.processorType
= PROC_SEXIUM
;
423 info
.flags
= SI_CMOS_Valid
| SI_BusTypeValid
|
424 SI_MemorySizeValid
| SI_NO_SmartROM
;
426 info
.flags
= SI_BusTypeValid
| SI_NO_SmartROM
;
429 info
.busType
= SI_PCI_BUS
;
432 * Copy out the info structure to the user.
434 if (size
> sizeof(char)) {
435 memcpy(data
, &info
, min(sizeof(info
), size
));
438 rv
= copyout(&info
, *(void **)data
, sizeof(info
));
444 dpti_passthrough(struct dpti_softc
*sc
, void *data
, struct proc
*proc
)
446 struct iop_softc
*iop
;
447 struct i2o_msg mh
, *mf
;
450 struct dpti_ptbuf bufs
[IOP_MAX_MSG_XFERS
];
451 u_int32_t mbtmp
[IOP_MAX_MSG_SIZE
/ sizeof(u_int32_t
)];
452 u_int32_t rbtmp
[IOP_MAX_MSG_SIZE
/ sizeof(u_int32_t
)];
453 int rv
, msgsize
, repsize
, sgoff
, i
, mapped
, nbuf
, nfrag
, j
, sz
;
456 iop
= (struct iop_softc
*)device_parent(&sc
->sc_dv
);
459 if ((rv
= dpti_blinkled(sc
)) != -1) {
461 aprint_error_dev(&sc
->sc_dv
, "adapter blinkled = 0x%02x\n", rv
);
467 * Copy in the message frame header and determine the size of the
468 * full message frame.
470 if ((rv
= copyin(data
, &mh
, sizeof(mh
))) != 0) {
471 DPRINTF(("%s: message copyin failed\n",
472 device_xname(&sc
->sc_dv
)));
476 msgsize
= (mh
.msgflags
>> 14) & ~3;
477 if (msgsize
< sizeof(mh
) || msgsize
>= IOP_MAX_MSG_SIZE
) {
478 DPRINTF(("%s: bad message frame size\n",
479 device_xname(&sc
->sc_dv
)));
484 * Handle special commands.
486 switch (mh
.msgfunc
>> 24) {
487 case I2O_EXEC_IOP_RESET
:
488 printf("%s: I2O_EXEC_IOP_RESET not implemented\n",
489 device_xname(&sc
->sc_dv
));
492 case I2O_EXEC_OUTBOUND_INIT
:
493 printf("%s: I2O_EXEC_OUTBOUND_INIT not implemented\n",
494 device_xname(&sc
->sc_dv
));
497 case I2O_EXEC_SYS_TAB_SET
:
498 printf("%s: I2O_EXEC_SYS_TAB_SET not implemented\n",
499 device_xname(&sc
->sc_dv
));
502 case I2O_EXEC_STATUS_GET
:
503 if ((rv
= iop_status_get(iop
, 0)) == 0)
504 rv
= copyout(&iop
->sc_status
, (char *)data
+ msgsize
,
505 sizeof(iop
->sc_status
));
510 * Copy in the full message frame.
512 if ((rv
= copyin(data
, mbtmp
, msgsize
)) != 0) {
513 DPRINTF(("%s: full message copyin failed\n",
514 device_xname(&sc
->sc_dv
)));
519 * Determine the size of the reply frame, and copy it in.
521 if ((rv
= copyin((char *)data
+ msgsize
, &rh
, sizeof(rh
))) != 0) {
522 DPRINTF(("%s: reply copyin failed\n",
523 device_xname(&sc
->sc_dv
)));
527 repsize
= (rh
.msgflags
>> 14) & ~3;
528 if (repsize
< sizeof(rh
) || repsize
>= IOP_MAX_MSG_SIZE
) {
529 DPRINTF(("%s: bad reply header size\n",
530 device_xname(&sc
->sc_dv
)));
534 if ((rv
= copyin((char *)data
+ msgsize
, rbtmp
, repsize
)) != 0) {
535 DPRINTF(("%s: reply too large\n", device_xname(&sc
->sc_dv
)));
540 * If the message has a scatter gather list, it must be comprised of
541 * simple elements. If any one transfer contains multiple segments,
542 * we allocate a temporary buffer for it; otherwise, the buffer will
543 * be mapped directly.
546 if ((sgoff
= ((mh
.msgflags
>> 4) & 15)) != 0) {
547 if ((sgoff
+ 2) > (msgsize
>> 2)) {
548 DPRINTF(("%s: invalid message size fields\n",
549 device_xname(&sc
->sc_dv
)));
553 memset(bufs
, 0, sizeof(bufs
));
556 pmax
= mbtmp
+ (msgsize
>> 2) - 2;
558 for (nbuf
= 0; nbuf
< IOP_MAX_MSG_XFERS
; nbuf
++, p
+= 2) {
560 DPRINTF(("%s: invalid SGL (1)\n",
561 device_xname(&sc
->sc_dv
)));
565 if ((p
[0] & 0x30000000) != I2O_SGL_SIMPLE
) {
566 DPRINTF(("%s: invalid SGL (2)\n",
567 device_xname(&sc
->sc_dv
)));
571 bufs
[nbuf
].db_out
= (p
[0] & I2O_SGL_DATA_OUT
) != 0;
572 bufs
[nbuf
].db_ptr
= NULL
;
574 if ((p
[0] & I2O_SGL_END_BUFFER
) != 0) {
575 if ((p
[0] & 0x00ffffff) > IOP_MAX_XFER
) {
576 DPRINTF(("%s: buffer too large\n",
577 device_xname(&sc
->sc_dv
)));
581 bufs
[nbuf
].db_ptr
= (void *)p
[1];
582 bufs
[nbuf
].db_proc
= proc
;
583 bufs
[nbuf
].db_size
= p
[0] & 0x00ffffff;
585 if ((p
[0] & I2O_SGL_END
) != 0)
592 * The buffer has multiple segments. Determine the
597 for (; p
<= pmax
; p
+= 2) {
598 if (nfrag
== DPTI_MAX_SEGS
) {
599 DPRINTF(("%s: too many segments\n",
600 device_xname(&sc
->sc_dv
)));
604 bufs
[nbuf
].db_frags
[nfrag
].iov_len
=
606 bufs
[nbuf
].db_frags
[nfrag
].iov_base
=
609 sz
+= p
[0] & 0x00ffffff;
612 if ((p
[0] & I2O_SGL_END
) != 0) {
613 if ((p
[0] & I2O_SGL_END_BUFFER
) == 0) {
615 "%s: invalid SGL (3)\n",
616 device_xname(&sc
->sc_dv
)));
621 if ((p
[0] & I2O_SGL_END_BUFFER
) != 0)
624 bufs
[nbuf
].db_nfrag
= nfrag
;
627 DPRINTF(("%s: invalid SGL (4)\n",
628 device_xname(&sc
->sc_dv
)));
632 if (sz
> IOP_MAX_XFER
) {
633 DPRINTF(("%s: buffer too large\n",
634 device_xname(&sc
->sc_dv
)));
638 bufs
[nbuf
].db_size
= sz
;
639 bufs
[nbuf
].db_ptr
= malloc(sz
, M_DEVBUF
, M_WAITOK
);
640 if (bufs
[nbuf
].db_ptr
== NULL
) {
641 DPRINTF(("%s: allocation failure\n",
642 device_xname(&sc
->sc_dv
)));
647 for (i
= 0, sz
= 0; i
< bufs
[nbuf
].db_nfrag
; i
++) {
648 rv
= copyin(bufs
[nbuf
].db_frags
[i
].iov_base
,
649 (char *)bufs
[nbuf
].db_ptr
+ sz
,
650 bufs
[nbuf
].db_frags
[i
].iov_len
);
652 DPRINTF(("%s: frag copyin\n",
653 device_xname(&sc
->sc_dv
)));
656 sz
+= bufs
[nbuf
].db_frags
[i
].iov_len
;
659 if ((p
[0] & I2O_SGL_END
) != 0)
663 if (nbuf
== IOP_MAX_MSG_XFERS
) {
664 DPRINTF(("%s: too many transfers\n",
665 device_xname(&sc
->sc_dv
)));
672 * Allocate a wrapper, and adjust the message header fields to
673 * indicate that no scatter-gather list is currently present.
676 im
= iop_msg_alloc(iop
, IM_WAIT
| IM_NOSTATUS
);
677 im
->im_rb
= (struct i2o_reply
*)rbtmp
;
678 mf
= (struct i2o_msg
*)mbtmp
;
679 mf
->msgictx
= IOP_ICTX
;
680 mf
->msgtctx
= im
->im_tctx
;
683 mf
->msgflags
= (mf
->msgflags
& 0xff0f) | (sgoff
<< 16);
686 * Map the data transfer(s).
688 for (i
= 0; i
<= nbuf
; i
++) {
689 rv
= iop_msg_map(iop
, im
, mbtmp
, bufs
[i
].db_ptr
,
690 bufs
[i
].db_size
, bufs
[i
].db_out
, bufs
[i
].db_proc
);
692 DPRINTF(("%s: msg_map failed, rv = %d\n",
693 device_xname(&sc
->sc_dv
), rv
));
700 * Start the command and sleep until it completes.
702 if ((rv
= iop_msg_post(iop
, im
, mbtmp
, 5*60*1000)) != 0)
706 * Copy out the reply frame.
708 if ((rv
= copyout(rbtmp
, (char *)data
+ msgsize
, repsize
)) != 0) {
709 DPRINTF(("%s: reply copyout() failed\n",
710 device_xname(&sc
->sc_dv
)));
715 * Free resources and return to the caller.
719 iop_msg_unmap(iop
, im
);
720 iop_msg_free(iop
, im
);
723 for (i
= 0; i
<= nbuf
; i
++) {
724 if (bufs
[i
].db_proc
!= NULL
)
727 if (!bufs
[i
].db_out
&& rv
== 0) {
728 for (j
= 0, sz
= 0; j
< bufs
[i
].db_nfrag
; j
++) {
729 rv
= copyout((char *)bufs
[i
].db_ptr
+ sz
,
730 bufs
[i
].db_frags
[j
].iov_base
,
731 bufs
[i
].db_frags
[j
].iov_len
);
734 sz
+= bufs
[i
].db_frags
[j
].iov_len
;
738 if (bufs
[i
].db_ptr
!= NULL
)
739 free(bufs
[i
].db_ptr
, M_DEVBUF
);