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