1 /* $NetBSD: ld_aac.c,v 1.2 2002/05/02 12:44:31 ad 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: ld_aac.c,v 1.2 2002/05/02 12:44:31 ad Exp $"); 41 42 #include "rnd.h" 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/kernel.h> 47 #include <sys/device.h> 48 #include <sys/buf.h> 49 #include <sys/endian.h> 50 #include <sys/dkio.h> 51 #include <sys/disk.h> 52 #if NRND > 0 53 #include <sys/rnd.h> 54 #endif 55 56 #include <machine/bus.h> 57 58 #include <uvm/uvm_extern.h> 59 60 #include <dev/ldvar.h> 61 62 #include <dev/ic/aacreg.h> 63 #include <dev/ic/aacvar.h> 64 65 struct ld_aac_softc { 66 struct ld_softc sc_ld; 67 int sc_hwunit; 68 }; 69 70 static void ld_aac_attach(struct device *, struct device *, void *); 71 static void ld_aac_intr(struct aac_ccb *); 72 static int ld_aac_dobio(struct ld_aac_softc *, void *, int, int, int, 73 struct buf *); 74 static int ld_aac_dump(struct ld_softc *, void *, int, int); 75 static int ld_aac_match(struct device *, struct cfdata *, void *); 76 static int ld_aac_start(struct ld_softc *, struct buf *); 77 78 struct cfattach ld_aac_ca = { 79 sizeof(struct ld_aac_softc), ld_aac_match, ld_aac_attach 80 }; 81 82 static int 83 ld_aac_match(struct device *parent, struct cfdata *match, void *aux) 84 { 85 86 return (1); 87 } 88 89 static void 90 ld_aac_attach(struct device *parent, struct device *self, void *aux) 91 { 92 struct aac_attach_args *aaca; 93 struct aac_drive *hdr; 94 struct ld_aac_softc *sc; 95 struct ld_softc *ld; 96 struct aac_softc *aac; 97 98 aaca = aux; 99 aac = (struct aac_softc *)parent; 100 sc = (struct ld_aac_softc *)self; 101 ld = &sc->sc_ld; 102 hdr = &aac->sc_hdr[aaca->aaca_unit]; 103 104 sc->sc_hwunit = aaca->aaca_unit; 105 ld->sc_flags = LDF_ENABLED; 106 ld->sc_maxxfer = AAC_MAX_XFER; 107 ld->sc_secperunit = hdr->hd_size; 108 ld->sc_secsize = AAC_SECTOR_SIZE; 109 ld->sc_maxqueuecnt = (AAC_NCCBS - AAC_NCCBS_RESERVE) / aac->sc_nunits; 110 ld->sc_start = ld_aac_start; 111 ld->sc_dump = ld_aac_dump; 112 113 printf(": %s\n", 114 aac_describe_code(aac_container_types, hdr->hd_devtype)); 115 ldattach(ld); 116 } 117 118 static int 119 ld_aac_dobio(struct ld_aac_softc *sc, void *data, int datasize, int blkno, 120 int dowrite, struct buf *bp) 121 { 122 struct aac_blockread_response *brr; 123 struct aac_blockwrite_response *bwr; 124 struct aac_ccb *ac; 125 struct aac_softc *aac; 126 struct aac_blockread *br; 127 struct aac_blockwrite *bw; 128 struct aac_sg_entry *sge; 129 struct aac_sg_table *sgt; 130 struct aac_fib *fib; 131 bus_dmamap_t xfer; 132 u_int32_t status; 133 u_int16_t size; 134 int s, rv, i; 135 136 aac = (struct aac_softc *)sc->sc_ld.sc_dv.dv_parent; 137 138 /* 139 * Allocate a command control block and map the data transfer. 140 */ 141 ac = aac_ccb_alloc(aac, (dowrite ? AAC_CCB_DATA_OUT : AAC_CCB_DATA_IN)); 142 ac->ac_data = data; 143 ac->ac_datalen = datasize; 144 145 if ((rv = aac_ccb_map(aac, ac)) != 0) { 146 aac_ccb_free(aac, ac); 147 return (rv); 148 } 149 150 /* 151 * Build the command. 152 */ 153 fib = ac->ac_fib; 154 155 fib->Header.XferState = htole32(AAC_FIBSTATE_HOSTOWNED | 156 AAC_FIBSTATE_INITIALISED | AAC_FIBSTATE_FROMHOST | 157 AAC_FIBSTATE_REXPECTED | AAC_FIBSTATE_NORM); 158 fib->Header.Command = htole16(ContainerCommand); 159 160 if (dowrite) { 161 bw = (struct aac_blockwrite *)&fib->data[0]; 162 bw->Command = htole32(VM_CtBlockWrite); 163 bw->ContainerId = htole32(sc->sc_hwunit); 164 bw->BlockNumber = htole32(blkno); 165 bw->ByteCount = htole32(datasize); 166 bw->Stable = htole32(CUNSTABLE); /* XXX what's appropriate here? */ 167 168 size = sizeof(struct aac_blockwrite); 169 sgt = &bw->SgMap; 170 } else { 171 br = (struct aac_blockread *)&fib->data[0]; 172 br->Command = htole32(VM_CtBlockRead); 173 br->ContainerId = htole32(sc->sc_hwunit); 174 br->BlockNumber = htole32(blkno); 175 br->ByteCount = htole32(datasize); 176 177 size = sizeof(struct aac_blockread); 178 sgt = &br->SgMap; 179 } 180 181 xfer = ac->ac_dmamap_xfer; 182 sgt->SgCount = xfer->dm_nsegs; 183 sge = sgt->SgEntry; 184 185 for (i = 0; i < xfer->dm_nsegs; i++, sge++) { 186 sge->SgAddress = htole32(xfer->dm_segs[i].ds_addr); 187 sge->SgByteCount = htole32(xfer->dm_segs[i].ds_len); 188 AAC_DPRINTF(AAC_D_IO, 189 ("#%d va %p pa %lx len %x\n", i, data, 190 (u_long)xfer->dm_segs[i].ds_addr, 191 xfer->dm_segs[i].ds_len)); 192 } 193 194 size += xfer->dm_nsegs * sizeof(struct aac_sg_entry); 195 size = htole16(sizeof(fib->Header) + size); 196 fib->Header.Size = htole16(size); 197 198 if (bp == NULL) { 199 /* 200 * Polled commands must not sit on the software queue. Wait 201 * up to 30 seconds for the command to complete. 202 */ 203 s = splbio(); 204 rv = aac_ccb_poll(aac, ac, 30000); 205 aac_ccb_unmap(aac, ac); 206 aac_ccb_free(aac, ac); 207 splx(s); 208 209 if (rv == 0) { 210 if (dowrite) { 211 bwr = (struct aac_blockwrite_response *) 212 &ac->ac_fib->data[0]; 213 status = le32toh(bwr->Status); 214 } else { 215 brr = (struct aac_blockread_response *) 216 &ac->ac_fib->data[0]; 217 status = le32toh(brr->Status); 218 } 219 220 if (status != ST_OK) { 221 printf("%s: I/O error: %s\n", 222 sc->sc_ld.sc_dv.dv_xname, 223 aac_describe_code(aac_command_status_table, 224 status)); 225 rv = EIO; 226 } 227 } 228 } else { 229 ac->ac_device = (struct device *)sc; 230 ac->ac_context = bp; 231 ac->ac_intr = ld_aac_intr; 232 aac_ccb_enqueue(aac, ac); 233 rv = 0; 234 } 235 236 return (rv); 237 } 238 239 static int 240 ld_aac_start(struct ld_softc *ld, struct buf *bp) 241 { 242 243 return (ld_aac_dobio((struct ld_aac_softc *)ld, bp->b_data, 244 bp->b_bcount, bp->b_rawblkno, (bp->b_flags & B_READ) == 0, bp)); 245 } 246 247 static void 248 ld_aac_intr(struct aac_ccb *ac) 249 { 250 struct aac_blockread_response *brr; 251 struct aac_blockwrite_response *bwr; 252 struct ld_aac_softc *sc; 253 struct aac_softc *aac; 254 struct buf *bp; 255 u_int32_t status; 256 257 bp = ac->ac_context; 258 sc = (struct ld_aac_softc *)ac->ac_device; 259 aac = (struct aac_softc *)sc->sc_ld.sc_dv.dv_parent; 260 261 if ((bp->b_flags & B_READ) != 0) { 262 brr = (struct aac_blockread_response *)&ac->ac_fib->data[0]; 263 status = le32toh(brr->Status); 264 } else { 265 bwr = (struct aac_blockwrite_response *)&ac->ac_fib->data[0]; 266 status = le32toh(bwr->Status); 267 } 268 269 aac_ccb_unmap(aac, ac); 270 aac_ccb_free(aac, ac); 271 272 if (status != ST_OK) { 273 bp->b_flags |= B_ERROR; 274 bp->b_error = EIO; 275 bp->b_resid = bp->b_bcount; 276 277 printf("%s: I/O error: %s\n", sc->sc_ld.sc_dv.dv_xname, 278 aac_describe_code(aac_command_status_table, status)); 279 } else 280 bp->b_resid = 0; 281 282 lddone(&sc->sc_ld, bp); 283 } 284 285 static int 286 ld_aac_dump(struct ld_softc *ld, void *data, int blkno, int blkcnt) 287 { 288 289 return (ld_aac_dobio((struct ld_aac_softc *)ld, data, 290 blkcnt * ld->sc_secsize, blkno, 1, NULL)); 291 } 292