1 /* $NetBSD: wd.c,v 1.9 2008/03/02 06:17:41 tsutsui Exp $ */
4 * Copyright (c) 2003 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/types.h>
33 #include <sys/stdint.h>
35 #include <lib/libsa/stand.h>
36 #include <lib/libkern/libkern.h>
38 #include <machine/param.h>
39 #include <machine/stdarg.h>
40 #include <dev/raidframe/raidframevar.h> /* For RF_PROTECTED_SECTORS */
45 static int wd_get_params(struct wd_softc
*wd
);
46 static int wdgetdisklabel(struct wd_softc
*wd
);
47 static void wdgetdefaultlabel(struct wd_softc
*wd
, struct disklabel
*lp
);
50 * Get drive parameters through 'device identify' command.
53 wd_get_params(struct wd_softc
*wd
)
56 uint8_t buf
[DEV_BSIZE
];
58 if ((error
= wdc_exec_identify(wd
, buf
)) != 0)
61 wd
->sc_params
= *(struct ataparams
*)buf
;
63 /* 48-bit LBA addressing */
64 if ((wd
->sc_params
.atap_cmd2_en
& ATA_CMD2_LBA48
) != 0) {
65 DPRINTF(("Drive supports LBA48.\n"));
66 #if defined(_ENABLE_LBA48)
67 wd
->sc_flags
|= WDF_LBA48
;
71 /* Prior to ATA-4, LBA was optional. */
72 if ((wd
->sc_params
.atap_capabilities1
& WDC_CAP_LBA
) != 0) {
73 DPRINTF(("Drive supports LBA.\n"));
74 wd
->sc_flags
|= WDF_LBA
;
81 * Initialize disk label to the default value.
84 wdgetdefaultlabel(struct wd_softc
*wd
, struct disklabel
*lp
)
87 memset(lp
, 0, sizeof(struct disklabel
));
89 lp
->d_secsize
= DEV_BSIZE
;
90 lp
->d_ntracks
= wd
->sc_params
.atap_heads
;
91 lp
->d_nsectors
= wd
->sc_params
.atap_sectors
;
92 lp
->d_ncylinders
= wd
->sc_params
.atap_cylinders
;
93 lp
->d_secpercyl
= lp
->d_ntracks
* lp
->d_nsectors
;
95 if (strcmp(wd
->sc_params
.atap_model
, "ST506") == 0)
96 lp
->d_type
= DTYPE_ST506
;
98 lp
->d_type
= DTYPE_ESDI
;
100 strncpy(lp
->d_typename
, wd
->sc_params
.atap_model
, 16);
101 strncpy(lp
->d_packname
, "fictitious", 16);
102 if (wd
->sc_capacity
> UINT32_MAX
)
103 lp
->d_secperunit
= UINT32_MAX
;
105 lp
->d_secperunit
= wd
->sc_capacity
;
107 lp
->d_interleave
= 1;
110 lp
->d_partitions
[RAW_PART
].p_offset
= 0;
111 lp
->d_partitions
[RAW_PART
].p_size
=
112 lp
->d_secperunit
* (lp
->d_secsize
/ DEV_BSIZE
);
113 lp
->d_partitions
[RAW_PART
].p_fstype
= FS_UNUSED
;
114 lp
->d_npartitions
= MAXPARTITIONS
; /* RAW_PART + 1 ??? */
116 lp
->d_magic
= DISKMAGIC
;
117 lp
->d_magic2
= DISKMAGIC
;
118 lp
->d_checksum
= dkcksum(lp
);
122 * Read disk label from the device.
125 wdgetdisklabel(struct wd_softc
*wd
)
130 struct disklabel
*lp
;
131 uint8_t buf
[DEV_BSIZE
];
133 wdgetdefaultlabel(wd
, &wd
->sc_label
);
136 * Find NetBSD Partition in DOS partition table.
139 if (wdstrategy(wd
, F_READ
, MBR_BBSECTOR
, DEV_BSIZE
, buf
, &rsize
))
142 if (*(uint16_t *)&buf
[MBR_MAGIC_OFFSET
] == MBR_MAGIC
) {
144 struct mbr_partition
*mp
;
147 * Lookup NetBSD slice. If there is none, go ahead
148 * and try to read the disklabel off sector #0.
150 mp
= (struct mbr_partition
*)&buf
[MBR_PART_OFFSET
];
151 for (i
= 0; i
< MBR_PART_COUNT
; i
++) {
152 if (mp
[i
].mbrp_type
== MBR_PTYPE_NETBSD
) {
153 sector
= mp
[i
].mbrp_start
;
159 if (wdstrategy(wd
, F_READ
, sector
+ LABELSECTOR
, DEV_BSIZE
,
163 if ((msg
= getdisklabel(buf
+ LABELOFFSET
, &wd
->sc_label
)))
164 printf("wd%d: getdisklabel: %s\n", wd
->sc_unit
, msg
);
168 /* check partition */
169 if ((wd
->sc_part
>= lp
->d_npartitions
) ||
170 (lp
->d_partitions
[wd
->sc_part
].p_fstype
== FS_UNUSED
)) {
171 DPRINTF(("illegal partition\n"));
175 DPRINTF(("label info: d_secsize %d, d_nsectors %d, d_ncylinders %d,"
176 "d_ntracks %d, d_secpercyl %d\n",
177 wd
->sc_label
.d_secsize
,
178 wd
->sc_label
.d_nsectors
,
179 wd
->sc_label
.d_ncylinders
,
180 wd
->sc_label
.d_ntracks
,
181 wd
->sc_label
.d_secpercyl
));
187 * Open device (read drive parameters and disklabel)
190 wdopen(struct open_file
*f
, ...)
198 unit
= va_arg(ap
, u_int
);
199 part
= va_arg(ap
, u_int
);
202 DPRINTF(("wdopen: %d:%d\n", unit
, part
));
204 wd
= alloc(sizeof(struct wd_softc
));
208 memset(wd
, 0, sizeof(struct wd_softc
));
210 if (wdc_init(wd
, &unit
) != 0)
216 if ((error
= wd_get_params(wd
)) != 0)
219 if ((error
= wdgetdisklabel(wd
)) != 0)
230 wdclose(struct open_file
*f
)
240 wdstrategy(void *f
, int rw
, daddr_t dblk
, size_t size
, void *p
, size_t *rsize
)
245 struct partition
*pp
;
256 pp
= &wd
->sc_label
.d_partitions
[wd
->sc_part
];
258 nsect
= howmany(size
, wd
->sc_label
.d_secsize
);
259 blkno
= dblk
+ pp
->p_offset
;
260 if (pp
->p_fstype
== FS_RAID
)
261 blkno
+= RF_PROTECTED_SECTORS
;
263 for (i
= 0; i
< nsect
; i
++, blkno
++) {
266 if ((error
= wdc_exec_read(wd
, WDCC_READ
, blkno
, buf
)) != 0)
269 buf
+= wd
->sc_label
.d_secsize
;