pst-raid.c revision 104066
118334Speter/*- 218334Speter * Copyright (c) 2001,2002 S�ren Schmidt <sos@FreeBSD.org> 318334Speter * All rights reserved. 418334Speter * 518334Speter * Redistribution and use in source and binary forms, with or without 618334Speter * modification, are permitted provided that the following conditions 718334Speter * are met: 818334Speter * 1. Redistributions of source code must retain the above copyright 918334Speter * notice, this list of conditions and the following disclaimer, 1018334Speter * without modification, immediately at the beginning of the file. 1118334Speter * 2. Redistributions in binary form must reproduce the above copyright 1218334Speter * notice, this list of conditions and the following disclaimer in the 1318334Speter * documentation and/or other materials provided with the distribution. 1418334Speter * 3. The name of the author may not be used to endorse or promote products 1518334Speter * derived from this software without specific prior written permission. 1618334Speter * 1718334Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1818334Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1918334Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2018334Speter * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2118334Speter * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2218334Speter * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2318334Speter * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2418334Speter * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2518334Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2618334Speter * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2718334Speter * 2818334Speter * $FreeBSD: head/sys/dev/pst/pst-raid.c 104066 2002-09-27 21:56:35Z sos $ 2918334Speter */ 3018334Speter 3118334Speter#include <sys/param.h> 3218334Speter#include <sys/systm.h> 3318334Speter#include <sys/kernel.h> 3418334Speter#include <sys/module.h> 3518334Speter#include <sys/bus.h> 3618334Speter#include <sys/bio.h> 3718334Speter#include <sys/conf.h> 3818334Speter#include <sys/disk.h> 3918334Speter#include <sys/devicestat.h> 4018334Speter#include <sys/eventhandler.h> 4118334Speter#include <sys/malloc.h> 4218334Speter#include <sys/lock.h> 4318334Speter#include <sys/mutex.h> 4418334Speter#include <vm/vm.h> 4518334Speter#include <vm/pmap.h> 4618334Speter#include <machine/stdarg.h> 4718334Speter#include <machine/resource.h> 4818334Speter#include <machine/bus.h> 4918334Speter#include <sys/rman.h> 5018334Speter#include <pci/pcivar.h> 5118334Speter#include <pci/pcireg.h> 5218334Speter 5318334Speter#include "dev/pst/pst-iop.h" 5418334Speter 5518334Speter/* device structures */ 5618334Speterstatic d_strategy_t pststrategy; 5718334Speterstatic struct cdevsw pst_cdevsw = { 5818334Speter /* open */ nullopen, 5918334Speter /* close */ nullclose, 6018334Speter /* read */ physread, 6118334Speter /* write */ physwrite, 6218334Speter /* ioctl */ noioctl, 6318334Speter /* poll */ nopoll, 6418334Speter /* mmap */ nommap, 6518334Speter /* strat */ pststrategy, 6618334Speter /* name */ "pst", 6718334Speter /* maj */ 200, 6818334Speter /* dump */ nodump, 6918334Speter /* psize */ nopsize, 7018334Speter /* flags */ D_DISK, 7118334Speter}; 7218334Speterstatic struct cdevsw pstdisk_cdevsw; 7318334Speter 7418334Speterstruct pst_softc { 7518334Speter struct iop_softc *iop; 7618334Speter struct i2o_lct_entry *lct; 7718334Speter struct i2o_bsa_device *info; 7818334Speter dev_t device; 7918334Speter struct devstat stats; 8018334Speter struct disk disk; 8118334Speter struct bio_queue_head queue; 8218334Speter struct mtx mtx; 8318334Speter int outstanding; 8418334Speter}; 8518334Speter 8618334Speterstruct pst_request { 8718334Speter struct pst_softc *psc; /* pointer to softc */ 8818334Speter u_int32_t mfa; /* frame addreess */ 8918334Speter struct callout_handle timeout_handle; /* handle for untimeout */ 9018334Speter struct bio *bp; /* associated bio ptr */ 9118334Speter}; 9218334Speter 9318334Speter/* prototypes */ 9418334Speterstatic int pst_probe(device_t); 9518334Speterstatic int pst_attach(device_t); 9618334Speterstatic int pst_shutdown(device_t); 9718334Speterstatic void pst_start(struct pst_softc *); 9818334Speterstatic void pst_done(struct iop_softc *, u_int32_t, struct i2o_single_reply *); 9918334Speterstatic int pst_rw(struct pst_request *); 10018334Speterstatic void pst_timeout(struct pst_request *); 10118334Speterstatic void bpack(int8_t *, int8_t *, int); 10218334Speter 10318334Speter/* local vars */ 10418334Speterstatic MALLOC_DEFINE(M_PSTRAID, "pst", "Promise SuperTrak RAID driver"); 10518334Speter 10618334Speterint 10718334Speterpst_add_raid(struct iop_softc *sc, struct i2o_lct_entry *lct) 10818334Speter{ 10918334Speter struct pst_softc *psc; 11018334Speter device_t child = device_add_child(sc->dev, "pst", -1); 11118334Speter 11218334Speter if (!child) 11318334Speter return ENOMEM; 11418334Speter psc = malloc(sizeof(struct pst_softc), M_PSTRAID, M_NOWAIT | M_ZERO); 11518334Speter psc->iop = sc; 11618334Speter psc->lct = lct; 11718334Speter device_set_softc(child, psc); 11818334Speter return bus_generic_attach(sc->dev); 11918334Speter} 12018334Speter 12118334Speterstatic int 12218334Speterpst_probe(device_t dev) 12318334Speter{ 12418334Speter device_set_desc(dev, "Promise SuperTrak RAID"); 12518334Speter return 0; 12618334Speter} 12718334Speter 12818334Speterstatic int 12918334Speterpst_attach(device_t dev) 13018334Speter{ 13118334Speter struct pst_softc *psc = device_get_softc(dev); 13218334Speter struct i2o_get_param_reply *reply; 13318334Speter struct i2o_device_identity *ident; 13418334Speter int lun = device_get_unit(dev); 13518334Speter int8_t name [32]; 13618334Speter 13718334Speter if (!(reply = iop_get_util_params(psc->iop, psc->lct->local_tid, 13818334Speter I2O_PARAMS_OPERATION_FIELD_GET, 13918334Speter I2O_BSA_DEVICE_INFO_GROUP_NO))) 14018334Speter return ENODEV; 14118334Speter 14218334Speter if (!(psc->info = (struct i2o_bsa_device *) 14318334Speter malloc(sizeof(struct i2o_bsa_device), M_PSTRAID, M_NOWAIT))) { 14418334Speter contigfree(reply, PAGE_SIZE, M_PSTRAID); 14518334Speter return ENOMEM; 14618334Speter } 14718334Speter bcopy(reply->result, psc->info, sizeof(struct i2o_bsa_device)); 14818334Speter contigfree(reply, PAGE_SIZE, M_PSTRAID); 14918334Speter 15018334Speter if (!(reply = iop_get_util_params(psc->iop, psc->lct->local_tid, 15118334Speter I2O_PARAMS_OPERATION_FIELD_GET, 15218334Speter I2O_UTIL_DEVICE_IDENTITY_GROUP_NO))) 15318334Speter return ENODEV; 15418334Speter ident = (struct i2o_device_identity *)reply->result; 15518334Speter#ifdef PSTDEBUG 15618334Speter printf("pst: vendor=<%.16s> product=<%.16s>\n", 15718334Speter ident->vendor, ident->product); 15818334Speter printf("pst: description=<%.16s> revision=<%.8s>\n", 15918334Speter ident->description, ident->revision); 16018334Speter printf("pst: capacity=%lld blocksize=%d\n", 16118334Speter psc->info->capacity, psc->info->block_size); 16218334Speter#endif 16318334Speter bpack(ident->vendor, ident->vendor, 16); 16418334Speter bpack(ident->product, ident->product, 16); 16518334Speter sprintf(name, "%s %s", ident->vendor, ident->product); 16618334Speter contigfree(reply, PAGE_SIZE, M_PSTRAID); 16718334Speter 16818334Speter bioq_init(&psc->queue); 16918334Speter mtx_init(&psc->mtx, "pst lock", MTX_DEF, 0); 17018334Speter 17118334Speter psc->device = disk_create(lun, &psc->disk, 0, &pst_cdevsw, &pstdisk_cdevsw); 17218334Speter psc->device->si_drv1 = psc; 17318334Speter psc->device->si_iosize_max = 64 * 1024; /*I2O_SGL_MAX_SEGS * PAGE_SIZE;*/ 17418334Speter 17518334Speter psc->disk.d_sectorsize = psc->info->block_size; 17618334Speter psc->disk.d_mediasize = psc->info->capacity; 17718334Speter psc->disk.d_fwsectors = 63; 17818334Speter psc->disk.d_fwheads = 255; 17918334Speter 18018334Speter devstat_add_entry(&psc->stats, "pst", lun, psc->info->block_size, 18118334Speter DEVSTAT_NO_ORDERED_TAGS, 18218334Speter DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE, 18318334Speter DEVSTAT_PRIORITY_DISK); 18418334Speter 18518334Speter printf("pst%d: %lluMB <%.40s> [%lld/%d/%d] on %.16s\n", lun, 18618334Speter (unsigned long long)psc->info->capacity / (1024 * 1024), 18718334Speter name, psc->info->capacity/(512*255*63), 255, 63, 18818334Speter device_get_nameunit(psc->iop->dev)); 18918334Speter 19018334Speter EVENTHANDLER_REGISTER(shutdown_post_sync, pst_shutdown, 19118334Speter dev, SHUTDOWN_PRI_FIRST); 19218334Speter return 0; 19318334Speter} 19418334Speter 19518334Speterstatic int 19618334Speterpst_shutdown(device_t dev) 19718334Speter{ 19818334Speter struct pst_softc *psc = device_get_softc(dev); 19918334Speter struct i2o_bsa_cache_flush_message *msg; 20018334Speter int mfa; 20118334Speter 20218334Speter mfa = iop_get_mfa(psc->iop); 20318334Speter msg = (struct i2o_bsa_cache_flush_message *)(psc->iop->ibase + mfa); 20418334Speter bzero(msg, sizeof(struct i2o_bsa_cache_flush_message)); 20518334Speter msg->version_offset = 0x01; 20618334Speter msg->message_flags = 0x0; 20718334Speter msg->message_size = sizeof(struct i2o_bsa_cache_flush_message) >> 2; 20818334Speter msg->target_address = psc->lct->local_tid; 20918334Speter msg->initiator_address = I2O_TID_HOST; 21018334Speter msg->function = I2O_BSA_CACHE_FLUSH; 21118334Speter msg->control_flags = 0x0; /* 0x80 = post progress reports */ 21218334Speter if (iop_queue_wait_msg(psc->iop, mfa, (struct i2o_basic_message *)msg)) 21318334Speter printf("pst: shutdown failed!\n"); 21418334Speter return 0; 21518334Speter} 21618334Speter 21718334Speterstatic void 21818334Speterpststrategy(struct bio *bp) 21918334Speter{ 22018334Speter struct pst_softc *psc = bp->bio_dev->si_drv1; 22118334Speter 22218334Speter mtx_lock(&psc->mtx); 22318334Speter bioqdisksort(&psc->queue, bp); 22418334Speter pst_start(psc); 22518334Speter mtx_unlock(&psc->mtx); 22618334Speter} 22718334Speter 22818334Speterstatic void 22918334Speterpst_start(struct pst_softc *psc) 23018334Speter{ 23118334Speter struct pst_request *request; 23218334Speter struct bio *bp; 23318334Speter u_int32_t mfa; 23418334Speter 23518334Speter if (psc->outstanding < (I2O_IOP_OUTBOUND_FRAME_COUNT - 1) && 23618334Speter (bp = bioq_first(&psc->queue))) { 23718334Speter if ((mfa = iop_get_mfa(psc->iop)) != 0xffffffff) { 23818334Speter if (!(request = malloc(sizeof(struct pst_request), 23918334Speter M_PSTRAID, M_NOWAIT | M_ZERO))) { 24018334Speter printf("pst: out of memory in start\n"); 24118334Speter iop_free_mfa(psc->iop, mfa); 24218334Speter return; 24318334Speter } 24418334Speter psc->outstanding++; 24518334Speter request->psc = psc; 24618334Speter request->mfa = mfa; 24718334Speter request->bp = bp; 24818334Speter if (dumping) 24918334Speter request->timeout_handle.callout = NULL; 25018334Speter else 25118334Speter request->timeout_handle = 25218334Speter timeout((timeout_t*)pst_timeout, request, 10 * hz); 25318334Speter bioq_remove(&psc->queue, bp); 25418334Speter devstat_start_transaction(&psc->stats); 25518334Speter if (pst_rw(request)) { 25618334Speter biofinish(request->bp, &psc->stats, EIO); 25718334Speter iop_free_mfa(request->psc->iop, request->mfa); 25818334Speter psc->outstanding--; 25918334Speter free(request, M_PSTRAID); 26018334Speter } 26118334Speter } 26218334Speter } 26318334Speter} 26418334Speter 26518334Speterstatic void 26618334Speterpst_done(struct iop_softc *sc, u_int32_t mfa, struct i2o_single_reply *reply) 26718334Speter{ 26818334Speter struct pst_request *request = 26918334Speter (struct pst_request *)reply->transaction_context; 27018334Speter struct pst_softc *psc = request->psc; 27118334Speter 27218334Speter untimeout((timeout_t *)pst_timeout, request, request->timeout_handle); 27318334Speter request->bp->bio_resid = request->bp->bio_bcount - reply->donecount; 27418334Speter biofinish(request->bp, &psc->stats, reply->status ? EIO : 0); 27518334Speter free(request, M_PSTRAID); 27618334Speter mtx_lock(&psc->mtx); 27718334Speter psc->iop->reg->oqueue = mfa; 27818334Speter psc->outstanding--; 27918334Speter pst_start(psc); 28018334Speter mtx_unlock(&psc->mtx); 28118334Speter} 28218334Speter 28318334Speterstatic void 28418334Speterpst_timeout(struct pst_request *request) 28518334Speter{ 28618334Speter printf("pst: timeout mfa=0x%08x cmd=0x%02x\n", 28718334Speter request->mfa, request->bp->bio_cmd); 28818334Speter mtx_lock(&request->psc->mtx); 28918334Speter iop_free_mfa(request->psc->iop, request->mfa); 29018334Speter if ((request->mfa = iop_get_mfa(request->psc->iop)) == 0xffffffff) { 29118334Speter printf("pst: timeout no mfa possible\n"); 29218334Speter biofinish(request->bp, &request->psc->stats, EIO); 29318334Speter request->psc->outstanding--; 29418334Speter mtx_unlock(&request->psc->mtx); 29518334Speter return; 29618334Speter } 29718334Speter if (dumping) 29818334Speter request->timeout_handle.callout = NULL; 29918334Speter else 30018334Speter request->timeout_handle = 30118334Speter timeout((timeout_t*)pst_timeout, request, 10 * hz); 30218334Speter if (pst_rw(request)) { 30318334Speter iop_free_mfa(request->psc->iop, request->mfa); 30418334Speter biofinish(request->bp, &request->psc->stats, EIO); 30518334Speter request->psc->outstanding--; 30618334Speter } 30718334Speter mtx_unlock(&request->psc->mtx); 30818334Speter} 30918334Speter 31018334Speterint 31118334Speterpst_rw(struct pst_request *request) 31218334Speter{ 31318334Speter struct i2o_bsa_rw_block_message *msg; 31418334Speter int sgl_flag; 31518334Speter 31618334Speter msg = (struct i2o_bsa_rw_block_message *) 31718334Speter (request->psc->iop->ibase + request->mfa); 31818334Speter bzero(msg, sizeof(struct i2o_bsa_rw_block_message)); 31918334Speter msg->version_offset = 0x81; 32018334Speter msg->message_flags = 0x0; 32118334Speter msg->message_size = sizeof(struct i2o_bsa_rw_block_message) >> 2; 32218334Speter msg->target_address = request->psc->lct->local_tid; 32318334Speter msg->initiator_address = I2O_TID_HOST; 32418334Speter switch (request->bp->bio_cmd) { 32518334Speter case BIO_READ: 32618334Speter msg->function = I2O_BSA_BLOCK_READ; 32718334Speter msg->control_flags = 0x0; /* 0x0c = read cache + readahead */ 32818334Speter msg->fetch_ahead = 0x0; /* 8 Kb */ 32918334Speter sgl_flag = 0; 33018334Speter break; 33118334Speter case BIO_WRITE: 33218334Speter msg->function = I2O_BSA_BLOCK_WRITE; 33318334Speter msg->control_flags = 0x0; /* 0x10 = write behind cache */ 33418334Speter msg->fetch_ahead = 0x0; 33518334Speter sgl_flag = I2O_SGL_DIR; 33618334Speter break; 33718334Speter default: 33818334Speter printf("pst: unknown command type\n"); 33918334Speter return -1; 34018334Speter } 34118334Speter msg->initiator_context = (u_int32_t)pst_done; 34218334Speter msg->transaction_context = (u_int32_t)request; 34318334Speter msg->time_multiplier = 1; 34418334Speter msg->bytecount = request->bp->bio_bcount; 34518334Speter msg->lba = ((u_int64_t)request->bp->bio_pblkno) * (DEV_BSIZE * 1LL); 34618334Speter if (!iop_create_sgl((struct i2o_basic_message *)msg, request->bp->bio_data, 34718334Speter request->bp->bio_bcount, sgl_flag)) 34818334Speter return -1; 34918334Speter request->psc->iop->reg->iqueue = request->mfa; 35018334Speter return 0; 35118334Speter} 35218334Speter 35318334Speterstatic void 35418334Speterbpack(int8_t *src, int8_t *dst, int len) 35518334Speter{ 35618334Speter int i, j, blank; 35718334Speter int8_t *ptr, *buf = dst; 35818334Speter 35918334Speter for (i = j = blank = 0 ; i < len; i++) { 36018334Speter if (blank && src[i] == ' ') continue; 36118334Speter if (blank && src[i] != ' ') { 36218334Speter dst[j++] = src[i]; 36318334Speter blank = 0; 36418334Speter continue; 36518334Speter } 36618334Speter if (src[i] == ' ') { 36718334Speter blank = 1; 36818334Speter if (i == 0) 36918334Speter continue; 37018334Speter } 37118334Speter dst[j++] = src[i]; 37218334Speter } 37318334Speter if (j < len) 37418334Speter dst[j] = 0x00; 37518334Speter for (ptr = buf; ptr < buf+len; ++ptr) 37618334Speter if (!*ptr) 37718334Speter *ptr = ' '; 37818334Speter for (ptr = buf + len - 1; ptr >= buf && *ptr == ' '; --ptr) 37918334Speter *ptr = 0; 38018334Speter} 38118334Speter 38218334Speterstatic device_method_t pst_methods[] = { 38318334Speter DEVMETHOD(device_probe, pst_probe), 38418334Speter DEVMETHOD(device_attach, pst_attach), 38518334Speter { 0, 0 } 38618334Speter}; 38718334Speter 38818334Speterstatic driver_t pst_driver = { 38918334Speter "pst", 39018334Speter pst_methods, 39118334Speter sizeof(struct pst_softc), 39218334Speter}; 39318334Speter 39418334Speterstatic devclass_t pst_devclass; 39518334Speter 39618334SpeterDRIVER_MODULE(pst, pstpci, pst_driver, pst_devclass, 0, 0); 39718334Speter