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 410