mfi_disk.c revision 243824
1251876Speter/*- 2251876Speter * Copyright (c) 2006 IronPort Systems 3251876Speter * All rights reserved. 4251876Speter * 5251876Speter * Redistribution and use in source and binary forms, with or without 6251876Speter * modification, are permitted provided that the following conditions 7251876Speter * are met: 8251876Speter * 1. Redistributions of source code must retain the above copyright 9251876Speter * notice, this list of conditions and the following disclaimer. 10253734Speter * 2. Redistributions in binary form must reproduce the above copyright 11251876Speter * notice, this list of conditions and the following disclaimer in the 12251876Speter * documentation and/or other materials provided with the distribution. 13251876Speter * 14251876Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15251876Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16251876Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17251876Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18251876Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19251876Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20251876Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21251876Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22251876Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23251876Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24251876Speter * SUCH DAMAGE. 25251876Speter */ 26251876Speter 27251876Speter#include <sys/cdefs.h> 28251876Speter__FBSDID("$FreeBSD: stable/9/sys/dev/mfi/mfi_disk.c 243824 2012-12-03 18:37:02Z delphij $"); 29251876Speter 30251876Speter#include "opt_mfi.h" 31251876Speter 32251876Speter#include <sys/param.h> 33251876Speter#include <sys/systm.h> 34251876Speter#include <sys/kernel.h> 35251876Speter#include <sys/selinfo.h> 36251876Speter#include <sys/module.h> 37251876Speter#include <sys/malloc.h> 38251876Speter#include <sys/sysctl.h> 39251876Speter#include <sys/uio.h> 40251876Speter 41251876Speter#include <sys/bio.h> 42251876Speter#include <sys/bus.h> 43251876Speter#include <sys/conf.h> 44251876Speter#include <sys/disk.h> 45251876Speter#include <geom/geom_disk.h> 46251876Speter 47251876Speter#include <vm/vm.h> 48251876Speter#include <vm/pmap.h> 49251876Speter 50251876Speter#include <machine/md_var.h> 51251876Speter#include <machine/bus.h> 52251876Speter#include <sys/rman.h> 53251876Speter 54251876Speter#include <dev/mfi/mfireg.h> 55251876Speter#include <dev/mfi/mfi_ioctl.h> 56251876Speter#include <dev/mfi/mfivar.h> 57251876Speter 58251876Speterstatic int mfi_disk_probe(device_t dev); 59251876Speterstatic int mfi_disk_attach(device_t dev); 60251876Speterstatic int mfi_disk_detach(device_t dev); 61251876Speter 62251876Speterstatic disk_open_t mfi_disk_open; 63251876Speterstatic disk_close_t mfi_disk_close; 64251876Speterstatic disk_strategy_t mfi_disk_strategy; 65251876Speterstatic dumper_t mfi_disk_dump; 66251876Speter 67251876Speterstatic devclass_t mfi_disk_devclass; 68251876Speter 69251876Speterstatic device_method_t mfi_disk_methods[] = { 70251876Speter DEVMETHOD(device_probe, mfi_disk_probe), 71251876Speter DEVMETHOD(device_attach, mfi_disk_attach), 72251876Speter DEVMETHOD(device_detach, mfi_disk_detach), 73251876Speter { 0, 0 } 74251876Speter}; 75251876Speter 76251876Speterstatic driver_t mfi_disk_driver = { 77251876Speter "mfid", 78251876Speter mfi_disk_methods, 79251876Speter sizeof(struct mfi_disk) 80251876Speter}; 81251876Speter 82251876SpeterDRIVER_MODULE(mfid, mfi, mfi_disk_driver, mfi_disk_devclass, 0, 0); 83251876Speter 84251876Speterstatic int 85251876Spetermfi_disk_probe(device_t dev) 86251876Speter{ 87251876Speter 88251876Speter return (0); 89251876Speter} 90251876Speter 91251876Speterstatic int 92251876Spetermfi_disk_attach(device_t dev) 93251876Speter{ 94251876Speter struct mfi_disk *sc; 95251876Speter struct mfi_ld_info *ld_info; 96251876Speter struct mfi_disk_pending *ld_pend; 97251876Speter uint64_t sectors; 98251876Speter uint32_t secsize; 99251876Speter char *state; 100251876Speter 101251876Speter sc = device_get_softc(dev); 102251876Speter ld_info = device_get_ivars(dev); 103251876Speter 104251876Speter sc->ld_dev = dev; 105251876Speter sc->ld_id = ld_info->ld_config.properties.ld.v.target_id; 106251876Speter sc->ld_unit = device_get_unit(dev); 107251876Speter sc->ld_info = ld_info; 108251876Speter sc->ld_controller = device_get_softc(device_get_parent(dev)); 109251876Speter sc->ld_flags = 0; 110251876Speter 111251876Speter sectors = ld_info->size; 112251876Speter secsize = MFI_SECTOR_LEN; 113251876Speter mtx_lock(&sc->ld_controller->mfi_io_lock); 114251876Speter TAILQ_INSERT_TAIL(&sc->ld_controller->mfi_ld_tqh, sc, ld_link); 115251876Speter TAILQ_FOREACH(ld_pend, &sc->ld_controller->mfi_ld_pend_tqh, 116251876Speter ld_link) { 117251876Speter TAILQ_REMOVE(&sc->ld_controller->mfi_ld_pend_tqh, 118251876Speter ld_pend, ld_link); 119251876Speter free(ld_pend, M_MFIBUF); 120251876Speter break; 121251876Speter } 122251876Speter mtx_unlock(&sc->ld_controller->mfi_io_lock); 123251876Speter 124251876Speter switch (ld_info->ld_config.params.state) { 125251876Speter case MFI_LD_STATE_OFFLINE: 126251876Speter state = "offline"; 127251876Speter break; 128251876Speter case MFI_LD_STATE_PARTIALLY_DEGRADED: 129251876Speter state = "partially degraded"; 130251876Speter break; 131251876Speter case MFI_LD_STATE_DEGRADED: 132251876Speter state = "degraded"; 133251876Speter break; 134251876Speter case MFI_LD_STATE_OPTIMAL: 135251876Speter state = "optimal"; 136251876Speter break; 137251876Speter default: 138251876Speter state = "unknown"; 139251876Speter break; 140251876Speter } 141251876Speter 142251876Speter if ( strlen(ld_info->ld_config.properties.name) == 0 ) { 143251876Speter device_printf(dev, 144251876Speter "%juMB (%ju sectors) RAID volume (no label) is %s\n", 145251876Speter sectors / (1024 * 1024 / secsize), sectors, state); 146251876Speter } else { 147251876Speter device_printf(dev, 148251876Speter "%juMB (%ju sectors) RAID volume '%s' is %s\n", 149251876Speter sectors / (1024 * 1024 / secsize), sectors, 150251876Speter ld_info->ld_config.properties.name, state); 151251876Speter } 152251876Speter 153251876Speter sc->ld_disk = disk_alloc(); 154251876Speter sc->ld_disk->d_drv1 = sc; 155251876Speter sc->ld_disk->d_maxsize = min(sc->ld_controller->mfi_max_io * secsize, 156251876Speter (sc->ld_controller->mfi_max_sge - 1) * PAGE_SIZE); 157251876Speter sc->ld_disk->d_name = "mfid"; 158251876Speter sc->ld_disk->d_open = mfi_disk_open; 159251876Speter sc->ld_disk->d_close = mfi_disk_close; 160251876Speter sc->ld_disk->d_strategy = mfi_disk_strategy; 161251876Speter sc->ld_disk->d_dump = mfi_disk_dump; 162251876Speter sc->ld_disk->d_unit = sc->ld_unit; 163251876Speter sc->ld_disk->d_sectorsize = secsize; 164251876Speter sc->ld_disk->d_mediasize = sectors * secsize; 165251876Speter if (sc->ld_disk->d_mediasize >= (1 * 1024 * 1024)) { 166251876Speter sc->ld_disk->d_fwheads = 255; 167251876Speter sc->ld_disk->d_fwsectors = 63; 168251876Speter } else { 169251876Speter sc->ld_disk->d_fwheads = 64; 170251876Speter sc->ld_disk->d_fwsectors = 32; 171251876Speter } 172251876Speter disk_create(sc->ld_disk, DISK_VERSION); 173251876Speter 174251876Speter return (0); 175251876Speter} 176251876Speter 177251876Speterstatic int 178251876Spetermfi_disk_detach(device_t dev) 179251876Speter{ 180251876Speter struct mfi_disk *sc; 181251876Speter 182251876Speter sc = device_get_softc(dev); 183251876Speter 184251876Speter mtx_lock(&sc->ld_controller->mfi_io_lock); 185251876Speter if (((sc->ld_disk->d_flags & DISKFLAG_OPEN) || 186251876Speter (sc->ld_flags & MFI_DISK_FLAGS_OPEN)) && 187251876Speter (sc->ld_controller->mfi_keep_deleted_volumes || 188251876Speter sc->ld_controller->mfi_detaching)) { 189251876Speter mtx_unlock(&sc->ld_controller->mfi_io_lock); 190251876Speter return (EBUSY); 191251876Speter } 192251876Speter mtx_unlock(&sc->ld_controller->mfi_io_lock); 193251876Speter 194251876Speter disk_destroy(sc->ld_disk); 195251876Speter mtx_lock(&sc->ld_controller->mfi_io_lock); 196251876Speter TAILQ_REMOVE(&sc->ld_controller->mfi_ld_tqh, sc, ld_link); 197251876Speter mtx_unlock(&sc->ld_controller->mfi_io_lock); 198251876Speter free(sc->ld_info, M_MFIBUF); 199251876Speter return (0); 200251876Speter} 201251876Speter 202251876Speterstatic int 203251876Spetermfi_disk_open(struct disk *dp) 204251876Speter{ 205251876Speter struct mfi_disk *sc; 206251876Speter int error; 207251876Speter 208251876Speter sc = dp->d_drv1; 209251876Speter mtx_lock(&sc->ld_controller->mfi_io_lock); 210251876Speter if (sc->ld_flags & MFI_DISK_FLAGS_DISABLED) 211251876Speter error = ENXIO; 212251876Speter else { 213251876Speter sc->ld_flags |= MFI_DISK_FLAGS_OPEN; 214251876Speter error = 0; 215251876Speter } 216251876Speter mtx_unlock(&sc->ld_controller->mfi_io_lock); 217251876Speter 218251876Speter return (error); 219251876Speter} 220251876Speter 221251876Speterstatic int 222251876Spetermfi_disk_close(struct disk *dp) 223251876Speter{ 224251876Speter struct mfi_disk *sc; 225251876Speter 226251876Speter sc = dp->d_drv1; 227251876Speter mtx_lock(&sc->ld_controller->mfi_io_lock); 228251876Speter sc->ld_flags &= ~MFI_DISK_FLAGS_OPEN; 229251876Speter mtx_unlock(&sc->ld_controller->mfi_io_lock); 230251876Speter 231251876Speter return (0); 232251876Speter} 233251876Speter 234251876Speterint 235251876Spetermfi_disk_disable(struct mfi_disk *sc) 236251876Speter{ 237251876Speter 238251876Speter mtx_assert(&sc->ld_controller->mfi_io_lock, MA_OWNED); 239251876Speter if (sc->ld_flags & MFI_DISK_FLAGS_OPEN) { 240251876Speter if (sc->ld_controller->mfi_delete_busy_volumes) 241251876Speter return (0); 242251876Speter device_printf(sc->ld_dev, "Unable to delete busy ld device\n"); 243251876Speter return (EBUSY); 244251876Speter } 245251876Speter sc->ld_flags |= MFI_DISK_FLAGS_DISABLED; 246251876Speter return (0); 247251876Speter} 248251876Speter 249251876Spetervoid 250251876Spetermfi_disk_enable(struct mfi_disk *sc) 251251876Speter{ 252251876Speter 253251876Speter mtx_assert(&sc->ld_controller->mfi_io_lock, MA_OWNED); 254251876Speter sc->ld_flags &= ~MFI_DISK_FLAGS_DISABLED; 255251876Speter} 256251876Speter 257251876Speterstatic void 258251876Spetermfi_disk_strategy(struct bio *bio) 259251876Speter{ 260251876Speter struct mfi_disk *sc; 261251876Speter struct mfi_softc *controller; 262251876Speter 263251876Speter sc = bio->bio_disk->d_drv1; 264251876Speter controller = sc->ld_controller; 265251876Speter 266251876Speter if (sc == NULL) { 267251876Speter bio->bio_error = EINVAL; 268251876Speter bio->bio_flags |= BIO_ERROR; 269251876Speter bio->bio_resid = bio->bio_bcount; 270251876Speter biodone(bio); 271251876Speter return; 272251876Speter } 273251876Speter 274251876Speter if (controller->adpreset) { 275251876Speter bio->bio_error = EBUSY; 276251876Speter return; 277251876Speter } 278251876Speter 279251876Speter if (controller->hw_crit_error) { 280251876Speter bio->bio_error = EBUSY; 281251876Speter return; 282251876Speter } 283251876Speter 284251876Speter if (controller->issuepend_done == 0) { 285251876Speter bio->bio_error = EBUSY; 286251876Speter return; 287251876Speter } 288251876Speter 289251876Speter bio->bio_driver1 = (void *)(uintptr_t)sc->ld_id; 290251876Speter /* Mark it as LD IO */ 291251876Speter bio->bio_driver2 = (void *)MFI_LD_IO; 292251876Speter mtx_lock(&controller->mfi_io_lock); 293251876Speter mfi_enqueue_bio(controller, bio); 294251876Speter mfi_startio(controller); 295251876Speter mtx_unlock(&controller->mfi_io_lock); 296251876Speter return; 297251876Speter} 298251876Speter 299251876Spetervoid 300251876Spetermfi_disk_complete(struct bio *bio) 301251876Speter{ 302251876Speter struct mfi_disk *sc; 303251876Speter struct mfi_frame_header *hdr; 304251876Speter 305251876Speter sc = bio->bio_disk->d_drv1; 306251876Speter hdr = bio->bio_driver1; 307251876Speter 308251876Speter if (bio->bio_flags & BIO_ERROR) { 309251876Speter bio->bio_resid = bio->bio_bcount; 310251876Speter if (bio->bio_error == 0) 311251876Speter bio->bio_error = EIO; 312251876Speter disk_err(bio, "hard error", -1, 1); 313251876Speter } else { 314251876Speter bio->bio_resid = 0; 315251876Speter } 316251876Speter biodone(bio); 317251876Speter} 318251876Speter 319251876Speterstatic int 320251876Spetermfi_disk_dump(void *arg, void *virt, vm_offset_t phys, off_t offset, size_t len) 321251876Speter{ 322251876Speter struct mfi_disk *sc; 323251876Speter struct mfi_softc *parent_sc; 324251876Speter struct disk *dp; 325251876Speter int error; 326251876Speter 327251876Speter dp = arg; 328251876Speter sc = dp->d_drv1; 329251876Speter parent_sc = sc->ld_controller; 330251876Speter 331251876Speter if (len > 0) { 332251876Speter if ((error = mfi_dump_blocks(parent_sc, sc->ld_id, offset / 333251876Speter MFI_SECTOR_LEN, virt, len)) != 0) 334251876Speter return (error); 335251876Speter } else { 336251876Speter /* mfi_sync_cache(parent_sc, sc->ld_id); */ 337251876Speter } 338251876Speter 339251876Speter return (0); 340251876Speter} 341251876Speter