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