1157114Sscottl/*- 2157114Sscottl * Copyright (c) 2006 IronPort Systems 3157114Sscottl * All rights reserved. 4157114Sscottl * 5157114Sscottl * Redistribution and use in source and binary forms, with or without 6157114Sscottl * modification, are permitted provided that the following conditions 7157114Sscottl * are met: 8157114Sscottl * 1. Redistributions of source code must retain the above copyright 9157114Sscottl * notice, this list of conditions and the following disclaimer. 10157114Sscottl * 2. Redistributions in binary form must reproduce the above copyright 11157114Sscottl * notice, this list of conditions and the following disclaimer in the 12157114Sscottl * documentation and/or other materials provided with the distribution. 13157114Sscottl * 14157114Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15157114Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16157114Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17157114Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18157114Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19157114Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20157114Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21157114Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22157114Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23157114Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24157114Sscottl * SUCH DAMAGE. 25157114Sscottl */ 26157114Sscottl 27157114Sscottl#include <sys/cdefs.h> 28157114Sscottl__FBSDID("$FreeBSD$"); 29157114Sscottl 30157114Sscottl#include "opt_mfi.h" 31157114Sscottl 32157114Sscottl#include <sys/param.h> 33157114Sscottl#include <sys/systm.h> 34157114Sscottl#include <sys/kernel.h> 35158737Sambrisko#include <sys/selinfo.h> 36157114Sscottl#include <sys/module.h> 37157114Sscottl#include <sys/malloc.h> 38229611Sjhb#include <sys/sysctl.h> 39158737Sambrisko#include <sys/uio.h> 40157114Sscottl 41157114Sscottl#include <sys/bio.h> 42157114Sscottl#include <sys/bus.h> 43157114Sscottl#include <sys/conf.h> 44157114Sscottl#include <sys/disk.h> 45157114Sscottl#include <geom/geom_disk.h> 46157114Sscottl 47157114Sscottl#include <vm/vm.h> 48157114Sscottl#include <vm/pmap.h> 49157114Sscottl 50157114Sscottl#include <machine/md_var.h> 51157114Sscottl#include <machine/bus.h> 52157114Sscottl#include <sys/rman.h> 53157114Sscottl 54157114Sscottl#include <dev/mfi/mfireg.h> 55157114Sscottl#include <dev/mfi/mfi_ioctl.h> 56157114Sscottl#include <dev/mfi/mfivar.h> 57157114Sscottl 58157114Sscottlstatic int mfi_disk_probe(device_t dev); 59157114Sscottlstatic int mfi_disk_attach(device_t dev); 60157114Sscottlstatic int mfi_disk_detach(device_t dev); 61157114Sscottl 62157114Sscottlstatic disk_open_t mfi_disk_open; 63157114Sscottlstatic disk_close_t mfi_disk_close; 64157114Sscottlstatic disk_strategy_t mfi_disk_strategy; 65157114Sscottlstatic dumper_t mfi_disk_dump; 66157114Sscottl 67157114Sscottlstatic devclass_t mfi_disk_devclass; 68157114Sscottl 69157114Sscottlstatic device_method_t mfi_disk_methods[] = { 70157114Sscottl DEVMETHOD(device_probe, mfi_disk_probe), 71157114Sscottl DEVMETHOD(device_attach, mfi_disk_attach), 72157114Sscottl DEVMETHOD(device_detach, mfi_disk_detach), 73157114Sscottl { 0, 0 } 74157114Sscottl}; 75157114Sscottl 76157114Sscottlstatic driver_t mfi_disk_driver = { 77157114Sscottl "mfid", 78157114Sscottl mfi_disk_methods, 79157114Sscottl sizeof(struct mfi_disk) 80157114Sscottl}; 81157114Sscottl 82157114SscottlDRIVER_MODULE(mfid, mfi, mfi_disk_driver, mfi_disk_devclass, 0, 0); 83157114Sscottl 84157114Sscottlstatic int 85157114Sscottlmfi_disk_probe(device_t dev) 86157114Sscottl{ 87157114Sscottl 88157114Sscottl return (0); 89157114Sscottl} 90157114Sscottl 91157114Sscottlstatic int 92157114Sscottlmfi_disk_attach(device_t dev) 93157114Sscottl{ 94157114Sscottl struct mfi_disk *sc; 95169451Sscottl struct mfi_ld_info *ld_info; 96243824Sdelphij struct mfi_disk_pending *ld_pend; 97157114Sscottl uint64_t sectors; 98157114Sscottl uint32_t secsize; 99163398Sscottl char *state; 100157114Sscottl 101157114Sscottl sc = device_get_softc(dev); 102169451Sscottl ld_info = device_get_ivars(dev); 103157114Sscottl 104157114Sscottl sc->ld_dev = dev; 105169451Sscottl sc->ld_id = ld_info->ld_config.properties.ld.v.target_id; 106157114Sscottl sc->ld_unit = device_get_unit(dev); 107169451Sscottl sc->ld_info = ld_info; 108157114Sscottl sc->ld_controller = device_get_softc(device_get_parent(dev)); 109169451Sscottl sc->ld_flags = 0; 110157114Sscottl 111169451Sscottl sectors = ld_info->size; 112159811Sps secsize = MFI_SECTOR_LEN; 113171821Sjhb mtx_lock(&sc->ld_controller->mfi_io_lock); 114169451Sscottl TAILQ_INSERT_TAIL(&sc->ld_controller->mfi_ld_tqh, sc, ld_link); 115243824Sdelphij TAILQ_FOREACH(ld_pend, &sc->ld_controller->mfi_ld_pend_tqh, 116243824Sdelphij ld_link) { 117243824Sdelphij TAILQ_REMOVE(&sc->ld_controller->mfi_ld_pend_tqh, 118243824Sdelphij ld_pend, ld_link); 119243824Sdelphij free(ld_pend, M_MFIBUF); 120243824Sdelphij break; 121243824Sdelphij } 122171821Sjhb mtx_unlock(&sc->ld_controller->mfi_io_lock); 123157114Sscottl 124169451Sscottl switch (ld_info->ld_config.params.state) { 125163398Sscottl case MFI_LD_STATE_OFFLINE: 126163398Sscottl state = "offline"; 127163398Sscottl break; 128163398Sscottl case MFI_LD_STATE_PARTIALLY_DEGRADED: 129163398Sscottl state = "partially degraded"; 130163398Sscottl break; 131163398Sscottl case MFI_LD_STATE_DEGRADED: 132163398Sscottl state = "degraded"; 133163398Sscottl break; 134163398Sscottl case MFI_LD_STATE_OPTIMAL: 135163398Sscottl state = "optimal"; 136163398Sscottl break; 137163398Sscottl default: 138163398Sscottl state = "unknown"; 139163398Sscottl break; 140163398Sscottl } 141157114Sscottl 142243824Sdelphij if ( strlen(ld_info->ld_config.properties.name) == 0 ) { 143243824Sdelphij device_printf(dev, 144243824Sdelphij "%juMB (%ju sectors) RAID volume (no label) is %s\n", 145243824Sdelphij sectors / (1024 * 1024 / secsize), sectors, state); 146243824Sdelphij } else { 147243824Sdelphij device_printf(dev, 148243824Sdelphij "%juMB (%ju sectors) RAID volume '%s' is %s\n", 149243824Sdelphij sectors / (1024 * 1024 / secsize), sectors, 150243824Sdelphij ld_info->ld_config.properties.name, state); 151243824Sdelphij } 152236719Ssbruno 153157114Sscottl sc->ld_disk = disk_alloc(); 154157114Sscottl sc->ld_disk->d_drv1 = sc; 155185035Sjhb sc->ld_disk->d_maxsize = min(sc->ld_controller->mfi_max_io * secsize, 156185035Sjhb (sc->ld_controller->mfi_max_sge - 1) * PAGE_SIZE); 157157114Sscottl sc->ld_disk->d_name = "mfid"; 158157114Sscottl sc->ld_disk->d_open = mfi_disk_open; 159157114Sscottl sc->ld_disk->d_close = mfi_disk_close; 160157114Sscottl sc->ld_disk->d_strategy = mfi_disk_strategy; 161157114Sscottl sc->ld_disk->d_dump = mfi_disk_dump; 162157114Sscottl sc->ld_disk->d_unit = sc->ld_unit; 163157114Sscottl sc->ld_disk->d_sectorsize = secsize; 164157114Sscottl sc->ld_disk->d_mediasize = sectors * secsize; 165157114Sscottl if (sc->ld_disk->d_mediasize >= (1 * 1024 * 1024)) { 166157114Sscottl sc->ld_disk->d_fwheads = 255; 167157114Sscottl sc->ld_disk->d_fwsectors = 63; 168157114Sscottl } else { 169157114Sscottl sc->ld_disk->d_fwheads = 64; 170157114Sscottl sc->ld_disk->d_fwsectors = 32; 171157114Sscottl } 172157114Sscottl disk_create(sc->ld_disk, DISK_VERSION); 173157114Sscottl 174157114Sscottl return (0); 175157114Sscottl} 176157114Sscottl 177157114Sscottlstatic int 178157114Sscottlmfi_disk_detach(device_t dev) 179157114Sscottl{ 180157114Sscottl struct mfi_disk *sc; 181157114Sscottl 182157114Sscottl sc = device_get_softc(dev); 183157114Sscottl 184171821Sjhb mtx_lock(&sc->ld_controller->mfi_io_lock); 185171821Sjhb if (((sc->ld_disk->d_flags & DISKFLAG_OPEN) || 186171821Sjhb (sc->ld_flags & MFI_DISK_FLAGS_OPEN)) && 187171821Sjhb (sc->ld_controller->mfi_keep_deleted_volumes || 188171821Sjhb sc->ld_controller->mfi_detaching)) { 189171821Sjhb mtx_unlock(&sc->ld_controller->mfi_io_lock); 190157114Sscottl return (EBUSY); 191171821Sjhb } 192171821Sjhb mtx_unlock(&sc->ld_controller->mfi_io_lock); 193157114Sscottl 194171821Sjhb disk_destroy(sc->ld_disk); 195171821Sjhb mtx_lock(&sc->ld_controller->mfi_io_lock); 196171821Sjhb TAILQ_REMOVE(&sc->ld_controller->mfi_ld_tqh, sc, ld_link); 197171821Sjhb mtx_unlock(&sc->ld_controller->mfi_io_lock); 198169451Sscottl free(sc->ld_info, M_MFIBUF); 199157114Sscottl return (0); 200157114Sscottl} 201157114Sscottl 202157114Sscottlstatic int 203157114Sscottlmfi_disk_open(struct disk *dp) 204157114Sscottl{ 205169451Sscottl struct mfi_disk *sc; 206171821Sjhb int error; 207157114Sscottl 208169451Sscottl sc = dp->d_drv1; 209169451Sscottl mtx_lock(&sc->ld_controller->mfi_io_lock); 210171821Sjhb if (sc->ld_flags & MFI_DISK_FLAGS_DISABLED) 211171821Sjhb error = ENXIO; 212171821Sjhb else { 213171821Sjhb sc->ld_flags |= MFI_DISK_FLAGS_OPEN; 214171821Sjhb error = 0; 215171821Sjhb } 216169451Sscottl mtx_unlock(&sc->ld_controller->mfi_io_lock); 217169451Sscottl 218171821Sjhb return (error); 219157114Sscottl} 220157114Sscottl 221157114Sscottlstatic int 222157114Sscottlmfi_disk_close(struct disk *dp) 223157114Sscottl{ 224169451Sscottl struct mfi_disk *sc; 225157114Sscottl 226169451Sscottl sc = dp->d_drv1; 227169451Sscottl mtx_lock(&sc->ld_controller->mfi_io_lock); 228169451Sscottl sc->ld_flags &= ~MFI_DISK_FLAGS_OPEN; 229169451Sscottl mtx_unlock(&sc->ld_controller->mfi_io_lock); 230169451Sscottl 231157114Sscottl return (0); 232157114Sscottl} 233157114Sscottl 234171821Sjhbint 235171821Sjhbmfi_disk_disable(struct mfi_disk *sc) 236171821Sjhb{ 237171821Sjhb 238171821Sjhb mtx_assert(&sc->ld_controller->mfi_io_lock, MA_OWNED); 239171821Sjhb if (sc->ld_flags & MFI_DISK_FLAGS_OPEN) { 240171821Sjhb if (sc->ld_controller->mfi_delete_busy_volumes) 241171821Sjhb return (0); 242234429Sambrisko device_printf(sc->ld_dev, "Unable to delete busy ld device\n"); 243171821Sjhb return (EBUSY); 244171821Sjhb } 245171821Sjhb sc->ld_flags |= MFI_DISK_FLAGS_DISABLED; 246171821Sjhb return (0); 247171821Sjhb} 248171821Sjhb 249171821Sjhbvoid 250171821Sjhbmfi_disk_enable(struct mfi_disk *sc) 251171821Sjhb{ 252171821Sjhb 253171821Sjhb mtx_assert(&sc->ld_controller->mfi_io_lock, MA_OWNED); 254171821Sjhb sc->ld_flags &= ~MFI_DISK_FLAGS_DISABLED; 255171821Sjhb} 256171821Sjhb 257157114Sscottlstatic void 258157114Sscottlmfi_disk_strategy(struct bio *bio) 259157114Sscottl{ 260157114Sscottl struct mfi_disk *sc; 261157114Sscottl struct mfi_softc *controller; 262157114Sscottl 263157114Sscottl sc = bio->bio_disk->d_drv1; 264157114Sscottl 265157114Sscottl if (sc == NULL) { 266157114Sscottl bio->bio_error = EINVAL; 267157114Sscottl bio->bio_flags |= BIO_ERROR; 268157114Sscottl bio->bio_resid = bio->bio_bcount; 269157114Sscottl biodone(bio); 270157114Sscottl return; 271157114Sscottl } 272157114Sscottl 273249290Sdelphij controller = sc->ld_controller; 274235135Sambrisko if (controller->adpreset) { 275234429Sambrisko bio->bio_error = EBUSY; 276234429Sambrisko return; 277234429Sambrisko } 278234429Sambrisko 279235135Sambrisko if (controller->hw_crit_error) { 280234429Sambrisko bio->bio_error = EBUSY; 281234429Sambrisko return; 282234429Sambrisko } 283234429Sambrisko 284235135Sambrisko if (controller->issuepend_done == 0) { 285234429Sambrisko bio->bio_error = EBUSY; 286234429Sambrisko return; 287234429Sambrisko } 288234429Sambrisko 289157114Sscottl bio->bio_driver1 = (void *)(uintptr_t)sc->ld_id; 290234429Sambrisko /* Mark it as LD IO */ 291234429Sambrisko bio->bio_driver2 = (void *)MFI_LD_IO; 292157114Sscottl mtx_lock(&controller->mfi_io_lock); 293157114Sscottl mfi_enqueue_bio(controller, bio); 294157114Sscottl mfi_startio(controller); 295157114Sscottl mtx_unlock(&controller->mfi_io_lock); 296157114Sscottl return; 297157114Sscottl} 298157114Sscottl 299157114Sscottlvoid 300157114Sscottlmfi_disk_complete(struct bio *bio) 301157114Sscottl{ 302157114Sscottl struct mfi_disk *sc; 303157114Sscottl struct mfi_frame_header *hdr; 304157114Sscottl 305157114Sscottl sc = bio->bio_disk->d_drv1; 306157114Sscottl hdr = bio->bio_driver1; 307157114Sscottl 308157114Sscottl if (bio->bio_flags & BIO_ERROR) { 309240873Ssbruno bio->bio_resid = bio->bio_bcount; 310157114Sscottl if (bio->bio_error == 0) 311157114Sscottl bio->bio_error = EIO; 312157114Sscottl disk_err(bio, "hard error", -1, 1); 313157114Sscottl } else { 314157114Sscottl bio->bio_resid = 0; 315157114Sscottl } 316157114Sscottl biodone(bio); 317157114Sscottl} 318157114Sscottl 319157114Sscottlstatic int 320157114Sscottlmfi_disk_dump(void *arg, void *virt, vm_offset_t phys, off_t offset, size_t len) 321157114Sscottl{ 322157114Sscottl struct mfi_disk *sc; 323157114Sscottl struct mfi_softc *parent_sc; 324157114Sscottl struct disk *dp; 325157114Sscottl int error; 326157114Sscottl 327157114Sscottl dp = arg; 328157114Sscottl sc = dp->d_drv1; 329157114Sscottl parent_sc = sc->ld_controller; 330157114Sscottl 331157114Sscottl if (len > 0) { 332157114Sscottl if ((error = mfi_dump_blocks(parent_sc, sc->ld_id, offset / 333159811Sps MFI_SECTOR_LEN, virt, len)) != 0) 334157114Sscottl return (error); 335157114Sscottl } else { 336157114Sscottl /* mfi_sync_cache(parent_sc, sc->ld_id); */ 337157114Sscottl } 338157114Sscottl 339157114Sscottl return (0); 340157114Sscottl} 341