1 /* $NetBSD: ld_cac.c,v 1.24 2009/03/21 19:44:26 ad Exp $ */
4 * Copyright (c) 2000, 2006 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 * Compaq array controller front-end for ld(4) driver.
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: ld_cac.c,v 1.24 2009/03/21 19:44:26 ad Exp $");
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/device.h>
47 #include <sys/endian.h>
56 #include <dev/ldvar.h>
58 #include <dev/ic/cacreg.h>
59 #include <dev/ic/cacvar.h>
62 struct ld_softc sc_ld
;
66 struct timeval sc_serrtm
;
69 void ld_cac_attach(device_t
, device_t
, void *);
70 void ld_cac_done(device_t
, void *, int);
71 int ld_cac_dump(struct ld_softc
*, void *, int, int);
72 int ld_cac_match(device_t
, cfdata_t
, void *);
73 int ld_cac_start(struct ld_softc
*, struct buf
*);
75 static const struct timeval ld_cac_serrintvl
= { 60, 0 };
77 CFATTACH_DECL_NEW(ld_cac
, sizeof(struct ld_cac_softc
),
78 ld_cac_match
, ld_cac_attach
, NULL
, NULL
);
81 ld_cac_match(device_t parent
, cfdata_t match
, void *aux
)
88 ld_cac_attach(device_t parent
, device_t self
, void *aux
)
90 struct cac_drive_info dinfo
;
91 struct cac_attach_args
*caca
;
92 struct ld_cac_softc
*sc
= device_private(self
);
93 struct cac_softc
*cac
= device_private(parent
);
94 struct ld_softc
*ld
= &sc
->sc_ld
;
99 sc
->sc_mutex
= &cac
->sc_mutex
;
100 sc
->sc_hwunit
= caca
->caca_unit
;
102 if (cac_cmd(cac
, CAC_CMD_GET_LOG_DRV_INFO
, &dinfo
, sizeof(dinfo
),
103 sc
->sc_hwunit
, 0, CAC_CCB_DATA_IN
, NULL
)) {
104 aprint_error(": CMD_GET_LOG_DRV_INFO failed\n");
108 ld
->sc_secsize
= CAC_GET2(dinfo
.secsize
);
109 ld
->sc_maxxfer
= CAC_MAX_XFER
;
110 ld
->sc_maxqueuecnt
= CAC_MAX_CCBS
/ cac
->sc_nunits
; /* XXX */
111 ld
->sc_secperunit
= CAC_GET2(dinfo
.ncylinders
) *
112 CAC_GET1(dinfo
.nheads
) * CAC_GET1(dinfo
.nsectors
);
113 ld
->sc_start
= ld_cac_start
;
114 ld
->sc_dump
= ld_cac_dump
;
116 switch (CAC_GET1(dinfo
.mirror
)) {
118 type
= "standalone disk or RAID0";
130 type
= "unknown type of";
134 aprint_normal(": %s array\n", type
);
136 /* XXX We should verify this... */
137 ld
->sc_flags
= LDF_ENABLED
;
142 ld_cac_start(struct ld_softc
*ld
, struct buf
*bp
)
145 struct cac_softc
*cac
;
146 struct ld_cac_softc
*sc
;
147 struct cac_context cc
;
149 sc
= (struct ld_cac_softc
*)ld
;
150 cac
= device_private(device_parent(ld
->sc_dv
));
152 cc
.cc_handler
= ld_cac_done
;
154 cc
.cc_dv
= ld
->sc_dv
;
156 if ((bp
->b_flags
& B_READ
) == 0) {
158 flags
= CAC_CCB_DATA_OUT
;
161 flags
= CAC_CCB_DATA_IN
;
164 return (cac_cmd(cac
, cmd
, bp
->b_data
, bp
->b_bcount
, sc
->sc_hwunit
,
165 bp
->b_rawblkno
, flags
, &cc
));
169 ld_cac_dump(struct ld_softc
*ld
, void *data
, int blkno
, int blkcnt
)
171 struct ld_cac_softc
*sc
;
173 sc
= (struct ld_cac_softc
*)ld
;
175 return (cac_cmd(device_private(device_parent(ld
->sc_dv
)),
176 CAC_CMD_WRITE_MEDIA
, data
, blkcnt
* ld
->sc_secsize
,
177 sc
->sc_hwunit
, blkno
, CAC_CCB_DATA_OUT
, NULL
));
181 ld_cac_done(device_t dv
, void *context
, int error
)
184 struct ld_cac_softc
*sc
;
189 sc
= device_private(dv
);
191 if ((error
& CAC_RET_CMD_REJECTED
) == CAC_RET_CMD_REJECTED
) {
192 aprint_error_dev(dv
, "command rejected\n");
195 if (rv
== 0 && (error
& CAC_RET_INVAL_BLOCK
) != 0) {
196 aprint_error_dev(dv
, "invalid request block\n");
199 if (rv
== 0 && (error
& CAC_RET_HARD_ERROR
) != 0) {
200 aprint_error_dev(dv
, "hard error\n");
203 if (rv
== 0 && (error
& CAC_RET_SOFT_ERROR
) != 0) {
205 if (ratecheck(&sc
->sc_serrtm
, &ld_cac_serrintvl
)) {
208 "%d soft errors; array may be degraded\n",
215 bp
->b_resid
= bp
->b_bcount
;
219 mutex_exit(sc
->sc_mutex
);
220 lddone(&sc
->sc_ld
, bp
);
221 mutex_enter(sc
->sc_mutex
);