Home | History | Annotate | Line # | Download | only in pci
ld_twe.c revision 1.39
      1 /*	$NetBSD: ld_twe.c,v 1.39 2016/09/27 03:33:32 pgoyette 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.39 2016/09/27 03:33:32 pgoyette 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/module.h>
     50 #include <sys/bus.h>
     51 
     52 #include <dev/ldvar.h>
     53 
     54 #include <dev/pci/twereg.h>
     55 #include <dev/pci/twevar.h>
     56 
     57 #include "ioconf.h"
     58 
     59 struct ld_twe_softc {
     60 	struct	ld_softc sc_ld;
     61 	int	sc_hwunit;
     62 };
     63 
     64 static void	ld_twe_attach(device_t, device_t, void *);
     65 static int	ld_twe_detach(device_t, int);
     66 static int	ld_twe_dobio(struct ld_twe_softc *, void *, int, int, int,
     67 			     struct buf *);
     68 static int	ld_twe_dump(struct ld_softc *, void *, int, int);
     69 static int	ld_twe_flush(struct ld_softc *, int);
     70 static void	ld_twe_handler(struct twe_ccb *, int);
     71 static int	ld_twe_match(device_t, cfdata_t, void *);
     72 static int	ld_twe_start(struct ld_softc *, struct buf *);
     73 
     74 static void	ld_twe_adjqparam(device_t, int);
     75 
     76 CFATTACH_DECL_NEW(ld_twe, sizeof(struct ld_twe_softc),
     77     ld_twe_match, ld_twe_attach, ld_twe_detach, NULL);
     78 
     79 static const struct twe_callbacks ld_twe_callbacks = {
     80 	ld_twe_adjqparam,
     81 };
     82 
     83 static int
     84 ld_twe_match(device_t parent, cfdata_t match, void *aux)
     85 {
     86 
     87 	return (1);
     88 }
     89 
     90 static void
     91 ld_twe_attach(device_t parent, device_t self, void *aux)
     92 {
     93 	struct twe_attach_args *twea = aux;
     94 	struct ld_twe_softc *sc = device_private(self);
     95 	struct ld_softc *ld = &sc->sc_ld;
     96 	struct twe_softc *twe = device_private(parent);
     97 	struct twe_drive *td = &twe->sc_units[twea->twea_unit];
     98 	const char *typestr, *stripestr, *statstr;
     99 	char unktype[16], stripebuf[32], unkstat[32];
    100 	int error;
    101 	uint8_t status;
    102 
    103 	ld->sc_dv = self;
    104 
    105 	twe_register_callbacks(twe, twea->twea_unit, &ld_twe_callbacks);
    106 
    107 	sc->sc_hwunit = twea->twea_unit;
    108 	ld->sc_flags = LDF_ENABLED;
    109 	ld->sc_maxxfer = twe_get_maxxfer(twe_get_maxsegs());
    110 	ld->sc_secperunit = td->td_size;
    111 	ld->sc_secsize = TWE_SECTOR_SIZE;
    112 	ld->sc_maxqueuecnt = twe->sc_openings;
    113 	ld->sc_start = ld_twe_start;
    114 	ld->sc_dump = ld_twe_dump;
    115 	ld->sc_flush = ld_twe_flush;
    116 
    117 	typestr = twe_describe_code(twe_table_unittype, td->td_type);
    118 	if (typestr == NULL) {
    119 		snprintf(unktype, sizeof(unktype), "<0x%02x>", td->td_type);
    120 		typestr = unktype;
    121 	}
    122 	switch (td->td_type) {
    123 	case TWE_AD_CONFIG_RAID0:
    124 	case TWE_AD_CONFIG_RAID5:
    125 	case TWE_AD_CONFIG_RAID10:
    126 		stripestr = twe_describe_code(twe_table_stripedepth,
    127 		    td->td_stripe);
    128 		if (stripestr == NULL)
    129 			snprintf(stripebuf, sizeof(stripebuf),
    130 			    "<stripe code 0x%02x> ", td->td_stripe);
    131 		else
    132 			snprintf(stripebuf, sizeof(stripebuf), "%s stripe ",
    133 			    stripestr);
    134 		break;
    135 	default:
    136 		stripebuf[0] = '\0';
    137 	}
    138 
    139 	error = twe_param_get_1(twe, TWE_PARAM_UNITINFO + twea->twea_unit,
    140 	    TWE_PARAM_UNITINFO_Status, &status);
    141 	status &= TWE_PARAM_UNITSTATUS_MASK;
    142 	if (error) {
    143 		snprintf(unkstat, sizeof(unkstat), "<unknown>");
    144 		statstr = unkstat;
    145 	} else if ((statstr =
    146 		    twe_describe_code(twe_table_unitstate, status)) == NULL) {
    147 		snprintf(unkstat, sizeof(unkstat), "<status code 0x%02x>",
    148 		    status);
    149 		statstr = unkstat;
    150 	}
    151 
    152 	aprint_normal(": %s%s, status: %s\n", stripebuf, typestr, statstr);
    153 	ldattach(ld, BUFQ_DISK_DEFAULT_STRAT);
    154 }
    155 
    156 static int
    157 ld_twe_detach(device_t self, int flags)
    158 {
    159 	struct ld_twe_softc *sc = device_private(self);
    160 	struct ld_softc *ld = &sc->sc_ld;
    161 	int rv;
    162 
    163 	if ((rv = ldbegindetach(ld, flags)) != 0)
    164 		return (rv);
    165 	ldenddetach(ld);
    166 
    167 	return (0);
    168 }
    169 
    170 static int
    171 ld_twe_dobio(struct ld_twe_softc *sc, void *data, int datasize, int blkno,
    172 	     int dowrite, struct buf *bp)
    173 {
    174 	struct twe_ccb *ccb;
    175 	struct twe_cmd *tc;
    176 	struct twe_softc *twe;
    177 	int s, rv, flags;
    178 
    179 	twe = device_private(device_parent(sc->sc_ld.sc_dv));
    180 
    181 	flags = (dowrite ? TWE_CCB_DATA_OUT : TWE_CCB_DATA_IN);
    182 	if ((ccb = twe_ccb_alloc(twe, flags)) == NULL)
    183 		return (EAGAIN);
    184 
    185 	ccb->ccb_data = data;
    186 	ccb->ccb_datasize = datasize;
    187 	tc = ccb->ccb_cmd;
    188 
    189 	/* Build the command. */
    190 	tc->tc_size = 3;
    191 	tc->tc_unit = sc->sc_hwunit;
    192 	tc->tc_count = htole16(datasize / TWE_SECTOR_SIZE);
    193 	tc->tc_args.io.lba = htole32(blkno);
    194 
    195 	if (dowrite)
    196 		tc->tc_opcode = TWE_OP_WRITE | (tc->tc_size << 5);
    197 	else
    198 		tc->tc_opcode = TWE_OP_READ | (tc->tc_size << 5);
    199 
    200 	/* Map the data transfer. */
    201 	if ((rv = twe_ccb_map(twe, ccb)) != 0) {
    202 		twe_ccb_free(twe, ccb);
    203 		return (rv);
    204 	}
    205 
    206 	if (bp == NULL) {
    207 		/*
    208 		 * Polled commands must not sit on the software queue.  Wait
    209 		 * up to 2 seconds for the command to complete.
    210 		 */
    211 		s = splbio();
    212 		rv = twe_ccb_poll(twe, ccb, 2000);
    213 		twe_ccb_unmap(twe, ccb);
    214 		twe_ccb_free(twe, ccb);
    215 		splx(s);
    216 	} else {
    217 		ccb->ccb_tx.tx_handler = ld_twe_handler;
    218 		ccb->ccb_tx.tx_context = bp;
    219 		ccb->ccb_tx.tx_dv = sc->sc_ld.sc_dv;
    220 		twe_ccb_enqueue(twe, ccb);
    221 		rv = 0;
    222 	}
    223 
    224 	return (rv);
    225 }
    226 
    227 static int
    228 ld_twe_start(struct ld_softc *ld, struct buf *bp)
    229 {
    230 
    231 	return (ld_twe_dobio((struct ld_twe_softc *)ld, bp->b_data,
    232 	    bp->b_bcount, bp->b_rawblkno, (bp->b_flags & B_READ) == 0, bp));
    233 }
    234 
    235 static void
    236 ld_twe_handler(struct twe_ccb *ccb, int error)
    237 {
    238 	struct buf *bp;
    239 	struct twe_context *tx;
    240 	struct ld_twe_softc *sc;
    241 	struct twe_softc *twe;
    242 
    243 	tx = &ccb->ccb_tx;
    244 	bp = tx->tx_context;
    245 	sc = device_private(tx->tx_dv);
    246 	twe = device_private(device_parent(sc->sc_ld.sc_dv));
    247 
    248 	twe_ccb_unmap(twe, ccb);
    249 	twe_ccb_free(twe, ccb);
    250 
    251 	if (error) {
    252 		bp->b_error = error;
    253 		bp->b_resid = bp->b_bcount;
    254 	} else
    255 		bp->b_resid = 0;
    256 
    257 	lddone(&sc->sc_ld, bp);
    258 }
    259 
    260 static int
    261 ld_twe_dump(struct ld_softc *ld, void *data, int blkno, int blkcnt)
    262 {
    263 
    264 	return (ld_twe_dobio((struct ld_twe_softc *)ld, data,
    265 	    blkcnt * ld->sc_secsize, blkno, 1, NULL));
    266 }
    267 
    268 static int
    269 ld_twe_flush(struct ld_softc *ld, int flags)
    270 {
    271 	struct ld_twe_softc *sc = (void *) ld;
    272 	struct twe_softc *twe = device_private(device_parent(ld->sc_dv));
    273 	struct twe_ccb *ccb;
    274 	struct twe_cmd *tc;
    275 	int s, rv;
    276 
    277 	ccb = twe_ccb_alloc_wait(twe, 0);
    278 	KASSERT(ccb != NULL);
    279 
    280 	ccb->ccb_data = NULL;
    281 	ccb->ccb_datasize = 0;
    282 
    283 	tc = ccb->ccb_cmd;
    284 	tc->tc_size = 2;
    285 	tc->tc_opcode = TWE_OP_FLUSH;
    286 	tc->tc_unit = sc->sc_hwunit;
    287 	tc->tc_count = 0;
    288 
    289 	if (flags & LDFL_POLL) {
    290 		/*
    291 		 * Polled commands must not sit on the software queue.  Wait
    292 		 * up to 2 seconds for the command to complete.
    293 		 */
    294 		s = splbio();
    295 		rv = twe_ccb_poll(twe, ccb, 2000);
    296 		twe_ccb_unmap(twe, ccb);
    297 		twe_ccb_free(twe, ccb);
    298 		splx(s);
    299 	} else {
    300 		ccb->ccb_tx.tx_handler = twe_ccb_wait_handler;
    301 		ccb->ccb_tx.tx_context = NULL;
    302 		ccb->ccb_tx.tx_dv = ld->sc_dv;
    303 		twe_ccb_enqueue(twe, ccb);
    304 
    305 		rv = 0;
    306 		s = splbio();
    307 		while ((ccb->ccb_flags & TWE_CCB_COMPLETE) == 0)
    308 			if ((rv = tsleep(ccb, PRIBIO, "tweflush",
    309 			    60 * hz)) != 0)
    310 				break;
    311 		twe_ccb_free(twe, ccb);
    312 		splx(s);
    313 	}
    314 
    315 	return (rv);
    316 }
    317 
    318 static void
    319 ld_twe_adjqparam(device_t self, int openings)
    320 {
    321 	struct ld_twe_softc *sc = device_private(self);
    322 	struct ld_softc *ld = &sc->sc_ld;
    323 
    324 	ldadjqparam(ld, openings);
    325 }
    326 
    327 MODULE(MODULE_CLASS_DRIVER, ld_twe, "ld,twe");
    328 
    329 #ifdef _MODULE
    330 /*
    331  * XXX Don't allow ioconf.c to redefine the "struct cfdriver ld_cd"
    332  * XXX it will be defined in the common-code module
    333  */
    334 #undef  CFDRIVER_DECL
    335 #define CFDRIVER_DECL(name, class, attr)
    336 #include "ioconf.c"
    337 #endif
    338 
    339 static int
    340 ld_twe_modcmd(modcmd_t cmd, void *opaque)
    341 {
    342 #ifdef _MODULE
    343 	/*
    344 	 * We ignore the cfdriver_vec[] that ioconf provides, since
    345 	 * the cfdrivers are attached already.
    346 	 */
    347 	static struct cfdriver * const no_cfdriver_vec[] = { NULL };
    348 #endif
    349 	int error = 0;
    350 
    351 #ifdef _MODULE
    352 	switch (cmd) {
    353 	case MODULE_CMD_INIT:
    354 		error = config_init_component(no_cfdriver_vec,
    355 		    cfattach_ioconf_ld_twe, cfdata_ioconf_ld_twe);
    356 		break;
    357 	case MODULE_CMD_FINI:
    358 		error = config_fini_component(no_cfdriver_vec,
    359 		    cfattach_ioconf_ld_twe, cfdata_ioconf_ld_twe);
    360 		break;
    361 	default:
    362 		error = ENOTTY;
    363 		break;
    364 	}
    365 #endif
    366 
    367 	return error;
    368 }
    369