pst-raid.c revision 102058
1/*-
2 * Copyright (c) 2001,2002 S�ren Schmidt <sos@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer,
10 *    without modification, immediately at the beginning of the file.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $FreeBSD: head/sys/dev/pst/pst-raid.c 102058 2002-08-18 12:20:33Z sos $
29 */
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/kernel.h>
34#include <sys/module.h>
35#include <sys/bus.h>
36#include <sys/bio.h>
37#include <sys/conf.h>
38#include <sys/disk.h>
39#include <sys/devicestat.h>
40#include <sys/eventhandler.h>
41#include <sys/malloc.h>
42#include <sys/lock.h>
43#include <sys/mutex.h>
44#include <vm/vm.h>
45#include <vm/pmap.h>
46#include <machine/stdarg.h>
47#include <machine/resource.h>
48#include <machine/bus.h>
49#include <sys/rman.h>
50#include <pci/pcivar.h>
51#include <pci/pcireg.h>
52
53#include "dev/pst/pst-iop.h"
54
55/* device structures */
56static d_strategy_t pststrategy;
57static struct cdevsw pst_cdevsw = {
58    /* open */	nullopen,
59    /* close */ nullclose,
60    /* read */	physread,
61    /* write */ physwrite,
62    /* ioctl */ noioctl,
63    /* poll */	nopoll,
64    /* mmap */	nommap,
65    /* strat */ pststrategy,
66    /* name */	"pst",
67    /* maj */	200,
68    /* dump */	nodump,
69    /* psize */ nopsize,
70    /* flags */ D_DISK,
71};
72static struct cdevsw pstdisk_cdevsw;
73
74struct pst_softc {
75    struct iop_softc		*iop;
76    struct i2o_lct_entry	*lct;
77    struct i2o_bsa_device	*info;
78    dev_t			device;
79    struct devstat		stats;
80    struct disk			disk;
81    struct bio_queue_head	queue;
82    struct mtx			mtx;
83    int				outstanding;
84};
85
86struct pst_request {
87    struct pst_softc		*psc;		/* pointer to softc */
88    u_int32_t			mfa;		/* frame addreess */
89    struct callout_handle	timeout_handle; /* handle for untimeout */
90    struct bio			*bp;		/* associated bio ptr */
91};
92
93/* prototypes */
94static int pst_probe(device_t);
95static int pst_attach(device_t);
96static int pst_shutdown(device_t);
97static void pst_start(struct pst_softc *);
98static void pst_done(struct iop_softc *, u_int32_t, struct i2o_single_reply *);
99static int pst_rw(struct pst_request *);
100static void pst_timeout(struct pst_request *);
101static void bpack(int8_t *, int8_t *, int);
102
103/* local vars */
104static MALLOC_DEFINE(M_PSTRAID, "pst", "Promise SuperTrak RAID driver");
105
106int
107pst_add_raid(struct iop_softc *sc, struct i2o_lct_entry *lct)
108{
109    struct pst_softc *psc;
110    device_t child = device_add_child(sc->dev, "pst", -1);
111
112    if (!child)
113	return ENOMEM;
114    psc = malloc(sizeof(struct pst_softc), M_PSTRAID, M_NOWAIT | M_ZERO);
115    psc->iop = sc;
116    psc->lct = lct;
117    device_set_softc(child, psc);
118    return bus_generic_attach(sc->dev);
119}
120
121static int
122pst_probe(device_t dev)
123{
124    device_set_desc(dev, "Promise SuperTrak RAID");
125    return 0;
126}
127
128static int
129pst_attach(device_t dev)
130{
131    struct pst_softc *psc = device_get_softc(dev);
132    struct i2o_get_param_reply *reply;
133    struct i2o_device_identity *ident;
134    int lun = device_get_unit(dev);
135    int8_t name [32];
136
137    if (!(reply = iop_get_util_params(psc->iop, psc->lct->local_tid,
138				      I2O_PARAMS_OPERATION_FIELD_GET,
139				      I2O_BSA_DEVICE_INFO_GROUP_NO)))
140	return ENODEV;
141
142    if (!(psc->info = (struct i2o_bsa_device *)
143	    malloc(sizeof(struct i2o_bsa_device), M_PSTRAID, M_NOWAIT))) {
144	contigfree(reply, PAGE_SIZE, M_PSTRAID);
145	return ENOMEM;
146    }
147    bcopy(reply->result, psc->info, sizeof(struct i2o_bsa_device));
148    contigfree(reply, PAGE_SIZE, M_PSTRAID);
149
150    if (!(reply = iop_get_util_params(psc->iop, psc->lct->local_tid,
151				      I2O_PARAMS_OPERATION_FIELD_GET,
152				      I2O_UTIL_DEVICE_IDENTITY_GROUP_NO)))
153	return ENODEV;
154    ident = (struct i2o_device_identity *)reply->result;
155#ifdef PSTDEBUG
156    printf("pst: vendor=<%.16s> product=<%.16s>\n",
157	   ident->vendor, ident->product);
158    printf("pst: description=<%.16s> revision=<%.8s>\n",
159	   ident->description, ident->revision);
160    printf("pst: capacity=%lld blocksize=%d\n",
161	   psc->info->capacity, psc->info->block_size);
162#endif
163    bpack(ident->vendor, ident->vendor, 16);
164    bpack(ident->product, ident->product, 16);
165    sprintf(name, "%s %s", ident->vendor, ident->product);
166    contigfree(reply, PAGE_SIZE, M_PSTRAID);
167
168    bioq_init(&psc->queue);
169    mtx_init(&psc->mtx, "pst lock", MTX_DEF, 0);
170
171    psc->device = disk_create(lun, &psc->disk, 0, &pst_cdevsw, &pstdisk_cdevsw);
172    psc->device->si_drv1 = psc;
173    psc->device->si_iosize_max = 64 * 1024; /*I2O_SGL_MAX_SEGS * PAGE_SIZE;*/
174
175    bzero(&psc->disk.d_label, sizeof(struct disklabel));
176    psc->disk.d_label.d_secsize = psc->info->block_size;
177    psc->disk.d_label.d_nsectors = 63;
178    psc->disk.d_label.d_ntracks = 255;
179    psc->disk.d_label.d_ncylinders =
180	(psc->info->capacity / psc->info->block_size) / (255 * 63);
181    psc->disk.d_label.d_secpercyl = 255 * 63;
182    psc->disk.d_label.d_secperunit =
183	psc->info->capacity / psc->info->block_size;
184
185    devstat_add_entry(&psc->stats, "pst", lun, psc->info->block_size,
186		      DEVSTAT_NO_ORDERED_TAGS,
187		      DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE,
188		      DEVSTAT_PRIORITY_DISK);
189
190    printf("pst%d: %lluMB <%.40s> [%d/%d/%d] on %.16s\n", lun,
191	   (unsigned long long)psc->disk.d_label.d_secperunit / (1024 * 2),
192	   name, psc->disk.d_label.d_ncylinders, 255, 63,
193	   device_get_nameunit(psc->iop->dev));
194
195    EVENTHANDLER_REGISTER(shutdown_post_sync, pst_shutdown,
196			  dev, SHUTDOWN_PRI_FIRST);
197    return 0;
198}
199
200static int
201pst_shutdown(device_t dev)
202{
203    struct pst_softc *psc = device_get_softc(dev);
204    struct i2o_bsa_cache_flush_message *msg;
205    int mfa;
206
207    mfa = iop_get_mfa(psc->iop);
208    msg = (struct i2o_bsa_cache_flush_message *)(psc->iop->ibase + mfa);
209    bzero(msg, sizeof(struct i2o_bsa_cache_flush_message));
210    msg->version_offset = 0x01;
211    msg->message_flags = 0x0;
212    msg->message_size = sizeof(struct i2o_bsa_cache_flush_message) >> 2;
213    msg->target_address = psc->lct->local_tid;
214    msg->initiator_address = I2O_TID_HOST;
215    msg->function = I2O_BSA_CACHE_FLUSH;
216    msg->control_flags = 0x0; /* 0x80 = post progress reports */
217    if (iop_queue_wait_msg(psc->iop, mfa, (struct i2o_basic_message *)msg))
218	printf("pst: shutdown failed!\n");
219    return 0;
220}
221
222static void
223pststrategy(struct bio *bp)
224{
225    struct pst_softc *psc = bp->bio_dev->si_drv1;
226
227    mtx_lock(&psc->mtx);
228    bioqdisksort(&psc->queue, bp);
229    pst_start(psc);
230    mtx_unlock(&psc->mtx);
231}
232
233static void
234pst_start(struct pst_softc *psc)
235{
236    struct pst_request *request;
237    struct bio *bp;
238    u_int32_t mfa;
239
240    if (psc->outstanding < (I2O_IOP_OUTBOUND_FRAME_COUNT - 1) &&
241	(bp = bioq_first(&psc->queue))) {
242	if ((mfa = iop_get_mfa(psc->iop)) != 0xffffffff) {
243	    if (!(request = malloc(sizeof(struct pst_request),
244				   M_PSTRAID, M_NOWAIT | M_ZERO))) {
245		printf("pst: out of memory in start\n");
246		iop_free_mfa(psc->iop, mfa);
247		return;
248	    }
249	    psc->outstanding++;
250	    request->psc = psc;
251	    request->mfa = mfa;
252	    request->bp = bp;
253	    if (dumping)
254		request->timeout_handle.callout = NULL;
255	    else
256		request->timeout_handle =
257		    timeout((timeout_t*)pst_timeout, request, 10 * hz);
258	    bioq_remove(&psc->queue, bp);
259	    devstat_start_transaction(&psc->stats);
260	    if (pst_rw(request)) {
261		biofinish(request->bp, &psc->stats, EIO);
262		iop_free_mfa(request->psc->iop, request->mfa);
263		psc->outstanding--;
264		free(request, M_PSTRAID);
265	    }
266	}
267    }
268}
269
270static void
271pst_done(struct iop_softc *sc, u_int32_t mfa, struct i2o_single_reply *reply)
272{
273    struct pst_request *request =
274	(struct pst_request *)reply->transaction_context;
275    struct pst_softc *psc = request->psc;
276
277    untimeout((timeout_t *)pst_timeout, request, request->timeout_handle);
278    request->bp->bio_resid = request->bp->bio_bcount - reply->donecount;
279    biofinish(request->bp, &psc->stats, reply->status ? EIO : 0);
280    free(request, M_PSTRAID);
281    mtx_lock(&psc->mtx);
282    psc->iop->reg->oqueue = mfa;
283    psc->outstanding--;
284    pst_start(psc);
285    mtx_unlock(&psc->mtx);
286}
287
288static void
289pst_timeout(struct pst_request *request)
290{
291    printf("pst: timeout mfa=0x%08x cmd=0x%02x\n",
292	   request->mfa, request->bp->bio_cmd);
293    mtx_lock(&request->psc->mtx);
294    iop_free_mfa(request->psc->iop, request->mfa);
295    if ((request->mfa = iop_get_mfa(request->psc->iop)) == 0xffffffff) {
296	printf("pst: timeout no mfa possible\n");
297	biofinish(request->bp, &request->psc->stats, EIO);
298	request->psc->outstanding--;
299	mtx_unlock(&request->psc->mtx);
300	return;
301    }
302    if (dumping)
303	request->timeout_handle.callout = NULL;
304    else
305	request->timeout_handle =
306	    timeout((timeout_t*)pst_timeout, request, 10 * hz);
307    if (pst_rw(request)) {
308	iop_free_mfa(request->psc->iop, request->mfa);
309	biofinish(request->bp, &request->psc->stats, EIO);
310	request->psc->outstanding--;
311    }
312    mtx_unlock(&request->psc->mtx);
313}
314
315int
316pst_rw(struct pst_request *request)
317{
318    struct i2o_bsa_rw_block_message *msg;
319    int sgl_flag;
320
321    msg = (struct i2o_bsa_rw_block_message *)
322	  (request->psc->iop->ibase + request->mfa);
323    bzero(msg, sizeof(struct i2o_bsa_rw_block_message));
324    msg->version_offset = 0x81;
325    msg->message_flags = 0x0;
326    msg->message_size = sizeof(struct i2o_bsa_rw_block_message) >> 2;
327    msg->target_address = request->psc->lct->local_tid;
328    msg->initiator_address = I2O_TID_HOST;
329    switch (request->bp->bio_cmd) {
330    case BIO_READ:
331	msg->function = I2O_BSA_BLOCK_READ;
332	msg->control_flags = 0x0; /* 0x0c = read cache + readahead */
333	msg->fetch_ahead = 0x0; /* 8 Kb */
334	sgl_flag = 0;
335	break;
336    case BIO_WRITE:
337	msg->function = I2O_BSA_BLOCK_WRITE;
338	msg->control_flags = 0x0; /* 0x10 = write behind cache */
339	msg->fetch_ahead = 0x0;
340	sgl_flag = I2O_SGL_DIR;
341	break;
342    default:
343	printf("pst: unknown command type\n");
344	return -1;
345    }
346    msg->initiator_context = (u_int32_t)pst_done;
347    msg->transaction_context = (u_int32_t)request;
348    msg->time_multiplier = 1;
349    msg->bytecount = request->bp->bio_bcount;
350    msg->lba = ((u_int64_t)request->bp->bio_pblkno) * (DEV_BSIZE * 1LL);
351    if (!iop_create_sgl((struct i2o_basic_message *)msg, request->bp->bio_data,
352			request->bp->bio_bcount, sgl_flag))
353	return -1;
354    request->psc->iop->reg->iqueue = request->mfa;
355    return 0;
356}
357
358static void
359bpack(int8_t *src, int8_t *dst, int len)
360{
361    int i, j, blank;
362    int8_t *ptr, *buf = dst;
363
364    for (i = j = blank = 0 ; i < len; i++) {
365	if (blank && src[i] == ' ') continue;
366	if (blank && src[i] != ' ') {
367	    dst[j++] = src[i];
368	    blank = 0;
369	    continue;
370	}
371	if (src[i] == ' ') {
372	    blank = 1;
373	    if (i == 0)
374		continue;
375	}
376	dst[j++] = src[i];
377    }
378    if (j < len)
379	dst[j] = 0x00;
380    for (ptr = buf; ptr < buf+len; ++ptr)
381	if (!*ptr)
382	    *ptr = ' ';
383    for (ptr = buf + len - 1; ptr >= buf && *ptr == ' '; --ptr)
384        *ptr = 0;
385}
386
387static device_method_t pst_methods[] = {
388    DEVMETHOD(device_probe,	pst_probe),
389    DEVMETHOD(device_attach,	pst_attach),
390    { 0, 0 }
391};
392
393static driver_t pst_driver = {
394    "pst",
395    pst_methods,
396    sizeof(struct pst_softc),
397};
398
399static devclass_t pst_devclass;
400
401DRIVER_MODULE(pst, pstpci, pst_driver, pst_devclass, 0, 0);
402