]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/atacontrol/atacontrol.c
This commit was generated by cvs2svn to compensate for changes in r99060,
[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_UDMA6: return "UDMA133";
54         case ATA_DMA: return "BIOSDMA";
55         default: return "???";
56         }
57 }
58
59 int
60 str2mode(char *str)
61 {
62         if (!strcasecmp(str, "BIOSPIO")) return ATA_PIO;
63         if (!strcasecmp(str, "PIO0")) return ATA_PIO0;
64         if (!strcasecmp(str, "PIO1")) return ATA_PIO1;
65         if (!strcasecmp(str, "PIO2")) return ATA_PIO2;
66         if (!strcasecmp(str, "PIO3")) return ATA_PIO3;
67         if (!strcasecmp(str, "PIO4")) return ATA_PIO4;
68         if (!strcasecmp(str, "WDMA2")) return ATA_WDMA2;
69         if (!strcasecmp(str, "UDMA2")) return ATA_UDMA2;
70         if (!strcasecmp(str, "UDMA33")) return ATA_UDMA2;
71         if (!strcasecmp(str, "UDMA4")) return ATA_UDMA4;
72         if (!strcasecmp(str, "UDMA66")) return ATA_UDMA4;
73         if (!strcasecmp(str, "UDMA5")) return ATA_UDMA5;
74         if (!strcasecmp(str, "UDMA100")) return ATA_UDMA5;
75         if (!strcasecmp(str, "UDMA6")) return ATA_UDMA6;
76         if (!strcasecmp(str, "UDMA133")) return ATA_UDMA6;
77         if (!strcasecmp(str, "BIOSDMA")) return ATA_DMA;
78         return -1;
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         u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
112                                 ((u_int32_t)parm->lba_size_2 << 16);
113
114         u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) |
115                                 ((u_int64_t)parm->lba_size48_2 << 16) |
116                                 ((u_int64_t)parm->lba_size48_3 << 32) |
117                                 ((u_int64_t)parm->lba_size48_4 << 48);
118  
119         printf("\n");
120         printf("ATA/ATAPI revision    %d\n", version(parm->version_major));
121         printf("device model          %.40s\n", parm->model);
122         printf("firmware revision     %.8s\n", parm->revision);
123
124         printf("cylinders             %d\n", parm->cylinders);
125         printf("heads                 %d\n", parm->heads);
126         printf("sectors/track         %d\n", parm->sectors);    
127         
128         printf("lba%ssupported         ", parm->support_lba ? " " : " not ");
129         if (lbasize)
130                 printf("%d sectors\n", lbasize);
131         else
132                 printf("\n");
133
134         printf("lba48%ssupported         ",
135                 parm->support.address48 ? " " : " not ");
136         if (lbasize48)
137                 printf("%lld sectors\n", lbasize48);    
138         else
139                 printf("\n");
140
141         printf("dma%ssupported\n", parm->support_dma ? " " : " not");
142
143         printf("overlap%ssupported\n", parm->support_queueing ? " " : " not ");
144   
145         printf("\nFeature                      "
146                 "Support  Enable    Value   Vendor\n");
147
148         printf("write cache                    %s       %s\n",
149                 parm->support.write_cache ? "yes" : "no",
150                 parm->enabled.write_cache ? "yes" : "no");      
151
152         printf("read ahead                     %s       %s\n",
153                 parm->support.look_ahead ? "yes" : "no",
154                 parm->enabled.look_ahead ? "yes" : "no");       
155
156         printf("dma queued                     %s       %s      %d/%02X\n",
157                 parm->support.queued ? "yes" : "no",
158                 parm->enabled.queued ? "yes" : "no",
159                 parm->queuelen, parm->queuelen);        
160
161         printf("SMART                          %s       %s\n",
162                 parm->support.smart ? "yes" : "no",
163                 parm->enabled.smart ? "yes" : "no");
164
165         printf("microcode download             %s       %s\n",
166                 parm->support.microcode ? "yes" : "no",
167                 parm->enabled.microcode ? "yes" : "no");        
168
169         printf("security                       %s       %s\n",
170                 parm->support.smart ? "yes" : "no",
171                 parm->enabled.smart ? "yes" : "no");    
172
173         printf("power management               %s       %s\n",
174                 parm->support.power_mngt ? "yes" : "no",
175                 parm->enabled.power_mngt ? "yes" : "no");       
176
177         printf("advanced power management      %s       %s      %d/%02X\n",
178                 parm->support.apm ? "yes" : "no",
179                 parm->enabled.apm ? "yes" : "no",
180                 parm->apm_value, parm->apm_value);
181
182         printf("automatic acoustic management  %s       %s      "
183                 "%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 }