Home | History | Annotate | Line # | Download | only in i2o
ld_iop.c revision 1.1
      1 /*	$NetBSD: ld_iop.c,v 1.1 2000/11/26 17:44:05 ad Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2000 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 /*
     40  * I2O front-end for ld(4) driver, supporting random block storage class
     41  * devices.  Currently, this doesn't support anything more complex than
     42  * fixed, direct access devices; hopefully, scsipi can take care of the
     43  * rest.
     44  */
     45 
     46 #include "opt_i2o.h"
     47 #include "rnd.h"
     48 
     49 #include <sys/param.h>
     50 #include <sys/systm.h>
     51 #include <sys/kernel.h>
     52 #include <sys/device.h>
     53 #include <sys/buf.h>
     54 #include <sys/endian.h>
     55 #include <sys/dkio.h>
     56 #include <sys/disk.h>
     57 #include <sys/proc.h>
     58 #if NRND > 0
     59 #include <sys/rnd.h>
     60 #endif
     61 
     62 #include <machine/bus.h>
     63 
     64 #include <dev/ldvar.h>
     65 
     66 #include <dev/i2o/i2o.h>
     67 #include <dev/i2o/iopvar.h>
     68 
     69 #define	LD_IOP_MAXQUEUECNT	64		/* XXX */
     70 
     71 struct ld_iop_softc {
     72 	struct	ld_softc sc_ld;
     73 	struct	iop_initiator sc_ii;
     74 	u_int	sc_tid;
     75 };
     76 
     77 static void	ld_iop_attach(struct device *, struct device *, void *);
     78 static int	ld_iop_dump(struct ld_softc *, void *, int, int);
     79 static int	ld_iop_flush(struct ld_softc *);
     80 static void	ld_iop_intr(struct device *, struct iop_msg *, void *);
     81 static int	ld_iop_start(struct ld_softc *, struct buf *);
     82 static int	ld_iop_match(struct device *, struct cfdata *, void *);
     83 
     84 struct cfattach ld_iop_ca = {
     85 	sizeof(struct ld_iop_softc), ld_iop_match, ld_iop_attach
     86 };
     87 
     88 #ifdef I2OVERBOSE
     89 static const char *ld_iop_errors[] = {
     90 	"success",
     91 	"media error",
     92 	"failure communicating with device",
     93 	"device failure",
     94 	"device is not ready",
     95 	"media not present",
     96 	"media locked by another user",
     97 	"media failure",
     98 	"failure communicating to device",
     99 	"device bus failure",
    100 	"device locked by another user",
    101 	"device write protected",
    102 	"device reset",
    103 	"volume has changed, waiting for acknowledgement",
    104 };
    105 #endif
    106 
    107 static int
    108 ld_iop_match(struct device *parent, struct cfdata *match, void *aux)
    109 {
    110 	struct iop_attach_args *ia;
    111 	struct {
    112 		struct	i2o_param_op_results pr;
    113 		struct	i2o_param_read_results prr;
    114 		struct	i2o_param_rbs_device_info bdi;
    115 	} param;
    116 	u_int32_t caps;
    117 
    118 	ia = aux;
    119 
    120 	if (ia->ia_class != I2O_CLASS_RANDOM_BLOCK_STORAGE)
    121 		return (0);
    122 
    123 	if (iop_params_get((struct iop_softc *)parent, ia->ia_tid,
    124 	    I2O_PARAM_RBS_DEVICE_INFO, &param, sizeof(param)) != 0)
    125 		return (0);
    126 
    127 	caps = le32toh(param.bdi.capabilities);
    128 
    129 	if (param.bdi.type != I2O_RBS_TYPE_DIRECT ||
    130 	    (caps & I2O_RBS_CAP_REMOVEABLE_MEDIA) != 0 ||
    131 	    (caps & I2O_RBS_CAP_REMOVEABLE_DEVICE) != 0)
    132 		return (0);
    133 
    134 	/*
    135 	 * Mark the physical device(s) that comprise(s) the block storage
    136 	 * unit as being `in use'.
    137 	 */
    138 	iop_tid_markallused((struct iop_softc *)parent, ia->ia_tid);
    139 	return (1);
    140 }
    141 
    142 static void
    143 ld_iop_attach(struct device *parent, struct device *self, void *aux)
    144 {
    145 	struct iop_attach_args *ia;
    146 	struct ld_softc *ld;
    147 	struct ld_iop_softc *sc;
    148 	struct iop_softc *iop;
    149 	int rv;
    150 	char ident[64 + 1];
    151 	u_int cachesz;
    152 	struct {
    153 		struct	i2o_param_op_results pr;
    154 		struct	i2o_param_read_results prr;
    155 		union {
    156 			struct	i2o_param_rbs_cache_control cc;
    157 			struct	i2o_param_rbs_device_info bdi;
    158 			struct	i2o_param_device_identity di;
    159 		} p;
    160 	} param;
    161 
    162 	sc = (struct ld_iop_softc *)self;
    163 	ld = &sc->sc_ld;
    164 	iop = (struct iop_softc *)parent;
    165 	ia = (struct iop_attach_args *)aux;
    166 	sc->sc_tid = ia->ia_tid;
    167 
    168 	/* Register us as an initiator. */
    169 	sc->sc_ii.ii_dv = self;
    170 	sc->sc_ii.ii_intr = ld_iop_intr;
    171 	sc->sc_ii.ii_flags = 0;
    172 	if (iop_initiator_register(iop, &sc->sc_ii) != 0) {
    173 		printf("%s: unable to register as an initiator\n",
    174 		    self->dv_xname);
    175 		return;
    176 	}
    177 
    178 	ld->sc_maxxfer = IOP_MAX_XFER;
    179 	ld->sc_maxqueuecnt = LD_IOP_MAXQUEUECNT;
    180 	ld->sc_dump = ld_iop_dump;
    181 	ld->sc_flush = ld_iop_flush;
    182 	ld->sc_start = ld_iop_start;
    183 
    184 	/* Say what the device is. */
    185 	printf(": ");
    186 	if (iop_params_get(iop, ia->ia_tid, I2O_PARAM_DEVICE_IDENTITY, &param,
    187 	    sizeof(param)) == 0) {
    188 		iop_strvis(param.p.di.vendorinfo,
    189 		    sizeof(param.p.di.vendorinfo), ident, sizeof(ident));
    190 		printf("<%s, ", ident);
    191 		iop_strvis(param.p.di.productinfo,
    192 		    sizeof(param.p.di.productinfo), ident, sizeof(ident));
    193 		printf("%s, ", ident);
    194 		iop_strvis(param.p.di.revlevel,
    195 		    sizeof(param.p.di.revlevel), ident, sizeof(ident));
    196 		printf("%s> ", ident);
    197 	}
    198 
    199 	/* Claim the device so that we don't get any nasty surprises. */
    200 	rv = iop_tid_claim(iop, ia->ia_tid, sc->sc_ii.ii_ictx,
    201 	    I2O_UTIL_CLAIM_RESET_SENSITIVE |
    202 	    I2O_UTIL_CLAIM_STATE_SENSITIVE |
    203 	    I2O_UTIL_CLAIM_CAPACITY_SENSITIVE |
    204 	    I2O_UTIL_CLAIM_NO_PEER_SERVICE |
    205 	    I2O_UTIL_CLAIM_NO_MANAGEMENT_SERVICE |
    206 	    I2O_UTIL_CLAIM_PRIMARY_USER);
    207 	if (rv != 0) {
    208 		printf("%s: unable to claim device (%d)\n",
    209 		   ld->sc_dv.dv_xname, rv);
    210 		goto bad;
    211 	}
    212 
    213 	rv = iop_params_get(iop, ia->ia_tid, I2O_PARAM_RBS_DEVICE_INFO, &param,
    214 	    sizeof(param));
    215 	if (rv != 0) {
    216 		printf("%s: unable to retrieve device parameters (%d)\n",
    217 		   ld->sc_dv.dv_xname, rv);
    218 		goto bad;
    219 	}
    220 
    221 	ld->sc_secsize = le32toh(param.p.bdi.blocksize);
    222 	ld->sc_secperunit = (int)
    223 	    (le64toh(param.p.bdi.capacity) / ld->sc_secsize);
    224 
    225 	/* Build synthetic geometry. */
    226 	if (ld->sc_secperunit <= 528 * 2048)		/* 528MB */
    227 		ld->sc_nheads = 16;
    228 	else if (ld->sc_secperunit <= 1024 * 2048)	/* 1GB */
    229 		ld->sc_nheads = 32;
    230 	else if (ld->sc_secperunit <= 21504 * 2048)	/* 21GB */
    231 		ld->sc_nheads = 64;
    232 	else if (ld->sc_secperunit <= 43008 * 2048)	/* 42GB */
    233 		ld->sc_nheads = 128;
    234 	else
    235 		ld->sc_nheads = 255;
    236 
    237 	ld->sc_nsectors = 63;
    238 	ld->sc_ncylinders = ld->sc_secperunit /
    239 	    (ld->sc_nheads * ld->sc_nsectors);
    240 
    241 #ifdef notyet
    242 	switch (param.p.bdi.type) {
    243 	case I2O_RBS_TYPE_DIRECT:
    244 		typestr = "direct access";
    245 		break;
    246 	case I2O_RBS_TYPE_WORM:
    247 		typestr = "WORM";
    248 		break;
    249 	case I2O_RBS_TYPE_CDROM:
    250 		typestr = "cdrom";
    251 		break;
    252 	case I2O_RBS_TYPE_OPTICAL:
    253 		typestr = "optical";
    254 		break;
    255 	default:
    256 		typestr = "unknown";
    257 		break;
    258 	}
    259 
    260 	if ((le32toh(param.p.bdi.capabilities) & I2O_RBS_CAP_REMOVEABLE_MEDIA)
    261 	    != 0) {
    262 		ld->sc_flags = LDF_ENABLED | LDF_REMOVEABLE;
    263 		fixedstr = "removeable";
    264 	} else {
    265 		ld->sc_flags = LDF_ENABLED;
    266 		fixedstr = "fixed";
    267 	}
    268 #endif
    269 	printf("direct access, fixed");
    270 
    271 	/*
    272 	 * Determine if the device has an private cache.  If so, print the
    273 	 * cache size.  Even if the device doesn't appear to have a cache,
    274 	 * we perform a flush at shutdown, as it is still valid to do so.
    275 	 */
    276 	rv = iop_params_get(iop, ia->ia_tid, I2O_PARAM_RBS_CACHE_CONTROL,
    277 	    &param, sizeof(param));
    278 	if (rv != 0) {
    279 		printf("%s: unable to retrieve cache parameters (%d)\n",
    280 		   ld->sc_dv.dv_xname, rv);
    281 		goto bad;
    282 	}
    283 
    284 	if ((cachesz = le32toh(param.p.cc.totalcachesize)) != 0)
    285 		printf(", %dkB cache", cachesz >> 10);
    286 
    287 	printf("\n");
    288 	ld->sc_flags = LDF_ENABLED;
    289 	ldattach(ld);
    290 	return;
    291 
    292 bad:
    293 	iop_initiator_unregister(iop, &sc->sc_ii);
    294 }
    295 
    296 static int
    297 ld_iop_start(struct ld_softc *ld, struct buf *bp)
    298 {
    299 	struct iop_msg *im;
    300 	struct iop_softc *iop;
    301 	struct ld_iop_softc *sc;
    302 	struct i2o_rbs_block_read *mb;
    303 	int rv, flags, write;
    304 	u_int64_t ba;
    305 
    306 	sc = (struct ld_iop_softc *)ld;
    307 	iop = (struct iop_softc *)ld->sc_dv.dv_parent;
    308 
    309 	im = NULL;
    310 	if ((rv = iop_msg_alloc(iop, &sc->sc_ii, &im, IM_NOWAIT)) != 0)
    311 		goto bad;
    312 	im->im_dvcontext = bp;
    313 
    314 	write = ((bp->b_flags & B_READ) == 0);
    315 	ba = (u_int64_t)bp->b_rawblkno * ld->sc_secsize;
    316 
    317 	if (write) {
    318 		if (bp == NULL || (bp->b_flags & B_ASYNC) == 0)
    319 			flags = I2O_RBS_BLOCK_WRITE_CACHE_WT;
    320 		else
    321 			flags = I2O_RBS_BLOCK_WRITE_CACHE_WB;
    322 	}
    323 
    324 	/*
    325 	 * Fill the message frame.  We can use the block_read structure for
    326 	 * both reads and writes, as it's almost identical to the
    327 	 * block_write structure.
    328 	 *
    329 	 * XXX We should be using the command time out facilities.
    330 	 */
    331 	mb = (struct i2o_rbs_block_read *)im->im_msg;
    332 	mb->msgflags = I2O_MSGFLAGS(i2o_rbs_block_read);
    333 	mb->msgfunc = I2O_MSGFUNC(sc->sc_tid,
    334 	    write ? I2O_RBS_BLOCK_WRITE : I2O_RBS_BLOCK_READ);
    335 	mb->msgictx = sc->sc_ii.ii_ictx;
    336 	mb->msgtctx = im->im_tctx;
    337 	mb->flags = flags;
    338 	mb->datasize = bp->b_bcount;
    339 	mb->lowoffset = (u_int32_t)ba;
    340 	mb->highoffset = (u_int32_t)(ba >> 32);
    341 
    342 	/* Map the data transfer. */
    343 	if ((rv = iop_msg_map(iop, im, bp->b_data, bp->b_bcount, write)) != 0)
    344 		goto bad;
    345 
    346 	/* Enqueue the command. */
    347 	if ((rv = iop_msg_enqueue(iop, im)) != 0) {
    348 		iop_msg_unmap(iop, im);
    349 		goto bad;
    350 	}
    351 
    352 	return (0);
    353 
    354 bad:
    355 	if (im != NULL)
    356 		iop_msg_free(iop, &sc->sc_ii, im);
    357 	return (rv);
    358 }
    359 
    360 static int
    361 ld_iop_dump(struct ld_softc *ld, void *data, int blkno, int blkcnt)
    362 {
    363 	struct iop_msg *im;
    364 	struct iop_softc *iop;
    365 	struct ld_iop_softc *sc;
    366 	struct i2o_rbs_block_write *mb;
    367 	int rv, bcount;
    368 	u_int64_t ba;
    369 
    370 	sc = (struct ld_iop_softc *)ld;
    371 	iop = (struct iop_softc *)ld->sc_dv.dv_parent;
    372 	bcount = blkcnt * ld->sc_secsize;
    373 	ba = (u_int64_t)blkno * ld->sc_secsize;
    374 
    375 	rv = iop_msg_alloc(iop, &sc->sc_ii, &im, IM_NOWAIT | IM_NOINTR);
    376 	if (rv != 0)
    377 		return (rv);
    378 
    379 	mb = (struct i2o_rbs_block_write *)im->im_msg;
    380 	mb->msgflags = I2O_MSGFLAGS(i2o_rbs_block_write);
    381 	mb->msgfunc = I2O_MSGFUNC(sc->sc_tid, I2O_RBS_BLOCK_WRITE);
    382 	mb->msgictx = sc->sc_ii.ii_ictx;
    383 	mb->msgtctx = im->im_tctx;
    384 	mb->flags = I2O_RBS_BLOCK_WRITE_CACHE_WT;
    385 	mb->datasize = bcount;
    386 	mb->lowoffset = (u_int32_t)ba;
    387 	mb->highoffset = (u_int32_t)(ba >> 32);
    388 
    389 	if ((rv = iop_msg_map(iop, im, data, bcount, 1)) != 0) {
    390 		iop_msg_free(iop, &sc->sc_ii, im);
    391 		return (rv);
    392 	}
    393 
    394 	rv = iop_msg_send(iop, im, 5000) != 0 ? EIO : 0;
    395 	iop_msg_unmap(iop, im);
    396 	iop_msg_free(iop, &sc->sc_ii, im);
    397  	return (rv);
    398 }
    399 
    400 static int
    401 ld_iop_flush(struct ld_softc *ld)
    402 {
    403 	struct iop_msg *im;
    404 	struct iop_softc *iop;
    405 	struct ld_iop_softc *sc;
    406 	struct i2o_rbs_cache_flush *mb;
    407 	int rv;
    408 
    409 	sc = (struct ld_iop_softc *)ld;
    410 	iop = (struct iop_softc *)ld->sc_dv.dv_parent;
    411 
    412 	rv = iop_msg_alloc(iop, &sc->sc_ii, &im, IM_NOWAIT | IM_NOINTR);
    413 	if (rv != 0)
    414 		return (rv);
    415 
    416 	mb = (struct i2o_rbs_cache_flush *)im->im_msg;
    417 	mb->msgflags = I2O_MSGFLAGS(i2o_rbs_cache_flush);
    418 	mb->msgfunc = I2O_MSGFUNC(sc->sc_tid, I2O_RBS_CACHE_FLUSH);
    419 	mb->msgictx = sc->sc_ii.ii_ictx;
    420 	mb->msgtctx = im->im_tctx;
    421 	mb->flags = 0;
    422 
    423  	rv = iop_msg_send(iop, im, 10000);
    424 	iop_msg_free(iop, &sc->sc_ii, im);
    425 	return (rv);
    426 }
    427 
    428 void
    429 ld_iop_intr(struct device *dv, struct iop_msg *im, void *reply)
    430 {
    431 	struct i2o_rbs_reply *rb;
    432 	struct buf *bp;
    433 	struct ld_iop_softc *sc;
    434 	struct iop_softc *iop;
    435 #ifdef I2OVERBOSE
    436 	int detail;
    437 	const char *errstr;
    438 #endif
    439 
    440 	rb = reply;
    441 	bp = im->im_dvcontext;
    442 	sc = (struct ld_iop_softc *)dv;
    443 	iop = (struct iop_softc *)dv->dv_parent;
    444 
    445 #ifdef I2OVERBOSE
    446 	if (rb->reqstatus != I2O_STATUS_SUCCESS) {
    447 		detail = le16toh(rb->detail);
    448 		if (detail > sizeof(ld_iop_errors) / sizeof(ld_iop_errors[0]))
    449 			errstr = "unknown error";
    450 		else
    451 			errstr = ld_iop_errors[detail];
    452 		printf("%s: %s\n", dv->dv_xname, errstr);
    453 #else
    454 	if (rb->reqstatus != I2O_STATUS_SUCCESS) {
    455 #endif
    456 		bp->b_flags |= B_ERROR;
    457 		bp->b_error = EIO;
    458 #ifndef notyet
    459 		bp->b_resid = bp->b_bcount;
    460 	} else
    461 		bp->b_resid = 0;
    462 #else
    463 	}
    464 	bp->b_resid = bp->b_bcount - le32toh(rb->transfercount);
    465 #endif
    466 
    467 	iop_msg_unmap(iop, im);
    468 	iop_msg_free(iop, &sc->sc_ii, im);
    469 	lddone(&sc->sc_ld, bp);
    470 }
    471