~ubuntu-branches/ubuntu/hardy/silo/hardy-updates

« back to all changes in this revision

Viewing changes to second/disk.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabio M. Di Nitto
  • Date: 2007-10-25 09:28:08 UTC
  • mfrom: (15.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20071025092808-1yhj12t7s4zqsfu5
Tags: 1.4.13a+git20070930-1ubuntu1
* Merge from debian unstable, remaining changes:
  - Build with -fno-stack-protector.
  - Change silo.postinst to automatically update the boot block without
    invoking siloconfig and keep asking questions on upgrades.
  - Convert silo.conf to use /dev/disk/by-uuid.
  - Ubuntu maintainer foobar.
  - Fix debian/rules call to dh_installdocs.
  - Drop the requirement of gcc-4.1 and start using default gcc.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Disk functions
 
2
   
 
3
   Copyright (C) 1996 Pete A. Zaitcev
 
4
                 1996,1997 Jakub Jelinek
 
5
   
 
6
   This program is free software; you can redistribute it and/or modify
 
7
   it under the terms of the GNU General Public License as published by
 
8
   the Free Software Foundation; either version 2 of the License, or
 
9
   (at your option) any later version.
 
10
   
 
11
   This program is distributed in the hope that it will be useful,
 
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
   GNU General Public License for more details.
 
15
 
 
16
   You should have received a copy of the GNU General Public License
 
17
   along with this program; if not, write to the Free Software
 
18
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
 
19
   USA.  */
 
20
 
 
21
#include <silo.h>
 
22
#include <stringops.h>
 
23
 
 
24
static int net = 0;
 
25
static int floppy = 0;
 
26
static unsigned int flash = 0;
 
27
static int fd;
 
28
static unsigned long long seekp;
 
29
static char bootdevice[4096];
 
30
static char currentdevice[4096];
 
31
 
 
32
char *silo_disk_get_bootdevice(void)
 
33
{
 
34
        return bootdevice;
 
35
}
 
36
 
 
37
int silo_disk_open(char *device)
 
38
{
 
39
    strcpy (currentdevice, device);
 
40
    net = 0;
 
41
    floppy = 0;
 
42
    seekp = 0xffffffffffffffffULL;
 
43
    switch (prom_vers) {
 
44
    case PROM_V0:
 
45
        {
 
46
                char buffer[20], *p;
 
47
        
 
48
                if (strlen (device) < 20) {
 
49
                    /* v0 prom likes to paint in devopen parameter sometimes... */
 
50
                    strcpy (buffer, device);
 
51
                    p = buffer;
 
52
                } else p = device;
 
53
                fd = (*romvec->pv_v0devops.v0_devopen) (p);
 
54
                if (device[0] == 'f' && device[1] == 'd')
 
55
                    floppy = 1;
 
56
                else if ((device[0] == 'l' || device[0] == 'i') && device[1] == 'e')
 
57
                    net = 1;
 
58
        }
 
59
        break;
 
60
    case PROM_V2:
 
61
    case PROM_V3:
 
62
        {
 
63
                int node;
 
64
                char buffer[20];
 
65
        
 
66
                fd = (*romvec->pv_v2devops.v2_dev_open) (device);
 
67
                if ((unsigned)(fd + 1) > 1) {
 
68
                    node = (romvec->pv_v2devops.v2_inst2pkg) (fd);
 
69
                    prom_getstring (node, "device_type", buffer, 20);
 
70
                    if (!strcmp (buffer, "network"))
 
71
                        net = 1;
 
72
                }
 
73
        }
 
74
        break;
 
75
    case PROM_P1275:
 
76
        {
 
77
                int node;
 
78
                char buffer [20];
 
79
 
 
80
                fd = p1275_cmd ("open", 1, device);
 
81
                if ((unsigned)(fd + 1) > 1) {
 
82
                    node = p1275_cmd ("instance-to-package", 1, fd);
 
83
                    /*
 
84
                     * Don't use our argument due to devalias.
 
85
                     * Alas, flash has no device_type property.
 
86
                     */
 
87
                    prom_getstring (node, "name", buffer, 20);
 
88
                    if (!strcmp (buffer, "flash-memory")) {
 
89
                        int reg[3];
 
90
                        reg[0] = 0;  reg[1] = 0;  reg[2] = 0;
 
91
                        prom_getproperty (node, "reg", (char*)&reg[0], sizeof (reg));
 
92
                        flash = reg[1];
 
93
                    } else {
 
94
                        prom_getstring (node, "device_type", buffer, 20);
 
95
                        if (!strcmp (buffer, "network"))
 
96
                            net = 1;
 
97
                    }
 
98
                }
 
99
        }
 
100
        break;
 
101
    }
 
102
    if (fd == 0 || fd == -1) {
 
103
        printf ("\nFatal error: Couldn't open device %s\n", device);
 
104
        return -1;
 
105
    }
 
106
    return 0;
 
107
}
 
108
 
 
109
extern unsigned char boot_part, boot_parts[32];
 
110
extern unsigned char raid_dsk_number;
 
111
 
 
112
int get_boot_part(void)
 
113
{
 
114
    int ret = boot_part;
 
115
    if (raid_dsk_number > 32)
 
116
        printf("Internal error. RAID disk number should be at most 32.\n");
 
117
    else if (raid_dsk_number)
 
118
        ret = boot_parts[raid_dsk_number - 1];
 
119
    return ret;
 
120
}
 
121
 
 
122
int silo_diskinit(void)
 
123
{
 
124
    fd = 0;
 
125
    if (prom_vers == PROM_V0) {
 
126
        struct linux_arguments_v0 *ap = *romvec->pv_v0bootargs;
 
127
        char *s = bootdevice;
 
128
 
 
129
        *s++ = ap->boot_dev[0];
 
130
        *s++ = ap->boot_dev[1];
 
131
        *s++ = '(';
 
132
        *s++ = (ap->boot_dev_ctrl & 07) + '0';
 
133
        *s++ = ',';
 
134
        if ((*s = ap->boot_dev_unit / 10 + '0') != '0')
 
135
            s++;
 
136
        *s++ = ap->boot_dev_unit % 10 + '0';
 
137
        *s++ = ','; 
 
138
        *s++ = get_boot_part() + '0';
 
139
        *s++ = ')';
 
140
        *s = 0;
 
141
    } else {
 
142
        char *p;
 
143
        if (prom_vers == PROM_P1275)
 
144
            prom_getproperty (prom_chosen, "bootpath", bootdevice, sizeof(bootdevice));
 
145
        else
 
146
            strcpy (bootdevice, *romvec->pv_v2bootargs.bootpath);
 
147
        p = strchr (bootdevice, ':');
 
148
        if (!p) {
 
149
            p = strchr (bootdevice, 0); *p++ = ':'; *p++ = get_boot_part() + 'a'; *p = 0;
 
150
        } else if (p[1] >= 'a' && p[1] <= 'z' && !p[2])
 
151
            p[1] = get_boot_part() + 'a';
 
152
    }
 
153
    return silo_disk_open(bootdevice);
 
154
}
 
155
 
 
156
static void silo_disk_reopen(void)
 
157
{
 
158
    char c;
 
159
    
 
160
    c = *currentdevice;
 
161
    silo_disk_close();
 
162
    *currentdevice = c;
 
163
    silo_disk_open(currentdevice);
 
164
}
 
165
 
 
166
static unsigned int flash_ld(unsigned int offset)
 
167
{
 
168
    unsigned int retval;
 
169
 
 
170
    offset += flash;
 
171
    __asm__ __volatile__("lda [%2] %1, %0\n\t" :
 
172
        "=r" (retval) : "i" (0x20), "r" (offset));
 
173
    return retval;
 
174
}
 
175
 
 
176
int silo_disk_read(char *buff, int size, unsigned long long offset)
 
177
{
 
178
    if (!size)
 
179
        return 0;
 
180
    if (prom_vers == PROM_V0) {
 
181
        if (net)
 
182
            return (*romvec->pv_v0devops.v0_rdnetdev) (fd, size, buff);
 
183
        else {
 
184
            char buffer[512];
 
185
            int i = 0, j, k, rc = 0, ret = 0;
 
186
 
 
187
            if (offset & 0x1ff) {
 
188
                if (size > 512 - (offset & 0x1ff))
 
189
                    i = 512 - (offset & 0x1ff);
 
190
                else
 
191
                    i = size;
 
192
                for (j = 0; j < 5; j++) {
 
193
                        rc = (*romvec->pv_v0devops.v0_rdblkdev) (fd, 1, (unsigned)(offset >> 9), buffer);
 
194
                        if (rc) break;
 
195
                        silo_disk_reopen();
 
196
                }
 
197
                if (rc != 1)
 
198
                    return -1;
 
199
                memcpy (buff, buffer + (offset & 0x1ff), i);
 
200
                buff += i;
 
201
                size -= i;
 
202
                offset = ((offset + 512) & ~0x1ffULL);
 
203
                ret = i;
 
204
            }
 
205
            if (size >> 9) {
 
206
                for (j = 0; j < 5; j++) {
 
207
                        rc = (*romvec->pv_v0devops.v0_rdblkdev) (fd, size >> 9, (unsigned)(offset >> 9), buff);
 
208
                        if (rc) break;
 
209
                        silo_disk_reopen();
 
210
                }
 
211
                if (rc != (size >> 9)) {
 
212
                    /* Lets try if the floppy is not happy because the read size is too large for it */
 
213
                    for (k = 0; k < (size >> 9); k++) {
 
214
                        for (j = 0; j < 5; j++) {
 
215
                            rc = (*romvec->pv_v0devops.v0_rdblkdev) (fd, 1, (unsigned)(offset >> 9) + k, buff + (k << 9));
 
216
                            if (rc) break;
 
217
                            silo_disk_reopen();
 
218
                        }
 
219
                        if (rc != 1)
 
220
                            return -1;
 
221
                    }
 
222
                }
 
223
                i = (size & (~0x1ff));
 
224
                ret += i;
 
225
                buff += i;
 
226
                offset += i;
 
227
            }
 
228
            size &= 0x1ff;
 
229
            if (size) {
 
230
                for (j = 0; j < 5; j++) {
 
231
                        rc = (*romvec->pv_v0devops.v0_rdblkdev) (fd, 1, (unsigned)(offset >> 9), buffer);
 
232
                        if (rc) break;
 
233
                        silo_disk_reopen();
 
234
                }
 
235
                if (rc != 1)
 
236
                    return -1;
 
237
                memcpy (buff, buffer, size);
 
238
                ret += size;
 
239
            }
 
240
            return ret;
 
241
        }
 
242
    } else {
 
243
        int rc = 0;
 
244
 
 
245
        if (flash) {
 
246
            unsigned int word;
 
247
            int xlen;
 
248
            int count;
 
249
 
 
250
            if (offset >= 0x1000000) {  /* Not very precise but will work... */
 
251
                printf ("Reading beyond 16MB of flash, bad filesystem.\n");
 
252
                return -1;
 
253
            }
 
254
 
 
255
            /*
 
256
             * Right thing is to map stuff in, then do a copy.
 
257
             * We, however, are not sure that PROM does not leak mappings.
 
258
             * So, let's kludge data in with ASI_BYPASS.
 
259
             * Note that flash must be accessed with 32 bits loads.
 
260
             */
 
261
            offset += 1024;     /* XXX Offset of flash filesystem */
 
262
            count = 0;
 
263
 
 
264
            xlen = 4 - (offset & 3);
 
265
            if (xlen != 4) {
 
266
                word = flash_ld (offset & ~3);
 
267
                memcpy (buff, ((char *)&word) + (4 - xlen), xlen);
 
268
                buff += xlen;
 
269
                offset += xlen;
 
270
                count += xlen;
 
271
            }
 
272
 
 
273
            while (count + 4 <= size) {
 
274
                word = flash_ld (offset);
 
275
                memcpy (buff, (char *)&word, 4);
 
276
                buff += 4;
 
277
                offset += 4;
 
278
                count += 4;
 
279
            }
 
280
 
 
281
            xlen = size - count;
 
282
            if (xlen != 0) {
 
283
                word = flash_ld (offset);
 
284
                memcpy (buff, (char *)&word, xlen);
 
285
                buff += xlen;
 
286
                offset += xlen;
 
287
                count += xlen;
 
288
            }
 
289
 
 
290
            return count;
 
291
        }
 
292
 
 
293
        if (!net) {
 
294
            if (prom_vers != PROM_P1275) {
 
295
                    if (((romvec->pv_printrev >> 16) < 2 || 
 
296
                         ((romvec->pv_printrev >> 16) == 2 && (romvec->pv_printrev && 0xffff) < 6)) 
 
297
                        && offset >= 0x40000000) {
 
298
                        printf ("Buggy old PROMs don't allow reading past 1GB from start of the disk. Send complaints to SMCC\n");
 
299
                        return -1;
 
300
                    }
 
301
            }
 
302
            if (seekp != offset) {
 
303
                if (prom_vers == PROM_P1275) {
 
304
                        if ((rc = p1275_cmd ("seek", P1275_ARG_64B(2) | 3, fd, 0, offset)) == -1)
 
305
                            return -1;
 
306
                } else {
 
307
                        if ((*romvec->pv_v2devops.v2_dev_seek) (fd, (unsigned)(offset >> 32), (unsigned)offset) == -1)
 
308
                            return -1;
 
309
                }
 
310
                seekp = offset;
 
311
            }
 
312
        }
 
313
        if (prom_vers == PROM_P1275) {
 
314
                rc = p1275_cmd ("read", 3, fd, buff, size);
 
315
        } else {
 
316
                int i;
 
317
                for (i = 0; i < 2; i++) {
 
318
                    rc = (*romvec->pv_v2devops.v2_dev_read) (fd, buff, size);
 
319
                    if (rc == size) break;
 
320
                    silo_disk_reopen();
 
321
                    if ((*romvec->pv_v2devops.v2_dev_seek) (fd, (unsigned)(offset >> 32), (unsigned)offset) == -1)
 
322
                        return -1;
 
323
                }
 
324
                if (rc != size && size > 32768) {
 
325
                    int j, s = size;
 
326
                    silo_disk_reopen();
 
327
                    while (size) {
 
328
                        if (size < 32768) j = size; else j = 32768;
 
329
                        if (silo_disk_read(buff, j, offset) != j)
 
330
                            return -1;
 
331
                        size -= j;
 
332
                        offset += j;
 
333
                        buff += j;
 
334
                    }
 
335
                    return s;
 
336
                }
 
337
        }
 
338
        if (!net) {
 
339
            seekp += size;
 
340
            if (rc == size)
 
341
                return size;
 
342
        } else
 
343
            return rc;
 
344
    }
 
345
    return -1;
 
346
}
 
347
 
 
348
void silo_disk_close(void)
 
349
{
 
350
    if (*currentdevice) {
 
351
        switch (prom_vers) {
 
352
        case PROM_V0:
 
353
            (*romvec->pv_v0devops.v0_devclose) (fd); break;
 
354
        case PROM_V2:
 
355
        case PROM_V3:
 
356
            (*romvec->pv_v2devops.v2_dev_close) (fd); break;
 
357
        case PROM_P1275:
 
358
            p1275_cmd ("close", 1, fd); break;
 
359
        }
 
360
    }
 
361
    *currentdevice = 0;
 
362
}
 
363
 
 
364
int silo_disk_setdisk(char *device)
 
365
{
 
366
    if (!strcmp(currentdevice, device))
 
367
        return 0;
 
368
 
 
369
    silo_disk_close();
 
370
    return silo_disk_open(device);
 
371
}
 
372
 
 
373
/*
 
374
 * XXX Good thing would be to have an argument, perhaps some device name.
 
375
 * XXX Other option is to make silo_disk_open() to return partitionable flag.
 
376
 * XXX Retrofit floppy ((flash == 0) && (floppy == 0) && (net == 0));
 
377
 */
 
378
int silo_disk_partitionable(void)
 
379
{
 
380
    return (flash == 0);
 
381
}