• Home
  • History
  • Annotate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/ap/gpl/hdparm-9.43/

Lines Matching defs:*

2  * Copyright (c) EMC Corporation 2008
3 * Copyright (c) Mark Lord 2008
5 * You may use/distribute this freely, under the terms of either
6 * (your choice) the GNU General Public License version 2,
7 * or a BSD style license.
9 #include <unistd.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <fcntl.h>
14 #include <errno.h>
15 #include <sys/ioctl.h>
16 #include <sys/stat.h>
17 #include <linux/types.h>
18 #include <linux/fs.h>
19 #include <sys/mman.h>
21 #include "hdparm.h"
22 #include "sgio.h"
24 /* glibc-2.2 / linux-2.4 don't have MAP_POPULATE */
25 #ifndef MAP_POPULATE
26 #define MAP_POPULATE 0
27 #endif
29 extern int verbose;
31 /* Download a firmware segment to the drive */
32 static int send_firmware (int fd, unsigned int xfer_mode, unsigned int offset,
33 const void *data, unsigned int bytecount)
35 int err = 0;
36 struct hdio_taskfile *r;
37 unsigned int blockcount = bytecount / 512;
38 unsigned int timeout_secs = 20;
39 __u64 lba;
41 lba = ((offset / 512) << 8) | ((blockcount >> 8) & 0xff);
42 r = malloc(sizeof(struct hdio_taskfile) + bytecount);
43 if (!r) {
44 if (xfer_mode == 3) { putchar('\n'); fflush(stdout); }
45 err = errno;
46 perror("malloc()");
47 return err;
49 init_hdio_taskfile(r, ATA_OP_DOWNLOAD_MICROCODE, RW_WRITE, LBA28_OK, lba, blockcount & 0xff, bytecount);
51 r->lob.feat = xfer_mode;
52 r->oflags.lob.feat = 1;
53 r->iflags.lob.nsect = 1;
55 if (data && bytecount)
56 memcpy(r->data, data, bytecount);
58 if (do_taskfile_cmd(fd, r, timeout_secs)) {
59 err = errno;
60 if (xfer_mode == 3) { putchar('\n'); fflush(stdout); }
61 perror("FAILED");
62 } else {
63 if (xfer_mode == 3) {
64 if (!verbose) { putchar('.'); fflush(stdout); }
65 switch (r->lob.nsect) {
66 case 1: // drive wants more data
67 case 2: // drive thinks it is all done
68 err = - r->lob.nsect;
69 break;
70 default: // no status indication
71 err = 0;
72 break;
76 free(r);
77 return err;
80 int fwdownload (int fd, __u16 *id, const char *fwpath, int xfer_mode)
82 int fwfd, err = 0;
83 struct stat st;
84 const char *fw = NULL;
85 const int max_bytes = 0xffff * 512;
86 int xfer_min = 1, xfer_max = 0xffff, xfer_size;
87 ssize_t offset;
89 if ((fwfd = open(fwpath, O_RDONLY)) == -1 || fstat(fwfd, &st) == -1) {
90 err = errno;
91 perror(fwpath);
92 return err;
95 if (!S_ISREG(st.st_mode)) {
96 fprintf(stderr, "%s: not a regular file\n", fwpath);
97 err = EINVAL;
98 goto done;
101 if (st.st_size > max_bytes) {
102 fprintf(stderr, "%s: file size too large, max=%u bytes\n", fwpath, max_bytes);
103 err = EINVAL;
104 goto done;
107 if (st.st_size == 0 || st.st_size % 512) {
108 fprintf(stderr, "%s: file size (%llu) not a multiple of 512\n",
109 fwpath, (unsigned long long) st.st_size);
110 err = EINVAL;
111 goto done;
114 if (verbose)
115 printf("%s: %llu bytes\n", fwpath, (unsigned long long)st.st_size);
117 fw = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED|MAP_POPULATE|MAP_LOCKED, fwfd, 0);
118 if (fw == MAP_FAILED) {
119 err = errno;
120 perror(fwpath);
121 goto done;
124 /* Check drive for fwdownload support */
125 if (!((id[83] & 1) && (id[86] & 1))) {
126 fprintf(stderr, "DOWNLOAD_MICROCODE: not supported by device\n");
127 err = ENOTSUP;
128 goto done;
130 if (xfer_mode == 0) {
131 if ((id[119] & 0x10) && (id[120] & 0x10))
132 xfer_mode = 3;
133 else
134 xfer_mode = 7;
137 if (xfer_mode == 3 || xfer_mode == 30) {
138 /* the newer, segmented transfer mode */
139 xfer_min = id[234];
140 if (xfer_min == 0 || xfer_min == 0xffff)
141 xfer_min = 1;
142 xfer_max = id[235];
143 if (xfer_max == 0 || xfer_max == 0xffff)
144 xfer_max = xfer_min;
147 if (xfer_mode == 30) { // mode-3, using xfer_max
148 xfer_mode = 3;
149 xfer_size = xfer_max;
150 } else if (xfer_mode == 3) {
151 xfer_size = xfer_min;
152 } else {
153 xfer_size = st.st_size / 512;
154 if (xfer_size > 0xffff) {
155 fprintf(stderr, "Error: file size (%llu) too large for mode7 transfers\n", (__u64)st.st_size);
156 err = EINVAL;
157 goto done;
161 xfer_size *= 512; /* bytecount */
163 fprintf(stderr, "%s: xfer_mode=%d min=%u max=%u size=%u\n",
164 __func__, xfer_mode, xfer_min, xfer_max, xfer_size);
166 /* Perform the fwdownload, in segments if appropriate */
167 for (offset = 0; !err && offset < st.st_size;) {
168 if ((offset + xfer_size) >= st.st_size)
169 xfer_size = st.st_size - offset;
170 err = send_firmware(fd, xfer_mode, offset, fw + offset, xfer_size);
171 offset += xfer_size;
173 if (err == -2) { // drive has had enough?
174 if (offset >= st.st_size) { // transfer complete?
175 err = 0;
176 } else {
177 if (xfer_mode == 3) { putchar('\n'); fflush(stdout); }
178 fprintf(stderr, "Error: drive completed transfer at %llu/%llu bytes\n",
179 (unsigned long long)offset, (unsigned long long)st.st_size);
180 err = EIO;
182 } else if (err == -1) {
183 if (offset >= st.st_size) { // no more data?
184 #if 0
185 /* Try sending an empty segment before complaining */
186 err = send_firmware(fd, xfer_mode, offset, NULL, 0);
187 if (err == 0 || err == -2) {
188 err = 0;
189 break;
191 #endif
192 if (xfer_mode == 3) { putchar('\n'); fflush(stdout); }
193 fprintf(stderr, "Error: drive expects more data than provided,\n");
194 fprintf(stderr, "but the transfer may have worked regardless.\n");
195 err = EIO;
196 } else {
197 err = 0;
201 if (!err)
202 printf(" Done.\n");
203 done:
204 munlock(fw, st.st_size);
205 close (fwfd);
206 return err;