mfi_disk.c revision 229611
154359Sroberto/*- 254359Sroberto * Copyright (c) 2006 IronPort Systems 354359Sroberto * All rights reserved. 454359Sroberto * 554359Sroberto * Redistribution and use in source and binary forms, with or without 654359Sroberto * modification, are permitted provided that the following conditions 754359Sroberto * are met: 854359Sroberto * 1. Redistributions of source code must retain the above copyright 954359Sroberto * notice, this list of conditions and the following disclaimer. 1054359Sroberto * 2. Redistributions in binary form must reproduce the above copyright 1154359Sroberto * notice, this list of conditions and the following disclaimer in the 1254359Sroberto * documentation and/or other materials provided with the distribution. 1354359Sroberto * 1454359Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1554359Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1654359Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1754359Sroberto * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1854359Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1954359Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2054359Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2154359Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2254359Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2356746Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2456746Sroberto * SUCH DAMAGE. 2556746Sroberto */ 2654359Sroberto 2754359Sroberto#include <sys/cdefs.h> 2854359Sroberto__FBSDID("$FreeBSD: stable/9/sys/dev/mfi/mfi_disk.c 229611 2012-01-05 18:30:48Z jhb $"); 2954359Sroberto 3054359Sroberto#include "opt_mfi.h" 3154359Sroberto 3254359Sroberto#include <sys/param.h> 3354359Sroberto#include <sys/systm.h> 3454359Sroberto#include <sys/kernel.h> 3554359Sroberto#include <sys/selinfo.h> 3654359Sroberto#include <sys/module.h> 3754359Sroberto#include <sys/malloc.h> 3854359Sroberto#include <sys/sysctl.h> 3954359Sroberto#include <sys/uio.h> 4054359Sroberto 4154359Sroberto#include <sys/bio.h> 4254359Sroberto#include <sys/bus.h> 4354359Sroberto#include <sys/conf.h> 4454359Sroberto#include <sys/disk.h> 4554359Sroberto#include <geom/geom_disk.h> 4654359Sroberto 4756746Sroberto#include <vm/vm.h> 4856746Sroberto#include <vm/pmap.h> 4954359Sroberto 5056746Sroberto#include <machine/md_var.h> 5156746Sroberto#include <machine/bus.h> 5254359Sroberto#include <sys/rman.h> 5356746Sroberto 5456746Sroberto#include <dev/mfi/mfireg.h> 5554359Sroberto#include <dev/mfi/mfi_ioctl.h> 5656746Sroberto#include <dev/mfi/mfivar.h> 5756746Sroberto 5854359Srobertostatic int mfi_disk_probe(device_t dev); 5956746Srobertostatic int mfi_disk_attach(device_t dev); 6056746Srobertostatic int mfi_disk_detach(device_t dev); 6154359Sroberto 6256746Srobertostatic disk_open_t mfi_disk_open; 6356746Srobertostatic disk_close_t mfi_disk_close; 6454359Srobertostatic disk_strategy_t mfi_disk_strategy; 6554359Srobertostatic dumper_t mfi_disk_dump; 6654359Sroberto 6754359Srobertostatic devclass_t mfi_disk_devclass; 6854359Sroberto 6954359Srobertostatic device_method_t mfi_disk_methods[] = { 7054359Sroberto DEVMETHOD(device_probe, mfi_disk_probe), 7156746Sroberto DEVMETHOD(device_attach, mfi_disk_attach), 7256746Sroberto DEVMETHOD(device_detach, mfi_disk_detach), 7356746Sroberto { 0, 0 } 7482498Sroberto}; 7582498Sroberto 7682498Srobertostatic driver_t mfi_disk_driver = { 7782498Sroberto "mfid", 7882498Sroberto mfi_disk_methods, 7982498Sroberto sizeof(struct mfi_disk) 8054359Sroberto}; 8154359Sroberto 8254359SrobertoDRIVER_MODULE(mfid, mfi, mfi_disk_driver, mfi_disk_devclass, 0, 0); 8354359Sroberto 8454359Srobertostatic int 8554359Srobertomfi_disk_probe(device_t dev) 8654359Sroberto{ 8754359Sroberto 8854359Sroberto return (0); 8954359Sroberto} 9054359Sroberto 9154359Srobertostatic int 9254359Srobertomfi_disk_attach(device_t dev) 9354359Sroberto{ 9454359Sroberto struct mfi_disk *sc; 9556746Sroberto struct mfi_ld_info *ld_info; 9656746Sroberto uint64_t sectors; 9756746Sroberto uint32_t secsize; 9854359Sroberto char *state; 9954359Sroberto 10054359Sroberto sc = device_get_softc(dev); 10154359Sroberto ld_info = device_get_ivars(dev); 10254359Sroberto 10354359Sroberto sc->ld_dev = dev; 10454359Sroberto sc->ld_id = ld_info->ld_config.properties.ld.v.target_id; 10554359Sroberto sc->ld_unit = device_get_unit(dev); 10654359Sroberto sc->ld_info = ld_info; 10756746Sroberto sc->ld_controller = device_get_softc(device_get_parent(dev)); 10856746Sroberto sc->ld_flags = 0; 10956746Sroberto 11054359Sroberto sectors = ld_info->size; 11154359Sroberto secsize = MFI_SECTOR_LEN; 11254359Sroberto mtx_lock(&sc->ld_controller->mfi_io_lock); 11354359Sroberto TAILQ_INSERT_TAIL(&sc->ld_controller->mfi_ld_tqh, sc, ld_link); 11454359Sroberto mtx_unlock(&sc->ld_controller->mfi_io_lock); 11554359Sroberto 11656746Sroberto switch (ld_info->ld_config.params.state) { 11756746Sroberto case MFI_LD_STATE_OFFLINE: 11854359Sroberto state = "offline"; 11954359Sroberto break; 12054359Sroberto case MFI_LD_STATE_PARTIALLY_DEGRADED: 12154359Sroberto state = "partially degraded"; 12254359Sroberto break; 12354359Sroberto case MFI_LD_STATE_DEGRADED: 12454359Sroberto state = "degraded"; 12554359Sroberto break; 12654359Sroberto case MFI_LD_STATE_OPTIMAL: 12754359Sroberto state = "optimal"; 12856746Sroberto break; 12956746Sroberto default: 13056746Sroberto state = "unknown"; 13156746Sroberto break; 13256746Sroberto } 13356746Sroberto device_printf(dev, "%juMB (%ju sectors) RAID volume '%s' is %s\n", 13456746Sroberto sectors / (1024 * 1024 / secsize), sectors, 13556746Sroberto ld_info->ld_config.properties.name, 13656746Sroberto state); 13754359Sroberto 13854359Sroberto sc->ld_disk = disk_alloc(); 13954359Sroberto sc->ld_disk->d_drv1 = sc; 14056746Sroberto sc->ld_disk->d_maxsize = min(sc->ld_controller->mfi_max_io * secsize, 14156746Sroberto (sc->ld_controller->mfi_max_sge - 1) * PAGE_SIZE); 14254359Sroberto sc->ld_disk->d_name = "mfid"; 14354359Sroberto sc->ld_disk->d_open = mfi_disk_open; 14454359Sroberto sc->ld_disk->d_close = mfi_disk_close; 14554359Sroberto sc->ld_disk->d_strategy = mfi_disk_strategy; 14654359Sroberto sc->ld_disk->d_dump = mfi_disk_dump; 14754359Sroberto sc->ld_disk->d_unit = sc->ld_unit; 14854359Sroberto sc->ld_disk->d_sectorsize = secsize; 14956746Sroberto sc->ld_disk->d_mediasize = sectors * secsize; 15056746Sroberto if (sc->ld_disk->d_mediasize >= (1 * 1024 * 1024)) { 15156746Sroberto sc->ld_disk->d_fwheads = 255; 15256746Sroberto sc->ld_disk->d_fwsectors = 63; 15356746Sroberto } else { 15456746Sroberto sc->ld_disk->d_fwheads = 64; 15554359Sroberto sc->ld_disk->d_fwsectors = 32; 15654359Sroberto } 15754359Sroberto disk_create(sc->ld_disk, DISK_VERSION); 15856746Sroberto 15956746Sroberto return (0); 16056746Sroberto} 16154359Sroberto 16254359Srobertostatic int 16354359Srobertomfi_disk_detach(device_t dev) 16456746Sroberto{ 16556746Sroberto struct mfi_disk *sc; 16654359Sroberto 16756746Sroberto sc = device_get_softc(dev); 16856746Sroberto 16954359Sroberto mtx_lock(&sc->ld_controller->mfi_io_lock); 17056746Sroberto if (((sc->ld_disk->d_flags & DISKFLAG_OPEN) || 17156746Sroberto (sc->ld_flags & MFI_DISK_FLAGS_OPEN)) && 17254359Sroberto (sc->ld_controller->mfi_keep_deleted_volumes || 17354359Sroberto sc->ld_controller->mfi_detaching)) { 17454359Sroberto mtx_unlock(&sc->ld_controller->mfi_io_lock); 17554359Sroberto return (EBUSY); 17654359Sroberto } 17754359Sroberto mtx_unlock(&sc->ld_controller->mfi_io_lock); 17854359Sroberto 17954359Sroberto disk_destroy(sc->ld_disk); 18054359Sroberto mtx_lock(&sc->ld_controller->mfi_io_lock); 18154359Sroberto TAILQ_REMOVE(&sc->ld_controller->mfi_ld_tqh, sc, ld_link); 18254359Sroberto mtx_unlock(&sc->ld_controller->mfi_io_lock); 18354359Sroberto free(sc->ld_info, M_MFIBUF); 18454359Sroberto return (0); 18554359Sroberto} 18654359Sroberto 18754359Srobertostatic int 18854359Srobertomfi_disk_open(struct disk *dp) 18954359Sroberto{ 19054359Sroberto struct mfi_disk *sc; 19154359Sroberto int error; 19254359Sroberto 19354359Sroberto sc = dp->d_drv1; 19454359Sroberto mtx_lock(&sc->ld_controller->mfi_io_lock); 19554359Sroberto if (sc->ld_flags & MFI_DISK_FLAGS_DISABLED) 19654359Sroberto error = ENXIO; 19754359Sroberto else { 19854359Sroberto sc->ld_flags |= MFI_DISK_FLAGS_OPEN; 19954359Sroberto error = 0; 20054359Sroberto } 20154359Sroberto mtx_unlock(&sc->ld_controller->mfi_io_lock); 20254359Sroberto 20354359Sroberto return (error); 20454359Sroberto} 20554359Sroberto 20654359Srobertostatic int 20754359Srobertomfi_disk_close(struct disk *dp) 20854359Sroberto{ 20954359Sroberto struct mfi_disk *sc; 21054359Sroberto 21154359Sroberto sc = dp->d_drv1; 21254359Sroberto mtx_lock(&sc->ld_controller->mfi_io_lock); 21354359Sroberto sc->ld_flags &= ~MFI_DISK_FLAGS_OPEN; 21454359Sroberto mtx_unlock(&sc->ld_controller->mfi_io_lock); 21554359Sroberto 21654359Sroberto return (0); 21754359Sroberto} 21854359Sroberto 21954359Srobertoint 22054359Srobertomfi_disk_disable(struct mfi_disk *sc) 22154359Sroberto{ 22254359Sroberto 22354359Sroberto mtx_assert(&sc->ld_controller->mfi_io_lock, MA_OWNED); 22454359Sroberto if (sc->ld_flags & MFI_DISK_FLAGS_OPEN) { 22554359Sroberto if (sc->ld_controller->mfi_delete_busy_volumes) 22654359Sroberto return (0); 22754359Sroberto device_printf(sc->ld_dev, "Unable to delete busy device\n"); 22854359Sroberto return (EBUSY); 22954359Sroberto } 23054359Sroberto sc->ld_flags |= MFI_DISK_FLAGS_DISABLED; 23154359Sroberto return (0); 23254359Sroberto} 23354359Sroberto 23454359Srobertovoid 23554359Srobertomfi_disk_enable(struct mfi_disk *sc) 23654359Sroberto{ 23754359Sroberto 23854359Sroberto mtx_assert(&sc->ld_controller->mfi_io_lock, MA_OWNED); 23954359Sroberto sc->ld_flags &= ~MFI_DISK_FLAGS_DISABLED; 24054359Sroberto} 24154359Sroberto 24254359Srobertostatic void 24354359Srobertomfi_disk_strategy(struct bio *bio) 24454359Sroberto{ 24554359Sroberto struct mfi_disk *sc; 24654359Sroberto struct mfi_softc *controller; 24754359Sroberto 24854359Sroberto sc = bio->bio_disk->d_drv1; 24954359Sroberto 25054359Sroberto if (sc == NULL) { 25154359Sroberto bio->bio_error = EINVAL; 25254359Sroberto bio->bio_flags |= BIO_ERROR; 25354359Sroberto bio->bio_resid = bio->bio_bcount; 25454359Sroberto biodone(bio); 25554359Sroberto return; 25654359Sroberto } 25754359Sroberto 25854359Sroberto controller = sc->ld_controller; 25954359Sroberto bio->bio_driver1 = (void *)(uintptr_t)sc->ld_id; 26054359Sroberto mtx_lock(&controller->mfi_io_lock); 26154359Sroberto mfi_enqueue_bio(controller, bio); 26254359Sroberto mfi_startio(controller); 26354359Sroberto mtx_unlock(&controller->mfi_io_lock); 26454359Sroberto return; 26554359Sroberto} 26654359Sroberto 26754359Srobertovoid 26854359Srobertomfi_disk_complete(struct bio *bio) 26954359Sroberto{ 27054359Sroberto struct mfi_disk *sc; 27154359Sroberto struct mfi_frame_header *hdr; 27282498Sroberto 27382498Sroberto sc = bio->bio_disk->d_drv1; 27482498Sroberto hdr = bio->bio_driver1; 27554359Sroberto 27654359Sroberto if (bio->bio_flags & BIO_ERROR) { 27754359Sroberto if (bio->bio_error == 0) 27854359Sroberto bio->bio_error = EIO; 27954359Sroberto disk_err(bio, "hard error", -1, 1); 28054359Sroberto } else { 28154359Sroberto bio->bio_resid = 0; 28254359Sroberto } 28354359Sroberto biodone(bio); 28454359Sroberto} 28554359Sroberto 28654359Srobertostatic int 28754359Srobertomfi_disk_dump(void *arg, void *virt, vm_offset_t phys, off_t offset, size_t len) 28854359Sroberto{ 28954359Sroberto struct mfi_disk *sc; 29054359Sroberto struct mfi_softc *parent_sc; 29154359Sroberto struct disk *dp; 29254359Sroberto int error; 29354359Sroberto 29454359Sroberto dp = arg; 29554359Sroberto sc = dp->d_drv1; 29654359Sroberto parent_sc = sc->ld_controller; 29754359Sroberto 29854359Sroberto if (len > 0) { 29954359Sroberto if ((error = mfi_dump_blocks(parent_sc, sc->ld_id, offset / 30054359Sroberto MFI_SECTOR_LEN, virt, len)) != 0) 30154359Sroberto return (error); 30282498Sroberto } else { 30382498Sroberto /* mfi_sync_cache(parent_sc, sc->ld_id); */ 30482498Sroberto } 30554359Sroberto 30654359Sroberto return (0); 30754359Sroberto} 30854359Sroberto