1 /*- 2 * Copyright (c) 2006 IronPort Systems 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 /*- 27 * Redistribution and use in source and binary forms, with or without 28 * modification, are permitted provided that the following conditions 29 * are met: 30 * 31 * Copyright 1994-2009 The FreeBSD Project. 32 * All rights reserved. 33 * 34 * 1. Redistributions of source code must retain the above copyright 35 * notice, this list of conditions and the following disclaimer. 36 * 2. Redistributions in binary form must reproduce the above copyright 37 * notice, this list of conditions and the following disclaimer in the 38 * documentation and/or other materials provided with the distribution. 39 * 40 * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT``AS IS'' AND 41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 42 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR 44 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 45 * EXEMPLARY,OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 46 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 47 * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY 48 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 49 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 50 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51 * 52 * The views and conclusions contained in the software and documentation 53 * are those of the authors and should not be interpreted as representing 54 * official policies,either expressed or implied, of the FreeBSD Project. 55 * 56 * $FreeBSD: src/sys/dev/mfi/mfi_disk.c,v 1.8 2008/11/17 23:30:19 jhb Exp $ 57 */ 58 59 #include "opt_mfi.h" 60 61 #include <sys/param.h> 62 #include <sys/systm.h> 63 #include <sys/kernel.h> 64 #include <sys/module.h> 65 #include <sys/malloc.h> 66 #include <sys/uio.h> 67 68 #include <sys/buf2.h> 69 #include <sys/bus.h> 70 #include <sys/conf.h> 71 #include <sys/disk.h> 72 73 #include <vm/vm.h> 74 #include <vm/pmap.h> 75 76 #include <machine/md_var.h> 77 #include <sys/rman.h> 78 79 #include <dev/raid/mfi/mfireg.h> 80 #include <dev/raid/mfi/mfi_ioctl.h> 81 #include <dev/raid/mfi/mfivar.h> 82 83 static int mfi_disk_probe(device_t dev); 84 static int mfi_disk_attach(device_t dev); 85 static int mfi_disk_detach(device_t dev); 86 87 static d_open_t mfi_disk_open; 88 static d_close_t mfi_disk_close; 89 static d_strategy_t mfi_disk_strategy; 90 static d_dump_t mfi_disk_dump; 91 92 static struct dev_ops mfi_disk_ops = { 93 { "mfid", 0, D_DISK }, 94 .d_open = mfi_disk_open, 95 .d_close = mfi_disk_close, 96 .d_strategy = mfi_disk_strategy, 97 .d_dump = mfi_disk_dump, 98 }; 99 100 static devclass_t mfi_disk_devclass; 101 102 static device_method_t mfi_disk_methods[] = { 103 DEVMETHOD(device_probe, mfi_disk_probe), 104 DEVMETHOD(device_attach, mfi_disk_attach), 105 DEVMETHOD(device_detach, mfi_disk_detach), 106 { 0, 0 } 107 }; 108 109 static driver_t mfi_disk_driver = { 110 "mfid", 111 mfi_disk_methods, 112 sizeof(struct mfi_disk) 113 }; 114 115 DRIVER_MODULE(mfid, mfi, mfi_disk_driver, mfi_disk_devclass, NULL, NULL); 116 117 static int 118 mfi_disk_probe(device_t dev) 119 { 120 121 return (0); 122 } 123 124 static int 125 mfi_disk_attach(device_t dev) 126 { 127 struct mfi_disk *sc; 128 struct mfi_ld_info *ld_info; 129 struct disk_info info; 130 uint64_t sectors; 131 uint32_t secsize; 132 char *state; 133 134 sc = device_get_softc(dev); 135 ld_info = device_get_ivars(dev); 136 137 sc->ld_dev = dev; 138 sc->ld_id = ld_info->ld_config.properties.ld.v.target_id; 139 sc->ld_unit = device_get_unit(dev); 140 sc->ld_info = ld_info; 141 sc->ld_controller = device_get_softc(device_get_parent(dev)); 142 sc->ld_flags = 0; 143 144 sectors = ld_info->size; 145 secsize = MFI_SECTOR_LEN; 146 lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE); 147 TAILQ_INSERT_TAIL(&sc->ld_controller->mfi_ld_tqh, sc, ld_link); 148 lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE); 149 150 switch (ld_info->ld_config.params.state) { 151 case MFI_LD_STATE_OFFLINE: 152 state = "offline"; 153 break; 154 case MFI_LD_STATE_PARTIALLY_DEGRADED: 155 state = "partially degraded"; 156 break; 157 case MFI_LD_STATE_DEGRADED: 158 state = "degraded"; 159 break; 160 case MFI_LD_STATE_OPTIMAL: 161 state = "optimal"; 162 break; 163 default: 164 state = "unknown"; 165 break; 166 } 167 device_printf(dev, "%juMB (%ju sectors) RAID volume '%s' is %s\n", 168 sectors / (1024 * 1024 / secsize), sectors, 169 ld_info->ld_config.properties.name, 170 state); 171 172 devstat_add_entry(&sc->ld_devstat, "mfid", device_get_unit(dev), 173 MFI_SECTOR_LEN, DEVSTAT_NO_ORDERED_TAGS, 174 DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, 175 DEVSTAT_PRIORITY_ARRAY); 176 177 sc->ld_disk.d_cdev = disk_create(sc->ld_unit, &sc->ld_disk, 178 &mfi_disk_ops); 179 sc->ld_disk.d_cdev->si_drv1 = sc; 180 sc->ld_disk.d_cdev->si_iosize_max = 181 min(sc->ld_controller->mfi_max_io * secsize, 182 (sc->ld_controller->mfi_max_sge - 1) * PAGE_SIZE); 183 184 bzero(&info, sizeof(info)); 185 info.d_media_blksize = secsize; /* mandatory */ 186 info.d_media_blocks = sectors; 187 188 if (info.d_media_blocks >= (1 * 1024 * 1024)) { 189 info.d_nheads = 255; 190 info.d_secpertrack = 63; 191 } else { 192 info.d_nheads = 64; 193 info.d_secpertrack = 32; 194 } 195 196 disk_setdiskinfo(&sc->ld_disk, &info); 197 198 return (0); 199 } 200 201 static int 202 mfi_disk_detach(device_t dev) 203 { 204 struct mfi_disk *sc; 205 206 sc = device_get_softc(dev); 207 208 lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE); 209 if ((sc->ld_flags & MFI_DISK_FLAGS_OPEN) && 210 (sc->ld_controller->mfi_keep_deleted_volumes || 211 sc->ld_controller->mfi_detaching)) { 212 lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE); 213 return (EBUSY); 214 } 215 lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE); 216 217 disk_destroy(&sc->ld_disk); 218 devstat_remove_entry(&sc->ld_devstat); 219 lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE); 220 TAILQ_REMOVE(&sc->ld_controller->mfi_ld_tqh, sc, ld_link); 221 lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE); 222 kfree(sc->ld_info, M_MFIBUF); 223 return (0); 224 } 225 226 static int 227 mfi_disk_open(struct dev_open_args *ap) 228 { 229 struct mfi_disk *sc = ap->a_head.a_dev->si_drv1; 230 int error; 231 232 lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE); 233 if (sc->ld_flags & MFI_DISK_FLAGS_DISABLED) 234 error = ENXIO; 235 else { 236 sc->ld_flags |= MFI_DISK_FLAGS_OPEN; 237 error = 0; 238 } 239 lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE); 240 241 return (error); 242 } 243 244 static int 245 mfi_disk_close(struct dev_close_args *ap) 246 { 247 struct mfi_disk *sc = ap->a_head.a_dev->si_drv1; 248 249 lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE); 250 sc->ld_flags &= ~MFI_DISK_FLAGS_OPEN; 251 lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE); 252 253 return (0); 254 } 255 256 int 257 mfi_disk_disable(struct mfi_disk *sc) 258 { 259 260 KKASSERT(lockstatus(&sc->ld_controller->mfi_io_lock, curthread) != 0); 261 if (sc->ld_flags & MFI_DISK_FLAGS_OPEN) { 262 if (sc->ld_controller->mfi_delete_busy_volumes) 263 return (0); 264 device_printf(sc->ld_dev, "Unable to delete busy ld device\n"); 265 return (EBUSY); 266 } 267 sc->ld_flags |= MFI_DISK_FLAGS_DISABLED; 268 return (0); 269 } 270 271 void 272 mfi_disk_enable(struct mfi_disk *sc) 273 { 274 275 KKASSERT(lockstatus(&sc->ld_controller->mfi_io_lock, curthread) != 0); 276 sc->ld_flags &= ~MFI_DISK_FLAGS_DISABLED; 277 } 278 279 static int 280 mfi_disk_strategy(struct dev_strategy_args *ap) 281 { 282 struct bio *bio = ap->a_bio; 283 struct buf *bp = bio->bio_buf; 284 struct mfi_disk *sc = ap->a_head.a_dev->si_drv1; 285 struct mfi_softc *controller; 286 287 if (sc == NULL) { 288 bp->b_error = EINVAL; 289 bp->b_flags |= B_ERROR; 290 bp->b_resid = bp->b_bcount; 291 biodone(bio); 292 return (0); 293 } 294 295 /* 296 * XXX swildner 297 * 298 * If it's a null transfer, do nothing. FreeBSD's original driver 299 * doesn't have this, but that caused hard error messages (even 300 * though everything else continued to work fine). Interestingly, 301 * only when HAMMER was used. 302 * 303 * Several others of our RAID drivers have this check, such as 304 * aac(4) and ida(4), so we insert it here, too. 305 * 306 * The cause of null transfers is yet unknown. 307 */ 308 if (bp->b_bcount == 0) { 309 bp->b_resid = bp->b_bcount; 310 biodone(bio); 311 return (0); 312 } 313 314 controller = sc->ld_controller; 315 bio->bio_driver_info = sc; 316 lockmgr(&controller->mfi_io_lock, LK_EXCLUSIVE); 317 mfi_enqueue_bio(controller, bio); 318 devstat_start_transaction(&sc->ld_devstat); 319 mfi_startio(controller); 320 lockmgr(&controller->mfi_io_lock, LK_RELEASE); 321 return (0); 322 } 323 324 void 325 mfi_disk_complete(struct bio *bio) 326 { 327 struct mfi_disk *sc = bio->bio_driver_info; 328 struct buf *bp = bio->bio_buf; 329 330 devstat_end_transaction_buf(&sc->ld_devstat, bp); 331 if (bp->b_flags & B_ERROR) { 332 if (bp->b_error == 0) 333 bp->b_error = EIO; 334 diskerr(bio, sc->ld_disk.d_cdev, "hard error", -1, 1); 335 kprintf("\n"); 336 } else { 337 bp->b_resid = 0; 338 } 339 biodone(bio); 340 } 341 342 static int 343 mfi_disk_dump(struct dev_dump_args *ap) 344 { 345 cdev_t dev = ap->a_head.a_dev; 346 off_t offset = ap->a_offset; 347 void *virt = ap->a_virtual; 348 size_t len = ap->a_length; 349 struct mfi_disk *sc; 350 struct mfi_softc *parent_sc; 351 int error; 352 353 sc = dev->si_drv1; 354 parent_sc = sc->ld_controller; 355 356 if (len > 0) { 357 if ((error = mfi_dump_blocks(parent_sc, sc->ld_id, offset / 358 MFI_SECTOR_LEN, virt, len)) != 0) 359 return (error); 360 } else { 361 /* mfi_sync_cache(parent_sc, sc->ld_id); */ 362 } 363 364 return (0); 365 } 366