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