1 /*- 2 * Copyright (c) 2008, 2009 Yahoo!, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The names of the authors may not be used to endorse or promote 14 * products derived from this software without specific prior written 15 * permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/param.h> 31 #include <err.h> 32 #include <errno.h> 33 #include <libutil.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 #include "mfiutil.h" 39 40 MFI_TABLE(top, foreign); 41 42 /* We currently don't know the full details of the following struct */ 43 struct mfi_foreign_scan_cfg { 44 char data[24]; 45 }; 46 47 struct mfi_foreign_scan_info { 48 uint32_t count; /* Number of foreign configs found */ 49 struct mfi_foreign_scan_cfg cfgs[8]; 50 }; 51 52 static int 53 foreign_drives(int ac __unused, char **av __unused) 54 { 55 struct mfi_pd_info info; 56 struct mfi_pd_list *list; 57 int error, fd; 58 u_int i; 59 fd = mfi_open(mfi_unit); 60 if (fd < 0) { 61 error = errno; 62 warn("mfi_open"); 63 return (error); 64 } 65 66 list = NULL; 67 if (mfi_pd_get_list(fd, &list, NULL) < 0) { 68 error = errno; 69 warn("Failed to get drive list"); 70 goto error; 71 } 72 /* List the drives. */ 73 printf("mfi%d Foreign disks:\n", mfi_unit); 74 for (i = 0; i < list->count; i++) { 75 /* Skip non-hard disks. */ 76 if (list->addr[i].scsi_dev_type != 0) 77 continue; 78 /* Fetch details for this drive. */ 79 if (mfi_pd_get_info(fd, list->addr[i].device_id, &info, 80 NULL) < 0) { 81 error = errno; 82 warn("Failed to fetch info for drive %u", 83 list->addr[i].device_id); 84 goto error; 85 } 86 87 if (!info.state.ddf.v.pd_type.is_foreign) 88 continue; 89 90 printf("%s ", mfi_drive_name(&info, list->addr[i].device_id, 91 MFI_DNAME_DEVICE_ID)); 92 print_pd(&info, -1); 93 printf(" %s\n", mfi_drive_name(&info, list->addr[i].device_id, 94 MFI_DNAME_ES)); 95 } 96 error: 97 if(list) 98 free(list); 99 close(fd); 100 error = 0; 101 return (0); 102 } 103 MFI_COMMAND(foreign, drives, foreign_drives); 104 105 static int 106 foreign_clear(int ac __unused, char **av __unused) 107 { 108 int ch, error, fd; 109 110 fd = mfi_open(mfi_unit); 111 if (fd < 0) { 112 error = errno; 113 warn("mfi_open"); 114 return (error); 115 } 116 117 printf( 118 "Are you sure you wish to clear ALL foreign configurations" 119 " on mfi%u? [y/N] ", mfi_unit); 120 121 ch = getchar(); 122 if (ch != 'y' && ch != 'Y') { 123 printf("\nAborting\n"); 124 close(fd); 125 return (0); 126 } 127 128 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_CLEAR, NULL, 0, NULL, 129 0, NULL) < 0) { 130 error = errno; 131 warn("Failed to clear foreign configuration"); 132 close(fd); 133 return (error); 134 } 135 136 printf("mfi%d: Foreign configuration cleared\n", mfi_unit); 137 close(fd); 138 return (0); 139 } 140 MFI_COMMAND(foreign, clear, foreign_clear); 141 142 static int 143 foreign_scan(int ac __unused, char **av __unused) 144 { 145 struct mfi_foreign_scan_info info; 146 int error, fd; 147 148 fd = mfi_open(mfi_unit); 149 if (fd < 0) { 150 error = errno; 151 warn("mfi_open"); 152 return (error); 153 } 154 155 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info, 156 sizeof(info), NULL, 0, NULL) < 0) { 157 error = errno; 158 warn("Failed to scan foreign configuration"); 159 close(fd); 160 return (error); 161 } 162 163 printf("mfi%d: Found %d foreign configurations\n", mfi_unit, 164 info.count); 165 close(fd); 166 return (0); 167 } 168 MFI_COMMAND(foreign, scan, foreign_scan); 169 170 static int 171 foreign_show_cfg(int fd, uint32_t opcode, uint8_t cfgidx) 172 { 173 struct mfi_config_data *config; 174 char prefix[26]; 175 int error; 176 uint8_t mbox[4]; 177 178 bzero(mbox, sizeof(mbox)); 179 mbox[0] = cfgidx; 180 if (mfi_config_read_opcode(fd, opcode, &config, mbox, sizeof(mbox)) 181 < 0) { 182 error = errno; 183 warn("Failed to get foreign config %d", cfgidx); 184 close(fd); 185 return (error); 186 } 187 188 if (opcode == MFI_DCMD_CFG_FOREIGN_PREVIEW) 189 sprintf(prefix, "Foreign configuration preview %d", cfgidx); 190 else 191 sprintf(prefix, "Foreign configuration %d", cfgidx); 192 /* 193 * MegaCli uses DCMD opcodes: 0x03100200 (which fails) followed by 194 * 0x1a721880 which returns what looks to be drive / volume info 195 * but we have no real information on what these are or what they do 196 * so we're currently relying solely on the config returned above 197 */ 198 dump_config(fd, config, prefix); 199 free(config); 200 201 return (0); 202 } 203 204 static int 205 foreign_display(int ac, char **av) 206 { 207 struct mfi_foreign_scan_info info; 208 uint8_t i; 209 int error, fd; 210 211 if (2 < ac) { 212 warnx("foreign display: extra arguments"); 213 return (EINVAL); 214 } 215 216 fd = mfi_open(mfi_unit); 217 if (fd < 0) { 218 error = errno; 219 warn("mfi_open"); 220 return (error); 221 } 222 223 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info, 224 sizeof(info), NULL, 0, NULL) < 0) { 225 error = errno; 226 warn("Failed to scan foreign configuration"); 227 close(fd); 228 return (error); 229 } 230 231 if (0 == info.count) { 232 warnx("foreign display: no foreign configs found"); 233 close(fd); 234 return (EINVAL); 235 } 236 237 if (1 == ac) { 238 for (i = 0; i < info.count; i++) { 239 error = foreign_show_cfg(fd, 240 MFI_DCMD_CFG_FOREIGN_DISPLAY, i); 241 if(0 != error) { 242 close(fd); 243 return (error); 244 } 245 if (i < info.count - 1) 246 printf("\n"); 247 } 248 } else if (2 == ac) { 249 error = foreign_show_cfg(fd, 250 MFI_DCMD_CFG_FOREIGN_DISPLAY, atoi(av[1])); 251 if (0 != error) { 252 close(fd); 253 return (error); 254 } 255 } 256 257 close(fd); 258 return (0); 259 } 260 MFI_COMMAND(foreign, display, foreign_display); 261 262 static int 263 foreign_preview(int ac, char **av) 264 { 265 struct mfi_foreign_scan_info info; 266 uint8_t i; 267 int error, fd; 268 269 if (2 < ac) { 270 warnx("foreign preview: extra arguments"); 271 return (EINVAL); 272 } 273 274 fd = mfi_open(mfi_unit); 275 if (fd < 0) { 276 error = errno; 277 warn("mfi_open"); 278 return (error); 279 } 280 281 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info, 282 sizeof(info), NULL, 0, NULL) < 0) { 283 error = errno; 284 warn("Failed to scan foreign configuration"); 285 close(fd); 286 return (error); 287 } 288 289 if (0 == info.count) { 290 warnx("foreign preview: no foreign configs found"); 291 close(fd); 292 return (EINVAL); 293 } 294 295 if (1 == ac) { 296 for (i = 0; i < info.count; i++) { 297 error = foreign_show_cfg(fd, 298 MFI_DCMD_CFG_FOREIGN_PREVIEW, i); 299 if(0 != error) { 300 close(fd); 301 return (error); 302 } 303 if (i < info.count - 1) 304 printf("\n"); 305 } 306 } else if (2 == ac) { 307 error = foreign_show_cfg(fd, 308 MFI_DCMD_CFG_FOREIGN_PREVIEW, atoi(av[1])); 309 if (0 != error) { 310 close(fd); 311 return (error); 312 } 313 } 314 315 close(fd); 316 return (0); 317 } 318 MFI_COMMAND(foreign, preview, foreign_preview); 319 320 static int 321 foreign_import(int ac, char **av) 322 { 323 struct mfi_foreign_scan_info info; 324 int ch, error, fd; 325 uint8_t cfgidx; 326 uint8_t mbox[4]; 327 328 if (2 < ac) { 329 warnx("foreign preview: extra arguments"); 330 return (EINVAL); 331 } 332 333 fd = mfi_open(mfi_unit); 334 if (fd < 0) { 335 error = errno; 336 warn("mfi_open"); 337 return (error); 338 } 339 340 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info, 341 sizeof(info), NULL, 0, NULL) < 0) { 342 error = errno; 343 warn("Failed to scan foreign configuration"); 344 close(fd); 345 return (error); 346 } 347 348 if (0 == info.count) { 349 warnx("foreign import: no foreign configs found"); 350 close(fd); 351 return (EINVAL); 352 } 353 354 if (1 == ac) { 355 cfgidx = 0xff; 356 printf("Are you sure you wish to import ALL foreign " 357 "configurations on mfi%u? [y/N] ", mfi_unit); 358 } else { 359 /* 360 * While this is docmmented for MegaCli this failed with 361 * exit code 0x03 on the test controller which was a Supermicro 362 * SMC2108 with firmware 12.12.0-0095 which is a LSI 2108 based 363 * controller. 364 */ 365 cfgidx = atoi(av[1]); 366 if (cfgidx >= info.count) { 367 warnx("Invalid foreign config %d specified max is %d", 368 cfgidx, info.count - 1); 369 close(fd); 370 return (EINVAL); 371 } 372 printf("Are you sure you wish to import the foreign " 373 "configuration %d on mfi%u? [y/N] ", cfgidx, mfi_unit); 374 } 375 376 ch = getchar(); 377 if (ch != 'y' && ch != 'Y') { 378 printf("\nAborting\n"); 379 close(fd); 380 return (0); 381 } 382 383 bzero(mbox, sizeof(mbox)); 384 mbox[0] = cfgidx; 385 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_IMPORT, NULL, 0, mbox, 386 sizeof(mbox), NULL) < 0) { 387 error = errno; 388 warn("Failed to import foreign configuration"); 389 close(fd); 390 return (error); 391 } 392 393 if (1 == ac) 394 printf("mfi%d: All foreign configurations imported\n", 395 mfi_unit); 396 else 397 printf("mfi%d: Foreign configuration %d imported\n", mfi_unit, 398 cfgidx); 399 close(fd); 400 return (0); 401 } 402 MFI_COMMAND(foreign, import, foreign_import); 403