pst-raid.c revision 103714
1234370Sjasone/*-
2234370Sjasone * Copyright (c) 2001,2002 S�ren Schmidt <sos@FreeBSD.org>
3234370Sjasone * All rights reserved.
4234370Sjasone *
5234370Sjasone * Redistribution and use in source and binary forms, with or without
6234370Sjasone * modification, are permitted provided that the following conditions
7234370Sjasone * are met:
8234370Sjasone * 1. Redistributions of source code must retain the above copyright
9234370Sjasone *    notice, this list of conditions and the following disclaimer,
10234370Sjasone *    without modification, immediately at the beginning of the file.
11234370Sjasone * 2. Redistributions in binary form must reproduce the above copyright
12234370Sjasone *    notice, this list of conditions and the following disclaimer in the
13234370Sjasone *    documentation and/or other materials provided with the distribution.
14234370Sjasone * 3. The name of the author may not be used to endorse or promote products
15234370Sjasone *    derived from this software without specific prior written permission.
16234370Sjasone *
17234370Sjasone * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18234370Sjasone * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19234370Sjasone * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20234370Sjasone * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21234370Sjasone * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22234370Sjasone * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23234370Sjasone * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24234543Sjasone * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25234370Sjasone * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26234543Sjasone * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27234370Sjasone *
28234370Sjasone * $FreeBSD: head/sys/dev/pst/pst-raid.c 103714 2002-09-20 19:36:05Z phk $
29245868Sjasone */
30234370Sjasone
31234370Sjasone#include <sys/param.h>
32234370Sjasone#include <sys/systm.h>
33234370Sjasone#include <sys/kernel.h>
34234370Sjasone#include <sys/module.h>
35234370Sjasone#include <sys/bus.h>
36234370Sjasone#include <sys/bio.h>
37234370Sjasone#include <sys/conf.h>
38234370Sjasone#include <sys/disk.h>
39234370Sjasone#include <sys/devicestat.h>
40234370Sjasone#include <sys/eventhandler.h>
41234370Sjasone#include <sys/malloc.h>
42234370Sjasone#include <sys/lock.h>
43234370Sjasone#include <sys/mutex.h>
44234370Sjasone#include <vm/vm.h>
45234370Sjasone#include <vm/pmap.h>
46234370Sjasone#include <machine/stdarg.h>
47234370Sjasone#include <machine/resource.h>
48234370Sjasone#include <machine/bus.h>
49234370Sjasone#include <sys/rman.h>
50234370Sjasone#include <pci/pcivar.h>
51234370Sjasone#include <pci/pcireg.h>
52234370Sjasone
53234370Sjasone#include "dev/pst/pst-iop.h"
54234370Sjasone
55234370Sjasone/* device structures */
56234370Sjasonestatic d_strategy_t pststrategy;
57234370Sjasonestatic struct cdevsw pst_cdevsw = {
58234370Sjasone    /* open */	nullopen,
59234370Sjasone    /* close */ nullclose,
60234370Sjasone    /* read */	physread,
61234370Sjasone    /* write */ physwrite,
62234370Sjasone    /* ioctl */ noioctl,
63234370Sjasone    /* poll */	nopoll,
64234370Sjasone    /* mmap */	nommap,
65234370Sjasone    /* strat */ pststrategy,
66234370Sjasone    /* name */	"pst",
67234370Sjasone    /* maj */	200,
68234370Sjasone    /* dump */	nodump,
69234370Sjasone    /* psize */ nopsize,
70234370Sjasone    /* flags */ D_DISK,
71234370Sjasone};
72234370Sjasonestatic struct cdevsw pstdisk_cdevsw;
73234370Sjasone
74234370Sjasonestruct pst_softc {
75234370Sjasone    struct iop_softc		*iop;
76234370Sjasone    struct i2o_lct_entry	*lct;
77234370Sjasone    struct i2o_bsa_device	*info;
78234370Sjasone    dev_t			device;
79234370Sjasone    struct devstat		stats;
80234370Sjasone    struct disk			disk;
81234370Sjasone    struct bio_queue_head	queue;
82234370Sjasone    struct mtx			mtx;
83234370Sjasone    int				outstanding;
84234370Sjasone};
85234370Sjasone
86234370Sjasonestruct pst_request {
87234370Sjasone    struct pst_softc		*psc;		/* pointer to softc */
88234370Sjasone    u_int32_t			mfa;		/* frame addreess */
89234370Sjasone    struct callout_handle	timeout_handle; /* handle for untimeout */
90234370Sjasone    struct bio			*bp;		/* associated bio ptr */
91234370Sjasone};
92234370Sjasone
93245868Sjasone/* prototypes */
94234370Sjasonestatic int pst_probe(device_t);
95234370Sjasonestatic int pst_attach(device_t);
96234370Sjasonestatic int pst_shutdown(device_t);
97234370Sjasonestatic void pst_start(struct pst_softc *);
98234370Sjasonestatic void pst_done(struct iop_softc *, u_int32_t, struct i2o_single_reply *);
99234370Sjasonestatic int pst_rw(struct pst_request *);
100234370Sjasonestatic void pst_timeout(struct pst_request *);
101234370Sjasonestatic void bpack(int8_t *, int8_t *, int);
102234370Sjasone
103234370Sjasone/* local vars */
104234370Sjasonestatic MALLOC_DEFINE(M_PSTRAID, "pst", "Promise SuperTrak RAID driver");
105234370Sjasone
106234370Sjasoneint
107234370Sjasonepst_add_raid(struct iop_softc *sc, struct i2o_lct_entry *lct)
108234370Sjasone{
109234370Sjasone    struct pst_softc *psc;
110234370Sjasone    device_t child = device_add_child(sc->dev, "pst", -1);
111234370Sjasone
112234370Sjasone    if (!child)
113234370Sjasone	return ENOMEM;
114234370Sjasone    psc = malloc(sizeof(struct pst_softc), M_PSTRAID, M_NOWAIT | M_ZERO);
115234370Sjasone    psc->iop = sc;
116234370Sjasone    psc->lct = lct;
117234370Sjasone    device_set_softc(child, psc);
118234370Sjasone    return bus_generic_attach(sc->dev);
119234370Sjasone}
120234370Sjasone
121234370Sjasonestatic int
122234370Sjasonepst_probe(device_t dev)
123234370Sjasone{
124234370Sjasone    device_set_desc(dev, "Promise SuperTrak RAID");
125234370Sjasone    return 0;
126234370Sjasone}
127234370Sjasone
128234370Sjasonestatic int
129234370Sjasonepst_attach(device_t dev)
130234370Sjasone{
131234370Sjasone    struct pst_softc *psc = device_get_softc(dev);
132234370Sjasone    struct i2o_get_param_reply *reply;
133234370Sjasone    struct i2o_device_identity *ident;
134234370Sjasone    int lun = device_get_unit(dev);
135234370Sjasone    int8_t name [32];
136234370Sjasone
137234370Sjasone    if (!(reply = iop_get_util_params(psc->iop, psc->lct->local_tid,
138234370Sjasone				      I2O_PARAMS_OPERATION_FIELD_GET,
139234370Sjasone				      I2O_BSA_DEVICE_INFO_GROUP_NO)))
140234370Sjasone	return ENODEV;
141234370Sjasone
142234370Sjasone    if (!(psc->info = (struct i2o_bsa_device *)
143234370Sjasone	    malloc(sizeof(struct i2o_bsa_device), M_PSTRAID, M_NOWAIT))) {
144234370Sjasone	contigfree(reply, PAGE_SIZE, M_PSTRAID);
145235238Sjasone	return ENOMEM;
146234370Sjasone    }
147234370Sjasone    bcopy(reply->result, psc->info, sizeof(struct i2o_bsa_device));
148234370Sjasone    contigfree(reply, PAGE_SIZE, M_PSTRAID);
149234370Sjasone
150235238Sjasone    if (!(reply = iop_get_util_params(psc->iop, psc->lct->local_tid,
151235238Sjasone				      I2O_PARAMS_OPERATION_FIELD_GET,
152234370Sjasone				      I2O_UTIL_DEVICE_IDENTITY_GROUP_NO)))
153234370Sjasone	return ENODEV;
154234370Sjasone    ident = (struct i2o_device_identity *)reply->result;
155234370Sjasone#ifdef PSTDEBUG
156234370Sjasone    printf("pst: vendor=<%.16s> product=<%.16s>\n",
157235238Sjasone	   ident->vendor, ident->product);
158234370Sjasone    printf("pst: description=<%.16s> revision=<%.8s>\n",
159234370Sjasone	   ident->description, ident->revision);
160234370Sjasone    printf("pst: capacity=%lld blocksize=%d\n",
161234370Sjasone	   psc->info->capacity, psc->info->block_size);
162234370Sjasone#endif
163234370Sjasone    bpack(ident->vendor, ident->vendor, 16);
164234370Sjasone    bpack(ident->product, ident->product, 16);
165235238Sjasone    sprintf(name, "%s %s", ident->vendor, ident->product);
166235238Sjasone    contigfree(reply, PAGE_SIZE, M_PSTRAID);
167235238Sjasone
168235238Sjasone    bioq_init(&psc->queue);
169235238Sjasone    mtx_init(&psc->mtx, "pst lock", MTX_DEF, 0);
170235238Sjasone
171234370Sjasone    psc->device = disk_create(lun, &psc->disk, 0, &pst_cdevsw, &pstdisk_cdevsw);
172234370Sjasone    psc->device->si_drv1 = psc;
173234370Sjasone    psc->device->si_iosize_max = 64 * 1024; /*I2O_SGL_MAX_SEGS * PAGE_SIZE;*/
174234370Sjasone
175234370Sjasone    psc->disk.d_sectorsize = psc->info->block_size;
176234370Sjasone    psc->disk.d_mediasize = psc->info->capacity;
177234370Sjasone    psc->disk.d_fssectors = 63;
178234370Sjasone    psc->disk.d_fsheads = 255;
179234370Sjasone
180234370Sjasone    devstat_add_entry(&psc->stats, "pst", lun, psc->info->block_size,
181234370Sjasone		      DEVSTAT_NO_ORDERED_TAGS,
182234370Sjasone		      DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE,
183234370Sjasone		      DEVSTAT_PRIORITY_DISK);
184234370Sjasone
185234370Sjasone    printf("pst%d: %lluMB <%.40s> [%d/%d/%d] on %.16s\n", lun,
186234370Sjasone	   (unsigned long long)psc->disk.d_label.d_secperunit / (1024 * 2),
187234370Sjasone	   name, psc->disk.d_label.d_ncylinders, 255, 63,
188234370Sjasone	   device_get_nameunit(psc->iop->dev));
189234370Sjasone
190234370Sjasone    EVENTHANDLER_REGISTER(shutdown_post_sync, pst_shutdown,
191234370Sjasone			  dev, SHUTDOWN_PRI_FIRST);
192234370Sjasone    return 0;
193234370Sjasone}
194234370Sjasone
195234370Sjasonestatic int
196234370Sjasonepst_shutdown(device_t dev)
197234370Sjasone{
198234370Sjasone    struct pst_softc *psc = device_get_softc(dev);
199234370Sjasone    struct i2o_bsa_cache_flush_message *msg;
200234370Sjasone    int mfa;
201234370Sjasone
202234370Sjasone    mfa = iop_get_mfa(psc->iop);
203234370Sjasone    msg = (struct i2o_bsa_cache_flush_message *)(psc->iop->ibase + mfa);
204234370Sjasone    bzero(msg, sizeof(struct i2o_bsa_cache_flush_message));
205234370Sjasone    msg->version_offset = 0x01;
206234370Sjasone    msg->message_flags = 0x0;
207234370Sjasone    msg->message_size = sizeof(struct i2o_bsa_cache_flush_message) >> 2;
208234370Sjasone    msg->target_address = psc->lct->local_tid;
209234370Sjasone    msg->initiator_address = I2O_TID_HOST;
210234370Sjasone    msg->function = I2O_BSA_CACHE_FLUSH;
211234370Sjasone    msg->control_flags = 0x0; /* 0x80 = post progress reports */
212234370Sjasone    if (iop_queue_wait_msg(psc->iop, mfa, (struct i2o_basic_message *)msg))
213234370Sjasone	printf("pst: shutdown failed!\n");
214234370Sjasone    return 0;
215234370Sjasone}
216234370Sjasone
217234370Sjasonestatic void
218234370Sjasonepststrategy(struct bio *bp)
219234370Sjasone{
220234370Sjasone    struct pst_softc *psc = bp->bio_dev->si_drv1;
221234370Sjasone
222234370Sjasone    mtx_lock(&psc->mtx);
223234370Sjasone    bioqdisksort(&psc->queue, bp);
224234370Sjasone    pst_start(psc);
225234370Sjasone    mtx_unlock(&psc->mtx);
226234370Sjasone}
227234370Sjasone
228234370Sjasonestatic void
229234370Sjasonepst_start(struct pst_softc *psc)
230234370Sjasone{
231234370Sjasone    struct pst_request *request;
232234370Sjasone    struct bio *bp;
233234370Sjasone    u_int32_t mfa;
234234370Sjasone
235234370Sjasone    if (psc->outstanding < (I2O_IOP_OUTBOUND_FRAME_COUNT - 1) &&
236234370Sjasone	(bp = bioq_first(&psc->queue))) {
237234370Sjasone	if ((mfa = iop_get_mfa(psc->iop)) != 0xffffffff) {
238234370Sjasone	    if (!(request = malloc(sizeof(struct pst_request),
239234370Sjasone				   M_PSTRAID, M_NOWAIT | M_ZERO))) {
240234370Sjasone		printf("pst: out of memory in start\n");
241234370Sjasone		iop_free_mfa(psc->iop, mfa);
242234370Sjasone		return;
243234370Sjasone	    }
244234370Sjasone	    psc->outstanding++;
245234370Sjasone	    request->psc = psc;
246234370Sjasone	    request->mfa = mfa;
247234370Sjasone	    request->bp = bp;
248234370Sjasone	    if (dumping)
249234370Sjasone		request->timeout_handle.callout = NULL;
250234370Sjasone	    else
251234370Sjasone		request->timeout_handle =
252234370Sjasone		    timeout((timeout_t*)pst_timeout, request, 10 * hz);
253234370Sjasone	    bioq_remove(&psc->queue, bp);
254234370Sjasone	    devstat_start_transaction(&psc->stats);
255234370Sjasone	    if (pst_rw(request)) {
256234370Sjasone		biofinish(request->bp, &psc->stats, EIO);
257234370Sjasone		iop_free_mfa(request->psc->iop, request->mfa);
258234370Sjasone		psc->outstanding--;
259234370Sjasone		free(request, M_PSTRAID);
260234370Sjasone	    }
261234370Sjasone	}
262234370Sjasone    }
263234370Sjasone}
264234370Sjasone
265234370Sjasonestatic void
266234370Sjasonepst_done(struct iop_softc *sc, u_int32_t mfa, struct i2o_single_reply *reply)
267234370Sjasone{
268234370Sjasone    struct pst_request *request =
269234370Sjasone	(struct pst_request *)reply->transaction_context;
270234370Sjasone    struct pst_softc *psc = request->psc;
271234370Sjasone
272234370Sjasone    untimeout((timeout_t *)pst_timeout, request, request->timeout_handle);
273234370Sjasone    request->bp->bio_resid = request->bp->bio_bcount - reply->donecount;
274234370Sjasone    biofinish(request->bp, &psc->stats, reply->status ? EIO : 0);
275234370Sjasone    free(request, M_PSTRAID);
276234370Sjasone    mtx_lock(&psc->mtx);
277234370Sjasone    psc->iop->reg->oqueue = mfa;
278234370Sjasone    psc->outstanding--;
279234370Sjasone    pst_start(psc);
280234370Sjasone    mtx_unlock(&psc->mtx);
281234370Sjasone}
282234370Sjasone
283234370Sjasonestatic void
284234370Sjasonepst_timeout(struct pst_request *request)
285234370Sjasone{
286234370Sjasone    printf("pst: timeout mfa=0x%08x cmd=0x%02x\n",
287234370Sjasone	   request->mfa, request->bp->bio_cmd);
288234370Sjasone    mtx_lock(&request->psc->mtx);
289234370Sjasone    iop_free_mfa(request->psc->iop, request->mfa);
290234370Sjasone    if ((request->mfa = iop_get_mfa(request->psc->iop)) == 0xffffffff) {
291234370Sjasone	printf("pst: timeout no mfa possible\n");
292234370Sjasone	biofinish(request->bp, &request->psc->stats, EIO);
293234370Sjasone	request->psc->outstanding--;
294234370Sjasone	mtx_unlock(&request->psc->mtx);
295234370Sjasone	return;
296234370Sjasone    }
297234370Sjasone    if (dumping)
298234370Sjasone	request->timeout_handle.callout = NULL;
299234370Sjasone    else
300234370Sjasone	request->timeout_handle =
301234370Sjasone	    timeout((timeout_t*)pst_timeout, request, 10 * hz);
302234370Sjasone    if (pst_rw(request)) {
303234370Sjasone	iop_free_mfa(request->psc->iop, request->mfa);
304234370Sjasone	biofinish(request->bp, &request->psc->stats, EIO);
305234370Sjasone	request->psc->outstanding--;
306234370Sjasone    }
307234370Sjasone    mtx_unlock(&request->psc->mtx);
308234370Sjasone}
309234370Sjasone
310234370Sjasoneint
311234370Sjasonepst_rw(struct pst_request *request)
312234370Sjasone{
313234370Sjasone    struct i2o_bsa_rw_block_message *msg;
314234370Sjasone    int sgl_flag;
315234370Sjasone
316234370Sjasone    msg = (struct i2o_bsa_rw_block_message *)
317234370Sjasone	  (request->psc->iop->ibase + request->mfa);
318234370Sjasone    bzero(msg, sizeof(struct i2o_bsa_rw_block_message));
319234370Sjasone    msg->version_offset = 0x81;
320234370Sjasone    msg->message_flags = 0x0;
321234370Sjasone    msg->message_size = sizeof(struct i2o_bsa_rw_block_message) >> 2;
322234370Sjasone    msg->target_address = request->psc->lct->local_tid;
323234370Sjasone    msg->initiator_address = I2O_TID_HOST;
324234370Sjasone    switch (request->bp->bio_cmd) {
325234370Sjasone    case BIO_READ:
326234370Sjasone	msg->function = I2O_BSA_BLOCK_READ;
327234370Sjasone	msg->control_flags = 0x0; /* 0x0c = read cache + readahead */
328234370Sjasone	msg->fetch_ahead = 0x0; /* 8 Kb */
329234370Sjasone	sgl_flag = 0;
330234370Sjasone	break;
331234370Sjasone    case BIO_WRITE:
332234370Sjasone	msg->function = I2O_BSA_BLOCK_WRITE;
333234370Sjasone	msg->control_flags = 0x0; /* 0x10 = write behind cache */
334234370Sjasone	msg->fetch_ahead = 0x0;
335234370Sjasone	sgl_flag = I2O_SGL_DIR;
336234370Sjasone	break;
337234370Sjasone    default:
338234370Sjasone	printf("pst: unknown command type\n");
339234370Sjasone	return -1;
340234370Sjasone    }
341234370Sjasone    msg->initiator_context = (u_int32_t)pst_done;
342234370Sjasone    msg->transaction_context = (u_int32_t)request;
343234370Sjasone    msg->time_multiplier = 1;
344234370Sjasone    msg->bytecount = request->bp->bio_bcount;
345234370Sjasone    msg->lba = ((u_int64_t)request->bp->bio_pblkno) * (DEV_BSIZE * 1LL);
346234370Sjasone    if (!iop_create_sgl((struct i2o_basic_message *)msg, request->bp->bio_data,
347234370Sjasone			request->bp->bio_bcount, sgl_flag))
348234370Sjasone	return -1;
349234370Sjasone    request->psc->iop->reg->iqueue = request->mfa;
350234370Sjasone    return 0;
351234370Sjasone}
352234370Sjasone
353234370Sjasonestatic void
354234370Sjasonebpack(int8_t *src, int8_t *dst, int len)
355234370Sjasone{
356234370Sjasone    int i, j, blank;
357234370Sjasone    int8_t *ptr, *buf = dst;
358234370Sjasone
359234370Sjasone    for (i = j = blank = 0 ; i < len; i++) {
360234370Sjasone	if (blank && src[i] == ' ') continue;
361234370Sjasone	if (blank && src[i] != ' ') {
362234370Sjasone	    dst[j++] = src[i];
363234370Sjasone	    blank = 0;
364234370Sjasone	    continue;
365234370Sjasone	}
366234370Sjasone	if (src[i] == ' ') {
367234370Sjasone	    blank = 1;
368234370Sjasone	    if (i == 0)
369234370Sjasone		continue;
370234370Sjasone	}
371234370Sjasone	dst[j++] = src[i];
372234370Sjasone    }
373234370Sjasone    if (j < len)
374234370Sjasone	dst[j] = 0x00;
375234370Sjasone    for (ptr = buf; ptr < buf+len; ++ptr)
376234370Sjasone	if (!*ptr)
377234370Sjasone	    *ptr = ' ';
378234370Sjasone    for (ptr = buf + len - 1; ptr >= buf && *ptr == ' '; --ptr)
379234370Sjasone        *ptr = 0;
380234370Sjasone}
381234370Sjasone
382234370Sjasonestatic device_method_t pst_methods[] = {
383234370Sjasone    DEVMETHOD(device_probe,	pst_probe),
384234370Sjasone    DEVMETHOD(device_attach,	pst_attach),
385234370Sjasone    { 0, 0 }
386234370Sjasone};
387234370Sjasone
388234370Sjasonestatic driver_t pst_driver = {
389234370Sjasone    "pst",
390234370Sjasone    pst_methods,
391234370Sjasone    sizeof(struct pst_softc),
392234370Sjasone};
393234370Sjasone
394234370Sjasonestatic devclass_t pst_devclass;
395234370Sjasone
396234370SjasoneDRIVER_MODULE(pst, pstpci, pst_driver, pst_devclass, 0, 0);
397234370Sjasone