]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/atacontrol/atacontrol.c
Simplify some things to use libufs-provided functionality here, such as the
[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("serial number         %.20s\n", parm->serial);
123         printf("firmware revision     %.8s\n", parm->revision);
124
125         printf("cylinders             %d\n", parm->cylinders);
126         printf("heads                 %d\n", parm->heads);
127         printf("sectors/track         %d\n", parm->sectors);    
128         
129         printf("lba%ssupported         ", parm->support_lba ? " " : " not ");
130         if (lbasize)
131                 printf("%d sectors\n", lbasize);
132         else
133                 printf("\n");
134
135         printf("lba48%ssupported         ",
136                 parm->support.address48 ? " " : " not ");
137         if (lbasize48)
138                 printf("%lld sectors\n", lbasize48);    
139         else
140                 printf("\n");
141
142         printf("dma%ssupported\n", parm->support_dma ? " " : " not");
143
144         printf("overlap%ssupported\n", parm->support_queueing ? " " : " not ");
145   
146         printf("\nFeature                      "
147                 "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      "
184                 "%d/%02X        %d/%02X\n",
185                 parm->support.auto_acoustic ? "yes" : "no",
186                 parm->enabled.auto_acoustic ? "yes" : "no",
187                 parm->current_acoustic, parm->current_acoustic,
188                 parm->vendor_acoustic, parm->vendor_acoustic);  
189 }
190
191 int
192 ata_cap_print(int fd, int channel, int device)
193 {
194         struct ata_cmd iocmd;
195
196         bzero(&iocmd, sizeof(struct ata_cmd));
197
198         iocmd.channel = channel;
199         iocmd.device = -1;
200         iocmd.cmd = ATAGPARM;
201
202         if (ioctl(fd, IOCATA, &iocmd) < 0)
203                 return errno;
204
205         printf("ATA channel %d, %s", channel, device==0 ? "Master" : "Slave");
206
207         if (iocmd.u.param.type[device]) {
208                 printf(", device %s:\n", iocmd.u.param.name[device]);
209                 cap_print(&iocmd.u.param.params[device]);
210         }
211         else
212                 printf(": no device present\n");
213         return 0;
214 }
215
216 int
217 info_print(int fd, int channel, int prchan)
218 {
219         struct ata_cmd iocmd;
220
221         bzero(&iocmd, sizeof(struct ata_cmd));
222         iocmd.channel = channel;
223         iocmd.device = -1;
224         iocmd.cmd = ATAGPARM;
225         if (ioctl(fd, IOCATA, &iocmd) < 0)
226                 return errno;
227         if (prchan)
228                 printf("ATA channel %d:\n", channel);
229         printf("%sMaster: ", prchan ? "    " : "");
230         if (iocmd.u.param.type[0]) {
231                 printf("%4.4s ", iocmd.u.param.name[0]);
232                 param_print(&iocmd.u.param.params[0]);
233         }
234         else
235                 printf("     no device present\n");
236         printf("%sSlave:  ", prchan ? "    " : "");
237         if (iocmd.u.param.type[1]) {
238                 printf("%4.4s ", iocmd.u.param.name[1]);
239                 param_print(&iocmd.u.param.params[1]);
240         }
241         else
242                 printf("     no device present\n");
243         return 0;
244 }
245
246 int
247 main(int argc, char **argv)
248 {
249         struct ata_cmd iocmd;
250         int fd;
251
252         if ((fd = open("/dev/ata", O_RDWR)) < 0)
253                 err(1, "control device not found");
254
255         if (argc < 2)
256                 usage();
257
258         bzero(&iocmd, sizeof(struct ata_cmd));
259
260         if (argc > 2 && strcmp(argv[1], "create")) {
261                 int chan;
262
263                 if (!strcmp(argv[1], "delete") ||
264                     !strcmp(argv[1], "status") ||
265                     !strcmp(argv[1], "rebuild")) {
266                         if (!(sscanf(argv[2], "%d", &chan) == 1 ||
267                               sscanf(argv[2], "ar%d", &chan) == 1))
268                                 usage();
269                 }
270                 else {
271                         if (!(sscanf(argv[2], "%d", &chan) == 1 ||
272                               sscanf(argv[2], "ata%d", &chan) == 1))
273                                 usage();
274                 }
275                 iocmd.channel = chan;
276         }
277
278         if (!strcmp(argv[1], "list") && argc == 2) {
279                 int unit = 0;
280
281                 while (info_print(fd, unit++, 1) != ENXIO);
282         }
283         else if (!strcmp(argv[1], "info") && argc == 3) {
284                 info_print(fd, iocmd.channel, 0);
285         }
286         else if (!strcmp(argv[1], "cap") && argc == 4) {
287                 ata_cap_print(fd, iocmd.channel, atoi(argv[3]));
288         }
289         else if (!strcmp(argv[1], "enclosure") && argc == 4) {
290                 iocmd.device = atoi(argv[3]);
291                 iocmd.cmd = ATAENCSTAT;
292                 if (ioctl(fd, IOCATA, &iocmd) < 0)
293                         err(1, "ioctl(ATAENCSTAT)");
294                 printf("fan RPM: %d temp: %.1f 5V: %.2f 12V: %.2f\n",
295                         iocmd.u.enclosure.fan,
296                         (double)iocmd.u.enclosure.temp / 10,
297                         (double)iocmd.u.enclosure.v05 / 1000,
298                         (double)iocmd.u.enclosure.v12 / 1000);
299         }
300         else if (!strcmp(argv[1], "detach") && argc == 3) {
301                 iocmd.cmd = ATADETACH;
302                 if (ioctl(fd, IOCATA, &iocmd) < 0)
303                         err(1, "ioctl(ATADETACH)");
304         }
305         else if (!strcmp(argv[1], "attach") && argc == 3) {
306                 iocmd.cmd = ATAATTACH;
307                 if (ioctl(fd, IOCATA, &iocmd) < 0)
308                         err(1, "ioctl(ATAATTACH)");
309                 info_print(fd, iocmd.channel, 0);
310         }
311         else if (!strcmp(argv[1], "reinit") && argc == 3) {
312                 iocmd.cmd = ATAREINIT;
313                 if (ioctl(fd, IOCATA, &iocmd) < 0)
314                         warn("ioctl(ATAREINIT)");
315                 info_print(fd, iocmd.channel, 0);
316         }
317         else if (!strcmp(argv[1], "create")) {
318                 int disk, dev, offset;
319
320                 iocmd.cmd = ATARAIDCREATE;
321                 if (!strcmp(argv[2], "RAID0") || !strcmp(argv[2], "stripe"))
322                         iocmd.u.raid_setup.type = 1;
323                 if (!strcmp(argv[2], "RAID1") || !strcmp(argv[2],"mirror"))
324                         iocmd.u.raid_setup.type = 2;
325                 if (!strcmp(argv[2], "RAID0+1"))
326                         iocmd.u.raid_setup.type = 3;
327                 if (!strcmp(argv[2], "SPAN") || !strcmp(argv[2], "JBOD"))
328                         iocmd.u.raid_setup.type = 4;
329                 if (!iocmd.u.raid_setup.type)
330                      usage();
331                 
332                 if (iocmd.u.raid_setup.type & 1) {
333                         if (!sscanf(argv[3], "%d",
334                                     &iocmd.u.raid_setup.interleave) == 1)
335                                 usage();
336                         offset = 4;
337                 }
338                 else
339                         offset = 3;
340                 
341                 for (disk = 0; disk < 16 && (offset + disk) < argc; disk++) {
342                         if (!(sscanf(argv[offset + disk], "%d", &dev) == 1 ||
343                               sscanf(argv[offset + disk], "ad%d", &dev) == 1))
344                                 usage();
345                         iocmd.u.raid_setup.disks[disk] = dev;
346                 }
347                 iocmd.u.raid_setup.total_disks = disk;
348                 if (ioctl(fd, IOCATA, &iocmd) < 0)
349                         err(1, "ioctl(ATARAIDCREATE)");
350                 else
351                         printf("ar%d created\n", iocmd.u.raid_setup.unit);
352         }
353         else if (!strcmp(argv[1], "delete") && argc == 3) {
354                 iocmd.cmd = ATARAIDDELETE;
355                 if (ioctl(fd, IOCATA, &iocmd) < 0)
356                         warn("ioctl(ATARAIDDELETE)");
357         }
358         else if (!strcmp(argv[1], "rebuild") && argc == 3) {
359                 iocmd.cmd = ATARAIDREBUILD;
360                 if (ioctl(fd, IOCATA, &iocmd) < 0)
361                         warn("ioctl(ATARAIDREBUILD)");
362         }
363         else if (!strcmp(argv[1], "status") && argc == 3) {
364                 int i;
365
366                 iocmd.cmd = ATARAIDSTATUS;
367                 if (ioctl(fd, IOCATA, &iocmd) < 0)
368                         err(1, "ioctl(ATARAIDSTATUS)");
369                 printf("ar%d: ATA ", iocmd.channel);
370                 switch (iocmd.u.raid_status.type) {
371                 case AR_RAID0:
372                         printf("RAID0");
373                         break;
374                 case AR_RAID1:
375                         printf("RAID1");
376                         break;
377                 case AR_RAID0 | AR_RAID1:
378                         printf("RAID0+1");
379                         break;
380                 case AR_SPAN:
381                         printf("SPAN");
382                         break;
383                 }
384                 printf(" subdisks: ");
385                 for (i = 0; i < iocmd.u.raid_status.total_disks; i++) {
386                         if (iocmd.u.raid_status.disks[i] >= 0)
387                                 printf("ad%d ", iocmd.u.raid_status.disks[i]);
388                         else
389                                 printf("DOWN ");
390                 }
391                 printf("status: ");
392                 switch (iocmd.u.raid_status.status) {
393                 case AR_READY:
394                         printf("READY\n");
395                         break;
396                 case AR_READY | AR_DEGRADED:
397                         printf("DEGRADED\n");
398                         break;
399                 case AR_READY | AR_DEGRADED | AR_REBUILDING:
400                         printf("REBUILDING %d%% completed\n",
401                                 iocmd.u.raid_status.progress);
402                         break;
403                 default:
404                         printf("BROKEN\n");
405                 }
406         }
407         else if (!strcmp(argv[1], "mode") && (argc == 3 || argc == 5)) {
408                 if (argc == 5) {
409                         iocmd.cmd = ATASMODE;
410                         iocmd.device = -1;
411                         iocmd.u.mode.mode[0] = str2mode(argv[3]);
412                         iocmd.u.mode.mode[1] = str2mode(argv[4]);
413                         if (ioctl(fd, IOCATA, &iocmd) < 0)
414                                 warn("ioctl(ATASMODE)");
415                 }
416                 if (argc == 3 || argc == 5) {
417                         iocmd.cmd = ATAGMODE;
418                         iocmd.device = -1;
419                         if (ioctl(fd, IOCATA, &iocmd) < 0)
420                                 err(1, "ioctl(ATAGMODE)");
421                         printf("Master = %s \nSlave  = %s\n",
422                                 mode2str(iocmd.u.mode.mode[0]), 
423                                 mode2str(iocmd.u.mode.mode[1]));
424                 }
425         }
426         else
427                 usage();
428         exit(0);
429 }