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 int error; 175 char *prefix; 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 asprintf(&prefix, "Foreign configuration preview %d", cfgidx); 190 else 191 asprintf(&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 free(prefix); 201 202 return (0); 203 } 204 205 static int 206 foreign_display(int ac, char **av) 207 { 208 struct mfi_foreign_scan_info info; 209 uint8_t i; 210 int error, fd; 211 212 if (2 < ac) { 213 warnx("foreign display: extra arguments"); 214 return (EINVAL); 215 } 216 217 fd = mfi_open(mfi_unit); 218 if (fd < 0) { 219 error = errno; 220 warn("mfi_open"); 221 return (error); 222 } 223 224 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info, 225 sizeof(info), NULL, 0, NULL) < 0) { 226 error = errno; 227 warn("Failed to scan foreign configuration"); 228 close(fd); 229 return (error); 230 } 231 232 if (0 == info.count) { 233 warnx("foreign display: no foreign configs found"); 234 close(fd); 235 return (EINVAL); 236 } 237 238 if (1 == ac) { 239 for (i = 0; i < info.count; i++) { 240 error = foreign_show_cfg(fd, 241 MFI_DCMD_CFG_FOREIGN_DISPLAY, i); 242 if(0 != error) { 243 close(fd); 244 return (error); 245 } 246 if (i < info.count - 1) 247 printf("\n"); 248 } 249 } else if (2 == ac) { 250 error = foreign_show_cfg(fd, 251 MFI_DCMD_CFG_FOREIGN_DISPLAY, atoi(av[1])); 252 if (0 != error) { 253 close(fd); 254 return (error); 255 } 256 } 257 258 close(fd); 259 return (0); 260 } 261 MFI_COMMAND(foreign, display, foreign_display); 262 263 static int 264 foreign_preview(int ac, char **av) 265 { 266 struct mfi_foreign_scan_info info; 267 uint8_t i; 268 int error, fd; 269 270 if (2 < ac) { 271 warnx("foreign preview: extra arguments"); 272 return (EINVAL); 273 } 274 275 fd = mfi_open(mfi_unit); 276 if (fd < 0) { 277 error = errno; 278 warn("mfi_open"); 279 return (error); 280 } 281 282 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info, 283 sizeof(info), NULL, 0, NULL) < 0) { 284 error = errno; 285 warn("Failed to scan foreign configuration"); 286 close(fd); 287 return (error); 288 } 289 290 if (0 == info.count) { 291 warnx("foreign preview: no foreign configs found"); 292 close(fd); 293 return (EINVAL); 294 } 295 296 if (1 == ac) { 297 for (i = 0; i < info.count; i++) { 298 error = foreign_show_cfg(fd, 299 MFI_DCMD_CFG_FOREIGN_PREVIEW, i); 300 if(0 != error) { 301 close(fd); 302 return (error); 303 } 304 if (i < info.count - 1) 305 printf("\n"); 306 } 307 } else if (2 == ac) { 308 error = foreign_show_cfg(fd, 309 MFI_DCMD_CFG_FOREIGN_PREVIEW, atoi(av[1])); 310 if (0 != error) { 311 close(fd); 312 return (error); 313 } 314 } 315 316 close(fd); 317 return (0); 318 } 319 MFI_COMMAND(foreign, preview, foreign_preview); 320 321 static int 322 foreign_import(int ac, char **av) 323 { 324 struct mfi_foreign_scan_info info; 325 int ch, error, fd; 326 uint8_t cfgidx; 327 uint8_t mbox[4]; 328 329 if (2 < ac) { 330 warnx("foreign preview: extra arguments"); 331 return (EINVAL); 332 } 333 334 fd = mfi_open(mfi_unit); 335 if (fd < 0) { 336 error = errno; 337 warn("mfi_open"); 338 return (error); 339 } 340 341 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info, 342 sizeof(info), NULL, 0, NULL) < 0) { 343 error = errno; 344 warn("Failed to scan foreign configuration"); 345 close(fd); 346 return (error); 347 } 348 349 if (0 == info.count) { 350 warnx("foreign import: no foreign configs found"); 351 close(fd); 352 return (EINVAL); 353 } 354 355 if (1 == ac) { 356 cfgidx = 0xff; 357 printf("Are you sure you wish to import ALL foreign " 358 "configurations on mfi%u? [y/N] ", mfi_unit); 359 } else { 360 /* 361 * While this is docmmented for MegaCli this failed with 362 * exit code 0x03 on the test controller which was a Supermicro 363 * SMC2108 with firmware 12.12.0-0095 which is a LSI 2108 based 364 * controller. 365 */ 366 cfgidx = atoi(av[1]); 367 if (cfgidx >= info.count) { 368 warnx("Invalid foreign config %d specified max is %d", 369 cfgidx, info.count - 1); 370 close(fd); 371 return (EINVAL); 372 } 373 printf("Are you sure you wish to import the foreign " 374 "configuration %d on mfi%u? [y/N] ", cfgidx, mfi_unit); 375 } 376 377 ch = getchar(); 378 if (ch != 'y' && ch != 'Y') { 379 printf("\nAborting\n"); 380 close(fd); 381 return (0); 382 } 383 384 bzero(mbox, sizeof(mbox)); 385 mbox[0] = cfgidx; 386 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_IMPORT, NULL, 0, mbox, 387 sizeof(mbox), NULL) < 0) { 388 error = errno; 389 warn("Failed to import foreign configuration"); 390 close(fd); 391 return (error); 392 } 393 394 if (1 == ac) 395 printf("mfi%d: All foreign configurations imported\n", 396 mfi_unit); 397 else 398 printf("mfi%d: Foreign configuration %d imported\n", mfi_unit, 399 cfgidx); 400 close(fd); 401 return (0); 402 } 403 MFI_COMMAND(foreign, import, foreign_import); 404