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_dev_t = disk_create(sc->ld_unit, &sc->ld_disk, &mfi_disk_ops); 178 sc->ld_dev_t->si_drv1 = sc; 179 sc->ld_dev_t->si_iosize_max = 180 min(sc->ld_controller->mfi_max_io * secsize, 181 (sc->ld_controller->mfi_max_sge - 1) * PAGE_SIZE); 182 183 bzero(&info, sizeof(info)); 184 info.d_media_blksize = secsize; /* mandatory */ 185 info.d_media_blocks = sectors; 186 187 if (info.d_media_blocks >= (1 * 1024 * 1024)) { 188 info.d_nheads = 255; 189 info.d_secpertrack = 63; 190 } else { 191 info.d_nheads = 64; 192 info.d_secpertrack = 32; 193 } 194 195 disk_setdiskinfo(&sc->ld_disk, &info); 196 197 return (0); 198 } 199 200 static int 201 mfi_disk_detach(device_t dev) 202 { 203 struct mfi_disk *sc; 204 205 sc = device_get_softc(dev); 206 207 lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE); 208 if ((sc->ld_flags & MFI_DISK_FLAGS_OPEN) && 209 (sc->ld_controller->mfi_keep_deleted_volumes || 210 sc->ld_controller->mfi_detaching)) { 211 lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE); 212 return (EBUSY); 213 } 214 lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE); 215 216 disk_destroy(&sc->ld_disk); 217 devstat_remove_entry(&sc->ld_devstat); 218 lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE); 219 TAILQ_REMOVE(&sc->ld_controller->mfi_ld_tqh, sc, ld_link); 220 lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE); 221 kfree(sc->ld_info, M_MFIBUF); 222 return (0); 223 } 224 225 static int 226 mfi_disk_open(struct dev_open_args *ap) 227 { 228 struct mfi_disk *sc = ap->a_head.a_dev->si_drv1; 229 int error; 230 231 lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE); 232 if (sc->ld_flags & MFI_DISK_FLAGS_DISABLED) 233 error = ENXIO; 234 else { 235 sc->ld_flags |= MFI_DISK_FLAGS_OPEN; 236 error = 0; 237 } 238 lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE); 239 240 return (error); 241 } 242 243 static int 244 mfi_disk_close(struct dev_close_args *ap) 245 { 246 struct mfi_disk *sc = ap->a_head.a_dev->si_drv1; 247 248 lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE); 249 sc->ld_flags &= ~MFI_DISK_FLAGS_OPEN; 250 lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE); 251 252 return (0); 253 } 254 255 int 256 mfi_disk_disable(struct mfi_disk *sc) 257 { 258 259 KKASSERT(lockstatus(&sc->ld_controller->mfi_io_lock, curthread) != 0); 260 if (sc->ld_flags & MFI_DISK_FLAGS_OPEN) { 261 if (sc->ld_controller->mfi_delete_busy_volumes) 262 return (0); 263 device_printf(sc->ld_dev, "Unable to delete busy ld device\n"); 264 return (EBUSY); 265 } 266 sc->ld_flags |= MFI_DISK_FLAGS_DISABLED; 267 return (0); 268 } 269 270 void 271 mfi_disk_enable(struct mfi_disk *sc) 272 { 273 274 KKASSERT(lockstatus(&sc->ld_controller->mfi_io_lock, curthread) != 0); 275 sc->ld_flags &= ~MFI_DISK_FLAGS_DISABLED; 276 } 277 278 static int 279 mfi_disk_strategy(struct dev_strategy_args *ap) 280 { 281 struct bio *bio = ap->a_bio; 282 struct buf *bp = bio->bio_buf; 283 struct mfi_disk *sc = ap->a_head.a_dev->si_drv1; 284 struct mfi_softc *controller; 285 286 if (sc == NULL) { 287 bp->b_error = EINVAL; 288 bp->b_flags |= B_ERROR; 289 bp->b_resid = bp->b_bcount; 290 biodone(bio); 291 return (0); 292 } 293 294 /* 295 * XXX swildner 296 * 297 * If it's a null transfer, do nothing. FreeBSD's original driver 298 * doesn't have this, but that caused hard error messages (even 299 * though everything else continued to work fine). Interestingly, 300 * only when HAMMER was used. 301 * 302 * Several others of our RAID drivers have this check, such as 303 * aac(4) and ida(4), so we insert it here, too. 304 * 305 * The cause of null transfers is yet unknown. 306 */ 307 if (bp->b_bcount == 0) { 308 bp->b_resid = bp->b_bcount; 309 biodone(bio); 310 return (0); 311 } 312 313 controller = sc->ld_controller; 314 bio->bio_driver_info = sc; 315 lockmgr(&controller->mfi_io_lock, LK_EXCLUSIVE); 316 mfi_enqueue_bio(controller, bio); 317 devstat_start_transaction(&sc->ld_devstat); 318 mfi_startio(controller); 319 lockmgr(&controller->mfi_io_lock, LK_RELEASE); 320 return (0); 321 } 322 323 void 324 mfi_disk_complete(struct bio *bio) 325 { 326 struct mfi_disk *sc = bio->bio_driver_info; 327 struct buf *bp = bio->bio_buf; 328 329 devstat_end_transaction_buf(&sc->ld_devstat, bp); 330 if (bp->b_flags & B_ERROR) { 331 if (bp->b_error == 0) 332 bp->b_error = EIO; 333 diskerr(bio, sc->ld_disk.d_cdev, "hard error", -1, 1); 334 kprintf("\n"); 335 } else { 336 bp->b_resid = 0; 337 } 338 biodone(bio); 339 } 340 341 static int 342 mfi_disk_dump(struct dev_dump_args *ap) 343 { 344 cdev_t dev = ap->a_head.a_dev; 345 off_t offset = ap->a_offset; 346 void *virt = ap->a_virtual; 347 size_t len = ap->a_length; 348 struct mfi_disk *sc; 349 struct mfi_softc *parent_sc; 350 int error; 351 352 sc = dev->si_drv1; 353 parent_sc = sc->ld_controller; 354 355 if (len > 0) { 356 if ((error = mfi_dump_blocks(parent_sc, sc->ld_id, offset / 357 MFI_SECTOR_LEN, virt, len)) != 0) 358 return (error); 359 } else { 360 /* mfi_sync_cache(parent_sc, sc->ld_id); */ 361 } 362 363 return (0); 364 } 365