pst-raid.c revision 102058
1101100Ssos/*- 2101100Ssos * Copyright (c) 2001,2002 S�ren Schmidt <sos@FreeBSD.org> 3101100Ssos * All rights reserved. 4101100Ssos * 5101100Ssos * Redistribution and use in source and binary forms, with or without 6101100Ssos * modification, are permitted provided that the following conditions 7101100Ssos * are met: 8101100Ssos * 1. Redistributions of source code must retain the above copyright 9101100Ssos * notice, this list of conditions and the following disclaimer, 10101100Ssos * without modification, immediately at the beginning of the file. 11101100Ssos * 2. Redistributions in binary form must reproduce the above copyright 12101100Ssos * notice, this list of conditions and the following disclaimer in the 13101100Ssos * documentation and/or other materials provided with the distribution. 14101100Ssos * 3. The name of the author may not be used to endorse or promote products 15101100Ssos * derived from this software without specific prior written permission. 16101100Ssos * 17101100Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18101100Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19101100Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20101100Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21101100Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22101100Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23101100Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24101100Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25101100Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26101100Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27101100Ssos * 28101100Ssos * $FreeBSD: head/sys/dev/pst/pst-raid.c 102058 2002-08-18 12:20:33Z sos $ 29101100Ssos */ 30101100Ssos 31101100Ssos#include <sys/param.h> 32101100Ssos#include <sys/systm.h> 33101100Ssos#include <sys/kernel.h> 34101100Ssos#include <sys/module.h> 35101100Ssos#include <sys/bus.h> 36101100Ssos#include <sys/bio.h> 37101100Ssos#include <sys/conf.h> 38101100Ssos#include <sys/disk.h> 39101100Ssos#include <sys/devicestat.h> 40101100Ssos#include <sys/eventhandler.h> 41101100Ssos#include <sys/malloc.h> 42101100Ssos#include <sys/lock.h> 43101100Ssos#include <sys/mutex.h> 44101100Ssos#include <vm/vm.h> 45101100Ssos#include <vm/pmap.h> 46101100Ssos#include <machine/stdarg.h> 47101100Ssos#include <machine/resource.h> 48101100Ssos#include <machine/bus.h> 49101100Ssos#include <sys/rman.h> 50101100Ssos#include <pci/pcivar.h> 51101100Ssos#include <pci/pcireg.h> 52101100Ssos 53101100Ssos#include "dev/pst/pst-iop.h" 54101100Ssos 55101100Ssos/* device structures */ 56101100Ssosstatic d_strategy_t pststrategy; 57101100Ssosstatic struct cdevsw pst_cdevsw = { 58101100Ssos /* open */ nullopen, 59101100Ssos /* close */ nullclose, 60101100Ssos /* read */ physread, 61101100Ssos /* write */ physwrite, 62101100Ssos /* ioctl */ noioctl, 63101100Ssos /* poll */ nopoll, 64101100Ssos /* mmap */ nommap, 65101100Ssos /* strat */ pststrategy, 66101100Ssos /* name */ "pst", 67101100Ssos /* maj */ 200, 68101100Ssos /* dump */ nodump, 69101100Ssos /* psize */ nopsize, 70101100Ssos /* flags */ D_DISK, 71101100Ssos}; 72101100Ssosstatic struct cdevsw pstdisk_cdevsw; 73101100Ssos 74101100Ssosstruct pst_softc { 75102058Ssos struct iop_softc *iop; 76102058Ssos struct i2o_lct_entry *lct; 77102058Ssos struct i2o_bsa_device *info; 78102058Ssos dev_t device; 79102058Ssos struct devstat stats; 80102058Ssos struct disk disk; 81102058Ssos struct bio_queue_head queue; 82102058Ssos struct mtx mtx; 83102058Ssos int outstanding; 84101100Ssos}; 85101100Ssos 86101100Ssosstruct pst_request { 87101100Ssos struct pst_softc *psc; /* pointer to softc */ 88101100Ssos u_int32_t mfa; /* frame addreess */ 89101100Ssos struct callout_handle timeout_handle; /* handle for untimeout */ 90101100Ssos struct bio *bp; /* associated bio ptr */ 91101100Ssos}; 92101100Ssos 93101100Ssos/* prototypes */ 94101100Ssosstatic int pst_probe(device_t); 95101100Ssosstatic int pst_attach(device_t); 96101100Ssosstatic int pst_shutdown(device_t); 97101100Ssosstatic void pst_start(struct pst_softc *); 98101100Ssosstatic void pst_done(struct iop_softc *, u_int32_t, struct i2o_single_reply *); 99101100Ssosstatic int pst_rw(struct pst_request *); 100101100Ssosstatic void pst_timeout(struct pst_request *); 101101100Ssosstatic void bpack(int8_t *, int8_t *, int); 102101100Ssos 103101100Ssos/* local vars */ 104101100Ssosstatic MALLOC_DEFINE(M_PSTRAID, "pst", "Promise SuperTrak RAID driver"); 105101100Ssos 106101100Ssosint 107101100Ssospst_add_raid(struct iop_softc *sc, struct i2o_lct_entry *lct) 108101100Ssos{ 109101100Ssos struct pst_softc *psc; 110101100Ssos device_t child = device_add_child(sc->dev, "pst", -1); 111101100Ssos 112101100Ssos if (!child) 113101100Ssos return ENOMEM; 114101100Ssos psc = malloc(sizeof(struct pst_softc), M_PSTRAID, M_NOWAIT | M_ZERO); 115101100Ssos psc->iop = sc; 116101100Ssos psc->lct = lct; 117101100Ssos device_set_softc(child, psc); 118101100Ssos return bus_generic_attach(sc->dev); 119101100Ssos} 120101100Ssos 121101100Ssosstatic int 122101100Ssospst_probe(device_t dev) 123101100Ssos{ 124101100Ssos device_set_desc(dev, "Promise SuperTrak RAID"); 125101100Ssos return 0; 126101100Ssos} 127101100Ssos 128101100Ssosstatic int 129101100Ssospst_attach(device_t dev) 130101100Ssos{ 131101100Ssos struct pst_softc *psc = device_get_softc(dev); 132101100Ssos struct i2o_get_param_reply *reply; 133101100Ssos struct i2o_device_identity *ident; 134101100Ssos int lun = device_get_unit(dev); 135101100Ssos int8_t name [32]; 136101100Ssos 137101100Ssos if (!(reply = iop_get_util_params(psc->iop, psc->lct->local_tid, 138101100Ssos I2O_PARAMS_OPERATION_FIELD_GET, 139101100Ssos I2O_BSA_DEVICE_INFO_GROUP_NO))) 140101100Ssos return ENODEV; 141101100Ssos 142101100Ssos if (!(psc->info = (struct i2o_bsa_device *) 143101100Ssos malloc(sizeof(struct i2o_bsa_device), M_PSTRAID, M_NOWAIT))) { 144101100Ssos contigfree(reply, PAGE_SIZE, M_PSTRAID); 145101100Ssos return ENOMEM; 146101100Ssos } 147101100Ssos bcopy(reply->result, psc->info, sizeof(struct i2o_bsa_device)); 148101100Ssos contigfree(reply, PAGE_SIZE, M_PSTRAID); 149101100Ssos 150101100Ssos if (!(reply = iop_get_util_params(psc->iop, psc->lct->local_tid, 151101100Ssos I2O_PARAMS_OPERATION_FIELD_GET, 152101100Ssos I2O_UTIL_DEVICE_IDENTITY_GROUP_NO))) 153101100Ssos return ENODEV; 154101100Ssos ident = (struct i2o_device_identity *)reply->result; 155101100Ssos#ifdef PSTDEBUG 156101100Ssos printf("pst: vendor=<%.16s> product=<%.16s>\n", 157101100Ssos ident->vendor, ident->product); 158101100Ssos printf("pst: description=<%.16s> revision=<%.8s>\n", 159101100Ssos ident->description, ident->revision); 160101100Ssos printf("pst: capacity=%lld blocksize=%d\n", 161101100Ssos psc->info->capacity, psc->info->block_size); 162101100Ssos#endif 163101100Ssos bpack(ident->vendor, ident->vendor, 16); 164101100Ssos bpack(ident->product, ident->product, 16); 165101100Ssos sprintf(name, "%s %s", ident->vendor, ident->product); 166101100Ssos contigfree(reply, PAGE_SIZE, M_PSTRAID); 167101100Ssos 168101100Ssos bioq_init(&psc->queue); 169101100Ssos mtx_init(&psc->mtx, "pst lock", MTX_DEF, 0); 170101100Ssos 171101100Ssos psc->device = disk_create(lun, &psc->disk, 0, &pst_cdevsw, &pstdisk_cdevsw); 172101100Ssos psc->device->si_drv1 = psc; 173101100Ssos psc->device->si_iosize_max = 64 * 1024; /*I2O_SGL_MAX_SEGS * PAGE_SIZE;*/ 174101100Ssos 175101100Ssos bzero(&psc->disk.d_label, sizeof(struct disklabel)); 176101100Ssos psc->disk.d_label.d_secsize = psc->info->block_size; 177101100Ssos psc->disk.d_label.d_nsectors = 63; 178101100Ssos psc->disk.d_label.d_ntracks = 255; 179101100Ssos psc->disk.d_label.d_ncylinders = 180101100Ssos (psc->info->capacity / psc->info->block_size) / (255 * 63); 181101100Ssos psc->disk.d_label.d_secpercyl = 255 * 63; 182101100Ssos psc->disk.d_label.d_secperunit = 183101100Ssos psc->info->capacity / psc->info->block_size; 184101100Ssos 185101100Ssos devstat_add_entry(&psc->stats, "pst", lun, psc->info->block_size, 186101100Ssos DEVSTAT_NO_ORDERED_TAGS, 187101100Ssos DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE, 188101100Ssos DEVSTAT_PRIORITY_DISK); 189101100Ssos 190101100Ssos printf("pst%d: %lluMB <%.40s> [%d/%d/%d] on %.16s\n", lun, 191101100Ssos (unsigned long long)psc->disk.d_label.d_secperunit / (1024 * 2), 192101100Ssos name, psc->disk.d_label.d_ncylinders, 255, 63, 193101100Ssos device_get_nameunit(psc->iop->dev)); 194101100Ssos 195101100Ssos EVENTHANDLER_REGISTER(shutdown_post_sync, pst_shutdown, 196101100Ssos dev, SHUTDOWN_PRI_FIRST); 197101100Ssos return 0; 198101100Ssos} 199101100Ssos 200101100Ssosstatic int 201101100Ssospst_shutdown(device_t dev) 202101100Ssos{ 203101100Ssos struct pst_softc *psc = device_get_softc(dev); 204101100Ssos struct i2o_bsa_cache_flush_message *msg; 205101100Ssos int mfa; 206101100Ssos 207101100Ssos mfa = iop_get_mfa(psc->iop); 208101100Ssos msg = (struct i2o_bsa_cache_flush_message *)(psc->iop->ibase + mfa); 209101100Ssos bzero(msg, sizeof(struct i2o_bsa_cache_flush_message)); 210101100Ssos msg->version_offset = 0x01; 211101100Ssos msg->message_flags = 0x0; 212101100Ssos msg->message_size = sizeof(struct i2o_bsa_cache_flush_message) >> 2; 213101100Ssos msg->target_address = psc->lct->local_tid; 214101100Ssos msg->initiator_address = I2O_TID_HOST; 215101100Ssos msg->function = I2O_BSA_CACHE_FLUSH; 216101100Ssos msg->control_flags = 0x0; /* 0x80 = post progress reports */ 217101100Ssos if (iop_queue_wait_msg(psc->iop, mfa, (struct i2o_basic_message *)msg)) 218101100Ssos printf("pst: shutdown failed!\n"); 219101100Ssos return 0; 220101100Ssos} 221101100Ssos 222101100Ssosstatic void 223101100Ssospststrategy(struct bio *bp) 224101100Ssos{ 225101100Ssos struct pst_softc *psc = bp->bio_dev->si_drv1; 226101100Ssos 227101100Ssos mtx_lock(&psc->mtx); 228101100Ssos bioqdisksort(&psc->queue, bp); 229101100Ssos pst_start(psc); 230101100Ssos mtx_unlock(&psc->mtx); 231101100Ssos} 232101100Ssos 233101100Ssosstatic void 234101100Ssospst_start(struct pst_softc *psc) 235101100Ssos{ 236101100Ssos struct pst_request *request; 237101100Ssos struct bio *bp; 238101100Ssos u_int32_t mfa; 239101100Ssos 240101100Ssos if (psc->outstanding < (I2O_IOP_OUTBOUND_FRAME_COUNT - 1) && 241101100Ssos (bp = bioq_first(&psc->queue))) { 242101100Ssos if ((mfa = iop_get_mfa(psc->iop)) != 0xffffffff) { 243101100Ssos if (!(request = malloc(sizeof(struct pst_request), 244101100Ssos M_PSTRAID, M_NOWAIT | M_ZERO))) { 245101100Ssos printf("pst: out of memory in start\n"); 246101100Ssos iop_free_mfa(psc->iop, mfa); 247101100Ssos return; 248101100Ssos } 249101100Ssos psc->outstanding++; 250101100Ssos request->psc = psc; 251101100Ssos request->mfa = mfa; 252101100Ssos request->bp = bp; 253101100Ssos if (dumping) 254101100Ssos request->timeout_handle.callout = NULL; 255101100Ssos else 256101100Ssos request->timeout_handle = 257102058Ssos timeout((timeout_t*)pst_timeout, request, 10 * hz); 258101100Ssos bioq_remove(&psc->queue, bp); 259101100Ssos devstat_start_transaction(&psc->stats); 260101100Ssos if (pst_rw(request)) { 261101100Ssos biofinish(request->bp, &psc->stats, EIO); 262101100Ssos iop_free_mfa(request->psc->iop, request->mfa); 263101100Ssos psc->outstanding--; 264101100Ssos free(request, M_PSTRAID); 265101100Ssos } 266101100Ssos } 267101100Ssos } 268101100Ssos} 269101100Ssos 270101100Ssosstatic void 271101100Ssospst_done(struct iop_softc *sc, u_int32_t mfa, struct i2o_single_reply *reply) 272101100Ssos{ 273101100Ssos struct pst_request *request = 274101100Ssos (struct pst_request *)reply->transaction_context; 275101100Ssos struct pst_softc *psc = request->psc; 276101100Ssos 277101100Ssos untimeout((timeout_t *)pst_timeout, request, request->timeout_handle); 278101100Ssos request->bp->bio_resid = request->bp->bio_bcount - reply->donecount; 279101100Ssos biofinish(request->bp, &psc->stats, reply->status ? EIO : 0); 280101100Ssos free(request, M_PSTRAID); 281101100Ssos mtx_lock(&psc->mtx); 282101100Ssos psc->iop->reg->oqueue = mfa; 283101100Ssos psc->outstanding--; 284101100Ssos pst_start(psc); 285101100Ssos mtx_unlock(&psc->mtx); 286101100Ssos} 287101100Ssos 288101100Ssosstatic void 289101100Ssospst_timeout(struct pst_request *request) 290101100Ssos{ 291101100Ssos printf("pst: timeout mfa=0x%08x cmd=0x%02x\n", 292101100Ssos request->mfa, request->bp->bio_cmd); 293101100Ssos mtx_lock(&request->psc->mtx); 294101100Ssos iop_free_mfa(request->psc->iop, request->mfa); 295101100Ssos if ((request->mfa = iop_get_mfa(request->psc->iop)) == 0xffffffff) { 296101100Ssos printf("pst: timeout no mfa possible\n"); 297101100Ssos biofinish(request->bp, &request->psc->stats, EIO); 298101100Ssos request->psc->outstanding--; 299101100Ssos mtx_unlock(&request->psc->mtx); 300101100Ssos return; 301101100Ssos } 302101100Ssos if (dumping) 303101100Ssos request->timeout_handle.callout = NULL; 304101100Ssos else 305101100Ssos request->timeout_handle = 306101100Ssos timeout((timeout_t*)pst_timeout, request, 10 * hz); 307101100Ssos if (pst_rw(request)) { 308101100Ssos iop_free_mfa(request->psc->iop, request->mfa); 309101100Ssos biofinish(request->bp, &request->psc->stats, EIO); 310101100Ssos request->psc->outstanding--; 311101100Ssos } 312101100Ssos mtx_unlock(&request->psc->mtx); 313101100Ssos} 314101100Ssos 315101100Ssosint 316101100Ssospst_rw(struct pst_request *request) 317101100Ssos{ 318101100Ssos struct i2o_bsa_rw_block_message *msg; 319101100Ssos int sgl_flag; 320101100Ssos 321101100Ssos msg = (struct i2o_bsa_rw_block_message *) 322101100Ssos (request->psc->iop->ibase + request->mfa); 323101100Ssos bzero(msg, sizeof(struct i2o_bsa_rw_block_message)); 324101100Ssos msg->version_offset = 0x81; 325101100Ssos msg->message_flags = 0x0; 326101100Ssos msg->message_size = sizeof(struct i2o_bsa_rw_block_message) >> 2; 327101100Ssos msg->target_address = request->psc->lct->local_tid; 328101100Ssos msg->initiator_address = I2O_TID_HOST; 329101100Ssos switch (request->bp->bio_cmd) { 330101100Ssos case BIO_READ: 331101100Ssos msg->function = I2O_BSA_BLOCK_READ; 332101100Ssos msg->control_flags = 0x0; /* 0x0c = read cache + readahead */ 333101100Ssos msg->fetch_ahead = 0x0; /* 8 Kb */ 334101100Ssos sgl_flag = 0; 335101100Ssos break; 336101100Ssos case BIO_WRITE: 337101100Ssos msg->function = I2O_BSA_BLOCK_WRITE; 338101100Ssos msg->control_flags = 0x0; /* 0x10 = write behind cache */ 339101100Ssos msg->fetch_ahead = 0x0; 340101100Ssos sgl_flag = I2O_SGL_DIR; 341101100Ssos break; 342101100Ssos default: 343101100Ssos printf("pst: unknown command type\n"); 344101100Ssos return -1; 345101100Ssos } 346101100Ssos msg->initiator_context = (u_int32_t)pst_done; 347101100Ssos msg->transaction_context = (u_int32_t)request; 348101100Ssos msg->time_multiplier = 1; 349101100Ssos msg->bytecount = request->bp->bio_bcount; 350101100Ssos msg->lba = ((u_int64_t)request->bp->bio_pblkno) * (DEV_BSIZE * 1LL); 351101100Ssos if (!iop_create_sgl((struct i2o_basic_message *)msg, request->bp->bio_data, 352101100Ssos request->bp->bio_bcount, sgl_flag)) 353101100Ssos return -1; 354101100Ssos request->psc->iop->reg->iqueue = request->mfa; 355101100Ssos return 0; 356101100Ssos} 357101100Ssos 358101100Ssosstatic void 359101100Ssosbpack(int8_t *src, int8_t *dst, int len) 360101100Ssos{ 361101100Ssos int i, j, blank; 362101100Ssos int8_t *ptr, *buf = dst; 363101100Ssos 364101100Ssos for (i = j = blank = 0 ; i < len; i++) { 365101100Ssos if (blank && src[i] == ' ') continue; 366101100Ssos if (blank && src[i] != ' ') { 367101100Ssos dst[j++] = src[i]; 368101100Ssos blank = 0; 369101100Ssos continue; 370101100Ssos } 371101100Ssos if (src[i] == ' ') { 372101100Ssos blank = 1; 373101100Ssos if (i == 0) 374101100Ssos continue; 375101100Ssos } 376101100Ssos dst[j++] = src[i]; 377101100Ssos } 378101100Ssos if (j < len) 379101100Ssos dst[j] = 0x00; 380101100Ssos for (ptr = buf; ptr < buf+len; ++ptr) 381101100Ssos if (!*ptr) 382101100Ssos *ptr = ' '; 383101100Ssos for (ptr = buf + len - 1; ptr >= buf && *ptr == ' '; --ptr) 384101100Ssos *ptr = 0; 385101100Ssos} 386101100Ssos 387101100Ssosstatic device_method_t pst_methods[] = { 388101100Ssos DEVMETHOD(device_probe, pst_probe), 389101100Ssos DEVMETHOD(device_attach, pst_attach), 390101100Ssos { 0, 0 } 391101100Ssos}; 392101100Ssos 393101100Ssosstatic driver_t pst_driver = { 394101100Ssos "pst", 395101100Ssos pst_methods, 396101100Ssos sizeof(struct pst_softc), 397101100Ssos}; 398101100Ssos 399101100Ssosstatic devclass_t pst_devclass; 400101100Ssos 401101100SsosDRIVER_MODULE(pst, pstpci, pst_driver, pst_devclass, 0, 0); 402