1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2006 IronPort Systems 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include "opt_mfi.h" 33 34 #include <sys/param.h> 35 #include <sys/bio.h> 36 #include <sys/bus.h> 37 #include <sys/conf.h> 38 #include <sys/disk.h> 39 #include <sys/kernel.h> 40 #include <sys/lock.h> 41 #include <sys/malloc.h> 42 #include <sys/module.h> 43 #include <sys/mutex.h> 44 #include <sys/selinfo.h> 45 #include <sys/sysctl.h> 46 #include <sys/systm.h> 47 #include <sys/uio.h> 48 49 #include <geom/geom_disk.h> 50 51 #include <vm/vm.h> 52 #include <vm/pmap.h> 53 54 #include <machine/md_var.h> 55 #include <machine/bus.h> 56 #include <sys/rman.h> 57 58 #include <dev/mfi/mfireg.h> 59 #include <dev/mfi/mfi_ioctl.h> 60 #include <dev/mfi/mfivar.h> 61 62 static int mfi_disk_probe(device_t dev); 63 static int mfi_disk_attach(device_t dev); 64 static int mfi_disk_detach(device_t dev); 65 66 static disk_open_t mfi_disk_open; 67 static disk_close_t mfi_disk_close; 68 static disk_strategy_t mfi_disk_strategy; 69 static dumper_t mfi_disk_dump; 70 71 static device_method_t mfi_disk_methods[] = { 72 DEVMETHOD(device_probe, mfi_disk_probe), 73 DEVMETHOD(device_attach, mfi_disk_attach), 74 DEVMETHOD(device_detach, mfi_disk_detach), 75 { 0, 0 } 76 }; 77 78 static driver_t mfi_disk_driver = { 79 "mfid", 80 mfi_disk_methods, 81 sizeof(struct mfi_disk) 82 }; 83 84 DRIVER_MODULE(mfid, mfi, mfi_disk_driver, 0, 0); 85 86 static int 87 mfi_disk_probe(device_t dev) 88 { 89 90 return (0); 91 } 92 93 static int 94 mfi_disk_attach(device_t dev) 95 { 96 struct mfi_disk *sc; 97 struct mfi_ld_info *ld_info; 98 struct mfi_disk_pending *ld_pend; 99 uint64_t sectors; 100 uint32_t secsize; 101 char *state; 102 103 sc = device_get_softc(dev); 104 ld_info = device_get_ivars(dev); 105 106 sc->ld_dev = dev; 107 sc->ld_id = ld_info->ld_config.properties.ld.v.target_id; 108 sc->ld_unit = device_get_unit(dev); 109 sc->ld_info = ld_info; 110 sc->ld_controller = device_get_softc(device_get_parent(dev)); 111 sc->ld_flags = 0; 112 113 sectors = ld_info->size; 114 secsize = MFI_SECTOR_LEN; 115 mtx_lock(&sc->ld_controller->mfi_io_lock); 116 TAILQ_INSERT_TAIL(&sc->ld_controller->mfi_ld_tqh, sc, ld_link); 117 TAILQ_FOREACH(ld_pend, &sc->ld_controller->mfi_ld_pend_tqh, 118 ld_link) { 119 TAILQ_REMOVE(&sc->ld_controller->mfi_ld_pend_tqh, 120 ld_pend, ld_link); 121 free(ld_pend, M_MFIBUF); 122 break; 123 } 124 mtx_unlock(&sc->ld_controller->mfi_io_lock); 125 126 switch (ld_info->ld_config.params.state) { 127 case MFI_LD_STATE_OFFLINE: 128 state = "offline"; 129 break; 130 case MFI_LD_STATE_PARTIALLY_DEGRADED: 131 state = "partially degraded"; 132 break; 133 case MFI_LD_STATE_DEGRADED: 134 state = "degraded"; 135 break; 136 case MFI_LD_STATE_OPTIMAL: 137 state = "optimal"; 138 break; 139 default: 140 state = "unknown"; 141 break; 142 } 143 144 if ( strlen(ld_info->ld_config.properties.name) == 0 ) { 145 device_printf(dev, 146 "%juMB (%ju sectors) RAID volume (no label) is %s\n", 147 sectors / (1024 * 1024 / secsize), sectors, state); 148 } else { 149 device_printf(dev, 150 "%juMB (%ju sectors) RAID volume '%s' is %s\n", 151 sectors / (1024 * 1024 / secsize), sectors, 152 ld_info->ld_config.properties.name, state); 153 } 154 155 sc->ld_disk = disk_alloc(); 156 sc->ld_disk->d_drv1 = sc; 157 sc->ld_disk->d_maxsize = min(sc->ld_controller->mfi_max_io * secsize, 158 (sc->ld_controller->mfi_max_sge - 1) * PAGE_SIZE); 159 sc->ld_disk->d_name = "mfid"; 160 sc->ld_disk->d_open = mfi_disk_open; 161 sc->ld_disk->d_close = mfi_disk_close; 162 sc->ld_disk->d_strategy = mfi_disk_strategy; 163 sc->ld_disk->d_dump = mfi_disk_dump; 164 sc->ld_disk->d_unit = sc->ld_unit; 165 sc->ld_disk->d_sectorsize = secsize; 166 sc->ld_disk->d_mediasize = sectors * secsize; 167 if (sc->ld_disk->d_mediasize >= (1 * 1024 * 1024)) { 168 sc->ld_disk->d_fwheads = 255; 169 sc->ld_disk->d_fwsectors = 63; 170 } else { 171 sc->ld_disk->d_fwheads = 64; 172 sc->ld_disk->d_fwsectors = 32; 173 } 174 sc->ld_disk->d_flags = DISKFLAG_UNMAPPED_BIO; 175 disk_create(sc->ld_disk, DISK_VERSION); 176 177 return (0); 178 } 179 180 static int 181 mfi_disk_detach(device_t dev) 182 { 183 struct mfi_disk *sc; 184 185 sc = device_get_softc(dev); 186 187 mtx_lock(&sc->ld_controller->mfi_io_lock); 188 if (((sc->ld_disk->d_flags & DISKFLAG_OPEN) || 189 (sc->ld_flags & MFI_DISK_FLAGS_OPEN)) && 190 (sc->ld_controller->mfi_keep_deleted_volumes || 191 sc->ld_controller->mfi_detaching)) { 192 mtx_unlock(&sc->ld_controller->mfi_io_lock); 193 return (EBUSY); 194 } 195 mtx_unlock(&sc->ld_controller->mfi_io_lock); 196 197 disk_destroy(sc->ld_disk); 198 mtx_lock(&sc->ld_controller->mfi_io_lock); 199 TAILQ_REMOVE(&sc->ld_controller->mfi_ld_tqh, sc, ld_link); 200 mtx_unlock(&sc->ld_controller->mfi_io_lock); 201 free(sc->ld_info, M_MFIBUF); 202 return (0); 203 } 204 205 static int 206 mfi_disk_open(struct disk *dp) 207 { 208 struct mfi_disk *sc; 209 int error; 210 211 sc = dp->d_drv1; 212 mtx_lock(&sc->ld_controller->mfi_io_lock); 213 if (sc->ld_flags & MFI_DISK_FLAGS_DISABLED) 214 error = ENXIO; 215 else { 216 sc->ld_flags |= MFI_DISK_FLAGS_OPEN; 217 error = 0; 218 } 219 mtx_unlock(&sc->ld_controller->mfi_io_lock); 220 221 return (error); 222 } 223 224 static int 225 mfi_disk_close(struct disk *dp) 226 { 227 struct mfi_disk *sc; 228 229 sc = dp->d_drv1; 230 mtx_lock(&sc->ld_controller->mfi_io_lock); 231 sc->ld_flags &= ~MFI_DISK_FLAGS_OPEN; 232 mtx_unlock(&sc->ld_controller->mfi_io_lock); 233 234 return (0); 235 } 236 237 int 238 mfi_disk_disable(struct mfi_disk *sc) 239 { 240 241 mtx_assert(&sc->ld_controller->mfi_io_lock, MA_OWNED); 242 if (sc->ld_flags & MFI_DISK_FLAGS_OPEN) { 243 if (sc->ld_controller->mfi_delete_busy_volumes) 244 return (0); 245 device_printf(sc->ld_dev, "Unable to delete busy ld device\n"); 246 return (EBUSY); 247 } 248 sc->ld_flags |= MFI_DISK_FLAGS_DISABLED; 249 return (0); 250 } 251 252 void 253 mfi_disk_enable(struct mfi_disk *sc) 254 { 255 256 mtx_assert(&sc->ld_controller->mfi_io_lock, MA_OWNED); 257 sc->ld_flags &= ~MFI_DISK_FLAGS_DISABLED; 258 } 259 260 static void 261 mfi_disk_strategy(struct bio *bio) 262 { 263 struct mfi_disk *sc; 264 struct mfi_softc *controller; 265 266 sc = bio->bio_disk->d_drv1; 267 268 if (sc == NULL) { 269 bio->bio_error = EINVAL; 270 bio->bio_flags |= BIO_ERROR; 271 bio->bio_resid = bio->bio_bcount; 272 biodone(bio); 273 return; 274 } 275 276 controller = sc->ld_controller; 277 if (controller->adpreset) { 278 bio->bio_error = EBUSY; 279 return; 280 } 281 282 if (controller->hw_crit_error) { 283 bio->bio_error = EBUSY; 284 return; 285 } 286 287 if (controller->issuepend_done == 0) { 288 bio->bio_error = EBUSY; 289 return; 290 } 291 292 bio->bio_driver1 = (void *)(uintptr_t)sc->ld_id; 293 /* Mark it as LD IO */ 294 bio->bio_driver2 = (void *)MFI_LD_IO; 295 mtx_lock(&controller->mfi_io_lock); 296 mfi_enqueue_bio(controller, bio); 297 mfi_startio(controller); 298 mtx_unlock(&controller->mfi_io_lock); 299 return; 300 } 301 302 void 303 mfi_disk_complete(struct bio *bio) 304 { 305 306 if (bio->bio_flags & BIO_ERROR) { 307 bio->bio_resid = bio->bio_bcount; 308 if (bio->bio_error == 0) 309 bio->bio_error = EIO; 310 disk_err(bio, "hard error", -1, 1); 311 } else { 312 bio->bio_resid = 0; 313 } 314 biodone(bio); 315 } 316 317 static int 318 mfi_disk_dump(void *arg, void *virt, off_t offset, size_t len) 319 { 320 struct mfi_disk *sc; 321 struct mfi_softc *parent_sc; 322 struct disk *dp; 323 int error; 324 325 dp = arg; 326 sc = dp->d_drv1; 327 parent_sc = sc->ld_controller; 328 329 if (len > 0) { 330 if ((error = mfi_dump_blocks(parent_sc, sc->ld_id, offset / 331 MFI_SECTOR_LEN, virt, len)) != 0) 332 return (error); 333 } else { 334 /* mfi_sync_cache(parent_sc, sc->ld_id); */ 335 } 336 337 return (0); 338 } 339