1 /* $NetBSD: ata_raid.c,v 1.34 2010/07/06 18:03:21 bsh 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.34 2010/07/06 18:03:21 bsh 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/malloc.h> 54 #include <sys/vnode.h> 55 #include <sys/proc.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 68 #ifdef ATA_RAID_DEBUG 69 #define DPRINTF(x) printf x 70 #else 71 #define DPRINTF(x) /* nothing */ 72 #endif 73 74 void ataraidattach(int); 75 76 static int ataraid_match(device_t, cfdata_t, void *); 77 static void ataraid_attach(device_t, device_t, void *); 78 static int ataraid_print(void *, const char *); 79 80 static int ata_raid_finalize(device_t); 81 82 ataraid_array_info_list_t ataraid_array_info_list = 83 TAILQ_HEAD_INITIALIZER(ataraid_array_info_list); 84 u_int ataraid_array_info_count; 85 86 CFATTACH_DECL_NEW(ataraid, 0, 87 ataraid_match, ataraid_attach, NULL, NULL); 88 89 /* 90 * ataraidattach: 91 * 92 * Pseudo-device attach routine. 93 */ 94 void 95 ataraidattach(int count) 96 { 97 98 /* 99 * Register a finalizer which will be used to actually configure 100 * the logical disks configured by ataraid. 101 */ 102 if (config_finalize_register(NULL, ata_raid_finalize) != 0) 103 printf("WARNING: unable to register ATA RAID finalizer\n"); 104 } 105 106 /* 107 * ata_raid_type_name: 108 * 109 * Return the type of ATA RAID. 110 */ 111 const char * 112 ata_raid_type_name(u_int type) 113 { 114 static const char *ata_raid_type_names[] = { 115 "Promise", 116 "Adaptec", 117 "VIA V-RAID", 118 "nVidia", 119 "JMicron", 120 "Intel MatrixRAID" 121 }; 122 123 if (type < __arraycount(ata_raid_type_names)) 124 return (ata_raid_type_names[type]); 125 126 return (NULL); 127 } 128 129 /* 130 * ata_raid_finalize: 131 * 132 * Autoconfiguration finalizer for ATA RAID. 133 */ 134 static int 135 ata_raid_finalize(device_t self) 136 { 137 static struct cfdata ataraid_cfdata = { 138 .cf_name = "ataraid", 139 .cf_atname = "ataraid", 140 .cf_unit = 0, 141 .cf_fstate = FSTATE_STAR, 142 }; 143 extern struct cfdriver ataraid_cd; 144 static int done_once; 145 int error; 146 147 /* 148 * Since we only handle real hardware, we only need to be 149 * called once. 150 */ 151 if (done_once) 152 return (0); 153 done_once = 1; 154 155 if (TAILQ_EMPTY(&ataraid_array_info_list)) 156 goto out; 157 158 error = config_cfattach_attach(ataraid_cd.cd_name, &ataraid_ca); 159 if (error) { 160 printf("%s: unable to register cfattach, error = %d\n", 161 ataraid_cd.cd_name, error); 162 (void) config_cfdriver_detach(&ataraid_cd); 163 goto out; 164 } 165 166 if (config_attach_pseudo(&ataraid_cfdata) == NULL) 167 printf("%s: unable to attach an instance\n", 168 ataraid_cd.cd_name); 169 170 out: 171 return (1); 172 } 173 174 /* 175 * ataraid_match: 176 * 177 * Autoconfiguration glue: match routine. 178 */ 179 static int 180 ataraid_match(device_t parent, cfdata_t cf, 181 void *aux) 182 { 183 184 /* pseudo-device; always present */ 185 return (1); 186 } 187 188 /* 189 * ataraid_attach: 190 * 191 * Autoconfiguration glue: attach routine. We attach the children. 192 */ 193 static void 194 ataraid_attach(device_t parent, device_t self, 195 void *aux) 196 { 197 struct ataraid_array_info *aai; 198 int locs[ATARAIDCF_NLOCS]; 199 200 /* 201 * We're a pseudo-device, so we get to announce our own 202 * presence. 203 */ 204 aprint_normal_dev(self, "found %u RAID volume%s\n", 205 ataraid_array_info_count, 206 ataraid_array_info_count == 1 ? "" : "s"); 207 208 TAILQ_FOREACH(aai, &ataraid_array_info_list, aai_list) { 209 locs[ATARAIDCF_VENDTYPE] = aai->aai_type; 210 locs[ATARAIDCF_UNIT] = aai->aai_arrayno; 211 212 config_found_sm_loc(self, "ataraid", locs, aai, 213 ataraid_print, config_stdsubmatch); 214 } 215 } 216 217 /* 218 * ataraid_print: 219 * 220 * Autoconfiguration glue: print routine. 221 */ 222 static int 223 ataraid_print(void *aux, const char *pnp) 224 { 225 struct ataraid_array_info *aai = aux; 226 227 if (pnp != NULL) 228 aprint_normal("block device at %s", pnp); 229 aprint_normal(" vendtype %d unit %d", aai->aai_type, aai->aai_arrayno); 230 return (UNCONF); 231 } 232 233 /* 234 * ata_raid_check_component: 235 * 236 * Check the component for a RAID configuration structure. 237 * Called via autoconfiguration callback. 238 */ 239 void 240 ata_raid_check_component(device_t self) 241 { 242 struct wd_softc *sc = device_private(self); 243 244 if (ata_raid_read_config_adaptec(sc) == 0) 245 return; 246 if (ata_raid_read_config_promise(sc) == 0) 247 return; 248 if (ata_raid_read_config_via(sc) == 0) 249 return; 250 if (ata_raid_read_config_nvidia(sc) == 0) 251 return; 252 if (ata_raid_read_config_jmicron(sc) == 0) 253 return; 254 if (ata_raid_read_config_intel(sc) == 0) 255 return; 256 } 257 258 struct ataraid_array_info * 259 ata_raid_get_array_info(u_int type, u_int arrayno) 260 { 261 struct ataraid_array_info *aai, *laai; 262 263 TAILQ_FOREACH(aai, &ataraid_array_info_list, aai_list) { 264 if (aai->aai_type == type && 265 aai->aai_arrayno == arrayno) 266 goto out; 267 } 268 269 /* Need to allocate a new one. */ 270 aai = malloc(sizeof(*aai), M_DEVBUF, M_WAITOK | M_ZERO); 271 aai->aai_type = type; 272 aai->aai_arrayno = arrayno; 273 aai->aai_curdisk = 0; 274 275 ataraid_array_info_count++; 276 277 /* Sort it into the list: type first, then array number. */ 278 TAILQ_FOREACH(laai, &ataraid_array_info_list, aai_list) { 279 if (aai->aai_type < laai->aai_type) { 280 TAILQ_INSERT_BEFORE(laai, aai, aai_list); 281 goto out; 282 } 283 if (aai->aai_type == laai->aai_type && 284 aai->aai_arrayno < laai->aai_arrayno) { 285 TAILQ_INSERT_BEFORE(laai, aai, aai_list); 286 goto out; 287 } 288 } 289 TAILQ_INSERT_TAIL(&ataraid_array_info_list, aai, aai_list); 290 291 out: 292 return (aai); 293 } 294 295 int 296 ata_raid_config_block_rw(struct vnode *vp, daddr_t blkno, void *tbuf, 297 size_t size, int bflags) 298 { 299 struct buf *bp; 300 int error; 301 302 bp = getiobuf(vp, false); 303 bp->b_blkno = blkno; 304 bp->b_bcount = bp->b_resid = size; 305 bp->b_flags = bflags; 306 bp->b_proc = curproc; 307 bp->b_data = tbuf; 308 SET(bp->b_cflags, BC_BUSY); /* mark buffer busy */ 309 310 VOP_STRATEGY(vp, bp); 311 error = biowait(bp); 312 313 putiobuf(bp); 314 return (error); 315 } 316