xref: /freebsd/usr.sbin/mfiutil/mfi_patrol.c (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2008, 2009 Yahoo!, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The names of the authors may not be used to endorse or promote
16  *    products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/types.h>
33 #include <sys/errno.h>
34 #include <err.h>
35 #include <fcntl.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <time.h>
40 #include <unistd.h>
41 #include "mfiutil.h"
42 
43 static char *
44 adapter_time(time_t now, uint32_t at_now, uint32_t at)
45 {
46 	time_t t;
47 
48 	t = (now - at_now) + at;
49 	return (ctime(&t));
50 }
51 
52 static void
53 mfi_get_time(int fd, uint32_t *at)
54 {
55 
56 	if (mfi_dcmd_command(fd, MFI_DCMD_TIME_SECS_GET, at, sizeof(*at), NULL,
57 	    0, NULL) < 0) {
58 		warn("Couldn't fetch adapter time");
59 		at = 0;
60 	}
61 }
62 
63 static int
64 patrol_get_props(int fd, struct mfi_pr_properties *prop)
65 {
66 	int error;
67 
68 	if (mfi_dcmd_command(fd, MFI_DCMD_PR_GET_PROPERTIES, prop,
69 	    sizeof(*prop), NULL, 0, NULL) < 0) {
70 		error = errno;
71 		warn("Failed to get patrol read properties");
72 		return (error);
73 	}
74 	return (0);
75 }
76 
77 static int
78 show_patrol(int ac __unused, char **av __unused)
79 {
80 	struct mfi_pr_properties prop;
81 	struct mfi_pr_status status;
82 	struct mfi_pd_list *list;
83 	struct mfi_pd_info info;
84 	char label[24];
85 	time_t now;
86 	uint32_t at;
87 	int error, fd;
88 	u_int i;
89 
90 	fd = mfi_open(mfi_device, O_RDWR);
91 	if (fd < 0) {
92 		error = errno;
93 		warn("mfi_open");
94 		return (error);
95 	}
96 
97 	time(&now);
98 	mfi_get_time(fd, &at);
99 	error = patrol_get_props(fd, &prop);
100 	if (error) {
101 		close(fd);
102 		return (error);
103 	}
104 	printf("Operation Mode: ");
105 	switch (prop.op_mode) {
106 	case MFI_PR_OPMODE_AUTO:
107 		printf("auto\n");
108 		break;
109 	case MFI_PR_OPMODE_MANUAL:
110 		printf("manual\n");
111 		break;
112 	case MFI_PR_OPMODE_DISABLED:
113 		printf("disabled\n");
114 		break;
115 	default:
116 		printf("??? (%02x)\n", prop.op_mode);
117 		break;
118 	}
119 	if (prop.op_mode == MFI_PR_OPMODE_AUTO) {
120 		if (at != 0 && prop.next_exec)
121 			printf("    Next Run Starts: %s", adapter_time(now, at,
122 			    prop.next_exec));
123 		if (prop.exec_freq == 0xffffffff)
124 			printf("    Runs Execute Continuously\n");
125 		else if (prop.exec_freq != 0)
126 			printf("    Runs Start Every %u seconds\n",
127 			    prop.exec_freq);
128 	}
129 
130 	if (mfi_dcmd_command(fd, MFI_DCMD_PR_GET_STATUS, &status,
131 	    sizeof(status), NULL, 0, NULL) < 0) {
132 		error = errno;
133 		warn("Failed to get patrol read properties");
134 		close(fd);
135 		return (error);
136 	}
137 	printf("Runs Completed: %u\n", status.num_iteration);
138 	printf("Current State: ");
139 	switch (status.state) {
140 	case MFI_PR_STATE_STOPPED:
141 		printf("stopped\n");
142 		break;
143 	case MFI_PR_STATE_READY:
144 		printf("ready\n");
145 		break;
146 	case MFI_PR_STATE_ACTIVE:
147 		printf("active\n");
148 		break;
149 	case MFI_PR_STATE_ABORTED:
150 		printf("aborted\n");
151 		break;
152 	default:
153 		printf("??? (%02x)\n", status.state);
154 		break;
155 	}
156 	if (status.state == MFI_PR_STATE_ACTIVE) {
157 		if (mfi_pd_get_list(fd, &list, NULL) < 0) {
158 			error = errno;
159 			warn("Failed to get drive list");
160 			close(fd);
161 			return (error);
162 		}
163 
164 		for (i = 0; i < list->count; i++) {
165 			if (list->addr[i].scsi_dev_type != 0)
166 				continue;
167 
168 			if (mfi_pd_get_info(fd, list->addr[i].device_id, &info,
169 			    NULL) < 0) {
170 				error = errno;
171 				warn("Failed to fetch info for drive %u",
172 				    list->addr[i].device_id);
173 				free(list);
174 				close(fd);
175 				return (error);
176 			}
177 			if (info.prog_info.active & MFI_PD_PROGRESS_PATROL) {
178 				snprintf(label, sizeof(label), "    Drive %s",
179 				    mfi_drive_name(NULL,
180 				    list->addr[i].device_id,
181 				    MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
182 				mfi_display_progress(label,
183 				    &info.prog_info.patrol);
184 			}
185 		}
186 		free(list);
187 	}
188 
189 	close(fd);
190 
191 	return (0);
192 }
193 MFI_COMMAND(show, patrol, show_patrol);
194 
195 static int
196 start_patrol(int ac __unused, char **av __unused)
197 {
198 	int error, fd;
199 
200 	fd = mfi_open(mfi_device, O_RDWR);
201 	if (fd < 0) {
202 		error = errno;
203 		warn("mfi_open");
204 		return (error);
205 	}
206 
207 	if (mfi_dcmd_command(fd, MFI_DCMD_PR_START, NULL, 0, NULL, 0, NULL) <
208 	    0) {
209 		error = errno;
210 		warn("Failed to start patrol read");
211 		close(fd);
212 		return (error);
213 	}
214 
215 	close(fd);
216 
217 	return (0);
218 }
219 MFI_COMMAND(start, patrol, start_patrol);
220 
221 static int
222 stop_patrol(int ac __unused, char **av __unused)
223 {
224 	int error, fd;
225 
226 	fd = mfi_open(mfi_device, O_RDWR);
227 	if (fd < 0) {
228 		error = errno;
229 		warn("mfi_open");
230 		return (error);
231 	}
232 
233 	if (mfi_dcmd_command(fd, MFI_DCMD_PR_STOP, NULL, 0, NULL, 0, NULL) <
234 	    0) {
235 		error = errno;
236 		warn("Failed to stop patrol read");
237 		close(fd);
238 		return (error);
239 	}
240 
241 	close(fd);
242 
243 	return (0);
244 }
245 MFI_COMMAND(stop, patrol, stop_patrol);
246 
247 static int
248 patrol_config(int ac, char **av)
249 {
250 	struct mfi_pr_properties prop;
251 	long val;
252 	time_t now;
253 	int error, fd;
254 	uint32_t at, next_exec, exec_freq;
255 	char *cp;
256 	uint8_t op_mode;
257 
258 	exec_freq = 0;	/* GCC too stupid */
259 	next_exec = 0;
260 	if (ac < 2) {
261 		warnx("patrol: command required");
262 		return (EINVAL);
263 	}
264 	if (strcasecmp(av[1], "auto") == 0) {
265 		op_mode = MFI_PR_OPMODE_AUTO;
266 		if (ac > 2) {
267 			if (strcasecmp(av[2], "continuously") == 0)
268 				exec_freq = 0xffffffff;
269 			else {
270 				val = strtol(av[2], &cp, 0);
271 				if (*cp != '\0') {
272 					warnx("patrol: Invalid interval %s",
273 					    av[2]);
274 					return (EINVAL);
275 				}
276 				exec_freq = val;
277 			}
278 		}
279 		if (ac > 3) {
280 			val = strtol(av[3], &cp, 0);
281 			if (*cp != '\0' || val < 0) {
282 				warnx("patrol: Invalid start time %s", av[3]);
283 				return (EINVAL);
284 			}
285 			next_exec = val;
286 		}
287 	} else if (strcasecmp(av[1], "manual") == 0)
288 		op_mode = MFI_PR_OPMODE_MANUAL;
289 	else if (strcasecmp(av[1], "disable") == 0)
290 		op_mode = MFI_PR_OPMODE_DISABLED;
291 	else {
292 		warnx("patrol: Invalid command %s", av[1]);
293 		return (EINVAL);
294 	}
295 
296 	fd = mfi_open(mfi_device, O_RDWR);
297 	if (fd < 0) {
298 		error = errno;
299 		warn("mfi_open");
300 		return (error);
301 	}
302 
303 	error = patrol_get_props(fd, &prop);
304 	if (error) {
305 		close(fd);
306 		return (error);
307 	}
308 	prop.op_mode = op_mode;
309 	if (op_mode == MFI_PR_OPMODE_AUTO) {
310 		if (ac > 2)
311 			prop.exec_freq = exec_freq;
312 		if (ac > 3) {
313 			time(&now);
314 			mfi_get_time(fd, &at);
315 			if (at == 0) {
316 				close(fd);
317 				return (ENXIO);
318 			}
319 			prop.next_exec = at + next_exec;
320 			printf("Starting next patrol read at %s",
321 			    adapter_time(now, at, prop.next_exec));
322 		}
323 	}
324 	if (mfi_dcmd_command(fd, MFI_DCMD_PR_SET_PROPERTIES, &prop,
325 	    sizeof(prop), NULL, 0, NULL) < 0) {
326 		error = errno;
327 		warn("Failed to set patrol read properties");
328 		close(fd);
329 		return (error);
330 	}
331 
332 	close(fd);
333 
334 	return (0);
335 }
336 MFI_COMMAND(top, patrol, patrol_config);
337