1 /* $NetBSD: ata_raid_intel.c,v 1.3 2008/09/16 11:45:30 tron Exp $ */
4 * Copyright (c) 2000-2008 Søren Schmidt <sos@FreeBSD.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer,
12 * without modification, immediately at the beginning of the file.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * Support for parsing Intel MatrixRAID controller configuration blocks.
32 * Adapted to NetBSD by Juan Romero Pardines (xtraeme@gmail.org).
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: ata_raid_intel.c,v 1.3 2008/09/16 11:45:30 tron Exp $");
38 #include <sys/param.h>
42 #include <sys/device.h>
44 #include <sys/disklabel.h>
45 #include <sys/fcntl.h>
46 #include <sys/malloc.h>
47 #include <sys/vnode.h>
48 #include <sys/kauth.h>
50 #include <miscfs/specfs/specdev.h>
52 #include <dev/ata/atareg.h>
53 #include <dev/ata/atavar.h>
54 #include <dev/ata/wdvar.h>
56 #include <dev/ata/ata_raidreg.h>
57 #include <dev/ata/ata_raidvar.h>
60 #define DPRINTF(x) printf x
62 #define DPRINTF(x) /* nothing */
67 ata_raid_intel_type(int type
)
69 static char buffer
[16];
79 sprintf(buffer
, "UNKNOWN 0x%02x", type
);
85 ata_raid_intel_print_info(struct intel_raid_conf
*info
)
87 struct intel_raid_mapping
*map
;
90 printf("********* ATA Intel MatrixRAID Metadata *********\n");
91 printf("intel_id <%.24s>\n", info
->intel_id
);
92 printf("version <%.6s>\n", info
->version
);
93 printf("checksum 0x%08x\n", info
->checksum
);
94 printf("config_size 0x%08x\n", info
->config_size
);
95 printf("config_id 0x%08x\n", info
->config_id
);
96 printf("generation 0x%08x\n", info
->generation
);
97 printf("total_disks %u\n", info
->total_disks
);
98 printf("total_volumes %u\n", info
->total_volumes
);
99 printf("DISK# serial disk sectors disk_id flags\n");
100 for (i
= 0; i
< info
->total_disks
; i
++) {
101 printf(" %d <%.16s> %u 0x%08x 0x%08x\n",
102 i
, info
->disk
[i
].serial
, info
->disk
[i
].sectors
,
103 info
->disk
[i
].id
, info
->disk
[i
].flags
);
106 map
= (struct intel_raid_mapping
*)&info
->disk
[info
->total_disks
];
107 for (j
= 0; j
< info
->total_volumes
; j
++) {
108 printf("name %.16s\n", map
->name
);
109 printf("total_sectors %ju\n", map
->total_sectors
);
110 printf("state %u\n", map
->state
);
111 printf("reserved %u\n", map
->reserved
);
112 printf("offset %u\n", map
->offset
);
113 printf("disk_sectors %u\n", map
->disk_sectors
);
114 printf("stripe_count %u\n", map
->stripe_count
);
115 printf("stripe_sectors %u\n", map
->stripe_sectors
);
116 printf("status %u\n", map
->status
);
117 printf("type %s\n", ata_raid_intel_type(map
->type
));
118 printf("total_disks %u\n", map
->total_disks
);
119 printf("magic[0] 0x%02x\n", map
->magic
[0]);
120 printf("magic[1] 0x%02x\n", map
->magic
[1]);
121 printf("magic[2] 0x%02x\n", map
->magic
[2]);
122 for (i
= 0; i
< map
->total_disks
; i
++)
123 printf(" disk %d at disk_idx 0x%08x\n",
124 i
, map
->disk_idx
[i
]);
126 map
= (struct intel_raid_mapping
*)
127 &map
->disk_idx
[map
->total_disks
];
129 printf("=================================================\n");
134 ata_raid_read_config_intel(struct wd_softc
*sc
)
136 struct intel_raid_conf
*info
;
137 struct intel_raid_mapping
*map
;
138 struct ataraid_array_info
*aai
;
139 struct ataraid_disk_info
*adi
;
141 uint32_t checksum
, *ptr
;
143 int bmajor
, count
, curvol
= 0, error
= 0;
147 info
= malloc(1536, M_DEVBUF
, M_WAITOK
|M_ZERO
);
149 bmajor
= devsw_name2blk(device_xname(sc
->sc_dev
), NULL
, 0);
151 /* Get a vnode for the raw partition of this disk. */
152 dev
= MAKEDISKDEV(bmajor
, device_unit(sc
->sc_dev
), RAW_PART
);
153 error
= bdevvp(dev
, &vp
);
157 error
= VOP_OPEN(vp
, FREAD
, NOCRED
);
163 error
= ata_raid_config_block_rw(vp
, INTEL_LBA(sc
), info
,
165 VOP_CLOSE(vp
, FREAD
, NOCRED
);
168 DPRINTF(("%s: error %d reading Intel MatrixRAID config block\n",
169 device_xname(sc
->sc_dev
), error
));
174 (void)memcpy(tmp
+ 1024, tmp
, 512);
175 (void)memcpy(tmp
, tmp
+ 512, 1024);
176 (void)memset(tmp
+ 1024, 0, 512);
178 /* Check if this is a Intel RAID struct */
179 if (strncmp(info
->intel_id
, INTEL_MAGIC
, strlen(INTEL_MAGIC
))) {
180 DPRINTF(("%s: Intel MatrixRAID signature check failed\n",
181 device_xname(sc
->sc_dev
)));
186 /* calculate checksum and compare for valid */
187 for (checksum
= 0, ptr
= (uint32_t *)info
, count
= 0;
188 count
< (info
->config_size
/ sizeof(uint32_t)); count
++)
191 checksum
-= info
->checksum
;
192 if (checksum
!= info
->checksum
) {
193 DPRINTF(("%s: Intel MatrixRAID checksum failed 0x%x != 0x%x\n",
194 device_xname(sc
->sc_dev
), checksum
, info
->checksum
));
199 #ifdef ATA_RAID_DEBUG
200 ata_raid_intel_print_info(info
);
203 /* This one points to the first volume */
204 map
= (struct intel_raid_mapping
*)&info
->disk
[info
->total_disks
];
208 * Lookup or allocate a new array info structure for this array.
210 aai
= ata_raid_get_array_info(ATA_RAID_TYPE_INTEL
, curvol
);
212 /* Fill in array info */
213 aai
->aai_generation
= info
->generation
;
214 aai
->aai_status
= AAI_S_READY
;
218 aai
->aai_level
= AAI_L_RAID0
;
219 aai
->aai_width
= map
->total_disks
;
222 aai
->aai_level
= AAI_L_RAID1
;
226 DPRINTF(("%s: unknown Intel MatrixRAID type 0x%02x\n",
227 device_xname(sc
->sc_dev
), map
->type
));
232 switch (map
->state
) {
233 case INTEL_S_DEGRADED
:
234 aai
->aai_status
|= AAI_S_DEGRADED
;
236 case INTEL_S_DISABLED
:
237 case INTEL_S_FAILURE
:
238 aai
->aai_status
&= ~AAI_S_READY
;
242 aai
->aai_type
= ATA_RAID_TYPE_INTEL
;
243 aai
->aai_capacity
= map
->total_sectors
;
244 aai
->aai_interleave
= map
->stripe_sectors
/ 2;
245 aai
->aai_ndisks
= map
->total_disks
;
246 aai
->aai_heads
= 255;
247 aai
->aai_sectors
= 63;
249 aai
->aai_capacity
/ (aai
->aai_heads
* aai
->aai_sectors
);
250 aai
->aai_offset
= map
->offset
;
251 aai
->aai_reserved
= 3;
253 strlcpy(aai
->aai_name
, map
->name
, sizeof(aai
->aai_name
));
255 /* Fill in disk info */
256 adi
= &aai
->aai_disks
[curdrive
];
259 if (info
->disk
[curdrive
].flags
& INTEL_F_ONLINE
)
260 adi
->adi_status
|= ADI_S_ONLINE
;
261 if (info
->disk
[curdrive
].flags
& INTEL_F_ASSIGNED
)
262 adi
->adi_status
|= ADI_S_ASSIGNED
;
263 if (info
->disk
[curdrive
].flags
& INTEL_F_SPARE
) {
264 adi
->adi_status
&= ~ADI_S_ONLINE
;
265 adi
->adi_status
|= ADI_S_SPARE
;
267 if (info
->disk
[curdrive
].flags
& INTEL_F_DOWN
)
268 adi
->adi_status
&= ~ADI_S_ONLINE
;
270 if (adi
->adi_status
) {
271 adi
->adi_dev
= sc
->sc_dev
;
272 adi
->adi_sectors
= info
->disk
[curdrive
].sectors
;
273 adi
->adi_compsize
= adi
->adi_sectors
- aai
->aai_reserved
;
275 * Check if that is the only volume, otherwise repeat
276 * the process to find more.
278 if ((curvol
+ 1) < info
->total_volumes
) {
280 map
= (struct intel_raid_mapping
*)
281 &map
->disk_idx
[map
->total_disks
];
288 free(info
, M_DEVBUF
);