1/* $NetBSD: ld_twe.c,v 1.35 2010/11/13 13:52:07 uebayasi Exp $ */ 2 3/*- 4 * Copyright (c) 2000, 2001, 2002, 2003 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; and by Jason R. Thorpe of Wasabi Systems, Inc. 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/* 33 * 3ware "Escalade" RAID controller front-end for ld(4) driver. 34 */ 35 36#include <sys/cdefs.h> 37__KERNEL_RCSID(0, "$NetBSD: ld_twe.c,v 1.35 2010/11/13 13:52:07 uebayasi Exp $"); 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/kernel.h> 42#include <sys/device.h> 43#include <sys/buf.h> 44#include <sys/bufq.h> 45#include <sys/endian.h> 46#include <sys/dkio.h> 47#include <sys/disk.h> 48#include <sys/proc.h> 49#include <sys/rnd.h> 50 51#include <sys/bus.h> 52 53#include <dev/ldvar.h> 54 55#include <dev/pci/twereg.h> 56#include <dev/pci/twevar.h> 57 58struct ld_twe_softc { 59 struct ld_softc sc_ld; 60 int sc_hwunit; 61}; 62 63static void ld_twe_attach(device_t, device_t, void *); 64static int ld_twe_detach(device_t, int); 65static int ld_twe_dobio(struct ld_twe_softc *, void *, int, int, int, 66 struct buf *); 67static int ld_twe_dump(struct ld_softc *, void *, int, int); 68static int ld_twe_flush(struct ld_softc *, int); 69static void ld_twe_handler(struct twe_ccb *, int); 70static int ld_twe_match(device_t, cfdata_t, void *); 71static int ld_twe_start(struct ld_softc *, struct buf *); 72 73static void ld_twe_adjqparam(device_t, int); 74 75CFATTACH_DECL_NEW(ld_twe, sizeof(struct ld_twe_softc), 76 ld_twe_match, ld_twe_attach, ld_twe_detach, NULL); 77 78static const struct twe_callbacks ld_twe_callbacks = { 79 ld_twe_adjqparam, 80}; 81 82static int 83ld_twe_match(device_t parent, cfdata_t match, void *aux) 84{ 85 86 return (1); 87} 88 89static void 90ld_twe_attach(device_t parent, device_t self, void *aux) 91{ 92 struct twe_attach_args *twea = aux; 93 struct ld_twe_softc *sc = device_private(self); 94 struct ld_softc *ld = &sc->sc_ld; 95 struct twe_softc *twe = device_private(parent); 96 struct twe_drive *td = &twe->sc_units[twea->twea_unit]; 97 const char *typestr, *stripestr, *statstr; 98 char unktype[16], stripebuf[32], unkstat[32]; 99 int error; 100 uint8_t status; 101 102 ld->sc_dv = self; 103 104 twe_register_callbacks(twe, twea->twea_unit, &ld_twe_callbacks); 105 106 sc->sc_hwunit = twea->twea_unit; 107 ld->sc_flags = LDF_ENABLED; 108 ld->sc_maxxfer = twe_get_maxxfer(twe_get_maxsegs()); 109 ld->sc_secperunit = td->td_size; 110 ld->sc_secsize = TWE_SECTOR_SIZE; 111 ld->sc_maxqueuecnt = twe->sc_openings; 112 ld->sc_start = ld_twe_start; 113 ld->sc_dump = ld_twe_dump; 114 ld->sc_flush = ld_twe_flush; 115 116 typestr = twe_describe_code(twe_table_unittype, td->td_type); 117 if (typestr == NULL) { 118 snprintf(unktype, sizeof(unktype), "<0x%02x>", td->td_type); 119 typestr = unktype; 120 } 121 switch (td->td_type) { 122 case TWE_AD_CONFIG_RAID0: 123 case TWE_AD_CONFIG_RAID5: 124 case TWE_AD_CONFIG_RAID10: 125 stripestr = twe_describe_code(twe_table_stripedepth, 126 td->td_stripe); 127 if (stripestr == NULL) 128 snprintf(stripebuf, sizeof(stripebuf), 129 "<stripe code 0x%02x> ", td->td_stripe); 130 else 131 snprintf(stripebuf, sizeof(stripebuf), "%s stripe ", 132 stripestr); 133 break; 134 default: 135 stripebuf[0] = '\0'; 136 } 137 138 error = twe_param_get_1(twe, TWE_PARAM_UNITINFO + twea->twea_unit, 139 TWE_PARAM_UNITINFO_Status, &status); 140 status &= TWE_PARAM_UNITSTATUS_MASK; 141 if (error) { 142 snprintf(unkstat, sizeof(unkstat), "<unknown>"); 143 statstr = unkstat; 144 } else if ((statstr = 145 twe_describe_code(twe_table_unitstate, status)) == NULL) { 146 snprintf(unkstat, sizeof(unkstat), "<status code 0x%02x>", 147 status); 148 statstr = unkstat; 149 } 150 151 aprint_normal(": %s%s, status: %s\n", stripebuf, typestr, statstr); 152 ldattach(ld); 153} 154 155static int 156ld_twe_detach(device_t self, int flags) 157{ 158 struct ld_twe_softc *sc = device_private(self); 159 struct ld_softc *ld = &sc->sc_ld; 160 int rv; 161 162 if ((rv = ldbegindetach(ld, flags)) != 0) 163 return (rv); 164 ldenddetach(ld); 165 166 return (0); 167} 168 169static int 170ld_twe_dobio(struct ld_twe_softc *sc, void *data, int datasize, int blkno, 171 int dowrite, struct buf *bp) 172{ 173 struct twe_ccb *ccb; 174 struct twe_cmd *tc; 175 struct twe_softc *twe; 176 int s, rv, flags; 177 178 twe = device_private(device_parent(sc->sc_ld.sc_dv)); 179 180 flags = (dowrite ? TWE_CCB_DATA_OUT : TWE_CCB_DATA_IN); 181 if ((ccb = twe_ccb_alloc(twe, flags)) == NULL) 182 return (EAGAIN); 183 184 ccb->ccb_data = data; 185 ccb->ccb_datasize = datasize; 186 tc = ccb->ccb_cmd; 187 188 /* Build the command. */ 189 tc->tc_size = 3; 190 tc->tc_unit = sc->sc_hwunit; 191 tc->tc_count = htole16(datasize / TWE_SECTOR_SIZE); 192 tc->tc_args.io.lba = htole32(blkno); 193 194 if (dowrite) 195 tc->tc_opcode = TWE_OP_WRITE | (tc->tc_size << 5); 196 else 197 tc->tc_opcode = TWE_OP_READ | (tc->tc_size << 5); 198 199 /* Map the data transfer. */ 200 if ((rv = twe_ccb_map(twe, ccb)) != 0) { 201 twe_ccb_free(twe, ccb); 202 return (rv); 203 } 204 205 if (bp == NULL) { 206 /* 207 * Polled commands must not sit on the software queue. Wait 208 * up to 2 seconds for the command to complete. 209 */ 210 s = splbio(); 211 rv = twe_ccb_poll(twe, ccb, 2000); 212 twe_ccb_unmap(twe, ccb); 213 twe_ccb_free(twe, ccb); 214 splx(s); 215 } else { 216 ccb->ccb_tx.tx_handler = ld_twe_handler; 217 ccb->ccb_tx.tx_context = bp; 218 ccb->ccb_tx.tx_dv = sc->sc_ld.sc_dv; 219 twe_ccb_enqueue(twe, ccb); 220 rv = 0; 221 } 222 223 return (rv); 224} 225 226static int 227ld_twe_start(struct ld_softc *ld, struct buf *bp) 228{ 229 230 return (ld_twe_dobio((struct ld_twe_softc *)ld, bp->b_data, 231 bp->b_bcount, bp->b_rawblkno, (bp->b_flags & B_READ) == 0, bp)); 232} 233 234static void 235ld_twe_handler(struct twe_ccb *ccb, int error) 236{ 237 struct buf *bp; 238 struct twe_context *tx; 239 struct ld_twe_softc *sc; 240 struct twe_softc *twe; 241 242 tx = &ccb->ccb_tx; 243 bp = tx->tx_context; 244 sc = device_private(tx->tx_dv); 245 twe = device_private(device_parent(sc->sc_ld.sc_dv)); 246 247 twe_ccb_unmap(twe, ccb); 248 twe_ccb_free(twe, ccb); 249 250 if (error) { 251 bp->b_error = error; 252 bp->b_resid = bp->b_bcount; 253 } else 254 bp->b_resid = 0; 255 256 lddone(&sc->sc_ld, bp); 257} 258 259static int 260ld_twe_dump(struct ld_softc *ld, void *data, int blkno, int blkcnt) 261{ 262 263 return (ld_twe_dobio((struct ld_twe_softc *)ld, data, 264 blkcnt * ld->sc_secsize, blkno, 1, NULL)); 265} 266 267static int 268ld_twe_flush(struct ld_softc *ld, int flags) 269{ 270 struct ld_twe_softc *sc = (void *) ld; 271 struct twe_softc *twe = device_private(device_parent(ld->sc_dv)); 272 struct twe_ccb *ccb; 273 struct twe_cmd *tc; 274 int s, rv; 275 276 ccb = twe_ccb_alloc_wait(twe, 0); 277 KASSERT(ccb != NULL); 278 279 ccb->ccb_data = NULL; 280 ccb->ccb_datasize = 0; 281 282 tc = ccb->ccb_cmd; 283 tc->tc_size = 2; 284 tc->tc_opcode = TWE_OP_FLUSH; 285 tc->tc_unit = sc->sc_hwunit; 286 tc->tc_count = 0; 287 288 if (flags & LDFL_POLL) { 289 /* 290 * Polled commands must not sit on the software queue. Wait 291 * up to 2 seconds for the command to complete. 292 */ 293 s = splbio(); 294 rv = twe_ccb_poll(twe, ccb, 2000); 295 twe_ccb_unmap(twe, ccb); 296 twe_ccb_free(twe, ccb); 297 splx(s); 298 } else { 299 ccb->ccb_tx.tx_handler = twe_ccb_wait_handler; 300 ccb->ccb_tx.tx_context = NULL; 301 ccb->ccb_tx.tx_dv = ld->sc_dv; 302 twe_ccb_enqueue(twe, ccb); 303 304 rv = 0; 305 s = splbio(); 306 while ((ccb->ccb_flags & TWE_CCB_COMPLETE) == 0) 307 if ((rv = tsleep(ccb, PRIBIO, "tweflush", 308 60 * hz)) != 0) 309 break; 310 twe_ccb_free(twe, ccb); 311 splx(s); 312 } 313 314 return (rv); 315} 316 317static void 318ld_twe_adjqparam(device_t self, int openings) 319{ 320 struct ld_twe_softc *sc = device_private(self); 321 struct ld_softc *ld = &sc->sc_ld; 322 323 ldadjqparam(ld, openings); 324} 325