1 /* $NetBSD: ld_icp.c,v 1.22 2008/09/09 12:45:39 tron Exp $ */
4 * Copyright (c) 2002 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 * ICP-Vortex "GDT" front-end for ld(4) driver.
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: ld_icp.c,v 1.22 2008/09/09 12:45:39 tron 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>
54 #include <uvm/uvm_extern.h>
58 #include <dev/ldvar.h>
60 #include <dev/ic/icpreg.h>
61 #include <dev/ic/icpvar.h>
64 struct ld_softc sc_ld
;
68 void ld_icp_attach(device_t
, device_t
, void *);
69 int ld_icp_detach(device_t
, int);
70 int ld_icp_dobio(struct ld_icp_softc
*, void *, int, int, int,
72 int ld_icp_dump(struct ld_softc
*, void *, int, int);
73 int ld_icp_flush(struct ld_softc
*, int);
74 void ld_icp_intr(struct icp_ccb
*);
75 int ld_icp_match(device_t
, cfdata_t
, void *);
76 int ld_icp_start(struct ld_softc
*, struct buf
*);
78 void ld_icp_adjqparam(device_t
, int);
80 CFATTACH_DECL_NEW(ld_icp
, sizeof(struct ld_icp_softc
),
81 ld_icp_match
, ld_icp_attach
, ld_icp_detach
, NULL
);
83 static const struct icp_servicecb ld_icp_servicecb
= {
88 ld_icp_match(device_t parent
, cfdata_t match
, void *aux
)
90 struct icp_attach_args
*icpa
;
94 return (icpa
->icpa_unit
< ICPA_UNIT_SCSI
);
98 ld_icp_attach(device_t parent
, device_t self
, void *aux
)
100 struct icp_attach_args
*icpa
= aux
;
101 struct ld_icp_softc
*sc
= device_private(self
);
102 struct ld_softc
*ld
= &sc
->sc_ld
;
103 struct icp_softc
*icp
= device_private(parent
);
104 struct icp_cachedrv
*cd
= &icp
->icp_cdr
[icpa
->icpa_unit
];
105 struct icp_cdevinfo
*cdi
;
111 icp_register_servicecb(icp
, icpa
->icpa_unit
, &ld_icp_servicecb
);
113 sc
->sc_hwunit
= icpa
->icpa_unit
;
114 ld
->sc_maxxfer
= ICP_MAX_XFER
;
115 ld
->sc_secsize
= ICP_SECTOR_SIZE
;
116 ld
->sc_start
= ld_icp_start
;
117 ld
->sc_dump
= ld_icp_dump
;
118 ld
->sc_flush
= ld_icp_flush
;
119 ld
->sc_secperunit
= cd
->cd_size
;
120 ld
->sc_flags
= LDF_ENABLED
;
121 ld
->sc_maxqueuecnt
= icp
->icp_openings
;
123 if (!icp_cmd(icp
, ICP_CACHESERVICE
, ICP_IOCTL
, ICP_CACHE_DRV_INFO
,
124 sc
->sc_hwunit
, sizeof(struct icp_cdevinfo
))) {
125 aprint_error(": unable to retrieve device info\n");
126 ld
->sc_flags
= LDF_ENABLED
;
129 cdi
= (struct icp_cdevinfo
*)icp
->icp_scr
;
131 aprint_normal(": <%.8s>, ", cdi
->ld_name
);
132 t
= le32toh(cdi
->ld_dtype
) >> 16;
137 if (le32toh(cdi
->ld_dcnt
) > 1 || le32toh(cdi
->ld_slave
) != -1)
146 str
= "unknown type";
148 aprint_normal("type: %s, ", str
);
151 * Print device status.
155 else if ((cdi
->ld_error
& 1) != 0) {
157 ld
->sc_flags
= LDF_ENABLED
;
158 } else if ((cdi
->ld_error
& 2) != 0)
162 ld
->sc_flags
= LDF_ENABLED
;
165 aprint_normal("status: %s\n", str
);
172 ld_icp_detach(device_t dv
, int flags
)
176 if ((rv
= ldbegindetach((struct ld_softc
*)dv
, flags
)) != 0)
178 ldenddetach((struct ld_softc
*) dv
);
184 ld_icp_dobio(struct ld_icp_softc
*sc
, void *data
, int datasize
, int blkno
,
185 int dowrite
, struct buf
*bp
)
187 struct icp_cachecmd
*cc
;
189 struct icp_softc
*icp
;
192 icp
= device_private(device_parent(sc
->sc_ld
.sc_dv
));
195 * Allocate a command control block.
197 if (__predict_false((ic
= icp_ccb_alloc(icp
)) == NULL
))
201 * Map the data transfer.
203 cc
= &ic
->ic_cmd
.cmd_packet
.cc
;
204 ic
->ic_sg
= cc
->cc_sg
;
205 ic
->ic_service
= ICP_CACHESERVICE
;
207 rv
= icp_ccb_map(icp
, ic
, data
, datasize
,
208 dowrite
? IC_XFER_OUT
: IC_XFER_IN
);
210 icp_ccb_free(icp
, ic
);
217 ic
->ic_cmd
.cmd_opcode
= htole16((dowrite
? ICP_WRITE
: ICP_READ
));
218 cc
->cc_deviceno
= htole16(sc
->sc_hwunit
);
219 cc
->cc_blockno
= htole32(blkno
);
220 cc
->cc_blockcnt
= htole32(datasize
/ ICP_SECTOR_SIZE
);
221 cc
->cc_addr
= ~0; /* scatter gather */
222 cc
->cc_nsgent
= htole32(ic
->ic_nsgent
);
224 ic
->ic_cmdlen
= (u_long
)ic
->ic_sg
- (u_long
)&ic
->ic_cmd
+
225 ic
->ic_nsgent
* sizeof(*ic
->ic_sg
);
228 * Fire it off to the controller.
232 rv
= icp_ccb_poll(icp
, ic
, 10000);
233 icp_ccb_unmap(icp
, ic
);
234 icp_ccb_free(icp
, ic
);
237 ic
->ic_intr
= ld_icp_intr
;
239 ic
->ic_dv
= sc
->sc_ld
.sc_dv
;
240 icp_ccb_enqueue(icp
, ic
);
247 ld_icp_start(struct ld_softc
*ld
, struct buf
*bp
)
250 return (ld_icp_dobio((struct ld_icp_softc
*)ld
, bp
->b_data
,
251 bp
->b_bcount
, bp
->b_rawblkno
, (bp
->b_flags
& B_READ
) == 0, bp
));
255 ld_icp_dump(struct ld_softc
*ld
, void *data
, int blkno
, int blkcnt
)
258 return (ld_icp_dobio((struct ld_icp_softc
*)ld
, data
,
259 blkcnt
* ld
->sc_secsize
, blkno
, 1, NULL
));
263 ld_icp_flush(struct ld_softc
*ld
, int flags
)
265 struct ld_icp_softc
*sc
;
266 struct icp_softc
*icp
;
267 struct icp_cachecmd
*cc
;
271 sc
= (struct ld_icp_softc
*)ld
;
272 icp
= device_private(device_parent(ld
->sc_dv
));
274 ic
= icp_ccb_alloc_wait(icp
);
275 ic
->ic_cmd
.cmd_opcode
= htole16(ICP_FLUSH
);
277 cc
= &ic
->ic_cmd
.cmd_packet
.cc
;
278 cc
->cc_deviceno
= htole16(sc
->sc_hwunit
);
279 cc
->cc_blockno
= htole32(1);
284 ic
->ic_cmdlen
= (u_long
)&cc
->cc_sg
- (u_long
)&ic
->ic_cmd
;
285 ic
->ic_service
= ICP_CACHESERVICE
;
287 rv
= icp_ccb_wait(icp
, ic
, 30000);
288 icp_ccb_free(icp
, ic
);
294 ld_icp_intr(struct icp_ccb
*ic
)
297 struct ld_icp_softc
*sc
;
298 struct icp_softc
*icp
;
301 sc
= (struct ld_icp_softc
*)device_private(ic
->ic_dv
);
302 icp
= device_private(device_parent(sc
->sc_ld
.sc_dv
));
304 if (ic
->ic_status
!= ICP_S_OK
) {
305 aprint_error_dev(ic
->ic_dv
, "request failed; status=0x%04x\n",
308 bp
->b_resid
= bp
->b_bcount
;
310 icp
->icp_evt
.size
= sizeof(icp
->icp_evt
.eu
.sync
);
311 icp
->icp_evt
.eu
.sync
.ionode
= device_unit(&icp
->icp_dv
);
312 icp
->icp_evt
.eu
.sync
.service
= icp
->icp_service
;
313 icp
->icp_evt
.eu
.sync
.status
= icp
->icp_status
;
314 icp
->icp_evt
.eu
.sync
.info
= icp
->icp_info
;
315 icp
->icp_evt
.eu
.sync
.hostdrive
= sc
->sc_hwunit
;
316 if (icp
->icp_status
>= 0x8000)
317 icp_store_event(icp
, GDT_ES_SYNC
, 0, &icp
->icp_evt
);
319 icp_store_event(icp
, GDT_ES_SYNC
, icp
->icp_service
,
324 icp_ccb_unmap(icp
, ic
);
325 icp_ccb_free(icp
, ic
);
326 lddone(&sc
->sc_ld
, bp
);
330 ld_icp_adjqparam(device_t dv
, int openings
)
333 ldadjqparam((struct ld_softc
*) dv
, openings
);