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, ¶m, 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, ¶m,
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, ¶m,
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 ¶m, 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