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