mfi_disk.c revision 234429
1202375Srdivacky/*- 2202375Srdivacky * Copyright (c) 2006 IronPort Systems 3202375Srdivacky * All rights reserved. 4202375Srdivacky * 5202375Srdivacky * Redistribution and use in source and binary forms, with or without 6202375Srdivacky * modification, are permitted provided that the following conditions 7202375Srdivacky * are met: 8202375Srdivacky * 1. Redistributions of source code must retain the above copyright 9202375Srdivacky * notice, this list of conditions and the following disclaimer. 10202375Srdivacky * 2. Redistributions in binary form must reproduce the above copyright 11202375Srdivacky * notice, this list of conditions and the following disclaimer in the 12202375Srdivacky * documentation and/or other materials provided with the distribution. 13202375Srdivacky * 14202375Srdivacky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15202375Srdivacky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16249423Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17221345Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18202375Srdivacky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19249423Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20202375Srdivacky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21202375Srdivacky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22202375Srdivacky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23202375Srdivacky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24202375Srdivacky * SUCH DAMAGE. 25249423Sdim */ 26249423Sdim 27202375Srdivacky#include <sys/cdefs.h> 28202375Srdivacky__FBSDID("$FreeBSD: stable/9/sys/dev/mfi/mfi_disk.c 234429 2012-04-18 18:31:11Z ambrisko $"); 29202375Srdivacky 30202375Srdivacky#include "opt_mfi.h" 31202375Srdivacky 32202375Srdivacky#include <sys/param.h> 33202375Srdivacky#include <sys/systm.h> 34202375Srdivacky#include <sys/kernel.h> 35202375Srdivacky#include <sys/selinfo.h> 36202375Srdivacky#include <sys/module.h> 37202375Srdivacky#include <sys/malloc.h> 38202375Srdivacky#include <sys/sysctl.h> 39249423Sdim#include <sys/uio.h> 40202375Srdivacky 41202375Srdivacky#include <sys/bio.h> 42202375Srdivacky#include <sys/bus.h> 43249423Sdim#include <sys/conf.h> 44202375Srdivacky#include <sys/disk.h> 45202375Srdivacky#include <geom/geom_disk.h> 46202375Srdivacky 47249423Sdim#include <vm/vm.h> 48202375Srdivacky#include <vm/pmap.h> 49202375Srdivacky 50202375Srdivacky#include <machine/md_var.h> 51202375Srdivacky#include <machine/bus.h> 52202375Srdivacky#include <sys/rman.h> 53202375Srdivacky 54202375Srdivacky#include <dev/mfi/mfireg.h> 55202375Srdivacky#include <dev/mfi/mfi_ioctl.h> 56202375Srdivacky#include <dev/mfi/mfivar.h> 57202375Srdivacky 58202375Srdivackystatic int mfi_disk_probe(device_t dev); 59249423Sdimstatic int mfi_disk_attach(device_t dev); 60202375Srdivackystatic int mfi_disk_detach(device_t dev); 61202375Srdivacky 62202375Srdivackystatic disk_open_t mfi_disk_open; 63202375Srdivackystatic disk_close_t mfi_disk_close; 64202375Srdivackystatic disk_strategy_t mfi_disk_strategy; 65202375Srdivackystatic dumper_t mfi_disk_dump; 66202375Srdivacky 67202375Srdivackystatic devclass_t mfi_disk_devclass; 68202375Srdivacky 69202375Srdivackystatic device_method_t mfi_disk_methods[] = { 70202375Srdivacky DEVMETHOD(device_probe, mfi_disk_probe), 71202375Srdivacky DEVMETHOD(device_attach, mfi_disk_attach), 72202375Srdivacky DEVMETHOD(device_detach, mfi_disk_detach), 73202375Srdivacky { 0, 0 } 74202375Srdivacky}; 75202375Srdivacky 76202375Srdivackystatic driver_t mfi_disk_driver = { 77202375Srdivacky "mfid", 78202375Srdivacky mfi_disk_methods, 79202375Srdivacky sizeof(struct mfi_disk) 80202375Srdivacky}; 81202375Srdivacky 82202375SrdivackyDRIVER_MODULE(mfid, mfi, mfi_disk_driver, mfi_disk_devclass, 0, 0); 83202375Srdivacky 84202375Srdivackystatic int 85202375Srdivackymfi_disk_probe(device_t dev) 86202375Srdivacky{ 87202375Srdivacky 88202375Srdivacky return (0); 89202375Srdivacky} 90202375Srdivacky 91202375Srdivackystatic int 92202375Srdivackymfi_disk_attach(device_t dev) 93234353Sdim{ 94249423Sdim struct mfi_disk *sc; 95202375Srdivacky struct mfi_ld_info *ld_info; 96202375Srdivacky uint64_t sectors; 97234353Sdim uint32_t secsize; 98234353Sdim char *state; 99234353Sdim 100234353Sdim sc = device_get_softc(dev); 101234353Sdim ld_info = device_get_ivars(dev); 102234353Sdim 103202375Srdivacky sc->ld_dev = dev; 104202375Srdivacky sc->ld_id = ld_info->ld_config.properties.ld.v.target_id; 105202375Srdivacky sc->ld_unit = device_get_unit(dev); 106202375Srdivacky sc->ld_info = ld_info; 107202375Srdivacky sc->ld_controller = device_get_softc(device_get_parent(dev)); 108202375Srdivacky sc->ld_flags = 0; 109204792Srdivacky 110204792Srdivacky sectors = ld_info->size; 111204792Srdivacky secsize = MFI_SECTOR_LEN; 112202375Srdivacky mtx_lock(&sc->ld_controller->mfi_io_lock); 113234353Sdim TAILQ_INSERT_TAIL(&sc->ld_controller->mfi_ld_tqh, sc, ld_link); 114204792Srdivacky mtx_unlock(&sc->ld_controller->mfi_io_lock); 115204792Srdivacky 116204792Srdivacky switch (ld_info->ld_config.params.state) { 117204792Srdivacky case MFI_LD_STATE_OFFLINE: 118204792Srdivacky state = "offline"; 119204792Srdivacky break; 120204792Srdivacky case MFI_LD_STATE_PARTIALLY_DEGRADED: 121249423Sdim state = "partially degraded"; 122218893Sdim break; 123218893Sdim case MFI_LD_STATE_DEGRADED: 124202375Srdivacky state = "degraded"; 125204792Srdivacky break; 126202375Srdivacky case MFI_LD_STATE_OPTIMAL: 127202375Srdivacky state = "optimal"; 128202375Srdivacky break; 129202375Srdivacky default: 130202375Srdivacky state = "unknown"; 131202375Srdivacky break; 132202375Srdivacky } 133202375Srdivacky device_printf(dev, "%juMB (%ju sectors) RAID volume '%s' is %s\n", 134202375Srdivacky sectors / (1024 * 1024 / secsize), sectors, 135202375Srdivacky ld_info->ld_config.properties.name, 136202375Srdivacky state); 137202375Srdivacky 138202375Srdivacky sc->ld_disk = disk_alloc(); 139202375Srdivacky sc->ld_disk->d_drv1 = sc; 140202375Srdivacky sc->ld_disk->d_maxsize = min(sc->ld_controller->mfi_max_io * secsize, 141202375Srdivacky (sc->ld_controller->mfi_max_sge - 1) * PAGE_SIZE); 142202375Srdivacky sc->ld_disk->d_name = "mfid"; 143202375Srdivacky sc->ld_disk->d_open = mfi_disk_open; 144202375Srdivacky sc->ld_disk->d_close = mfi_disk_close; 145202375Srdivacky sc->ld_disk->d_strategy = mfi_disk_strategy; 146202375Srdivacky sc->ld_disk->d_dump = mfi_disk_dump; 147202375Srdivacky sc->ld_disk->d_unit = sc->ld_unit; 148202375Srdivacky sc->ld_disk->d_sectorsize = secsize; 149202375Srdivacky sc->ld_disk->d_mediasize = sectors * secsize; 150218893Sdim if (sc->ld_disk->d_mediasize >= (1 * 1024 * 1024)) { 151218893Sdim sc->ld_disk->d_fwheads = 255; 152218893Sdim sc->ld_disk->d_fwsectors = 63; 153218893Sdim } else { 154218893Sdim sc->ld_disk->d_fwheads = 64; 155218893Sdim sc->ld_disk->d_fwsectors = 32; 156218893Sdim } 157249423Sdim disk_create(sc->ld_disk, DISK_VERSION); 158218893Sdim 159218893Sdim return (0); 160218893Sdim} 161218893Sdim 162218893Sdimstatic int 163218893Sdimmfi_disk_detach(device_t dev) 164218893Sdim{ 165218893Sdim struct mfi_disk *sc; 166218893Sdim 167218893Sdim sc = device_get_softc(dev); 168202375Srdivacky 169249423Sdim mtx_lock(&sc->ld_controller->mfi_io_lock); 170202375Srdivacky if (((sc->ld_disk->d_flags & DISKFLAG_OPEN) || 171202375Srdivacky (sc->ld_flags & MFI_DISK_FLAGS_OPEN)) && 172202375Srdivacky (sc->ld_controller->mfi_keep_deleted_volumes || 173202375Srdivacky sc->ld_controller->mfi_detaching)) { 174202375Srdivacky mtx_unlock(&sc->ld_controller->mfi_io_lock); 175202375Srdivacky return (EBUSY); 176263508Sdim } 177202375Srdivacky mtx_unlock(&sc->ld_controller->mfi_io_lock); 178202375Srdivacky 179202375Srdivacky disk_destroy(sc->ld_disk); 180202375Srdivacky mtx_lock(&sc->ld_controller->mfi_io_lock); 181202375Srdivacky TAILQ_REMOVE(&sc->ld_controller->mfi_ld_tqh, sc, ld_link); 182202375Srdivacky mtx_unlock(&sc->ld_controller->mfi_io_lock); 183263508Sdim free(sc->ld_info, M_MFIBUF); 184202375Srdivacky return (0); 185202375Srdivacky} 186202375Srdivacky 187202375Srdivackystatic int 188202375Srdivackymfi_disk_open(struct disk *dp) 189202375Srdivacky{ 190202375Srdivacky struct mfi_disk *sc; 191202375Srdivacky int error; 192202375Srdivacky 193202375Srdivacky sc = dp->d_drv1; 194202375Srdivacky mtx_lock(&sc->ld_controller->mfi_io_lock); 195202375Srdivacky if (sc->ld_flags & MFI_DISK_FLAGS_DISABLED) 196202375Srdivacky error = ENXIO; 197202375Srdivacky else { 198202375Srdivacky sc->ld_flags |= MFI_DISK_FLAGS_OPEN; 199202375Srdivacky error = 0; 200202375Srdivacky } 201202375Srdivacky mtx_unlock(&sc->ld_controller->mfi_io_lock); 202202375Srdivacky 203202375Srdivacky return (error); 204202375Srdivacky} 205202375Srdivacky 206202375Srdivackystatic int 207202375Srdivackymfi_disk_close(struct disk *dp) 208202375Srdivacky{ 209202375Srdivacky struct mfi_disk *sc; 210202375Srdivacky 211202375Srdivacky sc = dp->d_drv1; 212263508Sdim mtx_lock(&sc->ld_controller->mfi_io_lock); 213202375Srdivacky sc->ld_flags &= ~MFI_DISK_FLAGS_OPEN; 214218893Sdim mtx_unlock(&sc->ld_controller->mfi_io_lock); 215218893Sdim 216202375Srdivacky return (0); 217249423Sdim} 218218893Sdim 219202375Srdivackyint 220202375Srdivackymfi_disk_disable(struct mfi_disk *sc) 221202375Srdivacky{ 222202375Srdivacky 223202375Srdivacky mtx_assert(&sc->ld_controller->mfi_io_lock, MA_OWNED); 224202375Srdivacky if (sc->ld_flags & MFI_DISK_FLAGS_OPEN) { 225202375Srdivacky if (sc->ld_controller->mfi_delete_busy_volumes) 226202375Srdivacky return (0); 227202375Srdivacky device_printf(sc->ld_dev, "Unable to delete busy ld device\n"); 228202375Srdivacky return (EBUSY); 229202375Srdivacky } 230202375Srdivacky sc->ld_flags |= MFI_DISK_FLAGS_DISABLED; 231202375Srdivacky return (0); 232263508Sdim} 233202375Srdivacky 234218893Sdimvoid 235218893Sdimmfi_disk_enable(struct mfi_disk *sc) 236202375Srdivacky{ 237249423Sdim 238218893Sdim mtx_assert(&sc->ld_controller->mfi_io_lock, MA_OWNED); 239202375Srdivacky sc->ld_flags &= ~MFI_DISK_FLAGS_DISABLED; 240202375Srdivacky} 241202375Srdivacky 242202375Srdivackystatic void 243202375Srdivackymfi_disk_strategy(struct bio *bio) 244202375Srdivacky{ 245202375Srdivacky struct mfi_disk *sc; 246202375Srdivacky struct mfi_softc *controller; 247202375Srdivacky 248202375Srdivacky sc = bio->bio_disk->d_drv1; 249202375Srdivacky controller = sc->ld_controller; 250202375Srdivacky 251202375Srdivacky if (sc == NULL) { 252263508Sdim bio->bio_error = EINVAL; 253202375Srdivacky bio->bio_flags |= BIO_ERROR; 254202375Srdivacky bio->bio_resid = bio->bio_bcount; 255202375Srdivacky biodone(bio); 256202375Srdivacky return; 257202375Srdivacky } 258202375Srdivacky 259202375Srdivacky if (controller->adpreset){ 260202375Srdivacky bio->bio_error = EBUSY; 261202375Srdivacky return; 262202375Srdivacky } 263202375Srdivacky 264202375Srdivacky if (controller->hw_crit_error){ 265202375Srdivacky bio->bio_error = EBUSY; 266251662Sdim return; 267251662Sdim } 268249423Sdim 269202375Srdivacky if (controller->issuepend_done == 0){ 270202375Srdivacky bio->bio_error = EBUSY; 271204792Srdivacky return; 272204792Srdivacky } 273249423Sdim 274202375Srdivacky bio->bio_driver1 = (void *)(uintptr_t)sc->ld_id; 275202375Srdivacky /* Mark it as LD IO */ 276249423Sdim bio->bio_driver2 = (void *)MFI_LD_IO; 277202375Srdivacky mtx_lock(&controller->mfi_io_lock); 278202375Srdivacky mfi_enqueue_bio(controller, bio); 279263508Sdim mfi_startio(controller); 280202375Srdivacky mtx_unlock(&controller->mfi_io_lock); 281202375Srdivacky return; 282202375Srdivacky} 283249423Sdim 284202375Srdivackyvoid 285204792Srdivackymfi_disk_complete(struct bio *bio) 286202375Srdivacky{ 287202375Srdivacky struct mfi_disk *sc; 288202375Srdivacky struct mfi_frame_header *hdr; 289202375Srdivacky 290202375Srdivacky sc = bio->bio_disk->d_drv1; 291202375Srdivacky hdr = bio->bio_driver1; 292204792Srdivacky 293202375Srdivacky if (bio->bio_flags & BIO_ERROR) { 294202375Srdivacky if (bio->bio_error == 0) 295202375Srdivacky bio->bio_error = EIO; 296263508Sdim disk_err(bio, "hard error", -1, 1); 297202375Srdivacky } else { 298202375Srdivacky bio->bio_resid = 0; 299202375Srdivacky } 300202375Srdivacky biodone(bio); 301249423Sdim} 302202375Srdivacky 303204792Srdivackystatic int 304202375Srdivackymfi_disk_dump(void *arg, void *virt, vm_offset_t phys, off_t offset, size_t len) 305202375Srdivacky{ 306202375Srdivacky struct mfi_disk *sc; 307202375Srdivacky struct mfi_softc *parent_sc; 308202375Srdivacky struct disk *dp; 309202375Srdivacky int error; 310202375Srdivacky 311204792Srdivacky dp = arg; 312202375Srdivacky sc = dp->d_drv1; 313202375Srdivacky parent_sc = sc->ld_controller; 314202375Srdivacky 315202375Srdivacky if (len > 0) { 316202375Srdivacky if ((error = mfi_dump_blocks(parent_sc, sc->ld_id, offset / 317202375Srdivacky MFI_SECTOR_LEN, virt, len)) != 0) 318202375Srdivacky return (error); 319202375Srdivacky } else { 320202375Srdivacky /* mfi_sync_cache(parent_sc, sc->ld_id); */ 321202375Srdivacky } 322202375Srdivacky 323202375Srdivacky return (0); 324202375Srdivacky} 325202375Srdivacky