xref: /netbsd-src/sys/dev/ic/ld_aac.c (revision c2f76ff004a2cb67efe5b12d97bd3ef7fe89e18d)
1 /*	$NetBSD: ld_aac.c,v 1.25 2010/11/13 13:52:01 uebayasi 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.25 2010/11/13 13:52:01 uebayasi Exp $");
34 
35 #include "rnd.h"
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/device.h>
41 #include <sys/buf.h>
42 #include <sys/bufq.h>
43 #include <sys/endian.h>
44 #include <sys/dkio.h>
45 #include <sys/disk.h>
46 #if NRND > 0
47 #include <sys/rnd.h>
48 #endif
49 
50 #include <sys/bus.h>
51 
52 #include <dev/ldvar.h>
53 
54 #include <dev/ic/aacreg.h>
55 #include <dev/ic/aacvar.h>
56 
57 struct ld_aac_softc {
58 	struct	ld_softc sc_ld;
59 	int	sc_hwunit;
60 };
61 
62 static void	ld_aac_attach(device_t, device_t, void *);
63 static void	ld_aac_intr(struct aac_ccb *);
64 static int	ld_aac_dobio(struct ld_aac_softc *, void *, int, daddr_t, int,
65 			     struct buf *);
66 static int	ld_aac_dump(struct ld_softc *, void *, int, int);
67 static int	ld_aac_match(device_t, cfdata_t, void *);
68 static int	ld_aac_start(struct ld_softc *, struct buf *);
69 
70 CFATTACH_DECL_NEW(ld_aac, sizeof(struct ld_aac_softc),
71     ld_aac_match, ld_aac_attach, NULL, NULL);
72 
73 static int
74 ld_aac_match(device_t parent, cfdata_t match, void *aux)
75 {
76 
77 	return (1);
78 }
79 
80 static void
81 ld_aac_attach(device_t parent, device_t self, void *aux)
82 {
83 	struct aac_attach_args *aaca = aux;
84 	struct ld_aac_softc *sc = device_private(self);
85 	struct ld_softc *ld = &sc->sc_ld;
86 	struct aac_softc *aac = device_private(parent);
87 	struct aac_drive *hdr = &aac->sc_hdr[aaca->aaca_unit];
88 
89 	ld->sc_dv = self;
90 
91 	sc->sc_hwunit = aaca->aaca_unit;
92 	ld->sc_flags = LDF_ENABLED;
93 	ld->sc_maxxfer = AAC_MAX_XFER(aac);
94 	ld->sc_secperunit = hdr->hd_size;
95 	ld->sc_secsize = AAC_SECTOR_SIZE;
96 	ld->sc_maxqueuecnt =
97 	    (aac->sc_max_fibs - AAC_NCCBS_RESERVE) / aac->sc_nunits;
98 	ld->sc_start = ld_aac_start;
99 	ld->sc_dump = ld_aac_dump;
100 
101 	aprint_normal(": %s\n",
102 	    aac_describe_code(aac_container_types, hdr->hd_devtype));
103 	ldattach(ld);
104 }
105 
106 static int
107 ld_aac_dobio(struct ld_aac_softc *sc, void *data, int datasize, daddr_t blkno,
108 	     int dowrite, struct buf *bp)
109 {
110 	struct aac_blockread_response *brr;
111 	struct aac_blockwrite_response *bwr;
112 	struct aac_ccb *ac;
113 	struct aac_softc *aac;
114 	struct aac_fib *fib;
115 	bus_dmamap_t xfer;
116 	u_int32_t status;
117 	u_int16_t size;
118 	int s, rv, i;
119 
120 	aac = device_private(device_parent(sc->sc_ld.sc_dv));
121 
122 	/*
123 	 * Allocate a command control block and map the data transfer.
124 	 */
125 	ac = aac_ccb_alloc(aac, (dowrite ? AAC_CCB_DATA_OUT : AAC_CCB_DATA_IN));
126 	if (ac == NULL)
127 		return EBUSY;
128 	ac->ac_data = data;
129 	ac->ac_datalen = datasize;
130 
131 	if ((rv = aac_ccb_map(aac, ac)) != 0) {
132 		aac_ccb_free(aac, ac);
133 		return (rv);
134 	}
135 
136 	/*
137 	 * Build the command.
138 	 */
139 	fib = ac->ac_fib;
140 
141         fib->Header.XferState = htole32(AAC_FIBSTATE_HOSTOWNED |
142 	    AAC_FIBSTATE_INITIALISED | AAC_FIBSTATE_FROMHOST |
143 	    AAC_FIBSTATE_REXPECTED | AAC_FIBSTATE_NORM |
144 	    AAC_FIBSTATE_ASYNC | AAC_FIBSTATE_FAST_RESPONSE );
145 
146 	if (aac->sc_quirks & AAC_QUIRK_RAW_IO) {
147 		struct aac_raw_io *raw;
148 		struct aac_sg_entryraw *sge;
149 		struct aac_sg_tableraw *sgt;
150 
151 		raw = (struct aac_raw_io *)&fib->data[0];
152 		fib->Header.Command = htole16(RawIo);
153 		raw->BlockNumber = htole64(blkno);
154 		raw->ByteCount = htole32(datasize);
155 		raw->ContainerId = htole16(sc->sc_hwunit);
156 		raw->BpTotal = 0;
157 		raw->BpComplete = 0;
158 		size = sizeof(struct aac_raw_io);
159 		sgt = &raw->SgMapRaw;
160 		raw->Flags = (dowrite ? 0 : 1);
161 
162 		xfer = ac->ac_dmamap_xfer;
163 		sgt->SgCount = xfer->dm_nsegs;
164 		sge = sgt->SgEntryRaw;
165 
166 		for (i = 0; i < xfer->dm_nsegs; i++, sge++) {
167 			sge->SgAddress = htole64(xfer->dm_segs[i].ds_addr);
168 			sge->SgByteCount = htole32(xfer->dm_segs[i].ds_len);
169 			sge->Next = 0;
170 			sge->Prev = 0;
171 			sge->Flags = 0;
172 		}
173 		size += xfer->dm_nsegs * sizeof(struct aac_sg_entryraw);
174 		size = sizeof(fib->Header) + size;
175 		fib->Header.Size = htole16(size);
176 	} else if ((aac->sc_quirks & AAC_QUIRK_SG_64BIT) == 0) {
177 		struct aac_blockread *br;
178 		struct aac_blockwrite *bw;
179 		struct aac_sg_entry *sge;
180 		struct aac_sg_table *sgt;
181 
182 		fib->Header.Command = htole16(ContainerCommand);
183 		if (dowrite) {
184 			bw = (struct aac_blockwrite *)&fib->data[0];
185 			bw->Command = htole32(VM_CtBlockWrite);
186 			bw->ContainerId = htole32(sc->sc_hwunit);
187 			bw->BlockNumber = htole32(blkno);
188 			bw->ByteCount = htole32(datasize);
189 			bw->Stable = htole32(CUNSTABLE);
190 			/* CSTABLE sometimes?  FUA? */
191 
192 			size = sizeof(struct aac_blockwrite);
193 			sgt = &bw->SgMap;
194 		} else {
195 			br = (struct aac_blockread *)&fib->data[0];
196 			br->Command = htole32(VM_CtBlockRead);
197 			br->ContainerId = htole32(sc->sc_hwunit);
198 			br->BlockNumber = htole32(blkno);
199 			br->ByteCount = htole32(datasize);
200 
201 			size = sizeof(struct aac_blockread);
202 			sgt = &br->SgMap;
203 		}
204 
205 		xfer = ac->ac_dmamap_xfer;
206 		sgt->SgCount = xfer->dm_nsegs;
207 		sge = sgt->SgEntry;
208 
209 		for (i = 0; i < xfer->dm_nsegs; i++, sge++) {
210 			sge->SgAddress = htole32(xfer->dm_segs[i].ds_addr);
211 			sge->SgByteCount = htole32(xfer->dm_segs[i].ds_len);
212 			AAC_DPRINTF(AAC_D_IO,
213 			    ("#%d va %p pa %" PRIxPADDR " len %zx\n",
214 			    i, data, xfer->dm_segs[i].ds_addr,
215 			    xfer->dm_segs[i].ds_len));
216 		}
217 
218 		size += xfer->dm_nsegs * sizeof(struct aac_sg_entry);
219 		size = sizeof(fib->Header) + size;
220 		fib->Header.Size = htole16(size);
221 	} else {
222 		struct aac_blockread64 *br;
223 		struct aac_blockwrite64 *bw;
224 		struct aac_sg_entry64 *sge;
225 		struct aac_sg_table64 *sgt;
226 
227 		fib->Header.Command = htole16(ContainerCommand64);
228 		if (dowrite) {
229 			bw = (struct aac_blockwrite64 *)&fib->data[0];
230 			bw->Command = htole32(VM_CtHostWrite64);
231 			bw->BlockNumber = htole32(blkno);
232 			bw->ContainerId = htole16(sc->sc_hwunit);
233 			bw->SectorCount = htole16(datasize / AAC_BLOCK_SIZE);
234 			bw->Pad = 0;
235 			bw->Flags = 0;
236 
237 			size = sizeof(struct aac_blockwrite64);
238 			sgt = &bw->SgMap64;
239 		} else {
240 			br = (struct aac_blockread64 *)&fib->data[0];
241 			br->Command = htole32(VM_CtHostRead64);
242 			br->BlockNumber = htole32(blkno);
243 			br->ContainerId = htole16(sc->sc_hwunit);
244 			br->SectorCount = htole16(datasize / AAC_BLOCK_SIZE);
245 			br->Pad = 0;
246 			br->Flags = 0;
247 
248 			size = sizeof(struct aac_blockread64);
249 			sgt = &br->SgMap64;
250 		}
251 
252 		xfer = ac->ac_dmamap_xfer;
253 		sgt->SgCount = xfer->dm_nsegs;
254 		sge = sgt->SgEntry64;
255 
256 		for (i = 0; i < xfer->dm_nsegs; i++, sge++) {
257 			/*
258 			 * XXX - This is probably an alignment issue on non-x86
259 			 * platforms since this is a packed array of 64/32-bit
260 			 * tuples, so every other SgAddress is 32-bit, but not
261 			 * 64-bit aligned.
262 			 */
263 			sge->SgAddress = htole64(xfer->dm_segs[i].ds_addr);
264 			sge->SgByteCount = htole32(xfer->dm_segs[i].ds_len);
265 			AAC_DPRINTF(AAC_D_IO,
266 			    ("#%d va %p pa %" PRIxPADDR " len %zx\n",
267 			    i, data, xfer->dm_segs[i].ds_addr,
268 			    xfer->dm_segs[i].ds_len));
269 		}
270 		size += xfer->dm_nsegs * sizeof(struct aac_sg_entry64);
271 		size = sizeof(fib->Header) + size;
272 		fib->Header.Size = htole16(size);
273 	}
274 
275 	if (bp == NULL) {
276 		/*
277 		 * Polled commands must not sit on the software queue.  Wait
278 		 * up to 30 seconds for the command to complete.
279 		 */
280 		s = splbio();
281 		rv = aac_ccb_poll(aac, ac, 30000);
282 		aac_ccb_unmap(aac, ac);
283 		aac_ccb_free(aac, ac);
284 		splx(s);
285 
286 		if (rv == 0) {
287 			if (dowrite) {
288 				bwr = (struct aac_blockwrite_response *)
289 				    &ac->ac_fib->data[0];
290 				status = le32toh(bwr->Status);
291 			} else {
292 				brr = (struct aac_blockread_response *)
293 				    &ac->ac_fib->data[0];
294 				status = le32toh(brr->Status);
295 			}
296 
297 			if (status != ST_OK) {
298 				aprint_error_dev(sc->sc_ld.sc_dv,
299 				    "I/O error: %s\n",
300 				    aac_describe_code(aac_command_status_table,
301 				    status));
302 				rv = EIO;
303 			}
304 		}
305 	} else {
306 		ac->ac_device = (device_t)sc;
307 		ac->ac_context = bp;
308 		ac->ac_intr = ld_aac_intr;
309 		aac_ccb_enqueue(aac, ac);
310 		rv = 0;
311 	}
312 
313 	return (rv);
314 }
315 
316 static int
317 ld_aac_start(struct ld_softc *ld, struct buf *bp)
318 {
319 
320 	return (ld_aac_dobio((struct ld_aac_softc *)ld, bp->b_data,
321 	    bp->b_bcount, bp->b_rawblkno, (bp->b_flags & B_READ) == 0, bp));
322 }
323 
324 static void
325 ld_aac_intr(struct aac_ccb *ac)
326 {
327 	struct aac_blockread_response *brr;
328 	struct aac_blockwrite_response *bwr;
329 	struct ld_aac_softc *sc;
330 	struct aac_softc *aac;
331 	struct buf *bp;
332 	u_int32_t status;
333 
334 	bp = ac->ac_context;
335 	sc = (struct ld_aac_softc *)ac->ac_device;
336 	aac = device_private(device_parent(sc->sc_ld.sc_dv));
337 
338 	if ((bp->b_flags & B_READ) != 0) {
339 		brr = (struct aac_blockread_response *)&ac->ac_fib->data[0];
340 		status = le32toh(brr->Status);
341 	} else {
342 		bwr = (struct aac_blockwrite_response *)&ac->ac_fib->data[0];
343 		status = le32toh(bwr->Status);
344 	}
345 
346 	aac_ccb_unmap(aac, ac);
347 	aac_ccb_free(aac, ac);
348 
349 	if (status != ST_OK) {
350 		bp->b_error = EIO;
351 		bp->b_resid = bp->b_bcount;
352 
353 		aprint_error_dev(sc->sc_ld.sc_dv, "I/O error: %s\n",
354 		    aac_describe_code(aac_command_status_table, status));
355 	} else
356 		bp->b_resid = 0;
357 
358 	lddone(&sc->sc_ld, bp);
359 }
360 
361 static int
362 ld_aac_dump(struct ld_softc *ld, void *data, int blkno, int blkcnt)
363 {
364 
365 	return (ld_aac_dobio((struct ld_aac_softc *)ld, data,
366 	    blkcnt * ld->sc_secsize, blkno, 1, NULL));
367 }
368