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 devclass_t mfi_disk_devclass; 72 73 static device_method_t mfi_disk_methods[] = { 74 DEVMETHOD(device_probe, mfi_disk_probe), 75 DEVMETHOD(device_attach, mfi_disk_attach), 76 DEVMETHOD(device_detach, mfi_disk_detach), 77 { 0, 0 } 78 }; 79 80 static driver_t mfi_disk_driver = { 81 "mfid", 82 mfi_disk_methods, 83 sizeof(struct mfi_disk) 84 }; 85 86 DRIVER_MODULE(mfid, mfi, mfi_disk_driver, mfi_disk_devclass, 0, 0); 87 88 static int 89 mfi_disk_probe(device_t dev) 90 { 91 92 return (0); 93 } 94 95 static int 96 mfi_disk_attach(device_t dev) 97 { 98 struct mfi_disk *sc; 99 struct mfi_ld_info *ld_info; 100 struct mfi_disk_pending *ld_pend; 101 uint64_t sectors; 102 uint32_t secsize; 103 char *state; 104 105 sc = device_get_softc(dev); 106 ld_info = device_get_ivars(dev); 107 108 sc->ld_dev = dev; 109 sc->ld_id = ld_info->ld_config.properties.ld.v.target_id; 110 sc->ld_unit = device_get_unit(dev); 111 sc->ld_info = ld_info; 112 sc->ld_controller = device_get_softc(device_get_parent(dev)); 113 sc->ld_flags = 0; 114 115 sectors = ld_info->size; 116 secsize = MFI_SECTOR_LEN; 117 mtx_lock(&sc->ld_controller->mfi_io_lock); 118 TAILQ_INSERT_TAIL(&sc->ld_controller->mfi_ld_tqh, sc, ld_link); 119 TAILQ_FOREACH(ld_pend, &sc->ld_controller->mfi_ld_pend_tqh, 120 ld_link) { 121 TAILQ_REMOVE(&sc->ld_controller->mfi_ld_pend_tqh, 122 ld_pend, ld_link); 123 free(ld_pend, M_MFIBUF); 124 break; 125 } 126 mtx_unlock(&sc->ld_controller->mfi_io_lock); 127 128 switch (ld_info->ld_config.params.state) { 129 case MFI_LD_STATE_OFFLINE: 130 state = "offline"; 131 break; 132 case MFI_LD_STATE_PARTIALLY_DEGRADED: 133 state = "partially degraded"; 134 break; 135 case MFI_LD_STATE_DEGRADED: 136 state = "degraded"; 137 break; 138 case MFI_LD_STATE_OPTIMAL: 139 state = "optimal"; 140 break; 141 default: 142 state = "unknown"; 143 break; 144 } 145 146 if ( strlen(ld_info->ld_config.properties.name) == 0 ) { 147 device_printf(dev, 148 "%juMB (%ju sectors) RAID volume (no label) is %s\n", 149 sectors / (1024 * 1024 / secsize), sectors, state); 150 } else { 151 device_printf(dev, 152 "%juMB (%ju sectors) RAID volume '%s' is %s\n", 153 sectors / (1024 * 1024 / secsize), sectors, 154 ld_info->ld_config.properties.name, state); 155 } 156 157 sc->ld_disk = disk_alloc(); 158 sc->ld_disk->d_drv1 = sc; 159 sc->ld_disk->d_maxsize = min(sc->ld_controller->mfi_max_io * secsize, 160 (sc->ld_controller->mfi_max_sge - 1) * PAGE_SIZE); 161 sc->ld_disk->d_name = "mfid"; 162 sc->ld_disk->d_open = mfi_disk_open; 163 sc->ld_disk->d_close = mfi_disk_close; 164 sc->ld_disk->d_strategy = mfi_disk_strategy; 165 sc->ld_disk->d_dump = mfi_disk_dump; 166 sc->ld_disk->d_unit = sc->ld_unit; 167 sc->ld_disk->d_sectorsize = secsize; 168 sc->ld_disk->d_mediasize = sectors * secsize; 169 if (sc->ld_disk->d_mediasize >= (1 * 1024 * 1024)) { 170 sc->ld_disk->d_fwheads = 255; 171 sc->ld_disk->d_fwsectors = 63; 172 } else { 173 sc->ld_disk->d_fwheads = 64; 174 sc->ld_disk->d_fwsectors = 32; 175 } 176 sc->ld_disk->d_flags = DISKFLAG_UNMAPPED_BIO; 177 disk_create(sc->ld_disk, DISK_VERSION); 178 179 return (0); 180 } 181 182 static int 183 mfi_disk_detach(device_t dev) 184 { 185 struct mfi_disk *sc; 186 187 sc = device_get_softc(dev); 188 189 mtx_lock(&sc->ld_controller->mfi_io_lock); 190 if (((sc->ld_disk->d_flags & DISKFLAG_OPEN) || 191 (sc->ld_flags & MFI_DISK_FLAGS_OPEN)) && 192 (sc->ld_controller->mfi_keep_deleted_volumes || 193 sc->ld_controller->mfi_detaching)) { 194 mtx_unlock(&sc->ld_controller->mfi_io_lock); 195 return (EBUSY); 196 } 197 mtx_unlock(&sc->ld_controller->mfi_io_lock); 198 199 disk_destroy(sc->ld_disk); 200 mtx_lock(&sc->ld_controller->mfi_io_lock); 201 TAILQ_REMOVE(&sc->ld_controller->mfi_ld_tqh, sc, ld_link); 202 mtx_unlock(&sc->ld_controller->mfi_io_lock); 203 free(sc->ld_info, M_MFIBUF); 204 return (0); 205 } 206 207 static int 208 mfi_disk_open(struct disk *dp) 209 { 210 struct mfi_disk *sc; 211 int error; 212 213 sc = dp->d_drv1; 214 mtx_lock(&sc->ld_controller->mfi_io_lock); 215 if (sc->ld_flags & MFI_DISK_FLAGS_DISABLED) 216 error = ENXIO; 217 else { 218 sc->ld_flags |= MFI_DISK_FLAGS_OPEN; 219 error = 0; 220 } 221 mtx_unlock(&sc->ld_controller->mfi_io_lock); 222 223 return (error); 224 } 225 226 static int 227 mfi_disk_close(struct disk *dp) 228 { 229 struct mfi_disk *sc; 230 231 sc = dp->d_drv1; 232 mtx_lock(&sc->ld_controller->mfi_io_lock); 233 sc->ld_flags &= ~MFI_DISK_FLAGS_OPEN; 234 mtx_unlock(&sc->ld_controller->mfi_io_lock); 235 236 return (0); 237 } 238 239 int 240 mfi_disk_disable(struct mfi_disk *sc) 241 { 242 243 mtx_assert(&sc->ld_controller->mfi_io_lock, MA_OWNED); 244 if (sc->ld_flags & MFI_DISK_FLAGS_OPEN) { 245 if (sc->ld_controller->mfi_delete_busy_volumes) 246 return (0); 247 device_printf(sc->ld_dev, "Unable to delete busy ld device\n"); 248 return (EBUSY); 249 } 250 sc->ld_flags |= MFI_DISK_FLAGS_DISABLED; 251 return (0); 252 } 253 254 void 255 mfi_disk_enable(struct mfi_disk *sc) 256 { 257 258 mtx_assert(&sc->ld_controller->mfi_io_lock, MA_OWNED); 259 sc->ld_flags &= ~MFI_DISK_FLAGS_DISABLED; 260 } 261 262 static void 263 mfi_disk_strategy(struct bio *bio) 264 { 265 struct mfi_disk *sc; 266 struct mfi_softc *controller; 267 268 sc = bio->bio_disk->d_drv1; 269 270 if (sc == NULL) { 271 bio->bio_error = EINVAL; 272 bio->bio_flags |= BIO_ERROR; 273 bio->bio_resid = bio->bio_bcount; 274 biodone(bio); 275 return; 276 } 277 278 controller = sc->ld_controller; 279 if (controller->adpreset) { 280 bio->bio_error = EBUSY; 281 return; 282 } 283 284 if (controller->hw_crit_error) { 285 bio->bio_error = EBUSY; 286 return; 287 } 288 289 if (controller->issuepend_done == 0) { 290 bio->bio_error = EBUSY; 291 return; 292 } 293 294 bio->bio_driver1 = (void *)(uintptr_t)sc->ld_id; 295 /* Mark it as LD IO */ 296 bio->bio_driver2 = (void *)MFI_LD_IO; 297 mtx_lock(&controller->mfi_io_lock); 298 mfi_enqueue_bio(controller, bio); 299 mfi_startio(controller); 300 mtx_unlock(&controller->mfi_io_lock); 301 return; 302 } 303 304 void 305 mfi_disk_complete(struct bio *bio) 306 { 307 struct mfi_disk *sc; 308 struct mfi_frame_header *hdr; 309 310 sc = bio->bio_disk->d_drv1; 311 hdr = bio->bio_driver1; 312 313 if (bio->bio_flags & BIO_ERROR) { 314 bio->bio_resid = bio->bio_bcount; 315 if (bio->bio_error == 0) 316 bio->bio_error = EIO; 317 disk_err(bio, "hard error", -1, 1); 318 } else { 319 bio->bio_resid = 0; 320 } 321 biodone(bio); 322 } 323 324 static int 325 mfi_disk_dump(void *arg, void *virt, vm_offset_t phys, off_t offset, size_t len) 326 { 327 struct mfi_disk *sc; 328 struct mfi_softc *parent_sc; 329 struct disk *dp; 330 int error; 331 332 dp = arg; 333 sc = dp->d_drv1; 334 parent_sc = sc->ld_controller; 335 336 if (len > 0) { 337 if ((error = mfi_dump_blocks(parent_sc, sc->ld_id, offset / 338 MFI_SECTOR_LEN, virt, len)) != 0) 339 return (error); 340 } else { 341 /* mfi_sync_cache(parent_sc, sc->ld_id); */ 342 } 343 344 return (0); 345 } 346