1 /* $NetBSD: ld_aac.c,v 1.22 2008/10/02 08:21:57 sborrill 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.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: ld_aac.c,v 1.22 2008/10/02 08:21:57 sborrill Exp $");
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/device.h>
43 #include <sys/endian.h>
52 #include <uvm/uvm_extern.h>
54 #include <dev/ldvar.h>
56 #include <dev/ic/aacreg.h>
57 #include <dev/ic/aacvar.h>
60 struct ld_softc sc_ld
;
64 static void ld_aac_attach(device_t
, device_t
, void *);
65 static void ld_aac_intr(struct aac_ccb
*);
66 static int ld_aac_dobio(struct ld_aac_softc
*, void *, int, daddr_t
, int,
68 static int ld_aac_dump(struct ld_softc
*, void *, int, int);
69 static int ld_aac_match(device_t
, cfdata_t
, void *);
70 static int ld_aac_start(struct ld_softc
*, struct buf
*);
72 CFATTACH_DECL_NEW(ld_aac
, sizeof(struct ld_aac_softc
),
73 ld_aac_match
, ld_aac_attach
, NULL
, NULL
);
76 ld_aac_match(device_t parent
, cfdata_t match
, void *aux
)
83 ld_aac_attach(device_t parent
, device_t self
, void *aux
)
85 struct aac_attach_args
*aaca
= aux
;
86 struct ld_aac_softc
*sc
= device_private(self
);
87 struct ld_softc
*ld
= &sc
->sc_ld
;
88 struct aac_softc
*aac
= device_private(parent
);
89 struct aac_drive
*hdr
= &aac
->sc_hdr
[aaca
->aaca_unit
];
93 sc
->sc_hwunit
= aaca
->aaca_unit
;
94 ld
->sc_flags
= LDF_ENABLED
;
95 ld
->sc_maxxfer
= AAC_MAX_XFER(aac
);
96 ld
->sc_secperunit
= hdr
->hd_size
;
97 ld
->sc_secsize
= AAC_SECTOR_SIZE
;
99 (aac
->sc_max_fibs
- AAC_NCCBS_RESERVE
) / aac
->sc_nunits
;
100 ld
->sc_start
= ld_aac_start
;
101 ld
->sc_dump
= ld_aac_dump
;
103 aprint_normal(": %s\n",
104 aac_describe_code(aac_container_types
, hdr
->hd_devtype
));
109 ld_aac_dobio(struct ld_aac_softc
*sc
, void *data
, int datasize
, daddr_t blkno
,
110 int dowrite
, struct buf
*bp
)
112 struct aac_blockread_response
*brr
;
113 struct aac_blockwrite_response
*bwr
;
115 struct aac_softc
*aac
;
122 aac
= device_private(device_parent(sc
->sc_ld
.sc_dv
));
125 * Allocate a command control block and map the data transfer.
127 ac
= aac_ccb_alloc(aac
, (dowrite
? AAC_CCB_DATA_OUT
: AAC_CCB_DATA_IN
));
131 ac
->ac_datalen
= datasize
;
133 if ((rv
= aac_ccb_map(aac
, ac
)) != 0) {
134 aac_ccb_free(aac
, ac
);
143 fib
->Header
.XferState
= htole32(AAC_FIBSTATE_HOSTOWNED
|
144 AAC_FIBSTATE_INITIALISED
| AAC_FIBSTATE_FROMHOST
|
145 AAC_FIBSTATE_REXPECTED
| AAC_FIBSTATE_NORM
|
146 AAC_FIBSTATE_ASYNC
| AAC_FIBSTATE_FAST_RESPONSE
);
148 if (aac
->sc_quirks
& AAC_QUIRK_RAW_IO
) {
149 struct aac_raw_io
*raw
;
150 struct aac_sg_entryraw
*sge
;
151 struct aac_sg_tableraw
*sgt
;
153 raw
= (struct aac_raw_io
*)&fib
->data
[0];
154 fib
->Header
.Command
= htole16(RawIo
);
155 raw
->BlockNumber
= htole64(blkno
);
156 raw
->ByteCount
= htole32(datasize
);
157 raw
->ContainerId
= htole16(sc
->sc_hwunit
);
160 size
= sizeof(struct aac_raw_io
);
161 sgt
= &raw
->SgMapRaw
;
162 raw
->Flags
= (dowrite
? 0 : 1);
164 xfer
= ac
->ac_dmamap_xfer
;
165 sgt
->SgCount
= xfer
->dm_nsegs
;
166 sge
= sgt
->SgEntryRaw
;
168 for (i
= 0; i
< xfer
->dm_nsegs
; i
++, sge
++) {
169 sge
->SgAddress
= htole64(xfer
->dm_segs
[i
].ds_addr
);
170 sge
->SgByteCount
= htole32(xfer
->dm_segs
[i
].ds_len
);
175 size
+= xfer
->dm_nsegs
* sizeof(struct aac_sg_entryraw
);
176 size
= sizeof(fib
->Header
) + size
;
177 fib
->Header
.Size
= htole16(size
);
178 } else if ((aac
->sc_quirks
& AAC_QUIRK_SG_64BIT
) == 0) {
179 struct aac_blockread
*br
;
180 struct aac_blockwrite
*bw
;
181 struct aac_sg_entry
*sge
;
182 struct aac_sg_table
*sgt
;
184 fib
->Header
.Command
= htole16(ContainerCommand
);
186 bw
= (struct aac_blockwrite
*)&fib
->data
[0];
187 bw
->Command
= htole32(VM_CtBlockWrite
);
188 bw
->ContainerId
= htole32(sc
->sc_hwunit
);
189 bw
->BlockNumber
= htole32(blkno
);
190 bw
->ByteCount
= htole32(datasize
);
191 bw
->Stable
= htole32(CUNSTABLE
);
192 /* CSTABLE sometimes? FUA? */
194 size
= sizeof(struct aac_blockwrite
);
197 br
= (struct aac_blockread
*)&fib
->data
[0];
198 br
->Command
= htole32(VM_CtBlockRead
);
199 br
->ContainerId
= htole32(sc
->sc_hwunit
);
200 br
->BlockNumber
= htole32(blkno
);
201 br
->ByteCount
= htole32(datasize
);
203 size
= sizeof(struct aac_blockread
);
207 xfer
= ac
->ac_dmamap_xfer
;
208 sgt
->SgCount
= xfer
->dm_nsegs
;
211 for (i
= 0; i
< xfer
->dm_nsegs
; i
++, sge
++) {
212 sge
->SgAddress
= htole32(xfer
->dm_segs
[i
].ds_addr
);
213 sge
->SgByteCount
= htole32(xfer
->dm_segs
[i
].ds_len
);
214 AAC_DPRINTF(AAC_D_IO
,
215 ("#%d va %p pa %lx len %lx\n", i
, data
,
216 (u_long
)xfer
->dm_segs
[i
].ds_addr
,
217 (u_long
)xfer
->dm_segs
[i
].ds_len
));
220 size
+= xfer
->dm_nsegs
* sizeof(struct aac_sg_entry
);
221 size
= sizeof(fib
->Header
) + size
;
222 fib
->Header
.Size
= htole16(size
);
224 struct aac_blockread64
*br
;
225 struct aac_blockwrite64
*bw
;
226 struct aac_sg_entry64
*sge
;
227 struct aac_sg_table64
*sgt
;
229 fib
->Header
.Command
= htole16(ContainerCommand64
);
231 bw
= (struct aac_blockwrite64
*)&fib
->data
[0];
232 bw
->Command
= htole32(VM_CtHostWrite64
);
233 bw
->BlockNumber
= htole32(blkno
);
234 bw
->ContainerId
= htole16(sc
->sc_hwunit
);
235 bw
->SectorCount
= htole16(datasize
/ AAC_BLOCK_SIZE
);
239 size
= sizeof(struct aac_blockwrite64
);
242 br
= (struct aac_blockread64
*)&fib
->data
[0];
243 br
->Command
= htole32(VM_CtHostRead64
);
244 br
->BlockNumber
= htole32(blkno
);
245 br
->ContainerId
= htole16(sc
->sc_hwunit
);
246 br
->SectorCount
= htole16(datasize
/ AAC_BLOCK_SIZE
);
250 size
= sizeof(struct aac_blockread64
);
254 xfer
= ac
->ac_dmamap_xfer
;
255 sgt
->SgCount
= xfer
->dm_nsegs
;
256 sge
= sgt
->SgEntry64
;
258 for (i
= 0; i
< xfer
->dm_nsegs
; i
++, sge
++) {
260 * XXX - This is probably an alignment issue on non-x86
261 * platforms since this is a packed array of 64/32-bit
262 * tuples, so every other SgAddress is 32-bit, but not
265 sge
->SgAddress
= htole64(xfer
->dm_segs
[i
].ds_addr
);
266 sge
->SgByteCount
= htole32(xfer
->dm_segs
[i
].ds_len
);
267 AAC_DPRINTF(AAC_D_IO
,
268 ("#%d va %p pa %llx len %lx\n", i
, data
,
269 (u_int64_t
)xfer
->dm_segs
[i
].ds_addr
,
270 (u_long
)xfer
->dm_segs
[i
].ds_len
));
272 size
+= xfer
->dm_nsegs
* sizeof(struct aac_sg_entry64
);
273 size
= sizeof(fib
->Header
) + size
;
274 fib
->Header
.Size
= htole16(size
);
279 * Polled commands must not sit on the software queue. Wait
280 * up to 30 seconds for the command to complete.
283 rv
= aac_ccb_poll(aac
, ac
, 30000);
284 aac_ccb_unmap(aac
, ac
);
285 aac_ccb_free(aac
, ac
);
290 bwr
= (struct aac_blockwrite_response
*)
291 &ac
->ac_fib
->data
[0];
292 status
= le32toh(bwr
->Status
);
294 brr
= (struct aac_blockread_response
*)
295 &ac
->ac_fib
->data
[0];
296 status
= le32toh(brr
->Status
);
299 if (status
!= ST_OK
) {
300 aprint_error_dev(sc
->sc_ld
.sc_dv
,
302 aac_describe_code(aac_command_status_table
,
308 ac
->ac_device
= (device_t
)sc
;
310 ac
->ac_intr
= ld_aac_intr
;
311 aac_ccb_enqueue(aac
, ac
);
319 ld_aac_start(struct ld_softc
*ld
, struct buf
*bp
)
322 return (ld_aac_dobio((struct ld_aac_softc
*)ld
, bp
->b_data
,
323 bp
->b_bcount
, bp
->b_rawblkno
, (bp
->b_flags
& B_READ
) == 0, bp
));
327 ld_aac_intr(struct aac_ccb
*ac
)
329 struct aac_blockread_response
*brr
;
330 struct aac_blockwrite_response
*bwr
;
331 struct ld_aac_softc
*sc
;
332 struct aac_softc
*aac
;
337 sc
= (struct ld_aac_softc
*)ac
->ac_device
;
338 aac
= device_private(device_parent(sc
->sc_ld
.sc_dv
));
340 if ((bp
->b_flags
& B_READ
) != 0) {
341 brr
= (struct aac_blockread_response
*)&ac
->ac_fib
->data
[0];
342 status
= le32toh(brr
->Status
);
344 bwr
= (struct aac_blockwrite_response
*)&ac
->ac_fib
->data
[0];
345 status
= le32toh(bwr
->Status
);
348 aac_ccb_unmap(aac
, ac
);
349 aac_ccb_free(aac
, ac
);
351 if (status
!= ST_OK
) {
353 bp
->b_resid
= bp
->b_bcount
;
355 aprint_error_dev(sc
->sc_ld
.sc_dv
, "I/O error: %s\n",
356 aac_describe_code(aac_command_status_table
, status
));
360 lddone(&sc
->sc_ld
, bp
);
364 ld_aac_dump(struct ld_softc
*ld
, void *data
, int blkno
, int blkcnt
)
367 return (ld_aac_dobio((struct ld_aac_softc
*)ld
, data
,
368 blkcnt
* ld
->sc_secsize
, blkno
, 1, NULL
));