| @@ -1,1830 +1,1833 @@ | | | @@ -1,1830 +1,1833 @@ |
1 | /* $NetBSD: wd.c,v 1.386 2011/02/10 05:07:46 enami Exp $ */ | | 1 | /* $NetBSD: wd.c,v 1.387 2011/07/30 04:42:03 jakllsch Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved. | | 4 | * Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved. |
5 | * | | 5 | * |
6 | * Redistribution and use in source and binary forms, with or without | | 6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions | | 7 | * modification, are permitted provided that the following conditions |
8 | * are met: | | 8 | * are met: |
9 | * 1. Redistributions of source code must retain the above copyright | | 9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. | | 10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright | | 11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the | | 12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. | | 13 | * documentation and/or other materials provided with the distribution. |
14 | * | | 14 | * |
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | | 19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | | 20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | | 21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | | 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
25 | */ | | 25 | */ |
26 | | | 26 | |
27 | /*- | | 27 | /*- |
28 | * Copyright (c) 1998, 2003, 2004 The NetBSD Foundation, Inc. | | 28 | * Copyright (c) 1998, 2003, 2004 The NetBSD Foundation, Inc. |
29 | * All rights reserved. | | 29 | * All rights reserved. |
30 | * | | 30 | * |
31 | * This code is derived from software contributed to The NetBSD Foundation | | 31 | * This code is derived from software contributed to The NetBSD Foundation |
32 | * by Charles M. Hannum and by Onno van der Linden. | | 32 | * by Charles M. Hannum and by Onno van der Linden. |
33 | * | | 33 | * |
34 | * Redistribution and use in source and binary forms, with or without | | 34 | * Redistribution and use in source and binary forms, with or without |
35 | * modification, are permitted provided that the following conditions | | 35 | * modification, are permitted provided that the following conditions |
36 | * are met: | | 36 | * are met: |
37 | * 1. Redistributions of source code must retain the above copyright | | 37 | * 1. Redistributions of source code must retain the above copyright |
38 | * notice, this list of conditions and the following disclaimer. | | 38 | * notice, this list of conditions and the following disclaimer. |
39 | * 2. Redistributions in binary form must reproduce the above copyright | | 39 | * 2. Redistributions in binary form must reproduce the above copyright |
40 | * notice, this list of conditions and the following disclaimer in the | | 40 | * notice, this list of conditions and the following disclaimer in the |
41 | * documentation and/or other materials provided with the distribution. | | 41 | * documentation and/or other materials provided with the distribution. |
42 | * | | 42 | * |
43 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 43 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
44 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 44 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
45 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 45 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
46 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 46 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
47 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 47 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
48 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 48 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
49 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 49 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
50 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 50 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
51 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 51 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
52 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 52 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
53 | * POSSIBILITY OF SUCH DAMAGE. | | 53 | * POSSIBILITY OF SUCH DAMAGE. |
54 | */ | | 54 | */ |
55 | | | 55 | |
56 | #include <sys/cdefs.h> | | 56 | #include <sys/cdefs.h> |
57 | __KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.386 2011/02/10 05:07:46 enami Exp $"); | | 57 | __KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.387 2011/07/30 04:42:03 jakllsch Exp $"); |
58 | | | 58 | |
59 | #include "opt_ata.h" | | 59 | #include "opt_ata.h" |
60 | | | 60 | |
61 | #include "rnd.h" | | 61 | #include "rnd.h" |
62 | | | 62 | |
63 | #include <sys/param.h> | | 63 | #include <sys/param.h> |
64 | #include <sys/systm.h> | | 64 | #include <sys/systm.h> |
65 | #include <sys/kernel.h> | | 65 | #include <sys/kernel.h> |
66 | #include <sys/conf.h> | | 66 | #include <sys/conf.h> |
67 | #include <sys/file.h> | | 67 | #include <sys/file.h> |
68 | #include <sys/stat.h> | | 68 | #include <sys/stat.h> |
69 | #include <sys/ioctl.h> | | 69 | #include <sys/ioctl.h> |
70 | #include <sys/buf.h> | | 70 | #include <sys/buf.h> |
71 | #include <sys/bufq.h> | | 71 | #include <sys/bufq.h> |
72 | #include <sys/uio.h> | | 72 | #include <sys/uio.h> |
73 | #include <sys/malloc.h> | | 73 | #include <sys/malloc.h> |
74 | #include <sys/device.h> | | 74 | #include <sys/device.h> |
75 | #include <sys/disklabel.h> | | 75 | #include <sys/disklabel.h> |
76 | #include <sys/disk.h> | | 76 | #include <sys/disk.h> |
77 | #include <sys/syslog.h> | | 77 | #include <sys/syslog.h> |
78 | #include <sys/proc.h> | | 78 | #include <sys/proc.h> |
79 | #include <sys/reboot.h> | | 79 | #include <sys/reboot.h> |
80 | #include <sys/vnode.h> | | 80 | #include <sys/vnode.h> |
81 | #if NRND > 0 | | 81 | #if NRND > 0 |
82 | #include <sys/rnd.h> | | 82 | #include <sys/rnd.h> |
83 | #endif | | 83 | #endif |
84 | | | 84 | |
85 | #include <sys/intr.h> | | 85 | #include <sys/intr.h> |
86 | #include <sys/bus.h> | | 86 | #include <sys/bus.h> |
87 | | | 87 | |
88 | #include <dev/ata/atareg.h> | | 88 | #include <dev/ata/atareg.h> |
89 | #include <dev/ata/atavar.h> | | 89 | #include <dev/ata/atavar.h> |
90 | #include <dev/ata/wdvar.h> | | 90 | #include <dev/ata/wdvar.h> |
91 | #include <dev/ic/wdcreg.h> | | 91 | #include <dev/ic/wdcreg.h> |
92 | #include <sys/ataio.h> | | 92 | #include <sys/ataio.h> |
93 | #include "locators.h" | | 93 | #include "locators.h" |
94 | | | 94 | |
95 | #include <prop/proplib.h> | | 95 | #include <prop/proplib.h> |
96 | | | 96 | |
97 | #define WDIORETRIES_SINGLE 4 /* number of retries before single-sector */ | | 97 | #define WDIORETRIES_SINGLE 4 /* number of retries before single-sector */ |
98 | #define WDIORETRIES 5 /* number of retries before giving up */ | | 98 | #define WDIORETRIES 5 /* number of retries before giving up */ |
99 | #define RECOVERYTIME hz/2 /* time to wait before retrying a cmd */ | | 99 | #define RECOVERYTIME hz/2 /* time to wait before retrying a cmd */ |
100 | | | 100 | |
101 | #define WDUNIT(dev) DISKUNIT(dev) | | 101 | #define WDUNIT(dev) DISKUNIT(dev) |
102 | #define WDPART(dev) DISKPART(dev) | | 102 | #define WDPART(dev) DISKPART(dev) |
103 | #define WDMINOR(unit, part) DISKMINOR(unit, part) | | 103 | #define WDMINOR(unit, part) DISKMINOR(unit, part) |
104 | #define MAKEWDDEV(maj, unit, part) MAKEDISKDEV(maj, unit, part) | | 104 | #define MAKEWDDEV(maj, unit, part) MAKEDISKDEV(maj, unit, part) |
105 | | | 105 | |
106 | #define WDLABELDEV(dev) (MAKEWDDEV(major(dev), WDUNIT(dev), RAW_PART)) | | 106 | #define WDLABELDEV(dev) (MAKEWDDEV(major(dev), WDUNIT(dev), RAW_PART)) |
107 | | | 107 | |
108 | #define DEBUG_INTR 0x01 | | 108 | #define DEBUG_INTR 0x01 |
109 | #define DEBUG_XFERS 0x02 | | 109 | #define DEBUG_XFERS 0x02 |
110 | #define DEBUG_STATUS 0x04 | | 110 | #define DEBUG_STATUS 0x04 |
111 | #define DEBUG_FUNCS 0x08 | | 111 | #define DEBUG_FUNCS 0x08 |
112 | #define DEBUG_PROBE 0x10 | | 112 | #define DEBUG_PROBE 0x10 |
113 | #ifdef ATADEBUG | | 113 | #ifdef ATADEBUG |
114 | int wdcdebug_wd_mask = 0x0; | | 114 | int wdcdebug_wd_mask = 0x0; |
115 | #define ATADEBUG_PRINT(args, level) \ | | 115 | #define ATADEBUG_PRINT(args, level) \ |
116 | if (wdcdebug_wd_mask & (level)) \ | | 116 | if (wdcdebug_wd_mask & (level)) \ |
117 | printf args | | 117 | printf args |
118 | #else | | 118 | #else |
119 | #define ATADEBUG_PRINT(args, level) | | 119 | #define ATADEBUG_PRINT(args, level) |
120 | #endif | | 120 | #endif |
121 | | | 121 | |
122 | int wdprobe(device_t, cfdata_t, void *); | | 122 | int wdprobe(device_t, cfdata_t, void *); |
123 | void wdattach(device_t, device_t, void *); | | 123 | void wdattach(device_t, device_t, void *); |
124 | int wddetach(device_t, int); | | 124 | int wddetach(device_t, int); |
125 | int wdprint(void *, char *); | | 125 | int wdprint(void *, char *); |
126 | void wdperror(const struct wd_softc *); | | 126 | void wdperror(const struct wd_softc *); |
127 | | | 127 | |
128 | static int wdlastclose(device_t); | | 128 | static int wdlastclose(device_t); |
129 | static bool wd_suspend(device_t, const pmf_qual_t *); | | 129 | static bool wd_suspend(device_t, const pmf_qual_t *); |
130 | static int wd_standby(struct wd_softc *, int); | | 130 | static int wd_standby(struct wd_softc *, int); |
131 | | | 131 | |
132 | CFATTACH_DECL3_NEW(wd, sizeof(struct wd_softc), | | 132 | CFATTACH_DECL3_NEW(wd, sizeof(struct wd_softc), |
133 | wdprobe, wdattach, wddetach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN); | | 133 | wdprobe, wdattach, wddetach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN); |
134 | | | 134 | |
135 | extern struct cfdriver wd_cd; | | 135 | extern struct cfdriver wd_cd; |
136 | | | 136 | |
137 | dev_type_open(wdopen); | | 137 | dev_type_open(wdopen); |
138 | dev_type_close(wdclose); | | 138 | dev_type_close(wdclose); |
139 | dev_type_read(wdread); | | 139 | dev_type_read(wdread); |
140 | dev_type_write(wdwrite); | | 140 | dev_type_write(wdwrite); |
141 | dev_type_ioctl(wdioctl); | | 141 | dev_type_ioctl(wdioctl); |
142 | dev_type_strategy(wdstrategy); | | 142 | dev_type_strategy(wdstrategy); |
143 | dev_type_dump(wddump); | | 143 | dev_type_dump(wddump); |
144 | dev_type_size(wdsize); | | 144 | dev_type_size(wdsize); |
145 | | | 145 | |
146 | const struct bdevsw wd_bdevsw = { | | 146 | const struct bdevsw wd_bdevsw = { |
147 | wdopen, wdclose, wdstrategy, wdioctl, wddump, wdsize, D_DISK | | 147 | wdopen, wdclose, wdstrategy, wdioctl, wddump, wdsize, D_DISK |
148 | }; | | 148 | }; |
149 | | | 149 | |
150 | const struct cdevsw wd_cdevsw = { | | 150 | const struct cdevsw wd_cdevsw = { |
151 | wdopen, wdclose, wdread, wdwrite, wdioctl, | | 151 | wdopen, wdclose, wdread, wdwrite, wdioctl, |
152 | nostop, notty, nopoll, nommap, nokqfilter, D_DISK | | 152 | nostop, notty, nopoll, nommap, nokqfilter, D_DISK |
153 | }; | | 153 | }; |
154 | | | 154 | |
155 | /* | | 155 | /* |
156 | * Glue necessary to hook WDCIOCCOMMAND into physio | | 156 | * Glue necessary to hook WDCIOCCOMMAND into physio |
157 | */ | | 157 | */ |
158 | | | 158 | |
159 | struct wd_ioctl { | | 159 | struct wd_ioctl { |
160 | LIST_ENTRY(wd_ioctl) wi_list; | | 160 | LIST_ENTRY(wd_ioctl) wi_list; |
161 | struct buf wi_bp; | | 161 | struct buf wi_bp; |
162 | struct uio wi_uio; | | 162 | struct uio wi_uio; |
163 | struct iovec wi_iov; | | 163 | struct iovec wi_iov; |
164 | atareq_t wi_atareq; | | 164 | atareq_t wi_atareq; |
165 | struct wd_softc *wi_softc; | | 165 | struct wd_softc *wi_softc; |
166 | }; | | 166 | }; |
167 | | | 167 | |
168 | LIST_HEAD(, wd_ioctl) wi_head; | | 168 | LIST_HEAD(, wd_ioctl) wi_head; |
169 | | | 169 | |
170 | struct wd_ioctl *wi_find(struct buf *); | | 170 | struct wd_ioctl *wi_find(struct buf *); |
171 | void wi_free(struct wd_ioctl *); | | 171 | void wi_free(struct wd_ioctl *); |
172 | struct wd_ioctl *wi_get(void); | | 172 | struct wd_ioctl *wi_get(void); |
173 | void wdioctlstrategy(struct buf *); | | 173 | void wdioctlstrategy(struct buf *); |
174 | | | 174 | |
175 | void wdgetdefaultlabel(struct wd_softc *, struct disklabel *); | | 175 | void wdgetdefaultlabel(struct wd_softc *, struct disklabel *); |
176 | void wdgetdisklabel(struct wd_softc *); | | 176 | void wdgetdisklabel(struct wd_softc *); |
177 | void wdstart(void *); | | 177 | void wdstart(void *); |
178 | void wdstart1(struct wd_softc*, struct buf *); | | 178 | void wdstart1(struct wd_softc*, struct buf *); |
179 | void wdrestart(void *); | | 179 | void wdrestart(void *); |
180 | void wddone(void *); | | 180 | void wddone(void *); |
181 | int wd_get_params(struct wd_softc *, u_int8_t, struct ataparams *); | | 181 | int wd_get_params(struct wd_softc *, u_int8_t, struct ataparams *); |
182 | int wd_flushcache(struct wd_softc *, int); | | 182 | int wd_flushcache(struct wd_softc *, int); |
183 | bool wd_shutdown(device_t, int); | | 183 | bool wd_shutdown(device_t, int); |
184 | | | 184 | |
185 | int wd_getcache(struct wd_softc *, int *); | | 185 | int wd_getcache(struct wd_softc *, int *); |
186 | int wd_setcache(struct wd_softc *, int); | | 186 | int wd_setcache(struct wd_softc *, int); |
187 | | | 187 | |
188 | struct dkdriver wddkdriver = { wdstrategy, minphys }; | | 188 | struct dkdriver wddkdriver = { wdstrategy, minphys }; |
189 | | | 189 | |
190 | #ifdef HAS_BAD144_HANDLING | | 190 | #ifdef HAS_BAD144_HANDLING |
191 | static void bad144intern(struct wd_softc *); | | 191 | static void bad144intern(struct wd_softc *); |
192 | #endif | | 192 | #endif |
193 | | | 193 | |
194 | #define WD_QUIRK_SPLIT_MOD15_WRITE 0x0001 /* must split certain writes */ | | 194 | #define WD_QUIRK_SPLIT_MOD15_WRITE 0x0001 /* must split certain writes */ |
195 | | | 195 | |
196 | #define WD_QUIRK_FMT "\20\1SPLIT_MOD15_WRITE\2FORCE_LBA48" | | 196 | #define WD_QUIRK_FMT "\20\1SPLIT_MOD15_WRITE\2FORCE_LBA48" |
197 | | | 197 | |
198 | /* | | 198 | /* |
199 | * Quirk table for IDE drives. Put more-specific matches first, since | | 199 | * Quirk table for IDE drives. Put more-specific matches first, since |
200 | * a simple globbing routine is used for matching. | | 200 | * a simple globbing routine is used for matching. |
201 | */ | | 201 | */ |
202 | static const struct wd_quirk { | | 202 | static const struct wd_quirk { |
203 | const char *wdq_match; /* inquiry pattern to match */ | | 203 | const char *wdq_match; /* inquiry pattern to match */ |
204 | int wdq_quirks; /* drive quirks */ | | 204 | int wdq_quirks; /* drive quirks */ |
205 | } wd_quirk_table[] = { | | 205 | } wd_quirk_table[] = { |
206 | /* | | 206 | /* |
207 | * Some Seagate S-ATA drives have a PHY which can get confused | | 207 | * Some Seagate S-ATA drives have a PHY which can get confused |
208 | * with the way data is packetized by some S-ATA controllers. | | 208 | * with the way data is packetized by some S-ATA controllers. |
209 | * | | 209 | * |
210 | * The work-around is to split in two any write transfer whose | | 210 | * The work-around is to split in two any write transfer whose |
211 | * sector count % 15 == 1 (assuming 512 byte sectors). | | 211 | * sector count % 15 == 1 (assuming 512 byte sectors). |
212 | * | | 212 | * |
213 | * XXX This is an incomplete list. There are at least a couple | | 213 | * XXX This is an incomplete list. There are at least a couple |
214 | * XXX more model numbers. If you have trouble with such transfers | | 214 | * XXX more model numbers. If you have trouble with such transfers |
215 | * XXX (8K is the most common) on Seagate S-ATA drives, please | | 215 | * XXX (8K is the most common) on Seagate S-ATA drives, please |
216 | * XXX notify thorpej@NetBSD.org. | | 216 | * XXX notify thorpej@NetBSD.org. |
217 | */ | | 217 | */ |
218 | { "ST3120023AS", | | 218 | { "ST3120023AS", |
219 | WD_QUIRK_SPLIT_MOD15_WRITE }, | | 219 | WD_QUIRK_SPLIT_MOD15_WRITE }, |
220 | { "ST380023AS", | | 220 | { "ST380023AS", |
221 | WD_QUIRK_SPLIT_MOD15_WRITE }, | | 221 | WD_QUIRK_SPLIT_MOD15_WRITE }, |
222 | { NULL, | | 222 | { NULL, |
223 | 0 } | | 223 | 0 } |
224 | }; | | 224 | }; |
225 | | | 225 | |
226 | static const struct wd_quirk * | | 226 | static const struct wd_quirk * |
227 | wd_lookup_quirks(const char *name) | | 227 | wd_lookup_quirks(const char *name) |
228 | { | | 228 | { |
229 | const struct wd_quirk *wdq; | | 229 | const struct wd_quirk *wdq; |
230 | const char *estr; | | 230 | const char *estr; |
231 | | | 231 | |
232 | for (wdq = wd_quirk_table; wdq->wdq_match != NULL; wdq++) { | | 232 | for (wdq = wd_quirk_table; wdq->wdq_match != NULL; wdq++) { |
233 | /* | | 233 | /* |
234 | * We only want exact matches (which include matches | | 234 | * We only want exact matches (which include matches |
235 | * against globbing characters). | | 235 | * against globbing characters). |
236 | */ | | 236 | */ |
237 | if (pmatch(name, wdq->wdq_match, &estr) == 2) | | 237 | if (pmatch(name, wdq->wdq_match, &estr) == 2) |
238 | return (wdq); | | 238 | return (wdq); |
239 | } | | 239 | } |
240 | return (NULL); | | 240 | return (NULL); |
241 | } | | 241 | } |
242 | | | 242 | |
243 | int | | 243 | int |
244 | wdprobe(device_t parent, cfdata_t match, void *aux) | | 244 | wdprobe(device_t parent, cfdata_t match, void *aux) |
245 | { | | 245 | { |
246 | struct ata_device *adev = aux; | | 246 | struct ata_device *adev = aux; |
247 | | | 247 | |
248 | if (adev == NULL) | | 248 | if (adev == NULL) |
249 | return 0; | | 249 | return 0; |
250 | if (adev->adev_bustype->bustype_type != SCSIPI_BUSTYPE_ATA) | | 250 | if (adev->adev_bustype->bustype_type != SCSIPI_BUSTYPE_ATA) |
251 | return 0; | | 251 | return 0; |
252 | | | 252 | |
253 | if (match->cf_loc[ATA_HLCF_DRIVE] != ATA_HLCF_DRIVE_DEFAULT && | | 253 | if (match->cf_loc[ATA_HLCF_DRIVE] != ATA_HLCF_DRIVE_DEFAULT && |
254 | match->cf_loc[ATA_HLCF_DRIVE] != adev->adev_drv_data->drive) | | 254 | match->cf_loc[ATA_HLCF_DRIVE] != adev->adev_drv_data->drive) |
255 | return 0; | | 255 | return 0; |
256 | return 1; | | 256 | return 1; |
257 | } | | 257 | } |
258 | | | 258 | |
259 | void | | 259 | void |
260 | wdattach(device_t parent, device_t self, void *aux) | | 260 | wdattach(device_t parent, device_t self, void *aux) |
261 | { | | 261 | { |
262 | struct wd_softc *wd = device_private(self); | | 262 | struct wd_softc *wd = device_private(self); |
263 | struct ata_device *adev= aux; | | 263 | struct ata_device *adev= aux; |
264 | int i, blank; | | 264 | int i, blank; |
265 | char tbuf[41], pbuf[9], c, *p, *q; | | 265 | char tbuf[41], pbuf[9], c, *p, *q; |
266 | const struct wd_quirk *wdq; | | 266 | const struct wd_quirk *wdq; |
267 | | | 267 | |
268 | wd->sc_dev = self; | | 268 | wd->sc_dev = self; |
269 | | | 269 | |
270 | ATADEBUG_PRINT(("wdattach\n"), DEBUG_FUNCS | DEBUG_PROBE); | | 270 | ATADEBUG_PRINT(("wdattach\n"), DEBUG_FUNCS | DEBUG_PROBE); |
271 | callout_init(&wd->sc_restart_ch, 0); | | 271 | callout_init(&wd->sc_restart_ch, 0); |
272 | bufq_alloc(&wd->sc_q, BUFQ_DISK_DEFAULT_STRAT, BUFQ_SORT_RAWBLOCK); | | 272 | bufq_alloc(&wd->sc_q, BUFQ_DISK_DEFAULT_STRAT, BUFQ_SORT_RAWBLOCK); |
273 | #ifdef WD_SOFTBADSECT | | 273 | #ifdef WD_SOFTBADSECT |
274 | SLIST_INIT(&wd->sc_bslist); | | 274 | SLIST_INIT(&wd->sc_bslist); |
275 | #endif | | 275 | #endif |
276 | wd->atabus = adev->adev_bustype; | | 276 | wd->atabus = adev->adev_bustype; |
277 | wd->openings = adev->adev_openings; | | 277 | wd->openings = adev->adev_openings; |
278 | wd->drvp = adev->adev_drv_data; | | 278 | wd->drvp = adev->adev_drv_data; |
279 | | | 279 | |
280 | wd->drvp->drv_done = wddone; | | 280 | wd->drvp->drv_done = wddone; |
281 | wd->drvp->drv_softc = wd->sc_dev; | | 281 | wd->drvp->drv_softc = wd->sc_dev; |
282 | | | 282 | |
283 | aprint_naive("\n"); | | 283 | aprint_naive("\n"); |
284 | aprint_normal("\n"); | | 284 | aprint_normal("\n"); |
285 | | | 285 | |
286 | /* read our drive info */ | | 286 | /* read our drive info */ |
287 | if (wd_get_params(wd, AT_WAIT, &wd->sc_params) != 0) { | | 287 | if (wd_get_params(wd, AT_WAIT, &wd->sc_params) != 0) { |
288 | aprint_error_dev(self, "IDENTIFY failed\n"); | | 288 | aprint_error_dev(self, "IDENTIFY failed\n"); |
289 | return; | | 289 | return; |
290 | } | | 290 | } |
291 | | | 291 | |
292 | for (blank = 0, p = wd->sc_params.atap_model, q = tbuf, i = 0; | | 292 | for (blank = 0, p = wd->sc_params.atap_model, q = tbuf, i = 0; |
293 | i < sizeof(wd->sc_params.atap_model); i++) { | | 293 | i < sizeof(wd->sc_params.atap_model); i++) { |
294 | c = *p++; | | 294 | c = *p++; |
295 | if (c == '\0') | | 295 | if (c == '\0') |
296 | break; | | 296 | break; |
297 | if (c != ' ') { | | 297 | if (c != ' ') { |
298 | if (blank) { | | 298 | if (blank) { |
299 | *q++ = ' '; | | 299 | *q++ = ' '; |
300 | blank = 0; | | 300 | blank = 0; |
301 | } | | 301 | } |
302 | *q++ = c; | | 302 | *q++ = c; |
303 | } else | | 303 | } else |
304 | blank = 1; | | 304 | blank = 1; |
305 | } | | 305 | } |
306 | *q++ = '\0'; | | 306 | *q++ = '\0'; |
307 | | | 307 | |
308 | aprint_normal_dev(self, "<%s>\n", tbuf); | | 308 | aprint_normal_dev(self, "<%s>\n", tbuf); |
309 | | | 309 | |
310 | wdq = wd_lookup_quirks(tbuf); | | 310 | wdq = wd_lookup_quirks(tbuf); |
311 | if (wdq != NULL) | | 311 | if (wdq != NULL) |
312 | wd->sc_quirks = wdq->wdq_quirks; | | 312 | wd->sc_quirks = wdq->wdq_quirks; |
313 | | | 313 | |
314 | if (wd->sc_quirks != 0) { | | 314 | if (wd->sc_quirks != 0) { |
315 | char sbuf[sizeof(WD_QUIRK_FMT) + 64]; | | 315 | char sbuf[sizeof(WD_QUIRK_FMT) + 64]; |
316 | snprintb(sbuf, sizeof(sbuf), WD_QUIRK_FMT, wd->sc_quirks); | | 316 | snprintb(sbuf, sizeof(sbuf), WD_QUIRK_FMT, wd->sc_quirks); |
317 | aprint_normal_dev(self, "quirks %s\n", sbuf); | | 317 | aprint_normal_dev(self, "quirks %s\n", sbuf); |
318 | } | | 318 | } |
319 | | | 319 | |
320 | if ((wd->sc_params.atap_multi & 0xff) > 1) { | | 320 | if ((wd->sc_params.atap_multi & 0xff) > 1) { |
321 | wd->sc_multi = wd->sc_params.atap_multi & 0xff; | | 321 | wd->sc_multi = wd->sc_params.atap_multi & 0xff; |
322 | } else { | | 322 | } else { |
323 | wd->sc_multi = 1; | | 323 | wd->sc_multi = 1; |
324 | } | | 324 | } |
325 | | | 325 | |
326 | aprint_verbose_dev(self, "drive supports %d-sector PIO transfers,", | | 326 | aprint_verbose_dev(self, "drive supports %d-sector PIO transfers,", |
327 | wd->sc_multi); | | 327 | wd->sc_multi); |
328 | | | 328 | |
329 | /* 48-bit LBA addressing */ | | 329 | /* 48-bit LBA addressing */ |
330 | if ((wd->sc_params.atap_cmd2_en & ATA_CMD2_LBA48) != 0) | | 330 | if ((wd->sc_params.atap_cmd2_en & ATA_CMD2_LBA48) != 0) |
331 | wd->sc_flags |= WDF_LBA48; | | 331 | wd->sc_flags |= WDF_LBA48; |
332 | | | 332 | |
333 | /* Prior to ATA-4, LBA was optional. */ | | 333 | /* Prior to ATA-4, LBA was optional. */ |
334 | if ((wd->sc_params.atap_capabilities1 & WDC_CAP_LBA) != 0) | | 334 | if ((wd->sc_params.atap_capabilities1 & WDC_CAP_LBA) != 0) |
335 | wd->sc_flags |= WDF_LBA; | | 335 | wd->sc_flags |= WDF_LBA; |
336 | #if 0 | | 336 | #if 0 |
337 | /* ATA-4 requires LBA. */ | | 337 | /* ATA-4 requires LBA. */ |
338 | if (wd->sc_params.atap_ataversion != 0xffff && | | 338 | if (wd->sc_params.atap_ataversion != 0xffff && |
339 | wd->sc_params.atap_ataversion >= WDC_VER_ATA4) | | 339 | wd->sc_params.atap_ataversion >= WDC_VER_ATA4) |
340 | wd->sc_flags |= WDF_LBA; | | 340 | wd->sc_flags |= WDF_LBA; |
341 | #endif | | 341 | #endif |
342 | | | 342 | |
343 | if ((wd->sc_flags & WDF_LBA48) != 0) { | | 343 | if ((wd->sc_flags & WDF_LBA48) != 0) { |
344 | aprint_verbose(" LBA48 addressing\n"); | | 344 | aprint_verbose(" LBA48 addressing\n"); |
345 | wd->sc_capacity = | | 345 | wd->sc_capacity = |
346 | ((u_int64_t) wd->sc_params.atap_max_lba[3] << 48) | | | 346 | ((u_int64_t) wd->sc_params.atap_max_lba[3] << 48) | |
347 | ((u_int64_t) wd->sc_params.atap_max_lba[2] << 32) | | | 347 | ((u_int64_t) wd->sc_params.atap_max_lba[2] << 32) | |
348 | ((u_int64_t) wd->sc_params.atap_max_lba[1] << 16) | | | 348 | ((u_int64_t) wd->sc_params.atap_max_lba[1] << 16) | |
349 | ((u_int64_t) wd->sc_params.atap_max_lba[0] << 0); | | 349 | ((u_int64_t) wd->sc_params.atap_max_lba[0] << 0); |
350 | wd->sc_capacity28 = | | 350 | wd->sc_capacity28 = |
351 | (wd->sc_params.atap_capacity[1] << 16) | | | 351 | (wd->sc_params.atap_capacity[1] << 16) | |
352 | wd->sc_params.atap_capacity[0]; | | 352 | wd->sc_params.atap_capacity[0]; |
353 | } else if ((wd->sc_flags & WDF_LBA) != 0) { | | 353 | } else if ((wd->sc_flags & WDF_LBA) != 0) { |
354 | aprint_verbose(" LBA addressing\n"); | | 354 | aprint_verbose(" LBA addressing\n"); |
355 | wd->sc_capacity28 = wd->sc_capacity = | | 355 | wd->sc_capacity28 = wd->sc_capacity = |
356 | (wd->sc_params.atap_capacity[1] << 16) | | | 356 | (wd->sc_params.atap_capacity[1] << 16) | |
357 | wd->sc_params.atap_capacity[0]; | | 357 | wd->sc_params.atap_capacity[0]; |
358 | } else { | | 358 | } else { |
359 | aprint_verbose(" chs addressing\n"); | | 359 | aprint_verbose(" chs addressing\n"); |
360 | wd->sc_capacity28 = wd->sc_capacity = | | 360 | wd->sc_capacity28 = wd->sc_capacity = |
361 | wd->sc_params.atap_cylinders * | | 361 | wd->sc_params.atap_cylinders * |
362 | wd->sc_params.atap_heads * | | 362 | wd->sc_params.atap_heads * |
363 | wd->sc_params.atap_sectors; | | 363 | wd->sc_params.atap_sectors; |
364 | } | | 364 | } |
365 | format_bytes(pbuf, sizeof(pbuf), wd->sc_capacity * DEV_BSIZE); | | 365 | format_bytes(pbuf, sizeof(pbuf), wd->sc_capacity * DEV_BSIZE); |
366 | aprint_normal_dev(self, "%s, %d cyl, %d head, %d sec, " | | 366 | aprint_normal_dev(self, "%s, %d cyl, %d head, %d sec, " |
367 | "%d bytes/sect x %llu sectors\n", | | 367 | "%d bytes/sect x %llu sectors\n", |
368 | pbuf, | | 368 | pbuf, |
369 | (wd->sc_flags & WDF_LBA) ? (int)(wd->sc_capacity / | | 369 | (wd->sc_flags & WDF_LBA) ? (int)(wd->sc_capacity / |
370 | (wd->sc_params.atap_heads * wd->sc_params.atap_sectors)) : | | 370 | (wd->sc_params.atap_heads * wd->sc_params.atap_sectors)) : |
371 | wd->sc_params.atap_cylinders, | | 371 | wd->sc_params.atap_cylinders, |
372 | wd->sc_params.atap_heads, wd->sc_params.atap_sectors, | | 372 | wd->sc_params.atap_heads, wd->sc_params.atap_sectors, |
373 | DEV_BSIZE, (unsigned long long)wd->sc_capacity); | | 373 | DEV_BSIZE, (unsigned long long)wd->sc_capacity); |
374 | | | 374 | |
375 | ATADEBUG_PRINT(("%s: atap_dmatiming_mimi=%d, atap_dmatiming_recom=%d\n", | | 375 | ATADEBUG_PRINT(("%s: atap_dmatiming_mimi=%d, atap_dmatiming_recom=%d\n", |
376 | device_xname(self), wd->sc_params.atap_dmatiming_mimi, | | 376 | device_xname(self), wd->sc_params.atap_dmatiming_mimi, |
377 | wd->sc_params.atap_dmatiming_recom), DEBUG_PROBE); | | 377 | wd->sc_params.atap_dmatiming_recom), DEBUG_PROBE); |
378 | /* | | 378 | /* |
379 | * Initialize and attach the disk structure. | | 379 | * Initialize and attach the disk structure. |
380 | */ | | 380 | */ |
381 | /* we fill in dk_info later */ | | 381 | /* we fill in dk_info later */ |
382 | disk_init(&wd->sc_dk, device_xname(wd->sc_dev), &wddkdriver); | | 382 | disk_init(&wd->sc_dk, device_xname(wd->sc_dev), &wddkdriver); |
383 | disk_attach(&wd->sc_dk); | | 383 | disk_attach(&wd->sc_dk); |
384 | wd->sc_wdc_bio.lp = wd->sc_dk.dk_label; | | 384 | wd->sc_wdc_bio.lp = wd->sc_dk.dk_label; |
385 | #if NRND > 0 | | 385 | #if NRND > 0 |
386 | rnd_attach_source(&wd->rnd_source, device_xname(wd->sc_dev), | | 386 | rnd_attach_source(&wd->rnd_source, device_xname(wd->sc_dev), |
387 | RND_TYPE_DISK, 0); | | 387 | RND_TYPE_DISK, 0); |
388 | #endif | | 388 | #endif |
389 | | | 389 | |
390 | /* Discover wedges on this disk. */ | | 390 | /* Discover wedges on this disk. */ |
391 | dkwedge_discover(&wd->sc_dk); | | 391 | dkwedge_discover(&wd->sc_dk); |
392 | | | 392 | |
393 | if (!pmf_device_register1(self, wd_suspend, NULL, wd_shutdown)) | | 393 | if (!pmf_device_register1(self, wd_suspend, NULL, wd_shutdown)) |
394 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 394 | aprint_error_dev(self, "couldn't establish power handler\n"); |
395 | } | | 395 | } |
396 | | | 396 | |
397 | static bool | | 397 | static bool |
398 | wd_suspend(device_t dv, const pmf_qual_t *qual) | | 398 | wd_suspend(device_t dv, const pmf_qual_t *qual) |
399 | { | | 399 | { |
400 | struct wd_softc *sc = device_private(dv); | | 400 | struct wd_softc *sc = device_private(dv); |
401 | | | 401 | |
402 | wd_flushcache(sc, AT_WAIT); | | 402 | wd_flushcache(sc, AT_WAIT); |
403 | wd_standby(sc, AT_WAIT); | | 403 | wd_standby(sc, AT_WAIT); |
404 | return true; | | 404 | return true; |
405 | } | | 405 | } |
406 | | | 406 | |
407 | int | | 407 | int |
408 | wddetach(device_t self, int flags) | | 408 | wddetach(device_t self, int flags) |
409 | { | | 409 | { |
410 | struct wd_softc *sc = device_private(self); | | 410 | struct wd_softc *sc = device_private(self); |
411 | int bmaj, cmaj, i, mn, rc, s; | | 411 | int bmaj, cmaj, i, mn, rc, s; |
412 | | | 412 | |
413 | if ((rc = disk_begindetach(&sc->sc_dk, wdlastclose, self, flags)) != 0) | | 413 | if ((rc = disk_begindetach(&sc->sc_dk, wdlastclose, self, flags)) != 0) |
414 | return rc; | | 414 | return rc; |
415 | | | 415 | |
416 | /* locate the major number */ | | 416 | /* locate the major number */ |
417 | bmaj = bdevsw_lookup_major(&wd_bdevsw); | | 417 | bmaj = bdevsw_lookup_major(&wd_bdevsw); |
418 | cmaj = cdevsw_lookup_major(&wd_cdevsw); | | 418 | cmaj = cdevsw_lookup_major(&wd_cdevsw); |
419 | | | 419 | |
420 | /* Nuke the vnodes for any open instances. */ | | 420 | /* Nuke the vnodes for any open instances. */ |
421 | for (i = 0; i < MAXPARTITIONS; i++) { | | 421 | for (i = 0; i < MAXPARTITIONS; i++) { |
422 | mn = WDMINOR(device_unit(self), i); | | 422 | mn = WDMINOR(device_unit(self), i); |
423 | vdevgone(bmaj, mn, mn, VBLK); | | 423 | vdevgone(bmaj, mn, mn, VBLK); |
424 | vdevgone(cmaj, mn, mn, VCHR); | | 424 | vdevgone(cmaj, mn, mn, VCHR); |
425 | } | | 425 | } |
426 | | | 426 | |
427 | /* Delete all of our wedges. */ | | 427 | /* Delete all of our wedges. */ |
428 | dkwedge_delall(&sc->sc_dk); | | 428 | dkwedge_delall(&sc->sc_dk); |
429 | | | 429 | |
430 | s = splbio(); | | 430 | s = splbio(); |
431 | | | 431 | |
432 | /* Kill off any queued buffers. */ | | 432 | /* Kill off any queued buffers. */ |
433 | bufq_drain(sc->sc_q); | | 433 | bufq_drain(sc->sc_q); |
434 | | | 434 | |
435 | bufq_free(sc->sc_q); | | 435 | bufq_free(sc->sc_q); |
436 | sc->atabus->ata_killpending(sc->drvp); | | 436 | sc->atabus->ata_killpending(sc->drvp); |
437 | | | 437 | |
438 | splx(s); | | 438 | splx(s); |
439 | | | 439 | |
440 | /* Detach disk. */ | | 440 | /* Detach disk. */ |
441 | disk_detach(&sc->sc_dk); | | 441 | disk_detach(&sc->sc_dk); |
442 | disk_destroy(&sc->sc_dk); | | 442 | disk_destroy(&sc->sc_dk); |
443 | | | 443 | |
444 | #ifdef WD_SOFTBADSECT | | 444 | #ifdef WD_SOFTBADSECT |
445 | /* Clean out the bad sector list */ | | 445 | /* Clean out the bad sector list */ |
446 | while (!SLIST_EMPTY(&sc->sc_bslist)) { | | 446 | while (!SLIST_EMPTY(&sc->sc_bslist)) { |
447 | void *head = SLIST_FIRST(&sc->sc_bslist); | | 447 | void *head = SLIST_FIRST(&sc->sc_bslist); |
448 | SLIST_REMOVE_HEAD(&sc->sc_bslist, dbs_next); | | 448 | SLIST_REMOVE_HEAD(&sc->sc_bslist, dbs_next); |
449 | free(head, M_TEMP); | | 449 | free(head, M_TEMP); |
450 | } | | 450 | } |
451 | sc->sc_bscount = 0; | | 451 | sc->sc_bscount = 0; |
452 | #endif | | 452 | #endif |
453 | | | 453 | |
454 | pmf_device_deregister(self); | | 454 | pmf_device_deregister(self); |
455 | | | 455 | |
456 | #if NRND > 0 | | 456 | #if NRND > 0 |
457 | /* Unhook the entropy source. */ | | 457 | /* Unhook the entropy source. */ |
458 | rnd_detach_source(&sc->rnd_source); | | 458 | rnd_detach_source(&sc->rnd_source); |
459 | #endif | | 459 | #endif |
460 | | | 460 | |
461 | callout_destroy(&sc->sc_restart_ch); | | 461 | callout_destroy(&sc->sc_restart_ch); |
462 | | | 462 | |
463 | sc->drvp->drive_flags = 0; /* no drive any more here */ | | 463 | sc->drvp->drive_flags = 0; /* no drive any more here */ |
464 | | | 464 | |
465 | return (0); | | 465 | return (0); |
466 | } | | 466 | } |
467 | | | 467 | |
468 | /* | | 468 | /* |
469 | * Read/write routine for a buffer. Validates the arguments and schedules the | | 469 | * Read/write routine for a buffer. Validates the arguments and schedules the |
470 | * transfer. Does not wait for the transfer to complete. | | 470 | * transfer. Does not wait for the transfer to complete. |
471 | */ | | 471 | */ |
472 | void | | 472 | void |
473 | wdstrategy(struct buf *bp) | | 473 | wdstrategy(struct buf *bp) |
474 | { | | 474 | { |
475 | struct wd_softc *wd = | | 475 | struct wd_softc *wd = |
476 | device_lookup_private(&wd_cd, WDUNIT(bp->b_dev)); | | 476 | device_lookup_private(&wd_cd, WDUNIT(bp->b_dev)); |
477 | struct disklabel *lp = wd->sc_dk.dk_label; | | 477 | struct disklabel *lp = wd->sc_dk.dk_label; |
478 | daddr_t blkno; | | 478 | daddr_t blkno; |
479 | int s; | | 479 | int s; |
480 | | | 480 | |
481 | ATADEBUG_PRINT(("wdstrategy (%s)\n", device_xname(wd->sc_dev)), | | 481 | ATADEBUG_PRINT(("wdstrategy (%s)\n", device_xname(wd->sc_dev)), |
482 | DEBUG_XFERS); | | 482 | DEBUG_XFERS); |
483 | | | 483 | |
484 | /* Valid request? */ | | 484 | /* Valid request? */ |
485 | if (bp->b_blkno < 0 || | | 485 | if (bp->b_blkno < 0 || |
486 | (bp->b_bcount % lp->d_secsize) != 0 || | | 486 | (bp->b_bcount % lp->d_secsize) != 0 || |
487 | (bp->b_bcount / lp->d_secsize) >= (1 << NBBY)) { | | 487 | (bp->b_bcount / lp->d_secsize) >= (1 << NBBY)) { |
488 | bp->b_error = EINVAL; | | 488 | bp->b_error = EINVAL; |
489 | goto done; | | 489 | goto done; |
490 | } | | 490 | } |
491 | | | 491 | |
492 | /* If device invalidated (e.g. media change, door open, | | 492 | /* If device invalidated (e.g. media change, door open, |
493 | * device detachment), then error. | | 493 | * device detachment), then error. |
494 | */ | | 494 | */ |
495 | if ((wd->sc_flags & WDF_LOADED) == 0 || | | 495 | if ((wd->sc_flags & WDF_LOADED) == 0 || |
496 | !device_is_enabled(wd->sc_dev)) { | | 496 | !device_is_enabled(wd->sc_dev)) { |
497 | bp->b_error = EIO; | | 497 | bp->b_error = EIO; |
498 | goto done; | | 498 | goto done; |
499 | } | | 499 | } |
500 | | | 500 | |
501 | /* If it's a null transfer, return immediately. */ | | 501 | /* If it's a null transfer, return immediately. */ |
502 | if (bp->b_bcount == 0) | | 502 | if (bp->b_bcount == 0) |
503 | goto done; | | 503 | goto done; |
504 | | | 504 | |
505 | /* | | 505 | /* |
506 | * Do bounds checking, adjust transfer. if error, process. | | 506 | * Do bounds checking, adjust transfer. if error, process. |
507 | * If end of partition, just return. | | 507 | * If end of partition, just return. |
508 | */ | | 508 | */ |
509 | if (WDPART(bp->b_dev) == RAW_PART) { | | 509 | if (WDPART(bp->b_dev) == RAW_PART) { |
510 | if (bounds_check_with_mediasize(bp, DEV_BSIZE, | | 510 | if (bounds_check_with_mediasize(bp, DEV_BSIZE, |
511 | wd->sc_capacity) <= 0) | | 511 | wd->sc_capacity) <= 0) |
512 | goto done; | | 512 | goto done; |
513 | } else { | | 513 | } else { |
514 | if (bounds_check_with_label(&wd->sc_dk, bp, | | 514 | if (bounds_check_with_label(&wd->sc_dk, bp, |
515 | (wd->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0) | | 515 | (wd->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0) |
516 | goto done; | | 516 | goto done; |
517 | } | | 517 | } |
518 | | | 518 | |
519 | /* | | 519 | /* |
520 | * Now convert the block number to absolute and put it in | | 520 | * Now convert the block number to absolute and put it in |
521 | * terms of the device's logical block size. | | 521 | * terms of the device's logical block size. |
522 | */ | | 522 | */ |
523 | if (lp->d_secsize >= DEV_BSIZE) | | 523 | if (lp->d_secsize >= DEV_BSIZE) |
524 | blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE); | | 524 | blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE); |
525 | else | | 525 | else |
526 | blkno = bp->b_blkno * (DEV_BSIZE / lp->d_secsize); | | 526 | blkno = bp->b_blkno * (DEV_BSIZE / lp->d_secsize); |
527 | | | 527 | |
528 | if (WDPART(bp->b_dev) != RAW_PART) | | 528 | if (WDPART(bp->b_dev) != RAW_PART) |
529 | blkno += lp->d_partitions[WDPART(bp->b_dev)].p_offset; | | 529 | blkno += lp->d_partitions[WDPART(bp->b_dev)].p_offset; |
530 | | | 530 | |
531 | bp->b_rawblkno = blkno; | | 531 | bp->b_rawblkno = blkno; |
532 | | | 532 | |
533 | #ifdef WD_SOFTBADSECT | | 533 | #ifdef WD_SOFTBADSECT |
534 | /* | | 534 | /* |
535 | * If the transfer about to be attempted contains only a block that | | 535 | * If the transfer about to be attempted contains only a block that |
536 | * is known to be bad then return an error for the transfer without | | 536 | * is known to be bad then return an error for the transfer without |
537 | * even attempting to start a transfer up under the premis that we | | 537 | * even attempting to start a transfer up under the premis that we |
538 | * will just end up doing more retries for a transfer that will end | | 538 | * will just end up doing more retries for a transfer that will end |
539 | * up failing again. | | 539 | * up failing again. |
540 | * XXX:SMP - mutex required to protect with DIOCBSFLUSH | | 540 | * XXX:SMP - mutex required to protect with DIOCBSFLUSH |
541 | */ | | 541 | */ |
542 | if (__predict_false(!SLIST_EMPTY(&wd->sc_bslist))) { | | 542 | if (__predict_false(!SLIST_EMPTY(&wd->sc_bslist))) { |
543 | struct disk_badsectors *dbs; | | 543 | struct disk_badsectors *dbs; |
544 | daddr_t maxblk = blkno + (bp->b_bcount >> DEV_BSHIFT) - 1; | | 544 | daddr_t maxblk = blkno + (bp->b_bcount >> DEV_BSHIFT) - 1; |
545 | | | 545 | |
546 | SLIST_FOREACH(dbs, &wd->sc_bslist, dbs_next) | | 546 | SLIST_FOREACH(dbs, &wd->sc_bslist, dbs_next) |
547 | if ((dbs->dbs_min <= blkno && blkno <= dbs->dbs_max) || | | 547 | if ((dbs->dbs_min <= blkno && blkno <= dbs->dbs_max) || |
548 | (dbs->dbs_min <= maxblk && maxblk <= dbs->dbs_max)){ | | 548 | (dbs->dbs_min <= maxblk && maxblk <= dbs->dbs_max)){ |
549 | bp->b_error = EIO; | | 549 | bp->b_error = EIO; |
550 | goto done; | | 550 | goto done; |
551 | } | | 551 | } |
552 | } | | 552 | } |
553 | #endif | | 553 | #endif |
554 | | | 554 | |
555 | /* Queue transfer on drive, activate drive and controller if idle. */ | | 555 | /* Queue transfer on drive, activate drive and controller if idle. */ |
556 | s = splbio(); | | 556 | s = splbio(); |
557 | bufq_put(wd->sc_q, bp); | | 557 | bufq_put(wd->sc_q, bp); |
558 | wdstart(wd); | | 558 | wdstart(wd); |
559 | splx(s); | | 559 | splx(s); |
560 | return; | | 560 | return; |
561 | done: | | 561 | done: |
562 | /* Toss transfer; we're done early. */ | | 562 | /* Toss transfer; we're done early. */ |
563 | bp->b_resid = bp->b_bcount; | | 563 | bp->b_resid = bp->b_bcount; |
564 | biodone(bp); | | 564 | biodone(bp); |
565 | } | | 565 | } |
566 | | | 566 | |
567 | /* | | 567 | /* |
568 | * Queue a drive for I/O. | | 568 | * Queue a drive for I/O. |
569 | */ | | 569 | */ |
570 | void | | 570 | void |
571 | wdstart(void *arg) | | 571 | wdstart(void *arg) |
572 | { | | 572 | { |
573 | struct wd_softc *wd = arg; | | 573 | struct wd_softc *wd = arg; |
574 | struct buf *bp = NULL; | | 574 | struct buf *bp = NULL; |
575 | | | 575 | |
576 | ATADEBUG_PRINT(("wdstart %s\n", device_xname(wd->sc_dev)), | | 576 | ATADEBUG_PRINT(("wdstart %s\n", device_xname(wd->sc_dev)), |
577 | DEBUG_XFERS); | | 577 | DEBUG_XFERS); |
578 | | | 578 | |
579 | if (!device_is_active(wd->sc_dev)) | | 579 | if (!device_is_active(wd->sc_dev)) |
580 | return; | | 580 | return; |
581 | | | 581 | |
582 | while (wd->openings > 0) { | | 582 | while (wd->openings > 0) { |
583 | | | 583 | |
584 | /* Is there a buf for us ? */ | | 584 | /* Is there a buf for us ? */ |
585 | if ((bp = bufq_get(wd->sc_q)) == NULL) | | 585 | if ((bp = bufq_get(wd->sc_q)) == NULL) |
586 | return; | | 586 | return; |
587 | | | 587 | |
588 | /* | | 588 | /* |
589 | * Make the command. First lock the device | | 589 | * Make the command. First lock the device |
590 | */ | | 590 | */ |
591 | wd->openings--; | | 591 | wd->openings--; |
592 | | | 592 | |
593 | wd->retries = 0; | | 593 | wd->retries = 0; |
594 | wdstart1(wd, bp); | | 594 | wdstart1(wd, bp); |
595 | } | | 595 | } |
596 | } | | 596 | } |
597 | | | 597 | |
598 | static void | | 598 | static void |
599 | wd_split_mod15_write(struct buf *bp) | | 599 | wd_split_mod15_write(struct buf *bp) |
600 | { | | 600 | { |
601 | struct buf *obp = bp->b_private; | | 601 | struct buf *obp = bp->b_private; |
602 | struct wd_softc *sc = | | 602 | struct wd_softc *sc = |
603 | device_lookup_private(&wd_cd, DISKUNIT(obp->b_dev)); | | 603 | device_lookup_private(&wd_cd, DISKUNIT(obp->b_dev)); |
604 | int s; | | 604 | int s; |
605 | | | 605 | |
606 | if (__predict_false(bp->b_error != 0)) { | | 606 | if (__predict_false(bp->b_error != 0)) { |
607 | /* | | 607 | /* |
608 | * Propagate the error. If this was the first half of | | 608 | * Propagate the error. If this was the first half of |
609 | * the original transfer, make sure to account for that | | 609 | * the original transfer, make sure to account for that |
610 | * in the residual. | | 610 | * in the residual. |
611 | */ | | 611 | */ |
612 | if (bp->b_data == obp->b_data) | | 612 | if (bp->b_data == obp->b_data) |
613 | bp->b_resid += bp->b_bcount; | | 613 | bp->b_resid += bp->b_bcount; |
614 | goto done; | | 614 | goto done; |
615 | } | | 615 | } |
616 | | | 616 | |
617 | /* | | 617 | /* |
618 | * If this was the second half of the transfer, we're all done! | | 618 | * If this was the second half of the transfer, we're all done! |
619 | */ | | 619 | */ |
620 | if (bp->b_data != obp->b_data) | | 620 | if (bp->b_data != obp->b_data) |
621 | goto done; | | 621 | goto done; |
622 | | | 622 | |
623 | /* | | 623 | /* |
624 | * Advance the pointer to the second half and issue that command | | 624 | * Advance the pointer to the second half and issue that command |
625 | * using the same opening. | | 625 | * using the same opening. |
626 | */ | | 626 | */ |
627 | bp->b_flags = obp->b_flags; | | 627 | bp->b_flags = obp->b_flags; |
628 | bp->b_oflags = obp->b_oflags; | | 628 | bp->b_oflags = obp->b_oflags; |
629 | bp->b_cflags = obp->b_cflags; | | 629 | bp->b_cflags = obp->b_cflags; |
630 | bp->b_data = (char *)bp->b_data + bp->b_bcount; | | 630 | bp->b_data = (char *)bp->b_data + bp->b_bcount; |
631 | bp->b_blkno += (bp->b_bcount / 512); | | 631 | bp->b_blkno += (bp->b_bcount / 512); |
632 | bp->b_rawblkno += (bp->b_bcount / 512); | | 632 | bp->b_rawblkno += (bp->b_bcount / 512); |
633 | s = splbio(); | | 633 | s = splbio(); |
634 | wdstart1(sc, bp); | | 634 | wdstart1(sc, bp); |
635 | splx(s); | | 635 | splx(s); |
636 | return; | | 636 | return; |
637 | | | 637 | |
638 | done: | | 638 | done: |
639 | obp->b_error = bp->b_error; | | 639 | obp->b_error = bp->b_error; |
640 | obp->b_resid = bp->b_resid; | | 640 | obp->b_resid = bp->b_resid; |
641 | s = splbio(); | | 641 | s = splbio(); |
642 | putiobuf(bp); | | 642 | putiobuf(bp); |
643 | biodone(obp); | | 643 | biodone(obp); |
644 | sc->openings++; | | 644 | sc->openings++; |
645 | splx(s); | | 645 | splx(s); |
646 | /* wddone() will call wdstart() */ | | 646 | /* wddone() will call wdstart() */ |
647 | } | | 647 | } |
648 | | | 648 | |
649 | void | | 649 | void |
650 | wdstart1(struct wd_softc *wd, struct buf *bp) | | 650 | wdstart1(struct wd_softc *wd, struct buf *bp) |
651 | { | | 651 | { |
652 | | | 652 | |
653 | /* | | 653 | /* |
654 | * Deal with the "split mod15 write" quirk. We just divide the | | 654 | * Deal with the "split mod15 write" quirk. We just divide the |
655 | * transfer in two, doing the first half and then then second half | | 655 | * transfer in two, doing the first half and then then second half |
656 | * with the same command opening. | | 656 | * with the same command opening. |
657 | * | | 657 | * |
658 | * Note we MUST do this here, because we can't let insertion | | 658 | * Note we MUST do this here, because we can't let insertion |
659 | * into the bufq cause the transfers to be re-merged. | | 659 | * into the bufq cause the transfers to be re-merged. |
660 | */ | | 660 | */ |
661 | if (__predict_false((wd->sc_quirks & WD_QUIRK_SPLIT_MOD15_WRITE) != 0 && | | 661 | if (__predict_false((wd->sc_quirks & WD_QUIRK_SPLIT_MOD15_WRITE) != 0 && |
662 | (bp->b_flags & B_READ) == 0 && | | 662 | (bp->b_flags & B_READ) == 0 && |
663 | bp->b_bcount > 512 && | | 663 | bp->b_bcount > 512 && |
664 | ((bp->b_bcount / 512) % 15) == 1)) { | | 664 | ((bp->b_bcount / 512) % 15) == 1)) { |
665 | struct buf *nbp; | | 665 | struct buf *nbp; |
666 | | | 666 | |
667 | /* already at splbio */ | | 667 | /* already at splbio */ |
668 | nbp = getiobuf(NULL, false); | | 668 | nbp = getiobuf(NULL, false); |
669 | if (__predict_false(nbp == NULL)) { | | 669 | if (__predict_false(nbp == NULL)) { |
670 | /* No memory -- fail the iop. */ | | 670 | /* No memory -- fail the iop. */ |
671 | bp->b_error = ENOMEM; | | 671 | bp->b_error = ENOMEM; |
672 | bp->b_resid = bp->b_bcount; | | 672 | bp->b_resid = bp->b_bcount; |
673 | biodone(bp); | | 673 | biodone(bp); |
674 | wd->openings++; | | 674 | wd->openings++; |
675 | return; | | 675 | return; |
676 | } | | 676 | } |
677 | | | 677 | |
678 | nbp->b_error = 0; | | 678 | nbp->b_error = 0; |
679 | nbp->b_proc = bp->b_proc; | | 679 | nbp->b_proc = bp->b_proc; |
680 | nbp->b_dev = bp->b_dev; | | 680 | nbp->b_dev = bp->b_dev; |
681 | | | 681 | |
682 | nbp->b_bcount = bp->b_bcount / 2; | | 682 | nbp->b_bcount = bp->b_bcount / 2; |
683 | nbp->b_bufsize = bp->b_bcount / 2; | | 683 | nbp->b_bufsize = bp->b_bcount / 2; |
684 | nbp->b_data = bp->b_data; | | 684 | nbp->b_data = bp->b_data; |
685 | | | 685 | |
686 | nbp->b_blkno = bp->b_blkno; | | 686 | nbp->b_blkno = bp->b_blkno; |
687 | nbp->b_rawblkno = bp->b_rawblkno; | | 687 | nbp->b_rawblkno = bp->b_rawblkno; |
688 | | | 688 | |
689 | nbp->b_flags = bp->b_flags; | | 689 | nbp->b_flags = bp->b_flags; |
690 | nbp->b_oflags = bp->b_oflags; | | 690 | nbp->b_oflags = bp->b_oflags; |
691 | nbp->b_cflags = bp->b_cflags; | | 691 | nbp->b_cflags = bp->b_cflags; |
692 | nbp->b_iodone = wd_split_mod15_write; | | 692 | nbp->b_iodone = wd_split_mod15_write; |
693 | | | 693 | |
694 | /* Put ptr to orig buf in b_private and use new buf */ | | 694 | /* Put ptr to orig buf in b_private and use new buf */ |
695 | nbp->b_private = bp; | | 695 | nbp->b_private = bp; |
696 | | | 696 | |
697 | BIO_COPYPRIO(nbp, bp); | | 697 | BIO_COPYPRIO(nbp, bp); |
698 | | | 698 | |
699 | bp = nbp; | | 699 | bp = nbp; |
700 | } | | 700 | } |
701 | | | 701 | |
702 | wd->sc_wdc_bio.blkno = bp->b_rawblkno; | | 702 | wd->sc_wdc_bio.blkno = bp->b_rawblkno; |
703 | wd->sc_wdc_bio.bcount = bp->b_bcount; | | 703 | wd->sc_wdc_bio.bcount = bp->b_bcount; |
704 | wd->sc_wdc_bio.databuf = bp->b_data; | | 704 | wd->sc_wdc_bio.databuf = bp->b_data; |
705 | wd->sc_wdc_bio.blkdone =0; | | 705 | wd->sc_wdc_bio.blkdone =0; |
| | | 706 | KASSERT(bp == wd->sc_bp || wd->sc_bp == NULL); |
706 | wd->sc_bp = bp; | | 707 | wd->sc_bp = bp; |
707 | /* | | 708 | /* |
708 | * If we're retrying, retry in single-sector mode. This will give us | | 709 | * If we're retrying, retry in single-sector mode. This will give us |
709 | * the sector number of the problem, and will eventually allow the | | 710 | * the sector number of the problem, and will eventually allow the |
710 | * transfer to succeed. | | 711 | * transfer to succeed. |
711 | */ | | 712 | */ |
712 | if (wd->retries >= WDIORETRIES_SINGLE) | | 713 | if (wd->retries >= WDIORETRIES_SINGLE) |
713 | wd->sc_wdc_bio.flags = ATA_SINGLE; | | 714 | wd->sc_wdc_bio.flags = ATA_SINGLE; |
714 | else | | 715 | else |
715 | wd->sc_wdc_bio.flags = 0; | | 716 | wd->sc_wdc_bio.flags = 0; |
716 | if (wd->sc_flags & WDF_LBA48 && | | 717 | if (wd->sc_flags & WDF_LBA48 && |
717 | (wd->sc_wdc_bio.blkno + | | 718 | (wd->sc_wdc_bio.blkno + |
718 | wd->sc_wdc_bio.bcount / wd->sc_dk.dk_label->d_secsize) > | | 719 | wd->sc_wdc_bio.bcount / wd->sc_dk.dk_label->d_secsize) > |
719 | wd->sc_capacity28) | | 720 | wd->sc_capacity28) |
720 | wd->sc_wdc_bio.flags |= ATA_LBA48; | | 721 | wd->sc_wdc_bio.flags |= ATA_LBA48; |
721 | if (wd->sc_flags & WDF_LBA) | | 722 | if (wd->sc_flags & WDF_LBA) |
722 | wd->sc_wdc_bio.flags |= ATA_LBA; | | 723 | wd->sc_wdc_bio.flags |= ATA_LBA; |
723 | if (bp->b_flags & B_READ) | | 724 | if (bp->b_flags & B_READ) |
724 | wd->sc_wdc_bio.flags |= ATA_READ; | | 725 | wd->sc_wdc_bio.flags |= ATA_READ; |
725 | /* Instrumentation. */ | | 726 | /* Instrumentation. */ |
726 | disk_busy(&wd->sc_dk); | | 727 | disk_busy(&wd->sc_dk); |
727 | switch (wd->atabus->ata_bio(wd->drvp, &wd->sc_wdc_bio)) { | | 728 | switch (wd->atabus->ata_bio(wd->drvp, &wd->sc_wdc_bio)) { |
728 | case ATACMD_TRY_AGAIN: | | 729 | case ATACMD_TRY_AGAIN: |
729 | callout_reset(&wd->sc_restart_ch, hz, wdrestart, wd); | | 730 | callout_reset(&wd->sc_restart_ch, hz, wdrestart, wd); |
730 | break; | | 731 | break; |
731 | case ATACMD_QUEUED: | | 732 | case ATACMD_QUEUED: |
732 | case ATACMD_COMPLETE: | | 733 | case ATACMD_COMPLETE: |
733 | break; | | 734 | break; |
734 | default: | | 735 | default: |
735 | panic("wdstart1: bad return code from ata_bio()"); | | 736 | panic("wdstart1: bad return code from ata_bio()"); |
736 | } | | 737 | } |
737 | } | | 738 | } |
738 | | | 739 | |
739 | void | | 740 | void |
740 | wddone(void *v) | | 741 | wddone(void *v) |
741 | { | | 742 | { |
742 | struct wd_softc *wd = device_private(v); | | 743 | struct wd_softc *wd = device_private(v); |
743 | struct buf *bp = wd->sc_bp; | | 744 | struct buf *bp = wd->sc_bp; |
744 | const char *errmsg; | | 745 | const char *errmsg; |
745 | int do_perror = 0; | | 746 | int do_perror = 0; |
746 | | | 747 | |
747 | ATADEBUG_PRINT(("wddone %s\n", device_xname(wd->sc_dev)), | | 748 | ATADEBUG_PRINT(("wddone %s\n", device_xname(wd->sc_dev)), |
748 | DEBUG_XFERS); | | 749 | DEBUG_XFERS); |
749 | if (bp == NULL) | | 750 | if (bp == NULL) |
750 | return; | | 751 | return; |
751 | bp->b_resid = wd->sc_wdc_bio.bcount; | | 752 | bp->b_resid = wd->sc_wdc_bio.bcount; |
752 | switch (wd->sc_wdc_bio.error) { | | 753 | switch (wd->sc_wdc_bio.error) { |
753 | case ERR_DMA: | | 754 | case ERR_DMA: |
754 | errmsg = "DMA error"; | | 755 | errmsg = "DMA error"; |
755 | goto retry; | | 756 | goto retry; |
756 | case ERR_DF: | | 757 | case ERR_DF: |
757 | errmsg = "device fault"; | | 758 | errmsg = "device fault"; |
758 | goto retry; | | 759 | goto retry; |
759 | case TIMEOUT: | | 760 | case TIMEOUT: |
760 | errmsg = "device timeout"; | | 761 | errmsg = "device timeout"; |
761 | goto retry; | | 762 | goto retry; |
762 | case ERR_RESET: | | 763 | case ERR_RESET: |
763 | errmsg = "channel reset"; | | 764 | errmsg = "channel reset"; |
764 | goto retry2; | | 765 | goto retry2; |
765 | case ERROR: | | 766 | case ERROR: |
766 | /* Don't care about media change bits */ | | 767 | /* Don't care about media change bits */ |
767 | if (wd->sc_wdc_bio.r_error != 0 && | | 768 | if (wd->sc_wdc_bio.r_error != 0 && |
768 | (wd->sc_wdc_bio.r_error & ~(WDCE_MC | WDCE_MCR)) == 0) | | 769 | (wd->sc_wdc_bio.r_error & ~(WDCE_MC | WDCE_MCR)) == 0) |
769 | goto noerror; | | 770 | goto noerror; |
770 | errmsg = "error"; | | 771 | errmsg = "error"; |
771 | do_perror = 1; | | 772 | do_perror = 1; |
772 | retry: /* Just reset and retry. Can we do more ? */ | | 773 | retry: /* Just reset and retry. Can we do more ? */ |
773 | (*wd->atabus->ata_reset_drive)(wd->drvp, AT_RST_NOCMD); | | 774 | (*wd->atabus->ata_reset_drive)(wd->drvp, AT_RST_NOCMD); |
774 | retry2: | | 775 | retry2: |
775 | diskerr(bp, "wd", errmsg, LOG_PRINTF, | | 776 | diskerr(bp, "wd", errmsg, LOG_PRINTF, |
776 | wd->sc_wdc_bio.blkdone, wd->sc_dk.dk_label); | | 777 | wd->sc_wdc_bio.blkdone, wd->sc_dk.dk_label); |
777 | if (wd->retries < WDIORETRIES) | | 778 | if (wd->retries < WDIORETRIES) |
778 | printf(", retrying"); | | 779 | printf(", retrying"); |
779 | printf("\n"); | | 780 | printf("\n"); |
780 | if (do_perror) | | 781 | if (do_perror) |
781 | wdperror(wd); | | 782 | wdperror(wd); |
782 | if (wd->retries < WDIORETRIES) { | | 783 | if (wd->retries < WDIORETRIES) { |
783 | wd->retries++; | | 784 | wd->retries++; |
784 | callout_reset(&wd->sc_restart_ch, RECOVERYTIME, | | 785 | callout_reset(&wd->sc_restart_ch, RECOVERYTIME, |
785 | wdrestart, wd); | | 786 | wdrestart, wd); |
786 | return; | | 787 | return; |
787 | } | | 788 | } |
788 | | | 789 | |
789 | #ifdef WD_SOFTBADSECT | | 790 | #ifdef WD_SOFTBADSECT |
790 | /* | | 791 | /* |
791 | * Not all errors indicate a failed block but those that do, | | 792 | * Not all errors indicate a failed block but those that do, |
792 | * put the block on the bad-block list for the device. Only | | 793 | * put the block on the bad-block list for the device. Only |
793 | * do this for reads because the drive should do it for writes, | | 794 | * do this for reads because the drive should do it for writes, |
794 | * itself, according to Manuel. | | 795 | * itself, according to Manuel. |
795 | */ | | 796 | */ |
796 | if ((bp->b_flags & B_READ) && | | 797 | if ((bp->b_flags & B_READ) && |
797 | ((wd->drvp->ata_vers >= 4 && wd->sc_wdc_bio.r_error & 64) || | | 798 | ((wd->drvp->ata_vers >= 4 && wd->sc_wdc_bio.r_error & 64) || |
798 | (wd->drvp->ata_vers < 4 && wd->sc_wdc_bio.r_error & 192))) { | | 799 | (wd->drvp->ata_vers < 4 && wd->sc_wdc_bio.r_error & 192))) { |
799 | struct disk_badsectors *dbs; | | 800 | struct disk_badsectors *dbs; |
800 | | | 801 | |
801 | dbs = malloc(sizeof *dbs, M_TEMP, M_WAITOK); | | 802 | dbs = malloc(sizeof *dbs, M_TEMP, M_WAITOK); |
802 | dbs->dbs_min = bp->b_rawblkno; | | 803 | dbs->dbs_min = bp->b_rawblkno; |
803 | dbs->dbs_max = dbs->dbs_min + (bp->b_bcount >> DEV_BSHIFT) - 1; | | 804 | dbs->dbs_max = dbs->dbs_min + (bp->b_bcount >> DEV_BSHIFT) - 1; |
804 | microtime(&dbs->dbs_failedat); | | 805 | microtime(&dbs->dbs_failedat); |
805 | SLIST_INSERT_HEAD(&wd->sc_bslist, dbs, dbs_next); | | 806 | SLIST_INSERT_HEAD(&wd->sc_bslist, dbs, dbs_next); |
806 | wd->sc_bscount++; | | 807 | wd->sc_bscount++; |
807 | } | | 808 | } |
808 | #endif | | 809 | #endif |
809 | bp->b_error = EIO; | | 810 | bp->b_error = EIO; |
810 | break; | | 811 | break; |
811 | case NOERROR: | | 812 | case NOERROR: |
812 | noerror: if ((wd->sc_wdc_bio.flags & ATA_CORR) || wd->retries > 0) | | 813 | noerror: if ((wd->sc_wdc_bio.flags & ATA_CORR) || wd->retries > 0) |
813 | aprint_error_dev(wd->sc_dev, | | 814 | aprint_error_dev(wd->sc_dev, |
814 | "soft error (corrected)\n"); | | 815 | "soft error (corrected)\n"); |
815 | break; | | 816 | break; |
816 | case ERR_NODEV: | | 817 | case ERR_NODEV: |
817 | bp->b_error = EIO; | | 818 | bp->b_error = EIO; |
818 | break; | | 819 | break; |
819 | } | | 820 | } |
820 | disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid), | | 821 | disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid), |
821 | (bp->b_flags & B_READ)); | | 822 | (bp->b_flags & B_READ)); |
822 | #if NRND > 0 | | 823 | #if NRND > 0 |
823 | rnd_add_uint32(&wd->rnd_source, bp->b_blkno); | | 824 | rnd_add_uint32(&wd->rnd_source, bp->b_blkno); |
824 | #endif | | 825 | #endif |
825 | /* XXX Yuck, but we don't want to increment openings in this case */ | | 826 | /* XXX Yuck, but we don't want to increment openings in this case */ |
826 | if (__predict_false(bp->b_iodone == wd_split_mod15_write)) | | 827 | if (__predict_false(bp->b_iodone == wd_split_mod15_write)) |
827 | biodone(bp); | | 828 | biodone(bp); |
828 | else { | | 829 | else { |
829 | biodone(bp); | | 830 | biodone(bp); |
830 | wd->openings++; | | 831 | wd->openings++; |
831 | } | | 832 | } |
| | | 833 | KASSERT(wd->sc_bp != NULL); |
| | | 834 | wd->sc_bp = NULL; |
832 | wdstart(wd); | | 835 | wdstart(wd); |
833 | } | | 836 | } |
834 | | | 837 | |
835 | void | | 838 | void |
836 | wdrestart(void *v) | | 839 | wdrestart(void *v) |
837 | { | | 840 | { |
838 | struct wd_softc *wd = v; | | 841 | struct wd_softc *wd = v; |
839 | struct buf *bp = wd->sc_bp; | | 842 | struct buf *bp = wd->sc_bp; |
840 | int s; | | 843 | int s; |
841 | | | 844 | |
842 | ATADEBUG_PRINT(("wdrestart %s\n", device_xname(wd->sc_dev)), | | 845 | ATADEBUG_PRINT(("wdrestart %s\n", device_xname(wd->sc_dev)), |
843 | DEBUG_XFERS); | | 846 | DEBUG_XFERS); |
844 | s = splbio(); | | 847 | s = splbio(); |
845 | wdstart1(v, bp); | | 848 | wdstart1(v, bp); |
846 | splx(s); | | 849 | splx(s); |
847 | } | | 850 | } |
848 | | | 851 | |
849 | int | | 852 | int |
850 | wdread(dev_t dev, struct uio *uio, int flags) | | 853 | wdread(dev_t dev, struct uio *uio, int flags) |
851 | { | | 854 | { |
852 | | | 855 | |
853 | ATADEBUG_PRINT(("wdread\n"), DEBUG_XFERS); | | 856 | ATADEBUG_PRINT(("wdread\n"), DEBUG_XFERS); |
854 | return (physio(wdstrategy, NULL, dev, B_READ, minphys, uio)); | | 857 | return (physio(wdstrategy, NULL, dev, B_READ, minphys, uio)); |
855 | } | | 858 | } |
856 | | | 859 | |
857 | int | | 860 | int |
858 | wdwrite(dev_t dev, struct uio *uio, int flags) | | 861 | wdwrite(dev_t dev, struct uio *uio, int flags) |
859 | { | | 862 | { |
860 | | | 863 | |
861 | ATADEBUG_PRINT(("wdwrite\n"), DEBUG_XFERS); | | 864 | ATADEBUG_PRINT(("wdwrite\n"), DEBUG_XFERS); |
862 | return (physio(wdstrategy, NULL, dev, B_WRITE, minphys, uio)); | | 865 | return (physio(wdstrategy, NULL, dev, B_WRITE, minphys, uio)); |
863 | } | | 866 | } |
864 | | | 867 | |
865 | int | | 868 | int |
866 | wdopen(dev_t dev, int flag, int fmt, struct lwp *l) | | 869 | wdopen(dev_t dev, int flag, int fmt, struct lwp *l) |
867 | { | | 870 | { |
868 | struct wd_softc *wd; | | 871 | struct wd_softc *wd; |
869 | int part, error; | | 872 | int part, error; |
870 | | | 873 | |
871 | ATADEBUG_PRINT(("wdopen\n"), DEBUG_FUNCS); | | 874 | ATADEBUG_PRINT(("wdopen\n"), DEBUG_FUNCS); |
872 | wd = device_lookup_private(&wd_cd, WDUNIT(dev)); | | 875 | wd = device_lookup_private(&wd_cd, WDUNIT(dev)); |
873 | if (wd == NULL) | | 876 | if (wd == NULL) |
874 | return (ENXIO); | | 877 | return (ENXIO); |
875 | | | 878 | |
876 | if (! device_is_active(wd->sc_dev)) | | 879 | if (! device_is_active(wd->sc_dev)) |
877 | return (ENODEV); | | 880 | return (ENODEV); |
878 | | | 881 | |
879 | part = WDPART(dev); | | 882 | part = WDPART(dev); |
880 | | | 883 | |
881 | mutex_enter(&wd->sc_dk.dk_openlock); | | 884 | mutex_enter(&wd->sc_dk.dk_openlock); |
882 | | | 885 | |
883 | /* | | 886 | /* |
884 | * If there are wedges, and this is not RAW_PART, then we | | 887 | * If there are wedges, and this is not RAW_PART, then we |
885 | * need to fail. | | 888 | * need to fail. |
886 | */ | | 889 | */ |
887 | if (wd->sc_dk.dk_nwedges != 0 && part != RAW_PART) { | | 890 | if (wd->sc_dk.dk_nwedges != 0 && part != RAW_PART) { |
888 | error = EBUSY; | | 891 | error = EBUSY; |
889 | goto bad1; | | 892 | goto bad1; |
890 | } | | 893 | } |
891 | | | 894 | |
892 | /* | | 895 | /* |
893 | * If this is the first open of this device, add a reference | | 896 | * If this is the first open of this device, add a reference |
894 | * to the adapter. | | 897 | * to the adapter. |
895 | */ | | 898 | */ |
896 | if (wd->sc_dk.dk_openmask == 0 && | | 899 | if (wd->sc_dk.dk_openmask == 0 && |
897 | (error = wd->atabus->ata_addref(wd->drvp)) != 0) | | 900 | (error = wd->atabus->ata_addref(wd->drvp)) != 0) |
898 | goto bad1; | | 901 | goto bad1; |
899 | | | 902 | |
900 | if (wd->sc_dk.dk_openmask != 0) { | | 903 | if (wd->sc_dk.dk_openmask != 0) { |
901 | /* | | 904 | /* |
902 | * If any partition is open, but the disk has been invalidated, | | 905 | * If any partition is open, but the disk has been invalidated, |
903 | * disallow further opens. | | 906 | * disallow further opens. |
904 | */ | | 907 | */ |
905 | if ((wd->sc_flags & WDF_LOADED) == 0) { | | 908 | if ((wd->sc_flags & WDF_LOADED) == 0) { |
906 | error = EIO; | | 909 | error = EIO; |
907 | goto bad2; | | 910 | goto bad2; |
908 | } | | 911 | } |
909 | } else { | | 912 | } else { |
910 | if ((wd->sc_flags & WDF_LOADED) == 0) { | | 913 | if ((wd->sc_flags & WDF_LOADED) == 0) { |
911 | wd->sc_flags |= WDF_LOADED; | | 914 | wd->sc_flags |= WDF_LOADED; |
912 | | | 915 | |
913 | /* Load the physical device parameters. */ | | 916 | /* Load the physical device parameters. */ |
914 | wd_get_params(wd, AT_WAIT, &wd->sc_params); | | 917 | wd_get_params(wd, AT_WAIT, &wd->sc_params); |
915 | | | 918 | |
916 | /* Load the partition info if not already loaded. */ | | 919 | /* Load the partition info if not already loaded. */ |
917 | wdgetdisklabel(wd); | | 920 | wdgetdisklabel(wd); |
918 | } | | 921 | } |
919 | } | | 922 | } |
920 | | | 923 | |
921 | /* Check that the partition exists. */ | | 924 | /* Check that the partition exists. */ |
922 | if (part != RAW_PART && | | 925 | if (part != RAW_PART && |
923 | (part >= wd->sc_dk.dk_label->d_npartitions || | | 926 | (part >= wd->sc_dk.dk_label->d_npartitions || |
924 | wd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { | | 927 | wd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { |
925 | error = ENXIO; | | 928 | error = ENXIO; |
926 | goto bad2; | | 929 | goto bad2; |
927 | } | | 930 | } |
928 | | | 931 | |
929 | /* Insure only one open at a time. */ | | 932 | /* Insure only one open at a time. */ |
930 | switch (fmt) { | | 933 | switch (fmt) { |
931 | case S_IFCHR: | | 934 | case S_IFCHR: |
932 | wd->sc_dk.dk_copenmask |= (1 << part); | | 935 | wd->sc_dk.dk_copenmask |= (1 << part); |
933 | break; | | 936 | break; |
934 | case S_IFBLK: | | 937 | case S_IFBLK: |
935 | wd->sc_dk.dk_bopenmask |= (1 << part); | | 938 | wd->sc_dk.dk_bopenmask |= (1 << part); |
936 | break; | | 939 | break; |
937 | } | | 940 | } |
938 | wd->sc_dk.dk_openmask = | | 941 | wd->sc_dk.dk_openmask = |
939 | wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; | | 942 | wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; |
940 | | | 943 | |
941 | mutex_exit(&wd->sc_dk.dk_openlock); | | 944 | mutex_exit(&wd->sc_dk.dk_openlock); |
942 | return 0; | | 945 | return 0; |
943 | | | 946 | |
944 | bad2: | | 947 | bad2: |
945 | if (wd->sc_dk.dk_openmask == 0) | | 948 | if (wd->sc_dk.dk_openmask == 0) |
946 | wd->atabus->ata_delref(wd->drvp); | | 949 | wd->atabus->ata_delref(wd->drvp); |
947 | bad1: | | 950 | bad1: |
948 | mutex_exit(&wd->sc_dk.dk_openlock); | | 951 | mutex_exit(&wd->sc_dk.dk_openlock); |
949 | return error; | | 952 | return error; |
950 | } | | 953 | } |
951 | | | 954 | |
952 | /* | | 955 | /* |
953 | * Caller must hold wd->sc_dk.dk_openlock. | | 956 | * Caller must hold wd->sc_dk.dk_openlock. |
954 | */ | | 957 | */ |
955 | static int | | 958 | static int |
956 | wdlastclose(device_t self) | | 959 | wdlastclose(device_t self) |
957 | { | | 960 | { |
958 | struct wd_softc *wd = device_private(self); | | 961 | struct wd_softc *wd = device_private(self); |
959 | | | 962 | |
960 | wd_flushcache(wd, AT_WAIT); | | 963 | wd_flushcache(wd, AT_WAIT); |
961 | | | 964 | |
962 | if (! (wd->sc_flags & WDF_KLABEL)) | | 965 | if (! (wd->sc_flags & WDF_KLABEL)) |
963 | wd->sc_flags &= ~WDF_LOADED; | | 966 | wd->sc_flags &= ~WDF_LOADED; |
964 | | | 967 | |
965 | wd->atabus->ata_delref(wd->drvp); | | 968 | wd->atabus->ata_delref(wd->drvp); |
966 | | | 969 | |
967 | return 0; | | 970 | return 0; |
968 | } | | 971 | } |
969 | | | 972 | |
970 | int | | 973 | int |
971 | wdclose(dev_t dev, int flag, int fmt, struct lwp *l) | | 974 | wdclose(dev_t dev, int flag, int fmt, struct lwp *l) |
972 | { | | 975 | { |
973 | struct wd_softc *wd = | | 976 | struct wd_softc *wd = |
974 | device_lookup_private(&wd_cd, WDUNIT(dev)); | | 977 | device_lookup_private(&wd_cd, WDUNIT(dev)); |
975 | int part = WDPART(dev); | | 978 | int part = WDPART(dev); |
976 | | | 979 | |
977 | ATADEBUG_PRINT(("wdclose\n"), DEBUG_FUNCS); | | 980 | ATADEBUG_PRINT(("wdclose\n"), DEBUG_FUNCS); |
978 | | | 981 | |
979 | mutex_enter(&wd->sc_dk.dk_openlock); | | 982 | mutex_enter(&wd->sc_dk.dk_openlock); |
980 | | | 983 | |
981 | switch (fmt) { | | 984 | switch (fmt) { |
982 | case S_IFCHR: | | 985 | case S_IFCHR: |
983 | wd->sc_dk.dk_copenmask &= ~(1 << part); | | 986 | wd->sc_dk.dk_copenmask &= ~(1 << part); |
984 | break; | | 987 | break; |
985 | case S_IFBLK: | | 988 | case S_IFBLK: |
986 | wd->sc_dk.dk_bopenmask &= ~(1 << part); | | 989 | wd->sc_dk.dk_bopenmask &= ~(1 << part); |
987 | break; | | 990 | break; |
988 | } | | 991 | } |
989 | wd->sc_dk.dk_openmask = | | 992 | wd->sc_dk.dk_openmask = |
990 | wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; | | 993 | wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; |
991 | | | 994 | |
992 | if (wd->sc_dk.dk_openmask == 0) | | 995 | if (wd->sc_dk.dk_openmask == 0) |
993 | wdlastclose(wd->sc_dev); | | 996 | wdlastclose(wd->sc_dev); |
994 | | | 997 | |
995 | mutex_exit(&wd->sc_dk.dk_openlock); | | 998 | mutex_exit(&wd->sc_dk.dk_openlock); |
996 | return 0; | | 999 | return 0; |
997 | } | | 1000 | } |
998 | | | 1001 | |
999 | void | | 1002 | void |
1000 | wdgetdefaultlabel(struct wd_softc *wd, struct disklabel *lp) | | 1003 | wdgetdefaultlabel(struct wd_softc *wd, struct disklabel *lp) |
1001 | { | | 1004 | { |
1002 | | | 1005 | |
1003 | ATADEBUG_PRINT(("wdgetdefaultlabel\n"), DEBUG_FUNCS); | | 1006 | ATADEBUG_PRINT(("wdgetdefaultlabel\n"), DEBUG_FUNCS); |
1004 | memset(lp, 0, sizeof(struct disklabel)); | | 1007 | memset(lp, 0, sizeof(struct disklabel)); |
1005 | | | 1008 | |
1006 | lp->d_secsize = DEV_BSIZE; | | 1009 | lp->d_secsize = DEV_BSIZE; |
1007 | lp->d_ntracks = wd->sc_params.atap_heads; | | 1010 | lp->d_ntracks = wd->sc_params.atap_heads; |
1008 | lp->d_nsectors = wd->sc_params.atap_sectors; | | 1011 | lp->d_nsectors = wd->sc_params.atap_sectors; |
1009 | lp->d_ncylinders = (wd->sc_flags & WDF_LBA) ? wd->sc_capacity / | | 1012 | lp->d_ncylinders = (wd->sc_flags & WDF_LBA) ? wd->sc_capacity / |
1010 | (wd->sc_params.atap_heads * wd->sc_params.atap_sectors) : | | 1013 | (wd->sc_params.atap_heads * wd->sc_params.atap_sectors) : |
1011 | wd->sc_params.atap_cylinders; | | 1014 | wd->sc_params.atap_cylinders; |
1012 | lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; | | 1015 | lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; |
1013 | | | 1016 | |
1014 | if (strcmp(wd->sc_params.atap_model, "ST506") == 0) | | 1017 | if (strcmp(wd->sc_params.atap_model, "ST506") == 0) |
1015 | lp->d_type = DTYPE_ST506; | | 1018 | lp->d_type = DTYPE_ST506; |
1016 | else | | 1019 | else |
1017 | lp->d_type = DTYPE_ESDI; | | 1020 | lp->d_type = DTYPE_ESDI; |
1018 | | | 1021 | |
1019 | strncpy(lp->d_typename, wd->sc_params.atap_model, 16); | | 1022 | strncpy(lp->d_typename, wd->sc_params.atap_model, 16); |
1020 | strncpy(lp->d_packname, "fictitious", 16); | | 1023 | strncpy(lp->d_packname, "fictitious", 16); |
1021 | if (wd->sc_capacity > UINT32_MAX) | | 1024 | if (wd->sc_capacity > UINT32_MAX) |
1022 | lp->d_secperunit = UINT32_MAX; | | 1025 | lp->d_secperunit = UINT32_MAX; |
1023 | else | | 1026 | else |
1024 | lp->d_secperunit = wd->sc_capacity; | | 1027 | lp->d_secperunit = wd->sc_capacity; |
1025 | lp->d_rpm = 3600; | | 1028 | lp->d_rpm = 3600; |
1026 | lp->d_interleave = 1; | | 1029 | lp->d_interleave = 1; |
1027 | lp->d_flags = 0; | | 1030 | lp->d_flags = 0; |
1028 | | | 1031 | |
1029 | lp->d_partitions[RAW_PART].p_offset = 0; | | 1032 | lp->d_partitions[RAW_PART].p_offset = 0; |
1030 | lp->d_partitions[RAW_PART].p_size = | | 1033 | lp->d_partitions[RAW_PART].p_size = |
1031 | lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); | | 1034 | lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); |
1032 | lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; | | 1035 | lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; |
1033 | lp->d_npartitions = RAW_PART + 1; | | 1036 | lp->d_npartitions = RAW_PART + 1; |
1034 | | | 1037 | |
1035 | lp->d_magic = DISKMAGIC; | | 1038 | lp->d_magic = DISKMAGIC; |
1036 | lp->d_magic2 = DISKMAGIC; | | 1039 | lp->d_magic2 = DISKMAGIC; |
1037 | lp->d_checksum = dkcksum(lp); | | 1040 | lp->d_checksum = dkcksum(lp); |
1038 | } | | 1041 | } |
1039 | | | 1042 | |
1040 | /* | | 1043 | /* |
1041 | * Fabricate a default disk label, and try to read the correct one. | | 1044 | * Fabricate a default disk label, and try to read the correct one. |
1042 | */ | | 1045 | */ |
1043 | void | | 1046 | void |
1044 | wdgetdisklabel(struct wd_softc *wd) | | 1047 | wdgetdisklabel(struct wd_softc *wd) |
1045 | { | | 1048 | { |
1046 | struct disklabel *lp = wd->sc_dk.dk_label; | | 1049 | struct disklabel *lp = wd->sc_dk.dk_label; |
1047 | const char *errstring; | | 1050 | const char *errstring; |
1048 | int s; | | 1051 | int s; |
1049 | | | 1052 | |
1050 | ATADEBUG_PRINT(("wdgetdisklabel\n"), DEBUG_FUNCS); | | 1053 | ATADEBUG_PRINT(("wdgetdisklabel\n"), DEBUG_FUNCS); |
1051 | | | 1054 | |
1052 | memset(wd->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel)); | | 1055 | memset(wd->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel)); |
1053 | | | 1056 | |
1054 | wdgetdefaultlabel(wd, lp); | | 1057 | wdgetdefaultlabel(wd, lp); |
1055 | | | 1058 | |
1056 | wd->sc_badsect[0] = -1; | | 1059 | wd->sc_badsect[0] = -1; |
1057 | | | 1060 | |
1058 | if (wd->drvp->state > RESET) { | | 1061 | if (wd->drvp->state > RESET) { |
1059 | s = splbio(); | | 1062 | s = splbio(); |
1060 | wd->drvp->drive_flags |= DRIVE_RESET; | | 1063 | wd->drvp->drive_flags |= DRIVE_RESET; |
1061 | splx(s); | | 1064 | splx(s); |
1062 | } | | 1065 | } |
1063 | errstring = readdisklabel(MAKEWDDEV(0, device_unit(wd->sc_dev), | | 1066 | errstring = readdisklabel(MAKEWDDEV(0, device_unit(wd->sc_dev), |
1064 | RAW_PART), wdstrategy, lp, | | 1067 | RAW_PART), wdstrategy, lp, |
1065 | wd->sc_dk.dk_cpulabel); | | 1068 | wd->sc_dk.dk_cpulabel); |
1066 | if (errstring) { | | 1069 | if (errstring) { |
1067 | /* | | 1070 | /* |
1068 | * This probably happened because the drive's default | | 1071 | * This probably happened because the drive's default |
1069 | * geometry doesn't match the DOS geometry. We | | 1072 | * geometry doesn't match the DOS geometry. We |
1070 | * assume the DOS geometry is now in the label and try | | 1073 | * assume the DOS geometry is now in the label and try |
1071 | * again. XXX This is a kluge. | | 1074 | * again. XXX This is a kluge. |
1072 | */ | | 1075 | */ |
1073 | if (wd->drvp->state > RESET) { | | 1076 | if (wd->drvp->state > RESET) { |
1074 | s = splbio(); | | 1077 | s = splbio(); |
1075 | wd->drvp->drive_flags |= DRIVE_RESET; | | 1078 | wd->drvp->drive_flags |= DRIVE_RESET; |
1076 | splx(s); | | 1079 | splx(s); |
1077 | } | | 1080 | } |
1078 | errstring = readdisklabel(MAKEWDDEV(0, device_unit(wd->sc_dev), | | 1081 | errstring = readdisklabel(MAKEWDDEV(0, device_unit(wd->sc_dev), |
1079 | RAW_PART), wdstrategy, lp, wd->sc_dk.dk_cpulabel); | | 1082 | RAW_PART), wdstrategy, lp, wd->sc_dk.dk_cpulabel); |
1080 | } | | 1083 | } |
1081 | if (errstring) { | | 1084 | if (errstring) { |
1082 | aprint_error_dev(wd->sc_dev, "%s\n", errstring); | | 1085 | aprint_error_dev(wd->sc_dev, "%s\n", errstring); |
1083 | return; | | 1086 | return; |
1084 | } | | 1087 | } |
1085 | | | 1088 | |
1086 | if (wd->drvp->state > RESET) { | | 1089 | if (wd->drvp->state > RESET) { |
1087 | s = splbio(); | | 1090 | s = splbio(); |
1088 | wd->drvp->drive_flags |= DRIVE_RESET; | | 1091 | wd->drvp->drive_flags |= DRIVE_RESET; |
1089 | splx(s); | | 1092 | splx(s); |
1090 | } | | 1093 | } |
1091 | #ifdef HAS_BAD144_HANDLING | | 1094 | #ifdef HAS_BAD144_HANDLING |
1092 | if ((lp->d_flags & D_BADSECT) != 0) | | 1095 | if ((lp->d_flags & D_BADSECT) != 0) |
1093 | bad144intern(wd); | | 1096 | bad144intern(wd); |
1094 | #endif | | 1097 | #endif |
1095 | } | | 1098 | } |
1096 | | | 1099 | |
1097 | void | | 1100 | void |
1098 | wdperror(const struct wd_softc *wd) | | 1101 | wdperror(const struct wd_softc *wd) |
1099 | { | | 1102 | { |
1100 | static const char *const errstr0_3[] = {"address mark not found", | | 1103 | static const char *const errstr0_3[] = {"address mark not found", |
1101 | "track 0 not found", "aborted command", "media change requested", | | 1104 | "track 0 not found", "aborted command", "media change requested", |
1102 | "id not found", "media changed", "uncorrectable data error", | | 1105 | "id not found", "media changed", "uncorrectable data error", |
1103 | "bad block detected"}; | | 1106 | "bad block detected"}; |
1104 | static const char *const errstr4_5[] = { | | 1107 | static const char *const errstr4_5[] = { |
1105 | "obsolete (address mark not found)", | | 1108 | "obsolete (address mark not found)", |
1106 | "no media/write protected", "aborted command", | | 1109 | "no media/write protected", "aborted command", |
1107 | "media change requested", "id not found", "media changed", | | 1110 | "media change requested", "id not found", "media changed", |
1108 | "uncorrectable data error", "interface CRC error"}; | | 1111 | "uncorrectable data error", "interface CRC error"}; |
1109 | const char *const *errstr; | | 1112 | const char *const *errstr; |
1110 | int i; | | 1113 | int i; |
1111 | const char *sep = ""; | | 1114 | const char *sep = ""; |
1112 | | | 1115 | |
1113 | const char *devname = device_xname(wd->sc_dev); | | 1116 | const char *devname = device_xname(wd->sc_dev); |
1114 | struct ata_drive_datas *drvp = wd->drvp; | | 1117 | struct ata_drive_datas *drvp = wd->drvp; |
1115 | int errno = wd->sc_wdc_bio.r_error; | | 1118 | int errno = wd->sc_wdc_bio.r_error; |
1116 | | | 1119 | |
1117 | if (drvp->ata_vers >= 4) | | 1120 | if (drvp->ata_vers >= 4) |
1118 | errstr = errstr4_5; | | 1121 | errstr = errstr4_5; |
1119 | else | | 1122 | else |
1120 | errstr = errstr0_3; | | 1123 | errstr = errstr0_3; |
1121 | | | 1124 | |
1122 | printf("%s: (", devname); | | 1125 | printf("%s: (", devname); |
1123 | | | 1126 | |
1124 | if (errno == 0) | | 1127 | if (errno == 0) |
1125 | printf("error not notified"); | | 1128 | printf("error not notified"); |
1126 | | | 1129 | |
1127 | for (i = 0; i < 8; i++) { | | 1130 | for (i = 0; i < 8; i++) { |
1128 | if (errno & (1 << i)) { | | 1131 | if (errno & (1 << i)) { |
1129 | printf("%s%s", sep, errstr[i]); | | 1132 | printf("%s%s", sep, errstr[i]); |
1130 | sep = ", "; | | 1133 | sep = ", "; |
1131 | } | | 1134 | } |
1132 | } | | 1135 | } |
1133 | printf(")\n"); | | 1136 | printf(")\n"); |
1134 | } | | 1137 | } |
1135 | | | 1138 | |
1136 | int | | 1139 | int |
1137 | wdioctl(dev_t dev, u_long xfer, void *addr, int flag, struct lwp *l) | | 1140 | wdioctl(dev_t dev, u_long xfer, void *addr, int flag, struct lwp *l) |
1138 | { | | 1141 | { |
1139 | struct wd_softc *wd = | | 1142 | struct wd_softc *wd = |
1140 | device_lookup_private(&wd_cd, WDUNIT(dev)); | | 1143 | device_lookup_private(&wd_cd, WDUNIT(dev)); |
1141 | int error = 0, s; | | 1144 | int error = 0, s; |
1142 | #ifdef __HAVE_OLD_DISKLABEL | | 1145 | #ifdef __HAVE_OLD_DISKLABEL |
1143 | struct disklabel *newlabel = NULL; | | 1146 | struct disklabel *newlabel = NULL; |
1144 | #endif | | 1147 | #endif |
1145 | | | 1148 | |
1146 | ATADEBUG_PRINT(("wdioctl\n"), DEBUG_FUNCS); | | 1149 | ATADEBUG_PRINT(("wdioctl\n"), DEBUG_FUNCS); |
1147 | | | 1150 | |
1148 | if ((wd->sc_flags & WDF_LOADED) == 0) | | 1151 | if ((wd->sc_flags & WDF_LOADED) == 0) |
1149 | return EIO; | | 1152 | return EIO; |
1150 | | | 1153 | |
1151 | error = disk_ioctl(&wd->sc_dk, xfer, addr, flag, l); | | 1154 | error = disk_ioctl(&wd->sc_dk, xfer, addr, flag, l); |
1152 | if (error != EPASSTHROUGH) | | 1155 | if (error != EPASSTHROUGH) |
1153 | return (error); | | 1156 | return (error); |
1154 | | | 1157 | |
1155 | switch (xfer) { | | 1158 | switch (xfer) { |
1156 | #ifdef HAS_BAD144_HANDLING | | 1159 | #ifdef HAS_BAD144_HANDLING |
1157 | case DIOCSBAD: | | 1160 | case DIOCSBAD: |
1158 | if ((flag & FWRITE) == 0) | | 1161 | if ((flag & FWRITE) == 0) |
1159 | return EBADF; | | 1162 | return EBADF; |
1160 | wd->sc_dk.dk_cpulabel->bad = *(struct dkbad *)addr; | | 1163 | wd->sc_dk.dk_cpulabel->bad = *(struct dkbad *)addr; |
1161 | wd->sc_dk.dk_label->d_flags |= D_BADSECT; | | 1164 | wd->sc_dk.dk_label->d_flags |= D_BADSECT; |
1162 | bad144intern(wd); | | 1165 | bad144intern(wd); |
1163 | return 0; | | 1166 | return 0; |
1164 | #endif | | 1167 | #endif |
1165 | #ifdef WD_SOFTBADSECT | | 1168 | #ifdef WD_SOFTBADSECT |
1166 | case DIOCBSLIST : | | 1169 | case DIOCBSLIST : |
1167 | { | | 1170 | { |
1168 | u_int32_t count, missing, skip; | | 1171 | u_int32_t count, missing, skip; |
1169 | struct disk_badsecinfo dbsi; | | 1172 | struct disk_badsecinfo dbsi; |
1170 | struct disk_badsectors *dbs; | | 1173 | struct disk_badsectors *dbs; |
1171 | size_t available; | | 1174 | size_t available; |
1172 | uint8_t *laddr; | | 1175 | uint8_t *laddr; |
1173 | | | 1176 | |
1174 | dbsi = *(struct disk_badsecinfo *)addr; | | 1177 | dbsi = *(struct disk_badsecinfo *)addr; |
1175 | missing = wd->sc_bscount; | | 1178 | missing = wd->sc_bscount; |
1176 | count = 0; | | 1179 | count = 0; |
1177 | available = dbsi.dbsi_bufsize; | | 1180 | available = dbsi.dbsi_bufsize; |
1178 | skip = dbsi.dbsi_skip; | | 1181 | skip = dbsi.dbsi_skip; |
1179 | laddr = (uint8_t *)dbsi.dbsi_buffer; | | 1182 | laddr = (uint8_t *)dbsi.dbsi_buffer; |
1180 | | | 1183 | |
1181 | /* | | 1184 | /* |
1182 | * We start this loop with the expectation that all of the | | 1185 | * We start this loop with the expectation that all of the |
1183 | * entries will be missed and decrement this counter each | | 1186 | * entries will be missed and decrement this counter each |
1184 | * time we either skip over one (already copied out) or | | 1187 | * time we either skip over one (already copied out) or |
1185 | * we actually copy it back to user space. The structs | | 1188 | * we actually copy it back to user space. The structs |
1186 | * holding the bad sector information are copied directly | | 1189 | * holding the bad sector information are copied directly |
1187 | * back to user space whilst the summary is returned via | | 1190 | * back to user space whilst the summary is returned via |
1188 | * the struct passed in via the ioctl. | | 1191 | * the struct passed in via the ioctl. |
1189 | */ | | 1192 | */ |
1190 | SLIST_FOREACH(dbs, &wd->sc_bslist, dbs_next) { | | 1193 | SLIST_FOREACH(dbs, &wd->sc_bslist, dbs_next) { |
1191 | if (skip > 0) { | | 1194 | if (skip > 0) { |
1192 | missing--; | | 1195 | missing--; |
1193 | skip--; | | 1196 | skip--; |
1194 | continue; | | 1197 | continue; |
1195 | } | | 1198 | } |
1196 | if (available < sizeof(*dbs)) | | 1199 | if (available < sizeof(*dbs)) |
1197 | break; | | 1200 | break; |
1198 | available -= sizeof(*dbs); | | 1201 | available -= sizeof(*dbs); |
1199 | copyout(dbs, laddr, sizeof(*dbs)); | | 1202 | copyout(dbs, laddr, sizeof(*dbs)); |
1200 | laddr += sizeof(*dbs); | | 1203 | laddr += sizeof(*dbs); |
1201 | missing--; | | 1204 | missing--; |
1202 | count++; | | 1205 | count++; |
1203 | } | | 1206 | } |
1204 | dbsi.dbsi_left = missing; | | 1207 | dbsi.dbsi_left = missing; |
1205 | dbsi.dbsi_copied = count; | | 1208 | dbsi.dbsi_copied = count; |
1206 | *(struct disk_badsecinfo *)addr = dbsi; | | 1209 | *(struct disk_badsecinfo *)addr = dbsi; |
1207 | return 0; | | 1210 | return 0; |
1208 | } | | 1211 | } |
1209 | | | 1212 | |
1210 | case DIOCBSFLUSH : | | 1213 | case DIOCBSFLUSH : |
1211 | /* Clean out the bad sector list */ | | 1214 | /* Clean out the bad sector list */ |
1212 | while (!SLIST_EMPTY(&wd->sc_bslist)) { | | 1215 | while (!SLIST_EMPTY(&wd->sc_bslist)) { |
1213 | void *head = SLIST_FIRST(&wd->sc_bslist); | | 1216 | void *head = SLIST_FIRST(&wd->sc_bslist); |
1214 | SLIST_REMOVE_HEAD(&wd->sc_bslist, dbs_next); | | 1217 | SLIST_REMOVE_HEAD(&wd->sc_bslist, dbs_next); |
1215 | free(head, M_TEMP); | | 1218 | free(head, M_TEMP); |
1216 | } | | 1219 | } |
1217 | wd->sc_bscount = 0; | | 1220 | wd->sc_bscount = 0; |
1218 | return 0; | | 1221 | return 0; |
1219 | #endif | | 1222 | #endif |
1220 | case DIOCGDINFO: | | 1223 | case DIOCGDINFO: |
1221 | *(struct disklabel *)addr = *(wd->sc_dk.dk_label); | | 1224 | *(struct disklabel *)addr = *(wd->sc_dk.dk_label); |
1222 | return 0; | | 1225 | return 0; |
1223 | #ifdef __HAVE_OLD_DISKLABEL | | 1226 | #ifdef __HAVE_OLD_DISKLABEL |
1224 | case ODIOCGDINFO: | | 1227 | case ODIOCGDINFO: |
1225 | newlabel = malloc(sizeof *newlabel, M_TEMP, M_WAITOK); | | 1228 | newlabel = malloc(sizeof *newlabel, M_TEMP, M_WAITOK); |
1226 | if (newlabel == NULL) | | 1229 | if (newlabel == NULL) |
1227 | return EIO; | | 1230 | return EIO; |
1228 | *newlabel = *(wd->sc_dk.dk_label); | | 1231 | *newlabel = *(wd->sc_dk.dk_label); |
1229 | if (newlabel->d_npartitions <= OLDMAXPARTITIONS) | | 1232 | if (newlabel->d_npartitions <= OLDMAXPARTITIONS) |
1230 | memcpy(addr, newlabel, sizeof (struct olddisklabel)); | | 1233 | memcpy(addr, newlabel, sizeof (struct olddisklabel)); |
1231 | else | | 1234 | else |
1232 | error = ENOTTY; | | 1235 | error = ENOTTY; |
1233 | free(newlabel, M_TEMP); | | 1236 | free(newlabel, M_TEMP); |
1234 | return error; | | 1237 | return error; |
1235 | #endif | | 1238 | #endif |
1236 | | | 1239 | |
1237 | case DIOCGPART: | | 1240 | case DIOCGPART: |
1238 | ((struct partinfo *)addr)->disklab = wd->sc_dk.dk_label; | | 1241 | ((struct partinfo *)addr)->disklab = wd->sc_dk.dk_label; |
1239 | ((struct partinfo *)addr)->part = | | 1242 | ((struct partinfo *)addr)->part = |
1240 | &wd->sc_dk.dk_label->d_partitions[WDPART(dev)]; | | 1243 | &wd->sc_dk.dk_label->d_partitions[WDPART(dev)]; |
1241 | return 0; | | 1244 | return 0; |
1242 | | | 1245 | |
1243 | case DIOCWDINFO: | | 1246 | case DIOCWDINFO: |
1244 | case DIOCSDINFO: | | 1247 | case DIOCSDINFO: |
1245 | #ifdef __HAVE_OLD_DISKLABEL | | 1248 | #ifdef __HAVE_OLD_DISKLABEL |
1246 | case ODIOCWDINFO: | | 1249 | case ODIOCWDINFO: |
1247 | case ODIOCSDINFO: | | 1250 | case ODIOCSDINFO: |
1248 | #endif | | 1251 | #endif |
1249 | { | | 1252 | { |
1250 | struct disklabel *lp; | | 1253 | struct disklabel *lp; |
1251 | | | 1254 | |
1252 | if ((flag & FWRITE) == 0) | | 1255 | if ((flag & FWRITE) == 0) |
1253 | return EBADF; | | 1256 | return EBADF; |
1254 | | | 1257 | |
1255 | #ifdef __HAVE_OLD_DISKLABEL | | 1258 | #ifdef __HAVE_OLD_DISKLABEL |
1256 | if (xfer == ODIOCSDINFO || xfer == ODIOCWDINFO) { | | 1259 | if (xfer == ODIOCSDINFO || xfer == ODIOCWDINFO) { |
1257 | newlabel = malloc(sizeof *newlabel, M_TEMP, M_WAITOK); | | 1260 | newlabel = malloc(sizeof *newlabel, M_TEMP, M_WAITOK); |
1258 | if (newlabel == NULL) | | 1261 | if (newlabel == NULL) |
1259 | return EIO; | | 1262 | return EIO; |
1260 | memset(newlabel, 0, sizeof newlabel); | | 1263 | memset(newlabel, 0, sizeof newlabel); |
1261 | memcpy(newlabel, addr, sizeof (struct olddisklabel)); | | 1264 | memcpy(newlabel, addr, sizeof (struct olddisklabel)); |
1262 | lp = newlabel; | | 1265 | lp = newlabel; |
1263 | } else | | 1266 | } else |
1264 | #endif | | 1267 | #endif |
1265 | lp = (struct disklabel *)addr; | | 1268 | lp = (struct disklabel *)addr; |
1266 | | | 1269 | |
1267 | mutex_enter(&wd->sc_dk.dk_openlock); | | 1270 | mutex_enter(&wd->sc_dk.dk_openlock); |
1268 | wd->sc_flags |= WDF_LABELLING; | | 1271 | wd->sc_flags |= WDF_LABELLING; |
1269 | | | 1272 | |
1270 | error = setdisklabel(wd->sc_dk.dk_label, | | 1273 | error = setdisklabel(wd->sc_dk.dk_label, |
1271 | lp, /*wd->sc_dk.dk_openmask : */0, | | 1274 | lp, /*wd->sc_dk.dk_openmask : */0, |
1272 | wd->sc_dk.dk_cpulabel); | | 1275 | wd->sc_dk.dk_cpulabel); |
1273 | if (error == 0) { | | 1276 | if (error == 0) { |
1274 | if (wd->drvp->state > RESET) { | | 1277 | if (wd->drvp->state > RESET) { |
1275 | s = splbio(); | | 1278 | s = splbio(); |
1276 | wd->drvp->drive_flags |= DRIVE_RESET; | | 1279 | wd->drvp->drive_flags |= DRIVE_RESET; |
1277 | splx(s); | | 1280 | splx(s); |
1278 | } | | 1281 | } |
1279 | if (xfer == DIOCWDINFO | | 1282 | if (xfer == DIOCWDINFO |
1280 | #ifdef __HAVE_OLD_DISKLABEL | | 1283 | #ifdef __HAVE_OLD_DISKLABEL |
1281 | || xfer == ODIOCWDINFO | | 1284 | || xfer == ODIOCWDINFO |
1282 | #endif | | 1285 | #endif |
1283 | ) | | 1286 | ) |
1284 | error = writedisklabel(WDLABELDEV(dev), | | 1287 | error = writedisklabel(WDLABELDEV(dev), |
1285 | wdstrategy, wd->sc_dk.dk_label, | | 1288 | wdstrategy, wd->sc_dk.dk_label, |
1286 | wd->sc_dk.dk_cpulabel); | | 1289 | wd->sc_dk.dk_cpulabel); |
1287 | } | | 1290 | } |
1288 | | | 1291 | |
1289 | wd->sc_flags &= ~WDF_LABELLING; | | 1292 | wd->sc_flags &= ~WDF_LABELLING; |
1290 | mutex_exit(&wd->sc_dk.dk_openlock); | | 1293 | mutex_exit(&wd->sc_dk.dk_openlock); |
1291 | #ifdef __HAVE_OLD_DISKLABEL | | 1294 | #ifdef __HAVE_OLD_DISKLABEL |
1292 | if (newlabel != NULL) | | 1295 | if (newlabel != NULL) |
1293 | free(newlabel, M_TEMP); | | 1296 | free(newlabel, M_TEMP); |
1294 | #endif | | 1297 | #endif |
1295 | return error; | | 1298 | return error; |
1296 | } | | 1299 | } |
1297 | | | 1300 | |
1298 | case DIOCKLABEL: | | 1301 | case DIOCKLABEL: |
1299 | if (*(int *)addr) | | 1302 | if (*(int *)addr) |
1300 | wd->sc_flags |= WDF_KLABEL; | | 1303 | wd->sc_flags |= WDF_KLABEL; |
1301 | else | | 1304 | else |
1302 | wd->sc_flags &= ~WDF_KLABEL; | | 1305 | wd->sc_flags &= ~WDF_KLABEL; |
1303 | return 0; | | 1306 | return 0; |
1304 | | | 1307 | |
1305 | case DIOCWLABEL: | | 1308 | case DIOCWLABEL: |
1306 | if ((flag & FWRITE) == 0) | | 1309 | if ((flag & FWRITE) == 0) |
1307 | return EBADF; | | 1310 | return EBADF; |
1308 | if (*(int *)addr) | | 1311 | if (*(int *)addr) |
1309 | wd->sc_flags |= WDF_WLABEL; | | 1312 | wd->sc_flags |= WDF_WLABEL; |
1310 | else | | 1313 | else |
1311 | wd->sc_flags &= ~WDF_WLABEL; | | 1314 | wd->sc_flags &= ~WDF_WLABEL; |
1312 | return 0; | | 1315 | return 0; |
1313 | | | 1316 | |
1314 | case DIOCGDEFLABEL: | | 1317 | case DIOCGDEFLABEL: |
1315 | wdgetdefaultlabel(wd, (struct disklabel *)addr); | | 1318 | wdgetdefaultlabel(wd, (struct disklabel *)addr); |
1316 | return 0; | | 1319 | return 0; |
1317 | #ifdef __HAVE_OLD_DISKLABEL | | 1320 | #ifdef __HAVE_OLD_DISKLABEL |
1318 | case ODIOCGDEFLABEL: | | 1321 | case ODIOCGDEFLABEL: |
1319 | newlabel = malloc(sizeof *newlabel, M_TEMP, M_WAITOK); | | 1322 | newlabel = malloc(sizeof *newlabel, M_TEMP, M_WAITOK); |
1320 | if (newlabel == NULL) | | 1323 | if (newlabel == NULL) |
1321 | return EIO; | | 1324 | return EIO; |
1322 | wdgetdefaultlabel(wd, newlabel); | | 1325 | wdgetdefaultlabel(wd, newlabel); |
1323 | if (newlabel->d_npartitions <= OLDMAXPARTITIONS) | | 1326 | if (newlabel->d_npartitions <= OLDMAXPARTITIONS) |
1324 | memcpy(addr, &newlabel, sizeof (struct olddisklabel)); | | 1327 | memcpy(addr, &newlabel, sizeof (struct olddisklabel)); |
1325 | else | | 1328 | else |
1326 | error = ENOTTY; | | 1329 | error = ENOTTY; |
1327 | free(newlabel, M_TEMP); | | 1330 | free(newlabel, M_TEMP); |
1328 | return error; | | 1331 | return error; |
1329 | #endif | | 1332 | #endif |
1330 | | | 1333 | |
1331 | #ifdef notyet | | 1334 | #ifdef notyet |
1332 | case DIOCWFORMAT: | | 1335 | case DIOCWFORMAT: |
1333 | if ((flag & FWRITE) == 0) | | 1336 | if ((flag & FWRITE) == 0) |
1334 | return EBADF; | | 1337 | return EBADF; |
1335 | { | | 1338 | { |
1336 | register struct format_op *fop; | | 1339 | register struct format_op *fop; |
1337 | struct iovec aiov; | | 1340 | struct iovec aiov; |
1338 | struct uio auio; | | 1341 | struct uio auio; |
1339 | | | 1342 | |
1340 | fop = (struct format_op *)addr; | | 1343 | fop = (struct format_op *)addr; |
1341 | aiov.iov_base = fop->df_buf; | | 1344 | aiov.iov_base = fop->df_buf; |
1342 | aiov.iov_len = fop->df_count; | | 1345 | aiov.iov_len = fop->df_count; |
1343 | auio.uio_iov = &aiov; | | 1346 | auio.uio_iov = &aiov; |
1344 | auio.uio_iovcnt = 1; | | 1347 | auio.uio_iovcnt = 1; |
1345 | auio.uio_resid = fop->df_count; | | 1348 | auio.uio_resid = fop->df_count; |
1346 | auio.uio_offset = | | 1349 | auio.uio_offset = |
1347 | fop->df_startblk * wd->sc_dk.dk_label->d_secsize; | | 1350 | fop->df_startblk * wd->sc_dk.dk_label->d_secsize; |
1348 | auio.uio_vmspace = l->l_proc->p_vmspace; | | 1351 | auio.uio_vmspace = l->l_proc->p_vmspace; |
1349 | error = physio(wdformat, NULL, dev, B_WRITE, minphys, | | 1352 | error = physio(wdformat, NULL, dev, B_WRITE, minphys, |
1350 | &auio); | | 1353 | &auio); |
1351 | fop->df_count -= auio.uio_resid; | | 1354 | fop->df_count -= auio.uio_resid; |
1352 | fop->df_reg[0] = wdc->sc_status; | | 1355 | fop->df_reg[0] = wdc->sc_status; |
1353 | fop->df_reg[1] = wdc->sc_error; | | 1356 | fop->df_reg[1] = wdc->sc_error; |
1354 | return error; | | 1357 | return error; |
1355 | } | | 1358 | } |
1356 | #endif | | 1359 | #endif |
1357 | case DIOCGCACHE: | | 1360 | case DIOCGCACHE: |
1358 | return wd_getcache(wd, (int *)addr); | | 1361 | return wd_getcache(wd, (int *)addr); |
1359 | | | 1362 | |
1360 | case DIOCSCACHE: | | 1363 | case DIOCSCACHE: |
1361 | return wd_setcache(wd, *(int *)addr); | | 1364 | return wd_setcache(wd, *(int *)addr); |
1362 | | | 1365 | |
1363 | case DIOCCACHESYNC: | | 1366 | case DIOCCACHESYNC: |
1364 | return wd_flushcache(wd, AT_WAIT); | | 1367 | return wd_flushcache(wd, AT_WAIT); |
1365 | | | 1368 | |
1366 | case ATAIOCCOMMAND: | | 1369 | case ATAIOCCOMMAND: |
1367 | /* | | 1370 | /* |
1368 | * Make sure this command is (relatively) safe first | | 1371 | * Make sure this command is (relatively) safe first |
1369 | */ | | 1372 | */ |
1370 | if ((((atareq_t *) addr)->flags & ATACMD_READ) == 0 && | | 1373 | if ((((atareq_t *) addr)->flags & ATACMD_READ) == 0 && |
1371 | (flag & FWRITE) == 0) | | 1374 | (flag & FWRITE) == 0) |
1372 | return (EBADF); | | 1375 | return (EBADF); |
1373 | { | | 1376 | { |
1374 | struct wd_ioctl *wi; | | 1377 | struct wd_ioctl *wi; |
1375 | atareq_t *atareq = (atareq_t *) addr; | | 1378 | atareq_t *atareq = (atareq_t *) addr; |
1376 | int error1; | | 1379 | int error1; |
1377 | | | 1380 | |
1378 | wi = wi_get(); | | 1381 | wi = wi_get(); |
1379 | wi->wi_softc = wd; | | 1382 | wi->wi_softc = wd; |
1380 | wi->wi_atareq = *atareq; | | 1383 | wi->wi_atareq = *atareq; |
1381 | | | 1384 | |
1382 | if (atareq->datalen && atareq->flags & | | 1385 | if (atareq->datalen && atareq->flags & |
1383 | (ATACMD_READ | ATACMD_WRITE)) { | | 1386 | (ATACMD_READ | ATACMD_WRITE)) { |
1384 | void *tbuf; | | 1387 | void *tbuf; |
1385 | if (atareq->datalen < DEV_BSIZE | | 1388 | if (atareq->datalen < DEV_BSIZE |
1386 | && atareq->command == WDCC_IDENTIFY) { | | 1389 | && atareq->command == WDCC_IDENTIFY) { |
1387 | tbuf = malloc(DEV_BSIZE, M_TEMP, M_WAITOK); | | 1390 | tbuf = malloc(DEV_BSIZE, M_TEMP, M_WAITOK); |
1388 | wi->wi_iov.iov_base = tbuf; | | 1391 | wi->wi_iov.iov_base = tbuf; |
1389 | wi->wi_iov.iov_len = DEV_BSIZE; | | 1392 | wi->wi_iov.iov_len = DEV_BSIZE; |
1390 | UIO_SETUP_SYSSPACE(&wi->wi_uio); | | 1393 | UIO_SETUP_SYSSPACE(&wi->wi_uio); |
1391 | } else { | | 1394 | } else { |
1392 | tbuf = NULL; | | 1395 | tbuf = NULL; |
1393 | wi->wi_iov.iov_base = atareq->databuf; | | 1396 | wi->wi_iov.iov_base = atareq->databuf; |
1394 | wi->wi_iov.iov_len = atareq->datalen; | | 1397 | wi->wi_iov.iov_len = atareq->datalen; |
1395 | wi->wi_uio.uio_vmspace = l->l_proc->p_vmspace; | | 1398 | wi->wi_uio.uio_vmspace = l->l_proc->p_vmspace; |
1396 | } | | 1399 | } |
1397 | wi->wi_uio.uio_iov = &wi->wi_iov; | | 1400 | wi->wi_uio.uio_iov = &wi->wi_iov; |
1398 | wi->wi_uio.uio_iovcnt = 1; | | 1401 | wi->wi_uio.uio_iovcnt = 1; |
1399 | wi->wi_uio.uio_resid = atareq->datalen; | | 1402 | wi->wi_uio.uio_resid = atareq->datalen; |
1400 | wi->wi_uio.uio_offset = 0; | | 1403 | wi->wi_uio.uio_offset = 0; |
1401 | wi->wi_uio.uio_rw = | | 1404 | wi->wi_uio.uio_rw = |
1402 | (atareq->flags & ATACMD_READ) ? B_READ : B_WRITE; | | 1405 | (atareq->flags & ATACMD_READ) ? B_READ : B_WRITE; |
1403 | error1 = physio(wdioctlstrategy, &wi->wi_bp, dev, | | 1406 | error1 = physio(wdioctlstrategy, &wi->wi_bp, dev, |
1404 | (atareq->flags & ATACMD_READ) ? B_READ : B_WRITE, | | 1407 | (atareq->flags & ATACMD_READ) ? B_READ : B_WRITE, |
1405 | minphys, &wi->wi_uio); | | 1408 | minphys, &wi->wi_uio); |
1406 | if (tbuf != NULL && error1 == 0) { | | 1409 | if (tbuf != NULL && error1 == 0) { |
1407 | error1 = copyout(tbuf, atareq->databuf, | | 1410 | error1 = copyout(tbuf, atareq->databuf, |
1408 | atareq->datalen); | | 1411 | atareq->datalen); |
1409 | free(tbuf, M_TEMP); | | 1412 | free(tbuf, M_TEMP); |
1410 | } | | 1413 | } |
1411 | } else { | | 1414 | } else { |
1412 | /* No need to call physio if we don't have any | | 1415 | /* No need to call physio if we don't have any |
1413 | user data */ | | 1416 | user data */ |
1414 | wi->wi_bp.b_flags = 0; | | 1417 | wi->wi_bp.b_flags = 0; |
1415 | wi->wi_bp.b_data = 0; | | 1418 | wi->wi_bp.b_data = 0; |
1416 | wi->wi_bp.b_bcount = 0; | | 1419 | wi->wi_bp.b_bcount = 0; |
1417 | wi->wi_bp.b_dev = 0; | | 1420 | wi->wi_bp.b_dev = 0; |
1418 | wi->wi_bp.b_proc = l->l_proc; | | 1421 | wi->wi_bp.b_proc = l->l_proc; |
1419 | wdioctlstrategy(&wi->wi_bp); | | 1422 | wdioctlstrategy(&wi->wi_bp); |
1420 | error1 = wi->wi_bp.b_error; | | 1423 | error1 = wi->wi_bp.b_error; |
1421 | } | | 1424 | } |
1422 | *atareq = wi->wi_atareq; | | 1425 | *atareq = wi->wi_atareq; |
1423 | wi_free(wi); | | 1426 | wi_free(wi); |
1424 | return(error1); | | 1427 | return(error1); |
1425 | } | | 1428 | } |
1426 | | | 1429 | |
1427 | case DIOCAWEDGE: | | 1430 | case DIOCAWEDGE: |
1428 | { | | 1431 | { |
1429 | struct dkwedge_info *dkw = (void *) addr; | | 1432 | struct dkwedge_info *dkw = (void *) addr; |
1430 | | | 1433 | |
1431 | if ((flag & FWRITE) == 0) | | 1434 | if ((flag & FWRITE) == 0) |
1432 | return (EBADF); | | 1435 | return (EBADF); |
1433 | | | 1436 | |
1434 | /* If the ioctl happens here, the parent is us. */ | | 1437 | /* If the ioctl happens here, the parent is us. */ |
1435 | strcpy(dkw->dkw_parent, device_xname(wd->sc_dev)); | | 1438 | strcpy(dkw->dkw_parent, device_xname(wd->sc_dev)); |
1436 | return (dkwedge_add(dkw)); | | 1439 | return (dkwedge_add(dkw)); |
1437 | } | | 1440 | } |
1438 | | | 1441 | |
1439 | case DIOCDWEDGE: | | 1442 | case DIOCDWEDGE: |
1440 | { | | 1443 | { |
1441 | struct dkwedge_info *dkw = (void *) addr; | | 1444 | struct dkwedge_info *dkw = (void *) addr; |
1442 | | | 1445 | |
1443 | if ((flag & FWRITE) == 0) | | 1446 | if ((flag & FWRITE) == 0) |
1444 | return (EBADF); | | 1447 | return (EBADF); |
1445 | | | 1448 | |
1446 | /* If the ioctl happens here, the parent is us. */ | | 1449 | /* If the ioctl happens here, the parent is us. */ |
1447 | strcpy(dkw->dkw_parent, device_xname(wd->sc_dev)); | | 1450 | strcpy(dkw->dkw_parent, device_xname(wd->sc_dev)); |
1448 | return (dkwedge_del(dkw)); | | 1451 | return (dkwedge_del(dkw)); |
1449 | } | | 1452 | } |
1450 | | | 1453 | |
1451 | case DIOCLWEDGES: | | 1454 | case DIOCLWEDGES: |
1452 | { | | 1455 | { |
1453 | struct dkwedge_list *dkwl = (void *) addr; | | 1456 | struct dkwedge_list *dkwl = (void *) addr; |
1454 | | | 1457 | |
1455 | return (dkwedge_list(&wd->sc_dk, dkwl, l)); | | 1458 | return (dkwedge_list(&wd->sc_dk, dkwl, l)); |
1456 | } | | 1459 | } |
1457 | | | 1460 | |
1458 | case DIOCGSTRATEGY: | | 1461 | case DIOCGSTRATEGY: |
1459 | { | | 1462 | { |
1460 | struct disk_strategy *dks = (void *)addr; | | 1463 | struct disk_strategy *dks = (void *)addr; |
1461 | | | 1464 | |
1462 | s = splbio(); | | 1465 | s = splbio(); |
1463 | strlcpy(dks->dks_name, bufq_getstrategyname(wd->sc_q), | | 1466 | strlcpy(dks->dks_name, bufq_getstrategyname(wd->sc_q), |
1464 | sizeof(dks->dks_name)); | | 1467 | sizeof(dks->dks_name)); |
1465 | splx(s); | | 1468 | splx(s); |
1466 | dks->dks_paramlen = 0; | | 1469 | dks->dks_paramlen = 0; |
1467 | | | 1470 | |
1468 | return 0; | | 1471 | return 0; |
1469 | } | | 1472 | } |
1470 | | | 1473 | |
1471 | case DIOCSSTRATEGY: | | 1474 | case DIOCSSTRATEGY: |
1472 | { | | 1475 | { |
1473 | struct disk_strategy *dks = (void *)addr; | | 1476 | struct disk_strategy *dks = (void *)addr; |
1474 | struct bufq_state *new; | | 1477 | struct bufq_state *new; |
1475 | struct bufq_state *old; | | 1478 | struct bufq_state *old; |
1476 | | | 1479 | |
1477 | if ((flag & FWRITE) == 0) { | | 1480 | if ((flag & FWRITE) == 0) { |
1478 | return EBADF; | | 1481 | return EBADF; |
1479 | } | | 1482 | } |
1480 | if (dks->dks_param != NULL) { | | 1483 | if (dks->dks_param != NULL) { |
1481 | return EINVAL; | | 1484 | return EINVAL; |
1482 | } | | 1485 | } |
1483 | dks->dks_name[sizeof(dks->dks_name) - 1] = 0; /* ensure term */ | | 1486 | dks->dks_name[sizeof(dks->dks_name) - 1] = 0; /* ensure term */ |
1484 | error = bufq_alloc(&new, dks->dks_name, | | 1487 | error = bufq_alloc(&new, dks->dks_name, |
1485 | BUFQ_EXACT|BUFQ_SORT_RAWBLOCK); | | 1488 | BUFQ_EXACT|BUFQ_SORT_RAWBLOCK); |
1486 | if (error) { | | 1489 | if (error) { |
1487 | return error; | | 1490 | return error; |
1488 | } | | 1491 | } |
1489 | s = splbio(); | | 1492 | s = splbio(); |
1490 | old = wd->sc_q; | | 1493 | old = wd->sc_q; |
1491 | bufq_move(new, old); | | 1494 | bufq_move(new, old); |
1492 | wd->sc_q = new; | | 1495 | wd->sc_q = new; |
1493 | splx(s); | | 1496 | splx(s); |
1494 | bufq_free(old); | | 1497 | bufq_free(old); |
1495 | | | 1498 | |
1496 | return 0; | | 1499 | return 0; |
1497 | } | | 1500 | } |
1498 | | | 1501 | |
1499 | default: | | 1502 | default: |
1500 | return ENOTTY; | | 1503 | return ENOTTY; |
1501 | } | | 1504 | } |
1502 | | | 1505 | |
1503 | #ifdef DIAGNOSTIC | | 1506 | #ifdef DIAGNOSTIC |
1504 | panic("wdioctl: impossible"); | | 1507 | panic("wdioctl: impossible"); |
1505 | #endif | | 1508 | #endif |
1506 | } | | 1509 | } |
1507 | | | 1510 | |
1508 | #ifdef B_FORMAT | | 1511 | #ifdef B_FORMAT |
1509 | int | | 1512 | int |
1510 | wdformat(struct buf *bp) | | 1513 | wdformat(struct buf *bp) |
1511 | { | | 1514 | { |
1512 | | | 1515 | |
1513 | bp->b_flags |= B_FORMAT; | | 1516 | bp->b_flags |= B_FORMAT; |
1514 | return wdstrategy(bp); | | 1517 | return wdstrategy(bp); |
1515 | } | | 1518 | } |
1516 | #endif | | 1519 | #endif |
1517 | | | 1520 | |
1518 | int | | 1521 | int |
1519 | wdsize(dev_t dev) | | 1522 | wdsize(dev_t dev) |
1520 | { | | 1523 | { |
1521 | struct wd_softc *wd; | | 1524 | struct wd_softc *wd; |
1522 | int part, omask; | | 1525 | int part, omask; |
1523 | int size; | | 1526 | int size; |
1524 | | | 1527 | |
1525 | ATADEBUG_PRINT(("wdsize\n"), DEBUG_FUNCS); | | 1528 | ATADEBUG_PRINT(("wdsize\n"), DEBUG_FUNCS); |
1526 | | | 1529 | |
1527 | wd = device_lookup_private(&wd_cd, WDUNIT(dev)); | | 1530 | wd = device_lookup_private(&wd_cd, WDUNIT(dev)); |
1528 | if (wd == NULL) | | 1531 | if (wd == NULL) |
1529 | return (-1); | | 1532 | return (-1); |
1530 | | | 1533 | |
1531 | part = WDPART(dev); | | 1534 | part = WDPART(dev); |
1532 | omask = wd->sc_dk.dk_openmask & (1 << part); | | 1535 | omask = wd->sc_dk.dk_openmask & (1 << part); |
1533 | | | 1536 | |
1534 | if (omask == 0 && wdopen(dev, 0, S_IFBLK, NULL) != 0) | | 1537 | if (omask == 0 && wdopen(dev, 0, S_IFBLK, NULL) != 0) |
1535 | return (-1); | | 1538 | return (-1); |
1536 | if (wd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) | | 1539 | if (wd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) |
1537 | size = -1; | | 1540 | size = -1; |
1538 | else | | 1541 | else |
1539 | size = wd->sc_dk.dk_label->d_partitions[part].p_size * | | 1542 | size = wd->sc_dk.dk_label->d_partitions[part].p_size * |
1540 | (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE); | | 1543 | (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE); |
1541 | if (omask == 0 && wdclose(dev, 0, S_IFBLK, NULL) != 0) | | 1544 | if (omask == 0 && wdclose(dev, 0, S_IFBLK, NULL) != 0) |
1542 | return (-1); | | 1545 | return (-1); |
1543 | return (size); | | 1546 | return (size); |
1544 | } | | 1547 | } |
1545 | | | 1548 | |
1546 | /* #define WD_DUMP_NOT_TRUSTED if you just want to watch */ | | 1549 | /* #define WD_DUMP_NOT_TRUSTED if you just want to watch */ |
1547 | static int wddoingadump = 0; | | 1550 | static int wddoingadump = 0; |
1548 | static int wddumprecalibrated = 0; | | 1551 | static int wddumprecalibrated = 0; |
1549 | | | 1552 | |
1550 | /* | | 1553 | /* |
1551 | * Dump core after a system crash. | | 1554 | * Dump core after a system crash. |
1552 | */ | | 1555 | */ |
1553 | int | | 1556 | int |
1554 | wddump(dev_t dev, daddr_t blkno, void *va, size_t size) | | 1557 | wddump(dev_t dev, daddr_t blkno, void *va, size_t size) |
1555 | { | | 1558 | { |
1556 | struct wd_softc *wd; /* disk unit to do the I/O */ | | 1559 | struct wd_softc *wd; /* disk unit to do the I/O */ |
1557 | struct disklabel *lp; /* disk's disklabel */ | | 1560 | struct disklabel *lp; /* disk's disklabel */ |
1558 | int part, err; | | 1561 | int part, err; |
1559 | int nblks; /* total number of sectors left to write */ | | 1562 | int nblks; /* total number of sectors left to write */ |
1560 | | | 1563 | |
1561 | /* Check if recursive dump; if so, punt. */ | | 1564 | /* Check if recursive dump; if so, punt. */ |
1562 | if (wddoingadump) | | 1565 | if (wddoingadump) |
1563 | return EFAULT; | | 1566 | return EFAULT; |
1564 | wddoingadump = 1; | | 1567 | wddoingadump = 1; |
1565 | | | 1568 | |
1566 | wd = device_lookup_private(&wd_cd, WDUNIT(dev)); | | 1569 | wd = device_lookup_private(&wd_cd, WDUNIT(dev)); |
1567 | if (wd == NULL) | | 1570 | if (wd == NULL) |
1568 | return (ENXIO); | | 1571 | return (ENXIO); |
1569 | | | 1572 | |
1570 | part = WDPART(dev); | | 1573 | part = WDPART(dev); |
1571 | | | 1574 | |
1572 | /* Convert to disk sectors. Request must be a multiple of size. */ | | 1575 | /* Convert to disk sectors. Request must be a multiple of size. */ |
1573 | lp = wd->sc_dk.dk_label; | | 1576 | lp = wd->sc_dk.dk_label; |
1574 | if ((size % lp->d_secsize) != 0) | | 1577 | if ((size % lp->d_secsize) != 0) |
1575 | return EFAULT; | | 1578 | return EFAULT; |
1576 | nblks = size / lp->d_secsize; | | 1579 | nblks = size / lp->d_secsize; |
1577 | blkno = blkno / (lp->d_secsize / DEV_BSIZE); | | 1580 | blkno = blkno / (lp->d_secsize / DEV_BSIZE); |
1578 | | | 1581 | |
1579 | /* Check transfer bounds against partition size. */ | | 1582 | /* Check transfer bounds against partition size. */ |
1580 | if ((blkno < 0) || ((blkno + nblks) > lp->d_partitions[part].p_size)) | | 1583 | if ((blkno < 0) || ((blkno + nblks) > lp->d_partitions[part].p_size)) |
1581 | return EINVAL; | | 1584 | return EINVAL; |
1582 | | | 1585 | |
1583 | /* Offset block number to start of partition. */ | | 1586 | /* Offset block number to start of partition. */ |
1584 | blkno += lp->d_partitions[part].p_offset; | | 1587 | blkno += lp->d_partitions[part].p_offset; |
1585 | | | 1588 | |
1586 | /* Recalibrate, if first dump transfer. */ | | 1589 | /* Recalibrate, if first dump transfer. */ |
1587 | if (wddumprecalibrated == 0) { | | 1590 | if (wddumprecalibrated == 0) { |
1588 | wddumprecalibrated = 1; | | 1591 | wddumprecalibrated = 1; |
1589 | (*wd->atabus->ata_reset_drive)(wd->drvp, | | 1592 | (*wd->atabus->ata_reset_drive)(wd->drvp, |
1590 | AT_POLL | AT_RST_EMERG); | | 1593 | AT_POLL | AT_RST_EMERG); |
1591 | wd->drvp->state = RESET; | | 1594 | wd->drvp->state = RESET; |
1592 | } | | 1595 | } |
1593 | | | 1596 | |
1594 | wd->sc_bp = NULL; | | 1597 | wd->sc_bp = NULL; |
1595 | wd->sc_wdc_bio.blkno = blkno; | | 1598 | wd->sc_wdc_bio.blkno = blkno; |
1596 | wd->sc_wdc_bio.flags = ATA_POLL; | | 1599 | wd->sc_wdc_bio.flags = ATA_POLL; |
1597 | if (wd->sc_flags & WDF_LBA48 && | | 1600 | if (wd->sc_flags & WDF_LBA48 && |
1598 | (wd->sc_wdc_bio.blkno + nblks) > wd->sc_capacity28) | | 1601 | (wd->sc_wdc_bio.blkno + nblks) > wd->sc_capacity28) |
1599 | wd->sc_wdc_bio.flags |= ATA_LBA48; | | 1602 | wd->sc_wdc_bio.flags |= ATA_LBA48; |
1600 | if (wd->sc_flags & WDF_LBA) | | 1603 | if (wd->sc_flags & WDF_LBA) |
1601 | wd->sc_wdc_bio.flags |= ATA_LBA; | | 1604 | wd->sc_wdc_bio.flags |= ATA_LBA; |
1602 | wd->sc_wdc_bio.bcount = nblks * lp->d_secsize; | | 1605 | wd->sc_wdc_bio.bcount = nblks * lp->d_secsize; |
1603 | wd->sc_wdc_bio.databuf = va; | | 1606 | wd->sc_wdc_bio.databuf = va; |
1604 | #ifndef WD_DUMP_NOT_TRUSTED | | 1607 | #ifndef WD_DUMP_NOT_TRUSTED |
1605 | switch (err = wd->atabus->ata_bio(wd->drvp, &wd->sc_wdc_bio)) { | | 1608 | switch (err = wd->atabus->ata_bio(wd->drvp, &wd->sc_wdc_bio)) { |
1606 | case ATACMD_TRY_AGAIN: | | 1609 | case ATACMD_TRY_AGAIN: |
1607 | panic("wddump: try again"); | | 1610 | panic("wddump: try again"); |
1608 | break; | | 1611 | break; |
1609 | case ATACMD_QUEUED: | | 1612 | case ATACMD_QUEUED: |
1610 | panic("wddump: polled command has been queued"); | | 1613 | panic("wddump: polled command has been queued"); |
1611 | break; | | 1614 | break; |
1612 | case ATACMD_COMPLETE: | | 1615 | case ATACMD_COMPLETE: |
1613 | break; | | 1616 | break; |
1614 | default: | | 1617 | default: |
1615 | panic("wddump: unknown atacmd code %d", err); | | 1618 | panic("wddump: unknown atacmd code %d", err); |
1616 | } | | 1619 | } |
1617 | switch(err = wd->sc_wdc_bio.error) { | | 1620 | switch(err = wd->sc_wdc_bio.error) { |
1618 | case TIMEOUT: | | 1621 | case TIMEOUT: |
1619 | printf("wddump: device timed out"); | | 1622 | printf("wddump: device timed out"); |
1620 | err = EIO; | | 1623 | err = EIO; |
1621 | break; | | 1624 | break; |
1622 | case ERR_DF: | | 1625 | case ERR_DF: |
1623 | printf("wddump: drive fault"); | | 1626 | printf("wddump: drive fault"); |
1624 | err = EIO; | | 1627 | err = EIO; |
1625 | break; | | 1628 | break; |
1626 | case ERR_DMA: | | 1629 | case ERR_DMA: |
1627 | printf("wddump: DMA error"); | | 1630 | printf("wddump: DMA error"); |
1628 | err = EIO; | | 1631 | err = EIO; |
1629 | break; | | 1632 | break; |
1630 | case ERROR: | | 1633 | case ERROR: |
1631 | printf("wddump: "); | | 1634 | printf("wddump: "); |
1632 | wdperror(wd); | | 1635 | wdperror(wd); |
1633 | err = EIO; | | 1636 | err = EIO; |
1634 | break; | | 1637 | break; |
1635 | case NOERROR: | | 1638 | case NOERROR: |
1636 | err = 0; | | 1639 | err = 0; |
1637 | break; | | 1640 | break; |
1638 | default: | | 1641 | default: |
1639 | panic("wddump: unknown error type %d", err); | | 1642 | panic("wddump: unknown error type %d", err); |
1640 | } | | 1643 | } |
1641 | if (err != 0) { | | 1644 | if (err != 0) { |
1642 | printf("\n"); | | 1645 | printf("\n"); |
1643 | return err; | | 1646 | return err; |
1644 | } | | 1647 | } |
1645 | #else /* WD_DUMP_NOT_TRUSTED */ | | 1648 | #else /* WD_DUMP_NOT_TRUSTED */ |
1646 | /* Let's just talk about this first... */ | | 1649 | /* Let's just talk about this first... */ |
1647 | printf("wd%d: dump addr 0x%x, cylin %d, head %d, sector %d\n", | | 1650 | printf("wd%d: dump addr 0x%x, cylin %d, head %d, sector %d\n", |
1648 | unit, va, cylin, head, sector); | | 1651 | unit, va, cylin, head, sector); |
1649 | delay(500 * 1000); /* half a second */ | | 1652 | delay(500 * 1000); /* half a second */ |
1650 | #endif | | 1653 | #endif |
1651 | | | 1654 | |
1652 | wddoingadump = 0; | | 1655 | wddoingadump = 0; |
1653 | return 0; | | 1656 | return 0; |
1654 | } | | 1657 | } |
1655 | | | 1658 | |
1656 | #ifdef HAS_BAD144_HANDLING | | 1659 | #ifdef HAS_BAD144_HANDLING |
1657 | /* | | 1660 | /* |
1658 | * Internalize the bad sector table. | | 1661 | * Internalize the bad sector table. |
1659 | */ | | 1662 | */ |
1660 | void | | 1663 | void |
1661 | bad144intern(struct wd_softc *wd) | | 1664 | bad144intern(struct wd_softc *wd) |
1662 | { | | 1665 | { |
1663 | struct dkbad *bt = &wd->sc_dk.dk_cpulabel->bad; | | 1666 | struct dkbad *bt = &wd->sc_dk.dk_cpulabel->bad; |
1664 | struct disklabel *lp = wd->sc_dk.dk_label; | | 1667 | struct disklabel *lp = wd->sc_dk.dk_label; |
1665 | int i = 0; | | 1668 | int i = 0; |
1666 | | | 1669 | |
1667 | ATADEBUG_PRINT(("bad144intern\n"), DEBUG_XFERS); | | 1670 | ATADEBUG_PRINT(("bad144intern\n"), DEBUG_XFERS); |
1668 | | | 1671 | |
1669 | for (; i < NBT_BAD; i++) { | | 1672 | for (; i < NBT_BAD; i++) { |
1670 | if (bt->bt_bad[i].bt_cyl == 0xffff) | | 1673 | if (bt->bt_bad[i].bt_cyl == 0xffff) |
1671 | break; | | 1674 | break; |
1672 | wd->sc_badsect[i] = | | 1675 | wd->sc_badsect[i] = |
1673 | bt->bt_bad[i].bt_cyl * lp->d_secpercyl + | | 1676 | bt->bt_bad[i].bt_cyl * lp->d_secpercyl + |
1674 | (bt->bt_bad[i].bt_trksec >> 8) * lp->d_nsectors + | | 1677 | (bt->bt_bad[i].bt_trksec >> 8) * lp->d_nsectors + |
1675 | (bt->bt_bad[i].bt_trksec & 0xff); | | 1678 | (bt->bt_bad[i].bt_trksec & 0xff); |
1676 | } | | 1679 | } |
1677 | for (; i < NBT_BAD+1; i++) | | 1680 | for (; i < NBT_BAD+1; i++) |
1678 | wd->sc_badsect[i] = -1; | | 1681 | wd->sc_badsect[i] = -1; |
1679 | } | | 1682 | } |
1680 | #endif | | 1683 | #endif |
1681 | | | 1684 | |
1682 | static void | | 1685 | static void |
1683 | wd_params_to_properties(struct wd_softc *wd, struct ataparams *params) | | 1686 | wd_params_to_properties(struct wd_softc *wd, struct ataparams *params) |
1684 | { | | 1687 | { |
1685 | prop_dictionary_t disk_info, odisk_info, geom; | | 1688 | prop_dictionary_t disk_info, odisk_info, geom; |
1686 | const char *cp; | | 1689 | const char *cp; |
1687 | | | 1690 | |
1688 | disk_info = prop_dictionary_create(); | | 1691 | disk_info = prop_dictionary_create(); |
1689 | | | 1692 | |
1690 | if (strcmp(wd->sc_params.atap_model, "ST506") == 0) | | 1693 | if (strcmp(wd->sc_params.atap_model, "ST506") == 0) |
1691 | cp = "ST506"; | | 1694 | cp = "ST506"; |
1692 | else { | | 1695 | else { |
1693 | /* XXX Should have a case for ATA here, too. */ | | 1696 | /* XXX Should have a case for ATA here, too. */ |
1694 | cp = "ESDI"; | | 1697 | cp = "ESDI"; |
1695 | } | | 1698 | } |
1696 | prop_dictionary_set_cstring_nocopy(disk_info, "type", cp); | | 1699 | prop_dictionary_set_cstring_nocopy(disk_info, "type", cp); |
1697 | | | 1700 | |
1698 | geom = prop_dictionary_create(); | | 1701 | geom = prop_dictionary_create(); |
1699 | | | 1702 | |
1700 | prop_dictionary_set_uint64(geom, "sectors-per-unit", wd->sc_capacity); | | 1703 | prop_dictionary_set_uint64(geom, "sectors-per-unit", wd->sc_capacity); |
1701 | | | 1704 | |
1702 | prop_dictionary_set_uint32(geom, "sector-size", | | 1705 | prop_dictionary_set_uint32(geom, "sector-size", |
1703 | DEV_BSIZE /* XXX 512? */); | | 1706 | DEV_BSIZE /* XXX 512? */); |
1704 | | | 1707 | |
1705 | prop_dictionary_set_uint16(geom, "sectors-per-track", | | 1708 | prop_dictionary_set_uint16(geom, "sectors-per-track", |
1706 | wd->sc_params.atap_sectors); | | 1709 | wd->sc_params.atap_sectors); |
1707 | | | 1710 | |
1708 | prop_dictionary_set_uint16(geom, "tracks-per-cylinder", | | 1711 | prop_dictionary_set_uint16(geom, "tracks-per-cylinder", |
1709 | wd->sc_params.atap_heads); | | 1712 | wd->sc_params.atap_heads); |
1710 | | | 1713 | |
1711 | if (wd->sc_flags & WDF_LBA) | | 1714 | if (wd->sc_flags & WDF_LBA) |
1712 | prop_dictionary_set_uint64(geom, "cylinders-per-unit", | | 1715 | prop_dictionary_set_uint64(geom, "cylinders-per-unit", |
1713 | wd->sc_capacity / | | 1716 | wd->sc_capacity / |
1714 | (wd->sc_params.atap_heads * | | 1717 | (wd->sc_params.atap_heads * |
1715 | wd->sc_params.atap_sectors)); | | 1718 | wd->sc_params.atap_sectors)); |
1716 | else | | 1719 | else |
1717 | prop_dictionary_set_uint16(geom, "cylinders-per-unit", | | 1720 | prop_dictionary_set_uint16(geom, "cylinders-per-unit", |
1718 | wd->sc_params.atap_cylinders); | | 1721 | wd->sc_params.atap_cylinders); |
1719 | | | 1722 | |
1720 | prop_dictionary_set(disk_info, "geometry", geom); | | 1723 | prop_dictionary_set(disk_info, "geometry", geom); |
1721 | prop_object_release(geom); | | 1724 | prop_object_release(geom); |
1722 | | | 1725 | |
1723 | prop_dictionary_set(device_properties(wd->sc_dev), | | 1726 | prop_dictionary_set(device_properties(wd->sc_dev), |
1724 | "disk-info", disk_info); | | 1727 | "disk-info", disk_info); |
1725 | | | 1728 | |
1726 | /* | | 1729 | /* |
1727 | * Don't release disk_info here; we keep a reference to it. | | 1730 | * Don't release disk_info here; we keep a reference to it. |
1728 | * disk_detach() will release it when we go away. | | 1731 | * disk_detach() will release it when we go away. |
1729 | */ | | 1732 | */ |
1730 | | | 1733 | |
1731 | odisk_info = wd->sc_dk.dk_info; | | 1734 | odisk_info = wd->sc_dk.dk_info; |
1732 | wd->sc_dk.dk_info = disk_info; | | 1735 | wd->sc_dk.dk_info = disk_info; |
1733 | if (odisk_info) | | 1736 | if (odisk_info) |
1734 | prop_object_release(odisk_info); | | 1737 | prop_object_release(odisk_info); |
1735 | } | | 1738 | } |
1736 | | | 1739 | |
1737 | int | | 1740 | int |
1738 | wd_get_params(struct wd_softc *wd, u_int8_t flags, struct ataparams *params) | | 1741 | wd_get_params(struct wd_softc *wd, u_int8_t flags, struct ataparams *params) |
1739 | { | | 1742 | { |
1740 | | | 1743 | |
1741 | switch (wd->atabus->ata_get_params(wd->drvp, flags, params)) { | | 1744 | switch (wd->atabus->ata_get_params(wd->drvp, flags, params)) { |
1742 | case CMD_AGAIN: | | 1745 | case CMD_AGAIN: |
1743 | return 1; | | 1746 | return 1; |
1744 | case CMD_ERR: | | 1747 | case CMD_ERR: |
1745 | /* | | 1748 | /* |
1746 | * We `know' there's a drive here; just assume it's old. | | 1749 | * We `know' there's a drive here; just assume it's old. |
1747 | * This geometry is only used to read the MBR and print a | | 1750 | * This geometry is only used to read the MBR and print a |
1748 | * (false) attach message. | | 1751 | * (false) attach message. |
1749 | */ | | 1752 | */ |
1750 | strncpy(params->atap_model, "ST506", | | 1753 | strncpy(params->atap_model, "ST506", |
1751 | sizeof params->atap_model); | | 1754 | sizeof params->atap_model); |
1752 | params->atap_config = ATA_CFG_FIXED; | | 1755 | params->atap_config = ATA_CFG_FIXED; |
1753 | params->atap_cylinders = 1024; | | 1756 | params->atap_cylinders = 1024; |
1754 | params->atap_heads = 8; | | 1757 | params->atap_heads = 8; |
1755 | params->atap_sectors = 17; | | 1758 | params->atap_sectors = 17; |
1756 | params->atap_multi = 1; | | 1759 | params->atap_multi = 1; |
1757 | params->atap_capabilities1 = params->atap_capabilities2 = 0; | | 1760 | params->atap_capabilities1 = params->atap_capabilities2 = 0; |
1758 | wd->drvp->ata_vers = -1; /* Mark it as pre-ATA */ | | 1761 | wd->drvp->ata_vers = -1; /* Mark it as pre-ATA */ |
1759 | /* FALLTHROUGH */ | | 1762 | /* FALLTHROUGH */ |
1760 | case CMD_OK: | | 1763 | case CMD_OK: |
1761 | wd_params_to_properties(wd, params); | | 1764 | wd_params_to_properties(wd, params); |
1762 | return 0; | | 1765 | return 0; |
1763 | default: | | 1766 | default: |
1764 | panic("wd_get_params: bad return code from ata_get_params"); | | 1767 | panic("wd_get_params: bad return code from ata_get_params"); |
1765 | /* NOTREACHED */ | | 1768 | /* NOTREACHED */ |
1766 | } | | 1769 | } |
1767 | } | | 1770 | } |
1768 | | | 1771 | |
1769 | int | | 1772 | int |
1770 | wd_getcache(struct wd_softc *wd, int *bitsp) | | 1773 | wd_getcache(struct wd_softc *wd, int *bitsp) |
1771 | { | | 1774 | { |
1772 | struct ataparams params; | | 1775 | struct ataparams params; |
1773 | | | 1776 | |
1774 | if (wd_get_params(wd, AT_WAIT, ¶ms) != 0) | | 1777 | if (wd_get_params(wd, AT_WAIT, ¶ms) != 0) |
1775 | return EIO; | | 1778 | return EIO; |
1776 | if (params.atap_cmd_set1 == 0x0000 || | | 1779 | if (params.atap_cmd_set1 == 0x0000 || |
1777 | params.atap_cmd_set1 == 0xffff || | | 1780 | params.atap_cmd_set1 == 0xffff || |
1778 | (params.atap_cmd_set1 & WDC_CMD1_CACHE) == 0) { | | 1781 | (params.atap_cmd_set1 & WDC_CMD1_CACHE) == 0) { |
1779 | *bitsp = 0; | | 1782 | *bitsp = 0; |
1780 | return 0; | | 1783 | return 0; |
1781 | } | | 1784 | } |
1782 | *bitsp = DKCACHE_WCHANGE | DKCACHE_READ; | | 1785 | *bitsp = DKCACHE_WCHANGE | DKCACHE_READ; |
1783 | if (params.atap_cmd1_en & WDC_CMD1_CACHE) | | 1786 | if (params.atap_cmd1_en & WDC_CMD1_CACHE) |
1784 | *bitsp |= DKCACHE_WRITE; | | 1787 | *bitsp |= DKCACHE_WRITE; |
1785 | | | 1788 | |
1786 | return 0; | | 1789 | return 0; |
1787 | } | | 1790 | } |
1788 | | | 1791 | |
1789 | const char at_errbits[] = "\20\10ERROR\11TIMEOU\12DF"; | | 1792 | const char at_errbits[] = "\20\10ERROR\11TIMEOU\12DF"; |
1790 | | | 1793 | |
1791 | int | | 1794 | int |
1792 | wd_setcache(struct wd_softc *wd, int bits) | | 1795 | wd_setcache(struct wd_softc *wd, int bits) |
1793 | { | | 1796 | { |
1794 | struct ataparams params; | | 1797 | struct ataparams params; |
1795 | struct ata_command ata_c; | | 1798 | struct ata_command ata_c; |
1796 | | | 1799 | |
1797 | if (wd_get_params(wd, AT_WAIT, ¶ms) != 0) | | 1800 | if (wd_get_params(wd, AT_WAIT, ¶ms) != 0) |
1798 | return EIO; | | 1801 | return EIO; |
1799 | | | 1802 | |
1800 | if (params.atap_cmd_set1 == 0x0000 || | | 1803 | if (params.atap_cmd_set1 == 0x0000 || |
1801 | params.atap_cmd_set1 == 0xffff || | | 1804 | params.atap_cmd_set1 == 0xffff || |
1802 | (params.atap_cmd_set1 & WDC_CMD1_CACHE) == 0) | | 1805 | (params.atap_cmd_set1 & WDC_CMD1_CACHE) == 0) |
1803 | return EOPNOTSUPP; | | 1806 | return EOPNOTSUPP; |
1804 | | | 1807 | |
1805 | if ((bits & DKCACHE_READ) == 0 || | | 1808 | if ((bits & DKCACHE_READ) == 0 || |
1806 | (bits & DKCACHE_SAVE) != 0) | | 1809 | (bits & DKCACHE_SAVE) != 0) |
1807 | return EOPNOTSUPP; | | 1810 | return EOPNOTSUPP; |
1808 | | | 1811 | |
1809 | memset(&ata_c, 0, sizeof(struct ata_command)); | | 1812 | memset(&ata_c, 0, sizeof(struct ata_command)); |
1810 | ata_c.r_command = SET_FEATURES; | | 1813 | ata_c.r_command = SET_FEATURES; |
1811 | ata_c.r_st_bmask = 0; | | 1814 | ata_c.r_st_bmask = 0; |
1812 | ata_c.r_st_pmask = 0; | | 1815 | ata_c.r_st_pmask = 0; |
1813 | ata_c.timeout = 30000; /* 30s timeout */ | | 1816 | ata_c.timeout = 30000; /* 30s timeout */ |
1814 | ata_c.flags = AT_WAIT; | | 1817 | ata_c.flags = AT_WAIT; |
1815 | if (bits & DKCACHE_WRITE) | | 1818 | if (bits & DKCACHE_WRITE) |
1816 | ata_c.r_features = WDSF_WRITE_CACHE_EN; | | 1819 | ata_c.r_features = WDSF_WRITE_CACHE_EN; |
1817 | else | | 1820 | else |
1818 | ata_c.r_features = WDSF_WRITE_CACHE_DS; | | 1821 | ata_c.r_features = WDSF_WRITE_CACHE_DS; |
1819 | if (wd->atabus->ata_exec_command(wd->drvp, &ata_c) != ATACMD_COMPLETE) { | | 1822 | if (wd->atabus->ata_exec_command(wd->drvp, &ata_c) != ATACMD_COMPLETE) { |
1820 | aprint_error_dev(wd->sc_dev, | | 1823 | aprint_error_dev(wd->sc_dev, |
1821 | "wd_setcache command not complete\n"); | | 1824 | "wd_setcache command not complete\n"); |
1822 | return EIO; | | 1825 | return EIO; |
1823 | } | | 1826 | } |
1824 | if (ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { | | 1827 | if (ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { |
1825 | char sbuf[sizeof(at_errbits) + 64]; | | 1828 | char sbuf[sizeof(at_errbits) + 64]; |
1826 | snprintb(sbuf, sizeof(sbuf), at_errbits, ata_c.flags); | | 1829 | snprintb(sbuf, sizeof(sbuf), at_errbits, ata_c.flags); |
1827 | aprint_error_dev(wd->sc_dev, "wd_setcache: status=%s\n", sbuf); | | 1830 | aprint_error_dev(wd->sc_dev, "wd_setcache: status=%s\n", sbuf); |
1828 | return EIO; | | 1831 | return EIO; |
1829 | } | | 1832 | } |
1830 | return 0; | | 1833 | return 0; |