FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/ld_aac.c
1 /* $NetBSD: ld_aac.c,v 1.31 2022/07/30 12:48:17 mlelstv Exp $ */
2
3 /*-
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
18 *
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.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: ld_aac.c,v 1.31 2022/07/30 12:48:17 mlelstv Exp $");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/device.h>
39 #include <sys/buf.h>
40 #include <sys/bufq.h>
41 #include <sys/endian.h>
42 #include <sys/dkio.h>
43 #include <sys/disk.h>
44 #include <sys/module.h>
45
46 #include <sys/bus.h>
47
48 #include <dev/ldvar.h>
49
50 #include <dev/ic/aacreg.h>
51 #include <dev/ic/aacvar.h>
52
53 #include "ioconf.h"
54
55 struct ld_aac_softc {
56 struct ld_softc sc_ld;
57 int sc_hwunit;
58 };
59
60 static void ld_aac_attach(device_t, device_t, void *);
61 static void ld_aac_intr(struct aac_ccb *);
62 static int ld_aac_dobio(struct ld_aac_softc *, void *, int, daddr_t, int,
63 struct buf *);
64 static int ld_aac_dump(struct ld_softc *, void *, int, int);
65 static int ld_aac_match(device_t, cfdata_t, void *);
66 static int ld_aac_start(struct ld_softc *, struct buf *);
67
68 CFATTACH_DECL_NEW(ld_aac, sizeof(struct ld_aac_softc),
69 ld_aac_match, ld_aac_attach, NULL, NULL);
70
71 static int
72 ld_aac_match(device_t parent, cfdata_t match, void *aux)
73 {
74
75 return (1);
76 }
77
78 static void
79 ld_aac_attach(device_t parent, device_t self, void *aux)
80 {
81 struct aac_attach_args *aaca = aux;
82 struct ld_aac_softc *sc = device_private(self);
83 struct ld_softc *ld = &sc->sc_ld;
84 struct aac_softc *aac = device_private(parent);
85 struct aac_drive *hdr = &aac->sc_hdr[aaca->aaca_unit];
86
87 ld->sc_dv = self;
88
89 sc->sc_hwunit = aaca->aaca_unit;
90 ld->sc_flags = LDF_ENABLED;
91 ld->sc_maxxfer = AAC_MAX_XFER(aac);
92 ld->sc_secperunit = hdr->hd_size;
93 ld->sc_secsize = AAC_SECTOR_SIZE;
94 ld->sc_maxqueuecnt =
95 (aac->sc_max_fibs - AAC_NCCBS_RESERVE) / aac->sc_nunits;
96 ld->sc_start = ld_aac_start;
97 ld->sc_dump = ld_aac_dump;
98
99 aprint_normal(": %s\n",
100 aac_describe_code(aac_container_types, hdr->hd_devtype));
101 ldattach(ld, BUFQ_DISK_DEFAULT_STRAT);
102 }
103
104 static int
105 ld_aac_dobio(struct ld_aac_softc *sc, void *data, int datasize, daddr_t blkno,
106 int dowrite, struct buf *bp)
107 {
108 struct aac_blockread_response *brr;
109 struct aac_blockwrite_response *bwr;
110 struct aac_ccb *ac;
111 struct aac_softc *aac;
112 struct aac_fib *fib;
113 bus_dmamap_t xfer;
114 u_int32_t status;
115 u_int16_t size;
116 int s, rv, i;
117
118 aac = device_private(device_parent(sc->sc_ld.sc_dv));
119
120 /*
121 * Allocate a command control block and map the data transfer.
122 */
123 ac = aac_ccb_alloc(aac, (dowrite ? AAC_CCB_DATA_OUT : AAC_CCB_DATA_IN));
124 if (ac == NULL)
125 return EBUSY;
126 ac->ac_data = data;
127 ac->ac_datalen = datasize;
128
129 if ((rv = aac_ccb_map(aac, ac)) != 0) {
130 aac_ccb_free(aac, ac);
131 return (rv);
132 }
133
134 /*
135 * Build the command.
136 */
137 fib = ac->ac_fib;
138
139 fib->Header.XferState = htole32(AAC_FIBSTATE_HOSTOWNED |
140 AAC_FIBSTATE_INITIALISED | AAC_FIBSTATE_FROMHOST |
141 AAC_FIBSTATE_REXPECTED | AAC_FIBSTATE_NORM |
142 AAC_FIBSTATE_ASYNC | AAC_FIBSTATE_FAST_RESPONSE );
143
144 if (aac->sc_quirks & AAC_QUIRK_RAW_IO) {
145 struct aac_raw_io *raw;
146 struct aac_sg_entryraw *sge;
147 struct aac_sg_tableraw *sgt;
148
149 raw = (struct aac_raw_io *)&fib->data[0];
150 fib->Header.Command = htole16(RawIo);
151 raw->BlockNumber = htole64(blkno);
152 raw->ByteCount = htole32(datasize);
153 raw->ContainerId = htole16(sc->sc_hwunit);
154 raw->BpTotal = 0;
155 raw->BpComplete = 0;
156 size = sizeof(struct aac_raw_io);
157 sgt = &raw->SgMapRaw;
158 raw->Flags = (dowrite ? 0 : 1);
159
160 xfer = ac->ac_dmamap_xfer;
161 sgt->SgCount = xfer->dm_nsegs;
162 sge = sgt->SgEntryRaw;
163
164 for (i = 0; i < xfer->dm_nsegs; i++, sge++) {
165 sge->SgAddress = htole64(xfer->dm_segs[i].ds_addr);
166 sge->SgByteCount = htole32(xfer->dm_segs[i].ds_len);
167 sge->Next = 0;
168 sge->Prev = 0;
169 sge->Flags = 0;
170 }
171 size += xfer->dm_nsegs * sizeof(struct aac_sg_entryraw);
172 size = sizeof(fib->Header) + size;
173 fib->Header.Size = htole16(size);
174 } else if ((aac->sc_quirks & AAC_QUIRK_SG_64BIT) == 0) {
175 struct aac_blockread *br;
176 struct aac_blockwrite *bw;
177 struct aac_sg_entry *sge;
178 struct aac_sg_table *sgt;
179
180 fib->Header.Command = htole16(ContainerCommand);
181 if (dowrite) {
182 bw = (struct aac_blockwrite *)&fib->data[0];
183 bw->Command = htole32(VM_CtBlockWrite);
184 bw->ContainerId = htole32(sc->sc_hwunit);
185 bw->BlockNumber = htole32(blkno);
186 bw->ByteCount = htole32(datasize);
187 bw->Stable = htole32(CUNSTABLE);
188 /* CSTABLE sometimes? FUA? */
189
190 size = sizeof(struct aac_blockwrite);
191 sgt = &bw->SgMap;
192 } else {
193 br = (struct aac_blockread *)&fib->data[0];
194 br->Command = htole32(VM_CtBlockRead);
195 br->ContainerId = htole32(sc->sc_hwunit);
196 br->BlockNumber = htole32(blkno);
197 br->ByteCount = htole32(datasize);
198
199 size = sizeof(struct aac_blockread);
200 sgt = &br->SgMap;
201 }
202
203 xfer = ac->ac_dmamap_xfer;
204 sgt->SgCount = xfer->dm_nsegs;
205 sge = sgt->SgEntry;
206
207 for (i = 0; i < xfer->dm_nsegs; i++, sge++) {
208 sge->SgAddress = htole32(xfer->dm_segs[i].ds_addr);
209 sge->SgByteCount = htole32(xfer->dm_segs[i].ds_len);
210 AAC_DPRINTF(AAC_D_IO,
211 ("#%d va %p pa %" PRIxPADDR " len %zx\n",
212 i, data, xfer->dm_segs[i].ds_addr,
213 xfer->dm_segs[i].ds_len));
214 }
215
216 size += xfer->dm_nsegs * sizeof(struct aac_sg_entry);
217 size = sizeof(fib->Header) + size;
218 fib->Header.Size = htole16(size);
219 } else {
220 struct aac_blockread64 *br;
221 struct aac_blockwrite64 *bw;
222 struct aac_sg_entry64 *sge;
223 struct aac_sg_table64 *sgt;
224
225 fib->Header.Command = htole16(ContainerCommand64);
226 if (dowrite) {
227 bw = (struct aac_blockwrite64 *)&fib->data[0];
228 bw->Command = htole32(VM_CtHostWrite64);
229 bw->BlockNumber = htole32(blkno);
230 bw->ContainerId = htole16(sc->sc_hwunit);
231 bw->SectorCount = htole16(datasize / AAC_BLOCK_SIZE);
232 bw->Pad = 0;
233 bw->Flags = 0;
234
235 size = sizeof(struct aac_blockwrite64);
236 sgt = &bw->SgMap64;
237 } else {
238 br = (struct aac_blockread64 *)&fib->data[0];
239 br->Command = htole32(VM_CtHostRead64);
240 br->BlockNumber = htole32(blkno);
241 br->ContainerId = htole16(sc->sc_hwunit);
242 br->SectorCount = htole16(datasize / AAC_BLOCK_SIZE);
243 br->Pad = 0;
244 br->Flags = 0;
245
246 size = sizeof(struct aac_blockread64);
247 sgt = &br->SgMap64;
248 }
249
250 xfer = ac->ac_dmamap_xfer;
251 sgt->SgCount = xfer->dm_nsegs;
252 sge = sgt->SgEntry64;
253
254 for (i = 0; i < xfer->dm_nsegs; i++, sge++) {
255 /*
256 * XXX - This is probably an alignment issue on non-x86
257 * platforms since this is a packed array of 64/32-bit
258 * tuples, so every other SgAddress is 32-bit, but not
259 * 64-bit aligned.
260 */
261 sge->SgAddress = htole64(xfer->dm_segs[i].ds_addr);
262 sge->SgByteCount = htole32(xfer->dm_segs[i].ds_len);
263 AAC_DPRINTF(AAC_D_IO,
264 ("#%d va %p pa %" PRIxPADDR " len %zx\n",
265 i, data, xfer->dm_segs[i].ds_addr,
266 xfer->dm_segs[i].ds_len));
267 }
268 size += xfer->dm_nsegs * sizeof(struct aac_sg_entry64);
269 size = sizeof(fib->Header) + size;
270 fib->Header.Size = htole16(size);
271 }
272
273 if (bp == NULL) {
274 /*
275 * Polled commands must not sit on the software queue. Wait
276 * up to 30 seconds for the command to complete.
277 */
278 s = splbio();
279 rv = aac_ccb_poll(aac, ac, 30000);
280 aac_ccb_unmap(aac, ac);
281 aac_ccb_free(aac, ac);
282 splx(s);
283
284 if (rv == 0) {
285 if (dowrite) {
286 bwr = (struct aac_blockwrite_response *)
287 &ac->ac_fib->data[0];
288 status = le32toh(bwr->Status);
289 } else {
290 brr = (struct aac_blockread_response *)
291 &ac->ac_fib->data[0];
292 status = le32toh(brr->Status);
293 }
294
295 if (status != ST_OK) {
296 device_printf(sc->sc_ld.sc_dv,
297 "I/O error: %s\n",
298 aac_describe_code(aac_command_status_table,
299 status));
300 rv = EIO;
301 }
302 }
303 } else {
304 ac->ac_device = sc->sc_ld.sc_dv;
305 ac->ac_context = bp;
306 ac->ac_intr = ld_aac_intr;
307 aac_ccb_enqueue(aac, ac);
308 rv = 0;
309 }
310
311 return (rv);
312 }
313
314 static int
315 ld_aac_start(struct ld_softc *ld, struct buf *bp)
316 {
317
318 return (ld_aac_dobio((struct ld_aac_softc *)ld, bp->b_data,
319 bp->b_bcount, bp->b_rawblkno, (bp->b_flags & B_READ) == 0, bp));
320 }
321
322 static void
323 ld_aac_intr(struct aac_ccb *ac)
324 {
325 struct aac_blockread_response *brr;
326 struct aac_blockwrite_response *bwr;
327 struct ld_aac_softc *sc;
328 struct aac_softc *aac;
329 struct buf *bp;
330 u_int32_t status;
331
332 bp = ac->ac_context;
333 sc = device_private(ac->ac_device);
334 aac = device_private(device_parent(ac->ac_device));
335
336 if ((bp->b_flags & B_READ) != 0) {
337 brr = (struct aac_blockread_response *)&ac->ac_fib->data[0];
338 status = le32toh(brr->Status);
339 } else {
340 bwr = (struct aac_blockwrite_response *)&ac->ac_fib->data[0];
341 status = le32toh(bwr->Status);
342 }
343
344 aac_ccb_unmap(aac, ac);
345 aac_ccb_free(aac, ac);
346
347 if (status != ST_OK) {
348 bp->b_error = EIO;
349 bp->b_resid = bp->b_bcount;
350
351 device_printf(sc->sc_ld.sc_dv, "I/O error: %s\n",
352 aac_describe_code(aac_command_status_table, status));
353 } else
354 bp->b_resid = 0;
355
356 lddone(&sc->sc_ld, bp);
357 }
358
359 static int
360 ld_aac_dump(struct ld_softc *ld, void *data, int blkno, int blkcnt)
361 {
362
363 return (ld_aac_dobio((struct ld_aac_softc *)ld, data,
364 blkcnt * ld->sc_secsize, blkno, 1, NULL));
365 }
366
367 MODULE(MODULE_CLASS_DRIVER, ld_aac, "ld,aac");
368
369 #ifdef _MODULE
370 /*
371 * XXX Don't allow ioconf.c to redefine the "struct cfdriver ld_cd"
372 * XXX it will be defined in the common-code module
373 */
374 #undef CFDRIVER_DECL
375 #define CFDRIVER_DECL(name, class, attr)
376 #include "ioconf.c"
377 #endif
378
379 static int
380 ld_aac_modcmd(modcmd_t cmd, void *opaque)
381 {
382 #ifdef _MODULE
383 /*
384 * We ignore the cfdriver_vec[] that ioconf provides, since
385 * the cfdrivers are attached already.
386 */
387 static struct cfdriver * const no_cfdriver_vec[] = { NULL };
388 #endif
389 int error = 0;
390
391 #ifdef _MODULE
392 switch (cmd) {
393 case MODULE_CMD_INIT:
394 error = config_init_component(no_cfdriver_vec,
395 cfattach_ioconf_ld_aac, cfdata_ioconf_ld_aac);
396 break;
397 case MODULE_CMD_FINI:
398 error = config_fini_component(no_cfdriver_vec,
399 cfattach_ioconf_ld_aac, cfdata_ioconf_ld_aac);
400 break;
401 default:
402 error = ENOTTY;
403 break;
404 }
405 #endif
406
407 return error;
408 }
409
Cache object: 4419cd206f68d25de9daec3721c7b618
|