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 * $FreeBSD$ 30 */ 31 32 #include <sys/types.h> 33 #include <sys/errno.h> 34 #include <err.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <time.h> 39 #include <unistd.h> 40 #include "mfiutil.h" 41 42 static char * 43 adapter_time(time_t now, uint32_t at_now, uint32_t at) 44 { 45 time_t t; 46 47 t = (now - at_now) + at; 48 return (ctime(&t)); 49 } 50 51 static void 52 mfi_get_time(int fd, uint32_t *at) 53 { 54 55 if (mfi_dcmd_command(fd, MFI_DCMD_TIME_SECS_GET, at, sizeof(*at), NULL, 56 0, NULL) < 0) { 57 warn("Couldn't fetch adapter time"); 58 at = 0; 59 } 60 } 61 62 static int 63 patrol_get_props(int fd, struct mfi_pr_properties *prop) 64 { 65 66 if (mfi_dcmd_command(fd, MFI_DCMD_PR_GET_PROPERTIES, prop, 67 sizeof(*prop), NULL, 0, NULL) < 0) { 68 warn("Failed to get patrol read properties"); 69 return (-1); 70 } 71 return (0); 72 } 73 74 static int 75 show_patrol(int ac, char **av) 76 { 77 struct mfi_pr_properties prop; 78 struct mfi_pr_status status; 79 struct mfi_pd_list *list; 80 struct mfi_pd_info info; 81 char label[16]; 82 time_t now; 83 uint32_t at; 84 int fd; 85 u_int i; 86 87 fd = mfi_open(mfi_unit); 88 if (fd < 0) { 89 warn("mfi_open"); 90 return (errno); 91 } 92 93 time(&now); 94 mfi_get_time(fd, &at); 95 if (patrol_get_props(fd, &prop) < 0) 96 return (errno); 97 printf("Operation Mode: "); 98 switch (prop.op_mode) { 99 case MFI_PR_OPMODE_AUTO: 100 printf("auto\n"); 101 break; 102 case MFI_PR_OPMODE_MANUAL: 103 printf("manual\n"); 104 break; 105 case MFI_PR_OPMODE_DISABLED: 106 printf("disabled\n"); 107 break; 108 default: 109 printf("??? (%02x)\n", prop.op_mode); 110 break; 111 } 112 if (prop.op_mode == MFI_PR_OPMODE_AUTO) { 113 if (at != 0 && prop.next_exec) 114 printf(" Next Run Starts: %s", adapter_time(now, at, 115 prop.next_exec)); 116 if (prop.exec_freq == 0xffffffff) 117 printf(" Runs Execute Continuously\n"); 118 else if (prop.exec_freq != 0) 119 printf(" Runs Start Every %u seconds\n", 120 prop.exec_freq); 121 } 122 123 if (mfi_dcmd_command(fd, MFI_DCMD_PR_GET_STATUS, &status, 124 sizeof(status), NULL, 0, NULL) < 0) { 125 warn("Failed to get patrol read properties"); 126 return (errno); 127 } 128 printf("Runs Completed: %u\n", status.num_iteration); 129 printf("Current State: "); 130 switch (status.state) { 131 case MFI_PR_STATE_STOPPED: 132 printf("stopped\n"); 133 break; 134 case MFI_PR_STATE_READY: 135 printf("ready\n"); 136 break; 137 case MFI_PR_STATE_ACTIVE: 138 printf("active\n"); 139 break; 140 case MFI_PR_STATE_ABORTED: 141 printf("aborted\n"); 142 break; 143 default: 144 printf("??? (%02x)\n", status.state); 145 break; 146 } 147 if (status.state == MFI_PR_STATE_ACTIVE) { 148 if (mfi_pd_get_list(fd, &list, NULL) < 0) { 149 warn("Failed to get drive list"); 150 return (errno); 151 } 152 153 for (i = 0; i < list->count; i++) { 154 if (list->addr[i].scsi_dev_type != 0) 155 continue; 156 157 if (mfi_pd_get_info(fd, list->addr[i].device_id, &info, 158 NULL) < 0) { 159 warn("Failed to fetch info for drive %u", 160 list->addr[i].device_id); 161 return (errno); 162 } 163 if (info.prog_info.active & MFI_PD_PROGRESS_PATROL) { 164 snprintf(label, sizeof(label), " Drive %u", 165 list->addr[i].device_id); 166 mfi_display_progress(label, 167 &info.prog_info.patrol); 168 } 169 } 170 } 171 172 close(fd); 173 174 return (0); 175 } 176 MFI_COMMAND(show, patrol, show_patrol); 177 178 static int 179 start_patrol(int ac, char **av) 180 { 181 int fd; 182 183 fd = mfi_open(mfi_unit); 184 if (fd < 0) { 185 warn("mfi_open"); 186 return (errno); 187 } 188 189 if (mfi_dcmd_command(fd, MFI_DCMD_PR_START, NULL, 0, NULL, 0, NULL) < 190 0) { 191 warn("Failed to start patrol read"); 192 return (errno); 193 } 194 195 close(fd); 196 197 return (0); 198 } 199 MFI_COMMAND(start, patrol, start_patrol); 200 201 static int 202 stop_patrol(int ac, char **av) 203 { 204 int fd; 205 206 fd = mfi_open(mfi_unit); 207 if (fd < 0) { 208 warn("mfi_open"); 209 return (errno); 210 } 211 212 if (mfi_dcmd_command(fd, MFI_DCMD_PR_STOP, NULL, 0, NULL, 0, NULL) < 213 0) { 214 warn("Failed to stop patrol read"); 215 return (errno); 216 } 217 218 close(fd); 219 220 return (0); 221 } 222 MFI_COMMAND(stop, patrol, stop_patrol); 223 224 static int 225 patrol_config(int ac, char **av) 226 { 227 struct mfi_pr_properties prop; 228 long val; 229 time_t now; 230 uint32_t at, next_exec, exec_freq; 231 char *cp; 232 uint8_t op_mode; 233 int fd; 234 235 exec_freq = 0; /* GCC too stupid */ 236 next_exec = 0; 237 if (ac < 2) { 238 warnx("patrol: command required"); 239 return (EINVAL); 240 } 241 if (strcasecmp(av[1], "auto") == 0) { 242 op_mode = MFI_PR_OPMODE_AUTO; 243 if (ac > 2) { 244 if (strcasecmp(av[2], "continously") == 0) 245 exec_freq = 0xffffffff; 246 else { 247 val = strtol(av[2], &cp, 0); 248 if (*cp != '\0') { 249 warnx("patrol: Invalid interval %s", 250 av[2]); 251 return (EINVAL); 252 } 253 exec_freq = val; 254 } 255 } 256 if (ac > 3) { 257 val = strtol(av[3], &cp, 0); 258 if (*cp != '\0' || val < 0) { 259 warnx("patrol: Invalid start time %s", av[3]); 260 return (EINVAL); 261 } 262 next_exec = val; 263 } 264 } else if (strcasecmp(av[1], "manual") == 0) 265 op_mode = MFI_PR_OPMODE_MANUAL; 266 else if (strcasecmp(av[1], "disable") == 0) 267 op_mode = MFI_PR_OPMODE_DISABLED; 268 else { 269 warnx("patrol: Invalid command %s", av[1]); 270 return (EINVAL); 271 } 272 273 fd = mfi_open(mfi_unit); 274 if (fd < 0) { 275 warn("mfi_open"); 276 return (errno); 277 } 278 279 if (patrol_get_props(fd, &prop) < 0) 280 return (errno); 281 prop.op_mode = op_mode; 282 if (op_mode == MFI_PR_OPMODE_AUTO) { 283 if (ac > 2) 284 prop.exec_freq = exec_freq; 285 if (ac > 3) { 286 time(&now); 287 mfi_get_time(fd, &at); 288 if (at == 0) 289 return (ENXIO); 290 prop.next_exec = at + next_exec; 291 printf("Starting next patrol read at %s", 292 adapter_time(now, at, prop.next_exec)); 293 } 294 } 295 if (mfi_dcmd_command(fd, MFI_DCMD_PR_SET_PROPERTIES, &prop, 296 sizeof(prop), NULL, 0, NULL) < 0) { 297 warn("Failed to set patrol read properties"); 298 return (errno); 299 } 300 301 close(fd); 302 303 return (0); 304 } 305 MFI_COMMAND(top, patrol, patrol_config); 306