| File: | dev/softraid.c |
| Warning: | line 1238, column 5 Potential leak of memory pointed to by 'bc' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: softraid.c,v 1.429 2022/12/21 09:54:23 kn Exp $ */ | |||
| 2 | /* | |||
| 3 | * Copyright (c) 2007, 2008, 2009 Marco Peereboom <marco@peereboom.us> | |||
| 4 | * Copyright (c) 2008 Chris Kuethe <ckuethe@openbsd.org> | |||
| 5 | * Copyright (c) 2009 Joel Sing <jsing@openbsd.org> | |||
| 6 | * | |||
| 7 | * Permission to use, copy, modify, and distribute this software for any | |||
| 8 | * purpose with or without fee is hereby granted, provided that the above | |||
| 9 | * copyright notice and this permission notice appear in all copies. | |||
| 10 | * | |||
| 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
| 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
| 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
| 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
| 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
| 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| 18 | */ | |||
| 19 | ||||
| 20 | #include "bio.h" | |||
| 21 | ||||
| 22 | #include <sys/param.h> | |||
| 23 | #include <sys/systm.h> | |||
| 24 | #include <sys/buf.h> | |||
| 25 | #include <sys/device.h> | |||
| 26 | #include <sys/ioctl.h> | |||
| 27 | #include <sys/malloc.h> | |||
| 28 | #include <sys/pool.h> | |||
| 29 | #include <sys/kernel.h> | |||
| 30 | #include <sys/disk.h> | |||
| 31 | #include <sys/rwlock.h> | |||
| 32 | #include <sys/queue.h> | |||
| 33 | #include <sys/fcntl.h> | |||
| 34 | #include <sys/disklabel.h> | |||
| 35 | #include <sys/vnode.h> | |||
| 36 | #include <sys/lock.h> | |||
| 37 | #include <sys/mount.h> | |||
| 38 | #include <sys/sensors.h> | |||
| 39 | #include <sys/stat.h> | |||
| 40 | #include <sys/conf.h> | |||
| 41 | #include <sys/uio.h> | |||
| 42 | #include <sys/task.h> | |||
| 43 | #include <sys/kthread.h> | |||
| 44 | #include <sys/dkio.h> | |||
| 45 | #include <sys/stdint.h> | |||
| 46 | ||||
| 47 | #include <scsi/scsi_all.h> | |||
| 48 | #include <scsi/scsiconf.h> | |||
| 49 | #include <scsi/scsi_disk.h> | |||
| 50 | ||||
| 51 | #include <dev/softraidvar.h> | |||
| 52 | ||||
| 53 | #ifdef HIBERNATE1 | |||
| 54 | #include <lib/libsa/aes_xts.h> | |||
| 55 | #include <sys/hibernate.h> | |||
| 56 | #include <scsi/sdvar.h> | |||
| 57 | #endif /* HIBERNATE */ | |||
| 58 | ||||
| 59 | /* #define SR_FANCY_STATS */ | |||
| 60 | ||||
| 61 | #ifdef SR_DEBUG | |||
| 62 | #define SR_FANCY_STATS | |||
| 63 | uint32_t sr_debug = 0 | |||
| 64 | /* | SR_D_CMD */ | |||
| 65 | /* | SR_D_MISC */ | |||
| 66 | /* | SR_D_INTR */ | |||
| 67 | /* | SR_D_IOCTL */ | |||
| 68 | /* | SR_D_CCB */ | |||
| 69 | /* | SR_D_WU */ | |||
| 70 | /* | SR_D_META */ | |||
| 71 | /* | SR_D_DIS */ | |||
| 72 | /* | SR_D_STATE */ | |||
| 73 | /* | SR_D_REBUILD */ | |||
| 74 | ; | |||
| 75 | #endif | |||
| 76 | ||||
| 77 | struct sr_softc *softraid0; | |||
| 78 | struct sr_uuid sr_bootuuid; | |||
| 79 | u_int8_t sr_bootkey[SR_CRYPTO_MAXKEYBYTES32]; | |||
| 80 | ||||
| 81 | int sr_match(struct device *, void *, void *); | |||
| 82 | void sr_attach(struct device *, struct device *, void *); | |||
| 83 | int sr_detach(struct device *, int); | |||
| 84 | void sr_map_root(void); | |||
| 85 | ||||
| 86 | const struct cfattach softraid_ca = { | |||
| 87 | sizeof(struct sr_softc), sr_match, sr_attach, sr_detach, | |||
| 88 | }; | |||
| 89 | ||||
| 90 | struct cfdriver softraid_cd = { | |||
| 91 | NULL((void *)0), "softraid", DV_DULL | |||
| 92 | }; | |||
| 93 | ||||
| 94 | /* scsi & discipline */ | |||
| 95 | void sr_scsi_cmd(struct scsi_xfer *); | |||
| 96 | int sr_scsi_probe(struct scsi_link *); | |||
| 97 | int sr_scsi_ioctl(struct scsi_link *, u_long, | |||
| 98 | caddr_t, int); | |||
| 99 | int sr_bio_ioctl(struct device *, u_long, caddr_t); | |||
| 100 | int sr_bio_handler(struct sr_softc *, | |||
| 101 | struct sr_discipline *, u_long, struct bio *); | |||
| 102 | int sr_ioctl_inq(struct sr_softc *, struct bioc_inq *); | |||
| 103 | int sr_ioctl_vol(struct sr_softc *, struct bioc_vol *); | |||
| 104 | int sr_ioctl_disk(struct sr_softc *, struct bioc_disk *); | |||
| 105 | int sr_ioctl_setstate(struct sr_softc *, | |||
| 106 | struct bioc_setstate *); | |||
| 107 | int sr_ioctl_createraid(struct sr_softc *, | |||
| 108 | struct bioc_createraid *, int, void *); | |||
| 109 | int sr_ioctl_deleteraid(struct sr_softc *, | |||
| 110 | struct sr_discipline *, struct bioc_deleteraid *); | |||
| 111 | int sr_ioctl_discipline(struct sr_softc *, | |||
| 112 | struct sr_discipline *, struct bioc_discipline *); | |||
| 113 | int sr_ioctl_installboot(struct sr_softc *, | |||
| 114 | struct sr_discipline *, struct bioc_installboot *); | |||
| 115 | void sr_chunks_unwind(struct sr_softc *, | |||
| 116 | struct sr_chunk_head *); | |||
| 117 | void sr_discipline_free(struct sr_discipline *); | |||
| 118 | void sr_discipline_shutdown(struct sr_discipline *, int, int); | |||
| 119 | int sr_discipline_init(struct sr_discipline *, int); | |||
| 120 | int sr_alloc_resources(struct sr_discipline *); | |||
| 121 | void sr_free_resources(struct sr_discipline *); | |||
| 122 | void sr_set_chunk_state(struct sr_discipline *, int, int); | |||
| 123 | void sr_set_vol_state(struct sr_discipline *); | |||
| 124 | ||||
| 125 | /* utility functions */ | |||
| 126 | void sr_shutdown(int); | |||
| 127 | void sr_uuid_generate(struct sr_uuid *); | |||
| 128 | char *sr_uuid_format(struct sr_uuid *); | |||
| 129 | void sr_uuid_print(struct sr_uuid *, int); | |||
| 130 | void sr_checksum_print(u_int8_t *); | |||
| 131 | int sr_boot_assembly(struct sr_softc *); | |||
| 132 | int sr_already_assembled(struct sr_discipline *); | |||
| 133 | int sr_hotspare(struct sr_softc *, dev_t); | |||
| 134 | void sr_hotspare_rebuild(struct sr_discipline *); | |||
| 135 | int sr_rebuild_init(struct sr_discipline *, dev_t, int); | |||
| 136 | void sr_rebuild_start(void *); | |||
| 137 | void sr_rebuild_thread(void *); | |||
| 138 | void sr_rebuild(struct sr_discipline *); | |||
| 139 | void sr_roam_chunks(struct sr_discipline *); | |||
| 140 | int sr_chunk_in_use(struct sr_softc *, dev_t); | |||
| 141 | int sr_rw(struct sr_softc *, dev_t, char *, size_t, | |||
| 142 | daddr_t, long); | |||
| 143 | void sr_wu_done_callback(void *); | |||
| 144 | struct sr_discipline *sr_find_discipline(struct sr_softc *sc, const char *); | |||
| 145 | ||||
| 146 | /* don't include these on RAMDISK */ | |||
| 147 | #ifndef SMALL_KERNEL | |||
| 148 | void sr_sensors_refresh(void *); | |||
| 149 | int sr_sensors_create(struct sr_discipline *); | |||
| 150 | void sr_sensors_delete(struct sr_discipline *); | |||
| 151 | #endif | |||
| 152 | ||||
| 153 | /* metadata */ | |||
| 154 | int sr_meta_probe(struct sr_discipline *, dev_t *, int); | |||
| 155 | int sr_meta_attach(struct sr_discipline *, int, int); | |||
| 156 | int sr_meta_rw(struct sr_discipline *, dev_t, void *, long); | |||
| 157 | int sr_meta_clear(struct sr_discipline *); | |||
| 158 | void sr_meta_init(struct sr_discipline *, int, int); | |||
| 159 | void sr_meta_init_complete(struct sr_discipline *); | |||
| 160 | void sr_meta_opt_handler(struct sr_discipline *, | |||
| 161 | struct sr_meta_opt_hdr *); | |||
| 162 | ||||
| 163 | /* hotplug magic */ | |||
| 164 | void sr_disk_attach(struct disk *, int); | |||
| 165 | ||||
| 166 | struct sr_hotplug_list { | |||
| 167 | void (*sh_hotplug)(struct sr_discipline *, | |||
| 168 | struct disk *, int); | |||
| 169 | struct sr_discipline *sh_sd; | |||
| 170 | ||||
| 171 | SLIST_ENTRY(sr_hotplug_list)struct { struct sr_hotplug_list *sle_next; } shl_link; | |||
| 172 | }; | |||
| 173 | SLIST_HEAD(sr_hotplug_list_head, sr_hotplug_list)struct sr_hotplug_list_head { struct sr_hotplug_list *slh_first ; }; | |||
| 174 | ||||
| 175 | struct sr_hotplug_list_head sr_hotplug_callbacks; | |||
| 176 | extern void (*softraid_disk_attach)(struct disk *, int); | |||
| 177 | ||||
| 178 | /* scsi glue */ | |||
| 179 | const struct scsi_adapter sr_switch = { | |||
| 180 | sr_scsi_cmd, NULL((void *)0), sr_scsi_probe, NULL((void *)0), sr_scsi_ioctl | |||
| 181 | }; | |||
| 182 | ||||
| 183 | /* native metadata format */ | |||
| 184 | int sr_meta_native_bootprobe(struct sr_softc *, dev_t, | |||
| 185 | struct sr_boot_chunk_head *); | |||
| 186 | #define SR_META_NOTCLAIMED(0) (0) | |||
| 187 | #define SR_META_CLAIMED(1) (1) | |||
| 188 | int sr_meta_native_probe(struct sr_softc *, | |||
| 189 | struct sr_chunk *); | |||
| 190 | int sr_meta_native_attach(struct sr_discipline *, int); | |||
| 191 | int sr_meta_native_write(struct sr_discipline *, dev_t, | |||
| 192 | struct sr_metadata *,void *); | |||
| 193 | ||||
| 194 | #ifdef SR_DEBUG | |||
| 195 | void sr_meta_print(struct sr_metadata *); | |||
| 196 | #else | |||
| 197 | #define sr_meta_print(m) | |||
| 198 | #endif | |||
| 199 | ||||
| 200 | /* the metadata driver should remain stateless */ | |||
| 201 | struct sr_meta_driver { | |||
| 202 | daddr_t smd_offset; /* metadata location */ | |||
| 203 | u_int32_t smd_size; /* size of metadata */ | |||
| 204 | ||||
| 205 | int (*smd_probe)(struct sr_softc *, | |||
| 206 | struct sr_chunk *); | |||
| 207 | int (*smd_attach)(struct sr_discipline *, int); | |||
| 208 | int (*smd_detach)(struct sr_discipline *); | |||
| 209 | int (*smd_read)(struct sr_discipline *, dev_t, | |||
| 210 | struct sr_metadata *, void *); | |||
| 211 | int (*smd_write)(struct sr_discipline *, dev_t, | |||
| 212 | struct sr_metadata *, void *); | |||
| 213 | int (*smd_validate)(struct sr_discipline *, | |||
| 214 | struct sr_metadata *, void *); | |||
| 215 | } smd[] = { | |||
| 216 | { SR_META_OFFSET16, SR_META_SIZE64 * DEV_BSIZE(1 << 9), | |||
| 217 | sr_meta_native_probe, sr_meta_native_attach, NULL((void *)0), | |||
| 218 | sr_meta_native_read, sr_meta_native_write, NULL((void *)0) }, | |||
| 219 | { 0, 0, NULL((void *)0), NULL((void *)0), NULL((void *)0), NULL((void *)0) } | |||
| 220 | }; | |||
| 221 | ||||
| 222 | int | |||
| 223 | sr_meta_attach(struct sr_discipline *sd, int chunk_no, int force) | |||
| 224 | { | |||
| 225 | struct sr_softc *sc = sd->sd_sc; | |||
| 226 | struct sr_chunk_head *cl; | |||
| 227 | struct sr_chunk *ch_entry, *chunk1, *chunk2; | |||
| 228 | int rv = 1, i = 0; | |||
| 229 | ||||
| 230 | DNPRINTF(SR_D_META, "%s: sr_meta_attach(%d)\n", DEVNAME(sc), chunk_no); | |||
| 231 | ||||
| 232 | /* in memory copy of metadata */ | |||
| 233 | sd->sd_meta = malloc(SR_META_SIZE64 * DEV_BSIZE(1 << 9), M_DEVBUF2, | |||
| 234 | M_ZERO0x0008 | M_NOWAIT0x0002); | |||
| 235 | if (!sd->sd_meta) { | |||
| 236 | sr_error(sc, "could not allocate memory for metadata"); | |||
| 237 | goto bad; | |||
| 238 | } | |||
| 239 | ||||
| 240 | if (sd->sd_meta_type != SR_META_F_NATIVE0) { | |||
| 241 | /* in memory copy of foreign metadata */ | |||
| 242 | sd->sd_meta_foreign = malloc(smd[sd->sd_meta_type].smd_size, | |||
| 243 | M_DEVBUF2, M_ZERO0x0008 | M_NOWAIT0x0002); | |||
| 244 | if (!sd->sd_meta_foreign) { | |||
| 245 | /* unwind frees sd_meta */ | |||
| 246 | sr_error(sc, "could not allocate memory for foreign " | |||
| 247 | "metadata"); | |||
| 248 | goto bad; | |||
| 249 | } | |||
| 250 | } | |||
| 251 | ||||
| 252 | /* we have a valid list now create an array index */ | |||
| 253 | cl = &sd->sd_vol.sv_chunk_list; | |||
| 254 | sd->sd_vol.sv_chunks = mallocarray(chunk_no, sizeof(struct sr_chunk *), | |||
| 255 | M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 256 | ||||
| 257 | /* fill out chunk array */ | |||
| 258 | i = 0; | |||
| 259 | SLIST_FOREACH(ch_entry, cl, src_link)for((ch_entry) = ((cl)->slh_first); (ch_entry) != ((void * )0); (ch_entry) = ((ch_entry)->src_link.sle_next)) | |||
| 260 | sd->sd_vol.sv_chunks[i++] = ch_entry; | |||
| 261 | ||||
| 262 | /* attach metadata */ | |||
| 263 | if (smd[sd->sd_meta_type].smd_attach(sd, force)) | |||
| 264 | goto bad; | |||
| 265 | ||||
| 266 | /* Force chunks into correct order now that metadata is attached. */ | |||
| 267 | SLIST_INIT(cl){ ((cl)->slh_first) = ((void *)0); }; | |||
| 268 | for (i = 0; i < chunk_no; i++) { | |||
| 269 | ch_entry = sd->sd_vol.sv_chunks[i]; | |||
| 270 | chunk2 = NULL((void *)0); | |||
| 271 | SLIST_FOREACH(chunk1, cl, src_link)for((chunk1) = ((cl)->slh_first); (chunk1) != ((void *)0); (chunk1) = ((chunk1)->src_link.sle_next)) { | |||
| 272 | if (chunk1->src_meta.scmi_scm_invariant.scm_chunk_id > | |||
| 273 | ch_entry->src_meta.scmi_scm_invariant.scm_chunk_id) | |||
| 274 | break; | |||
| 275 | chunk2 = chunk1; | |||
| 276 | } | |||
| 277 | if (chunk2 == NULL((void *)0)) | |||
| 278 | SLIST_INSERT_HEAD(cl, ch_entry, src_link)do { (ch_entry)->src_link.sle_next = (cl)->slh_first; ( cl)->slh_first = (ch_entry); } while (0); | |||
| 279 | else | |||
| 280 | SLIST_INSERT_AFTER(chunk2, ch_entry, src_link)do { (ch_entry)->src_link.sle_next = (chunk2)->src_link .sle_next; (chunk2)->src_link.sle_next = (ch_entry); } while (0); | |||
| 281 | } | |||
| 282 | i = 0; | |||
| 283 | SLIST_FOREACH(ch_entry, cl, src_link)for((ch_entry) = ((cl)->slh_first); (ch_entry) != ((void * )0); (ch_entry) = ((ch_entry)->src_link.sle_next)) | |||
| 284 | sd->sd_vol.sv_chunks[i++] = ch_entry; | |||
| 285 | ||||
| 286 | rv = 0; | |||
| 287 | bad: | |||
| 288 | return (rv); | |||
| 289 | } | |||
| 290 | ||||
| 291 | int | |||
| 292 | sr_meta_probe(struct sr_discipline *sd, dev_t *dt, int no_chunk) | |||
| 293 | { | |||
| 294 | struct sr_softc *sc = sd->sd_sc; | |||
| 295 | struct vnode *vn; | |||
| 296 | struct sr_chunk *ch_entry, *ch_prev = NULL((void *)0); | |||
| 297 | struct sr_chunk_head *cl; | |||
| 298 | char devname[32]; | |||
| 299 | int i, d, type, found, prevf, error; | |||
| 300 | dev_t dev; | |||
| 301 | ||||
| 302 | DNPRINTF(SR_D_META, "%s: sr_meta_probe(%d)\n", DEVNAME(sc), no_chunk); | |||
| 303 | ||||
| 304 | if (no_chunk == 0) | |||
| 305 | goto unwind; | |||
| 306 | ||||
| 307 | cl = &sd->sd_vol.sv_chunk_list; | |||
| 308 | ||||
| 309 | for (d = 0, prevf = SR_META_F_INVALID-1; d < no_chunk; d++) { | |||
| 310 | ch_entry = malloc(sizeof(struct sr_chunk), M_DEVBUF2, | |||
| 311 | M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 312 | /* keep disks in user supplied order */ | |||
| 313 | if (ch_prev) | |||
| 314 | SLIST_INSERT_AFTER(ch_prev, ch_entry, src_link)do { (ch_entry)->src_link.sle_next = (ch_prev)->src_link .sle_next; (ch_prev)->src_link.sle_next = (ch_entry); } while (0); | |||
| 315 | else | |||
| 316 | SLIST_INSERT_HEAD(cl, ch_entry, src_link)do { (ch_entry)->src_link.sle_next = (cl)->slh_first; ( cl)->slh_first = (ch_entry); } while (0); | |||
| 317 | ch_prev = ch_entry; | |||
| 318 | dev = dt[d]; | |||
| 319 | ch_entry->src_dev_mm = dev; | |||
| 320 | ||||
| 321 | if (dev == NODEV(dev_t)(-1)) { | |||
| 322 | ch_entry->src_meta.scm_status = BIOC_SDOFFLINE0x01; | |||
| 323 | continue; | |||
| 324 | } else { | |||
| 325 | sr_meta_getdevname(sc, dev, devname, sizeof(devname)); | |||
| 326 | if (bdevvp(dev, &vn)) { | |||
| 327 | sr_error(sc, "sr_meta_probe: cannot allocate " | |||
| 328 | "vnode"); | |||
| 329 | goto unwind; | |||
| 330 | } | |||
| 331 | ||||
| 332 | /* | |||
| 333 | * XXX leaving dev open for now; move this to attach | |||
| 334 | * and figure out the open/close dance for unwind. | |||
| 335 | */ | |||
| 336 | error = VOP_OPEN(vn, FREAD0x0001 | FWRITE0x0002, NOCRED((struct ucred *)-1), curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc); | |||
| 337 | if (error) { | |||
| 338 | DNPRINTF(SR_D_META,"%s: sr_meta_probe can't " | |||
| 339 | "open %s\n", DEVNAME(sc), devname); | |||
| 340 | vput(vn); | |||
| 341 | goto unwind; | |||
| 342 | } | |||
| 343 | ||||
| 344 | strlcpy(ch_entry->src_devname, devname, | |||
| 345 | sizeof(ch_entry->src_devname)); | |||
| 346 | ch_entry->src_vn = vn; | |||
| 347 | } | |||
| 348 | ||||
| 349 | /* determine if this is a device we understand */ | |||
| 350 | for (i = 0, found = SR_META_F_INVALID-1; smd[i].smd_probe; i++) { | |||
| 351 | type = smd[i].smd_probe(sc, ch_entry); | |||
| 352 | if (type == SR_META_F_INVALID-1) | |||
| 353 | continue; | |||
| 354 | else { | |||
| 355 | found = type; | |||
| 356 | break; | |||
| 357 | } | |||
| 358 | } | |||
| 359 | ||||
| 360 | if (found == SR_META_F_INVALID-1) | |||
| 361 | goto unwind; | |||
| 362 | if (prevf == SR_META_F_INVALID-1) | |||
| 363 | prevf = found; | |||
| 364 | if (prevf != found) { | |||
| 365 | DNPRINTF(SR_D_META, "%s: prevf != found\n", | |||
| 366 | DEVNAME(sc)); | |||
| 367 | goto unwind; | |||
| 368 | } | |||
| 369 | } | |||
| 370 | ||||
| 371 | return (prevf); | |||
| 372 | unwind: | |||
| 373 | return (SR_META_F_INVALID-1); | |||
| 374 | } | |||
| 375 | ||||
| 376 | void | |||
| 377 | sr_meta_getdevname(struct sr_softc *sc, dev_t dev, char *buf, int size) | |||
| 378 | { | |||
| 379 | int maj, unit, part; | |||
| 380 | char *name; | |||
| 381 | ||||
| 382 | DNPRINTF(SR_D_META, "%s: sr_meta_getdevname(%p, %d)\n", | |||
| 383 | DEVNAME(sc), buf, size); | |||
| 384 | ||||
| 385 | if (!buf) | |||
| 386 | return; | |||
| 387 | ||||
| 388 | maj = major(dev)(((unsigned)(dev) >> 8) & 0xff); | |||
| 389 | part = DISKPART(dev)(((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8)) % 16); | |||
| 390 | unit = DISKUNIT(dev)(((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8)) / 16); | |||
| 391 | ||||
| 392 | name = findblkname(maj); | |||
| 393 | if (name == NULL((void *)0)) | |||
| 394 | return; | |||
| 395 | ||||
| 396 | snprintf(buf, size, "%s%d%c", name, unit, part + 'a'); | |||
| 397 | } | |||
| 398 | ||||
| 399 | int | |||
| 400 | sr_rw(struct sr_softc *sc, dev_t dev, char *buf, size_t size, daddr_t blkno, | |||
| 401 | long flags) | |||
| 402 | { | |||
| 403 | struct vnode *vp; | |||
| 404 | struct buf b; | |||
| 405 | size_t bufsize, dma_bufsize; | |||
| 406 | int rv = 1; | |||
| 407 | char *dma_buf; | |||
| 408 | int s; | |||
| 409 | ||||
| 410 | DNPRINTF(SR_D_MISC, "%s: sr_rw(0x%x, %p, %zu, %lld 0x%lx)\n", | |||
| 411 | DEVNAME(sc), dev, buf, size, (long long)blkno, flags); | |||
| 412 | ||||
| 413 | dma_bufsize = (size > MAXPHYS(64 * 1024)) ? MAXPHYS(64 * 1024) : size; | |||
| 414 | dma_buf = dma_alloc(dma_bufsize, PR_WAITOK0x0001); | |||
| 415 | ||||
| 416 | if (bdevvp(dev, &vp)) { | |||
| 417 | printf("%s: sr_rw: failed to allocate vnode\n", DEVNAME(sc)((sc)->sc_dev.dv_xname)); | |||
| 418 | goto done; | |||
| 419 | } | |||
| 420 | ||||
| 421 | while (size > 0) { | |||
| 422 | DNPRINTF(SR_D_MISC, "%s: dma_buf %p, size %zu, blkno %lld)\n", | |||
| 423 | DEVNAME(sc), dma_buf, size, (long long)blkno); | |||
| 424 | ||||
| 425 | bufsize = (size > MAXPHYS(64 * 1024)) ? MAXPHYS(64 * 1024) : size; | |||
| 426 | if (flags == B_WRITE0x00000000) | |||
| 427 | memcpy(dma_buf, buf, bufsize)__builtin_memcpy((dma_buf), (buf), (bufsize)); | |||
| 428 | ||||
| 429 | bzero(&b, sizeof(b))__builtin_bzero((&b), (sizeof(b))); | |||
| 430 | b.b_flags = flags | B_PHYS0x00002000; | |||
| 431 | b.b_proc = curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc; | |||
| 432 | b.b_dev = dev; | |||
| 433 | b.b_iodone = NULL((void *)0); | |||
| 434 | b.b_error = 0; | |||
| 435 | b.b_blkno = blkno; | |||
| 436 | b.b_data = dma_buf; | |||
| 437 | b.b_bcount = bufsize; | |||
| 438 | b.b_bufsize = bufsize; | |||
| 439 | b.b_resid = bufsize; | |||
| 440 | b.b_vp = vp; | |||
| 441 | ||||
| 442 | if ((b.b_flags & B_READ0x00008000) == 0) { | |||
| 443 | s = splbio()splraise(0x3); | |||
| 444 | vp->v_numoutput++; | |||
| 445 | splx(s)spllower(s); | |||
| 446 | } | |||
| 447 | ||||
| 448 | LIST_INIT(&b.b_dep)do { ((&b.b_dep)->lh_first) = ((void *)0); } while (0); | |||
| 449 | VOP_STRATEGY(vp, &b); | |||
| 450 | biowait(&b); | |||
| 451 | ||||
| 452 | if (b.b_flags & B_ERROR0x00000400) { | |||
| 453 | printf("%s: I/O error %d on dev 0x%x at block %llu\n", | |||
| 454 | DEVNAME(sc)((sc)->sc_dev.dv_xname), b.b_error, dev, b.b_blkno); | |||
| 455 | goto done; | |||
| 456 | } | |||
| 457 | ||||
| 458 | if (flags == B_READ0x00008000) | |||
| 459 | memcpy(buf, dma_buf, bufsize)__builtin_memcpy((buf), (dma_buf), (bufsize)); | |||
| 460 | ||||
| 461 | size -= bufsize; | |||
| 462 | buf += bufsize; | |||
| 463 | blkno += howmany(bufsize, DEV_BSIZE)(((bufsize) + (((1 << 9)) - 1)) / ((1 << 9))); | |||
| 464 | } | |||
| 465 | ||||
| 466 | rv = 0; | |||
| 467 | ||||
| 468 | done: | |||
| 469 | if (vp) | |||
| 470 | vput(vp); | |||
| 471 | ||||
| 472 | dma_free(dma_buf, dma_bufsize); | |||
| 473 | ||||
| 474 | return (rv); | |||
| 475 | } | |||
| 476 | ||||
| 477 | int | |||
| 478 | sr_meta_rw(struct sr_discipline *sd, dev_t dev, void *md, long flags) | |||
| 479 | { | |||
| 480 | int rv = 1; | |||
| 481 | ||||
| 482 | DNPRINTF(SR_D_META, "%s: sr_meta_rw(0x%x, %p, 0x%lx)\n", | |||
| 483 | DEVNAME(sd->sd_sc), dev, md, flags); | |||
| 484 | ||||
| 485 | if (md == NULL((void *)0)) { | |||
| 486 | printf("%s: sr_meta_rw: invalid metadata pointer\n", | |||
| 487 | DEVNAME(sd->sd_sc)((sd->sd_sc)->sc_dev.dv_xname)); | |||
| 488 | goto done; | |||
| 489 | } | |||
| 490 | ||||
| 491 | rv = sr_rw(sd->sd_sc, dev, md, SR_META_SIZE64 * DEV_BSIZE(1 << 9), | |||
| 492 | SR_META_OFFSET16, flags); | |||
| 493 | ||||
| 494 | done: | |||
| 495 | return (rv); | |||
| 496 | } | |||
| 497 | ||||
| 498 | int | |||
| 499 | sr_meta_clear(struct sr_discipline *sd) | |||
| 500 | { | |||
| 501 | struct sr_softc *sc = sd->sd_sc; | |||
| 502 | struct sr_chunk_head *cl = &sd->sd_vol.sv_chunk_list; | |||
| 503 | struct sr_chunk *ch_entry; | |||
| 504 | void *m; | |||
| 505 | int rv = 1; | |||
| 506 | ||||
| 507 | DNPRINTF(SR_D_META, "%s: sr_meta_clear\n", DEVNAME(sc)); | |||
| 508 | ||||
| 509 | if (sd->sd_meta_type != SR_META_F_NATIVE0) { | |||
| 510 | sr_error(sc, "cannot clear foreign metadata"); | |||
| 511 | goto done; | |||
| 512 | } | |||
| 513 | ||||
| 514 | m = malloc(SR_META_SIZE64 * DEV_BSIZE(1 << 9), M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 515 | SLIST_FOREACH(ch_entry, cl, src_link)for((ch_entry) = ((cl)->slh_first); (ch_entry) != ((void * )0); (ch_entry) = ((ch_entry)->src_link.sle_next)) { | |||
| 516 | if (sr_meta_native_write(sd, ch_entry->src_dev_mm, m, NULL((void *)0))) { | |||
| 517 | /* XXX mark disk offline */ | |||
| 518 | DNPRINTF(SR_D_META, "%s: sr_meta_clear failed to " | |||
| 519 | "clear %s\n", DEVNAME(sc), ch_entry->src_devname); | |||
| 520 | rv++; | |||
| 521 | continue; | |||
| 522 | } | |||
| 523 | bzero(&ch_entry->src_meta, sizeof(ch_entry->src_meta))__builtin_bzero((&ch_entry->src_meta), (sizeof(ch_entry ->src_meta))); | |||
| 524 | } | |||
| 525 | ||||
| 526 | bzero(sd->sd_meta, SR_META_SIZE * DEV_BSIZE)__builtin_bzero((sd->sd_meta), (64 * (1 << 9))); | |||
| 527 | ||||
| 528 | free(m, M_DEVBUF2, SR_META_SIZE64 * DEV_BSIZE(1 << 9)); | |||
| 529 | rv = 0; | |||
| 530 | done: | |||
| 531 | return (rv); | |||
| 532 | } | |||
| 533 | ||||
| 534 | void | |||
| 535 | sr_meta_init(struct sr_discipline *sd, int level, int no_chunk) | |||
| 536 | { | |||
| 537 | struct sr_softc *sc = sd->sd_sc; | |||
| 538 | struct sr_metadata *sm = sd->sd_meta; | |||
| 539 | struct sr_chunk_head *cl = &sd->sd_vol.sv_chunk_list; | |||
| 540 | struct sr_meta_chunk *scm; | |||
| 541 | struct sr_chunk *chunk; | |||
| 542 | int cid = 0; | |||
| 543 | u_int64_t max_chunk_sz = 0, min_chunk_sz = 0; | |||
| 544 | u_int32_t secsize = DEV_BSIZE(1 << 9); | |||
| 545 | ||||
| 546 | DNPRINTF(SR_D_META, "%s: sr_meta_init\n", DEVNAME(sc)); | |||
| 547 | ||||
| 548 | if (!sm) | |||
| 549 | return; | |||
| 550 | ||||
| 551 | /* Initialise volume metadata. */ | |||
| 552 | sm->ssdi_sdd_invariant.ssd_magic = SR_MAGIC0x4d4152436372616dLLU; | |||
| 553 | sm->ssdi_sdd_invariant.ssd_version = SR_META_VERSION6; | |||
| 554 | sm->ssdi_sdd_invariant.ssd_vol_flags = sd->sd_meta_flags; | |||
| 555 | sm->ssdi_sdd_invariant.ssd_volid = 0; | |||
| 556 | sm->ssdi_sdd_invariant.ssd_chunk_no = no_chunk; | |||
| 557 | sm->ssdi_sdd_invariant.ssd_level = level; | |||
| 558 | ||||
| 559 | sm->ssd_data_blkno = SR_DATA_OFFSET(16 + (64 + (320 + 128))); | |||
| 560 | sm->ssd_ondisk = 0; | |||
| 561 | ||||
| 562 | sr_uuid_generate(&sm->ssdi_sdd_invariant.ssd_uuid); | |||
| 563 | ||||
| 564 | /* Initialise chunk metadata and get min/max chunk sizes & secsize. */ | |||
| 565 | SLIST_FOREACH(chunk, cl, src_link)for((chunk) = ((cl)->slh_first); (chunk) != ((void *)0); ( chunk) = ((chunk)->src_link.sle_next)) { | |||
| 566 | scm = &chunk->src_meta; | |||
| 567 | scm->scmi_scm_invariant.scm_size = chunk->src_size; | |||
| 568 | scm->scmi_scm_invariant.scm_chunk_id = cid++; | |||
| 569 | scm->scm_status = BIOC_SDONLINE0x00; | |||
| 570 | scm->scmi_scm_invariant.scm_volid = 0; | |||
| 571 | strlcpy(scm->scmi_scm_invariant.scm_devname, chunk->src_devname, | |||
| 572 | sizeof(scm->scmi_scm_invariant.scm_devname)); | |||
| 573 | memcpy(&scm->scmi.scm_uuid, &sm->ssdi.ssd_uuid,__builtin_memcpy((&scm->_scm_invariant.scm_uuid), (& sm->_sdd_invariant.ssd_uuid), (sizeof(scm->_scm_invariant .scm_uuid))) | |||
| 574 | sizeof(scm->scmi.scm_uuid))__builtin_memcpy((&scm->_scm_invariant.scm_uuid), (& sm->_sdd_invariant.ssd_uuid), (sizeof(scm->_scm_invariant .scm_uuid))); | |||
| 575 | sr_checksum(sc, scm, &scm->scm_checksum, | |||
| 576 | sizeof(scm->scm_checksum)); | |||
| 577 | ||||
| 578 | if (min_chunk_sz == 0) | |||
| 579 | min_chunk_sz = scm->scmi_scm_invariant.scm_size; | |||
| 580 | if (chunk->src_secsize > secsize) | |||
| 581 | secsize = chunk->src_secsize; | |||
| 582 | min_chunk_sz = MIN(min_chunk_sz, scm->scmi.scm_size)(((min_chunk_sz)<(scm->_scm_invariant.scm_size))?(min_chunk_sz ):(scm->_scm_invariant.scm_size)); | |||
| 583 | max_chunk_sz = MAX(max_chunk_sz, scm->scmi.scm_size)(((max_chunk_sz)>(scm->_scm_invariant.scm_size))?(max_chunk_sz ):(scm->_scm_invariant.scm_size)); | |||
| 584 | } | |||
| 585 | ||||
| 586 | sm->ssdi_sdd_invariant.ssd_secsize = secsize; | |||
| 587 | ||||
| 588 | /* Equalize chunk sizes. */ | |||
| 589 | SLIST_FOREACH(chunk, cl, src_link)for((chunk) = ((cl)->slh_first); (chunk) != ((void *)0); ( chunk) = ((chunk)->src_link.sle_next)) | |||
| 590 | chunk->src_meta.scmi_scm_invariant.scm_coerced_size = min_chunk_sz; | |||
| 591 | ||||
| 592 | sd->sd_vol.sv_chunk_minsz = min_chunk_sz; | |||
| 593 | sd->sd_vol.sv_chunk_maxsz = max_chunk_sz; | |||
| 594 | } | |||
| 595 | ||||
| 596 | void | |||
| 597 | sr_meta_init_complete(struct sr_discipline *sd) | |||
| 598 | { | |||
| 599 | #ifdef SR_DEBUG | |||
| 600 | struct sr_softc *sc = sd->sd_sc; | |||
| 601 | #endif | |||
| 602 | struct sr_metadata *sm = sd->sd_meta; | |||
| 603 | ||||
| 604 | DNPRINTF(SR_D_META, "%s: sr_meta_complete\n", DEVNAME(sc)); | |||
| 605 | ||||
| 606 | /* Complete initialisation of volume metadata. */ | |||
| 607 | strlcpy(sm->ssdi_sdd_invariant.ssd_vendor, "OPENBSD", sizeof(sm->ssdi_sdd_invariant.ssd_vendor)); | |||
| 608 | snprintf(sm->ssdi_sdd_invariant.ssd_product, sizeof(sm->ssdi_sdd_invariant.ssd_product), | |||
| 609 | "SR %s", sd->sd_name); | |||
| 610 | snprintf(sm->ssdi_sdd_invariant.ssd_revision, sizeof(sm->ssdi_sdd_invariant.ssd_revision), | |||
| 611 | "%03d", sm->ssdi_sdd_invariant.ssd_version); | |||
| 612 | } | |||
| 613 | ||||
| 614 | void | |||
| 615 | sr_meta_opt_handler(struct sr_discipline *sd, struct sr_meta_opt_hdr *om) | |||
| 616 | { | |||
| 617 | if (om->som_type != SR_OPT_BOOT0x02) | |||
| 618 | panic("unknown optional metadata type"); | |||
| 619 | } | |||
| 620 | ||||
| 621 | void | |||
| 622 | sr_meta_save_callback(void *xsd) | |||
| 623 | { | |||
| 624 | struct sr_discipline *sd = xsd; | |||
| 625 | int s; | |||
| 626 | ||||
| 627 | s = splbio()splraise(0x3); | |||
| 628 | ||||
| 629 | if (sr_meta_save(sd, SR_META_DIRTY0x1)) | |||
| 630 | printf("%s: save metadata failed\n", DEVNAME(sd->sd_sc)((sd->sd_sc)->sc_dev.dv_xname)); | |||
| 631 | ||||
| 632 | sd->sd_must_flush = 0; | |||
| 633 | splx(s)spllower(s); | |||
| 634 | } | |||
| 635 | ||||
| 636 | int | |||
| 637 | sr_meta_save(struct sr_discipline *sd, u_int32_t flags) | |||
| 638 | { | |||
| 639 | struct sr_softc *sc = sd->sd_sc; | |||
| 640 | struct sr_metadata *sm = sd->sd_meta, *m; | |||
| 641 | struct sr_meta_driver *s; | |||
| 642 | struct sr_chunk *src; | |||
| 643 | struct sr_meta_chunk *cm; | |||
| 644 | struct sr_workunit wu; | |||
| 645 | struct sr_meta_opt_hdr *omh; | |||
| 646 | struct sr_meta_opt_item *omi; | |||
| 647 | int i; | |||
| 648 | ||||
| 649 | DNPRINTF(SR_D_META, "%s: sr_meta_save %s\n", | |||
| 650 | DEVNAME(sc), sd->sd_meta->ssd_devname); | |||
| 651 | ||||
| 652 | if (!sm) { | |||
| 653 | printf("%s: no in memory copy of metadata\n", DEVNAME(sc)((sc)->sc_dev.dv_xname)); | |||
| 654 | goto bad; | |||
| 655 | } | |||
| 656 | ||||
| 657 | /* meta scratchpad */ | |||
| 658 | s = &smd[sd->sd_meta_type]; | |||
| 659 | m = malloc(SR_META_SIZE64 * DEV_BSIZE(1 << 9), M_DEVBUF2, M_ZERO0x0008 | M_NOWAIT0x0002); | |||
| 660 | if (!m) { | |||
| 661 | printf("%s: could not allocate metadata scratch area\n", | |||
| 662 | DEVNAME(sc)((sc)->sc_dev.dv_xname)); | |||
| 663 | goto bad; | |||
| 664 | } | |||
| 665 | ||||
| 666 | /* from here on out metadata is updated */ | |||
| 667 | restart: | |||
| 668 | sm->ssd_ondisk++; | |||
| 669 | sm->ssd_meta_flags = flags; | |||
| 670 | memcpy(m, sm, sizeof(*m))__builtin_memcpy((m), (sm), (sizeof(*m))); | |||
| 671 | ||||
| 672 | /* Chunk metadata. */ | |||
| 673 | cm = (struct sr_meta_chunk *)(m + 1); | |||
| 674 | for (i = 0; i < sm->ssdi_sdd_invariant.ssd_chunk_no; i++) { | |||
| 675 | src = sd->sd_vol.sv_chunks[i]; | |||
| 676 | memcpy(cm, &src->src_meta, sizeof(*cm))__builtin_memcpy((cm), (&src->src_meta), (sizeof(*cm)) ); | |||
| 677 | cm++; | |||
| 678 | } | |||
| 679 | ||||
| 680 | /* Optional metadata. */ | |||
| 681 | omh = (struct sr_meta_opt_hdr *)(cm); | |||
| 682 | SLIST_FOREACH(omi, &sd->sd_meta_opt, omi_link)for((omi) = ((&sd->sd_meta_opt)->slh_first); (omi) != ((void *)0); (omi) = ((omi)->omi_link.sle_next)) { | |||
| 683 | DNPRINTF(SR_D_META, "%s: saving optional metadata type %u with " | |||
| 684 | "length %u\n", DEVNAME(sc), omi->omi_som->som_type, | |||
| 685 | omi->omi_som->som_length); | |||
| 686 | bzero(&omi->omi_som->som_checksum, MD5_DIGEST_LENGTH)__builtin_bzero((&omi->omi_som->som_checksum), (16) ); | |||
| 687 | sr_checksum(sc, omi->omi_som, &omi->omi_som->som_checksum, | |||
| 688 | omi->omi_som->som_length); | |||
| 689 | memcpy(omh, omi->omi_som, omi->omi_som->som_length)__builtin_memcpy((omh), (omi->omi_som), (omi->omi_som-> som_length)); | |||
| 690 | omh = (struct sr_meta_opt_hdr *)((u_int8_t *)omh + | |||
| 691 | omi->omi_som->som_length); | |||
| 692 | } | |||
| 693 | ||||
| 694 | for (i = 0; i < sm->ssdi_sdd_invariant.ssd_chunk_no; i++) { | |||
| 695 | src = sd->sd_vol.sv_chunks[i]; | |||
| 696 | ||||
| 697 | /* skip disks that are offline */ | |||
| 698 | if (src->src_meta.scm_status == BIOC_SDOFFLINE0x01) | |||
| 699 | continue; | |||
| 700 | ||||
| 701 | /* calculate metadata checksum for correct chunk */ | |||
| 702 | m->ssdi_sdd_invariant.ssd_chunk_id = i; | |||
| 703 | sr_checksum(sc, m, &m->ssd_checksum, | |||
| 704 | sizeof(struct sr_meta_invariant)); | |||
| 705 | ||||
| 706 | #ifdef SR_DEBUG | |||
| 707 | DNPRINTF(SR_D_META, "%s: sr_meta_save %s: volid: %d " | |||
| 708 | "chunkid: %d checksum: ", | |||
| 709 | DEVNAME(sc), src->src_meta.scmi.scm_devname, | |||
| 710 | m->ssdi.ssd_volid, m->ssdi.ssd_chunk_id); | |||
| 711 | ||||
| 712 | if (sr_debug & SR_D_META) | |||
| 713 | sr_checksum_print((u_int8_t *)&m->ssd_checksum); | |||
| 714 | DNPRINTF(SR_D_META, "\n"); | |||
| 715 | sr_meta_print(m); | |||
| 716 | #endif | |||
| 717 | ||||
| 718 | /* translate and write to disk */ | |||
| 719 | if (s->smd_write(sd, src->src_dev_mm, m, NULL((void *)0) /* XXX */)) { | |||
| 720 | printf("%s: could not write metadata to %s\n", | |||
| 721 | DEVNAME(sc)((sc)->sc_dev.dv_xname), src->src_devname); | |||
| 722 | /* restart the meta write */ | |||
| 723 | src->src_meta.scm_status = BIOC_SDOFFLINE0x01; | |||
| 724 | /* XXX recalculate volume status */ | |||
| 725 | goto restart; | |||
| 726 | } | |||
| 727 | } | |||
| 728 | ||||
| 729 | /* not all disciplines have sync */ | |||
| 730 | if (sd->sd_scsi_sync) { | |||
| 731 | bzero(&wu, sizeof(wu))__builtin_bzero((&wu), (sizeof(wu))); | |||
| 732 | wu.swu_flags |= SR_WUF_FAKE(1<<6); | |||
| 733 | wu.swu_dis = sd; | |||
| 734 | sd->sd_scsi_sync(&wu); | |||
| 735 | } | |||
| 736 | free(m, M_DEVBUF2, SR_META_SIZE64 * DEV_BSIZE(1 << 9)); | |||
| 737 | return (0); | |||
| 738 | bad: | |||
| 739 | return (1); | |||
| 740 | } | |||
| 741 | ||||
| 742 | int | |||
| 743 | sr_meta_read(struct sr_discipline *sd) | |||
| 744 | { | |||
| 745 | struct sr_softc *sc = sd->sd_sc; | |||
| 746 | struct sr_chunk_head *cl = &sd->sd_vol.sv_chunk_list; | |||
| 747 | struct sr_metadata *sm; | |||
| 748 | struct sr_chunk *ch_entry; | |||
| 749 | struct sr_meta_chunk *cp; | |||
| 750 | struct sr_meta_driver *s; | |||
| 751 | void *fm = NULL((void *)0); | |||
| 752 | int no_disk = 0, got_meta = 0; | |||
| 753 | ||||
| 754 | DNPRINTF(SR_D_META, "%s: sr_meta_read\n", DEVNAME(sc)); | |||
| 755 | ||||
| 756 | sm = malloc(SR_META_SIZE64 * DEV_BSIZE(1 << 9), M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 757 | s = &smd[sd->sd_meta_type]; | |||
| 758 | if (sd->sd_meta_type != SR_META_F_NATIVE0) | |||
| 759 | fm = malloc(s->smd_size, M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 760 | ||||
| 761 | cp = (struct sr_meta_chunk *)(sm + 1); | |||
| 762 | SLIST_FOREACH(ch_entry, cl, src_link)for((ch_entry) = ((cl)->slh_first); (ch_entry) != ((void * )0); (ch_entry) = ((ch_entry)->src_link.sle_next)) { | |||
| 763 | /* skip disks that are offline */ | |||
| 764 | if (ch_entry->src_meta.scm_status == BIOC_SDOFFLINE0x01) { | |||
| 765 | DNPRINTF(SR_D_META, | |||
| 766 | "%s: %s chunk marked offline, spoofing status\n", | |||
| 767 | DEVNAME(sc), ch_entry->src_devname); | |||
| 768 | cp++; /* adjust chunk pointer to match failure */ | |||
| 769 | continue; | |||
| 770 | } else if (s->smd_read(sd, ch_entry->src_dev_mm, sm, fm)) { | |||
| 771 | /* read and translate */ | |||
| 772 | /* XXX mark chunk offline, elsewhere!! */ | |||
| 773 | ch_entry->src_meta.scm_status = BIOC_SDOFFLINE0x01; | |||
| 774 | cp++; /* adjust chunk pointer to match failure */ | |||
| 775 | DNPRINTF(SR_D_META, "%s: sr_meta_read failed\n", | |||
| 776 | DEVNAME(sc)); | |||
| 777 | continue; | |||
| 778 | } | |||
| 779 | ||||
| 780 | if (sm->ssdi_sdd_invariant.ssd_magic != SR_MAGIC0x4d4152436372616dLLU) { | |||
| 781 | DNPRINTF(SR_D_META, "%s: sr_meta_read !SR_MAGIC\n", | |||
| 782 | DEVNAME(sc)); | |||
| 783 | continue; | |||
| 784 | } | |||
| 785 | ||||
| 786 | /* validate metadata */ | |||
| 787 | if (sr_meta_validate(sd, ch_entry->src_dev_mm, sm, fm)) { | |||
| 788 | DNPRINTF(SR_D_META, "%s: invalid metadata\n", | |||
| 789 | DEVNAME(sc)); | |||
| 790 | no_disk = -1; | |||
| 791 | goto done; | |||
| 792 | } | |||
| 793 | ||||
| 794 | /* assume first chunk contains metadata */ | |||
| 795 | if (got_meta == 0) { | |||
| 796 | sr_meta_opt_load(sc, sm, &sd->sd_meta_opt); | |||
| 797 | memcpy(sd->sd_meta, sm, sizeof(*sd->sd_meta))__builtin_memcpy((sd->sd_meta), (sm), (sizeof(*sd->sd_meta ))); | |||
| 798 | got_meta = 1; | |||
| 799 | } | |||
| 800 | ||||
| 801 | memcpy(&ch_entry->src_meta, cp, sizeof(ch_entry->src_meta))__builtin_memcpy((&ch_entry->src_meta), (cp), (sizeof( ch_entry->src_meta))); | |||
| 802 | ||||
| 803 | no_disk++; | |||
| 804 | cp++; | |||
| 805 | } | |||
| 806 | ||||
| 807 | free(sm, M_DEVBUF2, SR_META_SIZE64 * DEV_BSIZE(1 << 9)); | |||
| 808 | free(fm, M_DEVBUF2, s->smd_size); | |||
| 809 | ||||
| 810 | done: | |||
| 811 | DNPRINTF(SR_D_META, "%s: sr_meta_read found %d parts\n", DEVNAME(sc), | |||
| 812 | no_disk); | |||
| 813 | return (no_disk); | |||
| 814 | } | |||
| 815 | ||||
| 816 | void | |||
| 817 | sr_meta_opt_load(struct sr_softc *sc, struct sr_metadata *sm, | |||
| 818 | struct sr_meta_opt_head *som) | |||
| 819 | { | |||
| 820 | struct sr_meta_opt_hdr *omh; | |||
| 821 | struct sr_meta_opt_item *omi; | |||
| 822 | u_int8_t checksum[MD5_DIGEST_LENGTH16]; | |||
| 823 | int i; | |||
| 824 | ||||
| 825 | /* Process optional metadata. */ | |||
| 826 | omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(sm + 1) + | |||
| 827 | sizeof(struct sr_meta_chunk) * sm->ssdi_sdd_invariant.ssd_chunk_no); | |||
| 828 | for (i = 0; i < sm->ssdi_sdd_invariant.ssd_opt_no; i++) { | |||
| 829 | ||||
| 830 | omi = malloc(sizeof(struct sr_meta_opt_item), M_DEVBUF2, | |||
| 831 | M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 832 | SLIST_INSERT_HEAD(som, omi, omi_link)do { (omi)->omi_link.sle_next = (som)->slh_first; (som) ->slh_first = (omi); } while (0); | |||
| 833 | ||||
| 834 | if (omh->som_length == 0) { | |||
| 835 | ||||
| 836 | /* Load old fixed length optional metadata. */ | |||
| 837 | DNPRINTF(SR_D_META, "%s: old optional metadata of type " | |||
| 838 | "%u\n", DEVNAME(sc), omh->som_type); | |||
| 839 | ||||
| 840 | /* Validate checksum. */ | |||
| 841 | sr_checksum(sc, (void *)omh, &checksum, | |||
| 842 | SR_OLD_META_OPT_SIZE2480 - MD5_DIGEST_LENGTH16); | |||
| 843 | if (bcmp(&checksum, (void *)omh + SR_OLD_META_OPT_MD5(2480 - 16), | |||
| 844 | sizeof(checksum))) | |||
| 845 | panic("%s: invalid optional metadata checksum", | |||
| 846 | DEVNAME(sc)((sc)->sc_dev.dv_xname)); | |||
| 847 | ||||
| 848 | /* Determine correct length. */ | |||
| 849 | switch (omh->som_type) { | |||
| 850 | case SR_OPT_CRYPTO0x01: | |||
| 851 | omh->som_length = sizeof(struct sr_meta_crypto); | |||
| 852 | break; | |||
| 853 | case SR_OPT_BOOT0x02: | |||
| 854 | omh->som_length = sizeof(struct sr_meta_boot); | |||
| 855 | break; | |||
| 856 | case SR_OPT_KEYDISK0x03: | |||
| 857 | omh->som_length = | |||
| 858 | sizeof(struct sr_meta_keydisk); | |||
| 859 | break; | |||
| 860 | default: | |||
| 861 | panic("unknown old optional metadata type %u", | |||
| 862 | omh->som_type); | |||
| 863 | } | |||
| 864 | ||||
| 865 | omi->omi_som = malloc(omh->som_length, M_DEVBUF2, | |||
| 866 | M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 867 | memcpy((u_int8_t *)omi->omi_som + sizeof(*omi->omi_som),__builtin_memcpy(((u_int8_t *)omi->omi_som + sizeof(*omi-> omi_som)), ((u_int8_t *)omh + 8), (omh->som_length - sizeof (*omi->omi_som))) | |||
| 868 | (u_int8_t *)omh + SR_OLD_META_OPT_OFFSET,__builtin_memcpy(((u_int8_t *)omi->omi_som + sizeof(*omi-> omi_som)), ((u_int8_t *)omh + 8), (omh->som_length - sizeof (*omi->omi_som))) | |||
| 869 | omh->som_length - sizeof(*omi->omi_som))__builtin_memcpy(((u_int8_t *)omi->omi_som + sizeof(*omi-> omi_som)), ((u_int8_t *)omh + 8), (omh->som_length - sizeof (*omi->omi_som))); | |||
| 870 | omi->omi_som->som_type = omh->som_type; | |||
| 871 | omi->omi_som->som_length = omh->som_length; | |||
| 872 | ||||
| 873 | omh = (struct sr_meta_opt_hdr *)((void *)omh + | |||
| 874 | SR_OLD_META_OPT_SIZE2480); | |||
| 875 | } else { | |||
| 876 | ||||
| 877 | /* Load variable length optional metadata. */ | |||
| 878 | DNPRINTF(SR_D_META, "%s: optional metadata of type %u, " | |||
| 879 | "length %u\n", DEVNAME(sc), omh->som_type, | |||
| 880 | omh->som_length); | |||
| 881 | omi->omi_som = malloc(omh->som_length, M_DEVBUF2, | |||
| 882 | M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 883 | memcpy(omi->omi_som, omh, omh->som_length)__builtin_memcpy((omi->omi_som), (omh), (omh->som_length )); | |||
| 884 | ||||
| 885 | /* Validate checksum. */ | |||
| 886 | memcpy(&checksum, &omi->omi_som->som_checksum,__builtin_memcpy((&checksum), (&omi->omi_som->som_checksum ), (16)) | |||
| 887 | MD5_DIGEST_LENGTH)__builtin_memcpy((&checksum), (&omi->omi_som->som_checksum ), (16)); | |||
| 888 | bzero(&omi->omi_som->som_checksum, MD5_DIGEST_LENGTH)__builtin_bzero((&omi->omi_som->som_checksum), (16) ); | |||
| 889 | sr_checksum(sc, omi->omi_som, | |||
| 890 | &omi->omi_som->som_checksum, omh->som_length); | |||
| 891 | if (bcmp(&checksum, &omi->omi_som->som_checksum, | |||
| 892 | sizeof(checksum))) | |||
| 893 | panic("%s: invalid optional metadata checksum", | |||
| 894 | DEVNAME(sc)((sc)->sc_dev.dv_xname)); | |||
| 895 | ||||
| 896 | omh = (struct sr_meta_opt_hdr *)((void *)omh + | |||
| 897 | omh->som_length); | |||
| 898 | } | |||
| 899 | } | |||
| 900 | } | |||
| 901 | ||||
| 902 | int | |||
| 903 | sr_meta_validate(struct sr_discipline *sd, dev_t dev, struct sr_metadata *sm, | |||
| 904 | void *fm) | |||
| 905 | { | |||
| 906 | struct sr_softc *sc = sd->sd_sc; | |||
| 907 | struct sr_meta_driver *s; | |||
| 908 | #ifdef SR_DEBUG | |||
| 909 | struct sr_meta_chunk *mc; | |||
| 910 | #endif | |||
| 911 | u_int8_t checksum[MD5_DIGEST_LENGTH16]; | |||
| 912 | char devname[32]; | |||
| 913 | int rv = 1; | |||
| 914 | ||||
| 915 | DNPRINTF(SR_D_META, "%s: sr_meta_validate(%p)\n", DEVNAME(sc), sm); | |||
| 916 | ||||
| 917 | sr_meta_getdevname(sc, dev, devname, sizeof(devname)); | |||
| 918 | ||||
| 919 | s = &smd[sd->sd_meta_type]; | |||
| 920 | if (sd->sd_meta_type != SR_META_F_NATIVE0) | |||
| 921 | if (s->smd_validate(sd, sm, fm)) { | |||
| 922 | sr_error(sc, "invalid foreign metadata"); | |||
| 923 | goto done; | |||
| 924 | } | |||
| 925 | ||||
| 926 | /* | |||
| 927 | * at this point all foreign metadata has been translated to the native | |||
| 928 | * format and will be treated just like the native format | |||
| 929 | */ | |||
| 930 | ||||
| 931 | if (sm->ssdi_sdd_invariant.ssd_magic != SR_MAGIC0x4d4152436372616dLLU) { | |||
| 932 | sr_error(sc, "not valid softraid metadata"); | |||
| 933 | goto done; | |||
| 934 | } | |||
| 935 | ||||
| 936 | /* Verify metadata checksum. */ | |||
| 937 | sr_checksum(sc, sm, &checksum, sizeof(struct sr_meta_invariant)); | |||
| 938 | if (bcmp(&checksum, &sm->ssd_checksum, sizeof(checksum))) { | |||
| 939 | sr_error(sc, "invalid metadata checksum"); | |||
| 940 | goto done; | |||
| 941 | } | |||
| 942 | ||||
| 943 | /* Handle changes between versions. */ | |||
| 944 | if (sm->ssdi_sdd_invariant.ssd_version == 3) { | |||
| 945 | ||||
| 946 | /* | |||
| 947 | * Version 3 - update metadata version and fix up data blkno | |||
| 948 | * value since this did not exist in version 3. | |||
| 949 | */ | |||
| 950 | if (sm->ssd_data_blkno == 0) | |||
| 951 | sm->ssd_data_blkno = SR_META_V3_DATA_OFFSET(16 + 64); | |||
| 952 | sm->ssdi_sdd_invariant.ssd_secsize = DEV_BSIZE(1 << 9); | |||
| 953 | ||||
| 954 | } else if (sm->ssdi_sdd_invariant.ssd_version == 4) { | |||
| 955 | ||||
| 956 | /* | |||
| 957 | * Version 4 - original metadata format did not store | |||
| 958 | * data blkno so fix this up if necessary. | |||
| 959 | */ | |||
| 960 | if (sm->ssd_data_blkno == 0) | |||
| 961 | sm->ssd_data_blkno = SR_DATA_OFFSET(16 + (64 + (320 + 128))); | |||
| 962 | sm->ssdi_sdd_invariant.ssd_secsize = DEV_BSIZE(1 << 9); | |||
| 963 | ||||
| 964 | } else if (sm->ssdi_sdd_invariant.ssd_version == 5) { | |||
| 965 | ||||
| 966 | /* | |||
| 967 | * Version 5 - variable length optional metadata. Migration | |||
| 968 | * from earlier fixed length optional metadata is handled | |||
| 969 | * in sr_meta_read(). | |||
| 970 | */ | |||
| 971 | sm->ssdi_sdd_invariant.ssd_secsize = DEV_BSIZE(1 << 9); | |||
| 972 | ||||
| 973 | } else if (sm->ssdi_sdd_invariant.ssd_version == SR_META_VERSION6) { | |||
| 974 | ||||
| 975 | /* | |||
| 976 | * Version 6 - store & report a sector size. | |||
| 977 | */ | |||
| 978 | ||||
| 979 | } else { | |||
| 980 | ||||
| 981 | sr_error(sc, "cannot read metadata version %u on %s, " | |||
| 982 | "expected version %u or earlier", | |||
| 983 | sm->ssdi_sdd_invariant.ssd_version, devname, SR_META_VERSION6); | |||
| 984 | goto done; | |||
| 985 | ||||
| 986 | } | |||
| 987 | ||||
| 988 | /* Update version number and revision string. */ | |||
| 989 | sm->ssdi_sdd_invariant.ssd_version = SR_META_VERSION6; | |||
| 990 | snprintf(sm->ssdi_sdd_invariant.ssd_revision, sizeof(sm->ssdi_sdd_invariant.ssd_revision), | |||
| 991 | "%03d", SR_META_VERSION6); | |||
| 992 | ||||
| 993 | #ifdef SR_DEBUG | |||
| 994 | /* warn if disk changed order */ | |||
| 995 | mc = (struct sr_meta_chunk *)(sm + 1); | |||
| 996 | if (strncmp(mc[sm->ssdi_sdd_invariant.ssd_chunk_id].scmi_scm_invariant.scm_devname, devname, | |||
| 997 | sizeof(mc[sm->ssdi_sdd_invariant.ssd_chunk_id].scmi_scm_invariant.scm_devname))) | |||
| 998 | DNPRINTF(SR_D_META, "%s: roaming device %s -> %s\n", | |||
| 999 | DEVNAME(sc), mc[sm->ssdi.ssd_chunk_id].scmi.scm_devname, | |||
| 1000 | devname); | |||
| 1001 | #endif | |||
| 1002 | ||||
| 1003 | /* we have meta data on disk */ | |||
| 1004 | DNPRINTF(SR_D_META, "%s: sr_meta_validate valid metadata %s\n", | |||
| 1005 | DEVNAME(sc), devname); | |||
| 1006 | ||||
| 1007 | rv = 0; | |||
| 1008 | done: | |||
| 1009 | return (rv); | |||
| 1010 | } | |||
| 1011 | ||||
| 1012 | int | |||
| 1013 | sr_meta_native_bootprobe(struct sr_softc *sc, dev_t devno, | |||
| 1014 | struct sr_boot_chunk_head *bch) | |||
| 1015 | { | |||
| 1016 | struct vnode *vn; | |||
| 1017 | struct disklabel label; | |||
| 1018 | struct sr_metadata *md = NULL((void *)0); | |||
| 1019 | struct sr_discipline *fake_sd = NULL((void *)0); | |||
| 1020 | struct sr_boot_chunk *bc; | |||
| 1021 | char devname[32]; | |||
| 1022 | dev_t chrdev, rawdev; | |||
| 1023 | int error, i; | |||
| 1024 | int rv = SR_META_NOTCLAIMED(0); | |||
| 1025 | ||||
| 1026 | DNPRINTF(SR_D_META, "%s: sr_meta_native_bootprobe\n", DEVNAME(sc)); | |||
| 1027 | ||||
| 1028 | /* | |||
| 1029 | * Use character raw device to avoid SCSI complaints about missing | |||
| 1030 | * media on removable media devices. | |||
| 1031 | */ | |||
| 1032 | chrdev = blktochr(devno); | |||
| 1033 | rawdev = MAKEDISKDEV(major(chrdev), DISKUNIT(devno), RAW_PART)(((dev_t)((((((((unsigned)(chrdev) >> 8) & 0xff))) & 0xff) << 8) | (((((((((unsigned)((devno) & 0xff) | (((devno) & 0xffff0000) >> 8)) / 16))) * 16) + ((2 )))) & 0xff) | ((((((((((unsigned)((devno) & 0xff) | ( ((devno) & 0xffff0000) >> 8)) / 16))) * 16) + ((2)) )) & 0xffff00) << 8)))); | |||
| 1034 | if (cdevvp(rawdev, &vn)) { | |||
| 1035 | sr_error(sc, "sr_meta_native_bootprobe: cannot allocate vnode"); | |||
| 1036 | goto done; | |||
| 1037 | } | |||
| 1038 | ||||
| 1039 | /* open device */ | |||
| 1040 | error = VOP_OPEN(vn, FREAD0x0001, NOCRED((struct ucred *)-1), curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc); | |||
| 1041 | if (error) { | |||
| 1042 | DNPRINTF(SR_D_META, "%s: sr_meta_native_bootprobe open " | |||
| 1043 | "failed\n", DEVNAME(sc)); | |||
| 1044 | vput(vn); | |||
| 1045 | goto done; | |||
| 1046 | } | |||
| 1047 | ||||
| 1048 | /* get disklabel */ | |||
| 1049 | error = VOP_IOCTL(vn, DIOCGDINFO((unsigned long)0x40000000 | ((sizeof(struct disklabel) & 0x1fff) << 16) | ((('d')) << 8) | ((101))), (caddr_t)&label, FREAD0x0001, NOCRED((struct ucred *)-1), | |||
| 1050 | curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc); | |||
| 1051 | if (error) { | |||
| 1052 | DNPRINTF(SR_D_META, "%s: sr_meta_native_bootprobe ioctl " | |||
| 1053 | "failed\n", DEVNAME(sc)); | |||
| 1054 | VOP_CLOSE(vn, FREAD0x0001, NOCRED((struct ucred *)-1), curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc); | |||
| 1055 | vput(vn); | |||
| 1056 | goto done; | |||
| 1057 | } | |||
| 1058 | ||||
| 1059 | /* we are done, close device */ | |||
| 1060 | error = VOP_CLOSE(vn, FREAD0x0001, NOCRED((struct ucred *)-1), curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc); | |||
| 1061 | if (error) { | |||
| 1062 | DNPRINTF(SR_D_META, "%s: sr_meta_native_bootprobe close " | |||
| 1063 | "failed\n", DEVNAME(sc)); | |||
| 1064 | vput(vn); | |||
| 1065 | goto done; | |||
| 1066 | } | |||
| 1067 | vput(vn); | |||
| 1068 | ||||
| 1069 | md = malloc(SR_META_SIZE64 * DEV_BSIZE(1 << 9), M_DEVBUF2, M_ZERO0x0008 | M_NOWAIT0x0002); | |||
| 1070 | if (md == NULL((void *)0)) { | |||
| 1071 | sr_error(sc, "not enough memory for metadata buffer"); | |||
| 1072 | goto done; | |||
| 1073 | } | |||
| 1074 | ||||
| 1075 | /* create fake sd to use utility functions */ | |||
| 1076 | fake_sd = malloc(sizeof(struct sr_discipline), M_DEVBUF2, | |||
| 1077 | M_ZERO0x0008 | M_NOWAIT0x0002); | |||
| 1078 | if (fake_sd == NULL((void *)0)) { | |||
| 1079 | sr_error(sc, "not enough memory for fake discipline"); | |||
| 1080 | goto done; | |||
| 1081 | } | |||
| 1082 | fake_sd->sd_sc = sc; | |||
| 1083 | fake_sd->sd_meta_type = SR_META_F_NATIVE0; | |||
| 1084 | ||||
| 1085 | for (i = 0; i < MAXPARTITIONS16; i++) { | |||
| 1086 | if (label.d_partitions[i].p_fstype != FS_RAID19) | |||
| 1087 | continue; | |||
| 1088 | ||||
| 1089 | /* open partition */ | |||
| 1090 | rawdev = MAKEDISKDEV(major(devno), DISKUNIT(devno), i)(((dev_t)((((((((unsigned)(devno) >> 8) & 0xff))) & 0xff) << 8) | (((((((((unsigned)((devno) & 0xff) | (((devno) & 0xffff0000) >> 8)) / 16))) * 16) + ((i )))) & 0xff) | ((((((((((unsigned)((devno) & 0xff) | ( ((devno) & 0xffff0000) >> 8)) / 16))) * 16) + ((i)) )) & 0xffff00) << 8)))); | |||
| 1091 | if (bdevvp(rawdev, &vn)) { | |||
| 1092 | sr_error(sc, "sr_meta_native_bootprobe: cannot " | |||
| 1093 | "allocate vnode for partition"); | |||
| 1094 | goto done; | |||
| 1095 | } | |||
| 1096 | error = VOP_OPEN(vn, FREAD0x0001, NOCRED((struct ucred *)-1), curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc); | |||
| 1097 | if (error) { | |||
| 1098 | DNPRINTF(SR_D_META, "%s: sr_meta_native_bootprobe " | |||
| 1099 | "open failed, partition %d\n", | |||
| 1100 | DEVNAME(sc), i); | |||
| 1101 | vput(vn); | |||
| 1102 | continue; | |||
| 1103 | } | |||
| 1104 | ||||
| 1105 | if (sr_meta_native_read(fake_sd, rawdev, md, NULL((void *)0))) { | |||
| 1106 | sr_error(sc, "native bootprobe could not read native " | |||
| 1107 | "metadata"); | |||
| 1108 | VOP_CLOSE(vn, FREAD0x0001, NOCRED((struct ucred *)-1), curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc); | |||
| 1109 | vput(vn); | |||
| 1110 | continue; | |||
| 1111 | } | |||
| 1112 | ||||
| 1113 | /* are we a softraid partition? */ | |||
| 1114 | if (md->ssdi_sdd_invariant.ssd_magic != SR_MAGIC0x4d4152436372616dLLU) { | |||
| 1115 | VOP_CLOSE(vn, FREAD0x0001, NOCRED((struct ucred *)-1), curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc); | |||
| 1116 | vput(vn); | |||
| 1117 | continue; | |||
| 1118 | } | |||
| 1119 | ||||
| 1120 | sr_meta_getdevname(sc, rawdev, devname, sizeof(devname)); | |||
| 1121 | if (sr_meta_validate(fake_sd, rawdev, md, NULL((void *)0)) == 0) { | |||
| 1122 | /* XXX fix M_WAITOK, this is boot time */ | |||
| 1123 | bc = malloc(sizeof(struct sr_boot_chunk), | |||
| 1124 | M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 1125 | bc->sbc_metadata = malloc(sizeof(struct sr_metadata), | |||
| 1126 | M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 1127 | memcpy(bc->sbc_metadata, md, sizeof(struct sr_metadata))__builtin_memcpy((bc->sbc_metadata), (md), (sizeof(struct sr_metadata ))); | |||
| 1128 | bc->sbc_mm = rawdev; | |||
| 1129 | SLIST_INSERT_HEAD(bch, bc, sbc_link)do { (bc)->sbc_link.sle_next = (bch)->slh_first; (bch)-> slh_first = (bc); } while (0); | |||
| 1130 | rv = SR_META_CLAIMED(1); | |||
| 1131 | } | |||
| 1132 | ||||
| 1133 | /* we are done, close partition */ | |||
| 1134 | VOP_CLOSE(vn, FREAD0x0001, NOCRED((struct ucred *)-1), curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc); | |||
| 1135 | vput(vn); | |||
| 1136 | } | |||
| 1137 | ||||
| 1138 | done: | |||
| 1139 | free(fake_sd, M_DEVBUF2, sizeof(struct sr_discipline)); | |||
| 1140 | free(md, M_DEVBUF2, SR_META_SIZE64 * DEV_BSIZE(1 << 9)); | |||
| 1141 | ||||
| 1142 | return (rv); | |||
| 1143 | } | |||
| 1144 | ||||
| 1145 | int | |||
| 1146 | sr_boot_assembly(struct sr_softc *sc) | |||
| 1147 | { | |||
| 1148 | struct sr_boot_volume_head bvh; | |||
| 1149 | struct sr_boot_chunk_head bch, kdh; | |||
| 1150 | struct sr_boot_volume *bv, *bv1, *bv2; | |||
| 1151 | struct sr_boot_chunk *bc, *bcnext, *bc1, *bc2; | |||
| 1152 | struct sr_disk_head sdklist; | |||
| 1153 | struct sr_disk *sdk; | |||
| 1154 | struct disk *dk; | |||
| 1155 | struct bioc_createraid bcr; | |||
| 1156 | struct sr_meta_chunk *hm; | |||
| 1157 | struct sr_chunk_head *cl; | |||
| 1158 | struct sr_chunk *hotspare, *chunk, *last; | |||
| 1159 | u_int64_t *ondisk = NULL((void *)0); | |||
| 1160 | dev_t *devs = NULL((void *)0); | |||
| 1161 | void *data; | |||
| 1162 | char devname[32]; | |||
| 1163 | int rv = 0, i; | |||
| 1164 | ||||
| 1165 | DNPRINTF(SR_D_META, "%s: sr_boot_assembly\n", DEVNAME(sc)); | |||
| 1166 | ||||
| 1167 | SLIST_INIT(&sdklist){ ((&sdklist)->slh_first) = ((void *)0); }; | |||
| 1168 | SLIST_INIT(&bvh){ ((&bvh)->slh_first) = ((void *)0); }; | |||
| 1169 | SLIST_INIT(&bch){ ((&bch)->slh_first) = ((void *)0); }; | |||
| 1170 | SLIST_INIT(&kdh){ ((&kdh)->slh_first) = ((void *)0); }; | |||
| 1171 | ||||
| 1172 | dk = TAILQ_FIRST(&disklist)((&disklist)->tqh_first); | |||
| 1173 | while (dk != NULL((void *)0)) { | |||
| ||||
| 1174 | ||||
| 1175 | /* See if this disk has been checked. */ | |||
| 1176 | SLIST_FOREACH(sdk, &sdklist, sdk_link)for((sdk) = ((&sdklist)->slh_first); (sdk) != ((void * )0); (sdk) = ((sdk)->sdk_link.sle_next)) | |||
| 1177 | if (sdk->sdk_devno == dk->dk_devno) | |||
| 1178 | break; | |||
| 1179 | ||||
| 1180 | if (sdk
| |||
| 1181 | dk = TAILQ_NEXT(dk, dk_link)((dk)->dk_link.tqe_next); | |||
| 1182 | continue; | |||
| 1183 | } | |||
| 1184 | ||||
| 1185 | /* Add this disk to the list that we've checked. */ | |||
| 1186 | sdk = malloc(sizeof(struct sr_disk), M_DEVBUF2, | |||
| 1187 | M_NOWAIT0x0002 | M_ZERO0x0008); | |||
| 1188 | if (sdk == NULL((void *)0)) | |||
| 1189 | goto unwind; | |||
| 1190 | sdk->sdk_devno = dk->dk_devno; | |||
| 1191 | SLIST_INSERT_HEAD(&sdklist, sdk, sdk_link)do { (sdk)->sdk_link.sle_next = (&sdklist)->slh_first ; (&sdklist)->slh_first = (sdk); } while (0); | |||
| 1192 | ||||
| 1193 | /* Only check sd(4) and wd(4) devices. */ | |||
| 1194 | if (strncmp(dk->dk_name, "sd", 2) && | |||
| 1195 | strncmp(dk->dk_name, "wd", 2)) { | |||
| 1196 | dk = TAILQ_NEXT(dk, dk_link)((dk)->dk_link.tqe_next); | |||
| 1197 | continue; | |||
| 1198 | } | |||
| 1199 | ||||
| 1200 | /* native softraid uses partitions */ | |||
| 1201 | rw_enter_write(&sc->sc_lock); | |||
| 1202 | bio_status_init(&sc->sc_status, &sc->sc_dev); | |||
| 1203 | sr_meta_native_bootprobe(sc, dk->dk_devno, &bch); | |||
| 1204 | rw_exit_write(&sc->sc_lock); | |||
| 1205 | ||||
| 1206 | /* probe non-native disks if native failed. */ | |||
| 1207 | ||||
| 1208 | /* Restart scan since we may have slept. */ | |||
| 1209 | dk = TAILQ_FIRST(&disklist)((&disklist)->tqh_first); | |||
| 1210 | } | |||
| 1211 | ||||
| 1212 | /* | |||
| 1213 | * Create a list of volumes and associate chunks with each volume. | |||
| 1214 | */ | |||
| 1215 | for (bc = SLIST_FIRST(&bch)((&bch)->slh_first); bc
| |||
| 1216 | ||||
| 1217 | bcnext = SLIST_NEXT(bc, sbc_link)((bc)->sbc_link.sle_next); | |||
| 1218 | SLIST_REMOVE(&bch, bc, sr_boot_chunk, sbc_link)do { if ((&bch)->slh_first == (bc)) { do { ((&bch) )->slh_first = ((&bch))->slh_first->sbc_link.sle_next ; } while (0); } else { struct sr_boot_chunk *curelm = (& bch)->slh_first; while (curelm->sbc_link.sle_next != (bc )) curelm = curelm->sbc_link.sle_next; curelm->sbc_link .sle_next = curelm->sbc_link.sle_next->sbc_link.sle_next ; } ((bc)->sbc_link.sle_next) = ((void *)-1); } while (0); | |||
| 1219 | bc->sbc_chunk_id = bc->sbc_metadata->ssdi_sdd_invariant.ssd_chunk_id; | |||
| 1220 | ||||
| 1221 | /* Handle key disks separately. */ | |||
| 1222 | if (bc->sbc_metadata->ssdi_sdd_invariant.ssd_level == SR_KEYDISK_LEVEL0xfffffffe) { | |||
| 1223 | SLIST_INSERT_HEAD(&kdh, bc, sbc_link)do { (bc)->sbc_link.sle_next = (&kdh)->slh_first; ( &kdh)->slh_first = (bc); } while (0); | |||
| 1224 | continue; | |||
| 1225 | } | |||
| 1226 | ||||
| 1227 | SLIST_FOREACH(bv, &bvh, sbv_link)for((bv) = ((&bvh)->slh_first); (bv) != ((void *)0); ( bv) = ((bv)->sbv_link.sle_next)) { | |||
| 1228 | if (bcmp(&bc->sbc_metadata->ssdi_sdd_invariant.ssd_uuid, | |||
| 1229 | &bv->sbv_uuid, | |||
| 1230 | sizeof(bc->sbc_metadata->ssdi_sdd_invariant.ssd_uuid)) == 0) | |||
| 1231 | break; | |||
| 1232 | } | |||
| 1233 | ||||
| 1234 | if (bv
| |||
| 1235 | bv = malloc(sizeof(struct sr_boot_volume), | |||
| 1236 | M_DEVBUF2, M_NOWAIT0x0002 | M_ZERO0x0008); | |||
| 1237 | if (bv == NULL((void *)0)) { | |||
| 1238 | printf("%s: failed to allocate boot volume\n", | |||
| ||||
| 1239 | DEVNAME(sc)((sc)->sc_dev.dv_xname)); | |||
| 1240 | goto unwind; | |||
| 1241 | } | |||
| 1242 | ||||
| 1243 | bv->sbv_level = bc->sbc_metadata->ssdi_sdd_invariant.ssd_level; | |||
| 1244 | bv->sbv_volid = bc->sbc_metadata->ssdi_sdd_invariant.ssd_volid; | |||
| 1245 | bv->sbv_chunk_no = bc->sbc_metadata->ssdi_sdd_invariant.ssd_chunk_no; | |||
| 1246 | bv->sbv_flags = bc->sbc_metadata->ssdi_sdd_invariant.ssd_vol_flags; | |||
| 1247 | memcpy(&bv->sbv_uuid, &bc->sbc_metadata->ssdi.ssd_uuid,__builtin_memcpy((&bv->sbv_uuid), (&bc->sbc_metadata ->_sdd_invariant.ssd_uuid), (sizeof(bc->sbc_metadata-> _sdd_invariant.ssd_uuid))) | |||
| 1248 | sizeof(bc->sbc_metadata->ssdi.ssd_uuid))__builtin_memcpy((&bv->sbv_uuid), (&bc->sbc_metadata ->_sdd_invariant.ssd_uuid), (sizeof(bc->sbc_metadata-> _sdd_invariant.ssd_uuid))); | |||
| 1249 | SLIST_INIT(&bv->sbv_chunks){ ((&bv->sbv_chunks)->slh_first) = ((void *)0); }; | |||
| 1250 | ||||
| 1251 | /* Maintain volume order. */ | |||
| 1252 | bv2 = NULL((void *)0); | |||
| 1253 | SLIST_FOREACH(bv1, &bvh, sbv_link)for((bv1) = ((&bvh)->slh_first); (bv1) != ((void *)0); (bv1) = ((bv1)->sbv_link.sle_next)) { | |||
| 1254 | if (bv1->sbv_volid > bv->sbv_volid) | |||
| 1255 | break; | |||
| 1256 | bv2 = bv1; | |||
| 1257 | } | |||
| 1258 | if (bv2 == NULL((void *)0)) { | |||
| 1259 | DNPRINTF(SR_D_META, "%s: insert volume %u " | |||
| 1260 | "at head\n", DEVNAME(sc), bv->sbv_volid); | |||
| 1261 | SLIST_INSERT_HEAD(&bvh, bv, sbv_link)do { (bv)->sbv_link.sle_next = (&bvh)->slh_first; ( &bvh)->slh_first = (bv); } while (0); | |||
| 1262 | } else { | |||
| 1263 | DNPRINTF(SR_D_META, "%s: insert volume %u " | |||
| 1264 | "after %u\n", DEVNAME(sc), bv->sbv_volid, | |||
| 1265 | bv2->sbv_volid); | |||
| 1266 | SLIST_INSERT_AFTER(bv2, bv, sbv_link)do { (bv)->sbv_link.sle_next = (bv2)->sbv_link.sle_next ; (bv2)->sbv_link.sle_next = (bv); } while (0); | |||
| 1267 | } | |||
| 1268 | } | |||
| 1269 | ||||
| 1270 | /* Maintain chunk order. */ | |||
| 1271 | bc2 = NULL((void *)0); | |||
| 1272 | SLIST_FOREACH(bc1, &bv->sbv_chunks, sbc_link)for((bc1) = ((&bv->sbv_chunks)->slh_first); (bc1) != ((void *)0); (bc1) = ((bc1)->sbc_link.sle_next)) { | |||
| 1273 | if (bc1->sbc_chunk_id > bc->sbc_chunk_id) | |||
| 1274 | break; | |||
| 1275 | bc2 = bc1; | |||
| 1276 | } | |||
| 1277 | if (bc2 == NULL((void *)0)) { | |||
| 1278 | DNPRINTF(SR_D_META, "%s: volume %u insert chunk %u " | |||
| 1279 | "at head\n", DEVNAME(sc), bv->sbv_volid, | |||
| 1280 | bc->sbc_chunk_id); | |||
| 1281 | SLIST_INSERT_HEAD(&bv->sbv_chunks, bc, sbc_link)do { (bc)->sbc_link.sle_next = (&bv->sbv_chunks)-> slh_first; (&bv->sbv_chunks)->slh_first = (bc); } while (0); | |||
| 1282 | } else { | |||
| 1283 | DNPRINTF(SR_D_META, "%s: volume %u insert chunk %u " | |||
| 1284 | "after %u\n", DEVNAME(sc), bv->sbv_volid, | |||
| 1285 | bc->sbc_chunk_id, bc2->sbc_chunk_id); | |||
| 1286 | SLIST_INSERT_AFTER(bc2, bc, sbc_link)do { (bc)->sbc_link.sle_next = (bc2)->sbc_link.sle_next ; (bc2)->sbc_link.sle_next = (bc); } while (0); | |||
| 1287 | } | |||
| 1288 | ||||
| 1289 | bv->sbv_chunks_found++; | |||
| 1290 | } | |||
| 1291 | ||||
| 1292 | /* Allocate memory for device and ondisk version arrays. */ | |||
| 1293 | devs = mallocarray(BIOC_CRMAXLEN1024, sizeof(dev_t), M_DEVBUF2, | |||
| 1294 | M_NOWAIT0x0002); | |||
| 1295 | if (devs == NULL((void *)0)) { | |||
| 1296 | printf("%s: failed to allocate device array\n", DEVNAME(sc)((sc)->sc_dev.dv_xname)); | |||
| 1297 | goto unwind; | |||
| 1298 | } | |||
| 1299 | ondisk = mallocarray(BIOC_CRMAXLEN1024, sizeof(u_int64_t), M_DEVBUF2, | |||
| 1300 | M_NOWAIT0x0002); | |||
| 1301 | if (ondisk == NULL((void *)0)) { | |||
| 1302 | printf("%s: failed to allocate ondisk array\n", DEVNAME(sc)((sc)->sc_dev.dv_xname)); | |||
| 1303 | goto unwind; | |||
| 1304 | } | |||
| 1305 | ||||
| 1306 | /* | |||
| 1307 | * Assemble hotspare "volumes". | |||
| 1308 | */ | |||
| 1309 | SLIST_FOREACH(bv, &bvh, sbv_link)for((bv) = ((&bvh)->slh_first); (bv) != ((void *)0); ( bv) = ((bv)->sbv_link.sle_next)) { | |||
| 1310 | ||||
| 1311 | /* Check if this is a hotspare "volume". */ | |||
| 1312 | if (bv->sbv_level != SR_HOTSPARE_LEVEL0xffffffff || | |||
| 1313 | bv->sbv_chunk_no != 1) | |||
| 1314 | continue; | |||
| 1315 | ||||
| 1316 | #ifdef SR_DEBUG | |||
| 1317 | DNPRINTF(SR_D_META, "%s: assembling hotspare volume ", | |||
| 1318 | DEVNAME(sc)); | |||
| 1319 | if (sr_debug & SR_D_META) | |||
| 1320 | sr_uuid_print(&bv->sbv_uuid, 0); | |||
| 1321 | DNPRINTF(SR_D_META, " volid %u with %u chunks\n", | |||
| 1322 | bv->sbv_volid, bv->sbv_chunk_no); | |||
| 1323 | #endif | |||
| 1324 | ||||
| 1325 | /* Create hotspare chunk metadata. */ | |||
| 1326 | hotspare = malloc(sizeof(struct sr_chunk), M_DEVBUF2, | |||
| 1327 | M_NOWAIT0x0002 | M_ZERO0x0008); | |||
| 1328 | if (hotspare == NULL((void *)0)) { | |||
| 1329 | printf("%s: failed to allocate hotspare\n", | |||
| 1330 | DEVNAME(sc)((sc)->sc_dev.dv_xname)); | |||
| 1331 | goto unwind; | |||
| 1332 | } | |||
| 1333 | ||||
| 1334 | bc = SLIST_FIRST(&bv->sbv_chunks)((&bv->sbv_chunks)->slh_first); | |||
| 1335 | sr_meta_getdevname(sc, bc->sbc_mm, devname, sizeof(devname)); | |||
| 1336 | hotspare->src_dev_mm = bc->sbc_mm; | |||
| 1337 | strlcpy(hotspare->src_devname, devname, | |||
| 1338 | sizeof(hotspare->src_devname)); | |||
| 1339 | hotspare->src_size = bc->sbc_metadata->ssdi_sdd_invariant.ssd_size; | |||
| 1340 | ||||
| 1341 | hm = &hotspare->src_meta; | |||
| 1342 | hm->scmi_scm_invariant.scm_volid = SR_HOTSPARE_VOLID0xffffffff; | |||
| 1343 | hm->scmi_scm_invariant.scm_chunk_id = 0; | |||
| 1344 | hm->scmi_scm_invariant.scm_size = bc->sbc_metadata->ssdi_sdd_invariant.ssd_size; | |||
| 1345 | hm->scmi_scm_invariant.scm_coerced_size = bc->sbc_metadata->ssdi_sdd_invariant.ssd_size; | |||
| 1346 | strlcpy(hm->scmi_scm_invariant.scm_devname, devname, | |||
| 1347 | sizeof(hm->scmi_scm_invariant.scm_devname)); | |||
| 1348 | memcpy(&hm->scmi.scm_uuid, &bc->sbc_metadata->ssdi.ssd_uuid,__builtin_memcpy((&hm->_scm_invariant.scm_uuid), (& bc->sbc_metadata->_sdd_invariant.ssd_uuid), (sizeof(struct sr_uuid))) | |||
| 1349 | sizeof(struct sr_uuid))__builtin_memcpy((&hm->_scm_invariant.scm_uuid), (& bc->sbc_metadata->_sdd_invariant.ssd_uuid), (sizeof(struct sr_uuid))); | |||
| 1350 | ||||
| 1351 | sr_checksum(sc, hm, &hm->scm_checksum, | |||
| 1352 | sizeof(struct sr_meta_chunk_invariant)); | |||
| 1353 | ||||
| 1354 | hm->scm_status = BIOC_SDHOTSPARE0x04; | |||
| 1355 | ||||
| 1356 | /* Add chunk to hotspare list. */ | |||
| 1357 | rw_enter_write(&sc->sc_hs_lock); | |||
| 1358 | cl = &sc->sc_hotspare_list; | |||
| 1359 | if (SLIST_EMPTY(cl)(((cl)->slh_first) == ((void *)0))) | |||
| 1360 | SLIST_INSERT_HEAD(cl, hotspare, src_link)do { (hotspare)->src_link.sle_next = (cl)->slh_first; ( cl)->slh_first = (hotspare); } while (0); | |||
| 1361 | else { | |||
| 1362 | SLIST_FOREACH(chunk, cl, src_link)for((chunk) = ((cl)->slh_first); (chunk) != ((void *)0); ( chunk) = ((chunk)->src_link.sle_next)) | |||
| 1363 | last = chunk; | |||
| 1364 | SLIST_INSERT_AFTER(last, hotspare, src_link)do { (hotspare)->src_link.sle_next = (last)->src_link.sle_next ; (last)->src_link.sle_next = (hotspare); } while (0); | |||
| 1365 | } | |||
| 1366 | sc->sc_hotspare_no++; | |||
| 1367 | rw_exit_write(&sc->sc_hs_lock); | |||
| 1368 | ||||
| 1369 | } | |||
| 1370 | ||||
| 1371 | /* | |||
| 1372 | * Assemble RAID volumes. | |||
| 1373 | */ | |||
| 1374 | SLIST_FOREACH(bv, &bvh, sbv_link)for((bv) = ((&bvh)->slh_first); (bv) != ((void *)0); ( bv) = ((bv)->sbv_link.sle_next)) { | |||
| 1375 | ||||
| 1376 | bzero(&bcr, sizeof(bcr))__builtin_bzero((&bcr), (sizeof(bcr))); | |||
| 1377 | data = NULL((void *)0); | |||
| 1378 | ||||
| 1379 | /* Check if this is a hotspare "volume". */ | |||
| 1380 | if (bv->sbv_level == SR_HOTSPARE_LEVEL0xffffffff && | |||
| 1381 | bv->sbv_chunk_no == 1) | |||
| 1382 | continue; | |||
| 1383 | ||||
| 1384 | /* | |||
| 1385 | * Skip volumes that are marked as no auto assemble, unless | |||
| 1386 | * this was the volume which we actually booted from. | |||
| 1387 | */ | |||
| 1388 | if (bcmp(&sr_bootuuid, &bv->sbv_uuid, sizeof(sr_bootuuid)) != 0) | |||
| 1389 | if (bv->sbv_flags & BIOC_SCNOAUTOASSEMBLE0x04) | |||
| 1390 | continue; | |||
| 1391 | ||||
| 1392 | #ifdef SR_DEBUG | |||
| 1393 | DNPRINTF(SR_D_META, "%s: assembling volume ", DEVNAME(sc)); | |||
| 1394 | if (sr_debug & SR_D_META) | |||
| 1395 | sr_uuid_print(&bv->sbv_uuid, 0); | |||
| 1396 | DNPRINTF(SR_D_META, " volid %u with %u chunks\n", | |||
| 1397 | bv->sbv_volid, bv->sbv_chunk_no); | |||
| 1398 | #endif | |||
| 1399 | ||||
| 1400 | /* | |||
| 1401 | * If this is a crypto volume, try to find a matching | |||
| 1402 | * key disk... | |||
| 1403 | */ | |||
| 1404 | bcr.bc_key_disk = NODEV(dev_t)(-1); | |||
| 1405 | if (bv->sbv_level == 'C' || bv->sbv_level == 0x1C) { | |||
| 1406 | SLIST_FOREACH(bc, &kdh, sbc_link)for((bc) = ((&kdh)->slh_first); (bc) != ((void *)0); ( bc) = ((bc)->sbc_link.sle_next)) { | |||
| 1407 | if (bcmp(&bc->sbc_metadata->ssdi_sdd_invariant.ssd_uuid, | |||
| 1408 | &bv->sbv_uuid, | |||
| 1409 | sizeof(bc->sbc_metadata->ssdi_sdd_invariant.ssd_uuid)) | |||
| 1410 | == 0) | |||
| 1411 | bcr.bc_key_disk = bc->sbc_mm; | |||
| 1412 | } | |||
| 1413 | } | |||
| 1414 | ||||
| 1415 | for (i = 0; i < BIOC_CRMAXLEN1024; i++) { | |||
| 1416 | devs[i] = NODEV(dev_t)(-1); /* mark device as illegal */ | |||
| 1417 | ondisk[i] = 0; | |||
| 1418 | } | |||
| 1419 | ||||
| 1420 | SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link)for((bc) = ((&bv->sbv_chunks)->slh_first); (bc) != ( (void *)0); (bc) = ((bc)->sbc_link.sle_next)) { | |||
| 1421 | if (devs[bc->sbc_chunk_id] != NODEV(dev_t)(-1)) { | |||
| 1422 | bv->sbv_chunks_found--; | |||
| 1423 | sr_meta_getdevname(sc, bc->sbc_mm, devname, | |||
| 1424 | sizeof(devname)); | |||
| 1425 | printf("%s: found duplicate chunk %u for " | |||
| 1426 | "volume %u on device %s\n", DEVNAME(sc)((sc)->sc_dev.dv_xname), | |||
| 1427 | bc->sbc_chunk_id, bv->sbv_volid, devname); | |||
| 1428 | } | |||
| 1429 | ||||
| 1430 | if (devs[bc->sbc_chunk_id] == NODEV(dev_t)(-1) || | |||
| 1431 | bc->sbc_metadata->ssd_ondisk > | |||
| 1432 | ondisk[bc->sbc_chunk_id]) { | |||
| 1433 | devs[bc->sbc_chunk_id] = bc->sbc_mm; | |||
| 1434 | ondisk[bc->sbc_chunk_id] = | |||
| 1435 | bc->sbc_metadata->ssd_ondisk; | |||
| 1436 | DNPRINTF(SR_D_META, "%s: using ondisk " | |||
| 1437 | "metadata version %llu for chunk %u\n", | |||
| 1438 | DEVNAME(sc), ondisk[bc->sbc_chunk_id], | |||
| 1439 | bc->sbc_chunk_id); | |||
| 1440 | } | |||
| 1441 | } | |||
| 1442 | ||||
| 1443 | if (bv->sbv_chunk_no != bv->sbv_chunks_found) { | |||
| 1444 | printf("%s: not all chunks were provided; " | |||
| 1445 | "attempting to bring volume %d online\n", | |||
| 1446 | DEVNAME(sc)((sc)->sc_dev.dv_xname), bv->sbv_volid); | |||
| 1447 | } | |||
| 1448 | ||||
| 1449 | bcr.bc_level = bv->sbv_level; | |||
| 1450 | bcr.bc_dev_list_len = bv->sbv_chunk_no * sizeof(dev_t); | |||
| 1451 | bcr.bc_dev_list = devs; | |||
| 1452 | bcr.bc_flags = BIOC_SCDEVT0x02 | | |||
| 1453 | (bv->sbv_flags & BIOC_SCNOAUTOASSEMBLE0x04); | |||
| 1454 | ||||
| 1455 | if ((bv->sbv_level == 'C' || bv->sbv_level == 0x1C) && | |||
| 1456 | bcmp(&sr_bootuuid, &bv->sbv_uuid, sizeof(sr_bootuuid)) == 0) | |||
| 1457 | data = sr_bootkey; | |||
| 1458 | ||||
| 1459 | rw_enter_write(&sc->sc_lock); | |||
| 1460 | bio_status_init(&sc->sc_status, &sc->sc_dev); | |||
| 1461 | sr_ioctl_createraid(sc, &bcr, 0, data); | |||
| 1462 | rw_exit_write(&sc->sc_lock); | |||
| 1463 | ||||
| 1464 | rv++; | |||
| 1465 | } | |||
| 1466 | ||||
| 1467 | /* done with metadata */ | |||
| 1468 | unwind: | |||
| 1469 | /* Free boot volumes and associated chunks. */ | |||
| 1470 | for (bv1 = SLIST_FIRST(&bvh)((&bvh)->slh_first); bv1 != NULL((void *)0); bv1 = bv2) { | |||
| 1471 | bv2 = SLIST_NEXT(bv1, sbv_link)((bv1)->sbv_link.sle_next); | |||
| 1472 | for (bc1 = SLIST_FIRST(&bv1->sbv_chunks)((&bv1->sbv_chunks)->slh_first); bc1 != NULL((void *)0); | |||
| 1473 | bc1 = bc2) { | |||
| 1474 | bc2 = SLIST_NEXT(bc1, sbc_link)((bc1)->sbc_link.sle_next); | |||
| 1475 | free(bc1->sbc_metadata, M_DEVBUF2, | |||
| 1476 | sizeof(*bc1->sbc_metadata)); | |||
| 1477 | free(bc1, M_DEVBUF2, sizeof(*bc1)); | |||
| 1478 | } | |||
| 1479 | free(bv1, M_DEVBUF2, sizeof(*bv1)); | |||
| 1480 | } | |||
| 1481 | /* Free keydisks chunks. */ | |||
| 1482 | for (bc1 = SLIST_FIRST(&kdh)((&kdh)->slh_first); bc1 != NULL((void *)0); bc1 = bc2) { | |||
| 1483 | bc2 = SLIST_NEXT(bc1, sbc_link)((bc1)->sbc_link.sle_next); | |||
| 1484 | free(bc1->sbc_metadata, M_DEVBUF2, sizeof(*bc1->sbc_metadata)); | |||
| 1485 | free(bc1, M_DEVBUF2, sizeof(*bc1)); | |||
| 1486 | } | |||
| 1487 | /* Free unallocated chunks. */ | |||
| 1488 | for (bc1 = SLIST_FIRST(&bch)((&bch)->slh_first); bc1 != NULL((void *)0); bc1 = bc2) { | |||
| 1489 | bc2 = SLIST_NEXT(bc1, sbc_link)((bc1)->sbc_link.sle_next); | |||
| 1490 | free(bc1->sbc_metadata, M_DEVBUF2, sizeof(*bc1->sbc_metadata)); | |||
| 1491 | free(bc1, M_DEVBUF2, sizeof(*bc1)); | |||
| 1492 | } | |||
| 1493 | ||||
| 1494 | while (!SLIST_EMPTY(&sdklist)(((&sdklist)->slh_first) == ((void *)0))) { | |||
| 1495 | sdk = SLIST_FIRST(&sdklist)((&sdklist)->slh_first); | |||
| 1496 | SLIST_REMOVE_HEAD(&sdklist, sdk_link)do { (&sdklist)->slh_first = (&sdklist)->slh_first ->sdk_link.sle_next; } while (0); | |||
| 1497 | free(sdk, M_DEVBUF2, sizeof(*sdk)); | |||
| 1498 | } | |||
| 1499 | ||||
| 1500 | free(devs, M_DEVBUF2, BIOC_CRMAXLEN1024 * sizeof(dev_t)); | |||
| 1501 | free(ondisk, M_DEVBUF2, BIOC_CRMAXLEN1024 * sizeof(u_int64_t)); | |||
| 1502 | ||||
| 1503 | return (rv); | |||
| 1504 | } | |||
| 1505 | ||||
| 1506 | void | |||
| 1507 | sr_map_root(void) | |||
| 1508 | { | |||
| 1509 | struct sr_softc *sc = softraid0; | |||
| 1510 | struct sr_discipline *sd; | |||
| 1511 | struct sr_meta_opt_item *omi; | |||
| 1512 | struct sr_meta_boot *sbm; | |||
| 1513 | u_char duid[8]; | |||
| 1514 | int i; | |||
| 1515 | ||||
| 1516 | if (sc == NULL((void *)0)) | |||
| 1517 | return; | |||
| 1518 | ||||
| 1519 | DNPRINTF(SR_D_MISC, "%s: sr_map_root\n", DEVNAME(sc)); | |||
| 1520 | ||||
| 1521 | bzero(duid, sizeof(duid))__builtin_bzero((duid), (sizeof(duid))); | |||
| 1522 | if (bcmp(rootduid, duid, sizeof(duid)) == 0) { | |||
| 1523 | DNPRINTF(SR_D_MISC, "%s: root duid is zero\n", DEVNAME(sc)); | |||
| 1524 | return; | |||
| 1525 | } | |||
| 1526 | ||||
| 1527 | TAILQ_FOREACH(sd, &sc->sc_dis_list, sd_link)for((sd) = ((&sc->sc_dis_list)->tqh_first); (sd) != ((void *)0); (sd) = ((sd)->sd_link.tqe_next)) { | |||
| 1528 | SLIST_FOREACH(omi, &sd->sd_meta_opt, omi_link)for((omi) = ((&sd->sd_meta_opt)->slh_first); (omi) != ((void *)0); (omi) = ((omi)->omi_link.sle_next)) { | |||
| 1529 | if (omi->omi_som->som_type != SR_OPT_BOOT0x02) | |||
| 1530 | continue; | |||
| 1531 | sbm = (struct sr_meta_boot *)omi->omi_som; | |||
| 1532 | for (i = 0; i < SR_MAX_BOOT_DISKS16; i++) { | |||
| 1533 | if (bcmp(rootduid, sbm->sbm_boot_duid[i], | |||
| 1534 | sizeof(rootduid)) == 0) { | |||
| 1535 | memcpy(rootduid, sbm->sbm_root_duid,__builtin_memcpy((rootduid), (sbm->sbm_root_duid), (sizeof (rootduid))) | |||
| 1536 | sizeof(rootduid))__builtin_memcpy((rootduid), (sbm->sbm_root_duid), (sizeof (rootduid))); | |||
| 1537 | DNPRINTF(SR_D_MISC, "%s: root duid " | |||
| 1538 | "mapped to %s\n", DEVNAME(sc), | |||
| 1539 | duid_format(rootduid)); | |||
| 1540 | return; | |||
| 1541 | } | |||
| 1542 | } | |||
| 1543 | } | |||
| 1544 | } | |||
| 1545 | } | |||
| 1546 | ||||
| 1547 | int | |||
| 1548 | sr_meta_native_probe(struct sr_softc *sc, struct sr_chunk *ch_entry) | |||
| 1549 | { | |||
| 1550 | struct disklabel label; | |||
| 1551 | char *devname; | |||
| 1552 | int error, part; | |||
| 1553 | u_int64_t size; | |||
| 1554 | ||||
| 1555 | DNPRINTF(SR_D_META, "%s: sr_meta_native_probe(%s)\n", | |||
| 1556 | DEVNAME(sc), ch_entry->src_devname); | |||
| 1557 | ||||
| 1558 | devname = ch_entry->src_devname; | |||
| 1559 | part = DISKPART(ch_entry->src_dev_mm)(((unsigned)((ch_entry->src_dev_mm) & 0xff) | (((ch_entry ->src_dev_mm) & 0xffff0000) >> 8)) % 16); | |||
| 1560 | ||||
| 1561 | /* get disklabel */ | |||
| 1562 | error = VOP_IOCTL(ch_entry->src_vn, DIOCGDINFO((unsigned long)0x40000000 | ((sizeof(struct disklabel) & 0x1fff) << 16) | ((('d')) << 8) | ((101))), (caddr_t)&label, FREAD0x0001, | |||
| 1563 | NOCRED((struct ucred *)-1), curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc); | |||
| 1564 | if (error) { | |||
| 1565 | DNPRINTF(SR_D_META, "%s: %s can't obtain disklabel\n", | |||
| 1566 | DEVNAME(sc), devname); | |||
| 1567 | goto unwind; | |||
| 1568 | } | |||
| 1569 | memcpy(ch_entry->src_duid, label.d_uid, sizeof(ch_entry->src_duid))__builtin_memcpy((ch_entry->src_duid), (label.d_uid), (sizeof (ch_entry->src_duid))); | |||
| 1570 | ||||
| 1571 | /* make sure the partition is of the right type */ | |||
| 1572 | if (label.d_partitions[part].p_fstype != FS_RAID19) { | |||
| 1573 | DNPRINTF(SR_D_META, | |||
| 1574 | "%s: %s partition not of type RAID (%d)\n", DEVNAME(sc), | |||
| 1575 | devname, | |||
| 1576 | label.d_partitions[part].p_fstype); | |||
| 1577 | goto unwind; | |||
| 1578 | } | |||
| 1579 | ||||
| 1580 | size = DL_SECTOBLK(&label, DL_GETPSIZE(&label.d_partitions[part]))(((((u_int64_t)(&label.d_partitions[part])->p_sizeh << 32) + (&label.d_partitions[part])->p_size)) * ((& label)->d_secsize / (1 << 9))); | |||
| 1581 | if (size <= SR_DATA_OFFSET(16 + (64 + (320 + 128)))) { | |||
| 1582 | DNPRINTF(SR_D_META, "%s: %s partition too small\n", DEVNAME(sc), | |||
| 1583 | devname); | |||
| 1584 | goto unwind; | |||
| 1585 | } | |||
| 1586 | size -= SR_DATA_OFFSET(16 + (64 + (320 + 128))); | |||
| 1587 | if (size > INT64_MAX0x7fffffffffffffffLL) { | |||
| 1588 | DNPRINTF(SR_D_META, "%s: %s partition too large\n", DEVNAME(sc), | |||
| 1589 | devname); | |||
| 1590 | goto unwind; | |||
| 1591 | } | |||
| 1592 | ch_entry->src_size = size; | |||
| 1593 | ch_entry->src_secsize = label.d_secsize; | |||
| 1594 | ||||
| 1595 | DNPRINTF(SR_D_META, "%s: probe found %s size %lld\n", DEVNAME(sc), | |||
| 1596 | devname, (long long)size); | |||
| 1597 | ||||
| 1598 | return (SR_META_F_NATIVE0); | |||
| 1599 | unwind: | |||
| 1600 | DNPRINTF(SR_D_META, "%s: invalid device: %s\n", DEVNAME(sc), | |||
| 1601 | devname ? devname : "nodev"); | |||
| 1602 | return (SR_META_F_INVALID-1); | |||
| 1603 | } | |||
| 1604 | ||||
| 1605 | int | |||
| 1606 | sr_meta_native_attach(struct sr_discipline *sd, int force) | |||
| 1607 | { | |||
| 1608 | struct sr_softc *sc = sd->sd_sc; | |||
| 1609 | struct sr_chunk_head *cl = &sd->sd_vol.sv_chunk_list; | |||
| 1610 | struct sr_metadata *md = NULL((void *)0); | |||
| 1611 | struct sr_chunk *ch_entry, *ch_next; | |||
| 1612 | struct sr_uuid uuid; | |||
| 1613 | u_int64_t version = 0; | |||
| 1614 | int sr, not_sr, rv = 1, d, expected = -1, old_meta = 0; | |||
| 1615 | ||||
| 1616 | DNPRINTF(SR_D_META, "%s: sr_meta_native_attach\n", DEVNAME(sc)); | |||
| 1617 | ||||
| 1618 | md = malloc(SR_META_SIZE64 * DEV_BSIZE(1 << 9), M_DEVBUF2, M_ZERO0x0008 | M_NOWAIT0x0002); | |||
| 1619 | if (md == NULL((void *)0)) { | |||
| 1620 | sr_error(sc, "not enough memory for metadata buffer"); | |||
| 1621 | goto bad; | |||
| 1622 | } | |||
| 1623 | ||||
| 1624 | bzero(&uuid, sizeof uuid)__builtin_bzero((&uuid), (sizeof uuid)); | |||
| 1625 | ||||
| 1626 | sr = not_sr = d = 0; | |||
| 1627 | SLIST_FOREACH(ch_entry, cl, src_link)for((ch_entry) = ((cl)->slh_first); (ch_entry) != ((void * )0); (ch_entry) = ((ch_entry)->src_link.sle_next)) { | |||
| 1628 | if (ch_entry->src_dev_mm == NODEV(dev_t)(-1)) | |||
| 1629 | continue; | |||
| 1630 | ||||
| 1631 | if (sr_meta_native_read(sd, ch_entry->src_dev_mm, md, NULL((void *)0))) { | |||
| 1632 | sr_error(sc, "could not read native metadata"); | |||
| 1633 | goto bad; | |||
| 1634 | } | |||
| 1635 | ||||
| 1636 | if (md->ssdi_sdd_invariant.ssd_magic == SR_MAGIC0x4d4152436372616dLLU) { | |||
| 1637 | sr++; | |||
| 1638 | ch_entry->src_meta.scmi_scm_invariant.scm_chunk_id = | |||
| 1639 | md->ssdi_sdd_invariant.ssd_chunk_id; | |||
| 1640 | if (d == 0) { | |||
| 1641 | memcpy(&uuid, &md->ssdi.ssd_uuid, sizeof uuid)__builtin_memcpy((&uuid), (&md->_sdd_invariant.ssd_uuid ), (sizeof uuid)); | |||
| 1642 | expected = md->ssdi_sdd_invariant.ssd_chunk_no; | |||
| 1643 | version = md->ssd_ondisk; | |||
| 1644 | d++; | |||
| 1645 | continue; | |||
| 1646 | } else if (bcmp(&md->ssdi_sdd_invariant.ssd_uuid, &uuid, | |||
| 1647 | sizeof uuid)) { | |||
| 1648 | sr_error(sc, "not part of the same volume"); | |||
| 1649 | goto bad; | |||
| 1650 | } | |||
| 1651 | if (md->ssd_ondisk != version) { | |||
| 1652 | old_meta++; | |||
| 1653 | version = MAX(md->ssd_ondisk, version)(((md->ssd_ondisk)>(version))?(md->ssd_ondisk):(version )); | |||
| 1654 | } | |||
| 1655 | } else | |||
| 1656 | not_sr++; | |||
| 1657 | } | |||
| 1658 | ||||
| 1659 | if (sr && not_sr && !force) { | |||
| 1660 | sr_error(sc, "not all chunks are of the native metadata " | |||
| 1661 | "format"); | |||
| 1662 | goto bad; | |||
| 1663 | } | |||
| 1664 | ||||
| 1665 | /* mixed metadata versions; mark bad disks offline */ | |||
| 1666 | if (old_meta) { | |||
| 1667 | d = 0; | |||
| 1668 | for (ch_entry = SLIST_FIRST(cl)((cl)->slh_first); ch_entry != NULL((void *)0); | |||
| 1669 | ch_entry = ch_next, d++) { | |||
| 1670 | ch_next = SLIST_NEXT(ch_entry, src_link)((ch_entry)->src_link.sle_next); | |||
| 1671 | ||||
| 1672 | /* XXX do we want to read this again? */ | |||
| 1673 | if (ch_entry->src_dev_mm == NODEV(dev_t)(-1)) | |||
| 1674 | panic("src_dev_mm == NODEV"); | |||
| 1675 | if (sr_meta_native_read(sd, ch_entry->src_dev_mm, md, | |||
| 1676 | NULL((void *)0))) | |||
| 1677 | sr_warn(sc, "could not read native metadata"); | |||
| 1678 | if (md->ssd_ondisk != version) | |||
| 1679 | sd->sd_vol.sv_chunks[d]->src_meta.scm_status = | |||
| 1680 | BIOC_SDOFFLINE0x01; | |||
| 1681 | } | |||
| 1682 | } | |||
| 1683 | ||||
| 1684 | if (expected != sr && !force && expected != -1) { | |||
| 1685 | DNPRINTF(SR_D_META, "%s: not all chunks were provided, trying " | |||
| 1686 | "anyway\n", DEVNAME(sc)); | |||
| 1687 | } | |||
| 1688 | ||||
| 1689 | rv = 0; | |||
| 1690 | bad: | |||
| 1691 | free(md, M_DEVBUF2, SR_META_SIZE64 * DEV_BSIZE(1 << 9)); | |||
| 1692 | return (rv); | |||
| 1693 | } | |||
| 1694 | ||||
| 1695 | int | |||
| 1696 | sr_meta_native_read(struct sr_discipline *sd, dev_t dev, | |||
| 1697 | struct sr_metadata *md, void *fm) | |||
| 1698 | { | |||
| 1699 | #ifdef SR_DEBUG | |||
| 1700 | struct sr_softc *sc = sd->sd_sc; | |||
| 1701 | #endif | |||
| 1702 | DNPRINTF(SR_D_META, "%s: sr_meta_native_read(0x%x, %p)\n", | |||
| 1703 | DEVNAME(sc), dev, md); | |||
| 1704 | ||||
| 1705 | return (sr_meta_rw(sd, dev, md, B_READ0x00008000)); | |||
| 1706 | } | |||
| 1707 | ||||
| 1708 | int | |||
| 1709 | sr_meta_native_write(struct sr_discipline *sd, dev_t dev, | |||
| 1710 | struct sr_metadata *md, void *fm) | |||
| 1711 | { | |||
| 1712 | #ifdef SR_DEBUG | |||
| 1713 | struct sr_softc *sc = sd->sd_sc; | |||
| 1714 | #endif | |||
| 1715 | DNPRINTF(SR_D_META, "%s: sr_meta_native_write(0x%x, %p)\n", | |||
| 1716 | DEVNAME(sc), dev, md); | |||
| 1717 | ||||
| 1718 | return (sr_meta_rw(sd, dev, md, B_WRITE0x00000000)); | |||
| 1719 | } | |||
| 1720 | ||||
| 1721 | void | |||
| 1722 | sr_hotplug_register(struct sr_discipline *sd, void *func) | |||
| 1723 | { | |||
| 1724 | struct sr_hotplug_list *mhe; | |||
| 1725 | ||||
| 1726 | DNPRINTF(SR_D_MISC, "%s: sr_hotplug_register: %p\n", | |||
| 1727 | DEVNAME(sd->sd_sc), func); | |||
| 1728 | ||||
| 1729 | /* make sure we aren't on the list yet */ | |||
| 1730 | SLIST_FOREACH(mhe, &sr_hotplug_callbacks, shl_link)for((mhe) = ((&sr_hotplug_callbacks)->slh_first); (mhe ) != ((void *)0); (mhe) = ((mhe)->shl_link.sle_next)) | |||
| 1731 | if (mhe->sh_hotplug == func) | |||
| 1732 | return; | |||
| 1733 | ||||
| 1734 | mhe = malloc(sizeof(struct sr_hotplug_list), M_DEVBUF2, | |||
| 1735 | M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 1736 | mhe->sh_hotplug = func; | |||
| 1737 | mhe->sh_sd = sd; | |||
| 1738 | SLIST_INSERT_HEAD(&sr_hotplug_callbacks, mhe, shl_link)do { (mhe)->shl_link.sle_next = (&sr_hotplug_callbacks )->slh_first; (&sr_hotplug_callbacks)->slh_first = ( mhe); } while (0); | |||
| 1739 | } | |||
| 1740 | ||||
| 1741 | void | |||
| 1742 | sr_hotplug_unregister(struct sr_discipline *sd, void *func) | |||
| 1743 | { | |||
| 1744 | struct sr_hotplug_list *mhe; | |||
| 1745 | ||||
| 1746 | DNPRINTF(SR_D_MISC, "%s: sr_hotplug_unregister: %s %p\n", | |||
| 1747 | DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname, func); | |||
| 1748 | ||||
| 1749 | /* make sure we are on the list yet */ | |||
| 1750 | SLIST_FOREACH(mhe, &sr_hotplug_callbacks, shl_link)for((mhe) = ((&sr_hotplug_callbacks)->slh_first); (mhe ) != ((void *)0); (mhe) = ((mhe)->shl_link.sle_next)) { | |||
| 1751 | if (mhe->sh_hotplug == func) | |||
| 1752 | break; | |||
| 1753 | } | |||
| 1754 | if (mhe != NULL((void *)0)) { | |||
| 1755 | SLIST_REMOVE(&sr_hotplug_callbacks, mhe,do { if ((&sr_hotplug_callbacks)->slh_first == (mhe)) { do { ((&sr_hotplug_callbacks))->slh_first = ((&sr_hotplug_callbacks ))->slh_first->shl_link.sle_next; } while (0); } else { struct sr_hotplug_list *curelm = (&sr_hotplug_callbacks) ->slh_first; while (curelm->shl_link.sle_next != (mhe)) curelm = curelm->shl_link.sle_next; curelm->shl_link.sle_next = curelm->shl_link.sle_next->shl_link.sle_next; } ((mhe )->shl_link.sle_next) = ((void *)-1); } while (0) | |||
| 1756 | sr_hotplug_list, shl_link)do { if ((&sr_hotplug_callbacks)->slh_first == (mhe)) { do { ((&sr_hotplug_callbacks))->slh_first = ((&sr_hotplug_callbacks ))->slh_first->shl_link.sle_next; } while (0); } else { struct sr_hotplug_list *curelm = (&sr_hotplug_callbacks) ->slh_first; while (curelm->shl_link.sle_next != (mhe)) curelm = curelm->shl_link.sle_next; curelm->shl_link.sle_next = curelm->shl_link.sle_next->shl_link.sle_next; } ((mhe )->shl_link.sle_next) = ((void *)-1); } while (0); | |||
| 1757 | free(mhe, M_DEVBUF2, sizeof(*mhe)); | |||
| 1758 | } | |||
| 1759 | } | |||
| 1760 | ||||
| 1761 | void | |||
| 1762 | sr_disk_attach(struct disk *diskp, int action) | |||
| 1763 | { | |||
| 1764 | struct sr_hotplug_list *mhe; | |||
| 1765 | ||||
| 1766 | SLIST_FOREACH(mhe, &sr_hotplug_callbacks, shl_link)for((mhe) = ((&sr_hotplug_callbacks)->slh_first); (mhe ) != ((void *)0); (mhe) = ((mhe)->shl_link.sle_next)) | |||
| 1767 | if (mhe->sh_sd->sd_ready) | |||
| 1768 | mhe->sh_hotplug(mhe->sh_sd, diskp, action); | |||
| 1769 | } | |||
| 1770 | ||||
| 1771 | int | |||
| 1772 | sr_match(struct device *parent, void *match, void *aux) | |||
| 1773 | { | |||
| 1774 | return (1); | |||
| 1775 | } | |||
| 1776 | ||||
| 1777 | void | |||
| 1778 | sr_attach(struct device *parent, struct device *self, void *aux) | |||
| 1779 | { | |||
| 1780 | struct sr_softc *sc = (void *)self; | |||
| 1781 | struct scsibus_attach_args saa; | |||
| 1782 | ||||
| 1783 | DNPRINTF(SR_D_MISC, "\n%s: sr_attach", DEVNAME(sc)); | |||
| 1784 | ||||
| 1785 | if (softraid0 == NULL((void *)0)) | |||
| 1786 | softraid0 = sc; | |||
| 1787 | ||||
| 1788 | rw_init(&sc->sc_lock, "sr_lock")_rw_init_flags(&sc->sc_lock, "sr_lock", 0, ((void *)0) ); | |||
| 1789 | rw_init(&sc->sc_hs_lock, "sr_hs_lock")_rw_init_flags(&sc->sc_hs_lock, "sr_hs_lock", 0, ((void *)0)); | |||
| 1790 | ||||
| 1791 | SLIST_INIT(&sr_hotplug_callbacks){ ((&sr_hotplug_callbacks)->slh_first) = ((void *)0); }; | |||
| 1792 | TAILQ_INIT(&sc->sc_dis_list)do { (&sc->sc_dis_list)->tqh_first = ((void *)0); ( &sc->sc_dis_list)->tqh_last = &(&sc->sc_dis_list )->tqh_first; } while (0); | |||
| 1793 | SLIST_INIT(&sc->sc_hotspare_list){ ((&sc->sc_hotspare_list)->slh_first) = ((void *)0 ); }; | |||
| 1794 | ||||
| 1795 | #if NBIO1 > 0 | |||
| 1796 | if (bio_register(&sc->sc_dev, sr_bio_ioctl) != 0) | |||
| 1797 | printf("%s: controller registration failed", DEVNAME(sc)((sc)->sc_dev.dv_xname)); | |||
| 1798 | #endif /* NBIO > 0 */ | |||
| 1799 | ||||
| 1800 | #ifndef SMALL_KERNEL | |||
| 1801 | strlcpy(sc->sc_sensordev.xname, DEVNAME(sc)((sc)->sc_dev.dv_xname), | |||
| 1802 | sizeof(sc->sc_sensordev.xname)); | |||
| 1803 | sensordev_install(&sc->sc_sensordev); | |||
| 1804 | #endif /* SMALL_KERNEL */ | |||
| 1805 | ||||
| 1806 | printf("\n"); | |||
| 1807 | ||||
| 1808 | saa.saa_adapter_softc = sc; | |||
| 1809 | saa.saa_adapter = &sr_switch; | |||
| 1810 | saa.saa_adapter_target = SDEV_NO_ADAPTER_TARGET0xffff; | |||
| 1811 | saa.saa_adapter_buswidth = SR_MAX_LD256; | |||
| 1812 | saa.saa_luns = 1; | |||
| 1813 | saa.saa_openings = 0; | |||
| 1814 | saa.saa_pool = NULL((void *)0); | |||
| 1815 | saa.saa_quirks = saa.saa_flags = 0; | |||
| 1816 | saa.saa_wwpn = saa.saa_wwnn = 0; | |||
| 1817 | ||||
| 1818 | sc->sc_scsibus = (struct scsibus_softc *)config_found(&sc->sc_dev, &saa,config_found_sm((&sc->sc_dev), (&saa), (scsiprint) , ((void *)0)) | |||
| 1819 | scsiprint)config_found_sm((&sc->sc_dev), (&saa), (scsiprint) , ((void *)0)); | |||
| 1820 | ||||
| 1821 | softraid_disk_attach = sr_disk_attach; | |||
| 1822 | ||||
| 1823 | sr_boot_assembly(sc); | |||
| 1824 | ||||
| 1825 | explicit_bzero(sr_bootkey, sizeof(sr_bootkey)); | |||
| 1826 | } | |||
| 1827 | ||||
| 1828 | int | |||
| 1829 | sr_detach(struct device *self, int flags) | |||
| 1830 | { | |||
| 1831 | struct sr_softc *sc = (void *)self; | |||
| 1832 | int rv; | |||
| 1833 | ||||
| 1834 | DNPRINTF(SR_D_MISC, "%s: sr_detach\n", DEVNAME(sc)); | |||
| 1835 | ||||
| 1836 | softraid_disk_attach = NULL((void *)0); | |||
| 1837 | ||||
| 1838 | sr_shutdown(0); | |||
| 1839 | ||||
| 1840 | #ifndef SMALL_KERNEL | |||
| 1841 | if (sc->sc_sensor_task != NULL((void *)0)) | |||
| 1842 | sensor_task_unregister(sc->sc_sensor_task); | |||
| 1843 | sensordev_deinstall(&sc->sc_sensordev); | |||
| 1844 | #endif /* SMALL_KERNEL */ | |||
| 1845 | ||||
| 1846 | if (sc->sc_scsibus != NULL((void *)0)) { | |||
| 1847 | rv = config_detach((struct device *)sc->sc_scsibus, flags); | |||
| 1848 | if (rv != 0) | |||
| 1849 | return (rv); | |||
| 1850 | sc->sc_scsibus = NULL((void *)0); | |||
| 1851 | } | |||
| 1852 | ||||
| 1853 | return (0); | |||
| 1854 | } | |||
| 1855 | ||||
| 1856 | void | |||
| 1857 | sr_info(struct sr_softc *sc, const char *fmt, ...) | |||
| 1858 | { | |||
| 1859 | va_list ap; | |||
| 1860 | ||||
| 1861 | rw_assert_wrlock(&sc->sc_lock); | |||
| 1862 | ||||
| 1863 | va_start(ap, fmt)__builtin_va_start((ap), fmt); | |||
| 1864 | bio_status(&sc->sc_status, 0, BIO_MSG_INFO1, fmt, &ap); | |||
| 1865 | va_end(ap)__builtin_va_end((ap)); | |||
| 1866 | } | |||
| 1867 | ||||
| 1868 | void | |||
| 1869 | sr_warn(struct sr_softc *sc, const char *fmt, ...) | |||
| 1870 | { | |||
| 1871 | va_list ap; | |||
| 1872 | ||||
| 1873 | rw_assert_wrlock(&sc->sc_lock); | |||
| 1874 | ||||
| 1875 | va_start(ap, fmt)__builtin_va_start((ap), fmt); | |||
| 1876 | bio_status(&sc->sc_status, 1, BIO_MSG_WARN2, fmt, &ap); | |||
| 1877 | va_end(ap)__builtin_va_end((ap)); | |||
| 1878 | } | |||
| 1879 | ||||
| 1880 | void | |||
| 1881 | sr_error(struct sr_softc *sc, const char *fmt, ...) | |||
| 1882 | { | |||
| 1883 | va_list ap; | |||
| 1884 | ||||
| 1885 | rw_assert_wrlock(&sc->sc_lock); | |||
| 1886 | ||||
| 1887 | va_start(ap, fmt)__builtin_va_start((ap), fmt); | |||
| 1888 | bio_status(&sc->sc_status, 1, BIO_MSG_ERROR3, fmt, &ap); | |||
| 1889 | va_end(ap)__builtin_va_end((ap)); | |||
| 1890 | } | |||
| 1891 | ||||
| 1892 | int | |||
| 1893 | sr_ccb_alloc(struct sr_discipline *sd) | |||
| 1894 | { | |||
| 1895 | struct sr_ccb *ccb; | |||
| 1896 | int i; | |||
| 1897 | ||||
| 1898 | if (!sd) | |||
| 1899 | return (1); | |||
| 1900 | ||||
| 1901 | DNPRINTF(SR_D_CCB, "%s: sr_ccb_alloc\n", DEVNAME(sd->sd_sc)); | |||
| 1902 | ||||
| 1903 | if (sd->sd_ccb) | |||
| 1904 | return (1); | |||
| 1905 | ||||
| 1906 | sd->sd_ccb = mallocarray(sd->sd_max_wu, | |||
| 1907 | sd->sd_max_ccb_per_wu * sizeof(struct sr_ccb), | |||
| 1908 | M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 1909 | TAILQ_INIT(&sd->sd_ccb_freeq)do { (&sd->sd_ccb_freeq)->tqh_first = ((void *)0); ( &sd->sd_ccb_freeq)->tqh_last = &(&sd->sd_ccb_freeq )->tqh_first; } while (0); | |||
| 1910 | for (i = 0; i < sd->sd_max_wu * sd->sd_max_ccb_per_wu; i++) { | |||
| 1911 | ccb = &sd->sd_ccb[i]; | |||
| 1912 | ccb->ccb_dis = sd; | |||
| 1913 | sr_ccb_put(ccb); | |||
| 1914 | } | |||
| 1915 | ||||
| 1916 | DNPRINTF(SR_D_CCB, "%s: sr_ccb_alloc ccb: %d\n", | |||
| 1917 | DEVNAME(sd->sd_sc), sd->sd_max_wu * sd->sd_max_ccb_per_wu); | |||
| 1918 | ||||
| 1919 | return (0); | |||
| 1920 | } | |||
| 1921 | ||||
| 1922 | void | |||
| 1923 | sr_ccb_free(struct sr_discipline *sd) | |||
| 1924 | { | |||
| 1925 | struct sr_ccb *ccb; | |||
| 1926 | ||||
| 1927 | if (!sd) | |||
| 1928 | return; | |||
| 1929 | ||||
| 1930 | DNPRINTF(SR_D_CCB, "%s: sr_ccb_free %p\n", DEVNAME(sd->sd_sc), sd); | |||
| 1931 | ||||
| 1932 | while ((ccb = TAILQ_FIRST(&sd->sd_ccb_freeq)((&sd->sd_ccb_freeq)->tqh_first)) != NULL((void *)0)) | |||
| 1933 | TAILQ_REMOVE(&sd->sd_ccb_freeq, ccb, ccb_link)do { if (((ccb)->ccb_link.tqe_next) != ((void *)0)) (ccb)-> ccb_link.tqe_next->ccb_link.tqe_prev = (ccb)->ccb_link. tqe_prev; else (&sd->sd_ccb_freeq)->tqh_last = (ccb )->ccb_link.tqe_prev; *(ccb)->ccb_link.tqe_prev = (ccb) ->ccb_link.tqe_next; ((ccb)->ccb_link.tqe_prev) = ((void *)-1); ((ccb)->ccb_link.tqe_next) = ((void *)-1); } while (0); | |||
| 1934 | ||||
| 1935 | free(sd->sd_ccb, M_DEVBUF2, sd->sd_max_wu * sd->sd_max_ccb_per_wu * | |||
| 1936 | sizeof(struct sr_ccb)); | |||
| 1937 | } | |||
| 1938 | ||||
| 1939 | struct sr_ccb * | |||
| 1940 | sr_ccb_get(struct sr_discipline *sd) | |||
| 1941 | { | |||
| 1942 | struct sr_ccb *ccb; | |||
| 1943 | int s; | |||
| 1944 | ||||
| 1945 | s = splbio()splraise(0x3); | |||
| 1946 | ||||
| 1947 | ccb = TAILQ_FIRST(&sd->sd_ccb_freeq)((&sd->sd_ccb_freeq)->tqh_first); | |||
| 1948 | if (ccb) { | |||
| 1949 | TAILQ_REMOVE(&sd->sd_ccb_freeq, ccb, ccb_link)do { if (((ccb)->ccb_link.tqe_next) != ((void *)0)) (ccb)-> ccb_link.tqe_next->ccb_link.tqe_prev = (ccb)->ccb_link. tqe_prev; else (&sd->sd_ccb_freeq)->tqh_last = (ccb )->ccb_link.tqe_prev; *(ccb)->ccb_link.tqe_prev = (ccb) ->ccb_link.tqe_next; ((ccb)->ccb_link.tqe_prev) = ((void *)-1); ((ccb)->ccb_link.tqe_next) = ((void *)-1); } while (0); | |||
| 1950 | ccb->ccb_state = SR_CCB_INPROGRESS1; | |||
| 1951 | } | |||
| 1952 | ||||
| 1953 | splx(s)spllower(s); | |||
| 1954 | ||||
| 1955 | DNPRINTF(SR_D_CCB, "%s: sr_ccb_get: %p\n", DEVNAME(sd->sd_sc), | |||
| 1956 | ccb); | |||
| 1957 | ||||
| 1958 | return (ccb); | |||
| 1959 | } | |||
| 1960 | ||||
| 1961 | void | |||
| 1962 | sr_ccb_put(struct sr_ccb *ccb) | |||
| 1963 | { | |||
| 1964 | struct sr_discipline *sd = ccb->ccb_dis; | |||
| 1965 | int s; | |||
| 1966 | ||||
| 1967 | DNPRINTF(SR_D_CCB, "%s: sr_ccb_put: %p\n", DEVNAME(sd->sd_sc), | |||
| 1968 | ccb); | |||
| 1969 | ||||
| 1970 | s = splbio()splraise(0x3); | |||
| 1971 | ||||
| 1972 | ccb->ccb_wu = NULL((void *)0); | |||
| 1973 | ccb->ccb_state = SR_CCB_FREE0; | |||
| 1974 | ccb->ccb_target = -1; | |||
| 1975 | ccb->ccb_opaque = NULL((void *)0); | |||
| 1976 | ||||
| 1977 | TAILQ_INSERT_TAIL(&sd->sd_ccb_freeq, ccb, ccb_link)do { (ccb)->ccb_link.tqe_next = ((void *)0); (ccb)->ccb_link .tqe_prev = (&sd->sd_ccb_freeq)->tqh_last; *(&sd ->sd_ccb_freeq)->tqh_last = (ccb); (&sd->sd_ccb_freeq )->tqh_last = &(ccb)->ccb_link.tqe_next; } while (0 ); | |||
| 1978 | ||||
| 1979 | splx(s)spllower(s); | |||
| 1980 | } | |||
| 1981 | ||||
| 1982 | struct sr_ccb * | |||
| 1983 | sr_ccb_rw(struct sr_discipline *sd, int chunk, daddr_t blkno, | |||
| 1984 | long len, u_int8_t *data, int xsflags, int ccbflags) | |||
| 1985 | { | |||
| 1986 | struct sr_chunk *sc = sd->sd_vol.sv_chunks[chunk]; | |||
| 1987 | struct sr_ccb *ccb = NULL((void *)0); | |||
| 1988 | int s; | |||
| 1989 | ||||
| 1990 | ccb = sr_ccb_get(sd); | |||
| 1991 | if (ccb == NULL((void *)0)) | |||
| 1992 | goto out; | |||
| 1993 | ||||
| 1994 | ccb->ccb_flags = ccbflags; | |||
| 1995 | ccb->ccb_target = chunk; | |||
| 1996 | ||||
| 1997 | ccb->ccb_buf.b_flags = B_PHYS0x00002000 | B_CALL0x00000040; | |||
| 1998 | if (ISSET(xsflags, SCSI_DATA_IN)((xsflags) & (0x00800))) | |||
| 1999 | ccb->ccb_buf.b_flags |= B_READ0x00008000; | |||
| 2000 | else | |||
| 2001 | ccb->ccb_buf.b_flags |= B_WRITE0x00000000; | |||
| 2002 | ||||
| 2003 | ccb->ccb_buf.b_blkno = blkno + sd->sd_meta->ssd_data_blkno; | |||
| 2004 | ccb->ccb_buf.b_bcount = len; | |||
| 2005 | ccb->ccb_buf.b_bufsize = len; | |||
| 2006 | ccb->ccb_buf.b_resid = len; | |||
| 2007 | ccb->ccb_buf.b_data = data; | |||
| 2008 | ccb->ccb_buf.b_error = 0; | |||
| 2009 | ccb->ccb_buf.b_iodone = sd->sd_scsi_intr; | |||
| 2010 | ccb->ccb_buf.b_proc = curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc; | |||
| 2011 | ccb->ccb_buf.b_dev = sc->src_dev_mm; | |||
| 2012 | ccb->ccb_buf.b_vp = sc->src_vn; | |||
| 2013 | ccb->ccb_buf.b_bq = NULL((void *)0); | |||
| 2014 | ||||
| 2015 | if (!ISSET(ccb->ccb_buf.b_flags, B_READ)((ccb->ccb_buf.b_flags) & (0x00008000))) { | |||
| 2016 | s = splbio()splraise(0x3); | |||
| 2017 | ccb->ccb_buf.b_vp->v_numoutput++; | |||
| 2018 | splx(s)spllower(s); | |||
| 2019 | } | |||
| 2020 | ||||
| 2021 | LIST_INIT(&ccb->ccb_buf.b_dep)do { ((&ccb->ccb_buf.b_dep)->lh_first) = ((void *)0 ); } while (0); | |||
| 2022 | ||||
| 2023 | DNPRINTF(SR_D_DIS, "%s: %s %s ccb " | |||
| 2024 | "b_bcount %ld b_blkno %lld b_flags 0x%0lx b_data %p\n", | |||
| 2025 | DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname, sd->sd_name, | |||
| 2026 | ccb->ccb_buf.b_bcount, (long long)ccb->ccb_buf.b_blkno, | |||
| 2027 | ccb->ccb_buf.b_flags, ccb->ccb_buf.b_data); | |||
| 2028 | ||||
| 2029 | out: | |||
| 2030 | return ccb; | |||
| 2031 | } | |||
| 2032 | ||||
| 2033 | void | |||
| 2034 | sr_ccb_done(struct sr_ccb *ccb) | |||
| 2035 | { | |||
| 2036 | struct sr_workunit *wu = ccb->ccb_wu; | |||
| 2037 | struct sr_discipline *sd = wu->swu_dis; | |||
| 2038 | struct sr_softc *sc = sd->sd_sc; | |||
| 2039 | ||||
| 2040 | DNPRINTF(SR_D_INTR, "%s: %s %s ccb done b_bcount %ld b_resid %zu" | |||
| 2041 | " b_flags 0x%0lx block %lld target %d\n", | |||
| 2042 | DEVNAME(sc), sd->sd_meta->ssd_devname, sd->sd_name, | |||
| 2043 | ccb->ccb_buf.b_bcount, ccb->ccb_buf.b_resid, ccb->ccb_buf.b_flags, | |||
| 2044 | (long long)ccb->ccb_buf.b_blkno, ccb->ccb_target); | |||
| 2045 | ||||
| 2046 | splassert(IPL_BIO)do { if (splassert_ctl > 0) { splassert_check(0x3, __func__ ); } } while (0); | |||
| 2047 | ||||
| 2048 | if (ccb->ccb_target == -1) | |||
| 2049 | panic("%s: invalid target on wu: %p", DEVNAME(sc)((sc)->sc_dev.dv_xname), wu); | |||
| 2050 | ||||
| 2051 | if (ccb->ccb_buf.b_flags & B_ERROR0x00000400) { | |||
| 2052 | DNPRINTF(SR_D_INTR, "%s: i/o error on block %lld target %d\n", | |||
| 2053 | DEVNAME(sc), (long long)ccb->ccb_buf.b_blkno, | |||
| 2054 | ccb->ccb_target); | |||
| 2055 | if (ISSET(sd->sd_capabilities, SR_CAP_REDUNDANT)((sd->sd_capabilities) & (0x00000010))) | |||
| 2056 | sd->sd_set_chunk_state(sd, ccb->ccb_target, | |||
| 2057 | BIOC_SDOFFLINE0x01); | |||
| 2058 | else | |||
| 2059 | printf("%s: %s: i/o error %d @ %s block %lld\n", | |||
| 2060 | DEVNAME(sc)((sc)->sc_dev.dv_xname), sd->sd_meta->ssd_devname, | |||
| 2061 | ccb->ccb_buf.b_error, sd->sd_name, | |||
| 2062 | (long long)ccb->ccb_buf.b_blkno); | |||
| 2063 | ccb->ccb_state = SR_CCB_FAILED3; | |||
| 2064 | wu->swu_ios_failed++; | |||
| 2065 | } else { | |||
| 2066 | ccb->ccb_state = SR_CCB_OK2; | |||
| 2067 | wu->swu_ios_succeeded++; | |||
| 2068 | } | |||
| 2069 | ||||
| 2070 | wu->swu_ios_complete++; | |||
| 2071 | } | |||
| 2072 | ||||
| 2073 | int | |||
| 2074 | sr_wu_alloc(struct sr_discipline *sd) | |||
| 2075 | { | |||
| 2076 | struct sr_workunit *wu; | |||
| 2077 | int i, no_wu; | |||
| 2078 | ||||
| 2079 | DNPRINTF(SR_D_WU, "%s: sr_wu_alloc %p %d\n", DEVNAME(sd->sd_sc), | |||
| 2080 | sd, sd->sd_max_wu); | |||
| 2081 | ||||
| 2082 | no_wu = sd->sd_max_wu; | |||
| 2083 | sd->sd_wu_pending = no_wu; | |||
| 2084 | ||||
| 2085 | mtx_init(&sd->sd_wu_mtx, IPL_BIO)do { (void)(((void *)0)); (void)(0); __mtx_init((&sd-> sd_wu_mtx), ((((0x3)) > 0x0 && ((0x3)) < 0x9) ? 0x9 : ((0x3)))); } while (0); | |||
| 2086 | TAILQ_INIT(&sd->sd_wu)do { (&sd->sd_wu)->tqh_first = ((void *)0); (&sd ->sd_wu)->tqh_last = &(&sd->sd_wu)->tqh_first ; } while (0); | |||
| 2087 | TAILQ_INIT(&sd->sd_wu_freeq)do { (&sd->sd_wu_freeq)->tqh_first = ((void *)0); ( &sd->sd_wu_freeq)->tqh_last = &(&sd->sd_wu_freeq )->tqh_first; } while (0); | |||
| 2088 | TAILQ_INIT(&sd->sd_wu_pendq)do { (&sd->sd_wu_pendq)->tqh_first = ((void *)0); ( &sd->sd_wu_pendq)->tqh_last = &(&sd->sd_wu_pendq )->tqh_first; } while (0); | |||
| 2089 | TAILQ_INIT(&sd->sd_wu_defq)do { (&sd->sd_wu_defq)->tqh_first = ((void *)0); (& sd->sd_wu_defq)->tqh_last = &(&sd->sd_wu_defq )->tqh_first; } while (0); | |||
| 2090 | ||||
| 2091 | for (i = 0; i < no_wu; i++) { | |||
| 2092 | wu = malloc(sd->sd_wu_size, M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 2093 | TAILQ_INSERT_TAIL(&sd->sd_wu, wu, swu_next)do { (wu)->swu_next.tqe_next = ((void *)0); (wu)->swu_next .tqe_prev = (&sd->sd_wu)->tqh_last; *(&sd->sd_wu )->tqh_last = (wu); (&sd->sd_wu)->tqh_last = & (wu)->swu_next.tqe_next; } while (0); | |||
| 2094 | TAILQ_INIT(&wu->swu_ccb)do { (&wu->swu_ccb)->tqh_first = ((void *)0); (& wu->swu_ccb)->tqh_last = &(&wu->swu_ccb)-> tqh_first; } while (0); | |||
| 2095 | wu->swu_dis = sd; | |||
| 2096 | task_set(&wu->swu_task, sr_wu_done_callback, wu); | |||
| 2097 | sr_wu_put(sd, wu); | |||
| 2098 | } | |||
| 2099 | ||||
| 2100 | return (0); | |||
| 2101 | } | |||
| 2102 | ||||
| 2103 | void | |||
| 2104 | sr_wu_free(struct sr_discipline *sd) | |||
| 2105 | { | |||
| 2106 | struct sr_workunit *wu; | |||
| 2107 | ||||
| 2108 | DNPRINTF(SR_D_WU, "%s: sr_wu_free %p\n", DEVNAME(sd->sd_sc), sd); | |||
| 2109 | ||||
| 2110 | while ((wu = TAILQ_FIRST(&sd->sd_wu_freeq)((&sd->sd_wu_freeq)->tqh_first)) != NULL((void *)0)) | |||
| 2111 | TAILQ_REMOVE(&sd->sd_wu_freeq, wu, swu_link)do { if (((wu)->swu_link.tqe_next) != ((void *)0)) (wu)-> swu_link.tqe_next->swu_link.tqe_prev = (wu)->swu_link.tqe_prev ; else (&sd->sd_wu_freeq)->tqh_last = (wu)->swu_link .tqe_prev; *(wu)->swu_link.tqe_prev = (wu)->swu_link.tqe_next ; ((wu)->swu_link.tqe_prev) = ((void *)-1); ((wu)->swu_link .tqe_next) = ((void *)-1); } while (0); | |||
| 2112 | while ((wu = TAILQ_FIRST(&sd->sd_wu_pendq)((&sd->sd_wu_pendq)->tqh_first)) != NULL((void *)0)) | |||
| 2113 | TAILQ_REMOVE(&sd->sd_wu_pendq, wu, swu_link)do { if (((wu)->swu_link.tqe_next) != ((void *)0)) (wu)-> swu_link.tqe_next->swu_link.tqe_prev = (wu)->swu_link.tqe_prev ; else (&sd->sd_wu_pendq)->tqh_last = (wu)->swu_link .tqe_prev; *(wu)->swu_link.tqe_prev = (wu)->swu_link.tqe_next ; ((wu)->swu_link.tqe_prev) = ((void *)-1); ((wu)->swu_link .tqe_next) = ((void *)-1); } while (0); | |||
| 2114 | while ((wu = TAILQ_FIRST(&sd->sd_wu_defq)((&sd->sd_wu_defq)->tqh_first)) != NULL((void *)0)) | |||
| 2115 | TAILQ_REMOVE(&sd->sd_wu_defq, wu, swu_link)do { if (((wu)->swu_link.tqe_next) != ((void *)0)) (wu)-> swu_link.tqe_next->swu_link.tqe_prev = (wu)->swu_link.tqe_prev ; else (&sd->sd_wu_defq)->tqh_last = (wu)->swu_link .tqe_prev; *(wu)->swu_link.tqe_prev = (wu)->swu_link.tqe_next ; ((wu)->swu_link.tqe_prev) = ((void *)-1); ((wu)->swu_link .tqe_next) = ((void *)-1); } while (0); | |||
| 2116 | ||||
| 2117 | while ((wu = TAILQ_FIRST(&sd->sd_wu)((&sd->sd_wu)->tqh_first)) != NULL((void *)0)) { | |||
| 2118 | TAILQ_REMOVE(&sd->sd_wu, wu, swu_next)do { if (((wu)->swu_next.tqe_next) != ((void *)0)) (wu)-> swu_next.tqe_next->swu_next.tqe_prev = (wu)->swu_next.tqe_prev ; else (&sd->sd_wu)->tqh_last = (wu)->swu_next.tqe_prev ; *(wu)->swu_next.tqe_prev = (wu)->swu_next.tqe_next; ( (wu)->swu_next.tqe_prev) = ((void *)-1); ((wu)->swu_next .tqe_next) = ((void *)-1); } while (0); | |||
| 2119 | free(wu, M_DEVBUF2, sd->sd_wu_size); | |||
| 2120 | } | |||
| 2121 | } | |||
| 2122 | ||||
| 2123 | void * | |||
| 2124 | sr_wu_get(void *xsd) | |||
| 2125 | { | |||
| 2126 | struct sr_discipline *sd = (struct sr_discipline *)xsd; | |||
| 2127 | struct sr_workunit *wu; | |||
| 2128 | ||||
| 2129 | mtx_enter(&sd->sd_wu_mtx); | |||
| 2130 | wu = TAILQ_FIRST(&sd->sd_wu_freeq)((&sd->sd_wu_freeq)->tqh_first); | |||
| 2131 | if (wu) { | |||
| 2132 | TAILQ_REMOVE(&sd->sd_wu_freeq, wu, swu_link)do { if (((wu)->swu_link.tqe_next) != ((void *)0)) (wu)-> swu_link.tqe_next->swu_link.tqe_prev = (wu)->swu_link.tqe_prev ; else (&sd->sd_wu_freeq)->tqh_last = (wu)->swu_link .tqe_prev; *(wu)->swu_link.tqe_prev = (wu)->swu_link.tqe_next ; ((wu)->swu_link.tqe_prev) = ((void *)-1); ((wu)->swu_link .tqe_next) = ((void *)-1); } while (0); | |||
| 2133 | sd->sd_wu_pending++; | |||
| 2134 | } | |||
| 2135 | mtx_leave(&sd->sd_wu_mtx); | |||
| 2136 | ||||
| 2137 | DNPRINTF(SR_D_WU, "%s: sr_wu_get: %p\n", DEVNAME(sd->sd_sc), wu); | |||
| 2138 | ||||
| 2139 | return (wu); | |||
| 2140 | } | |||
| 2141 | ||||
| 2142 | void | |||
| 2143 | sr_wu_put(void *xsd, void *xwu) | |||
| 2144 | { | |||
| 2145 | struct sr_discipline *sd = (struct sr_discipline *)xsd; | |||
| 2146 | struct sr_workunit *wu = (struct sr_workunit *)xwu; | |||
| 2147 | ||||
| 2148 | DNPRINTF(SR_D_WU, "%s: sr_wu_put: %p\n", DEVNAME(sd->sd_sc), wu); | |||
| 2149 | ||||
| 2150 | sr_wu_release_ccbs(wu); | |||
| 2151 | sr_wu_init(sd, wu); | |||
| 2152 | ||||
| 2153 | mtx_enter(&sd->sd_wu_mtx); | |||
| 2154 | TAILQ_INSERT_TAIL(&sd->sd_wu_freeq, wu, swu_link)do { (wu)->swu_link.tqe_next = ((void *)0); (wu)->swu_link .tqe_prev = (&sd->sd_wu_freeq)->tqh_last; *(&sd ->sd_wu_freeq)->tqh_last = (wu); (&sd->sd_wu_freeq )->tqh_last = &(wu)->swu_link.tqe_next; } while (0); | |||
| 2155 | sd->sd_wu_pending--; | |||
| 2156 | mtx_leave(&sd->sd_wu_mtx); | |||
| 2157 | } | |||
| 2158 | ||||
| 2159 | void | |||
| 2160 | sr_wu_init(struct sr_discipline *sd, struct sr_workunit *wu) | |||
| 2161 | { | |||
| 2162 | int s; | |||
| 2163 | ||||
| 2164 | s = splbio()splraise(0x3); | |||
| 2165 | if (wu->swu_cb_active == 1) | |||
| 2166 | panic("%s: sr_wu_init got active wu", DEVNAME(sd->sd_sc)((sd->sd_sc)->sc_dev.dv_xname)); | |||
| 2167 | splx(s)spllower(s); | |||
| 2168 | ||||
| 2169 | wu->swu_xs = NULL((void *)0); | |||
| 2170 | wu->swu_state = SR_WU_FREE0; | |||
| 2171 | wu->swu_flags = 0; | |||
| 2172 | wu->swu_blk_start = 0; | |||
| 2173 | wu->swu_blk_end = 0; | |||
| 2174 | wu->swu_collider = NULL((void *)0); | |||
| 2175 | } | |||
| 2176 | ||||
| 2177 | void | |||
| 2178 | sr_wu_enqueue_ccb(struct sr_workunit *wu, struct sr_ccb *ccb) | |||
| 2179 | { | |||
| 2180 | struct sr_discipline *sd = wu->swu_dis; | |||
| 2181 | int s; | |||
| 2182 | ||||
| 2183 | s = splbio()splraise(0x3); | |||
| 2184 | if (wu->swu_cb_active == 1) | |||
| 2185 | panic("%s: sr_wu_enqueue_ccb got active wu", | |||
| 2186 | DEVNAME(sd->sd_sc)((sd->sd_sc)->sc_dev.dv_xname)); | |||
| 2187 | ccb->ccb_wu = wu; | |||
| 2188 | wu->swu_io_count++; | |||
| 2189 | TAILQ_INSERT_TAIL(&wu->swu_ccb, ccb, ccb_link)do { (ccb)->ccb_link.tqe_next = ((void *)0); (ccb)->ccb_link .tqe_prev = (&wu->swu_ccb)->tqh_last; *(&wu-> swu_ccb)->tqh_last = (ccb); (&wu->swu_ccb)->tqh_last = &(ccb)->ccb_link.tqe_next; } while (0); | |||
| 2190 | splx(s)spllower(s); | |||
| 2191 | } | |||
| 2192 | ||||
| 2193 | void | |||
| 2194 | sr_wu_release_ccbs(struct sr_workunit *wu) | |||
| 2195 | { | |||
| 2196 | struct sr_ccb *ccb; | |||
| 2197 | ||||
| 2198 | /* Return all ccbs that are associated with this workunit. */ | |||
| 2199 | while ((ccb = TAILQ_FIRST(&wu->swu_ccb)((&wu->swu_ccb)->tqh_first)) != NULL((void *)0)) { | |||
| 2200 | TAILQ_REMOVE(&wu->swu_ccb, ccb, ccb_link)do { if (((ccb)->ccb_link.tqe_next) != ((void *)0)) (ccb)-> ccb_link.tqe_next->ccb_link.tqe_prev = (ccb)->ccb_link. tqe_prev; else (&wu->swu_ccb)->tqh_last = (ccb)-> ccb_link.tqe_prev; *(ccb)->ccb_link.tqe_prev = (ccb)->ccb_link .tqe_next; ((ccb)->ccb_link.tqe_prev) = ((void *)-1); ((ccb )->ccb_link.tqe_next) = ((void *)-1); } while (0); | |||
| 2201 | sr_ccb_put(ccb); | |||
| 2202 | } | |||
| 2203 | ||||
| 2204 | wu->swu_io_count = 0; | |||
| 2205 | wu->swu_ios_complete = 0; | |||
| 2206 | wu->swu_ios_failed = 0; | |||
| 2207 | wu->swu_ios_succeeded = 0; | |||
| 2208 | } | |||
| 2209 | ||||
| 2210 | void | |||
| 2211 | sr_wu_done(struct sr_workunit *wu) | |||
| 2212 | { | |||
| 2213 | struct sr_discipline *sd = wu->swu_dis; | |||
| 2214 | ||||
| 2215 | DNPRINTF(SR_D_INTR, "%s: sr_wu_done count %d completed %d failed %d\n", | |||
| 2216 | DEVNAME(sd->sd_sc), wu->swu_io_count, wu->swu_ios_complete, | |||
| 2217 | wu->swu_ios_failed); | |||
| 2218 | ||||
| 2219 | if (wu->swu_ios_complete < wu->swu_io_count) | |||
| 2220 | return; | |||
| 2221 | ||||
| 2222 | task_add(sd->sd_taskq, &wu->swu_task); | |||
| 2223 | } | |||
| 2224 | ||||
| 2225 | void | |||
| 2226 | sr_wu_done_callback(void *xwu) | |||
| 2227 | { | |||
| 2228 | struct sr_workunit *wu = xwu; | |||
| 2229 | struct sr_discipline *sd = wu->swu_dis; | |||
| 2230 | struct scsi_xfer *xs = wu->swu_xs; | |||
| 2231 | struct sr_workunit *wup; | |||
| 2232 | int s; | |||
| 2233 | ||||
| 2234 | /* | |||
| 2235 | * The SR_WUF_DISCIPLINE or SR_WUF_REBUILD flag must be set if | |||
| 2236 | * the work unit is not associated with a scsi_xfer. | |||
| 2237 | */ | |||
| 2238 | KASSERT(xs != NULL ||((xs != ((void *)0) || (wu->swu_flags & ((1<<5)| (1<<0)))) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/softraid.c" , 2239, "xs != NULL || (wu->swu_flags & (SR_WUF_DISCIPLINE|SR_WUF_REBUILD))" )) | |||
| 2239 | (wu->swu_flags & (SR_WUF_DISCIPLINE|SR_WUF_REBUILD)))((xs != ((void *)0) || (wu->swu_flags & ((1<<5)| (1<<0)))) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/softraid.c" , 2239, "xs != NULL || (wu->swu_flags & (SR_WUF_DISCIPLINE|SR_WUF_REBUILD))" )); | |||
| 2240 | ||||
| 2241 | s = splbio()splraise(0x3); | |||
| 2242 | ||||
| 2243 | if (xs != NULL((void *)0)) { | |||
| 2244 | if (wu->swu_ios_failed) | |||
| 2245 | xs->error = XS_DRIVER_STUFFUP2; | |||
| 2246 | else | |||
| 2247 | xs->error = XS_NOERROR0; | |||
| 2248 | } | |||
| 2249 | ||||
| 2250 | if (sd->sd_scsi_wu_done) { | |||
| 2251 | if (sd->sd_scsi_wu_done(wu) == SR_WU_RESTART7) | |||
| 2252 | goto done; | |||
| 2253 | } | |||
| 2254 | ||||
| 2255 | /* Remove work unit from pending queue. */ | |||
| 2256 | TAILQ_FOREACH(wup, &sd->sd_wu_pendq, swu_link)for((wup) = ((&sd->sd_wu_pendq)->tqh_first); (wup) != ((void *)0); (wup) = ((wup)->swu_link.tqe_next)) | |||
| 2257 | if (wup == wu) | |||
| 2258 | break; | |||
| 2259 | if (wup == NULL((void *)0)) | |||
| 2260 | panic("%s: wu %p not on pending queue", | |||
| 2261 | DEVNAME(sd->sd_sc)((sd->sd_sc)->sc_dev.dv_xname), wu); | |||
| 2262 | TAILQ_REMOVE(&sd->sd_wu_pendq, wu, swu_link)do { if (((wu)->swu_link.tqe_next) != ((void *)0)) (wu)-> swu_link.tqe_next->swu_link.tqe_prev = (wu)->swu_link.tqe_prev ; else (&sd->sd_wu_pendq)->tqh_last = (wu)->swu_link .tqe_prev; *(wu)->swu_link.tqe_prev = (wu)->swu_link.tqe_next ; ((wu)->swu_link.tqe_prev) = ((void *)-1); ((wu)->swu_link .tqe_next) = ((void *)-1); } while (0); | |||
| 2263 | ||||
| 2264 | if (wu->swu_collider) { | |||
| 2265 | if (wu->swu_ios_failed) | |||
| 2266 | sr_raid_recreate_wu(wu->swu_collider); | |||
| 2267 | ||||
| 2268 | /* XXX Should the collider be failed if this xs failed? */ | |||
| 2269 | sr_raid_startwu(wu->swu_collider); | |||
| 2270 | } | |||
| 2271 | ||||
| 2272 | /* | |||
| 2273 | * If a discipline provides its own sd_scsi_done function, then it | |||
| 2274 | * is responsible for calling sr_scsi_done() once I/O is complete. | |||
| 2275 | */ | |||
| 2276 | if (wu->swu_flags & SR_WUF_REBUILD(1<<0)) | |||
| 2277 | wu->swu_flags |= SR_WUF_REBUILDIOCOMP(1<<1); | |||
| 2278 | if (wu->swu_flags & SR_WUF_WAKEUP(1<<4)) | |||
| 2279 | wakeup(wu); | |||
| 2280 | if (sd->sd_scsi_done) | |||
| 2281 | sd->sd_scsi_done(wu); | |||
| 2282 | else if (wu->swu_flags & SR_WUF_DISCIPLINE(1<<5)) | |||
| 2283 | sr_scsi_wu_put(sd, wu); | |||
| 2284 | else if (!(wu->swu_flags & SR_WUF_REBUILD(1<<0))) | |||
| 2285 | sr_scsi_done(sd, xs); | |||
| 2286 | ||||
| 2287 | done: | |||
| 2288 | splx(s)spllower(s); | |||
| 2289 | } | |||
| 2290 | ||||
| 2291 | struct sr_workunit * | |||
| 2292 | sr_scsi_wu_get(struct sr_discipline *sd, int flags) | |||
| 2293 | { | |||
| 2294 | return scsi_io_get(&sd->sd_iopool, flags); | |||
| 2295 | } | |||
| 2296 | ||||
| 2297 | void | |||
| 2298 | sr_scsi_wu_put(struct sr_discipline *sd, struct sr_workunit *wu) | |||
| 2299 | { | |||
| 2300 | scsi_io_put(&sd->sd_iopool, wu); | |||
| 2301 | ||||
| 2302 | if (sd->sd_sync && sd->sd_wu_pending == 0) | |||
| 2303 | wakeup(sd); | |||
| 2304 | } | |||
| 2305 | ||||
| 2306 | void | |||
| 2307 | sr_scsi_done(struct sr_discipline *sd, struct scsi_xfer *xs) | |||
| 2308 | { | |||
| 2309 | DNPRINTF(SR_D_DIS, "%s: sr_scsi_done: xs %p\n", DEVNAME(sd->sd_sc), xs); | |||
| 2310 | ||||
| 2311 | if (xs->error == XS_NOERROR0) | |||
| 2312 | xs->resid = 0; | |||
| 2313 | ||||
| 2314 | scsi_done(xs); | |||
| 2315 | ||||
| 2316 | if (sd->sd_sync && sd->sd_wu_pending == 0) | |||
| 2317 | wakeup(sd); | |||
| 2318 | } | |||
| 2319 | ||||
| 2320 | void | |||
| 2321 | sr_scsi_cmd(struct scsi_xfer *xs) | |||
| 2322 | { | |||
| 2323 | struct scsi_link *link = xs->sc_link; | |||
| 2324 | struct sr_softc *sc = link->bus->sb_adapter_softc; | |||
| 2325 | struct sr_workunit *wu = xs->io; | |||
| 2326 | struct sr_discipline *sd; | |||
| 2327 | ||||
| 2328 | DNPRINTF(SR_D_CMD, "%s: sr_scsi_cmd target %d xs %p flags %#x\n", | |||
| 2329 | DEVNAME(sc), link->target, xs, xs->flags); | |||
| 2330 | ||||
| 2331 | sd = sc->sc_targets[link->target]; | |||
| 2332 | if (sd == NULL((void *)0)) | |||
| 2333 | panic("%s: sr_scsi_cmd NULL discipline", DEVNAME(sc)((sc)->sc_dev.dv_xname)); | |||
| 2334 | ||||
| 2335 | if (sd->sd_deleted) { | |||
| 2336 | printf("%s: %s device is being deleted, failing io\n", | |||
| 2337 | DEVNAME(sc)((sc)->sc_dev.dv_xname), sd->sd_meta->ssd_devname); | |||
| 2338 | goto stuffup; | |||
| 2339 | } | |||
| 2340 | ||||
| 2341 | /* scsi layer *can* re-send wu without calling sr_wu_put(). */ | |||
| 2342 | sr_wu_release_ccbs(wu); | |||
| 2343 | sr_wu_init(sd, wu); | |||
| 2344 | wu->swu_state = SR_WU_INPROGRESS1; | |||
| 2345 | wu->swu_xs = xs; | |||
| 2346 | ||||
| 2347 | switch (xs->cmd.opcode) { | |||
| 2348 | case READ_COMMAND0x08: | |||
| 2349 | case READ_100x28: | |||
| 2350 | case READ_160x88: | |||
| 2351 | case WRITE_COMMAND0x0a: | |||
| 2352 | case WRITE_100x2a: | |||
| 2353 | case WRITE_160x8a: | |||
| 2354 | DNPRINTF(SR_D_CMD, "%s: sr_scsi_cmd: READ/WRITE %02x\n", | |||
| 2355 | DEVNAME(sc), xs->cmd.opcode); | |||
| 2356 | if (sd->sd_scsi_rw(wu)) | |||
| 2357 | goto stuffup; | |||
| 2358 | break; | |||
| 2359 | ||||
| 2360 | case SYNCHRONIZE_CACHE0x35: | |||
| 2361 | DNPRINTF(SR_D_CMD, "%s: sr_scsi_cmd: SYNCHRONIZE_CACHE\n", | |||
| 2362 | DEVNAME(sc)); | |||
| 2363 | if (sd->sd_scsi_sync(wu)) | |||
| 2364 | goto stuffup; | |||
| 2365 | goto complete; | |||
| 2366 | ||||
| 2367 | case TEST_UNIT_READY0x00: | |||
| 2368 | DNPRINTF(SR_D_CMD, "%s: sr_scsi_cmd: TEST_UNIT_READY\n", | |||
| 2369 | DEVNAME(sc)); | |||
| 2370 | if (sd->sd_scsi_tur(wu)) | |||
| 2371 | goto stuffup; | |||
| 2372 | goto complete; | |||
| 2373 | ||||
| 2374 | case START_STOP0x1b: | |||
| 2375 | DNPRINTF(SR_D_CMD, "%s: sr_scsi_cmd: START_STOP\n", | |||
| 2376 | DEVNAME(sc)); | |||
| 2377 | if (sd->sd_scsi_start_stop(wu)) | |||
| 2378 | goto stuffup; | |||
| 2379 | goto complete; | |||
| 2380 | ||||
| 2381 | case INQUIRY0x12: | |||
| 2382 | DNPRINTF(SR_D_CMD, "%s: sr_scsi_cmd: INQUIRY\n", | |||
| 2383 | DEVNAME(sc)); | |||
| 2384 | if (sd->sd_scsi_inquiry(wu)) | |||
| 2385 | goto stuffup; | |||
| 2386 | goto complete; | |||
| 2387 | ||||
| 2388 | case READ_CAPACITY0x25: | |||
| 2389 | case READ_CAPACITY_160x9e: | |||
| 2390 | DNPRINTF(SR_D_CMD, "%s: sr_scsi_cmd READ CAPACITY 0x%02x\n", | |||
| 2391 | DEVNAME(sc), xs->cmd.opcode); | |||
| 2392 | if (sd->sd_scsi_read_cap(wu)) | |||
| 2393 | goto stuffup; | |||
| 2394 | goto complete; | |||
| 2395 | ||||
| 2396 | case REQUEST_SENSE0x03: | |||
| 2397 | DNPRINTF(SR_D_CMD, "%s: sr_scsi_cmd REQUEST SENSE\n", | |||
| 2398 | DEVNAME(sc)); | |||
| 2399 | if (sd->sd_scsi_req_sense(wu)) | |||
| 2400 | goto stuffup; | |||
| 2401 | goto complete; | |||
| 2402 | ||||
| 2403 | default: | |||
| 2404 | DNPRINTF(SR_D_CMD, "%s: unsupported scsi command %x\n", | |||
| 2405 | DEVNAME(sc), xs->cmd.opcode); | |||
| 2406 | /* XXX might need to add generic function to handle others */ | |||
| 2407 | goto stuffup; | |||
| 2408 | } | |||
| 2409 | ||||
| 2410 | return; | |||
| 2411 | stuffup: | |||
| 2412 | if (sd->sd_scsi_sense.error_code) { | |||
| 2413 | xs->error = XS_SENSE1; | |||
| 2414 | memcpy(&xs->sense, &sd->sd_scsi_sense, sizeof(xs->sense))__builtin_memcpy((&xs->sense), (&sd->sd_scsi_sense ), (sizeof(xs->sense))); | |||
| 2415 | bzero(&sd->sd_scsi_sense, sizeof(sd->sd_scsi_sense))__builtin_bzero((&sd->sd_scsi_sense), (sizeof(sd->sd_scsi_sense ))); | |||
| 2416 | } else { | |||
| 2417 | xs->error = XS_DRIVER_STUFFUP2; | |||
| 2418 | } | |||
| 2419 | complete: | |||
| 2420 | sr_scsi_done(sd, xs); | |||
| 2421 | } | |||
| 2422 | ||||
| 2423 | int | |||
| 2424 | sr_scsi_probe(struct scsi_link *link) | |||
| 2425 | { | |||
| 2426 | struct sr_softc *sc = link->bus->sb_adapter_softc; | |||
| 2427 | struct sr_discipline *sd; | |||
| 2428 | ||||
| 2429 | KASSERT(link->target < SR_MAX_LD && link->lun == 0)((link->target < 256 && link->lun == 0) ? (void )0 : __assert("diagnostic ", "/usr/src/sys/dev/softraid.c", 2429 , "link->target < SR_MAX_LD && link->lun == 0" )); | |||
| 2430 | ||||
| 2431 | sd = sc->sc_targets[link->target]; | |||
| 2432 | if (sd == NULL((void *)0)) | |||
| 2433 | return (ENODEV19); | |||
| 2434 | ||||
| 2435 | link->pool = &sd->sd_iopool; | |||
| 2436 | if (sd->sd_openings) | |||
| 2437 | link->openings = sd->sd_openings(sd); | |||
| 2438 | else | |||
| 2439 | link->openings = sd->sd_max_wu; | |||
| 2440 | ||||
| 2441 | return (0); | |||
| 2442 | } | |||
| 2443 | ||||
| 2444 | int | |||
| 2445 | sr_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag) | |||
| 2446 | { | |||
| 2447 | struct sr_softc *sc = link->bus->sb_adapter_softc; | |||
| 2448 | struct sr_discipline *sd; | |||
| 2449 | ||||
| 2450 | sd = sc->sc_targets[link->target]; | |||
| 2451 | if (sd == NULL((void *)0)) | |||
| 2452 | return (ENODEV19); | |||
| 2453 | ||||
| 2454 | DNPRINTF(SR_D_IOCTL, "%s: %s sr_scsi_ioctl cmd: %#lx\n", | |||
| 2455 | DEVNAME(sc), sd->sd_meta->ssd_devname, cmd); | |||
| 2456 | ||||
| 2457 | /* Pass bio ioctls through to the bio handler. */ | |||
| 2458 | if (IOCGROUP(cmd)(((cmd) >> 8) & 0xff) == 'B') | |||
| 2459 | return (sr_bio_handler(sc, sd, cmd, (struct bio *)addr)); | |||
| 2460 | ||||
| 2461 | switch (cmd) { | |||
| 2462 | case DIOCGCACHE((unsigned long)0x40000000 | ((sizeof(struct dk_cache) & 0x1fff ) << 16) | ((('d')) << 8) | ((117))): | |||
| 2463 | case DIOCSCACHE((unsigned long)0x80000000 | ((sizeof(struct dk_cache) & 0x1fff ) << 16) | ((('d')) << 8) | ((118))): | |||
| 2464 | return (EOPNOTSUPP45); | |||
| 2465 | default: | |||
| 2466 | return (ENOTTY25); | |||
| 2467 | } | |||
| 2468 | } | |||
| 2469 | ||||
| 2470 | int | |||
| 2471 | sr_bio_ioctl(struct device *dev, u_long cmd, caddr_t addr) | |||
| 2472 | { | |||
| 2473 | struct sr_softc *sc = (struct sr_softc *) dev; | |||
| 2474 | DNPRINTF(SR_D_IOCTL, "%s: sr_bio_ioctl\n", DEVNAME(sc)); | |||
| 2475 | ||||
| 2476 | return sr_bio_handler(sc, NULL((void *)0), cmd, (struct bio *)addr); | |||
| 2477 | } | |||
| 2478 | ||||
| 2479 | int | |||
| 2480 | sr_bio_handler(struct sr_softc *sc, struct sr_discipline *sd, u_long cmd, | |||
| 2481 | struct bio *bio) | |||
| 2482 | { | |||
| 2483 | int rv = 0; | |||
| 2484 | ||||
| 2485 | DNPRINTF(SR_D_IOCTL, "%s: sr_bio_handler ", DEVNAME(sc)); | |||
| 2486 | ||||
| 2487 | rw_enter_write(&sc->sc_lock); | |||
| 2488 | ||||
| 2489 | bio_status_init(&sc->sc_status, &sc->sc_dev); | |||
| 2490 | ||||
| 2491 | switch (cmd) { | |||
| 2492 | case BIOCINQ(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct bioc_inq) & 0x1fff) << 16) | ((('B')) << 8) | ((32))): | |||
| 2493 | DNPRINTF(SR_D_IOCTL, "inq\n"); | |||
| 2494 | rv = sr_ioctl_inq(sc, (struct bioc_inq *)bio); | |||
| 2495 | break; | |||
| 2496 | ||||
| 2497 | case BIOCVOL(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct bioc_vol) & 0x1fff) << 16) | ((('B')) << 8) | ((34))): | |||
| 2498 | DNPRINTF(SR_D_IOCTL, "vol\n"); | |||
| 2499 | rv = sr_ioctl_vol(sc, (struct bioc_vol *)bio); | |||
| 2500 | break; | |||
| 2501 | ||||
| 2502 | case BIOCDISK(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct bioc_disk) & 0x1fff) << 16) | ((('B')) << 8) | ((33))): | |||
| 2503 | DNPRINTF(SR_D_IOCTL, "disk\n"); | |||
| 2504 | rv = sr_ioctl_disk(sc, (struct bioc_disk *)bio); | |||
| 2505 | break; | |||
| 2506 | ||||
| 2507 | case BIOCALARM(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct bioc_alarm) & 0x1fff) << 16) | ((('B')) << 8) | ((35))): | |||
| 2508 | DNPRINTF(SR_D_IOCTL, "alarm\n"); | |||
| 2509 | /*rv = sr_ioctl_alarm(sc, (struct bioc_alarm *)bio); */ | |||
| 2510 | break; | |||
| 2511 | ||||
| 2512 | case BIOCBLINK(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct bioc_blink) & 0x1fff) << 16) | ((('B')) << 8) | ((36))): | |||
| 2513 | DNPRINTF(SR_D_IOCTL, "blink\n"); | |||
| 2514 | /*rv = sr_ioctl_blink(sc, (struct bioc_blink *)bio); */ | |||
| 2515 | break; | |||
| 2516 | ||||
| 2517 | case BIOCSETSTATE(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct bioc_setstate) & 0x1fff) << 16) | ((('B')) << 8) | ((37))): | |||
| 2518 | DNPRINTF(SR_D_IOCTL, "setstate\n"); | |||
| 2519 | rv = sr_ioctl_setstate(sc, (struct bioc_setstate *)bio); | |||
| 2520 | break; | |||
| 2521 | ||||
| 2522 | case BIOCCREATERAID(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct bioc_createraid) & 0x1fff) << 16) | ((('B') ) << 8) | ((38))): | |||
| 2523 | DNPRINTF(SR_D_IOCTL, "createraid\n"); | |||
| 2524 | rv = sr_ioctl_createraid(sc, (struct bioc_createraid *)bio, | |||
| 2525 | 1, NULL((void *)0)); | |||
| 2526 | break; | |||
| 2527 | ||||
| 2528 | case BIOCDELETERAID(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct bioc_deleteraid) & 0x1fff) << 16) | ((('B') ) << 8) | ((39))): | |||
| 2529 | DNPRINTF(SR_D_IOCTL, "deleteraid\n"); | |||
| 2530 | rv = sr_ioctl_deleteraid(sc, sd, (struct bioc_deleteraid *)bio); | |||
| 2531 | break; | |||
| 2532 | ||||
| 2533 | case BIOCDISCIPLINE(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct bioc_discipline) & 0x1fff) << 16) | ((('B') ) << 8) | ((40))): | |||
| 2534 | DNPRINTF(SR_D_IOCTL, "discipline\n"); | |||
| 2535 | rv = sr_ioctl_discipline(sc, sd, (struct bioc_discipline *)bio); | |||
| 2536 | break; | |||
| 2537 | ||||
| 2538 | case BIOCINSTALLBOOT(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct bioc_installboot) & 0x1fff) << 16) | ((('B' )) << 8) | ((41))): | |||
| 2539 | DNPRINTF(SR_D_IOCTL, "installboot\n"); | |||
| 2540 | rv = sr_ioctl_installboot(sc, sd, | |||
| 2541 | (struct bioc_installboot *)bio); | |||
| 2542 | break; | |||
| 2543 | ||||
| 2544 | default: | |||
| 2545 | DNPRINTF(SR_D_IOCTL, "invalid ioctl\n"); | |||
| 2546 | rv = ENOTTY25; | |||
| 2547 | } | |||
| 2548 | ||||
| 2549 | sc->sc_status.bs_status = (rv ? BIO_STATUS_ERROR2 : BIO_STATUS_SUCCESS1); | |||
| 2550 | ||||
| 2551 | if (sc->sc_status.bs_msg_count > 0) | |||
| 2552 | rv = 0; | |||
| 2553 | ||||
| 2554 | memcpy(&bio->bio_status, &sc->sc_status, sizeof(struct bio_status))__builtin_memcpy((&bio->bio_status), (&sc->sc_status ), (sizeof(struct bio_status))); | |||
| 2555 | ||||
| 2556 | rw_exit_write(&sc->sc_lock); | |||
| 2557 | ||||
| 2558 | return (rv); | |||
| 2559 | } | |||
| 2560 | ||||
| 2561 | int | |||
| 2562 | sr_ioctl_inq(struct sr_softc *sc, struct bioc_inq *bi) | |||
| 2563 | { | |||
| 2564 | struct sr_discipline *sd; | |||
| 2565 | int vol = 0, disk = 0; | |||
| 2566 | ||||
| 2567 | TAILQ_FOREACH(sd, &sc->sc_dis_list, sd_link)for((sd) = ((&sc->sc_dis_list)->tqh_first); (sd) != ((void *)0); (sd) = ((sd)->sd_link.tqe_next)) { | |||
| 2568 | vol++; | |||
| 2569 | disk += sd->sd_meta->ssdi_sdd_invariant.ssd_chunk_no; | |||
| 2570 | } | |||
| 2571 | ||||
| 2572 | strlcpy(bi->bi_dev, sc->sc_dev.dv_xname, sizeof(bi->bi_dev)); | |||
| 2573 | bi->bi_novol = vol + sc->sc_hotspare_no; | |||
| 2574 | bi->bi_nodisk = disk + sc->sc_hotspare_no; | |||
| 2575 | ||||
| 2576 | return (0); | |||
| 2577 | } | |||
| 2578 | ||||
| 2579 | int | |||
| 2580 | sr_ioctl_vol(struct sr_softc *sc, struct bioc_vol *bv) | |||
| 2581 | { | |||
| 2582 | int vol = -1, rv = EINVAL22; | |||
| 2583 | struct sr_discipline *sd; | |||
| 2584 | struct sr_chunk *hotspare; | |||
| 2585 | ||||
| 2586 | TAILQ_FOREACH(sd, &sc->sc_dis_list, sd_link)for((sd) = ((&sc->sc_dis_list)->tqh_first); (sd) != ((void *)0); (sd) = ((sd)->sd_link.tqe_next)) { | |||
| 2587 | vol++; | |||
| 2588 | if (vol != bv->bv_volid) | |||
| 2589 | continue; | |||
| 2590 | ||||
| 2591 | bv->bv_status = sd->sd_vol_status; | |||
| 2592 | bv->bv_size = sd->sd_meta->ssdi_sdd_invariant.ssd_size << DEV_BSHIFT9; | |||
| 2593 | bv->bv_level = sd->sd_meta->ssdi_sdd_invariant.ssd_level; | |||
| 2594 | bv->bv_nodisk = sd->sd_meta->ssdi_sdd_invariant.ssd_chunk_no; | |||
| 2595 | ||||
| 2596 | #ifdef CRYPTO1 | |||
| 2597 | if (sd->sd_meta->ssdi_sdd_invariant.ssd_level == 'C' && | |||
| 2598 | sd->mdssd_dis_specific.mdd_crypto.key_disk != NULL((void *)0)) | |||
| 2599 | bv->bv_nodisk++; | |||
| 2600 | else if (sd->sd_meta->ssdi_sdd_invariant.ssd_level == 0x1C && | |||
| 2601 | sd->mdssd_dis_specific.mdd_raid1c.sr1c_crypto.key_disk != NULL((void *)0)) | |||
| 2602 | bv->bv_nodisk++; | |||
| 2603 | #endif | |||
| 2604 | if (bv->bv_status == BIOC_SVREBUILD0x05) | |||
| 2605 | bv->bv_percent = sr_rebuild_percent(sd); | |||
| 2606 | ||||
| 2607 | strlcpy(bv->bv_dev, sd->sd_meta->ssd_devname, | |||
| 2608 | sizeof(bv->bv_dev)); | |||
| 2609 | strlcpy(bv->bv_vendor, sd->sd_meta->ssdi_sdd_invariant.ssd_vendor, | |||
| 2610 | sizeof(bv->bv_vendor)); | |||
| 2611 | rv = 0; | |||
| 2612 | goto done; | |||
| 2613 | } | |||
| 2614 | ||||
| 2615 | /* Check hotspares list. */ | |||
| 2616 | SLIST_FOREACH(hotspare, &sc->sc_hotspare_list, src_link)for((hotspare) = ((&sc->sc_hotspare_list)->slh_first ); (hotspare) != ((void *)0); (hotspare) = ((hotspare)->src_link .sle_next)) { | |||
| 2617 | vol++; | |||
| 2618 | if (vol != bv->bv_volid) | |||
| 2619 | continue; | |||
| 2620 | ||||
| 2621 | bv->bv_status = BIOC_SVONLINE0x00; | |||
| 2622 | bv->bv_size = hotspare->src_meta.scmi_scm_invariant.scm_size << DEV_BSHIFT9; | |||
| 2623 | bv->bv_level = -1; /* Hotspare. */ | |||
| 2624 | bv->bv_nodisk = 1; | |||
| 2625 | strlcpy(bv->bv_dev, hotspare->src_meta.scmi_scm_invariant.scm_devname, | |||
| 2626 | sizeof(bv->bv_dev)); | |||
| 2627 | strlcpy(bv->bv_vendor, hotspare->src_meta.scmi_scm_invariant.scm_devname, | |||
| 2628 | sizeof(bv->bv_vendor)); | |||
| 2629 | rv = 0; | |||
| 2630 | goto done; | |||
| 2631 | } | |||
| 2632 | ||||
| 2633 | done: | |||
| 2634 | return (rv); | |||
| 2635 | } | |||
| 2636 | ||||
| 2637 | int | |||
| 2638 | sr_ioctl_disk(struct sr_softc *sc, struct bioc_disk *bd) | |||
| 2639 | { | |||
| 2640 | struct sr_discipline *sd; | |||
| 2641 | struct sr_chunk *src, *hotspare; | |||
| 2642 | int vol = -1, rv = EINVAL22; | |||
| 2643 | ||||
| 2644 | if (bd->bd_diskid < 0) | |||
| 2645 | goto done; | |||
| 2646 | ||||
| 2647 | TAILQ_FOREACH(sd, &sc->sc_dis_list, sd_link)for((sd) = ((&sc->sc_dis_list)->tqh_first); (sd) != ((void *)0); (sd) = ((sd)->sd_link.tqe_next)) { | |||
| 2648 | vol++; | |||
| 2649 | if (vol != bd->bd_volid) | |||
| 2650 | continue; | |||
| 2651 | ||||
| 2652 | if (bd->bd_diskid < sd->sd_meta->ssdi_sdd_invariant.ssd_chunk_no) | |||
| 2653 | src = sd->sd_vol.sv_chunks[bd->bd_diskid]; | |||
| 2654 | #ifdef CRYPTO1 | |||
| 2655 | else if (bd->bd_diskid == sd->sd_meta->ssdi_sdd_invariant.ssd_chunk_no && | |||
| 2656 | sd->sd_meta->ssdi_sdd_invariant.ssd_level == 'C' && | |||
| 2657 | sd->mdssd_dis_specific.mdd_crypto.key_disk != NULL((void *)0)) | |||
| 2658 | src = sd->mdssd_dis_specific.mdd_crypto.key_disk; | |||
| 2659 | else if (bd->bd_diskid == sd->sd_meta->ssdi_sdd_invariant.ssd_chunk_no && | |||
| 2660 | sd->sd_meta->ssdi_sdd_invariant.ssd_level == 0x1C && | |||
| 2661 | sd->mdssd_dis_specific.mdd_raid1c.sr1c_crypto.key_disk != NULL((void *)0)) | |||
| 2662 | src = sd->mdssd_dis_specific.mdd_crypto.key_disk; | |||
| 2663 | #endif | |||
| 2664 | else | |||
| 2665 | break; | |||
| 2666 | ||||
| 2667 | bd->bd_status = src->src_meta.scm_status; | |||
| 2668 | bd->bd_size = src->src_meta.scmi_scm_invariant.scm_size << DEV_BSHIFT9; | |||
| 2669 | bd->bd_channel = vol; | |||
| 2670 | bd->bd_target = bd->bd_diskid; | |||
| 2671 | strlcpy(bd->bd_vendor, src->src_meta.scmi_scm_invariant.scm_devname, | |||
| 2672 | sizeof(bd->bd_vendor)); | |||
| 2673 | rv = 0; | |||
| 2674 | goto done; | |||
| 2675 | } | |||
| 2676 | ||||
| 2677 | /* Check hotspares list. */ | |||
| 2678 | SLIST_FOREACH(hotspare, &sc->sc_hotspare_list, src_link)for((hotspare) = ((&sc->sc_hotspare_list)->slh_first ); (hotspare) != ((void *)0); (hotspare) = ((hotspare)->src_link .sle_next)) { | |||
| 2679 | vol++; | |||
| 2680 | if (vol != bd->bd_volid) | |||
| 2681 | continue; | |||
| 2682 | ||||
| 2683 | if (bd->bd_diskid != 0) | |||
| 2684 | break; | |||
| 2685 | ||||
| 2686 | bd->bd_status = hotspare->src_meta.scm_status; | |||
| 2687 | bd->bd_size = hotspare->src_meta.scmi_scm_invariant.scm_size << DEV_BSHIFT9; | |||
| 2688 | bd->bd_channel = vol; | |||
| 2689 | bd->bd_target = bd->bd_diskid; | |||
| 2690 | strlcpy(bd->bd_vendor, hotspare->src_meta.scmi_scm_invariant.scm_devname, | |||
| 2691 | sizeof(bd->bd_vendor)); | |||
| 2692 | rv = 0; | |||
| 2693 | goto done; | |||
| 2694 | } | |||
| 2695 | ||||
| 2696 | done: | |||
| 2697 | return (rv); | |||
| 2698 | } | |||
| 2699 | ||||
| 2700 | int | |||
| 2701 | sr_ioctl_setstate(struct sr_softc *sc, struct bioc_setstate *bs) | |||
| 2702 | { | |||
| 2703 | int rv = EINVAL22; | |||
| 2704 | int vol = -1, found, c; | |||
| 2705 | struct sr_discipline *sd; | |||
| 2706 | struct sr_chunk *ch_entry; | |||
| 2707 | struct sr_chunk_head *cl; | |||
| 2708 | ||||
| 2709 | if (bs->bs_other_id_type == BIOC_SSOTHER_UNUSED0x00) | |||
| 2710 | goto done; | |||
| 2711 | ||||
| 2712 | if (bs->bs_status == BIOC_SSHOTSPARE0x02) { | |||
| 2713 | rv = sr_hotspare(sc, (dev_t)bs->bs_other_id); | |||
| 2714 | goto done; | |||
| 2715 | } | |||
| 2716 | ||||
| 2717 | TAILQ_FOREACH(sd, &sc->sc_dis_list, sd_link)for((sd) = ((&sc->sc_dis_list)->tqh_first); (sd) != ((void *)0); (sd) = ((sd)->sd_link.tqe_next)) { | |||
| 2718 | vol++; | |||
| 2719 | if (vol == bs->bs_volid) | |||
| 2720 | break; | |||
| 2721 | } | |||
| 2722 | if (sd == NULL((void *)0)) | |||
| 2723 | goto done; | |||
| 2724 | ||||
| 2725 | switch (bs->bs_status) { | |||
| 2726 | case BIOC_SSOFFLINE0x01: | |||
| 2727 | /* Take chunk offline */ | |||
| 2728 | found = c = 0; | |||
| 2729 | cl = &sd->sd_vol.sv_chunk_list; | |||
| 2730 | SLIST_FOREACH(ch_entry, cl, src_link)for((ch_entry) = ((cl)->slh_first); (ch_entry) != ((void * )0); (ch_entry) = ((ch_entry)->src_link.sle_next)) { | |||
| 2731 | if (ch_entry->src_dev_mm == bs->bs_other_id) { | |||
| 2732 | found = 1; | |||
| 2733 | break; | |||
| 2734 | } | |||
| 2735 | c++; | |||
| 2736 | } | |||
| 2737 | if (found == 0) { | |||
| 2738 | sr_error(sc, "chunk not part of array"); | |||
| 2739 | goto done; | |||
| 2740 | } | |||
| 2741 | ||||
| 2742 | /* XXX: check current state first */ | |||
| 2743 | sd->sd_set_chunk_state(sd, c, BIOC_SDOFFLINE0x01); | |||
| 2744 | ||||
| 2745 | if (sr_meta_save(sd, SR_META_DIRTY0x1)) { | |||
| 2746 | sr_error(sc, "could not save metadata for %s", | |||
| 2747 | sd->sd_meta->ssd_devname); | |||
| 2748 | goto done; | |||
| 2749 | } | |||
| 2750 | rv = 0; | |||
| 2751 | break; | |||
| 2752 | ||||
| 2753 | case BIOC_SDSCRUB0x06: | |||
| 2754 | break; | |||
| 2755 | ||||
| 2756 | case BIOC_SSREBUILD0x03: | |||
| 2757 | rv = sr_rebuild_init(sd, (dev_t)bs->bs_other_id, 0); | |||
| 2758 | break; | |||
| 2759 | ||||
| 2760 | default: | |||
| 2761 | sr_error(sc, "unsupported state request %d", bs->bs_status); | |||
| 2762 | } | |||
| 2763 | ||||
| 2764 | done: | |||
| 2765 | return (rv); | |||
| 2766 | } | |||
| 2767 | ||||
| 2768 | int | |||
| 2769 | sr_chunk_in_use(struct sr_softc *sc, dev_t dev) | |||
| 2770 | { | |||
| 2771 | struct sr_discipline *sd; | |||
| 2772 | struct sr_chunk *chunk; | |||
| 2773 | int i; | |||
| 2774 | ||||
| 2775 | DNPRINTF(SR_D_MISC, "%s: sr_chunk_in_use(%d)\n", DEVNAME(sc), dev); | |||
| 2776 | ||||
| 2777 | if (dev == NODEV(dev_t)(-1)) | |||
| 2778 | return BIOC_SDINVALID0xff; | |||
| 2779 | ||||
| 2780 | /* See if chunk is already in use. */ | |||
| 2781 | TAILQ_FOREACH(sd, &sc->sc_dis_list, sd_link)for((sd) = ((&sc->sc_dis_list)->tqh_first); (sd) != ((void *)0); (sd) = ((sd)->sd_link.tqe_next)) { | |||
| 2782 | for (i = 0; i < sd->sd_meta->ssdi_sdd_invariant.ssd_chunk_no; i++) { | |||
| 2783 | chunk = sd->sd_vol.sv_chunks[i]; | |||
| 2784 | if (chunk->src_dev_mm == dev) | |||
| 2785 | return chunk->src_meta.scm_status; | |||
| 2786 | } | |||
| 2787 | } | |||
| 2788 | ||||
| 2789 | /* Check hotspares list. */ | |||
| 2790 | SLIST_FOREACH(chunk, &sc->sc_hotspare_list, src_link)for((chunk) = ((&sc->sc_hotspare_list)->slh_first); (chunk) != ((void *)0); (chunk) = ((chunk)->src_link.sle_next )) | |||
| 2791 | if (chunk->src_dev_mm == dev) | |||
| 2792 | return chunk->src_meta.scm_status; | |||
| 2793 | ||||
| 2794 | return BIOC_SDINVALID0xff; | |||
| 2795 | } | |||
| 2796 | ||||
| 2797 | int | |||
| 2798 | sr_hotspare(struct sr_softc *sc, dev_t dev) | |||
| 2799 | { | |||
| 2800 | struct sr_discipline *sd = NULL((void *)0); | |||
| 2801 | struct sr_metadata *sm = NULL((void *)0); | |||
| 2802 | struct sr_meta_chunk *hm; | |||
| 2803 | struct sr_chunk_head *cl; | |||
| 2804 | struct sr_chunk *chunk, *last, *hotspare = NULL((void *)0); | |||
| 2805 | struct sr_uuid uuid; | |||
| 2806 | struct disklabel label; | |||
| 2807 | struct vnode *vn; | |||
| 2808 | u_int64_t size; | |||
| 2809 | char devname[32]; | |||
| 2810 | int rv = EINVAL22; | |||
| 2811 | int c, part, open = 0; | |||
| 2812 | ||||
| 2813 | /* | |||
| 2814 | * Add device to global hotspares list. | |||
| 2815 | */ | |||
| 2816 | ||||
| 2817 | sr_meta_getdevname(sc, dev, devname, sizeof(devname)); | |||
| 2818 | ||||
| 2819 | /* Make sure chunk is not already in use. */ | |||
| 2820 | c = sr_chunk_in_use(sc, dev); | |||
| 2821 | if (c != BIOC_SDINVALID0xff && c != BIOC_SDOFFLINE0x01) { | |||
| 2822 | if (c == BIOC_SDHOTSPARE0x04) | |||
| 2823 | sr_error(sc, "%s is already a hotspare", devname); | |||
| 2824 | else | |||
| 2825 | sr_error(sc, "%s is already in use", devname); | |||
| 2826 | goto done; | |||
| 2827 | } | |||
| 2828 | ||||
| 2829 | /* XXX - See if there is an existing degraded volume... */ | |||
| 2830 | ||||
| 2831 | /* Open device. */ | |||
| 2832 | if (bdevvp(dev, &vn)) { | |||
| 2833 | sr_error(sc, "sr_hotspare: cannot allocate vnode"); | |||
| 2834 | goto done; | |||
| 2835 | } | |||
| 2836 | if (VOP_OPEN(vn, FREAD0x0001 | FWRITE0x0002, NOCRED((struct ucred *)-1), curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc)) { | |||
| 2837 | DNPRINTF(SR_D_META,"%s: sr_hotspare cannot open %s\n", | |||
| 2838 | DEVNAME(sc), devname); | |||
| 2839 | vput(vn); | |||
| 2840 | goto fail; | |||
| 2841 | } | |||
| 2842 | open = 1; /* close dev on error */ | |||
| 2843 | ||||
| 2844 | /* Get partition details. */ | |||
| 2845 | part = DISKPART(dev)(((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8)) % 16); | |||
| 2846 | if (VOP_IOCTL(vn, DIOCGDINFO((unsigned long)0x40000000 | ((sizeof(struct disklabel) & 0x1fff) << 16) | ((('d')) << 8) | ((101))), (caddr_t)&label, FREAD0x0001, | |||
| 2847 | NOCRED((struct ucred *)-1), curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc)) { | |||
| 2848 | DNPRINTF(SR_D_META, "%s: sr_hotspare ioctl failed\n", | |||
| 2849 | DEVNAME(sc)); | |||
| 2850 | goto fail; | |||
| 2851 | } | |||
| 2852 | if (label.d_partitions[part].p_fstype != FS_RAID19) { | |||
| 2853 | sr_error(sc, "%s partition not of type RAID (%d)", | |||
| 2854 | devname, label.d_partitions[part].p_fstype); | |||
| 2855 | goto fail; | |||
| 2856 | } | |||
| 2857 | ||||
| 2858 | /* Calculate partition size. */ | |||
| 2859 | size = DL_SECTOBLK(&label, DL_GETPSIZE(&label.d_partitions[part]))(((((u_int64_t)(&label.d_partitions[part])->p_sizeh << 32) + (&label.d_partitions[part])->p_size)) * ((& label)->d_secsize / (1 << 9))); | |||
| 2860 | if (size <= SR_DATA_OFFSET(16 + (64 + (320 + 128)))) { | |||
| 2861 | DNPRINTF(SR_D_META, "%s: %s partition too small\n", DEVNAME(sc), | |||
| 2862 | devname); | |||
| 2863 | goto fail; | |||
| 2864 | } | |||
| 2865 | size -= SR_DATA_OFFSET(16 + (64 + (320 + 128))); | |||
| 2866 | if (size > INT64_MAX0x7fffffffffffffffLL) { | |||
| 2867 | DNPRINTF(SR_D_META, "%s: %s partition too large\n", DEVNAME(sc), | |||
| 2868 | devname); | |||
| 2869 | goto fail; | |||
| 2870 | } | |||
| 2871 | ||||
| 2872 | /* | |||
| 2873 | * Create and populate chunk metadata. | |||
| 2874 | */ | |||
| 2875 | ||||
| 2876 | sr_uuid_generate(&uuid); | |||
| 2877 | hotspare = malloc(sizeof(struct sr_chunk), M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 2878 | ||||
| 2879 | hotspare->src_dev_mm = dev; | |||
| 2880 | hotspare->src_vn = vn; | |||
| 2881 | strlcpy(hotspare->src_devname, devname, sizeof(hm->scmi_scm_invariant.scm_devname)); | |||
| 2882 | hotspare->src_size = size; | |||
| 2883 | ||||
| 2884 | hm = &hotspare->src_meta; | |||
| 2885 | hm->scmi_scm_invariant.scm_volid = SR_HOTSPARE_VOLID0xffffffff; | |||
| 2886 | hm->scmi_scm_invariant.scm_chunk_id = 0; | |||
| 2887 | hm->scmi_scm_invariant.scm_size = size; | |||
| 2888 | hm->scmi_scm_invariant.scm_coerced_size = size; | |||
| 2889 | strlcpy(hm->scmi_scm_invariant.scm_devname, devname, sizeof(hm->scmi_scm_invariant.scm_devname)); | |||
| 2890 | memcpy(&hm->scmi.scm_uuid, &uuid, sizeof(struct sr_uuid))__builtin_memcpy((&hm->_scm_invariant.scm_uuid), (& uuid), (sizeof(struct sr_uuid))); | |||
| 2891 | ||||
| 2892 | sr_checksum(sc, hm, &hm->scm_checksum, | |||
| 2893 | sizeof(struct sr_meta_chunk_invariant)); | |||
| 2894 | ||||
| 2895 | hm->scm_status = BIOC_SDHOTSPARE0x04; | |||
| 2896 | ||||
| 2897 | /* | |||
| 2898 | * Create and populate our own discipline and metadata. | |||
| 2899 | */ | |||
| 2900 | ||||
| 2901 | sm = malloc(sizeof(struct sr_metadata), M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 2902 | sm->ssdi_sdd_invariant.ssd_magic = SR_MAGIC0x4d4152436372616dLLU; | |||
| 2903 | sm->ssdi_sdd_invariant.ssd_version = SR_META_VERSION6; | |||
| 2904 | sm->ssd_ondisk = 0; | |||
| 2905 | sm->ssdi_sdd_invariant.ssd_vol_flags = 0; | |||
| 2906 | memcpy(&sm->ssdi.ssd_uuid, &uuid, sizeof(struct sr_uuid))__builtin_memcpy((&sm->_sdd_invariant.ssd_uuid), (& uuid), (sizeof(struct sr_uuid))); | |||
| 2907 | sm->ssdi_sdd_invariant.ssd_chunk_no = 1; | |||
| 2908 | sm->ssdi_sdd_invariant.ssd_volid = SR_HOTSPARE_VOLID0xffffffff; | |||
| 2909 | sm->ssdi_sdd_invariant.ssd_level = SR_HOTSPARE_LEVEL0xffffffff; | |||
| 2910 | sm->ssdi_sdd_invariant.ssd_size = size; | |||
| 2911 | sm->ssdi_sdd_invariant.ssd_secsize = label.d_secsize; | |||
| 2912 | strlcpy(sm->ssdi_sdd_invariant.ssd_vendor, "OPENBSD", sizeof(sm->ssdi_sdd_invariant.ssd_vendor)); | |||
| 2913 | snprintf(sm->ssdi_sdd_invariant.ssd_product, sizeof(sm->ssdi_sdd_invariant.ssd_product), | |||
| 2914 | "SR %s", "HOTSPARE"); | |||
| 2915 | snprintf(sm->ssdi_sdd_invariant.ssd_revision, sizeof(sm->ssdi_sdd_invariant.ssd_revision), | |||
| 2916 | "%03d", SR_META_VERSION6); | |||
| 2917 | ||||
| 2918 | sd = malloc(sizeof(struct sr_discipline), M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 2919 | sd->sd_sc = sc; | |||
| 2920 | sd->sd_meta = sm; | |||
| 2921 | sd->sd_meta_type = SR_META_F_NATIVE0; | |||
| 2922 | sd->sd_vol_status = BIOC_SVONLINE0x00; | |||
| 2923 | strlcpy(sd->sd_name, "HOTSPARE", sizeof(sd->sd_name)); | |||
| 2924 | SLIST_INIT(&sd->sd_meta_opt){ ((&sd->sd_meta_opt)->slh_first) = ((void *)0); }; | |||
| 2925 | ||||
| 2926 | /* Add chunk to volume. */ | |||
| 2927 | sd->sd_vol.sv_chunks = malloc(sizeof(struct sr_chunk *), M_DEVBUF2, | |||
| 2928 | M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 2929 | sd->sd_vol.sv_chunks[0] = hotspare; | |||
| 2930 | SLIST_INIT(&sd->sd_vol.sv_chunk_list){ ((&sd->sd_vol.sv_chunk_list)->slh_first) = ((void *)0); }; | |||
| 2931 | SLIST_INSERT_HEAD(&sd->sd_vol.sv_chunk_list, hotspare, src_link)do { (hotspare)->src_link.sle_next = (&sd->sd_vol.sv_chunk_list )->slh_first; (&sd->sd_vol.sv_chunk_list)->slh_first = (hotspare); } while (0); | |||
| 2932 | ||||
| 2933 | /* Save metadata. */ | |||
| 2934 | if (sr_meta_save(sd, SR_META_DIRTY0x1)) { | |||
| 2935 | sr_error(sc, "could not save metadata to %s", devname); | |||
| 2936 | goto fail; | |||
| 2937 | } | |||
| 2938 | ||||
| 2939 | /* | |||
| 2940 | * Add chunk to hotspare list. | |||
| 2941 | */ | |||
| 2942 | rw_enter_write(&sc->sc_hs_lock); | |||
| 2943 | cl = &sc->sc_hotspare_list; | |||
| 2944 | if (SLIST_EMPTY(cl)(((cl)->slh_first) == ((void *)0))) | |||
| 2945 | SLIST_INSERT_HEAD(cl, hotspare, src_link)do { (hotspare)->src_link.sle_next = (cl)->slh_first; ( cl)->slh_first = (hotspare); } while (0); | |||
| 2946 | else { | |||
| 2947 | SLIST_FOREACH(chunk, cl, src_link)for((chunk) = ((cl)->slh_first); (chunk) != ((void *)0); ( chunk) = ((chunk)->src_link.sle_next)) | |||
| 2948 | last = chunk; | |||
| 2949 | SLIST_INSERT_AFTER(last, hotspare, src_link)do { (hotspare)->src_link.sle_next = (last)->src_link.sle_next ; (last)->src_link.sle_next = (hotspare); } while (0); | |||
| 2950 | } | |||
| 2951 | sc->sc_hotspare_no++; | |||
| 2952 | rw_exit_write(&sc->sc_hs_lock); | |||
| 2953 | ||||
| 2954 | rv = 0; | |||
| 2955 | goto done; | |||
| 2956 | ||||
| 2957 | fail: | |||
| 2958 | free(hotspare, M_DEVBUF2, sizeof(*hotspare)); | |||
| 2959 | ||||
| 2960 | done: | |||
| 2961 | if (sd) | |||
| 2962 | free(sd->sd_vol.sv_chunks, M_DEVBUF2, | |||
| 2963 | sizeof(sd->sd_vol.sv_chunks)); | |||
| 2964 | free(sd, M_DEVBUF2, sizeof(*sd)); | |||
| 2965 | free(sm, M_DEVBUF2, sizeof(*sm)); | |||
| 2966 | if (open) { | |||
| 2967 | VOP_CLOSE(vn, FREAD0x0001 | FWRITE0x0002, NOCRED((struct ucred *)-1), curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc); | |||
| 2968 | vput(vn); | |||
| 2969 | } | |||
| 2970 | ||||
| 2971 | return (rv); | |||
| 2972 | } | |||
| 2973 | ||||
| 2974 | void | |||
| 2975 | sr_hotspare_rebuild_callback(void *xsd) | |||
| 2976 | { | |||
| 2977 | struct sr_discipline *sd = xsd; | |||
| 2978 | sr_hotspare_rebuild(sd); | |||
| 2979 | } | |||
| 2980 | ||||
| 2981 | void | |||
| 2982 | sr_hotspare_rebuild(struct sr_discipline *sd) | |||
| 2983 | { | |||
| 2984 | struct sr_softc *sc = sd->sd_sc; | |||
| 2985 | struct sr_chunk_head *cl; | |||
| 2986 | struct sr_chunk *hotspare, *chunk = NULL((void *)0); | |||
| 2987 | struct sr_workunit *wu; | |||
| 2988 | struct sr_ccb *ccb; | |||
| 2989 | int i, s, cid, busy; | |||
| 2990 | ||||
| 2991 | /* | |||
| 2992 | * Attempt to locate a hotspare and initiate rebuild. | |||
| 2993 | */ | |||
| 2994 | ||||
| 2995 | /* Find first offline chunk. */ | |||
| 2996 | for (cid = 0; cid < sd->sd_meta->ssdi_sdd_invariant.ssd_chunk_no; cid++) { | |||
| 2997 | if (sd->sd_vol.sv_chunks[cid]->src_meta.scm_status == | |||
| 2998 | BIOC_SDOFFLINE0x01) { | |||
| 2999 | chunk = sd->sd_vol.sv_chunks[cid]; | |||
| 3000 | break; | |||
| 3001 | } | |||
| 3002 | } | |||
| 3003 | if (chunk == NULL((void *)0)) { | |||
| 3004 | printf("%s: no offline chunk found on %s!\n", | |||
| 3005 | DEVNAME(sc)((sc)->sc_dev.dv_xname), sd->sd_meta->ssd_devname); | |||
| 3006 | return; | |||
| 3007 | } | |||
| 3008 | ||||
| 3009 | /* See if we have a suitable hotspare... */ | |||
| 3010 | rw_enter_write(&sc->sc_hs_lock); | |||
| 3011 | cl = &sc->sc_hotspare_list; | |||
| 3012 | SLIST_FOREACH(hotspare, cl, src_link)for((hotspare) = ((cl)->slh_first); (hotspare) != ((void * )0); (hotspare) = ((hotspare)->src_link.sle_next)) | |||
| 3013 | if (hotspare->src_size >= chunk->src_size && | |||
| 3014 | hotspare->src_secsize <= sd->sd_meta->ssdi_sdd_invariant.ssd_secsize) | |||
| 3015 | break; | |||
| 3016 | ||||
| 3017 | if (hotspare != NULL((void *)0)) { | |||
| 3018 | ||||
| 3019 | printf("%s: %s volume degraded, will attempt to " | |||
| 3020 | "rebuild on hotspare %s\n", DEVNAME(sc)((sc)->sc_dev.dv_xname), | |||
| 3021 | sd->sd_meta->ssd_devname, hotspare->src_devname); | |||
| 3022 | ||||
| 3023 | /* | |||
| 3024 | * Ensure that all pending I/O completes on the failed chunk | |||
| 3025 | * before trying to initiate a rebuild. | |||
| 3026 | */ | |||
| 3027 | i = 0; | |||
| 3028 | do { | |||
| 3029 | busy = 0; | |||
| 3030 | ||||
| 3031 | s = splbio()splraise(0x3); | |||
| 3032 | TAILQ_FOREACH(wu, &sd->sd_wu_pendq, swu_link)for((wu) = ((&sd->sd_wu_pendq)->tqh_first); (wu) != ((void *)0); (wu) = ((wu)->swu_link.tqe_next)) { | |||
| 3033 | TAILQ_FOREACH(ccb, &wu->swu_ccb, ccb_link)for((ccb) = ((&wu->swu_ccb)->tqh_first); (ccb) != ( (void *)0); (ccb) = ((ccb)->ccb_link.tqe_next)) { | |||
| 3034 | if (ccb->ccb_target == cid) | |||
| 3035 | busy = 1; | |||
| 3036 | } | |||
| 3037 | } | |||
| 3038 | TAILQ_FOREACH(wu, &sd->sd_wu_defq, swu_link)for((wu) = ((&sd->sd_wu_defq)->tqh_first); (wu) != ( (void *)0); (wu) = ((wu)->swu_link.tqe_next)) { | |||
| 3039 | TAILQ_FOREACH(ccb, &wu->swu_ccb, ccb_link)for((ccb) = ((&wu->swu_ccb)->tqh_first); (ccb) != ( (void *)0); (ccb) = ((ccb)->ccb_link.tqe_next)) { | |||
| 3040 | if (ccb->ccb_target == cid) | |||
| 3041 | busy = 1; | |||
| 3042 | } | |||
| 3043 | } | |||
| 3044 | splx(s)spllower(s); | |||
| 3045 | ||||
| 3046 | if (busy) { | |||
| 3047 | tsleep_nsec(sd, PRIBIO16, "sr_hotspare", | |||
| 3048 | SEC_TO_NSEC(1)); | |||
| 3049 | i++; | |||
| 3050 | } | |||
| 3051 | ||||
| 3052 | } while (busy && i < 120); | |||
| 3053 | ||||
| 3054 | DNPRINTF(SR_D_META, "%s: waited %i seconds for I/O to " | |||
| 3055 | "complete on failed chunk %s\n", DEVNAME(sc), | |||
| 3056 | i, chunk->src_devname); | |||
| 3057 | ||||
| 3058 | if (busy) { | |||
| 3059 | printf("%s: pending I/O failed to complete on " | |||
| 3060 | "failed chunk %s, hotspare rebuild aborted...\n", | |||
| 3061 | DEVNAME(sc)((sc)->sc_dev.dv_xname), chunk->src_devname); | |||
| 3062 | goto done; | |||
| 3063 | } | |||
| 3064 | ||||
| 3065 | s = splbio()splraise(0x3); | |||
| 3066 | rw_enter_write(&sc->sc_lock); | |||
| 3067 | bio_status_init(&sc->sc_status, &sc->sc_dev); | |||
| 3068 | if (sr_rebuild_init(sd, hotspare->src_dev_mm, 1) == 0) { | |||
| 3069 | ||||
| 3070 | /* Remove hotspare from available list. */ | |||
| 3071 | sc->sc_hotspare_no--; | |||
| 3072 | SLIST_REMOVE(cl, hotspare, sr_chunk, src_link)do { if ((cl)->slh_first == (hotspare)) { do { ((cl))-> slh_first = ((cl))->slh_first->src_link.sle_next; } while (0); } else { struct sr_chunk *curelm = (cl)->slh_first; while (curelm->src_link.sle_next != (hotspare)) curelm = curelm ->src_link.sle_next; curelm->src_link.sle_next = curelm ->src_link.sle_next->src_link.sle_next; } ((hotspare)-> src_link.sle_next) = ((void *)-1); } while (0); | |||
| 3073 | free(hotspare, M_DEVBUF2, sizeof(*hotspare)); | |||
| 3074 | ||||
| 3075 | } | |||
| 3076 | rw_exit_write(&sc->sc_lock); | |||
| 3077 | splx(s)spllower(s); | |||
| 3078 | } | |||
| 3079 | done: | |||
| 3080 | rw_exit_write(&sc->sc_hs_lock); | |||
| 3081 | } | |||
| 3082 | ||||
| 3083 | int | |||
| 3084 | sr_rebuild_init(struct sr_discipline *sd, dev_t dev, int hotspare) | |||
| 3085 | { | |||
| 3086 | struct sr_softc *sc = sd->sd_sc; | |||
| 3087 | struct sr_chunk *chunk = NULL((void *)0); | |||
| 3088 | struct sr_meta_chunk *meta; | |||
| 3089 | struct disklabel label; | |||
| 3090 | struct vnode *vn; | |||
| 3091 | u_int64_t size; | |||
| 3092 | int64_t csize; | |||
| 3093 | char devname[32]; | |||
| 3094 | int rv = EINVAL22, open = 0; | |||
| 3095 | int cid, i, part, status; | |||
| 3096 | ||||
| 3097 | /* | |||
| 3098 | * Attempt to initiate a rebuild onto the specified device. | |||
| 3099 | */ | |||
| 3100 | ||||
| 3101 | if (!(sd->sd_capabilities & SR_CAP_REBUILD0x00000004)) { | |||
| 3102 | sr_error(sc, "discipline does not support rebuild"); | |||
| 3103 | goto done; | |||
| 3104 | } | |||
| 3105 | ||||
| 3106 | /* make sure volume is in the right state */ | |||
| 3107 | if (sd->sd_vol_status == BIOC_SVREBUILD0x05) { | |||
| 3108 | sr_error(sc, "rebuild already in progress"); | |||
| 3109 | goto done; | |||
| 3110 | } | |||
| 3111 | if (sd->sd_vol_status != BIOC_SVDEGRADED0x02) { | |||
| 3112 | sr_error(sc, "volume not degraded"); | |||
| 3113 | goto done; | |||
| 3114 | } | |||
| 3115 | ||||
| 3116 | /* Find first offline chunk. */ | |||
| 3117 | for (cid = 0; cid < sd->sd_meta->ssdi_sdd_invariant.ssd_chunk_no; cid++) { | |||
| 3118 | if (sd->sd_vol.sv_chunks[cid]->src_meta.scm_status == | |||
| 3119 | BIOC_SDOFFLINE0x01) { | |||
| 3120 | chunk = sd->sd_vol.sv_chunks[cid]; | |||
| 3121 | break; | |||
| 3122 | } | |||
| 3123 | } | |||
| 3124 | if (chunk == NULL((void *)0)) { | |||
| 3125 | sr_error(sc, "no offline chunks available to rebuild"); | |||
| 3126 | goto done; | |||
| 3127 | } | |||
| 3128 | ||||
| 3129 | /* Get coerced size from another online chunk. */ | |||
| 3130 | csize = 0; | |||
| 3131 | for (i = 0; i < sd->sd_meta->ssdi_sdd_invariant.ssd_chunk_no; i++) { | |||
| 3132 | if (sd->sd_vol.sv_chunks[i]->src_meta.scm_status == | |||
| 3133 | BIOC_SDONLINE0x00) { | |||
| 3134 | meta = &sd->sd_vol.sv_chunks[i]->src_meta; | |||
| 3135 | csize = meta->scmi_scm_invariant.scm_coerced_size; | |||
| 3136 | break; | |||
| 3137 | } | |||
| 3138 | } | |||
| 3139 | if (csize == 0) { | |||
| 3140 | sr_error(sc, "no online chunks available for rebuild"); | |||
| 3141 | goto done; | |||
| 3142 | } | |||
| 3143 | ||||
| 3144 | sr_meta_getdevname(sc, dev, devname, sizeof(devname)); | |||
| 3145 | if (bdevvp(dev, &vn)) { | |||
| 3146 | printf("%s: sr_rebuild_init: can't allocate vnode\n", | |||
| 3147 | DEVNAME(sc)((sc)->sc_dev.dv_xname)); | |||
| 3148 | goto done; | |||
| 3149 | } | |||
| 3150 | if (VOP_OPEN(vn, FREAD0x0001 | FWRITE0x0002, NOCRED((struct ucred *)-1), curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc)) { | |||
| 3151 | DNPRINTF(SR_D_META,"%s: sr_ioctl_setstate can't " | |||
| 3152 | "open %s\n", DEVNAME(sc), devname); | |||
| 3153 | vput(vn); | |||
| 3154 | goto done; | |||
| 3155 | } | |||
| 3156 | open = 1; /* close dev on error */ | |||
| 3157 | ||||
| 3158 | /* Get disklabel and check partition. */ | |||
| 3159 | part = DISKPART(dev)(((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8)) % 16); | |||
| 3160 | if (VOP_IOCTL(vn, DIOCGDINFO((unsigned long)0x40000000 | ((sizeof(struct disklabel) & 0x1fff) << 16) | ((('d')) << 8) | ((101))), (caddr_t)&label, FREAD0x0001, | |||
| 3161 | NOCRED((struct ucred *)-1), curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc)) { | |||
| 3162 | DNPRINTF(SR_D_META, "%s: sr_ioctl_setstate ioctl failed\n", | |||
| 3163 | DEVNAME(sc)); | |||
| 3164 | goto done; | |||
| 3165 | } | |||
| 3166 | if (label.d_partitions[part].p_fstype != FS_RAID19) { | |||
| 3167 | sr_error(sc, "%s partition not of type RAID (%d)", | |||
| 3168 | devname, label.d_partitions[part].p_fstype); | |||
| 3169 | goto done; | |||
| 3170 | } | |||
| 3171 | ||||
| 3172 | /* Is the partition large enough? */ | |||
| 3173 | size = DL_SECTOBLK(&label, DL_GETPSIZE(&label.d_partitions[part]))(((((u_int64_t)(&label.d_partitions[part])->p_sizeh << 32) + (&label.d_partitions[part])->p_size)) * ((& label)->d_secsize / (1 << 9))); | |||
| 3174 | if (size <= sd->sd_meta->ssd_data_blkno) { | |||
| 3175 | sr_error(sc, "%s: %s partition too small", DEVNAME(sc)((sc)->sc_dev.dv_xname), | |||
| 3176 | devname); | |||
| 3177 | goto done; | |||
| 3178 | } | |||
| 3179 | size -= sd->sd_meta->ssd_data_blkno; | |||
| 3180 | if (size > INT64_MAX0x7fffffffffffffffLL) { | |||
| 3181 | sr_error(sc, "%s: %s partition too large", DEVNAME(sc)((sc)->sc_dev.dv_xname), | |||
| 3182 | devname); | |||
| 3183 | goto done; | |||
| 3184 | } | |||
| 3185 | if (size < csize) { | |||
| 3186 | sr_error(sc, "%s partition too small, at least %lld bytes " | |||
| 3187 | "required", devname, (long long)(csize << DEV_BSHIFT9)); | |||
| 3188 | goto done; | |||
| 3189 | } else if (size > csize) | |||
| 3190 | sr_warn(sc, "%s partition too large, wasting %lld bytes", | |||
| 3191 | devname, (long long)((size - csize) << DEV_BSHIFT9)); | |||
| 3192 | if (label.d_secsize > sd->sd_meta->ssdi_sdd_invariant.ssd_secsize) { | |||
| 3193 | sr_error(sc, "%s sector size too large, <= %u bytes " | |||
| 3194 | "required", devname, sd->sd_meta->ssdi_sdd_invariant.ssd_secsize); | |||
| 3195 | goto done; | |||
| 3196 | } | |||
| 3197 | ||||
| 3198 | /* Ensure that this chunk is not already in use. */ | |||
| 3199 | status = sr_chunk_in_use(sc, dev); | |||
| 3200 | if (status != BIOC_SDINVALID0xff && status != BIOC_SDOFFLINE0x01 && | |||
| 3201 | !(hotspare && status == BIOC_SDHOTSPARE0x04)) { | |||
| 3202 | sr_error(sc, "%s is already in use", devname); | |||
| 3203 | goto done; | |||
| 3204 | } | |||
| 3205 | ||||
| 3206 | /* Reset rebuild counter since we rebuilding onto a new chunk. */ | |||
| 3207 | sd->sd_meta->ssd_rebuild = 0; | |||
| 3208 | ||||
| 3209 | open = 0; /* leave dev open from here on out */ | |||
| 3210 | ||||
| 3211 | /* Fix up chunk. */ | |||
| 3212 | memcpy(chunk->src_duid, label.d_uid, sizeof(chunk->src_duid))__builtin_memcpy((chunk->src_duid), (label.d_uid), (sizeof (chunk->src_duid))); | |||
| 3213 | chunk->src_dev_mm = dev; | |||
| 3214 | chunk->src_vn = vn; | |||
| 3215 | ||||
| 3216 | /* Reconstruct metadata. */ | |||
| 3217 | meta = &chunk->src_meta; | |||
| 3218 | meta->scmi_scm_invariant.scm_volid = sd->sd_meta->ssdi_sdd_invariant.ssd_volid; | |||
| 3219 | meta->scmi_scm_invariant.scm_chunk_id = cid; | |||
| 3220 | strlcpy(meta->scmi_scm_invariant.scm_devname, devname, | |||
| 3221 | sizeof(meta->scmi_scm_invariant.scm_devname)); | |||
| 3222 | meta->scmi_scm_invariant.scm_size = size; | |||
| 3223 | meta->scmi_scm_invariant.scm_coerced_size = csize; | |||
| 3224 | memcpy(&meta->scmi.scm_uuid, &sd->sd_meta->ssdi.ssd_uuid,__builtin_memcpy((&meta->_scm_invariant.scm_uuid), (& sd->sd_meta->_sdd_invariant.ssd_uuid), (sizeof(meta-> _scm_invariant.scm_uuid))) | |||
| 3225 | sizeof(meta->scmi.scm_uuid))__builtin_memcpy((&meta->_scm_invariant.scm_uuid), (& sd->sd_meta->_sdd_invariant.ssd_uuid), (sizeof(meta-> _scm_invariant.scm_uuid))); | |||
| 3226 | sr_checksum(sc, meta, &meta->scm_checksum, | |||
| 3227 | sizeof(struct sr_meta_chunk_invariant)); | |||
| 3228 | ||||
| 3229 | sd->sd_set_chunk_state(sd, cid, BIOC_SDREBUILD0x03); | |||
| 3230 | ||||
| 3231 | if (sr_meta_save(sd, SR_META_DIRTY0x1)) { | |||
| 3232 | sr_error(sc, "could not save metadata to %s", devname); | |||
| 3233 | open = 1; | |||
| 3234 | goto done; | |||
| 3235 | } | |||
| 3236 | ||||
| 3237 | sr_warn(sc, "rebuild of %s started on %s", | |||
| 3238 | sd->sd_meta->ssd_devname, devname); | |||
| 3239 | ||||
| 3240 | sd->sd_reb_abort = 0; | |||
| 3241 | kthread_create_deferred(sr_rebuild_start, sd); | |||
| 3242 | ||||
| 3243 | rv = 0; | |||
| 3244 | done: | |||
| 3245 | if (open) { | |||
| 3246 | VOP_CLOSE(vn, FREAD0x0001 | FWRITE0x0002, NOCRED((struct ucred *)-1), curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc); | |||
| 3247 | vput(vn); | |||
| 3248 | } | |||
| 3249 | ||||
| 3250 | return (rv); | |||
| 3251 | } | |||
| 3252 | ||||
| 3253 | int | |||
| 3254 | sr_rebuild_percent(struct sr_discipline *sd) | |||
| 3255 | { | |||
| 3256 | daddr_t rb, sz; | |||
| 3257 | ||||
| 3258 | sz = sd->sd_meta->ssdi_sdd_invariant.ssd_size; | |||
| 3259 | rb = sd->sd_meta->ssd_rebuild; | |||
| 3260 | ||||
| 3261 | if (rb > 0) | |||
| 3262 | return (100 - ((sz * 100 - rb * 100) / sz) - 1); | |||
| 3263 | ||||
| 3264 | return (0); | |||
| 3265 | } | |||
| 3266 | ||||
| 3267 | void | |||
| 3268 | sr_roam_chunks(struct sr_discipline *sd) | |||
| 3269 | { | |||
| 3270 | struct sr_softc *sc = sd->sd_sc; | |||
| 3271 | struct sr_chunk *chunk; | |||
| 3272 | struct sr_meta_chunk *meta; | |||
| 3273 | int roamed = 0; | |||
| 3274 | ||||
| 3275 | /* Have any chunks roamed? */ | |||
| 3276 | SLIST_FOREACH(chunk, &sd->sd_vol.sv_chunk_list, src_link)for((chunk) = ((&sd->sd_vol.sv_chunk_list)->slh_first ); (chunk) != ((void *)0); (chunk) = ((chunk)->src_link.sle_next )) { | |||
| 3277 | meta = &chunk->src_meta; | |||
| 3278 | if (strncmp(meta->scmi_scm_invariant.scm_devname, chunk->src_devname, | |||
| 3279 | sizeof(meta->scmi_scm_invariant.scm_devname))) { | |||
| 3280 | ||||
| 3281 | printf("%s: roaming device %s -> %s\n", DEVNAME(sc)((sc)->sc_dev.dv_xname), | |||
| 3282 | meta->scmi_scm_invariant.scm_devname, chunk->src_devname); | |||
| 3283 | ||||
| 3284 | strlcpy(meta->scmi_scm_invariant.scm_devname, chunk->src_devname, | |||
| 3285 | sizeof(meta->scmi_scm_invariant.scm_devname)); | |||
| 3286 | ||||
| 3287 | roamed++; | |||
| 3288 | } | |||
| 3289 | } | |||
| 3290 | ||||
| 3291 | if (roamed) | |||
| 3292 | sr_meta_save(sd, SR_META_DIRTY0x1); | |||
| 3293 | } | |||
| 3294 | ||||
| 3295 | int | |||
| 3296 | sr_ioctl_createraid(struct sr_softc *sc, struct bioc_createraid *bc, | |||
| 3297 | int user, void *data) | |||
| 3298 | { | |||
| 3299 | struct sr_meta_opt_item *omi; | |||
| 3300 | struct sr_chunk_head *cl; | |||
| 3301 | struct sr_discipline *sd = NULL((void *)0); | |||
| 3302 | struct sr_chunk *ch_entry; | |||
| 3303 | struct scsi_link *link; | |||
| 3304 | struct device *dev; | |||
| 3305 | char *uuid, devname[32]; | |||
| 3306 | dev_t *dt = NULL((void *)0); | |||
| 3307 | int i, no_chunk, rv = EINVAL22, target, vol; | |||
| 3308 | int no_meta; | |||
| 3309 | ||||
| 3310 | DNPRINTF(SR_D_IOCTL, "%s: sr_ioctl_createraid(%d)\n", | |||
| 3311 | DEVNAME(sc), user); | |||
| 3312 | ||||
| 3313 | /* user input */ | |||
| 3314 | if (bc->bc_dev_list_len > BIOC_CRMAXLEN1024) | |||
| 3315 | goto unwind; | |||
| 3316 | ||||
| 3317 | dt = malloc(bc->bc_dev_list_len, M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 3318 | if (user) { | |||
| 3319 | if (copyin(bc->bc_dev_list, dt, bc->bc_dev_list_len) != 0) | |||
| 3320 | goto unwind; | |||
| 3321 | } else | |||
| 3322 | memcpy(dt, bc->bc_dev_list, bc->bc_dev_list_len)__builtin_memcpy((dt), (bc->bc_dev_list), (bc->bc_dev_list_len )); | |||
| 3323 | ||||
| 3324 | /* Initialise discipline. */ | |||
| 3325 | sd = malloc(sizeof(struct sr_discipline), M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 3326 | sd->sd_sc = sc; | |||
| 3327 | SLIST_INIT(&sd->sd_meta_opt){ ((&sd->sd_meta_opt)->slh_first) = ((void *)0); }; | |||
| 3328 | sd->sd_taskq = taskq_create("srdis", 1, IPL_BIO0x3, 0); | |||
| 3329 | if (sd->sd_taskq == NULL((void *)0)) { | |||
| 3330 | sr_error(sc, "could not create discipline taskq"); | |||
| 3331 | goto unwind; | |||
| 3332 | } | |||
| 3333 | if (sr_discipline_init(sd, bc->bc_level)) { | |||
| 3334 | sr_error(sc, "could not initialize discipline"); | |||
| 3335 | goto unwind; | |||
| 3336 | } | |||
| 3337 | ||||
| 3338 | no_chunk = bc->bc_dev_list_len / sizeof(dev_t); | |||
| 3339 | cl = &sd->sd_vol.sv_chunk_list; | |||
| 3340 | SLIST_INIT(cl){ ((cl)->slh_first) = ((void *)0); }; | |||
| 3341 | ||||
| 3342 | /* Ensure that chunks are not already in use. */ | |||
| 3343 | for (i = 0; i < no_chunk; i++) { | |||
| 3344 | if (sr_chunk_in_use(sc, dt[i]) != BIOC_SDINVALID0xff) { | |||
| 3345 | sr_meta_getdevname(sc, dt[i], devname, sizeof(devname)); | |||
| 3346 | sr_error(sc, "chunk %s already in use", devname); | |||
| 3347 | goto unwind; | |||
| 3348 | } | |||
| 3349 | } | |||
| 3350 | ||||
| 3351 | sd->sd_meta_type = sr_meta_probe(sd, dt, no_chunk); | |||
| 3352 | if (sd->sd_meta_type == SR_META_F_INVALID-1) { | |||
| 3353 | sr_error(sc, "invalid metadata format"); | |||
| 3354 | goto unwind; | |||
| 3355 | } | |||
| 3356 | ||||
| 3357 | if (sr_meta_attach(sd, no_chunk, bc->bc_flags & BIOC_SCFORCE0x01)) | |||
| 3358 | goto unwind; | |||
| 3359 | ||||
| 3360 | /* force the raid volume by clearing metadata region */ | |||
| 3361 | if (bc->bc_flags & BIOC_SCFORCE0x01) { | |||
| 3362 | /* make sure disk isn't up and running */ | |||
| 3363 | if (sr_meta_read(sd)) | |||
| 3364 | if (sr_already_assembled(sd)) { | |||
| 3365 | uuid = sr_uuid_format( | |||
| 3366 | &sd->sd_meta->ssdi_sdd_invariant.ssd_uuid); | |||
| 3367 | sr_error(sc, "disk %s is currently in use; " | |||
| 3368 | "cannot force create", uuid); | |||
| 3369 | free(uuid, M_DEVBUF2, 37); | |||
| 3370 | goto unwind; | |||
| 3371 | } | |||
| 3372 | ||||
| 3373 | if (sr_meta_clear(sd)) { | |||
| 3374 | sr_error(sc, "failed to clear metadata"); | |||
| 3375 | goto unwind; | |||
| 3376 | } | |||
| 3377 | } | |||
| 3378 | ||||
| 3379 | no_meta = sr_meta_read(sd); | |||
| 3380 | if (no_meta == -1) { | |||
| 3381 | ||||
| 3382 | /* Corrupt metadata on one or more chunks. */ | |||
| 3383 | sr_error(sc, "one of the chunks has corrupt metadata; " | |||
| 3384 | "aborting assembly"); | |||
| 3385 | goto unwind; | |||
| 3386 | ||||
| 3387 | } else if (no_meta == 0) { | |||
| 3388 | ||||
| 3389 | /* Initialise volume and chunk metadata. */ | |||
| 3390 | sr_meta_init(sd, bc->bc_level, no_chunk); | |||
| 3391 | sd->sd_vol_status = BIOC_SVONLINE0x00; | |||
| 3392 | sd->sd_meta_flags = bc->bc_flags & BIOC_SCNOAUTOASSEMBLE0x04; | |||
| 3393 | if (sd->sd_create) { | |||
| 3394 | if ((i = sd->sd_create(sd, bc, no_chunk, | |||
| 3395 | sd->sd_vol.sv_chunk_minsz))) { | |||
| 3396 | rv = i; | |||
| 3397 | goto unwind; | |||
| 3398 | } | |||
| 3399 | } | |||
| 3400 | sr_meta_init_complete(sd); | |||
| 3401 | ||||
| 3402 | DNPRINTF(SR_D_IOCTL, | |||
| 3403 | "%s: sr_ioctl_createraid: vol_size: %lld\n", | |||
| 3404 | DEVNAME(sc), sd->sd_meta->ssdi.ssd_size); | |||
| 3405 | ||||
| 3406 | /* Warn if we've wasted chunk space due to coercing. */ | |||
| 3407 | if ((sd->sd_capabilities & SR_CAP_NON_COERCED0x00000008) == 0 && | |||
| 3408 | sd->sd_vol.sv_chunk_minsz != sd->sd_vol.sv_chunk_maxsz) | |||
| 3409 | sr_warn(sc, "chunk sizes are not equal; up to %llu " | |||
| 3410 | "blocks wasted per chunk", | |||
| 3411 | sd->sd_vol.sv_chunk_maxsz - | |||
| 3412 | sd->sd_vol.sv_chunk_minsz); | |||
| 3413 | ||||
| 3414 | } else { | |||
| 3415 | ||||
| 3416 | /* Ensure we are assembling the correct # of chunks. */ | |||
| 3417 | if (bc->bc_level == 0x1C && | |||
| 3418 | sd->sd_meta->ssdi_sdd_invariant.ssd_chunk_no > no_chunk) { | |||
| 3419 | sr_warn(sc, "trying to bring up %s degraded", | |||
| 3420 | sd->sd_meta->ssd_devname); | |||
| 3421 | } else if (sd->sd_meta->ssdi_sdd_invariant.ssd_chunk_no != no_chunk) { | |||
| 3422 | sr_error(sc, "volume chunk count does not match metadata " | |||
| 3423 | "chunk count"); | |||
| 3424 | goto unwind; | |||
| 3425 | } | |||
| 3426 | ||||
| 3427 | /* Ensure metadata level matches requested assembly level. */ | |||
| 3428 | if (sd->sd_meta->ssdi_sdd_invariant.ssd_level != bc->bc_level) { | |||
| 3429 | sr_error(sc, "volume level does not match metadata " | |||
| 3430 | "level"); | |||
| 3431 | goto unwind; | |||
| 3432 | } | |||
| 3433 | ||||
| 3434 | if (sr_already_assembled(sd)) { | |||
| 3435 | uuid = sr_uuid_format(&sd->sd_meta->ssdi_sdd_invariant.ssd_uuid); | |||
| 3436 | sr_error(sc, "disk %s already assembled", uuid); | |||
| 3437 | free(uuid, M_DEVBUF2, 37); | |||
| 3438 | goto unwind; | |||
| 3439 | } | |||
| 3440 | ||||
| 3441 | if (user == 0 && sd->sd_meta_flags & BIOC_SCNOAUTOASSEMBLE0x04) { | |||
| 3442 | DNPRINTF(SR_D_META, "%s: disk not auto assembled from " | |||
| 3443 | "metadata\n", DEVNAME(sc)); | |||
| 3444 | goto unwind; | |||
| 3445 | } | |||
| 3446 | ||||
| 3447 | if (no_meta != no_chunk) | |||
| 3448 | sr_warn(sc, "trying to bring up %s degraded", | |||
| 3449 | sd->sd_meta->ssd_devname); | |||
| 3450 | ||||
| 3451 | if (sd->sd_meta->ssd_meta_flags & SR_META_DIRTY0x1) | |||
| 3452 | sr_warn(sc, "%s was not shutdown properly", | |||
| 3453 | sd->sd_meta->ssd_devname); | |||
| 3454 | ||||
| 3455 | SLIST_FOREACH(omi, &sd->sd_meta_opt, omi_link)for((omi) = ((&sd->sd_meta_opt)->slh_first); (omi) != ((void *)0); (omi) = ((omi)->omi_link.sle_next)) | |||
| 3456 | if (sd->sd_meta_opt_handler == NULL((void *)0) || | |||
| 3457 | sd->sd_meta_opt_handler(sd, omi->omi_som) != 0) | |||
| 3458 | sr_meta_opt_handler(sd, omi->omi_som); | |||
| 3459 | ||||
| 3460 | if (sd->sd_assemble) { | |||
| 3461 | if ((i = sd->sd_assemble(sd, bc, no_chunk, data))) { | |||
| 3462 | rv = i; | |||
| 3463 | goto unwind; | |||
| 3464 | } | |||
| 3465 | } | |||
| 3466 | ||||
| 3467 | DNPRINTF(SR_D_META, "%s: disk assembled from metadata\n", | |||
| 3468 | DEVNAME(sc)); | |||
| 3469 | ||||
| 3470 | } | |||
| 3471 | ||||
| 3472 | /* Metadata MUST be fully populated by this point. */ | |||
| 3473 | TAILQ_INSERT_TAIL(&sc->sc_dis_list, sd, sd_link)do { (sd)->sd_link.tqe_next = ((void *)0); (sd)->sd_link .tqe_prev = (&sc->sc_dis_list)->tqh_last; *(&sc ->sc_dis_list)->tqh_last = (sd); (&sc->sc_dis_list )->tqh_last = &(sd)->sd_link.tqe_next; } while (0); | |||
| 3474 | ||||
| 3475 | /* Allocate all resources. */ | |||
| 3476 | if ((rv = sd->sd_alloc_resources(sd))) | |||
| 3477 | goto unwind; | |||
| 3478 | ||||
| 3479 | /* Adjust flags if necessary. */ | |||
| 3480 | if ((sd->sd_capabilities & SR_CAP_AUTO_ASSEMBLE0x00000002) && | |||
| 3481 | (bc->bc_flags & BIOC_SCNOAUTOASSEMBLE0x04) != | |||
| 3482 | (sd->sd_meta->ssdi_sdd_invariant.ssd_vol_flags & BIOC_SCNOAUTOASSEMBLE0x04)) { | |||
| 3483 | sd->sd_meta->ssdi_sdd_invariant.ssd_vol_flags &= ~BIOC_SCNOAUTOASSEMBLE0x04; | |||
| 3484 | sd->sd_meta->ssdi_sdd_invariant.ssd_vol_flags |= | |||
| 3485 | bc->bc_flags & BIOC_SCNOAUTOASSEMBLE0x04; | |||
| 3486 | } | |||
| 3487 | ||||
| 3488 | if (sd->sd_capabilities & SR_CAP_SYSTEM_DISK0x00000001) { | |||
| 3489 | /* Initialise volume state. */ | |||
| 3490 | sd->sd_set_vol_state(sd); | |||
| 3491 | if (sd->sd_vol_status == BIOC_SVOFFLINE0x01) { | |||
| 3492 | sr_error(sc, "%s is offline, will not be brought " | |||
| 3493 | "online", sd->sd_meta->ssd_devname); | |||
| 3494 | goto unwind; | |||
| 3495 | } | |||
| 3496 | ||||
| 3497 | /* Setup SCSI iopool. */ | |||
| 3498 | scsi_iopool_init(&sd->sd_iopool, sd, sr_wu_get, sr_wu_put); | |||
| 3499 | ||||
| 3500 | /* | |||
| 3501 | * All checks passed - return ENXIO if volume cannot be created. | |||
| 3502 | */ | |||
| 3503 | rv = ENXIO6; | |||
| 3504 | ||||
| 3505 | /* | |||
| 3506 | * Find a free target. | |||
| 3507 | * | |||
| 3508 | * XXX: We reserve sd_target == 0 to indicate the | |||
| 3509 | * discipline is not linked into sc->sc_targets, so begin | |||
| 3510 | * the search with target = 1. | |||
| 3511 | */ | |||
| 3512 | for (target = 1; target < SR_MAX_LD256; target++) | |||
| 3513 | if (sc->sc_targets[target] == NULL((void *)0)) | |||
| 3514 | break; | |||
| 3515 | if (target == SR_MAX_LD256) { | |||
| 3516 | sr_error(sc, "no free target for %s", | |||
| 3517 | sd->sd_meta->ssd_devname); | |||
| 3518 | goto unwind; | |||
| 3519 | } | |||
| 3520 | ||||
| 3521 | /* Clear sense data. */ | |||
| 3522 | bzero(&sd->sd_scsi_sense, sizeof(sd->sd_scsi_sense))__builtin_bzero((&sd->sd_scsi_sense), (sizeof(sd->sd_scsi_sense ))); | |||
| 3523 | ||||
| 3524 | /* Attach discipline and get midlayer to probe it. */ | |||
| 3525 | sd->sd_target = target; | |||
| 3526 | sc->sc_targets[target] = sd; | |||
| 3527 | if (scsi_probe_lun(sc->sc_scsibus, target, 0) != 0) { | |||
| 3528 | sr_error(sc, "scsi_probe_lun failed"); | |||
| 3529 | sc->sc_targets[target] = NULL((void *)0); | |||
| 3530 | sd->sd_target = 0; | |||
| 3531 | goto unwind; | |||
| 3532 | } | |||
| 3533 | ||||
| 3534 | link = scsi_get_link(sc->sc_scsibus, target, 0); | |||
| 3535 | if (link == NULL((void *)0)) | |||
| 3536 | goto unwind; | |||
| 3537 | ||||
| 3538 | dev = link->device_softc; | |||
| 3539 | DNPRINTF(SR_D_IOCTL, "%s: sr device added: %s at target %d\n", | |||
| 3540 | DEVNAME(sc), dev->dv_xname, sd->sd_target); | |||
| 3541 | ||||
| 3542 | /* XXX - Count volumes, not targets. */ | |||
| 3543 | for (i = 0, vol = -1; i <= sd->sd_target; i++) | |||
| 3544 | if (sc->sc_targets[i]) | |||
| 3545 | vol++; | |||
| 3546 | ||||
| 3547 | rv = 0; | |||
| 3548 | ||||
| 3549 | if (sd->sd_meta->ssd_devname[0] != '\0' && | |||
| 3550 | strncmp(sd->sd_meta->ssd_devname, dev->dv_xname, | |||
| 3551 | sizeof(dev->dv_xname))) | |||
| 3552 | sr_warn(sc, "volume %s is roaming, it used to be %s, " | |||
| 3553 | "updating metadata", dev->dv_xname, | |||
| 3554 | sd->sd_meta->ssd_devname); | |||
| 3555 | ||||
| 3556 | /* Populate remaining volume metadata. */ | |||
| 3557 | sd->sd_meta->ssdi_sdd_invariant.ssd_volid = vol; | |||
| 3558 | strlcpy(sd->sd_meta->ssd_devname, dev->dv_xname, | |||
| 3559 | sizeof(sd->sd_meta->ssd_devname)); | |||
| 3560 | ||||
| 3561 | sr_info(sc, "%s volume attached as %s", | |||
| 3562 | sd->sd_name, sd->sd_meta->ssd_devname); | |||
| 3563 | ||||
| 3564 | /* Update device name on any roaming chunks. */ | |||
| 3565 | sr_roam_chunks(sd); | |||
| 3566 | ||||
| 3567 | #ifndef SMALL_KERNEL | |||
| 3568 | if (sr_sensors_create(sd)) | |||
| 3569 | sr_warn(sc, "unable to create sensor for %s", | |||
| 3570 | dev->dv_xname); | |||
| 3571 | #endif /* SMALL_KERNEL */ | |||
| 3572 | } else { | |||
| 3573 | /* This volume does not attach as a system disk. */ | |||
| 3574 | ch_entry = SLIST_FIRST(cl)((cl)->slh_first); /* XXX */ | |||
| 3575 | strlcpy(sd->sd_meta->ssd_devname, ch_entry->src_devname, | |||
| 3576 | sizeof(sd->sd_meta->ssd_devname)); | |||
| 3577 | ||||
| 3578 | if (sd->sd_start_discipline(sd)) | |||
| 3579 | goto unwind; | |||
| 3580 | } | |||
| 3581 | ||||
| 3582 | /* Save current metadata to disk. */ | |||
| 3583 | rv = sr_meta_save(sd, SR_META_DIRTY0x1); | |||
| 3584 | ||||
| 3585 | if (sd->sd_vol_status == BIOC_SVREBUILD0x05) | |||
| 3586 | kthread_create_deferred(sr_rebuild_start, sd); | |||
| 3587 | ||||
| 3588 | sd->sd_ready = 1; | |||
| 3589 | ||||
| 3590 | free(dt, M_DEVBUF2, bc->bc_dev_list_len); | |||
| 3591 | ||||
| 3592 | return (rv); | |||
| 3593 | ||||
| 3594 | unwind: | |||
| 3595 | free(dt, M_DEVBUF2, bc->bc_dev_list_len); | |||
| 3596 | ||||
| 3597 | sr_discipline_shutdown(sd, 0, 0); | |||
| 3598 | ||||
| 3599 | if (rv == EAGAIN35) | |||
| 3600 | rv = 0; | |||
| 3601 | ||||
| 3602 | return (rv); | |||
| 3603 | } | |||
| 3604 | ||||
| 3605 | int | |||
| 3606 | sr_ioctl_deleteraid(struct sr_softc *sc, struct sr_discipline *sd, | |||
| 3607 | struct bioc_deleteraid *bd) | |||
| 3608 | { | |||
| 3609 | int rv = 1; | |||
| 3610 | ||||
| 3611 | DNPRINTF(SR_D_IOCTL, "%s: sr_ioctl_deleteraid %s\n", | |||
| 3612 | DEVNAME(sc), bd->bd_dev); | |||
| 3613 | ||||
| 3614 | if (sd == NULL((void *)0) && (sd = sr_find_discipline(sc, bd->bd_dev)) == NULL((void *)0)) { | |||
| 3615 | sr_error(sc, "volume %s not found", bd->bd_dev); | |||
| 3616 | goto bad; | |||
| 3617 | } | |||
| 3618 | ||||
| 3619 | /* | |||
| 3620 | * XXX Better check for mounted file systems and refuse to detach any | |||
| 3621 | * volume that is actively in use. | |||
| 3622 | */ | |||
| 3623 | if (bcmp(&sr_bootuuid, &sd->sd_meta->ssdi_sdd_invariant.ssd_uuid, | |||
| 3624 | sizeof(sr_bootuuid)) == 0) { | |||
| 3625 | sr_error(sc, "refusing to delete boot volume"); | |||
| 3626 | goto bad; | |||
| 3627 | } | |||
| 3628 | ||||
| 3629 | sd->sd_deleted = 1; | |||
| 3630 | sd->sd_meta->ssdi_sdd_invariant.ssd_vol_flags = BIOC_SCNOAUTOASSEMBLE0x04; | |||
| 3631 | sr_discipline_shutdown(sd, 1, 0); | |||
| 3632 | ||||
| 3633 | rv = 0; | |||
| 3634 | bad: | |||
| 3635 | return (rv); | |||
| 3636 | } | |||
| 3637 | ||||
| 3638 | int | |||
| 3639 | sr_ioctl_discipline(struct sr_softc *sc, struct sr_discipline *sd, | |||
| 3640 | struct bioc_discipline *bd) | |||
| 3641 | { | |||
| 3642 | int rv = 1; | |||
| 3643 | ||||
| 3644 | /* Dispatch a discipline specific ioctl. */ | |||
| 3645 | ||||
| 3646 | DNPRINTF(SR_D_IOCTL, "%s: sr_ioctl_discipline %s\n", DEVNAME(sc), | |||
| 3647 | bd->bd_dev); | |||
| 3648 | ||||
| 3649 | if (sd == NULL((void *)0) && (sd = sr_find_discipline(sc, bd->bd_dev)) == NULL((void *)0)) { | |||
| 3650 | sr_error(sc, "volume %s not found", bd->bd_dev); | |||
| 3651 | goto bad; | |||
| 3652 | } | |||
| 3653 | ||||
| 3654 | if (sd->sd_ioctl_handler) | |||
| 3655 | rv = sd->sd_ioctl_handler(sd, bd); | |||
| 3656 | ||||
| 3657 | bad: | |||
| 3658 | return (rv); | |||
| 3659 | } | |||
| 3660 | ||||
| 3661 | int | |||
| 3662 | sr_ioctl_installboot(struct sr_softc *sc, struct sr_discipline *sd, | |||
| 3663 | struct bioc_installboot *bb) | |||
| 3664 | { | |||
| 3665 | void *bootblk = NULL((void *)0), *bootldr = NULL((void *)0); | |||
| 3666 | struct sr_chunk *chunk; | |||
| 3667 | struct sr_meta_opt_item *omi; | |||
| 3668 | struct sr_meta_boot *sbm; | |||
| 3669 | struct disk *dk; | |||
| 3670 | u_int32_t bbs = 0, bls = 0, secsize; | |||
| 3671 | u_char duid[8]; | |||
| 3672 | int rv = EINVAL22; | |||
| 3673 | int i; | |||
| 3674 | ||||
| 3675 | DNPRINTF(SR_D_IOCTL, "%s: sr_ioctl_installboot %s\n", DEVNAME(sc), | |||
| 3676 | bb->bb_dev); | |||
| 3677 | ||||
| 3678 | if (sd == NULL((void *)0) && (sd = sr_find_discipline(sc, bb->bb_dev)) == NULL((void *)0)) { | |||
| 3679 | sr_error(sc, "volume %s not found", bb->bb_dev); | |||
| 3680 | goto done; | |||
| 3681 | } | |||
| 3682 | ||||
| 3683 | TAILQ_FOREACH(dk, &disklist, dk_link)for((dk) = ((&disklist)->tqh_first); (dk) != ((void *) 0); (dk) = ((dk)->dk_link.tqe_next)) | |||
| 3684 | if (!strncmp(dk->dk_name, bb->bb_dev, sizeof(bb->bb_dev))) | |||
| 3685 | break; | |||
| 3686 | if (dk == NULL((void *)0) || dk->dk_label == NULL((void *)0) || | |||
| 3687 | duid_iszero(dk->dk_label->d_uid)) { | |||
| 3688 | sr_error(sc, "failed to get DUID for softraid volume"); | |||
| 3689 | goto done; | |||
| 3690 | } | |||
| 3691 | memcpy(duid, dk->dk_label->d_uid, sizeof(duid))__builtin_memcpy((duid), (dk->dk_label->d_uid), (sizeof (duid))); | |||
| 3692 | ||||
| 3693 | /* Ensure that boot storage area is large enough. */ | |||
| 3694 | if (sd->sd_meta->ssd_data_blkno < (SR_BOOT_OFFSET(16 + 64) + SR_BOOT_SIZE(320 + 128))) { | |||
| 3695 | sr_error(sc, "insufficient boot storage"); | |||
| 3696 | goto done; | |||
| 3697 | } | |||
| 3698 | ||||
| 3699 | if (bb->bb_bootblk_size > SR_BOOT_BLOCKS_SIZE128 * DEV_BSIZE(1 << 9)) { | |||
| 3700 | sr_error(sc, "boot block too large (%d > %d)", | |||
| 3701 | bb->bb_bootblk_size, SR_BOOT_BLOCKS_SIZE128 * DEV_BSIZE(1 << 9)); | |||
| 3702 | goto done; | |||
| 3703 | } | |||
| 3704 | ||||
| 3705 | if (bb->bb_bootldr_size > SR_BOOT_LOADER_SIZE320 * DEV_BSIZE(1 << 9)) { | |||
| 3706 | sr_error(sc, "boot loader too large (%d > %d)", | |||
| 3707 | bb->bb_bootldr_size, SR_BOOT_LOADER_SIZE320 * DEV_BSIZE(1 << 9)); | |||
| 3708 | goto done; | |||
| 3709 | } | |||
| 3710 | ||||
| 3711 | secsize = sd->sd_meta->ssdi_sdd_invariant.ssd_secsize; | |||
| 3712 | ||||
| 3713 | /* Copy in boot block. */ | |||
| 3714 | bbs = howmany(bb->bb_bootblk_size, secsize)(((bb->bb_bootblk_size) + ((secsize) - 1)) / (secsize)) * secsize; | |||
| 3715 | bootblk = malloc(bbs, M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 3716 | if (copyin(bb->bb_bootblk, bootblk, bb->bb_bootblk_size) != 0) | |||
| 3717 | goto done; | |||
| 3718 | ||||
| 3719 | /* Copy in boot loader. */ | |||
| 3720 | bls = howmany(bb->bb_bootldr_size, secsize)(((bb->bb_bootldr_size) + ((secsize) - 1)) / (secsize)) * secsize; | |||
| 3721 | bootldr = malloc(bls, M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 3722 | if (copyin(bb->bb_bootldr, bootldr, bb->bb_bootldr_size) != 0) | |||
| 3723 | goto done; | |||
| 3724 | ||||
| 3725 | /* Create or update optional meta for bootable volumes. */ | |||
| 3726 | SLIST_FOREACH(omi, &sd->sd_meta_opt, omi_link)for((omi) = ((&sd->sd_meta_opt)->slh_first); (omi) != ((void *)0); (omi) = ((omi)->omi_link.sle_next)) | |||
| 3727 | if (omi->omi_som->som_type == SR_OPT_BOOT0x02) | |||
| 3728 | break; | |||
| 3729 | if (omi == NULL((void *)0)) { | |||
| 3730 | omi = malloc(sizeof(struct sr_meta_opt_item), M_DEVBUF2, | |||
| 3731 | M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 3732 | omi->omi_som = malloc(sizeof(struct sr_meta_boot), M_DEVBUF2, | |||
| 3733 | M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 3734 | omi->omi_som->som_type = SR_OPT_BOOT0x02; | |||
| 3735 | omi->omi_som->som_length = sizeof(struct sr_meta_boot); | |||
| 3736 | SLIST_INSERT_HEAD(&sd->sd_meta_opt, omi, omi_link)do { (omi)->omi_link.sle_next = (&sd->sd_meta_opt)-> slh_first; (&sd->sd_meta_opt)->slh_first = (omi); } while (0); | |||
| 3737 | sd->sd_meta->ssdi_sdd_invariant.ssd_opt_no++; | |||
| 3738 | } | |||
| 3739 | sbm = (struct sr_meta_boot *)omi->omi_som; | |||
| 3740 | ||||
| 3741 | memcpy(sbm->sbm_root_duid, duid, sizeof(sbm->sbm_root_duid))__builtin_memcpy((sbm->sbm_root_duid), (duid), (sizeof(sbm ->sbm_root_duid))); | |||
| 3742 | bzero(&sbm->sbm_boot_duid, sizeof(sbm->sbm_boot_duid))__builtin_bzero((&sbm->sbm_boot_duid), (sizeof(sbm-> sbm_boot_duid))); | |||
| 3743 | sbm->sbm_bootblk_size = bbs; | |||
| 3744 | sbm->sbm_bootldr_size = bls; | |||
| 3745 | ||||
| 3746 | DNPRINTF(SR_D_IOCTL, "sr_ioctl_installboot: root duid is %s\n", | |||
| 3747 | duid_format(sbm->sbm_root_duid)); | |||
| 3748 | ||||
| 3749 | /* Save boot block and boot loader to each chunk. */ | |||
| 3750 | for (i = 0; i < sd->sd_meta->ssdi_sdd_invariant.ssd_chunk_no; i++) { | |||
| 3751 | ||||
| 3752 | chunk = sd->sd_vol.sv_chunks[i]; | |||
| 3753 | if (chunk->src_meta.scm_status != BIOC_SDONLINE0x00 && | |||
| 3754 | chunk->src_meta.scm_status != BIOC_SDREBUILD0x03) | |||
| 3755 | continue; | |||
| 3756 | ||||
| 3757 | if (i < SR_MAX_BOOT_DISKS16) | |||
| 3758 | memcpy(&sbm->sbm_boot_duid[i], chunk->src_duid,__builtin_memcpy((&sbm->sbm_boot_duid[i]), (chunk-> src_duid), (sizeof(sbm->sbm_boot_duid[i]))) | |||
| 3759 | sizeof(sbm->sbm_boot_duid[i]))__builtin_memcpy((&sbm->sbm_boot_duid[i]), (chunk-> src_duid), (sizeof(sbm->sbm_boot_duid[i]))); | |||
| 3760 | ||||
| 3761 | /* Save boot blocks. */ | |||
| 3762 | DNPRINTF(SR_D_IOCTL, | |||
| 3763 | "sr_ioctl_installboot: saving boot block to %s " | |||
| 3764 | "(%u bytes)\n", chunk->src_devname, bbs); | |||
| 3765 | ||||
| 3766 | if (sr_rw(sc, chunk->src_dev_mm, bootblk, bbs, | |||
| 3767 | SR_BOOT_BLOCKS_OFFSET((16 + 64) + 320), B_WRITE0x00000000)) { | |||
| 3768 | sr_error(sc, "failed to write boot block"); | |||
| 3769 | goto done; | |||
| 3770 | } | |||
| 3771 | ||||
| 3772 | /* Save boot loader.*/ | |||
| 3773 | DNPRINTF(SR_D_IOCTL, | |||
| 3774 | "sr_ioctl_installboot: saving boot loader to %s " | |||
| 3775 | "(%u bytes)\n", chunk->src_devname, bls); | |||
| 3776 | ||||
| 3777 | if (sr_rw(sc, chunk->src_dev_mm, bootldr, bls, | |||
| 3778 | SR_BOOT_LOADER_OFFSET(16 + 64), B_WRITE0x00000000)) { | |||
| 3779 | sr_error(sc, "failed to write boot loader"); | |||
| 3780 | goto done; | |||
| 3781 | } | |||
| 3782 | } | |||
| 3783 | ||||
| 3784 | /* XXX - Install boot block on disk - MD code. */ | |||
| 3785 | ||||
| 3786 | /* Mark volume as bootable and save metadata. */ | |||
| 3787 | sd->sd_meta->ssdi_sdd_invariant.ssd_vol_flags |= BIOC_SCBOOTABLE0x08; | |||
| 3788 | if (sr_meta_save(sd, SR_META_DIRTY0x1)) { | |||
| 3789 | sr_error(sc, "could not save metadata to %s", DEVNAME(sc)((sc)->sc_dev.dv_xname)); | |||
| 3790 | goto done; | |||
| 3791 | } | |||
| 3792 | ||||
| 3793 | rv = 0; | |||
| 3794 | ||||
| 3795 | done: | |||
| 3796 | free(bootblk, M_DEVBUF2, bbs); | |||
| 3797 | free(bootldr, M_DEVBUF2, bls); | |||
| 3798 | ||||
| 3799 | return (rv); | |||
| 3800 | } | |||
| 3801 | ||||
| 3802 | void | |||
| 3803 | sr_chunks_unwind(struct sr_softc *sc, struct sr_chunk_head *cl) | |||
| 3804 | { | |||
| 3805 | struct sr_chunk *ch_entry, *ch_next; | |||
| 3806 | ||||
| 3807 | DNPRINTF(SR_D_IOCTL, "%s: sr_chunks_unwind\n", DEVNAME(sc)); | |||
| 3808 | ||||
| 3809 | if (!cl) | |||
| 3810 | return; | |||
| 3811 | ||||
| 3812 | for (ch_entry = SLIST_FIRST(cl)((cl)->slh_first); ch_entry != NULL((void *)0); ch_entry = ch_next) { | |||
| 3813 | ch_next = SLIST_NEXT(ch_entry, src_link)((ch_entry)->src_link.sle_next); | |||
| 3814 | ||||
| 3815 | DNPRINTF(SR_D_IOCTL, "%s: sr_chunks_unwind closing: %s\n", | |||
| 3816 | DEVNAME(sc), ch_entry->src_devname); | |||
| 3817 | if (ch_entry->src_vn) { | |||
| 3818 | /* | |||
| 3819 | * XXX - explicitly lock the vnode until we can resolve | |||
| 3820 | * the problem introduced by vnode aliasing... specfs | |||
| 3821 | * has no locking, whereas ufs/ffs does! | |||
| 3822 | */ | |||
| 3823 | vn_lock(ch_entry->src_vn, LK_EXCLUSIVE0x0001UL | LK_RETRY0x2000UL); | |||
| 3824 | VOP_CLOSE(ch_entry->src_vn, FREAD0x0001 | FWRITE0x0002, NOCRED((struct ucred *)-1), | |||
| 3825 | curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc); | |||
| 3826 | vput(ch_entry->src_vn); | |||
| 3827 | } | |||
| 3828 | free(ch_entry, M_DEVBUF2, sizeof(*ch_entry)); | |||
| 3829 | } | |||
| 3830 | SLIST_INIT(cl){ ((cl)->slh_first) = ((void *)0); }; | |||
| 3831 | } | |||
| 3832 | ||||
| 3833 | void | |||
| 3834 | sr_discipline_free(struct sr_discipline *sd) | |||
| 3835 | { | |||
| 3836 | struct sr_softc *sc; | |||
| 3837 | struct sr_discipline *sdtmp1; | |||
| 3838 | struct sr_meta_opt_head *som; | |||
| 3839 | struct sr_meta_opt_item *omi, *omi_next; | |||
| 3840 | ||||
| 3841 | if (!sd) | |||
| 3842 | return; | |||
| 3843 | ||||
| 3844 | sc = sd->sd_sc; | |||
| 3845 | ||||
| 3846 | DNPRINTF(SR_D_DIS, "%s: sr_discipline_free %s\n", | |||
| 3847 | DEVNAME(sc), | |||
| 3848 | sd->sd_meta ? sd->sd_meta->ssd_devname : "nodev"); | |||
| 3849 | if (sd->sd_free_resources) | |||
| 3850 | sd->sd_free_resources(sd); | |||
| 3851 | free(sd->sd_vol.sv_chunks, M_DEVBUF2, 0); | |||
| 3852 | free(sd->sd_meta, M_DEVBUF2, SR_META_SIZE64 * DEV_BSIZE(1 << 9)); | |||
| 3853 | free(sd->sd_meta_foreign, M_DEVBUF2, smd[sd->sd_meta_type].smd_size); | |||
| 3854 | ||||
| 3855 | som = &sd->sd_meta_opt; | |||
| 3856 | for (omi = SLIST_FIRST(som)((som)->slh_first); omi != NULL((void *)0); omi = omi_next) { | |||
| 3857 | omi_next = SLIST_NEXT(omi, omi_link)((omi)->omi_link.sle_next); | |||
| 3858 | free(omi->omi_som, M_DEVBUF2, 0); | |||
| 3859 | free(omi, M_DEVBUF2, sizeof(*omi)); | |||
| 3860 | } | |||
| 3861 | ||||
| 3862 | if (sd->sd_target != 0) { | |||
| 3863 | KASSERT(sc->sc_targets[sd->sd_target] == sd)((sc->sc_targets[sd->sd_target] == sd) ? (void)0 : __assert ("diagnostic ", "/usr/src/sys/dev/softraid.c", 3863, "sc->sc_targets[sd->sd_target] == sd" )); | |||
| 3864 | sc->sc_targets[sd->sd_target] = NULL((void *)0); | |||
| 3865 | } | |||
| 3866 | ||||
| 3867 | TAILQ_FOREACH(sdtmp1, &sc->sc_dis_list, sd_link)for((sdtmp1) = ((&sc->sc_dis_list)->tqh_first); (sdtmp1 ) != ((void *)0); (sdtmp1) = ((sdtmp1)->sd_link.tqe_next)) { | |||
| 3868 | if (sdtmp1 == sd) | |||
| 3869 | break; | |||
| 3870 | } | |||
| 3871 | if (sdtmp1 != NULL((void *)0)) | |||
| 3872 | TAILQ_REMOVE(&sc->sc_dis_list, sd, sd_link)do { if (((sd)->sd_link.tqe_next) != ((void *)0)) (sd)-> sd_link.tqe_next->sd_link.tqe_prev = (sd)->sd_link.tqe_prev ; else (&sc->sc_dis_list)->tqh_last = (sd)->sd_link .tqe_prev; *(sd)->sd_link.tqe_prev = (sd)->sd_link.tqe_next ; ((sd)->sd_link.tqe_prev) = ((void *)-1); ((sd)->sd_link .tqe_next) = ((void *)-1); } while (0); | |||
| 3873 | ||||
| 3874 | explicit_bzero(sd, sizeof *sd); | |||
| 3875 | free(sd, M_DEVBUF2, sizeof(*sd)); | |||
| 3876 | } | |||
| 3877 | ||||
| 3878 | void | |||
| 3879 | sr_discipline_shutdown(struct sr_discipline *sd, int meta_save, int dying) | |||
| 3880 | { | |||
| 3881 | struct sr_softc *sc; | |||
| 3882 | int ret, s; | |||
| 3883 | ||||
| 3884 | if (!sd) | |||
| 3885 | return; | |||
| 3886 | sc = sd->sd_sc; | |||
| 3887 | ||||
| 3888 | DNPRINTF(SR_D_DIS, "%s: sr_discipline_shutdown %s\n", DEVNAME(sc), | |||
| 3889 | sd->sd_meta ? sd->sd_meta->ssd_devname : "nodev"); | |||
| 3890 | ||||
| 3891 | /* If rebuilding, abort rebuild and drain I/O. */ | |||
| 3892 | if (sd->sd_reb_active) { | |||
| 3893 | sd->sd_reb_abort = 1; | |||
| 3894 | while (sd->sd_reb_active) | |||
| 3895 | tsleep_nsec(sd, PWAIT32, "sr_shutdown", MSEC_TO_NSEC(1)); | |||
| 3896 | } | |||
| 3897 | ||||
| 3898 | if (meta_save) | |||
| 3899 | sr_meta_save(sd, 0); | |||
| 3900 | ||||
| 3901 | s = splbio()splraise(0x3); | |||
| 3902 | ||||
| 3903 | sd->sd_ready = 0; | |||
| 3904 | ||||
| 3905 | /* make sure there isn't a sync pending and yield */ | |||
| 3906 | wakeup(sd); | |||
| 3907 | while (sd->sd_sync || sd->sd_must_flush) { | |||
| 3908 | ret = tsleep_nsec(&sd->sd_sync, MAXPRI127, "sr_down", | |||
| 3909 | SEC_TO_NSEC(60)); | |||
| 3910 | if (ret == EWOULDBLOCK35) | |||
| 3911 | break; | |||
| 3912 | } | |||
| 3913 | if (dying == -1) { | |||
| 3914 | sd->sd_ready = 1; | |||
| 3915 | splx(s)spllower(s); | |||
| 3916 | return; | |||
| 3917 | } | |||
| 3918 | ||||
| 3919 | #ifndef SMALL_KERNEL | |||
| 3920 | sr_sensors_delete(sd); | |||
| 3921 | #endif /* SMALL_KERNEL */ | |||
| 3922 | ||||
| 3923 | if (sd->sd_target != 0) | |||
| 3924 | scsi_detach_lun(sc->sc_scsibus, sd->sd_target, 0, | |||
| 3925 | dying ? 0 : DETACH_FORCE0x01); | |||
| 3926 | ||||
| 3927 | sr_chunks_unwind(sc, &sd->sd_vol.sv_chunk_list); | |||
| 3928 | ||||
| 3929 | if (sd->sd_taskq) | |||
| 3930 | taskq_destroy(sd->sd_taskq); | |||
| 3931 | ||||
| 3932 | sr_discipline_free(sd); | |||
| 3933 | ||||
| 3934 | splx(s)spllower(s); | |||
| 3935 | } | |||
| 3936 | ||||
| 3937 | int | |||
| 3938 | sr_discipline_init(struct sr_discipline *sd, int level) | |||
| 3939 | { | |||
| 3940 | int rv = 1; | |||
| 3941 | ||||
| 3942 | /* Initialise discipline function pointers with defaults. */ | |||
| 3943 | sd->sd_alloc_resources = sr_alloc_resources; | |||
| 3944 | sd->sd_assemble = NULL((void *)0); | |||
| 3945 | sd->sd_create = NULL((void *)0); | |||
| 3946 | sd->sd_free_resources = sr_free_resources; | |||
| 3947 | sd->sd_ioctl_handler = NULL((void *)0); | |||
| 3948 | sd->sd_openings = NULL((void *)0); | |||
| 3949 | sd->sd_meta_opt_handler = NULL((void *)0); | |||
| 3950 | sd->sd_rebuild = sr_rebuild; | |||
| 3951 | sd->sd_scsi_inquiry = sr_raid_inquiry; | |||
| 3952 | sd->sd_scsi_read_cap = sr_raid_read_cap; | |||
| 3953 | sd->sd_scsi_tur = sr_raid_tur; | |||
| 3954 | sd->sd_scsi_req_sense = sr_raid_request_sense; | |||
| 3955 | sd->sd_scsi_start_stop = sr_raid_start_stop; | |||
| 3956 | sd->sd_scsi_sync = sr_raid_sync; | |||
| 3957 | sd->sd_scsi_rw = NULL((void *)0); | |||
| 3958 | sd->sd_scsi_intr = sr_raid_intr; | |||
| 3959 | sd->sd_scsi_wu_done = NULL((void *)0); | |||
| 3960 | sd->sd_scsi_done = NULL((void *)0); | |||
| 3961 | sd->sd_set_chunk_state = sr_set_chunk_state; | |||
| 3962 | sd->sd_set_vol_state = sr_set_vol_state; | |||
| 3963 | sd->sd_start_discipline = NULL((void *)0); | |||
| 3964 | ||||
| 3965 | task_set(&sd->sd_meta_save_task, sr_meta_save_callback, sd); | |||
| 3966 | task_set(&sd->sd_hotspare_rebuild_task, sr_hotspare_rebuild_callback, | |||
| 3967 | sd); | |||
| 3968 | ||||
| 3969 | sd->sd_wu_size = sizeof(struct sr_workunit); | |||
| 3970 | switch (level) { | |||
| 3971 | case 0: | |||
| 3972 | sr_raid0_discipline_init(sd); | |||
| 3973 | break; | |||
| 3974 | case 1: | |||
| 3975 | sr_raid1_discipline_init(sd); | |||
| 3976 | break; | |||
| 3977 | case 5: | |||
| 3978 | sr_raid5_discipline_init(sd); | |||
| 3979 | break; | |||
| 3980 | case 6: | |||
| 3981 | sr_raid6_discipline_init(sd); | |||
| 3982 | break; | |||
| 3983 | #ifdef CRYPTO1 | |||
| 3984 | case 'C': | |||
| 3985 | sr_crypto_discipline_init(sd); | |||
| 3986 | break; | |||
| 3987 | case 0x1C: | |||
| 3988 | sr_raid1c_discipline_init(sd); | |||
| 3989 | break; | |||
| 3990 | #endif | |||
| 3991 | case 'c': | |||
| 3992 | sr_concat_discipline_init(sd); | |||
| 3993 | break; | |||
| 3994 | default: | |||
| 3995 | goto bad; | |||
| 3996 | } | |||
| 3997 | ||||
| 3998 | rv = 0; | |||
| 3999 | bad: | |||
| 4000 | return (rv); | |||
| 4001 | } | |||
| 4002 | ||||
| 4003 | int | |||
| 4004 | sr_raid_inquiry(struct sr_workunit *wu) | |||
| 4005 | { | |||
| 4006 | struct sr_discipline *sd = wu->swu_dis; | |||
| 4007 | struct scsi_xfer *xs = wu->swu_xs; | |||
| 4008 | struct scsi_inquiry *cdb = (struct scsi_inquiry *)&xs->cmd; | |||
| 4009 | struct scsi_inquiry_data inq; | |||
| 4010 | ||||
| 4011 | DNPRINTF(SR_D_DIS, "%s: sr_raid_inquiry\n", DEVNAME(sd->sd_sc)); | |||
| 4012 | ||||
| 4013 | if (xs->cmdlen != sizeof(*cdb)) | |||
| 4014 | return (EINVAL22); | |||
| 4015 | ||||
| 4016 | if (ISSET(cdb->flags, SI_EVPD)((cdb->flags) & (0x01))) | |||
| 4017 | return (EOPNOTSUPP45); | |||
| 4018 | ||||
| 4019 | bzero(&inq, sizeof(inq))__builtin_bzero((&inq), (sizeof(inq))); | |||
| 4020 | inq.device = T_DIRECT0x00; | |||
| 4021 | inq.dev_qual2 = 0; | |||
| 4022 | inq.version = SCSI_REV_20x02; | |||
| 4023 | inq.response_format = SID_SCSI2_RESPONSE0x02; | |||
| 4024 | inq.additional_length = SID_SCSI2_ALEN31; | |||
| 4025 | inq.flags |= SID_CmdQue0x02; | |||
| 4026 | strlcpy(inq.vendor, sd->sd_meta->ssdi_sdd_invariant.ssd_vendor, | |||
| 4027 | sizeof(inq.vendor)); | |||
| 4028 | strlcpy(inq.product, sd->sd_meta->ssdi_sdd_invariant.ssd_product, | |||
| 4029 | sizeof(inq.product)); | |||
| 4030 | strlcpy(inq.revision, sd->sd_meta->ssdi_sdd_invariant.ssd_revision, | |||
| 4031 | sizeof(inq.revision)); | |||
| 4032 | scsi_copy_internal_data(xs, &inq, sizeof(inq)); | |||
| 4033 | ||||
| 4034 | return (0); | |||
| 4035 | } | |||
| 4036 | ||||
| 4037 | int | |||
| 4038 | sr_raid_read_cap(struct sr_workunit *wu) | |||
| 4039 | { | |||
| 4040 | struct sr_discipline *sd = wu->swu_dis; | |||
| 4041 | struct scsi_xfer *xs = wu->swu_xs; | |||
| 4042 | struct scsi_read_cap_data rcd; | |||
| 4043 | struct scsi_read_cap_data_16 rcd16; | |||
| 4044 | u_int64_t addr; | |||
| 4045 | int rv = 1; | |||
| 4046 | u_int32_t secsize; | |||
| 4047 | ||||
| 4048 | DNPRINTF(SR_D_DIS, "%s: sr_raid_read_cap\n", DEVNAME(sd->sd_sc)); | |||
| 4049 | ||||
| 4050 | secsize = sd->sd_meta->ssdi_sdd_invariant.ssd_secsize; | |||
| 4051 | ||||
| 4052 | addr = ((sd->sd_meta->ssdi_sdd_invariant.ssd_size * DEV_BSIZE(1 << 9)) / secsize) - 1; | |||
| 4053 | if (xs->cmd.opcode == READ_CAPACITY0x25) { | |||
| 4054 | bzero(&rcd, sizeof(rcd))__builtin_bzero((&rcd), (sizeof(rcd))); | |||
| 4055 | if (addr > 0xffffffffllu) | |||
| 4056 | _lto4b(0xffffffff, rcd.addr); | |||
| 4057 | else | |||
| 4058 | _lto4b(addr, rcd.addr); | |||
| 4059 | _lto4b(secsize, rcd.length); | |||
| 4060 | scsi_copy_internal_data(xs, &rcd, sizeof(rcd)); | |||
| 4061 | rv = 0; | |||
| 4062 | } else if (xs->cmd.opcode == READ_CAPACITY_160x9e) { | |||
| 4063 | bzero(&rcd16, sizeof(rcd16))__builtin_bzero((&rcd16), (sizeof(rcd16))); | |||
| 4064 | _lto8b(addr, rcd16.addr); | |||
| 4065 | _lto4b(secsize, rcd16.length); | |||
| 4066 | scsi_copy_internal_data(xs, &rcd16, sizeof(rcd16)); | |||
| 4067 | rv = 0; | |||
| 4068 | } | |||
| 4069 | ||||
| 4070 | return (rv); | |||
| 4071 | } | |||
| 4072 | ||||
| 4073 | int | |||
| 4074 | sr_raid_tur(struct sr_workunit *wu) | |||
| 4075 | { | |||
| 4076 | struct sr_discipline *sd = wu->swu_dis; | |||
| 4077 | ||||
| 4078 | DNPRINTF(SR_D_DIS, "%s: sr_raid_tur\n", DEVNAME(sd->sd_sc)); | |||
| 4079 | ||||
| 4080 | if (sd->sd_vol_status == BIOC_SVOFFLINE0x01) { | |||
| 4081 | sd->sd_scsi_sense.error_code = SSD_ERRCODE_CURRENT0x70; | |||
| 4082 | sd->sd_scsi_sense.flags = SKEY_NOT_READY0x02; | |||
| 4083 | sd->sd_scsi_sense.add_sense_code = 0x04; | |||
| 4084 | sd->sd_scsi_sense.add_sense_code_qual = 0x11; | |||
| 4085 | sd->sd_scsi_sense.extra_len = 4; | |||
| 4086 | return (1); | |||
| 4087 | } else if (sd->sd_vol_status == BIOC_SVINVALID0xff) { | |||
| 4088 | sd->sd_scsi_sense.error_code = SSD_ERRCODE_CURRENT0x70; | |||
| 4089 | sd->sd_scsi_sense.flags = SKEY_HARDWARE_ERROR0x04; | |||
| 4090 | sd->sd_scsi_sense.add_sense_code = 0x05; | |||
| 4091 | sd->sd_scsi_sense.add_sense_code_qual = 0x00; | |||
| 4092 | sd->sd_scsi_sense.extra_len = 4; | |||
| 4093 | return (1); | |||
| 4094 | } | |||
| 4095 | ||||
| 4096 | return (0); | |||
| 4097 | } | |||
| 4098 | ||||
| 4099 | int | |||
| 4100 | sr_raid_request_sense(struct sr_workunit *wu) | |||
| 4101 | { | |||
| 4102 | struct sr_discipline *sd = wu->swu_dis; | |||
| 4103 | struct scsi_xfer *xs = wu->swu_xs; | |||
| 4104 | ||||
| 4105 | DNPRINTF(SR_D_DIS, "%s: sr_raid_request_sense\n", | |||
| 4106 | DEVNAME(sd->sd_sc)); | |||
| 4107 | ||||
| 4108 | /* use latest sense data */ | |||
| 4109 | memcpy(&xs->sense, &sd->sd_scsi_sense, sizeof(xs->sense))__builtin_memcpy((&xs->sense), (&sd->sd_scsi_sense ), (sizeof(xs->sense))); | |||
| 4110 | ||||
| 4111 | /* clear sense data */ | |||
| 4112 | bzero(&sd->sd_scsi_sense, sizeof(sd->sd_scsi_sense))__builtin_bzero((&sd->sd_scsi_sense), (sizeof(sd->sd_scsi_sense ))); | |||
| 4113 | ||||
| 4114 | return (0); | |||
| 4115 | } | |||
| 4116 | ||||
| 4117 | int | |||
| 4118 | sr_raid_start_stop(struct sr_workunit *wu) | |||
| 4119 | { | |||
| 4120 | struct scsi_xfer *xs = wu->swu_xs; | |||
| 4121 | struct scsi_start_stop *ss = (struct scsi_start_stop *)&xs->cmd; | |||
| 4122 | ||||
| 4123 | DNPRINTF(SR_D_DIS, "%s: sr_raid_start_stop\n", | |||
| 4124 | DEVNAME(wu->swu_dis->sd_sc)); | |||
| 4125 | ||||
| 4126 | if (!ss) | |||
| 4127 | return (1); | |||
| 4128 | ||||
| 4129 | /* | |||
| 4130 | * do nothing! | |||
| 4131 | * a softraid discipline should always reflect correct status | |||
| 4132 | */ | |||
| 4133 | return (0); | |||
| 4134 | } | |||
| 4135 | ||||
| 4136 | int | |||
| 4137 | sr_raid_sync(struct sr_workunit *wu) | |||
| 4138 | { | |||
| 4139 | struct sr_discipline *sd = wu->swu_dis; | |||
| 4140 | int s, ret, rv = 0, ios; | |||
| 4141 | ||||
| 4142 | DNPRINTF(SR_D_DIS, "%s: sr_raid_sync\n", DEVNAME(sd->sd_sc)); | |||
| 4143 | ||||
| 4144 | /* when doing a fake sync don't count the wu */ | |||
| 4145 | ios = (wu->swu_flags & SR_WUF_FAKE(1<<6)) ? 0 : 1; | |||
| 4146 | ||||
| 4147 | s = splbio()splraise(0x3); | |||
| 4148 | sd->sd_sync = 1; | |||
| 4149 | while (sd->sd_wu_pending > ios) { | |||
| 4150 | ret = tsleep_nsec(sd, PRIBIO16, "sr_sync", SEC_TO_NSEC(15)); | |||
| 4151 | if (ret == EWOULDBLOCK35) { | |||
| 4152 | DNPRINTF(SR_D_DIS, "%s: sr_raid_sync timeout\n", | |||
| 4153 | DEVNAME(sd->sd_sc)); | |||
| 4154 | rv = 1; | |||
| 4155 | break; | |||
| 4156 | } | |||
| 4157 | } | |||
| 4158 | sd->sd_sync = 0; | |||
| 4159 | splx(s)spllower(s); | |||
| 4160 | ||||
| 4161 | wakeup(&sd->sd_sync); | |||
| 4162 | ||||
| 4163 | return (rv); | |||
| 4164 | } | |||
| 4165 | ||||
| 4166 | void | |||
| 4167 | sr_raid_intr(struct buf *bp) | |||
| 4168 | { | |||
| 4169 | struct sr_ccb *ccb = (struct sr_ccb *)bp; | |||
| 4170 | struct sr_workunit *wu = ccb->ccb_wu; | |||
| 4171 | #ifdef SR_DEBUG | |||
| 4172 | struct sr_discipline *sd = wu->swu_dis; | |||
| 4173 | struct scsi_xfer *xs = wu->swu_xs; | |||
| 4174 | #endif | |||
| 4175 | int s; | |||
| 4176 | ||||
| 4177 | DNPRINTF(SR_D_INTR, "%s: %s %s intr bp %p xs %p\n", | |||
| 4178 | DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname, sd->sd_name, bp, xs); | |||
| 4179 | ||||
| 4180 | s = splbio()splraise(0x3); | |||
| 4181 | sr_ccb_done(ccb); | |||
| 4182 | sr_wu_done(wu); | |||
| 4183 | splx(s)spllower(s); | |||
| 4184 | } | |||
| 4185 | ||||
| 4186 | void | |||
| 4187 | sr_schedule_wu(struct sr_workunit *wu) | |||
| 4188 | { | |||
| 4189 | struct sr_discipline *sd = wu->swu_dis; | |||
| 4190 | struct sr_workunit *wup; | |||
| 4191 | int s; | |||
| 4192 | ||||
| 4193 | DNPRINTF(SR_D_WU, "sr_schedule_wu: schedule wu %p state %i " | |||
| 4194 | "flags 0x%x\n", wu, wu->swu_state, wu->swu_flags); | |||
| 4195 | ||||
| 4196 | KASSERT(wu->swu_io_count > 0)((wu->swu_io_count > 0) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/dev/softraid.c", 4196, "wu->swu_io_count > 0" )); | |||
| 4197 | ||||
| 4198 | s = splbio()splraise(0x3); | |||
| 4199 | ||||
| 4200 | /* Construct the work unit, do not schedule it. */ | |||
| 4201 | if (wu->swu_state == SR_WU_CONSTRUCT9) | |||
| 4202 | goto queued; | |||
| 4203 | ||||
| 4204 | /* Deferred work unit being reconstructed, do not start. */ | |||
| 4205 | if (wu->swu_state == SR_WU_REQUEUE8) | |||
| 4206 | goto queued; | |||
| 4207 | ||||
| 4208 | /* Current work unit failed, restart. */ | |||
| 4209 | if (wu->swu_state == SR_WU_RESTART7) | |||
| 4210 | goto start; | |||
| 4211 | ||||
| 4212 | if (wu->swu_state != SR_WU_INPROGRESS1) | |||
| 4213 | panic("sr_schedule_wu: work unit not in progress (state %i)", | |||
| 4214 | wu->swu_state); | |||
| 4215 | ||||
| 4216 | /* Walk queue backwards and fill in collider if we have one. */ | |||
| 4217 | TAILQ_FOREACH_REVERSE(wup, &sd->sd_wu_pendq, sr_wu_list, swu_link)for((wup) = (*(((struct sr_wu_list *)((&sd->sd_wu_pendq )->tqh_last))->tqh_last)); (wup) != ((void *)0); (wup) = (*(((struct sr_wu_list *)((wup)->swu_link.tqe_prev))-> tqh_last))) { | |||
| 4218 | if (wu->swu_blk_end < wup->swu_blk_start || | |||
| 4219 | wup->swu_blk_end < wu->swu_blk_start) | |||
| 4220 | continue; | |||
| 4221 | ||||
| 4222 | /* Defer work unit due to LBA collision. */ | |||
| 4223 | DNPRINTF(SR_D_WU, "sr_schedule_wu: deferring work unit %p\n", | |||
| 4224 | wu); | |||
| 4225 | wu->swu_state = SR_WU_DEFERRED5; | |||
| 4226 | while (wup->swu_collider) | |||
| 4227 | wup = wup->swu_collider; | |||
| 4228 | wup->swu_collider = wu; | |||
| 4229 | TAILQ_INSERT_TAIL(&sd->sd_wu_defq, wu, swu_link)do { (wu)->swu_link.tqe_next = ((void *)0); (wu)->swu_link .tqe_prev = (&sd->sd_wu_defq)->tqh_last; *(&sd-> sd_wu_defq)->tqh_last = (wu); (&sd->sd_wu_defq)-> tqh_last = &(wu)->swu_link.tqe_next; } while (0); | |||
| 4230 | sd->sd_wu_collisions++; | |||
| 4231 | goto queued; | |||
| 4232 | } | |||
| 4233 | ||||
| 4234 | start: | |||
| 4235 | sr_raid_startwu(wu); | |||
| 4236 | ||||
| 4237 | queued: | |||
| 4238 | splx(s)spllower(s); | |||
| 4239 | } | |||
| 4240 | ||||
| 4241 | void | |||
| 4242 | sr_raid_startwu(struct sr_workunit *wu) | |||
| 4243 | { | |||
| 4244 | struct sr_discipline *sd = wu->swu_dis; | |||
| 4245 | struct sr_ccb *ccb; | |||
| 4246 | ||||
| 4247 | DNPRINTF(SR_D_WU, "sr_raid_startwu: start wu %p\n", wu); | |||
| 4248 | ||||
| 4249 | splassert(IPL_BIO)do { if (splassert_ctl > 0) { splassert_check(0x3, __func__ ); } } while (0); | |||
| 4250 | ||||
| 4251 | if (wu->swu_state == SR_WU_DEFERRED5) { | |||
| 4252 | TAILQ_REMOVE(&sd->sd_wu_defq, wu, swu_link)do { if (((wu)->swu_link.tqe_next) != ((void *)0)) (wu)-> swu_link.tqe_next->swu_link.tqe_prev = (wu)->swu_link.tqe_prev ; else (&sd->sd_wu_defq)->tqh_last = (wu)->swu_link .tqe_prev; *(wu)->swu_link.tqe_prev = (wu)->swu_link.tqe_next ; ((wu)->swu_link.tqe_prev) = ((void *)-1); ((wu)->swu_link .tqe_next) = ((void *)-1); } while (0); | |||
| 4253 | wu->swu_state = SR_WU_INPROGRESS1; | |||
| 4254 | } | |||
| 4255 | ||||
| 4256 | if (wu->swu_state != SR_WU_RESTART7) | |||
| 4257 | TAILQ_INSERT_TAIL(&sd->sd_wu_pendq, wu, swu_link)do { (wu)->swu_link.tqe_next = ((void *)0); (wu)->swu_link .tqe_prev = (&sd->sd_wu_pendq)->tqh_last; *(&sd ->sd_wu_pendq)->tqh_last = (wu); (&sd->sd_wu_pendq )->tqh_last = &(wu)->swu_link.tqe_next; } while (0); | |||
| 4258 | ||||
| 4259 | /* Start all of the individual I/Os. */ | |||
| 4260 | if (wu->swu_cb_active == 1) | |||
| 4261 | panic("%s: sr_startwu_callback", DEVNAME(sd->sd_sc)((sd->sd_sc)->sc_dev.dv_xname)); | |||
| 4262 | wu->swu_cb_active = 1; | |||
| 4263 | ||||
| 4264 | TAILQ_FOREACH(ccb, &wu->swu_ccb, ccb_link)for((ccb) = ((&wu->swu_ccb)->tqh_first); (ccb) != ( (void *)0); (ccb) = ((ccb)->ccb_link.tqe_next)) | |||
| 4265 | VOP_STRATEGY(ccb->ccb_buf.b_vp, &ccb->ccb_buf); | |||
| 4266 | ||||
| 4267 | wu->swu_cb_active = 0; | |||
| 4268 | } | |||
| 4269 | ||||
| 4270 | void | |||
| 4271 | sr_raid_recreate_wu(struct sr_workunit *wu) | |||
| 4272 | { | |||
| 4273 | struct sr_discipline *sd = wu->swu_dis; | |||
| 4274 | struct sr_workunit *wup = wu; | |||
| 4275 | ||||
| 4276 | /* | |||
| 4277 | * Recreate a work unit by releasing the associated CCBs and reissuing | |||
| 4278 | * the SCSI I/O request. This process is then repeated for all of the | |||
| 4279 | * colliding work units. | |||
| 4280 | */ | |||
| 4281 | do { | |||
| 4282 | sr_wu_release_ccbs(wup); | |||
| 4283 | ||||
| 4284 | wup->swu_state = SR_WU_REQUEUE8; | |||
| 4285 | if (sd->sd_scsi_rw(wup)) | |||
| 4286 | panic("could not requeue I/O"); | |||
| 4287 | ||||
| 4288 | wup = wup->swu_collider; | |||
| 4289 | } while (wup); | |||
| 4290 | } | |||
| 4291 | ||||
| 4292 | int | |||
| 4293 | sr_alloc_resources(struct sr_discipline *sd) | |||
| 4294 | { | |||
| 4295 | if (sr_wu_alloc(sd)) { | |||
| 4296 | sr_error(sd->sd_sc, "unable to allocate work units"); | |||
| 4297 | return (ENOMEM12); | |||
| 4298 | } | |||
| 4299 | if (sr_ccb_alloc(sd)) { | |||
| 4300 | sr_error(sd->sd_sc, "unable to allocate ccbs"); | |||
| 4301 | return (ENOMEM12); | |||
| 4302 | } | |||
| 4303 | ||||
| 4304 | return (0); | |||
| 4305 | } | |||
| 4306 | ||||
| 4307 | void | |||
| 4308 | sr_free_resources(struct sr_discipline *sd) | |||
| 4309 | { | |||
| 4310 | sr_wu_free(sd); | |||
| 4311 | sr_ccb_free(sd); | |||
| 4312 | } | |||
| 4313 | ||||
| 4314 | void | |||
| 4315 | sr_set_chunk_state(struct sr_discipline *sd, int c, int new_state) | |||
| 4316 | { | |||
| 4317 | int old_state, s; | |||
| 4318 | ||||
| 4319 | DNPRINTF(SR_D_STATE, "%s: %s: %s: sr_set_chunk_state %d -> %d\n", | |||
| 4320 | DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname, | |||
| 4321 | sd->sd_vol.sv_chunks[c]->src_meta.scmi.scm_devname, c, new_state); | |||
| 4322 | ||||
| 4323 | /* ok to go to splbio since this only happens in error path */ | |||
| 4324 | s = splbio()splraise(0x3); | |||
| 4325 | old_state = sd->sd_vol.sv_chunks[c]->src_meta.scm_status; | |||
| 4326 | ||||
| 4327 | /* multiple IOs to the same chunk that fail will come through here */ | |||
| 4328 | if (old_state == new_state) | |||
| 4329 | goto done; | |||
| 4330 | ||||
| 4331 | switch (old_state) { | |||
| 4332 | case BIOC_SDONLINE0x00: | |||
| 4333 | if (new_state == BIOC_SDOFFLINE0x01) | |||
| 4334 | break; | |||
| 4335 | else | |||
| 4336 | goto die; | |||
| 4337 | break; | |||
| 4338 | ||||
| 4339 | case BIOC_SDOFFLINE0x01: | |||
| 4340 | goto die; | |||
| 4341 | ||||
| 4342 | default: | |||
| 4343 | die: | |||
| 4344 | splx(s)spllower(s); /* XXX */ | |||
| 4345 | panic("%s: %s: %s: invalid chunk state transition %d -> %d", | |||
| 4346 | DEVNAME(sd->sd_sc)((sd->sd_sc)->sc_dev.dv_xname), | |||
| 4347 | sd->sd_meta->ssd_devname, | |||
| 4348 | sd->sd_vol.sv_chunks[c]->src_meta.scmi_scm_invariant.scm_devname, | |||
| 4349 | old_state, new_state); | |||
| 4350 | /* NOTREACHED */ | |||
| 4351 | } | |||
| 4352 | ||||
| 4353 | sd->sd_vol.sv_chunks[c]->src_meta.scm_status = new_state; | |||
| 4354 | sd->sd_set_vol_state(sd); | |||
| 4355 | ||||
| 4356 | sd->sd_must_flush = 1; | |||
| 4357 | task_add(systq, &sd->sd_meta_save_task); | |||
| 4358 | done: | |||
| 4359 | splx(s)spllower(s); | |||
| 4360 | } | |||
| 4361 | ||||
| 4362 | void | |||
| 4363 | sr_set_vol_state(struct sr_discipline *sd) | |||
| 4364 | { | |||
| 4365 | int states[SR_MAX_STATES7]; | |||
| 4366 | int new_state, i, nd; | |||
| 4367 | int old_state = sd->sd_vol_status; | |||
| 4368 | u_int32_t s; | |||
| 4369 | ||||
| 4370 | DNPRINTF(SR_D_STATE, "%s: %s: sr_set_vol_state\n", | |||
| 4371 | DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname); | |||
| 4372 | ||||
| 4373 | nd = sd->sd_meta->ssdi_sdd_invariant.ssd_chunk_no; | |||
| 4374 | ||||
| 4375 | for (i = 0; i < SR_MAX_STATES7; i++) | |||
| 4376 | states[i] = 0; | |||
| 4377 | ||||
| 4378 | for (i = 0; i < nd; i++) { | |||
| 4379 | s = sd->sd_vol.sv_chunks[i]->src_meta.scm_status; | |||
| 4380 | if (s >= SR_MAX_STATES7) | |||
| 4381 | panic("%s: %s: %s: invalid chunk state", | |||
| 4382 | DEVNAME(sd->sd_sc)((sd->sd_sc)->sc_dev.dv_xname), | |||
| 4383 | sd->sd_meta->ssd_devname, | |||
| 4384 | sd->sd_vol.sv_chunks[i]->src_meta.scmi_scm_invariant.scm_devname); | |||
| 4385 | states[s]++; | |||
| 4386 | } | |||
| 4387 | ||||
| 4388 | if (states[BIOC_SDONLINE0x00] == nd) | |||
| 4389 | new_state = BIOC_SVONLINE0x00; | |||
| 4390 | else | |||
| 4391 | new_state = BIOC_SVOFFLINE0x01; | |||
| 4392 | ||||
| 4393 | DNPRINTF(SR_D_STATE, "%s: %s: sr_set_vol_state %d -> %d\n", | |||
| 4394 | DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname, | |||
| 4395 | old_state, new_state); | |||
| 4396 | ||||
| 4397 | switch (old_state) { | |||
| 4398 | case BIOC_SVONLINE0x00: | |||
| 4399 | if (new_state == BIOC_SVOFFLINE0x01 || new_state == BIOC_SVONLINE0x00) | |||
| 4400 | break; | |||
| 4401 | else | |||
| 4402 | goto die; | |||
| 4403 | break; | |||
| 4404 | ||||
| 4405 | case BIOC_SVOFFLINE0x01: | |||
| 4406 | /* XXX this might be a little too much */ | |||
| 4407 | goto die; | |||
| 4408 | ||||
| 4409 | default: | |||
| 4410 | die: | |||
| 4411 | panic("%s: %s: invalid volume state transition %d -> %d", | |||
| 4412 | DEVNAME(sd->sd_sc)((sd->sd_sc)->sc_dev.dv_xname), | |||
| 4413 | sd->sd_meta->ssd_devname, | |||
| 4414 | old_state, new_state); | |||
| 4415 | /* NOTREACHED */ | |||
| 4416 | } | |||
| 4417 | ||||
| 4418 | sd->sd_vol_status = new_state; | |||
| 4419 | } | |||
| 4420 | ||||
| 4421 | void * | |||
| 4422 | sr_block_get(struct sr_discipline *sd, long length) | |||
| 4423 | { | |||
| 4424 | return dma_alloc(length, PR_NOWAIT0x0002 | PR_ZERO0x0008); | |||
| 4425 | } | |||
| 4426 | ||||
| 4427 | void | |||
| 4428 | sr_block_put(struct sr_discipline *sd, void *ptr, int length) | |||
| 4429 | { | |||
| 4430 | dma_free(ptr, length); | |||
| 4431 | } | |||
| 4432 | ||||
| 4433 | void | |||
| 4434 | sr_checksum_print(u_int8_t *md5) | |||
| 4435 | { | |||
| 4436 | int i; | |||
| 4437 | ||||
| 4438 | for (i = 0; i < MD5_DIGEST_LENGTH16; i++) | |||
| 4439 | printf("%02x", md5[i]); | |||
| 4440 | } | |||
| 4441 | ||||
| 4442 | void | |||
| 4443 | sr_checksum(struct sr_softc *sc, void *src, void *md5, u_int32_t len) | |||
| 4444 | { | |||
| 4445 | MD5_CTX ctx; | |||
| 4446 | ||||
| 4447 | DNPRINTF(SR_D_MISC, "%s: sr_checksum(%p %p %d)\n", DEVNAME(sc), src, | |||
| 4448 | md5, len); | |||
| 4449 | ||||
| 4450 | MD5Init(&ctx); | |||
| 4451 | MD5Update(&ctx, src, len); | |||
| 4452 | MD5Final(md5, &ctx); | |||
| 4453 | } | |||
| 4454 | ||||
| 4455 | void | |||
| 4456 | sr_uuid_generate(struct sr_uuid *uuid) | |||
| 4457 | { | |||
| 4458 | arc4random_buf(uuid->sui_id, sizeof(uuid->sui_id)); | |||
| 4459 | /* UUID version 4: random */ | |||
| 4460 | uuid->sui_id[6] &= 0x0f; | |||
| 4461 | uuid->sui_id[6] |= 0x40; | |||
| 4462 | /* RFC4122 variant */ | |||
| 4463 | uuid->sui_id[8] &= 0x3f; | |||
| 4464 | uuid->sui_id[8] |= 0x80; | |||
| 4465 | } | |||
| 4466 | ||||
| 4467 | char * | |||
| 4468 | sr_uuid_format(struct sr_uuid *uuid) | |||
| 4469 | { | |||
| 4470 | char *uuidstr; | |||
| 4471 | ||||
| 4472 | uuidstr = malloc(37, M_DEVBUF2, M_WAITOK0x0001); | |||
| 4473 | ||||
| 4474 | snprintf(uuidstr, 37, | |||
| 4475 | "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" | |||
| 4476 | "%02x%02x%02x%02x%02x%02x", | |||
| 4477 | uuid->sui_id[0], uuid->sui_id[1], | |||
| 4478 | uuid->sui_id[2], uuid->sui_id[3], | |||
| 4479 | uuid->sui_id[4], uuid->sui_id[5], | |||
| 4480 | uuid->sui_id[6], uuid->sui_id[7], | |||
| 4481 | uuid->sui_id[8], uuid->sui_id[9], | |||
| 4482 | uuid->sui_id[10], uuid->sui_id[11], | |||
| 4483 | uuid->sui_id[12], uuid->sui_id[13], | |||
| 4484 | uuid->sui_id[14], uuid->sui_id[15]); | |||
| 4485 | ||||
| 4486 | return uuidstr; | |||
| 4487 | } | |||
| 4488 | ||||
| 4489 | void | |||
| 4490 | sr_uuid_print(struct sr_uuid *uuid, int cr) | |||
| 4491 | { | |||
| 4492 | char *uuidstr; | |||
| 4493 | ||||
| 4494 | uuidstr = sr_uuid_format(uuid); | |||
| 4495 | printf("%s%s", uuidstr, (cr ? "\n" : "")); | |||
| 4496 | free(uuidstr, M_DEVBUF2, 37); | |||
| 4497 | } | |||
| 4498 | ||||
| 4499 | int | |||
| 4500 | sr_already_assembled(struct sr_discipline *sd) | |||
| 4501 | { | |||
| 4502 | struct sr_softc *sc = sd->sd_sc; | |||
| 4503 | struct sr_discipline *sdtmp; | |||
| 4504 | ||||
| 4505 | TAILQ_FOREACH(sdtmp, &sc->sc_dis_list, sd_link)for((sdtmp) = ((&sc->sc_dis_list)->tqh_first); (sdtmp ) != ((void *)0); (sdtmp) = ((sdtmp)->sd_link.tqe_next)) { | |||
| 4506 | if (!bcmp(&sd->sd_meta->ssdi_sdd_invariant.ssd_uuid, | |||
| 4507 | &sdtmp->sd_meta->ssdi_sdd_invariant.ssd_uuid, | |||
| 4508 | sizeof(sd->sd_meta->ssdi_sdd_invariant.ssd_uuid))) | |||
| 4509 | return (1); | |||
| 4510 | } | |||
| 4511 | ||||
| 4512 | return (0); | |||
| 4513 | } | |||
| 4514 | ||||
| 4515 | int32_t | |||
| 4516 | sr_validate_stripsize(u_int32_t b) | |||
| 4517 | { | |||
| 4518 | int s = 0; | |||
| 4519 | ||||
| 4520 | if (b % DEV_BSIZE(1 << 9)) | |||
| 4521 | return (-1); | |||
| 4522 | ||||
| 4523 | while ((b & 1) == 0) { | |||
| 4524 | b >>= 1; | |||
| 4525 | s++; | |||
| 4526 | } | |||
| 4527 | ||||
| 4528 | /* only multiple of twos */ | |||
| 4529 | b >>= 1; | |||
| 4530 | if (b) | |||
| 4531 | return(-1); | |||
| 4532 | ||||
| 4533 | return (s); | |||
| 4534 | } | |||
| 4535 | ||||
| 4536 | void | |||
| 4537 | sr_quiesce(void) | |||
| 4538 | { | |||
| 4539 | struct sr_softc *sc = softraid0; | |||
| 4540 | struct sr_discipline *sd, *nsd; | |||
| 4541 | ||||
| 4542 | if (sc == NULL((void *)0)) | |||
| 4543 | return; | |||
| 4544 | ||||
| 4545 | /* Shutdown disciplines in reverse attach order. */ | |||
| 4546 | TAILQ_FOREACH_REVERSE_SAFE(sd, &sc->sc_dis_list,for ((sd) = (*(((struct sr_discipline_list *)((&sc->sc_dis_list )->tqh_last))->tqh_last)); (sd) != ((void *)0) && ((nsd) = (*(((struct sr_discipline_list *)((sd)->sd_link. tqe_prev))->tqh_last)), 1); (sd) = (nsd)) | |||
| 4547 | sr_discipline_list, sd_link, nsd)for ((sd) = (*(((struct sr_discipline_list *)((&sc->sc_dis_list )->tqh_last))->tqh_last)); (sd) != ((void *)0) && ((nsd) = (*(((struct sr_discipline_list *)((sd)->sd_link. tqe_prev))->tqh_last)), 1); (sd) = (nsd)) | |||
| 4548 | sr_discipline_shutdown(sd, 1, -1); | |||
| 4549 | } | |||
| 4550 | ||||
| 4551 | void | |||
| 4552 | sr_shutdown(int dying) | |||
| 4553 | { | |||
| 4554 | struct sr_softc *sc = softraid0; | |||
| 4555 | struct sr_discipline *sd; | |||
| 4556 | ||||
| 4557 | if (sc == NULL((void *)0)) | |||
| 4558 | return; | |||
| 4559 | ||||
| 4560 | DNPRINTF(SR_D_MISC, "%s: sr_shutdown\n", DEVNAME(sc)); | |||
| 4561 | ||||
| 4562 | /* | |||
| 4563 | * Since softraid is not under mainbus, we have to explicitly | |||
| 4564 | * notify its children that the power is going down, so they | |||
| 4565 | * can execute their shutdown hooks. | |||
| 4566 | */ | |||
| 4567 | config_suspend((struct device *)sc, DVACT_POWERDOWN6); | |||
| 4568 | ||||
| 4569 | /* Shutdown disciplines in reverse attach order. */ | |||
| 4570 | while ((sd = TAILQ_LAST(&sc->sc_dis_list, sr_discipline_list)(*(((struct sr_discipline_list *)((&sc->sc_dis_list)-> tqh_last))->tqh_last))) != NULL((void *)0)) | |||
| 4571 | sr_discipline_shutdown(sd, 1, dying); | |||
| 4572 | } | |||
| 4573 | ||||
| 4574 | int | |||
| 4575 | sr_validate_io(struct sr_workunit *wu, daddr_t *blkno, char *func) | |||
| 4576 | { | |||
| 4577 | struct sr_discipline *sd = wu->swu_dis; | |||
| 4578 | struct scsi_xfer *xs = wu->swu_xs; | |||
| 4579 | int rv = 1; | |||
| 4580 | ||||
| 4581 | DNPRINTF(SR_D_DIS, "%s: %s 0x%02x\n", DEVNAME(sd->sd_sc), func, | |||
| 4582 | xs->cmd.opcode); | |||
| 4583 | ||||
| 4584 | if (sd->sd_meta->ssd_data_blkno == 0) | |||
| 4585 | panic("invalid data blkno"); | |||
| 4586 | ||||
| 4587 | if (sd->sd_vol_status == BIOC_SVOFFLINE0x01) { | |||
| 4588 | DNPRINTF(SR_D_DIS, "%s: %s device offline\n", | |||
| 4589 | DEVNAME(sd->sd_sc), func); | |||
| 4590 | goto bad; | |||
| 4591 | } | |||
| 4592 | ||||
| 4593 | if (xs->datalen == 0) { | |||
| 4594 | printf("%s: %s: illegal block count for %s\n", | |||
| 4595 | DEVNAME(sd->sd_sc)((sd->sd_sc)->sc_dev.dv_xname), func, sd->sd_meta->ssd_devname); | |||
| 4596 | goto bad; | |||
| 4597 | } | |||
| 4598 | ||||
| 4599 | if (xs->cmdlen == 10) | |||
| 4600 | *blkno = _4btol(((struct scsi_rw_10 *)&xs->cmd)->addr); | |||
| 4601 | else if (xs->cmdlen == 16) | |||
| 4602 | *blkno = _8btol(((struct scsi_rw_16 *)&xs->cmd)->addr); | |||
| 4603 | else if (xs->cmdlen == 6) | |||
| 4604 | *blkno = _3btol(((struct scsi_rw *)&xs->cmd)->addr); | |||
| 4605 | else { | |||
| 4606 | printf("%s: %s: illegal cmdlen for %s\n", | |||
| 4607 | DEVNAME(sd->sd_sc)((sd->sd_sc)->sc_dev.dv_xname), func, sd->sd_meta->ssd_devname); | |||
| 4608 | goto bad; | |||
| 4609 | } | |||
| 4610 | ||||
| 4611 | *blkno *= (sd->sd_meta->ssdi_sdd_invariant.ssd_secsize / DEV_BSIZE(1 << 9)); | |||
| 4612 | ||||
| 4613 | wu->swu_blk_start = *blkno; | |||
| 4614 | wu->swu_blk_end = *blkno + (xs->datalen >> DEV_BSHIFT9) - 1; | |||
| 4615 | ||||
| 4616 | if (wu->swu_blk_end > sd->sd_meta->ssdi_sdd_invariant.ssd_size) { | |||
| 4617 | DNPRINTF(SR_D_DIS, "%s: %s out of bounds start: %lld " | |||
| 4618 | "end: %lld length: %d\n", | |||
| 4619 | DEVNAME(sd->sd_sc), func, (long long)wu->swu_blk_start, | |||
| 4620 | (long long)wu->swu_blk_end, xs->datalen); | |||
| 4621 | ||||
| 4622 | sd->sd_scsi_sense.error_code = SSD_ERRCODE_CURRENT0x70 | | |||
| 4623 | SSD_ERRCODE_VALID0x80; | |||
| 4624 | sd->sd_scsi_sense.flags = SKEY_ILLEGAL_REQUEST0x05; | |||
| 4625 | sd->sd_scsi_sense.add_sense_code = 0x21; | |||
| 4626 | sd->sd_scsi_sense.add_sense_code_qual = 0x00; | |||
| 4627 | sd->sd_scsi_sense.extra_len = 4; | |||
| 4628 | goto bad; | |||
| 4629 | } | |||
| 4630 | ||||
| 4631 | rv = 0; | |||
| 4632 | bad: | |||
| 4633 | return (rv); | |||
| 4634 | } | |||
| 4635 | ||||
| 4636 | void | |||
| 4637 | sr_rebuild_start(void *arg) | |||
| 4638 | { | |||
| 4639 | struct sr_discipline *sd = arg; | |||
| 4640 | struct sr_softc *sc = sd->sd_sc; | |||
| 4641 | ||||
| 4642 | DNPRINTF(SR_D_REBUILD, "%s: %s starting rebuild thread\n", | |||
| 4643 | DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname); | |||
| 4644 | ||||
| 4645 | if (kthread_create(sr_rebuild_thread, sd, &sd->sd_background_proc, | |||
| 4646 | DEVNAME(sc)((sc)->sc_dev.dv_xname)) != 0) | |||
| 4647 | printf("%s: unable to start background operation\n", | |||
| 4648 | DEVNAME(sc)((sc)->sc_dev.dv_xname)); | |||
| 4649 | } | |||
| 4650 | ||||
| 4651 | void | |||
| 4652 | sr_rebuild_thread(void *arg) | |||
| 4653 | { | |||
| 4654 | struct sr_discipline *sd = arg; | |||
| 4655 | ||||
| 4656 | DNPRINTF(SR_D_REBUILD, "%s: %s rebuild thread started\n", | |||
| 4657 | DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname); | |||
| 4658 | ||||
| 4659 | sd->sd_reb_active = 1; | |||
| 4660 | sd->sd_rebuild(sd); | |||
| 4661 | sd->sd_reb_active = 0; | |||
| 4662 | ||||
| 4663 | kthread_exit(0); | |||
| 4664 | } | |||
| 4665 | ||||
| 4666 | void | |||
| 4667 | sr_rebuild(struct sr_discipline *sd) | |||
| 4668 | { | |||
| 4669 | struct sr_softc *sc = sd->sd_sc; | |||
| 4670 | u_int64_t sz, whole_blk, partial_blk, blk, restart; | |||
| 4671 | daddr_t lba; | |||
| 4672 | struct sr_workunit *wu_r, *wu_w; | |||
| 4673 | struct scsi_xfer xs_r, xs_w; | |||
| 4674 | struct scsi_rw_16 *cr, *cw; | |||
| 4675 | int c, s, slept, percent = 0, old_percent = -1; | |||
| 4676 | u_int8_t *buf; | |||
| 4677 | ||||
| 4678 | whole_blk = sd->sd_meta->ssdi_sdd_invariant.ssd_size / SR_REBUILD_IO_SIZE128; | |||
| 4679 | partial_blk = sd->sd_meta->ssdi_sdd_invariant.ssd_size % SR_REBUILD_IO_SIZE128; | |||
| 4680 | ||||
| 4681 | restart = sd->sd_meta->ssd_rebuild / SR_REBUILD_IO_SIZE128; | |||
| 4682 | if (restart > whole_blk) { | |||
| 4683 | printf("%s: bogus rebuild restart offset, starting from 0\n", | |||
| 4684 | DEVNAME(sc)((sc)->sc_dev.dv_xname)); | |||
| 4685 | restart = 0; | |||
| 4686 | } | |||
| 4687 | if (restart) { | |||
| 4688 | /* | |||
| 4689 | * XXX there is a hole here; there is a possibility that we | |||
| 4690 | * had a restart however the chunk that was supposed to | |||
| 4691 | * be rebuilt is no longer valid; we can reach this situation | |||
| 4692 | * when a rebuild is in progress and the box crashes and | |||
| 4693 | * on reboot the rebuild chunk is different (like zero'd or | |||
| 4694 | * replaced). We need to check the uuid of the chunk that is | |||
| 4695 | * being rebuilt to assert this. | |||
| 4696 | */ | |||
| 4697 | percent = sr_rebuild_percent(sd); | |||
| 4698 | printf("%s: resuming rebuild on %s at %d%%\n", | |||
| 4699 | DEVNAME(sc)((sc)->sc_dev.dv_xname), sd->sd_meta->ssd_devname, percent); | |||
| 4700 | } | |||
| 4701 | ||||
| 4702 | /* currently this is 64k therefore we can use dma_alloc */ | |||
| 4703 | buf = dma_alloc(SR_REBUILD_IO_SIZE128 << DEV_BSHIFT9, PR_WAITOK0x0001); | |||
| 4704 | for (blk = restart; blk <= whole_blk; blk++) { | |||
| 4705 | lba = blk * SR_REBUILD_IO_SIZE128; | |||
| 4706 | sz = SR_REBUILD_IO_SIZE128; | |||
| 4707 | if (blk == whole_blk) { | |||
| 4708 | if (partial_blk == 0) | |||
| 4709 | break; | |||
| 4710 | sz = partial_blk; | |||
| 4711 | } | |||
| 4712 | ||||
| 4713 | /* get some wu */ | |||
| 4714 | wu_r = sr_scsi_wu_get(sd, 0); | |||
| 4715 | wu_w = sr_scsi_wu_get(sd, 0); | |||
| 4716 | ||||
| 4717 | DNPRINTF(SR_D_REBUILD, "%s: %s rebuild wu_r %p, wu_w %p\n", | |||
| 4718 | DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname, wu_r, wu_w); | |||
| 4719 | ||||
| 4720 | /* setup read io */ | |||
| 4721 | bzero(&xs_r, sizeof xs_r)__builtin_bzero((&xs_r), (sizeof xs_r)); | |||
| 4722 | xs_r.error = XS_NOERROR0; | |||
| 4723 | xs_r.flags = SCSI_DATA_IN0x00800; | |||
| 4724 | xs_r.datalen = sz << DEV_BSHIFT9; | |||
| 4725 | xs_r.data = buf; | |||
| 4726 | xs_r.cmdlen = sizeof(*cr); | |||
| 4727 | cr = (struct scsi_rw_16 *)&xs_r.cmd; | |||
| 4728 | cr->opcode = READ_160x88; | |||
| 4729 | _lto4b(sz, cr->length); | |||
| 4730 | _lto8b(lba, cr->addr); | |||
| 4731 | wu_r->swu_state = SR_WU_CONSTRUCT9; | |||
| 4732 | wu_r->swu_flags |= SR_WUF_REBUILD(1<<0); | |||
| 4733 | wu_r->swu_xs = &xs_r; | |||
| 4734 | if (sd->sd_scsi_rw(wu_r)) { | |||
| 4735 | printf("%s: could not create read io\n", | |||
| 4736 | DEVNAME(sc)((sc)->sc_dev.dv_xname)); | |||
| 4737 | goto fail; | |||
| 4738 | } | |||
| 4739 | ||||
| 4740 | /* setup write io */ | |||
| 4741 | bzero(&xs_w, sizeof xs_w)__builtin_bzero((&xs_w), (sizeof xs_w)); | |||
| 4742 | xs_w.error = XS_NOERROR0; | |||
| 4743 | xs_w.flags = SCSI_DATA_OUT0x01000; | |||
| 4744 | xs_w.datalen = sz << DEV_BSHIFT9; | |||
| 4745 | xs_w.data = buf; | |||
| 4746 | xs_w.cmdlen = sizeof(*cw); | |||
| 4747 | cw = (struct scsi_rw_16 *)&xs_w.cmd; | |||
| 4748 | cw->opcode = WRITE_160x8a; | |||
| 4749 | _lto4b(sz, cw->length); | |||
| 4750 | _lto8b(lba, cw->addr); | |||
| 4751 | wu_w->swu_state = SR_WU_CONSTRUCT9; | |||
| 4752 | wu_w->swu_flags |= SR_WUF_REBUILD(1<<0) | SR_WUF_WAKEUP(1<<4); | |||
| 4753 | wu_w->swu_xs = &xs_w; | |||
| 4754 | if (sd->sd_scsi_rw(wu_w)) { | |||
| 4755 | printf("%s: could not create write io\n", | |||
| 4756 | DEVNAME(sc)((sc)->sc_dev.dv_xname)); | |||
| 4757 | goto fail; | |||
| 4758 | } | |||
| 4759 | ||||
| 4760 | /* | |||
| 4761 | * collide with the read io so that we get automatically | |||
| 4762 | * started when the read is done | |||
| 4763 | */ | |||
| 4764 | wu_w->swu_state = SR_WU_DEFERRED5; | |||
| 4765 | wu_r->swu_collider = wu_w; | |||
| 4766 | s = splbio()splraise(0x3); | |||
| 4767 | TAILQ_INSERT_TAIL(&sd->sd_wu_defq, wu_w, swu_link)do { (wu_w)->swu_link.tqe_next = ((void *)0); (wu_w)->swu_link .tqe_prev = (&sd->sd_wu_defq)->tqh_last; *(&sd-> sd_wu_defq)->tqh_last = (wu_w); (&sd->sd_wu_defq)-> tqh_last = &(wu_w)->swu_link.tqe_next; } while (0); | |||
| 4768 | splx(s)spllower(s); | |||
| 4769 | ||||
| 4770 | DNPRINTF(SR_D_REBUILD, "%s: %s rebuild scheduling wu_r %p\n", | |||
| 4771 | DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname, wu_r); | |||
| 4772 | ||||
| 4773 | wu_r->swu_state = SR_WU_INPROGRESS1; | |||
| 4774 | sr_schedule_wu(wu_r); | |||
| 4775 | ||||
| 4776 | /* wait for write completion */ | |||
| 4777 | slept = 0; | |||
| 4778 | while ((wu_w->swu_flags & SR_WUF_REBUILDIOCOMP(1<<1)) == 0) { | |||
| 4779 | tsleep_nsec(wu_w, PRIBIO16, "sr_rebuild", INFSLP0xffffffffffffffffULL); | |||
| 4780 | slept = 1; | |||
| 4781 | } | |||
| 4782 | /* yield if we didn't sleep */ | |||
| 4783 | if (slept == 0) | |||
| 4784 | tsleep_nsec(sc, PWAIT32, "sr_yield", MSEC_TO_NSEC(1)); | |||
| 4785 | ||||
| 4786 | sr_scsi_wu_put(sd, wu_r); | |||
| 4787 | sr_scsi_wu_put(sd, wu_w); | |||
| 4788 | ||||
| 4789 | sd->sd_meta->ssd_rebuild = lba; | |||
| 4790 | ||||
| 4791 | /* XXX - this should be based on size, not percentage. */ | |||
| 4792 | /* save metadata every percent */ | |||
| 4793 | percent = sr_rebuild_percent(sd); | |||
| 4794 | if (percent != old_percent && blk != whole_blk) { | |||
| 4795 | if (sr_meta_save(sd, SR_META_DIRTY0x1)) | |||
| 4796 | printf("%s: could not save metadata to %s\n", | |||
| 4797 | DEVNAME(sc)((sc)->sc_dev.dv_xname), sd->sd_meta->ssd_devname); | |||
| 4798 | old_percent = percent; | |||
| 4799 | } | |||
| 4800 | ||||
| 4801 | if (sd->sd_reb_abort) | |||
| 4802 | goto abort; | |||
| 4803 | } | |||
| 4804 | ||||
| 4805 | /* all done */ | |||
| 4806 | sd->sd_meta->ssd_rebuild = 0; | |||
| 4807 | for (c = 0; c < sd->sd_meta->ssdi_sdd_invariant.ssd_chunk_no; c++) { | |||
| 4808 | if (sd->sd_vol.sv_chunks[c]->src_meta.scm_status == | |||
| 4809 | BIOC_SDREBUILD0x03) { | |||
| 4810 | sd->sd_set_chunk_state(sd, c, BIOC_SDONLINE0x00); | |||
| 4811 | break; | |||
| 4812 | } | |||
| 4813 | } | |||
| 4814 | ||||
| 4815 | abort: | |||
| 4816 | if (sr_meta_save(sd, SR_META_DIRTY0x1)) | |||
| 4817 | printf("%s: could not save metadata to %s\n", | |||
| 4818 | DEVNAME(sc)((sc)->sc_dev.dv_xname), sd->sd_meta->ssd_devname); | |||
| 4819 | fail: | |||
| 4820 | dma_free(buf, SR_REBUILD_IO_SIZE128 << DEV_BSHIFT9); | |||
| 4821 | } | |||
| 4822 | ||||
| 4823 | struct sr_discipline * | |||
| 4824 | sr_find_discipline(struct sr_softc *sc, const char *devname) | |||
| 4825 | { | |||
| 4826 | struct sr_discipline *sd; | |||
| 4827 | ||||
| 4828 | TAILQ_FOREACH(sd, &sc->sc_dis_list, sd_link)for((sd) = ((&sc->sc_dis_list)->tqh_first); (sd) != ((void *)0); (sd) = ((sd)->sd_link.tqe_next)) | |||
| 4829 | if (!strncmp(sd->sd_meta->ssd_devname, devname, | |||
| 4830 | sizeof(sd->sd_meta->ssd_devname))) | |||
| 4831 | break; | |||
| 4832 | return sd; | |||
| 4833 | } | |||
| 4834 | ||||
| 4835 | #ifndef SMALL_KERNEL | |||
| 4836 | int | |||
| 4837 | sr_sensors_create(struct sr_discipline *sd) | |||
| 4838 | { | |||
| 4839 | struct sr_softc *sc = sd->sd_sc; | |||
| 4840 | int rv = 1; | |||
| 4841 | ||||
| 4842 | DNPRINTF(SR_D_STATE, "%s: %s: sr_sensors_create\n", | |||
| 4843 | DEVNAME(sc), sd->sd_meta->ssd_devname); | |||
| 4844 | ||||
| 4845 | sd->sd_vol.sv_sensor.type = SENSOR_DRIVE; | |||
| 4846 | sd->sd_vol.sv_sensor.status = SENSOR_S_UNKNOWN; | |||
| 4847 | strlcpy(sd->sd_vol.sv_sensor.desc, sd->sd_meta->ssd_devname, | |||
| 4848 | sizeof(sd->sd_vol.sv_sensor.desc)); | |||
| 4849 | ||||
| 4850 | sensor_attach(&sc->sc_sensordev, &sd->sd_vol.sv_sensor); | |||
| 4851 | sd->sd_vol.sv_sensor_attached = 1; | |||
| 4852 | ||||
| 4853 | if (sc->sc_sensor_task == NULL((void *)0)) { | |||
| 4854 | sc->sc_sensor_task = sensor_task_register(sc, | |||
| 4855 | sr_sensors_refresh, 10); | |||
| 4856 | if (sc->sc_sensor_task == NULL((void *)0)) | |||
| 4857 | goto bad; | |||
| 4858 | } | |||
| 4859 | ||||
| 4860 | rv = 0; | |||
| 4861 | bad: | |||
| 4862 | return (rv); | |||
| 4863 | } | |||
| 4864 | ||||
| 4865 | void | |||
| 4866 | sr_sensors_delete(struct sr_discipline *sd) | |||
| 4867 | { | |||
| 4868 | DNPRINTF(SR_D_STATE, "%s: sr_sensors_delete\n", DEVNAME(sd->sd_sc)); | |||
| 4869 | ||||
| 4870 | if (sd->sd_vol.sv_sensor_attached) | |||
| 4871 | sensor_detach(&sd->sd_sc->sc_sensordev, &sd->sd_vol.sv_sensor); | |||
| 4872 | } | |||
| 4873 | ||||
| 4874 | void | |||
| 4875 | sr_sensors_refresh(void *arg) | |||
| 4876 | { | |||
| 4877 | struct sr_softc *sc = arg; | |||
| 4878 | struct sr_volume *sv; | |||
| 4879 | struct sr_discipline *sd; | |||
| 4880 | ||||
| 4881 | DNPRINTF(SR_D_STATE, "%s: sr_sensors_refresh\n", DEVNAME(sc)); | |||
| 4882 | ||||
| 4883 | TAILQ_FOREACH(sd, &sc->sc_dis_list, sd_link)for((sd) = ((&sc->sc_dis_list)->tqh_first); (sd) != ((void *)0); (sd) = ((sd)->sd_link.tqe_next)) { | |||
| 4884 | sv = &sd->sd_vol; | |||
| 4885 | ||||
| 4886 | switch(sd->sd_vol_status) { | |||
| 4887 | case BIOC_SVOFFLINE0x01: | |||
| 4888 | sv->sv_sensor.value = SENSOR_DRIVE_FAIL9; | |||
| 4889 | sv->sv_sensor.status = SENSOR_S_CRIT; | |||
| 4890 | break; | |||
| 4891 | ||||
| 4892 | case BIOC_SVDEGRADED0x02: | |||
| 4893 | sv->sv_sensor.value = SENSOR_DRIVE_PFAIL10; | |||
| 4894 | sv->sv_sensor.status = SENSOR_S_WARN; | |||
| 4895 | break; | |||
| 4896 | ||||
| 4897 | case BIOC_SVREBUILD0x05: | |||
| 4898 | sv->sv_sensor.value = SENSOR_DRIVE_REBUILD7; | |||
| 4899 | sv->sv_sensor.status = SENSOR_S_WARN; | |||
| 4900 | break; | |||
| 4901 | ||||
| 4902 | case BIOC_SVSCRUB0x04: | |||
| 4903 | case BIOC_SVONLINE0x00: | |||
| 4904 | sv->sv_sensor.value = SENSOR_DRIVE_ONLINE4; | |||
| 4905 | sv->sv_sensor.status = SENSOR_S_OK; | |||
| 4906 | break; | |||
| 4907 | ||||
| 4908 | default: | |||
| 4909 | sv->sv_sensor.value = 0; /* unknown */ | |||
| 4910 | sv->sv_sensor.status = SENSOR_S_UNKNOWN; | |||
| 4911 | } | |||
| 4912 | } | |||
| 4913 | } | |||
| 4914 | #endif /* SMALL_KERNEL */ | |||
| 4915 | ||||
| 4916 | #ifdef SR_FANCY_STATS | |||
| 4917 | void sr_print_stats(void); | |||
| 4918 | ||||
| 4919 | void | |||
| 4920 | sr_print_stats(void) | |||
| 4921 | { | |||
| 4922 | struct sr_softc *sc = softraid0; | |||
| 4923 | struct sr_discipline *sd; | |||
| 4924 | ||||
| 4925 | if (sc == NULL((void *)0)) { | |||
| 4926 | printf("no softraid softc found\n"); | |||
| 4927 | return; | |||
| 4928 | } | |||
| 4929 | ||||
| 4930 | TAILQ_FOREACH(sd, &sc->sc_dis_list, sd_link)for((sd) = ((&sc->sc_dis_list)->tqh_first); (sd) != ((void *)0); (sd) = ((sd)->sd_link.tqe_next)) { | |||
| 4931 | printf("%s: ios pending %d, collisions %llu\n", | |||
| 4932 | sd->sd_meta->ssd_devname, | |||
| 4933 | sd->sd_wu_pending, | |||
| 4934 | sd->sd_wu_collisions); | |||
| 4935 | } | |||
| 4936 | } | |||
| 4937 | #endif /* SR_FANCY_STATS */ | |||
| 4938 | ||||
| 4939 | #ifdef SR_DEBUG | |||
| 4940 | void | |||
| 4941 | sr_meta_print(struct sr_metadata *m) | |||
| 4942 | { | |||
| 4943 | int i; | |||
| 4944 | struct sr_meta_chunk *mc; | |||
| 4945 | struct sr_meta_opt_hdr *omh; | |||
| 4946 | ||||
| 4947 | if (!(sr_debug & SR_D_META)) | |||
| 4948 | return; | |||
| 4949 | ||||
| 4950 | printf("\tssd_magic 0x%llx\n", m->ssdi_sdd_invariant.ssd_magic); | |||
| 4951 | printf("\tssd_version %d\n", m->ssdi_sdd_invariant.ssd_version); | |||
| 4952 | printf("\tssd_vol_flags 0x%x\n", m->ssdi_sdd_invariant.ssd_vol_flags); | |||
| 4953 | printf("\tssd_uuid "); | |||
| 4954 | sr_uuid_print(&m->ssdi_sdd_invariant.ssd_uuid, 1); | |||
| 4955 | printf("\tssd_chunk_no %d\n", m->ssdi_sdd_invariant.ssd_chunk_no); | |||
| 4956 | printf("\tssd_chunk_id %d\n", m->ssdi_sdd_invariant.ssd_chunk_id); | |||
| 4957 | printf("\tssd_opt_no %d\n", m->ssdi_sdd_invariant.ssd_opt_no); | |||
| 4958 | printf("\tssd_volid %d\n", m->ssdi_sdd_invariant.ssd_volid); | |||
| 4959 | printf("\tssd_level %d\n", m->ssdi_sdd_invariant.ssd_level); | |||
| 4960 | printf("\tssd_size %lld\n", m->ssdi_sdd_invariant.ssd_size); | |||
| 4961 | printf("\tssd_devname %s\n", m->ssd_devname); | |||
| 4962 | printf("\tssd_vendor %s\n", m->ssdi_sdd_invariant.ssd_vendor); | |||
| 4963 | printf("\tssd_product %s\n", m->ssdi_sdd_invariant.ssd_product); | |||
| 4964 | printf("\tssd_revision %s\n", m->ssdi_sdd_invariant.ssd_revision); | |||
| 4965 | printf("\tssd_strip_size %d\n", m->ssdi_sdd_invariant.ssd_strip_size); | |||
| 4966 | printf("\tssd_checksum "); | |||
| 4967 | sr_checksum_print(m->ssd_checksum); | |||
| 4968 | printf("\n"); | |||
| 4969 | printf("\tssd_meta_flags 0x%x\n", m->ssd_meta_flags); | |||
| 4970 | printf("\tssd_ondisk %llu\n", m->ssd_ondisk); | |||
| 4971 | ||||
| 4972 | mc = (struct sr_meta_chunk *)(m + 1); | |||
| 4973 | for (i = 0; i < m->ssdi_sdd_invariant.ssd_chunk_no; i++, mc++) { | |||
| 4974 | printf("\t\tscm_volid %d\n", mc->scmi_scm_invariant.scm_volid); | |||
| 4975 | printf("\t\tscm_chunk_id %d\n", mc->scmi_scm_invariant.scm_chunk_id); | |||
| 4976 | printf("\t\tscm_devname %s\n", mc->scmi_scm_invariant.scm_devname); | |||
| 4977 | printf("\t\tscm_size %lld\n", mc->scmi_scm_invariant.scm_size); | |||
| 4978 | printf("\t\tscm_coerced_size %lld\n",mc->scmi_scm_invariant.scm_coerced_size); | |||
| 4979 | printf("\t\tscm_uuid "); | |||
| 4980 | sr_uuid_print(&mc->scmi_scm_invariant.scm_uuid, 1); | |||
| 4981 | printf("\t\tscm_checksum "); | |||
| 4982 | sr_checksum_print(mc->scm_checksum); | |||
| 4983 | printf("\n"); | |||
| 4984 | printf("\t\tscm_status %d\n", mc->scm_status); | |||
| 4985 | } | |||
| 4986 | ||||
| 4987 | omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(m + 1) + | |||
| 4988 | sizeof(struct sr_meta_chunk) * m->ssdi_sdd_invariant.ssd_chunk_no); | |||
| 4989 | for (i = 0; i < m->ssdi_sdd_invariant.ssd_opt_no; i++) { | |||
| 4990 | printf("\t\t\tsom_type %d\n", omh->som_type); | |||
| 4991 | printf("\t\t\tsom_checksum "); | |||
| 4992 | sr_checksum_print(omh->som_checksum); | |||
| 4993 | printf("\n"); | |||
| 4994 | omh = (struct sr_meta_opt_hdr *)((void *)omh + | |||
| 4995 | omh->som_length); | |||
| 4996 | } | |||
| 4997 | } | |||
| 4998 | ||||
| 4999 | void | |||
| 5000 | sr_dump_block(void *blk, int len) | |||
| 5001 | { | |||
| 5002 | uint8_t *b = blk; | |||
| 5003 | int i, j, c; | |||
| 5004 | ||||
| 5005 | for (i = 0; i < len; i += 16) { | |||
| 5006 | for (j = 0; j < 16; j++) | |||
| 5007 | printf("%.2x ", b[i + j]); | |||
| 5008 | printf(" "); | |||
| 5009 | for (j = 0; j < 16; j++) { | |||
| 5010 | c = b[i + j]; | |||
| 5011 | if (c < ' ' || c > 'z' || i + j > len) | |||
| 5012 | c = '.'; | |||
| 5013 | printf("%c", c); | |||
| 5014 | } | |||
| 5015 | printf("\n"); | |||
| 5016 | } | |||
| 5017 | } | |||
| 5018 | ||||
| 5019 | void | |||
| 5020 | sr_dump_mem(u_int8_t *p, int len) | |||
| 5021 | { | |||
| 5022 | int i; | |||
| 5023 | ||||
| 5024 | for (i = 0; i < len; i++) | |||
| 5025 | printf("%02x ", *p++); | |||
| 5026 | printf("\n"); | |||
| 5027 | } | |||
| 5028 | ||||
| 5029 | #endif /* SR_DEBUG */ | |||
| 5030 | ||||
| 5031 | #ifdef HIBERNATE1 | |||
| 5032 | /* | |||
| 5033 | * Side-effect free (no malloc, printf, pool, splx) softraid crypto writer. | |||
| 5034 | * | |||
| 5035 | * This function must perform the following: | |||
| 5036 | * 1. Determine the underlying device's own side-effect free I/O function | |||
| 5037 | * (eg, ahci_hibernate_io, wd_hibernate_io, etc). | |||
| 5038 | * 2. Store enough information in the provided page argument for subsequent | |||
| 5039 | * I/O calls (such as the crypto discipline structure for the keys, the | |||
| 5040 | * offset of the softraid partition on the underlying disk, as well as | |||
| 5041 | * the offset of the swap partition within the crypto volume. | |||
| 5042 | * 3. Encrypt the incoming data using the sr_discipline keys, then pass | |||
| 5043 | * the request to the underlying device's own I/O function. | |||
| 5044 | */ | |||
| 5045 | int | |||
| 5046 | sr_hibernate_io(dev_t dev, daddr_t blkno, vaddr_t addr, size_t size, int op, void *page) | |||
| 5047 | { | |||
| 5048 | /* Struct for stashing data obtained on HIB_INIT. | |||
| 5049 | * XXX | |||
| 5050 | * We share the page with the underlying device's own | |||
| 5051 | * side-effect free I/O function, so we pad our data to | |||
| 5052 | * the end of the page. Presently this does not overlap | |||
| 5053 | * with either of the two other side-effect free i/o | |||
| 5054 | * functions (ahci/wd). | |||
| 5055 | */ | |||
| 5056 | struct { | |||
| 5057 | char pad[3072]; | |||
| 5058 | struct sr_discipline *srd; | |||
| 5059 | hibio_fn subfn; /* underlying device i/o fn */ | |||
| 5060 | dev_t subdev; /* underlying device dev_t */ | |||
| 5061 | daddr_t sr_swapoff; /* ofs of swap part in sr volume */ | |||
| 5062 | char buf[DEV_BSIZE(1 << 9)]; /* encryption performed into this buf */ | |||
| 5063 | } *my = page; | |||
| 5064 | extern struct cfdriver sd_cd; | |||
| 5065 | char errstr[128], *dl_ret; | |||
| 5066 | struct sr_chunk *schunk; | |||
| 5067 | struct sd_softc *sd; | |||
| 5068 | struct aes_xts_ctx ctx; | |||
| 5069 | struct sr_softc *sc; | |||
| 5070 | struct device *dv; | |||
| 5071 | daddr_t key_blkno; | |||
| 5072 | uint32_t sub_raidoff; /* ofs of sr part in underlying dev */ | |||
| 5073 | struct disklabel dl; | |||
| 5074 | struct partition *pp; | |||
| 5075 | size_t i, j; | |||
| 5076 | u_char iv[8]; | |||
| 5077 | ||||
| 5078 | /* | |||
| 5079 | * In HIB_INIT, we are passed the swap partition size and offset | |||
| 5080 | * in 'size' and 'blkno' respectively. These are relative to the | |||
| 5081 | * start of the softraid partition, and we need to save these | |||
| 5082 | * for later translation to the underlying device's layout. | |||
| 5083 | */ | |||
| 5084 | if (op == HIB_INIT-1) { | |||
| 5085 | dv = disk_lookup(&sd_cd, DISKUNIT(dev)(((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8)) / 16)); | |||
| 5086 | sd = (struct sd_softc *)dv; | |||
| 5087 | sc = (struct sr_softc *)dv->dv_parent->dv_parent; | |||
| 5088 | ||||
| 5089 | /* | |||
| 5090 | * Look up the sr discipline. This is used to determine | |||
| 5091 | * if we are SR crypto and what the underlying device is. | |||
| 5092 | */ | |||
| 5093 | my->srd = sc->sc_targets[sd->sc_link->target]; | |||
| 5094 | DNPRINTF(SR_D_MISC, "sr_hibernate_io: discipline is %s\n", | |||
| 5095 | my->srd->sd_name); | |||
| 5096 | if (strncmp(my->srd->sd_name, "CRYPTO", | |||
| 5097 | sizeof(my->srd->sd_name))) | |||
| 5098 | return (ENOTSUP91); | |||
| 5099 | ||||
| 5100 | /* Find the underlying device */ | |||
| 5101 | schunk = my->srd->sd_vol.sv_chunks[0]; | |||
| 5102 | my->subdev = schunk->src_dev_mm; | |||
| 5103 | ||||
| 5104 | /* | |||
| 5105 | * Find the appropriate underlying device side effect free | |||
| 5106 | * I/O function, based on the type of device it is. | |||
| 5107 | */ | |||
| 5108 | my->subfn = get_hibernate_io_function(my->subdev); | |||
| 5109 | if (!my->subfn) | |||
| 5110 | return (ENODEV19); | |||
| 5111 | ||||
| 5112 | /* | |||
| 5113 | * Find blkno where this raid partition starts on | |||
| 5114 | * the underlying disk. | |||
| 5115 | */ | |||
| 5116 | dl_ret = disk_readlabel(&dl, my->subdev, errstr, | |||
| 5117 | sizeof(errstr)); | |||
| 5118 | if (dl_ret) { | |||
| 5119 | printf("Hibernate error reading disklabel: %s\n", dl_ret); | |||
| 5120 | return (ENOTSUP91); | |||
| 5121 | } | |||
| 5122 | ||||
| 5123 | pp = &dl.d_partitions[DISKPART(my->subdev)(((unsigned)((my->subdev) & 0xff) | (((my->subdev) & 0xffff0000) >> 8)) % 16)]; | |||
| 5124 | if (pp->p_fstype != FS_RAID19 || DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size) == 0) | |||
| 5125 | return (ENOTSUP91); | |||
| 5126 | ||||
| 5127 | /* Find the blkno of the SR part in the underlying device */ | |||
| 5128 | sub_raidoff = my->srd->sd_meta->ssd_data_blkno + | |||
| 5129 | DL_SECTOBLK(&dl, DL_GETPOFFSET(pp))(((((u_int64_t)(pp)->p_offseth << 32) + (pp)->p_offset )) * ((&dl)->d_secsize / (1 << 9))); | |||
| 5130 | DNPRINTF(SR_D_MISC,"sr_hibernate_io: blk trans ofs: %d blks\n", | |||
| 5131 | sub_raidoff); | |||
| 5132 | ||||
| 5133 | /* Save the blkno of the swap partition in the SR disk */ | |||
| 5134 | my->sr_swapoff = blkno; | |||
| 5135 | ||||
| 5136 | /* Initialize the sub-device */ | |||
| 5137 | return my->subfn(my->subdev, sub_raidoff + blkno, | |||
| 5138 | addr, size, op, page); | |||
| 5139 | } | |||
| 5140 | ||||
| 5141 | /* Hibernate only uses (and we only support) writes */ | |||
| 5142 | if (op != HIB_W1) | |||
| 5143 | return (ENOTSUP91); | |||
| 5144 | ||||
| 5145 | /* | |||
| 5146 | * Blocks act as the IV for the encryption. These block numbers | |||
| 5147 | * are relative to the start of the sr partition, but the 'blkno' | |||
| 5148 | * passed above is relative to the start of the swap partition | |||
| 5149 | * inside the sr partition, so bias appropriately. | |||
| 5150 | */ | |||
| 5151 | key_blkno = my->sr_swapoff + blkno; | |||
| 5152 | ||||
| 5153 | /* Process each disk block one at a time. */ | |||
| 5154 | for (i = 0; i < size; i += DEV_BSIZE(1 << 9)) { | |||
| 5155 | int res; | |||
| 5156 | ||||
| 5157 | bzero(&ctx, sizeof(ctx))__builtin_bzero((&ctx), (sizeof(ctx))); | |||
| 5158 | ||||
| 5159 | /* | |||
| 5160 | * Set encryption key (from the sr discipline stashed | |||
| 5161 | * during HIB_INIT. This code is based on the softraid | |||
| 5162 | * bootblock code. | |||
| 5163 | */ | |||
| 5164 | aes_xts_setkey(&ctx, my->srd->mdssd_dis_specific.mdd_crypto.scr_key[0], 64); | |||
| 5165 | /* We encrypt DEV_BSIZE bytes at a time in my->buf */ | |||
| 5166 | memcpy(my->buf, ((char *)addr) + i, DEV_BSIZE)__builtin_memcpy((my->buf), (((char *)addr) + i), ((1 << 9))); | |||
| 5167 | ||||
| 5168 | /* Block number is the IV */ | |||
| 5169 | memcpy(&iv, &key_blkno, sizeof(key_blkno))__builtin_memcpy((&iv), (&key_blkno), (sizeof(key_blkno ))); | |||
| 5170 | aes_xts_reinit(&ctx, iv); | |||
| 5171 | ||||
| 5172 | /* Encrypt DEV_BSIZE bytes, AES_XTS_BLOCKSIZE bytes at a time */ | |||
| 5173 | for (j = 0; j < DEV_BSIZE(1 << 9); j += AES_XTS_BLOCKSIZE16) | |||
| 5174 | aes_xts_encrypt(&ctx, my->buf + j); | |||
| 5175 | ||||
| 5176 | /* | |||
| 5177 | * Write one block out from my->buf to the underlying device | |||
| 5178 | * using its own side-effect free I/O function. | |||
| 5179 | */ | |||
| 5180 | res = my->subfn(my->subdev, blkno + (i / DEV_BSIZE(1 << 9)), | |||
| 5181 | (vaddr_t)(my->buf), DEV_BSIZE(1 << 9), op, page); | |||
| 5182 | if (res != 0) | |||
| 5183 | return (res); | |||
| 5184 | key_blkno++; | |||
| 5185 | } | |||
| 5186 | return (0); | |||
| 5187 | } | |||
| 5188 | #endif /* HIBERNATE */ |