1 /* $NetBSD: ata_raid.c,v 1.9 2004/09/13 12:55:47 drochner 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.9 2004/09/13 12:55:47 drochner Exp $"); 44 45 #include <sys/param.h> 46 #include <sys/buf.h> 47 #include <sys/conf.h> 48 #include <sys/device.h> 49 #include <sys/disk.h> 50 #include <sys/disklabel.h> 51 #include <sys/fcntl.h> 52 #include <sys/malloc.h> 53 #include <sys/vnode.h> 54 55 #include <miscfs/specfs/specdev.h> 56 57 #include <dev/ata/atareg.h> 58 #include <dev/ata/atavar.h> 59 #include <dev/ata/wdvar.h> 60 61 #include <dev/ata/ata_raidreg.h> 62 #include <dev/ata/ata_raidvar.h> 63 64 #include "locators.h" 65 66 #ifdef ATA_RAID_DEBUG 67 #define DPRINTF(x) printf x 68 #else 69 #define DPRINTF(x) /* nothing */ 70 #endif 71 72 void ataraidattach(int); 73 74 static int ataraid_match(struct device *, struct cfdata *, void *); 75 static void ataraid_attach(struct device *, struct device *, void *); 76 static int ataraid_print(void *, const char *); 77 78 static int ataraid_submatch(struct device *, struct cfdata *, 79 const locdesc_t *, void *); 80 81 static int ata_raid_finalize(struct device *); 82 83 ataraid_array_info_list_t ataraid_array_info_list = 84 TAILQ_HEAD_INITIALIZER(ataraid_array_info_list); 85 u_int ataraid_array_info_count; 86 87 CFATTACH_DECL(ataraid, sizeof(struct device), 88 ataraid_match, ataraid_attach, NULL, NULL); 89 90 /* 91 * ataraidattach: 92 * 93 * Pseudo-device attach routine. 94 */ 95 void 96 ataraidattach(int count) 97 { 98 99 /* 100 * Register a finalizer which will be used to actually configure 101 * the logical disks configured by ataraid. 102 */ 103 if (config_finalize_register(NULL, ata_raid_finalize) != 0) 104 printf("WARNING: unable to register ATA RAID finalizer\n"); 105 } 106 107 /* 108 * ata_raid_type_name: 109 * 110 * Return the type of ATA RAID. 111 */ 112 const char * 113 ata_raid_type_name(u_int type) 114 { 115 static const char *ata_raid_type_names[] = { 116 "Promise", 117 }; 118 119 if (type <= ATA_RAID_TYPE_MAX) 120 return (ata_raid_type_names[type]); 121 122 return (NULL); 123 } 124 125 /* 126 * ata_raid_finalize: 127 * 128 * Autoconfiguration finalizer for ATA RAID. 129 */ 130 static int 131 ata_raid_finalize(struct device *self) 132 { 133 extern struct cfdriver ataraid_cd; 134 static int done_once; 135 int error; 136 137 /* 138 * Since we only handle real hardware, we only need to be 139 * called once. 140 */ 141 if (done_once) 142 return (0); 143 done_once = 1; 144 145 if (TAILQ_EMPTY(&ataraid_array_info_list)) 146 goto out; 147 148 error = config_cfattach_attach(ataraid_cd.cd_name, &ataraid_ca); 149 if (error) { 150 printf("%s: unable to register cfattach, error = %d\n", 151 ataraid_cd.cd_name, error); 152 (void) config_cfdriver_detach(&ataraid_cd); 153 goto out; 154 } 155 156 if (config_attach_pseudo(ataraid_cd.cd_name, -1) == NULL) 157 printf("%s: unable to attach an instance\n", 158 ataraid_cd.cd_name); 159 160 out: 161 return (1); 162 } 163 164 /* 165 * ataraid_match: 166 * 167 * Autoconfiguration glue: match routine. 168 */ 169 static int 170 ataraid_match(struct device *parent, struct cfdata *cf, void *aux) 171 { 172 173 /* pseudo-device; always present */ 174 return (1); 175 } 176 177 /* 178 * ataraid_attach: 179 * 180 * Autoconfiguration glue: attach routine. We attach the children. 181 */ 182 static void 183 ataraid_attach(struct device *parent, struct device *self, void *aux) 184 { 185 struct ataraid_array_info *aai; 186 int help[3]; 187 locdesc_t *ldesc = (void *)help; /* XXX */ 188 189 /* 190 * We're a pseudo-device, so we get to announce our own 191 * presence. 192 */ 193 aprint_normal("%s: found %u RAID volume%s\n", 194 self->dv_xname, ataraid_array_info_count, 195 ataraid_array_info_count == 1 ? "" : "s"); 196 197 TAILQ_FOREACH(aai, &ataraid_array_info_list, aai_list) { 198 ldesc->len = 2; 199 ldesc->locs[ATARAIDCF_VENDTYPE] = aai->aai_type; 200 ldesc->locs[ATARAIDCF_UNIT] = aai->aai_arrayno; 201 202 config_found_sm_loc(self, "ataraid", NULL, aai, 203 ataraid_print, ataraid_submatch); 204 } 205 } 206 207 /* 208 * ataraid_print: 209 * 210 * Autoconfiguration glue: print routine. 211 */ 212 static int 213 ataraid_print(void *aux, const char *pnp) 214 { 215 struct ataraid_array_info *aai = aux; 216 217 if (pnp != NULL) 218 aprint_normal("block device at %s", pnp); 219 aprint_normal(" vendtype %d unit %d", aai->aai_type, aai->aai_arrayno); 220 return (UNCONF); 221 } 222 223 /* 224 * ataraid_submatch: 225 * 226 * Submatch routine for ATA RAID logical disks. 227 */ 228 static int 229 ataraid_submatch(struct device *parent, struct cfdata *cf, 230 const locdesc_t *ldesc, void *aux) 231 { 232 233 if (cf->cf_loc[ATARAIDCF_VENDTYPE] != ATARAIDCF_VENDTYPE_DEFAULT && 234 cf->cf_loc[ATARAIDCF_VENDTYPE] != ldesc->locs[ATARAIDCF_VENDTYPE]) 235 return (0); 236 237 if (cf->cf_loc[ATARAIDCF_UNIT] != ATARAIDCF_UNIT_DEFAULT && 238 cf->cf_loc[ATARAIDCF_UNIT] != ldesc->locs[ATARAIDCF_UNIT]) 239 return (0); 240 241 return (config_match(parent, cf, aux)); 242 } 243 244 /* 245 * ata_raid_check_component: 246 * 247 * Check the component for a RAID configuration structure. 248 * Called via autoconfiguration callback. 249 */ 250 void 251 ata_raid_check_component(struct device *self) 252 { 253 struct wd_softc *sc = (void *) self; 254 255 if (ata_raid_read_config_promise(sc) == 0) 256 return; 257 } 258 259 struct ataraid_array_info * 260 ata_raid_get_array_info(u_int type, u_int arrayno) 261 { 262 struct ataraid_array_info *aai, *laai; 263 264 TAILQ_FOREACH(aai, &ataraid_array_info_list, aai_list) { 265 if (aai->aai_type == type && 266 aai->aai_arrayno == arrayno) 267 goto out; 268 } 269 270 /* Need to allocate a new one. */ 271 aai = malloc(sizeof(*aai), M_DEVBUF, M_WAITOK | M_ZERO); 272 aai->aai_type = type; 273 aai->aai_arrayno = arrayno; 274 275 ataraid_array_info_count++; 276 277 if (TAILQ_EMPTY(&ataraid_array_info_list)) { 278 TAILQ_INSERT_TAIL(&ataraid_array_info_list, aai, aai_list); 279 goto out; 280 } 281 282 /* Sort it into the list: type first, then array number. */ 283 TAILQ_FOREACH(laai, &ataraid_array_info_list, aai_list) { 284 if (aai->aai_type < laai->aai_type) { 285 TAILQ_INSERT_BEFORE(laai, aai, aai_list); 286 goto out; 287 } 288 if (aai->aai_type == laai->aai_type && 289 aai->aai_arrayno < laai->aai_arrayno) { 290 TAILQ_INSERT_BEFORE(laai, aai, aai_list); 291 goto out; 292 } 293 } 294 TAILQ_INSERT_TAIL(&ataraid_array_info_list, aai, aai_list); 295 296 out: 297 return (aai); 298 } 299 300 int 301 ata_raid_config_block_rw(struct vnode *vp, daddr_t blkno, void *buf, 302 size_t size, int bflags) 303 { 304 struct buf *bp; 305 int error, s; 306 307 s = splbio(); 308 bp = pool_get(&bufpool, PR_WAITOK); 309 splx(s); 310 BUF_INIT(bp); 311 312 bp->b_vp = vp; 313 bp->b_blkno = blkno; 314 bp->b_bcount = bp->b_resid = size; 315 bp->b_flags = bflags; 316 bp->b_proc = curproc; 317 bp->b_data = buf; 318 319 VOP_STRATEGY(vp, bp); 320 error = biowait(bp); 321 322 s = splbio(); 323 pool_put(&bufpool, bp); 324 splx(s); 325 return (error); 326 } 327