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