GC !__DragonFly__ section.
[dragonfly.git] / sbin / atacontrol / atacontrol.c
1 /*-
2  * Copyright (c) 2000,2001,2002 Søren Schmidt <sos@FreeBSD.org>
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  *    without modification, immediately at the beginning of the file.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sbin/atacontrol/atacontrol.c,v 1.11.2.5 2002/08/21 13:18:17 sos Exp $
29  * $DragonFly: src/sbin/atacontrol/atacontrol.c,v 1.4 2005/01/09 04:43:33 cpressey Exp $
30  */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <err.h>
38 #include <sys/ata.h>
39
40 static const char *mode2str(int);
41 static int      str2mode(char *);
42 static void     usage(void);
43 static int      version(int);
44 static void     param_print(struct ata_params *);
45 static void     cap_print(struct ata_params *);
46 static int      ata_cap_print(int, int, int);
47 static int      info_print(int, int, int);
48
49 const char *
50 mode2str(int mode)
51 {
52         switch (mode) {
53         case ATA_PIO: return "BIOSPIO";
54         case ATA_PIO0: return "PIO0";
55         case ATA_PIO1: return "PIO1";
56         case ATA_PIO2: return "PIO2";
57         case ATA_PIO3: return "PIO3";
58         case ATA_PIO4: return "PIO4";
59         case ATA_WDMA2: return "WDMA2";
60         case ATA_UDMA2: return "UDMA33";
61         case ATA_UDMA4: return "UDMA66";
62         case ATA_UDMA5: return "UDMA100";
63         case ATA_UDMA6: return "UDMA133";
64         case ATA_DMA: return "BIOSDMA";
65         default: return "???";
66         }
67 }
68
69 int
70 str2mode(char *str)
71 {
72         if (!strcasecmp(str, "BIOSPIO")) return ATA_PIO;
73         if (!strcasecmp(str, "PIO0")) return ATA_PIO0;
74         if (!strcasecmp(str, "PIO1")) return ATA_PIO1;
75         if (!strcasecmp(str, "PIO2")) return ATA_PIO2;
76         if (!strcasecmp(str, "PIO3")) return ATA_PIO3;
77         if (!strcasecmp(str, "PIO4")) return ATA_PIO4;
78         if (!strcasecmp(str, "WDMA2")) return ATA_WDMA2;
79         if (!strcasecmp(str, "UDMA2")) return ATA_UDMA2;
80         if (!strcasecmp(str, "UDMA33")) return ATA_UDMA2;
81         if (!strcasecmp(str, "UDMA4")) return ATA_UDMA4;
82         if (!strcasecmp(str, "UDMA66")) return ATA_UDMA4;
83         if (!strcasecmp(str, "UDMA5")) return ATA_UDMA5;
84         if (!strcasecmp(str, "UDMA100")) return ATA_UDMA5;
85         if (!strcasecmp(str, "UDMA6")) return ATA_UDMA6;
86         if (!strcasecmp(str, "UDMA133")) return ATA_UDMA6;
87         if (!strcasecmp(str, "BIOSDMA")) return ATA_DMA;
88         return -1;
89 }
90
91
92 void
93 usage(void)
94 {
95         fprintf(stderr, "usage: atacontrol <command> channel [args]\n");
96         exit(1);
97 }
98
99 int
100 version(int ver)
101 {
102         int bit;
103     
104         if (ver == 0xffff)
105                 return 0;
106         for (bit = 15; bit >= 0; bit--)
107                 if (ver & (1 << bit))
108                         return bit;
109         return 0;
110 }
111
112 void
113 param_print(struct ata_params *parm)
114 {
115         printf("<%.40s/%.8s> ATA/ATAPI rev %d\n",
116                 parm->model, parm->revision, version(parm->version_major)); 
117 }
118
119 void
120 cap_print(struct ata_params *parm)
121 {
122         printf("\n");
123         printf("ATA/ATAPI revision    %d\n", version(parm->version_major));
124         printf("device model          %.40s\n", parm->model);
125         printf("serial number         %.20s\n", parm->serial);
126         printf("firmware revision     %.8s\n", parm->revision);
127
128         printf("cylinders             %d\n", parm->cylinders);
129         printf("heads                 %d\n", parm->heads);
130         printf("sectors/track         %d\n", parm->sectors);    
131         
132         printf("lba%ssupported         ", parm->support_lba ? " " : " not ");
133         if (parm->lba_size)
134                 printf("%d sectors\n", parm->lba_size); 
135         else
136                 printf("\n");
137
138         printf("lba48%ssupported         ", parm->support.address48 ? " " : " not ");
139         if (parm->lba_size48)
140                 printf("%lld sectors\n", parm->lba_size48);     
141         else
142                 printf("\n");
143         printf("dma%ssupported\n", parm->support_dma ? " " : " not");
144
145         printf("overlap%ssupported\n", parm->support_queueing ? " " : " not ");
146   
147         printf("\nFeature                      Support  Enable    Value   Vendor\n");
148
149         printf("write cache                    %s       %s\n",
150                 parm->support.write_cache ? "yes" : "no",
151                 parm->enabled.write_cache ? "yes" : "no");      
152
153         printf("read ahead                     %s       %s\n",
154                 parm->support.look_ahead ? "yes" : "no",
155                 parm->enabled.look_ahead ? "yes" : "no");       
156
157         printf("dma queued                     %s       %s      %d/%02X\n",
158                 parm->support.queued ? "yes" : "no",
159                 parm->enabled.queued ? "yes" : "no",
160                 parm->queuelen, parm->queuelen);        
161
162         printf("SMART                          %s       %s\n",
163                 parm->support.smart ? "yes" : "no",
164                 parm->enabled.smart ? "yes" : "no");
165
166         printf("microcode download             %s       %s\n",
167                 parm->support.microcode ? "yes" : "no",
168                 parm->enabled.microcode ? "yes" : "no");        
169
170         printf("security                       %s       %s\n",
171                 parm->support.smart ? "yes" : "no",
172                 parm->enabled.smart ? "yes" : "no");    
173
174         printf("power management               %s       %s\n",
175                 parm->support.power_mngt ? "yes" : "no",
176                 parm->enabled.power_mngt ? "yes" : "no");       
177
178         printf("advanced power management      %s       %s      %d/%02X\n",
179                 parm->support.apm ? "yes" : "no",
180                 parm->enabled.apm ? "yes" : "no",
181                 parm->apm_value, parm->apm_value);
182
183         printf("automatic acoustic management  %s       %s      %d/%02X %d/%02X\n",
184                 parm->support.auto_acoustic ? "yes" : "no",
185                 parm->enabled.auto_acoustic ? "yes" : "no",
186                 parm->current_acoustic, parm->current_acoustic,
187                 parm->vendor_acoustic, parm->vendor_acoustic);  
188 }
189
190 int
191 ata_cap_print(int fd, int channel, int device)
192 {
193         struct ata_cmd iocmd;
194
195         bzero(&iocmd, sizeof(struct ata_cmd));
196
197         iocmd.channel = channel;
198         iocmd.device = -1;
199         iocmd.cmd = ATAGPARM;
200
201         if (ioctl(fd, IOCATA, &iocmd) < 0)
202                 return errno;
203
204         printf("ATA channel %d, %s", channel, device==0 ? "Master" : "Slave");
205
206         if (iocmd.u.param.type[device]) {
207                 printf(", device %s:\n", iocmd.u.param.name[device]);
208                 cap_print(&iocmd.u.param.params[device]);
209         }
210         else
211                 printf(": no device present\n");
212         return 0;
213 }
214
215 int
216 info_print(int fd, int channel, int prchan)
217 {
218         struct ata_cmd iocmd;
219
220         bzero(&iocmd, sizeof(struct ata_cmd));
221         iocmd.channel = channel;
222         iocmd.device = -1;
223         iocmd.cmd = ATAGPARM;
224         if (ioctl(fd, IOCATA, &iocmd) < 0)
225                 return errno;
226         if (prchan)
227                 printf("ATA channel %d:\n", channel);
228         printf("%sMaster: ", prchan ? "    " : "");
229         if (iocmd.u.param.type[0]) {
230                 printf("%4.4s ", iocmd.u.param.name[0]);
231                 param_print(&iocmd.u.param.params[0]);
232         }
233         else
234                 printf("     no device present\n");
235         printf("%sSlave:  ", prchan ? "    " : "");
236         if (iocmd.u.param.type[1]) {
237                 printf("%4.4s ", iocmd.u.param.name[1]);
238                 param_print(&iocmd.u.param.params[1]);
239         }
240         else
241                 printf("     no device present\n");
242         return 0;
243 }
244
245 int
246 main(int argc, char **argv)
247 {
248         struct ata_cmd iocmd;
249         int fd;
250
251         if ((fd = open("/dev/ata", O_RDWR)) < 0)
252                 err(1, "control device not found");
253
254         if (argc < 2)
255                 usage();
256
257         bzero(&iocmd, sizeof(struct ata_cmd));
258
259         if (argc > 2 && strcmp(argv[1], "create")) {
260                 int chan;
261
262                 if (!strcmp(argv[1], "delete") ||
263                     !strcmp(argv[1], "status") ||
264                     !strcmp(argv[1], "rebuild")) {
265                         if (!(sscanf(argv[2], "%d", &chan) == 1 ||
266                               sscanf(argv[2], "ar%d", &chan) == 1))
267                                 usage();
268                 }
269                 else {
270                         if (!(sscanf(argv[2], "%d", &chan) == 1 ||
271                               sscanf(argv[2], "ata%d", &chan) == 1))
272                                 usage();
273                 }
274                 iocmd.channel = chan;
275         }
276
277         if (!strcmp(argv[1], "list") && argc == 2) {
278                 int unit = 0;
279
280                 while (info_print(fd, unit++, 1) != ENXIO);
281         }
282         else if (!strcmp(argv[1], "info") && argc == 3) {
283                 info_print(fd, iocmd.channel, 0);
284         }
285         else if (!strcmp(argv[1], "cap") && argc == 4) {
286                 ata_cap_print(fd, iocmd.channel, atoi(argv[3]));
287         }
288         else if (!strcmp(argv[1], "enclosure") && argc == 4) {
289                 iocmd.device = atoi(argv[3]);
290                 iocmd.cmd = ATAENCSTAT;
291                 if (ioctl(fd, IOCATA, &iocmd) < 0)
292                         err(1, "ioctl(ATAENCSTAT)");
293                 printf("fan RPM: %d temp: %.1f 5V: %.2f 12V: %.2f\n",
294                         iocmd.u.enclosure.fan,
295                         (double)iocmd.u.enclosure.temp / 10,
296                         (double)iocmd.u.enclosure.v05 / 1000,
297                         (double)iocmd.u.enclosure.v12 / 1000);
298         }
299         else if (!strcmp(argv[1], "detach") && argc == 3) {
300                 iocmd.cmd = ATADETACH;
301                 if (ioctl(fd, IOCATA, &iocmd) < 0)
302                         err(1, "ioctl(ATADETACH)");
303         }
304         else if (!strcmp(argv[1], "attach") && argc == 3) {
305                 iocmd.cmd = ATAATTACH;
306                 if (ioctl(fd, IOCATA, &iocmd) < 0)
307                         err(1, "ioctl(ATAATTACH)");
308                 info_print(fd, iocmd.channel, 0);
309         }
310         else if (!strcmp(argv[1], "reinit") && argc == 3) {
311                 iocmd.cmd = ATAREINIT;
312                 if (ioctl(fd, IOCATA, &iocmd) < 0)
313                         warn("ioctl(ATAREINIT)");
314                 info_print(fd, iocmd.channel, 0);
315         }
316         else if (!strcmp(argv[1], "create")) {
317                 int disk, dev, offset;
318
319                 iocmd.cmd = ATARAIDCREATE;
320                 if (!strcmp(argv[2], "RAID0") || !strcmp(argv[2], "stripe"))
321                         iocmd.u.raid_setup.type = 1;
322                 if (!strcmp(argv[2], "RAID1") || !strcmp(argv[2],"mirror"))
323                         iocmd.u.raid_setup.type = 2;
324                 if (!strcmp(argv[2], "RAID0+1"))
325                         iocmd.u.raid_setup.type = 3;
326                 if (!strcmp(argv[2], "SPAN") || !strcmp(argv[2], "JBOD"))
327                         iocmd.u.raid_setup.type = 4;
328                 if (!iocmd.u.raid_setup.type)
329                      usage();
330                 
331                 if (iocmd.u.raid_setup.type & 1) {
332                         if (!sscanf(argv[3], "%d",
333                                     &iocmd.u.raid_setup.interleave) == 1)
334                                 usage();
335                         offset = 4;
336                 }
337                 else
338                         offset = 3;
339                 
340                 for (disk = 0; disk < 16 && (offset + disk) < argc; disk++) {
341                         if (!(sscanf(argv[offset + disk], "%d", &dev) == 1 ||
342                               sscanf(argv[offset + disk], "ad%d", &dev) == 1))
343                                 usage();
344                         iocmd.u.raid_setup.disks[disk] = dev;
345                 }
346                 iocmd.u.raid_setup.total_disks = disk;
347                 if (ioctl(fd, IOCATA, &iocmd) < 0)
348                         err(1, "ioctl(ATARAIDCREATE)");
349                 else
350                         printf("ar%d created\n", iocmd.u.raid_setup.unit);
351         }
352         else if (!strcmp(argv[1], "delete") && argc == 3) {
353                 iocmd.cmd = ATARAIDDELETE;
354                 if (ioctl(fd, IOCATA, &iocmd) < 0)
355                         warn("ioctl(ATARAIDDELETE)");
356         }
357         else if (!strcmp(argv[1], "rebuild") && argc == 3) {
358                 iocmd.cmd = ATARAIDREBUILD;
359                 if (ioctl(fd, IOCATA, &iocmd) < 0)
360                         warn("ioctl(ATARAIDREBUILD)");
361         }
362         else if (!strcmp(argv[1], "status") && argc == 3) {
363                 int i;
364
365                 iocmd.cmd = ATARAIDSTATUS;
366                 if (ioctl(fd, IOCATA, &iocmd) < 0)
367                         err(1, "ioctl(ATARAIDSTATUS)");
368                 printf("ar%d: ATA ", iocmd.channel);
369                 switch (iocmd.u.raid_status.type) {
370                 case AR_RAID0:
371                         printf("RAID0");
372                         break;
373                 case AR_RAID1:
374                         printf("RAID1");
375                         break;
376                 case AR_RAID0 | AR_RAID1:
377                         printf("RAID0+1");
378                         break;
379                 case AR_SPAN:
380                         printf("SPAN");
381                         break;
382                 }
383                 printf(" subdisks: ");
384                 for (i = 0; i < iocmd.u.raid_status.total_disks; i++) {
385                         if (iocmd.u.raid_status.disks[i] >= 0)
386                                 printf("ad%d ", iocmd.u.raid_status.disks[i]);
387                         else
388                                 printf("DOWN ");
389                 }
390                 printf("status: ");
391                 switch (iocmd.u.raid_status.status) {
392                 case AR_READY:
393                         printf("READY\n");
394                         break;
395                 case AR_READY | AR_DEGRADED:
396                         printf("DEGRADED\n");
397                         break;
398                 case AR_READY | AR_DEGRADED | AR_REBUILDING:
399                         printf("REBUILDING %d%% completed\n",
400                                 iocmd.u.raid_status.progress);
401                         break;
402                 default:
403                         printf("BROKEN\n");
404                 }
405         }
406         else if (!strcmp(argv[1], "mode") && (argc == 3 || argc == 5)) {
407                 if (argc == 5) {
408                         iocmd.cmd = ATASMODE;
409                         iocmd.device = -1;
410                         iocmd.u.mode.mode[0] = str2mode(argv[3]);
411                         iocmd.u.mode.mode[1] = str2mode(argv[4]);
412                         if (ioctl(fd, IOCATA, &iocmd) < 0)
413                                 warn("ioctl(ATASMODE)");
414                 }
415                 if (argc == 3 || argc == 5) {
416                         iocmd.cmd = ATAGMODE;
417                         iocmd.device = -1;
418                         if (ioctl(fd, IOCATA, &iocmd) < 0)
419                                 err(1, "ioctl(ATAGMODE)");
420                         printf("Master = %s \nSlave  = %s\n",
421                                 mode2str(iocmd.u.mode.mode[0]), 
422                                 mode2str(iocmd.u.mode.mode[1]));
423                 }
424         }
425         else
426                 usage();
427         exit(0);
428 }