]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/atacontrol/atacontrol.c
Add support for getting status (fan, temp, 5V and 12V levels) from
[FreeBSD/FreeBSD.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$
29  */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <err.h>
37 #include <sys/ata.h>
38
39 char *
40 mode2str(int mode)
41 {
42         switch (mode) {
43         case ATA_PIO: return "BIOSPIO";
44         case ATA_PIO0: return "PIO0";
45         case ATA_PIO1: return "PIO1";
46         case ATA_PIO2: return "PIO2";
47         case ATA_PIO3: return "PIO3";
48         case ATA_PIO4: return "PIO4";
49         case ATA_WDMA2: return "WDMA2";
50         case ATA_UDMA2: return "UDMA33";
51         case ATA_UDMA4: return "UDMA66";
52         case ATA_UDMA5: return "UDMA100";
53         case ATA_DMA: return "BIOSDMA";
54         default: return "???";
55         }
56 }
57
58 int
59 str2mode(char *str)
60 {
61         if (!strcasecmp(str, "BIOSPIO")) return ATA_PIO;
62         if (!strcasecmp(str, "PIO0")) return ATA_PIO0;
63         if (!strcasecmp(str, "PIO1")) return ATA_PIO1;
64         if (!strcasecmp(str, "PIO2")) return ATA_PIO2;
65         if (!strcasecmp(str, "PIO3")) return ATA_PIO3;
66         if (!strcasecmp(str, "PIO4")) return ATA_PIO4;
67         if (!strcasecmp(str, "WDMA2")) return ATA_WDMA2;
68         if (!strcasecmp(str, "UDMA2")) return ATA_UDMA2;
69         if (!strcasecmp(str, "UDMA33")) return ATA_UDMA2;
70         if (!strcasecmp(str, "UDMA4")) return ATA_UDMA4;
71         if (!strcasecmp(str, "UDMA66")) return ATA_UDMA4;
72         if (!strcasecmp(str, "UDMA5")) return ATA_UDMA5;
73         if (!strcasecmp(str, "UDMA100")) return ATA_UDMA5;
74         if (!strcasecmp(str, "UDMA6")) return ATA_UDMA6;
75         if (!strcasecmp(str, "UDMA133")) return ATA_UDMA6;
76         if (!strcasecmp(str, "BIOSDMA")) return ATA_DMA;
77         return -1;
78 }
79
80
81 void
82 usage()
83 {
84         fprintf(stderr, "usage: atacontrol <command> channel [args]\n");
85         exit(1);
86 }
87
88 int
89 version(int version)
90 {
91         int bit;
92     
93         if (version == 0xffff)
94                 return 0;
95         for (bit = 15; bit >= 0; bit--)
96                 if (version & (1<<bit))
97                         return bit;
98         return 0;
99 }
100
101 void
102 param_print(struct ata_params *parm)
103 {
104         printf("<%.40s/%.8s> ATA/ATAPI rev %d\n",
105                 parm->model, parm->revision, version(parm->version_major)); 
106 }
107
108 void
109 cap_print(struct ata_params *parm)
110 {
111         printf("\n");
112         printf("ATA/ATAPI revision    %d\n", version(parm->version_major));
113         printf("device model          %.40s\n", parm->model);
114         printf("firmware revision     %.8s\n", parm->revision);
115
116         printf("cylinders             %d\n", parm->cylinders);
117         printf("heads                 %d\n", parm->heads);
118         printf("sectors/track         %d\n", parm->sectors);    
119         
120         printf("lba%ssupported         ", parm->support_lba ? " " : " not ");
121         if (parm->lba_size)
122                 printf("%d sectors\n", parm->lba_size); 
123         else
124                 printf("\n");
125
126         printf("lba48%ssupported         ", parm->support.address48 ? " " : " not ");
127         if (parm->lba_size48)
128                 printf("%lld sectors\n", parm->lba_size48);     
129         else
130                 printf("\n");
131         printf("dma%ssupported\n", parm->support_dma ? " " : " not");
132
133         printf("overlap%ssupported\n", parm->support_queueing ? " " : " not ");
134   
135         printf("\nFeature                      Support  Enable    Value   Vendor\n");
136
137         printf("write cache                    %s       %s\n",
138                 parm->support.write_cache ? "yes" : "no",
139                 parm->enabled.write_cache ? "yes" : "no");      
140
141         printf("read ahead                     %s       %s\n",
142                 parm->support.look_ahead ? "yes" : "no",
143                 parm->enabled.look_ahead ? "yes" : "no");       
144
145         printf("dma queued                     %s       %s      %d/%02X\n",
146                 parm->support.queued ? "yes" : "no",
147                 parm->enabled.queued ? "yes" : "no",
148                 parm->queuelen, parm->queuelen);        
149
150         printf("SMART                          %s       %s\n",
151                 parm->support.smart ? "yes" : "no",
152                 parm->enabled.smart ? "yes" : "no");
153
154         printf("microcode download             %s       %s\n",
155                 parm->support.microcode ? "yes" : "no",
156                 parm->enabled.microcode ? "yes" : "no");        
157
158         printf("security                       %s       %s\n",
159                 parm->support.smart ? "yes" : "no",
160                 parm->enabled.smart ? "yes" : "no");    
161
162         printf("power management               %s       %s\n",
163                 parm->support.power_mngt ? "yes" : "no",
164                 parm->enabled.power_mngt ? "yes" : "no");       
165
166         printf("advanced power management      %s       %s      %d/%02X\n",
167                 parm->support.apm ? "yes" : "no",
168                 parm->enabled.apm ? "yes" : "no",
169                 parm->apm_value, parm->apm_value);
170
171         printf("automatic acoustic management  %s       %s      %d/%02X %d/%02X\n",
172                 parm->support.auto_acoustic ? "yes" : "no",
173                 parm->enabled.auto_acoustic ? "yes" : "no",
174                 parm->current_acoustic, parm->current_acoustic,
175                 parm->vendor_acoustic, parm->vendor_acoustic);  
176 }
177
178 int
179 ata_cap_print(int fd, int channel, int device)
180 {
181         struct ata_cmd iocmd;
182
183         bzero(&iocmd, sizeof(struct ata_cmd));
184
185         iocmd.channel = channel;
186         iocmd.device = -1;
187         iocmd.cmd = ATAGPARM;
188
189         if (ioctl(fd, IOCATA, &iocmd) < 0)
190                 return errno;
191
192         printf("ATA channel %d, %s", channel, device==0 ? "Master" : "Slave");
193
194         if (iocmd.u.param.type[device]) {
195                 printf(", device %s:\n", iocmd.u.param.name[device]);
196                 cap_print(&iocmd.u.param.params[device]);
197         }
198         else
199                 printf(": no device present\n");
200         return 0;
201 }
202
203 int
204 info_print(int fd, int channel, int prchan)
205 {
206         struct ata_cmd iocmd;
207
208         bzero(&iocmd, sizeof(struct ata_cmd));
209         iocmd.channel = channel;
210         iocmd.device = -1;
211         iocmd.cmd = ATAGPARM;
212         if (ioctl(fd, IOCATA, &iocmd) < 0)
213                 return errno;
214         if (prchan)
215                 printf("ATA channel %d:\n", channel);
216         printf("%sMaster: ", prchan ? "    " : "");
217         if (iocmd.u.param.type[0]) {
218                 printf("%4.4s ", iocmd.u.param.name[0]);
219                 param_print(&iocmd.u.param.params[0]);
220         }
221         else
222                 printf("     no device present\n");
223         printf("%sSlave:  ", prchan ? "    " : "");
224         if (iocmd.u.param.type[1]) {
225                 printf("%4.4s ", iocmd.u.param.name[1]);
226                 param_print(&iocmd.u.param.params[1]);
227         }
228         else
229                 printf("     no device present\n");
230         return 0;
231 }
232
233 int
234 main(int argc, char **argv)
235 {
236         struct ata_cmd iocmd;
237         int fd;
238
239         if ((fd = open("/dev/ata", O_RDWR)) < 0)
240                 err(1, "control device not found");
241
242         if (argc < 2)
243                 usage();
244
245         bzero(&iocmd, sizeof(struct ata_cmd));
246
247         if (argc > 2 && strcmp(argv[1], "create")) {
248                 int chan;
249
250                 if (!strcmp(argv[1], "delete") ||
251                     !strcmp(argv[1], "rebuild")) {
252                         if (!(sscanf(argv[2], "%d", &chan) == 1 ||
253                               sscanf(argv[2], "ar%d", &chan) == 1))
254                                 usage();
255                 }
256                 else {
257                         if (!(sscanf(argv[2], "%d", &chan) == 1 ||
258                               sscanf(argv[2], "ata%d", &chan) == 1))
259                                 usage();
260                 }
261                 iocmd.channel = chan;
262         }
263
264         if (!strcmp(argv[1], "list") && argc == 2) {
265                 int unit = 0;
266
267                 while (info_print(fd, unit++, 1) != ENXIO);
268         }
269         else if (!strcmp(argv[1], "info") && argc == 3) {
270                 info_print(fd, iocmd.channel, 0);
271         }
272         else if (!strcmp(argv[1], "cap") && argc == 4) {
273                 ata_cap_print(fd, iocmd.channel, atoi(argv[3]));
274         }
275         else if (!strcmp(argv[1], "enclosure") && argc == 4) {
276                 iocmd.device = atoi(argv[3]);
277                 iocmd.cmd = ATAENCSTAT;
278                 if (ioctl(fd, IOCATA, &iocmd) < 0)
279                         err(1, "ioctl(ATAENCSTAT)");
280                 printf("fan RPM: %d temp: %.1f 5V: %.2f 12V: %.2f\n",
281                         iocmd.u.enclosure.fan,
282                         (double)iocmd.u.enclosure.temp / 10,
283                         (double)iocmd.u.enclosure.v05 / 1000,
284                         (double)iocmd.u.enclosure.v12 / 1000);
285         }
286         else if (!strcmp(argv[1], "detach") && argc == 3) {
287                 iocmd.cmd = ATADETACH;
288                 if (ioctl(fd, IOCATA, &iocmd) < 0)
289                         err(1, "ioctl(ATADETACH)");
290         }
291         else if (!strcmp(argv[1], "attach") && argc == 3) {
292                 iocmd.cmd = ATAATTACH;
293                 if (ioctl(fd, IOCATA, &iocmd) < 0)
294                         err(1, "ioctl(ATAATTACH)");
295                 info_print(fd, iocmd.channel, 0);
296         }
297         else if (!strcmp(argv[1], "reinit") && argc == 3) {
298                 iocmd.cmd = ATAREINIT;
299                 if (ioctl(fd, IOCATA, &iocmd) < 0)
300                         warn("ioctl(ATAREINIT)");
301                 info_print(fd, iocmd.channel, 0);
302         }
303         else if (!strcmp(argv[1], "rebuild") && argc == 3) {
304                 iocmd.cmd = ATARAIDREBUILD;
305                 if (ioctl(fd, IOCATA, &iocmd) < 0)
306                         warn("ioctl(ATARAIDREBUILD)");
307         }
308         else if (!strcmp(argv[1], "delete") && argc == 3) {
309                 iocmd.cmd = ATARAIDDELETE;
310                 if (ioctl(fd, IOCATA, &iocmd) < 0)
311                         warn("ioctl(ATARAIDDELETE)");
312         }
313         else if (!strcmp(argv[1], "create")) {
314                 int disk, dev, offset;
315
316                 iocmd.cmd = ATARAIDCREATE;
317                 if (!strcmp(argv[2], "RAID0") || !strcmp(argv[2], "stripe"))
318                         iocmd.u.raid_setup.type = 1;
319                 if (!strcmp(argv[2], "RAID1") || !strcmp(argv[2],"mirror"))
320                         iocmd.u.raid_setup.type = 2;
321                 if (!strcmp(argv[2], "RAID0+1"))
322                         iocmd.u.raid_setup.type = 3;
323                 if (!strcmp(argv[2], "SPAN") || !strcmp(argv[2], "JBOD"))
324                         iocmd.u.raid_setup.type = 4;
325                 if (!iocmd.u.raid_setup.type)
326                      usage();
327                 
328                 if (iocmd.u.raid_setup.type & 1) {
329                         if (!sscanf(argv[3], "%d",
330                                     &iocmd.u.raid_setup.interleave) == 1)
331                                 usage();
332                         offset = 4;
333                 }
334                 else
335                         offset = 3;
336                 
337                 for (disk = 0; disk < 16 && (offset + disk) < argc; disk++) {
338                         if (!(sscanf(argv[offset + disk], "%d", &dev) == 1 ||
339                               sscanf(argv[offset + disk], "ad%d", &dev) == 1))
340                                 usage();
341                         iocmd.u.raid_setup.disks[disk] = dev;
342                 }
343                 iocmd.u.raid_setup.total_disks = disk;
344                 if (ioctl(fd, IOCATA, &iocmd) < 0)
345                         warn("ioctl(ATARAIDCREATE)");
346                 else
347                         printf("ar%d created\n", iocmd.u.raid_setup.unit);
348         }
349         else if (!strcmp(argv[1], "mode") && (argc == 3 || argc == 5)) {
350                 if (argc == 5) {
351                         iocmd.cmd = ATASMODE;
352                         iocmd.device = -1;
353                         iocmd.u.mode.mode[0] = str2mode(argv[3]);
354                         iocmd.u.mode.mode[1] = str2mode(argv[4]);
355                         if (ioctl(fd, IOCATA, &iocmd) < 0)
356                                 warn("ioctl(ATASMODE)");
357                 }
358                 if (argc == 3 || argc == 5) {
359                         iocmd.cmd = ATAGMODE;
360                         iocmd.device = -1;
361                         if (ioctl(fd, IOCATA, &iocmd) < 0)
362                                 err(1, "ioctl(ATAGMODE)");
363                         printf("Master = %s \nSlave  = %s\n",
364                                 mode2str(iocmd.u.mode.mode[0]), 
365                                 mode2str(iocmd.u.mode.mode[1]));
366                 }
367         }
368         else
369                 usage();
370         exit(0);
371 }