1 /* $NetBSD: ata_raid.c,v 1.45 2021/08/07 16:19:09 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 2003 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 /* 39 * Support for autoconfiguration of RAID sets on ATA RAID controllers. 40 */ 41 42 #include <sys/cdefs.h> 43 __KERNEL_RCSID(0, "$NetBSD: ata_raid.c,v 1.45 2021/08/07 16:19:09 thorpej Exp $"); 44 45 #include <sys/param.h> 46 #include <sys/buf.h> 47 #include <sys/bufq.h> 48 #include <sys/conf.h> 49 #include <sys/device.h> 50 #include <sys/disk.h> 51 #include <sys/disklabel.h> 52 #include <sys/fcntl.h> 53 #include <sys/vnode.h> 54 #include <sys/proc.h> 55 #include <sys/module.h> 56 57 #include <miscfs/specfs/specdev.h> 58 59 #include <dev/ata/atareg.h> 60 #include <dev/ata/atavar.h> 61 #include <dev/ata/wdvar.h> 62 63 #include <dev/ata/ata_raidreg.h> 64 #include <dev/ata/ata_raidvar.h> 65 66 #include "locators.h" 67 #include "ioconf.h" 68 69 #ifdef ATA_RAID_DEBUG 70 #define DPRINTF(x) printf x 71 #else 72 #define DPRINTF(x) /* nothing */ 73 #endif 74 75 static int ataraid_match(device_t, cfdata_t, void *); 76 static void ataraid_attach(device_t, device_t, void *); 77 static int ataraid_rescan(device_t, const char *, const int *); 78 static int ataraid_print(void *, const char *); 79 80 static int ata_raid_finalize(device_t); 81 82 static int finalize_done; 83 84 ataraid_array_info_list_t ataraid_array_info_list = 85 TAILQ_HEAD_INITIALIZER(ataraid_array_info_list); 86 u_int ataraid_array_info_count; 87 88 CFATTACH_DECL3_NEW(ataraid, 0, 89 ataraid_match, ataraid_attach, NULL, NULL, ataraid_rescan, NULL, 0); 90 91 /* 92 * ataraidattach: 93 * 94 * Pseudo-device attach routine. 95 */ 96 void 97 ataraidattach(int count) 98 { 99 100 /* 101 * Register a finalizer which will be used to actually configure 102 * the logical disks configured by ataraid. 103 */ 104 finalize_done = 0; 105 if (config_finalize_register(NULL, ata_raid_finalize) != 0) 106 aprint_normal("WARNING: " 107 "unable to register ATA RAID finalizer\n"); 108 } 109 110 /* 111 * Use the config_finalizer to rescan for new devices, since the 112 * ld_ataraid driver might not be immediately available. 113 */ 114 115 /* ARGSUSED */ 116 static int 117 ataraid_rescan(device_t self, const char *ifattr, const int *locs) 118 { 119 120 finalize_done = 0; 121 (void)ata_raid_finalize(self); 122 123 return 0; 124 } 125 126 /* 127 * ata_raid_type_name: 128 * 129 * Return the type of ATA RAID. 130 */ 131 const char * 132 ata_raid_type_name(u_int type) 133 { 134 static const char *ata_raid_type_names[] = { 135 "Promise", 136 "Adaptec", 137 "VIA V-RAID", 138 "nVidia", 139 "JMicron", 140 "Intel MatrixRAID" 141 }; 142 143 if (type < __arraycount(ata_raid_type_names)) 144 return ata_raid_type_names[type]; 145 146 return NULL; 147 } 148 149 /* 150 * ata_raid_finalize: 151 * 152 * Autoconfiguration finalizer for ATA RAID. 153 */ 154 static int 155 ata_raid_finalize(device_t self) 156 { 157 static struct cfdata ataraid_cfdata = { 158 .cf_name = "ataraid", 159 .cf_atname = "ataraid", 160 .cf_unit = 0, 161 .cf_fstate = FSTATE_STAR, 162 }; 163 164 /* 165 * Only run once for each instantiation 166 */ 167 if (finalize_done) 168 return 0; 169 finalize_done = 1; 170 171 if (TAILQ_EMPTY(&ataraid_array_info_list)) 172 goto out; 173 174 if (config_attach_pseudo(&ataraid_cfdata) == NULL) 175 printf("%s: unable to attach an instance\n", 176 ataraid_cd.cd_name); 177 178 out: 179 return 1; 180 } 181 182 /* 183 * ataraid_match: 184 * 185 * Autoconfiguration glue: match routine. 186 */ 187 static int 188 ataraid_match(device_t parent, cfdata_t cf, void *aux) 189 { 190 191 /* pseudo-device; always present */ 192 return 1; 193 } 194 195 /* 196 * ataraid_attach: 197 * 198 * Autoconfiguration glue: attach routine. We attach the children. 199 */ 200 static void 201 ataraid_attach(device_t parent, device_t self, void *aux) 202 { 203 struct ataraid_array_info *aai; 204 int locs[ATARAIDCF_NLOCS]; 205 206 /* 207 * We're a pseudo-device, so we get to announce our own 208 * presence. 209 */ 210 aprint_normal_dev(self, "found %u RAID volume%s\n", 211 ataraid_array_info_count, 212 ataraid_array_info_count == 1 ? "" : "s"); 213 214 TAILQ_FOREACH(aai, &ataraid_array_info_list, aai_list) { 215 locs[ATARAIDCF_VENDTYPE] = aai->aai_type; 216 locs[ATARAIDCF_UNIT] = aai->aai_arrayno; 217 218 config_found(self, aai, ataraid_print, 219 CFARGS(.submatch = config_stdsubmatch, 220 .locators = locs)); 221 } 222 } 223 224 /* 225 * ataraid_print: 226 * 227 * Autoconfiguration glue: print routine. 228 */ 229 static int 230 ataraid_print(void *aux, const char *pnp) 231 { 232 struct ataraid_array_info *aai = aux; 233 234 if (pnp != NULL) 235 aprint_normal("block device at %s", pnp); 236 aprint_normal(" vendtype %d unit %d", aai->aai_type, aai->aai_arrayno); 237 return UNCONF; 238 } 239 240 /* 241 * ata_raid_check_component: 242 * 243 * Check the component for a RAID configuration structure. 244 * Called via autoconfiguration callback. 245 */ 246 void 247 ata_raid_check_component(device_t self) 248 { 249 struct wd_softc *sc = device_private(self); 250 251 if (ata_raid_read_config_adaptec(sc) == 0) 252 return; 253 if (ata_raid_read_config_promise(sc) == 0) 254 return; 255 if (ata_raid_read_config_via(sc) == 0) 256 return; 257 if (ata_raid_read_config_nvidia(sc) == 0) 258 return; 259 if (ata_raid_read_config_jmicron(sc) == 0) 260 return; 261 if (ata_raid_read_config_intel(sc) == 0) 262 return; 263 } 264 265 struct ataraid_array_info * 266 ata_raid_get_array_info(u_int type, u_int arrayno) 267 { 268 struct ataraid_array_info *aai, *laai; 269 270 TAILQ_FOREACH(aai, &ataraid_array_info_list, aai_list) { 271 if (aai->aai_type == type && 272 aai->aai_arrayno == arrayno) 273 goto out; 274 } 275 276 /* Need to allocate a new one. */ 277 aai = kmem_zalloc(sizeof(*aai), KM_SLEEP); 278 aai->aai_type = type; 279 aai->aai_arrayno = arrayno; 280 aai->aai_curdisk = 0; 281 282 ataraid_array_info_count++; 283 284 /* Sort it into the list: type first, then array number. */ 285 TAILQ_FOREACH(laai, &ataraid_array_info_list, aai_list) { 286 if (aai->aai_type < laai->aai_type) { 287 TAILQ_INSERT_BEFORE(laai, aai, aai_list); 288 goto out; 289 } 290 if (aai->aai_type == laai->aai_type && 291 aai->aai_arrayno < laai->aai_arrayno) { 292 TAILQ_INSERT_BEFORE(laai, aai, aai_list); 293 goto out; 294 } 295 } 296 TAILQ_INSERT_TAIL(&ataraid_array_info_list, aai, aai_list); 297 298 out: 299 return aai; 300 } 301 302 int 303 ata_raid_config_block_rw(struct vnode *vp, daddr_t blkno, void *tbuf, 304 size_t size, int bflags) 305 { 306 struct buf *bp; 307 int error; 308 309 bp = getiobuf(vp, false); 310 bp->b_blkno = blkno; 311 bp->b_bcount = bp->b_resid = size; 312 bp->b_flags = bflags; 313 bp->b_proc = curproc; 314 bp->b_data = tbuf; 315 SET(bp->b_cflags, BC_BUSY); /* mark buffer busy */ 316 317 VOP_STRATEGY(vp, bp); 318 error = biowait(bp); 319 320 putiobuf(bp); 321 return error; 322 } 323 324 MODULE(MODULE_CLASS_DRIVER, ataraid, NULL); 325 326 #ifdef _MODULE 327 CFDRIVER_DECL(ataraid, DV_DISK, NULL); 328 #endif 329 330 static int 331 ataraid_modcmd(modcmd_t cmd, void *arg) 332 { 333 int error = 0; 334 335 switch (cmd) { 336 case MODULE_CMD_INIT: 337 #ifdef _MODULE 338 error = config_cfdriver_attach(&ataraid_cd); 339 if (error) 340 break; 341 #endif 342 343 error = config_cfattach_attach(ataraid_cd.cd_name, &ataraid_ca); 344 if (error) { 345 #ifdef _MODULE 346 config_cfdriver_detach(&ataraid_cd); 347 #endif 348 aprint_error("%s: unable to register cfattach for \n" 349 "%s, error %d", __func__, ataraid_cd.cd_name, 350 error); 351 break; 352 } 353 break; 354 case MODULE_CMD_FINI: 355 error = config_cfattach_detach(ataraid_cd.cd_name, &ataraid_ca); 356 if (error) { 357 aprint_error("%s: failed to detach %s cfattach, " 358 "error %d\n", __func__, ataraid_cd.cd_name, error); 359 break; 360 } 361 #ifdef _MODULE 362 error = config_cfdriver_detach(&ataraid_cd); 363 if (error) { 364 (void)config_cfattach_attach(ataraid_cd.cd_name, 365 &ataraid_ca); 366 aprint_error("%s: failed to detach %s cfdriver, " 367 "error %d\n", __func__, ataraid_cd.cd_name, error); 368 break; 369 } 370 #endif 371 break; 372 case MODULE_CMD_STAT: 373 default: 374 error = ENOTTY; 375 } 376 377 return error; 378 } 379