Commit | Line | Data |
---|---|---|
c1b3d7c5 | 1 | /*- |
f6e8a0a1 | 2 | * Copyright (c) 1998 - 2006 Søren Schmidt <sos@FreeBSD.org> |
c1b3d7c5 TS |
3 | * All rights reserved. |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer, | |
10 | * without modification, immediately at the beginning of the file. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * | |
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 | |
17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
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 | |
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 | |
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
25 | * | |
02d7aa4a | 26 | * $FreeBSD: src/sys/dev/ata/ata-disk.c,v 1.199 2006/09/14 19:12:29 sos Exp $ |
c1b3d7c5 TS |
27 | */ |
28 | ||
29 | #include "opt_ata.h" | |
30 | ||
31 | #include <sys/param.h> | |
32 | #include <sys/bio.h> | |
33 | #include <sys/buf.h> | |
34 | #include <sys/bus.h> | |
35 | #include <sys/device.h> | |
36 | #include <sys/devicestat.h> | |
37 | #include <sys/disk.h> | |
38 | #include <sys/libkern.h> | |
39 | #include <sys/malloc.h> | |
40 | #include <sys/module.h> | |
41 | #include <sys/nata.h> | |
42 | #include <sys/systm.h> | |
43 | ||
44 | #include <vm/pmap.h> | |
45 | ||
46 | #include <machine/md_var.h> | |
47 | ||
48 | #include "ata-all.h" | |
49 | #include "ata-disk.h" | |
50 | #include "ata_if.h" | |
51 | ||
bb15467a | 52 | /* local implementation, to trigger a warning */ |
53 | static inline void | |
54 | biofinish(struct bio *bp, struct bio *x __unused, int error) | |
55 | { | |
56 | struct buf *bbp = bp->bio_buf; | |
57 | ||
58 | bbp->b_flags |= B_ERROR; | |
59 | bbp->b_error = error; | |
60 | biodone(bp); | |
61 | } | |
62 | ||
c1b3d7c5 TS |
63 | /* device structure */ |
64 | static d_open_t ad_open; | |
65 | static d_close_t ad_close; | |
66 | static d_ioctl_t ad_ioctl; | |
67 | static d_strategy_t ad_strategy; | |
68 | static d_dump_t ad_dump; | |
69 | static struct dev_ops ad_ops = { | |
47f4bca5 | 70 | { "ad", 0, D_DISK }, |
c1b3d7c5 TS |
71 | .d_open = ad_open, |
72 | .d_close = ad_close, | |
73 | .d_read = physread, | |
74 | .d_write = physwrite, | |
75 | .d_ioctl = ad_ioctl, | |
76 | .d_strategy = ad_strategy, | |
77 | .d_dump = ad_dump, | |
78 | }; | |
79 | ||
80 | /* prototypes */ | |
cbf684e5 | 81 | static void ad_init(device_t dev); |
82 | static void ad_get_geometry(device_t dev); | |
83 | static void ad_done(struct ata_request *request); | |
c1b3d7c5 | 84 | static void ad_describe(device_t dev); |
cbf684e5 | 85 | static int ad_version(u_int16_t version); |
c1b3d7c5 TS |
86 | |
87 | /* local vars */ | |
88 | static MALLOC_DEFINE(M_AD, "ad_driver", "ATA disk driver"); | |
89 | ||
90 | static int | |
91 | ad_probe(device_t dev) | |
92 | { | |
93 | struct ata_device *atadev = device_get_softc(dev); | |
94 | ||
95 | if (!(atadev->param.config & ATA_PROTO_ATAPI) || | |
96 | (atadev->param.config == ATA_CFA_MAGIC1) || | |
3ec9ecbc MD |
97 | (atadev->param.config == ATA_CFA_MAGIC2) || |
98 | (atadev->param.config == ATA_CFA_MAGIC3)) | |
c1b3d7c5 TS |
99 | return 0; |
100 | else | |
101 | return ENXIO; | |
102 | } | |
103 | ||
104 | static int | |
105 | ad_attach(device_t dev) | |
106 | { | |
107 | struct ata_channel *ch = device_get_softc(device_get_parent(dev)); | |
108 | struct ata_device *atadev = device_get_softc(dev); | |
a688b15c | 109 | struct disk_info info; |
c1b3d7c5 TS |
110 | struct ad_softc *adp; |
111 | cdev_t cdev; | |
c1b3d7c5 TS |
112 | |
113 | /* check that we have a virgin disk to attach */ | |
114 | if (device_get_ivars(dev)) | |
115 | return EEXIST; | |
116 | ||
a01741bb | 117 | adp = kmalloc(sizeof(struct ad_softc), M_AD, M_INTWAIT | M_ZERO); |
c1b3d7c5 TS |
118 | device_set_ivars(dev, adp); |
119 | ||
cbf684e5 | 120 | /* get device geometry into internal structs */ |
121 | ad_get_geometry(dev); | |
c1b3d7c5 TS |
122 | |
123 | /* init device parameters */ | |
124 | ad_init(dev); | |
125 | ||
126 | /* create the disk device */ | |
127 | /* XXX TGEN Maybe use DEVSTAT_ALL_SUPPORTED, DEVSTAT_TYPE_DIRECT, | |
128 | DEVSTAT_PRIORITY_MAX. */ | |
129 | devstat_add_entry(&adp->stats, "ad", device_get_unit(dev), DEV_BSIZE, | |
130 | DEVSTAT_NO_ORDERED_TAGS, | |
131 | DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE, | |
132 | DEVSTAT_PRIORITY_DISK); | |
a688b15c | 133 | cdev = disk_create(device_get_unit(dev), &adp->disk, &ad_ops); |
c1b3d7c5 TS |
134 | cdev->si_drv1 = dev; |
135 | if (ch->dma) | |
136 | cdev->si_iosize_max = ch->dma->max_iosize; | |
137 | else | |
d83666e0 | 138 | cdev->si_iosize_max = min(MAXPHYS,64*1024); |
c1b3d7c5 | 139 | adp->cdev = cdev; |
a688b15c MD |
140 | |
141 | bzero(&info, sizeof(info)); | |
142 | info.d_media_blksize = DEV_BSIZE; /* mandatory */ | |
143 | info.d_media_blocks = adp->total_secs; | |
144 | ||
145 | info.d_secpertrack = adp->sectors; /* optional */ | |
146 | info.d_nheads = adp->heads; | |
147 | info.d_ncylinders = adp->total_secs/(adp->heads*adp->sectors); | |
148 | info.d_secpercyl = adp->sectors * adp->heads; | |
55230951 | 149 | info.d_serialno = atadev->param.serial; |
a688b15c | 150 | |
c1b3d7c5 TS |
151 | device_add_child(dev, "subdisk", device_get_unit(dev)); |
152 | bus_generic_attach(dev); | |
153 | ||
154 | /* announce we are here */ | |
155 | ad_describe(dev); | |
a688b15c MD |
156 | |
157 | disk_setdiskinfo(&adp->disk, &info); | |
158 | ||
9243051b | 159 | #if defined(__DragonFly__) |
160 | callout_init_mp(&atadev->spindown_timer); | |
161 | #else | |
162 | callout_init(&atadev->spindown_timer, 1); | |
163 | #endif | |
c1b3d7c5 TS |
164 | return 0; |
165 | } | |
166 | ||
167 | static int | |
168 | ad_detach(device_t dev) | |
169 | { | |
170 | struct ad_softc *adp = device_get_ivars(dev); | |
9243051b | 171 | struct ata_device *atadev = device_get_softc(dev); |
c1b3d7c5 TS |
172 | device_t *children; |
173 | int nchildren, i; | |
174 | ||
175 | /* check that we have a valid disk to detach */ | |
176 | if (!adp) | |
177 | return ENXIO; | |
178 | ||
9243051b | 179 | /* destroy the power timeout */ |
180 | callout_drain(&atadev->spindown_timer); | |
181 | ||
c1b3d7c5 TS |
182 | /* detach & delete all children */ |
183 | if (!device_get_children(dev, &children, &nchildren)) { | |
184 | for (i = 0; i < nchildren; i++) | |
185 | if (children[i]) | |
186 | device_delete_child(dev, children[i]); | |
187 | kfree(children, M_TEMP); | |
188 | } | |
189 | ||
190 | /* detroy disk from the system so we dont get any further requests */ | |
191 | disk_invalidate(&adp->disk); | |
192 | disk_destroy(&adp->disk); | |
193 | ||
194 | /* fail requests on the queue and any thats "in flight" for this device */ | |
195 | ata_fail_requests(dev); | |
196 | ||
197 | /* dont leave anything behind */ | |
198 | /* disk_destroy() already took care of the dev_ops */ | |
199 | devstat_remove_entry(&adp->stats); | |
200 | device_set_ivars(dev, NULL); | |
201 | kfree(adp, M_AD); | |
202 | return 0; | |
203 | } | |
204 | ||
205 | static void | |
206 | ad_shutdown(device_t dev) | |
207 | { | |
208 | struct ata_device *atadev = device_get_softc(dev); | |
209 | ||
210 | if (atadev->param.support.command2 & ATA_SUPPORT_FLUSHCACHE) | |
211 | ata_controlcmd(dev, ATA_FLUSHCACHE, 0, 0, 0); | |
212 | } | |
213 | ||
214 | static int | |
215 | ad_reinit(device_t dev) | |
216 | { | |
217 | struct ata_channel *ch = device_get_softc(device_get_parent(dev)); | |
218 | struct ata_device *atadev = device_get_softc(dev); | |
219 | ||
220 | /* if detach pending, return error */ | |
221 | if (((atadev->unit == ATA_MASTER) && !(ch->devices & ATA_ATA_MASTER)) || | |
222 | ((atadev->unit == ATA_SLAVE) && !(ch->devices & ATA_ATA_SLAVE))) { | |
223 | return 1; | |
224 | } | |
225 | ad_init(dev); | |
226 | return 0; | |
227 | } | |
228 | ||
9243051b | 229 | static void |
230 | ad_power_callback(struct ata_request *request) | |
231 | { | |
232 | device_printf(request->dev, "drive spun down.\n"); | |
233 | ata_free_request(request); | |
234 | } | |
235 | ||
236 | static void | |
237 | ad_spindown(void *priv) | |
238 | { | |
239 | device_t dev = priv; | |
240 | struct ata_device *atadev = device_get_softc(dev); | |
241 | struct ata_request *request; | |
242 | ||
243 | if (!atadev->spindown) | |
244 | return; | |
245 | device_printf(dev, "Idle, spin down\n"); | |
246 | atadev->spindown_state = 1; | |
247 | if (!(request = ata_alloc_request())) { | |
248 | device_printf(dev, "FAILURE - out of memory in ad_spindown\n"); | |
249 | return; | |
250 | } | |
251 | request->dev = dev; | |
252 | request->flags = ATA_R_CONTROL; | |
253 | request->timeout = ATA_DEFAULT_TIMEOUT; | |
254 | request->retries = 1; | |
255 | request->callback = ad_power_callback; | |
256 | request->u.ata.command = ATA_STANDBY_IMMEDIATE; | |
257 | ata_queue_request(request); | |
258 | } | |
259 | ||
c1b3d7c5 TS |
260 | static int |
261 | ad_open(struct dev_open_args *ap) | |
262 | { | |
263 | device_t dev = ap->a_head.a_dev->si_drv1; | |
264 | struct ad_softc *adp = device_get_ivars(dev); | |
265 | ||
266 | if (!adp || adp->cdev == NULL) | |
267 | return ENXIO; | |
268 | if(!device_is_attached(dev)) | |
269 | return EBUSY; | |
270 | ||
c1b3d7c5 TS |
271 | return 0; |
272 | } | |
273 | ||
274 | static int | |
275 | ad_close(struct dev_close_args *ap) | |
276 | { | |
c1b3d7c5 TS |
277 | return 0; |
278 | } | |
279 | ||
c1b3d7c5 TS |
280 | static int |
281 | ad_strategy(struct dev_strategy_args *ap) | |
282 | { | |
283 | device_t dev = ap->a_head.a_dev->si_drv1; | |
284 | struct bio *bp = ap->a_bio; | |
285 | struct buf *bbp = bp->bio_buf; | |
286 | struct ata_device *atadev = device_get_softc(dev); | |
287 | struct ata_request *request; | |
288 | struct ad_softc *adp = device_get_ivars(dev); | |
289 | ||
9243051b | 290 | if (atadev->spindown) |
291 | callout_reset(&atadev->spindown_timer, hz * atadev->spindown, | |
292 | ad_spindown, dev); | |
293 | ||
c1b3d7c5 TS |
294 | if (!(request = ata_alloc_request())) { |
295 | device_printf(dev, "FAILURE - out of memory in strategy\n"); | |
bb15467a | 296 | biofinish(bp, NULL, ENOMEM); |
c1b3d7c5 TS |
297 | return(0); |
298 | } | |
299 | ||
300 | /* setup request */ | |
301 | request->dev = dev; | |
302 | request->bio = bp; | |
303 | request->callback = ad_done; | |
9243051b | 304 | if (atadev->spindown_state) { |
305 | device_printf(dev, "request while spun down, starting.\n"); | |
306 | atadev->spindown_state = 0; | |
307 | request->timeout = MAX(ATA_DEFAULT_TIMEOUT, 31); | |
308 | } else { | |
309 | request->timeout = ATA_DEFAULT_TIMEOUT; | |
310 | } | |
c1b3d7c5 TS |
311 | request->retries = 2; |
312 | request->data = bbp->b_data; | |
313 | request->bytecount = bbp->b_bcount; | |
314 | /* lba is block granularity, convert byte granularity bio_offset */ | |
315 | request->u.ata.lba = (u_int64_t)(bp->bio_offset >> DEV_BSHIFT); | |
316 | request->u.ata.count = request->bytecount / DEV_BSIZE; | |
317 | request->transfersize = min(bbp->b_bcount, atadev->max_iosize); | |
318 | ||
319 | switch (bbp->b_cmd) { | |
320 | case BUF_CMD_READ: | |
321 | request->flags = ATA_R_READ; | |
322 | if (atadev->mode >= ATA_DMA) { | |
323 | request->u.ata.command = ATA_READ_DMA; | |
324 | request->flags |= ATA_R_DMA; | |
325 | } | |
326 | else if (request->transfersize > DEV_BSIZE) | |
327 | request->u.ata.command = ATA_READ_MUL; | |
328 | else | |
329 | request->u.ata.command = ATA_READ; | |
330 | break; | |
331 | case BUF_CMD_WRITE: | |
332 | request->flags = ATA_R_WRITE; | |
333 | if (atadev->mode >= ATA_DMA) { | |
334 | request->u.ata.command = ATA_WRITE_DMA; | |
335 | request->flags |= ATA_R_DMA; | |
336 | } | |
337 | else if (request->transfersize > DEV_BSIZE) | |
338 | request->u.ata.command = ATA_WRITE_MUL; | |
339 | else | |
340 | request->u.ata.command = ATA_WRITE; | |
341 | break; | |
87870bc8 MD |
342 | case BUF_CMD_FLUSH: |
343 | request->u.ata.lba = 0; | |
344 | request->u.ata.count = 0; | |
345 | request->u.ata.feature = 0; | |
346 | request->bytecount = 0; | |
347 | request->transfersize = 0; | |
348 | request->flags = ATA_R_CONTROL; | |
349 | request->u.ata.command = ATA_FLUSHCACHE; | |
7648d8d6 | 350 | /* ATA FLUSHCACHE requests may take up to 30 sec to timeout */ |
cbf684e5 | 351 | request->timeout = 30; /* ATA_DEFAULT_TIMEOUT */ |
87870bc8 | 352 | break; |
c1b3d7c5 TS |
353 | default: |
354 | device_printf(dev, "FAILURE - unknown BUF operation\n"); | |
355 | ata_free_request(request); | |
bb15467a | 356 | biofinish(bp, NULL, EIO); |
c1b3d7c5 TS |
357 | return(0); |
358 | } | |
359 | request->flags |= ATA_R_ORDERED; | |
360 | devstat_start_transaction(&adp->stats); | |
361 | ata_queue_request(request); | |
362 | return(0); | |
363 | } | |
364 | ||
365 | static void | |
366 | ad_done(struct ata_request *request) | |
367 | { | |
368 | struct ad_softc *adp = device_get_ivars(request->dev); | |
369 | struct bio *bp = request->bio; | |
370 | struct buf *bbp = bp->bio_buf; | |
371 | ||
372 | /* finish up transfer */ | |
373 | if ((bbp->b_error = request->result)) | |
374 | bbp->b_flags |= B_ERROR; | |
375 | bbp->b_resid = bbp->b_bcount - request->donecount; | |
376 | devstat_end_transaction_buf(&adp->stats, bbp); | |
377 | biodone(bp); | |
378 | ata_free_request(request); | |
379 | } | |
380 | ||
bb15467a | 381 | static int |
382 | ad_ioctl(struct dev_ioctl_args *ap) | |
383 | { | |
384 | return ata_device_ioctl(ap->a_head.a_dev->si_drv1, ap->a_cmd, ap->a_data); | |
385 | } | |
386 | ||
c1b3d7c5 TS |
387 | static int |
388 | ad_dump(struct dev_dump_args *ap) | |
389 | { | |
b24cd69c AH |
390 | device_t dev = ap->a_head.a_dev->si_drv1; |
391 | struct ata_device *atadev = device_get_softc(dev); | |
392 | struct ata_request request; | |
393 | ||
ef352403 | 394 | ata_drop_requests(dev); |
b24cd69c AH |
395 | /* |
396 | * 0 length means flush buffers and return | |
397 | */ | |
398 | if (ap->a_length == 0) { | |
399 | /* flush buffers to media */ | |
400 | if (atadev->param.support.command2 & ATA_SUPPORT_FLUSHCACHE) | |
401 | return ata_controlcmd(dev, ATA_FLUSHCACHE, 0, 0, 0); | |
402 | else | |
403 | return ENXIO; | |
c1b3d7c5 TS |
404 | } |
405 | ||
5c16e43e TS |
406 | bzero(&request, sizeof(struct ata_request)); |
407 | request.dev = dev; | |
b24cd69c AH |
408 | |
409 | request.data = ap->a_virtual; | |
410 | request.bytecount = ap->a_length; | |
5c16e43e | 411 | request.transfersize = min(request.bytecount, atadev->max_iosize); |
b24cd69c AH |
412 | request.flags = ATA_R_WRITE; |
413 | ||
5c16e43e | 414 | if (atadev->mode >= ATA_DMA) { |
b24cd69c AH |
415 | request.u.ata.command = ATA_WRITE_DMA; |
416 | request.flags |= ATA_DMA; | |
5c16e43e | 417 | } else if (request.transfersize > DEV_BSIZE) |
b24cd69c | 418 | request.u.ata.command = ATA_WRITE_MUL; |
5c16e43e | 419 | else |
b24cd69c AH |
420 | request.u.ata.command = ATA_WRITE; |
421 | request.u.ata.lba = ap->a_offset / DEV_BSIZE; | |
422 | request.u.ata.count = request.bytecount / DEV_BSIZE; | |
c1b3d7c5 | 423 | |
b24cd69c AH |
424 | request.timeout = ATA_DEFAULT_TIMEOUT; |
425 | request.retries = 2; | |
c1b3d7c5 | 426 | |
b24cd69c AH |
427 | ata_queue_request(&request); |
428 | return request.result; | |
c1b3d7c5 TS |
429 | } |
430 | ||
431 | static void | |
432 | ad_init(device_t dev) | |
433 | { | |
434 | struct ata_device *atadev = device_get_softc(dev); | |
435 | ||
436 | ATA_SETMODE(device_get_parent(dev), dev); | |
437 | ||
438 | /* enable readahead caching */ | |
439 | if (atadev->param.support.command1 & ATA_SUPPORT_LOOKAHEAD) | |
440 | ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_ENAB_RCACHE, 0, 0); | |
441 | ||
442 | /* enable write caching if supported and configured */ | |
443 | if (atadev->param.support.command1 & ATA_SUPPORT_WRITECACHE) { | |
444 | if (ata_wc) | |
445 | ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_ENAB_WCACHE, 0, 0); | |
446 | else | |
447 | ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_DIS_WCACHE, 0, 0); | |
448 | } | |
449 | ||
450 | /* use multiple sectors/interrupt if device supports it */ | |
451 | if (ad_version(atadev->param.version_major)) { | |
79db9382 | 452 | int secsperint = max(1, min(atadev->param.sectors_intr & 0xff, 16)); |
c1b3d7c5 TS |
453 | |
454 | if (!ata_controlcmd(dev, ATA_SET_MULTI, 0, 0, secsperint)) | |
455 | atadev->max_iosize = secsperint * DEV_BSIZE; | |
456 | } | |
457 | else | |
458 | atadev->max_iosize = DEV_BSIZE; | |
459 | } | |
460 | ||
cbf684e5 | 461 | static void |
462 | ad_get_geometry(device_t dev) | |
463 | { | |
464 | struct ata_device *atadev = device_get_softc(dev); | |
465 | struct ad_softc *adp = device_get_ivars(dev); | |
466 | u_int64_t lbasize48; | |
467 | u_int32_t lbasize; | |
468 | ||
469 | if ((atadev->param.atavalid & ATA_FLAG_54_58) && | |
470 | atadev->param.current_heads && atadev->param.current_sectors) { | |
471 | adp->heads = atadev->param.current_heads; | |
472 | adp->sectors = atadev->param.current_sectors; | |
473 | adp->total_secs = (u_int32_t)atadev->param.current_size_1 | | |
474 | ((u_int32_t)atadev->param.current_size_2 << 16); | |
475 | } | |
476 | else { | |
477 | adp->heads = atadev->param.heads; | |
478 | adp->sectors = atadev->param.sectors; | |
479 | adp->total_secs = atadev->param.cylinders * adp->heads * adp->sectors; | |
480 | } | |
481 | lbasize = (u_int32_t)atadev->param.lba_size_1 | | |
482 | ((u_int32_t)atadev->param.lba_size_2 << 16); | |
483 | ||
484 | /* does this device need oldstyle CHS addressing */ | |
485 | if (!ad_version(atadev->param.version_major) || !lbasize) | |
486 | atadev->flags |= ATA_D_USE_CHS; | |
487 | ||
488 | /* use the 28bit LBA size if valid or bigger than the CHS mapping */ | |
489 | if (atadev->param.cylinders == 16383 || adp->total_secs < lbasize) | |
490 | adp->total_secs = lbasize; | |
491 | ||
492 | /* use the 48bit LBA size if valid */ | |
493 | lbasize48 = ((u_int64_t)atadev->param.lba_size48_1) | | |
494 | ((u_int64_t)atadev->param.lba_size48_2 << 16) | | |
495 | ((u_int64_t)atadev->param.lba_size48_3 << 32) | | |
496 | ((u_int64_t)atadev->param.lba_size48_4 << 48); | |
497 | if ((atadev->param.support.command2 & ATA_SUPPORT_ADDRESS48) && | |
498 | lbasize48 > ATA_MAX_28BIT_LBA) | |
499 | adp->total_secs = lbasize48; | |
500 | } | |
501 | ||
8406cf70 | 502 | static void |
c1b3d7c5 TS |
503 | ad_describe(device_t dev) |
504 | { | |
505 | struct ata_channel *ch = device_get_softc(device_get_parent(dev)); | |
506 | struct ata_device *atadev = device_get_softc(dev); | |
507 | struct ad_softc *adp = device_get_ivars(dev); | |
508 | u_int8_t *marker, vendor[64], product[64]; | |
509 | ||
510 | /* try to seperate the ATA model string into vendor and model parts */ | |
511 | if ((marker = index(atadev->param.model, ' ')) || | |
512 | (marker = index(atadev->param.model, '-'))) { | |
513 | int len = (marker - atadev->param.model); | |
514 | ||
515 | strncpy(vendor, atadev->param.model, len); | |
516 | vendor[len++] = 0; | |
517 | strcat(vendor, " "); | |
518 | strncpy(product, atadev->param.model + len, 40 - len); | |
519 | vendor[40 - len] = 0; | |
520 | } | |
521 | else { | |
522 | if (!strncmp(atadev->param.model, "ST", 2)) | |
523 | strcpy(vendor, "Seagate "); | |
3ec9ecbc MD |
524 | else if (!strncmp(atadev->param.model, "HDS", 3)) |
525 | strcpy(vendor, "Hitachi "); | |
c1b3d7c5 TS |
526 | else |
527 | strcpy(vendor, ""); | |
528 | strncpy(product, atadev->param.model, 40); | |
529 | } | |
530 | ||
bb15467a | 531 | device_printf(dev, "%juMB <%s%s %.8s> at ata%d-%s %s%s\n", |
532 | adp->total_secs / (1048576 / DEV_BSIZE), | |
c1b3d7c5 | 533 | vendor, product, atadev->param.revision, |
cbf684e5 | 534 | device_get_unit(ch->dev), ata_unit2str(atadev), |
c1b3d7c5 TS |
535 | (adp->flags & AD_F_TAG_ENABLED) ? "tagged " : "", |
536 | ata_mode2str(atadev->mode)); | |
537 | if (bootverbose) { | |
bb15467a | 538 | device_printf(dev, "%ju sectors [%juC/%dH/%dS] " |
539 | "%d sectors/interrupt %d depth queue\n", adp->total_secs, | |
540 | adp->total_secs / (adp->heads * adp->sectors), | |
c1b3d7c5 TS |
541 | adp->heads, adp->sectors, atadev->max_iosize / DEV_BSIZE, |
542 | adp->num_tags + 1); | |
543 | } | |
544 | } | |
545 | ||
546 | static int | |
547 | ad_version(u_int16_t version) | |
548 | { | |
549 | int bit; | |
550 | ||
551 | if (version == 0xffff) | |
552 | return 0; | |
553 | for (bit = 15; bit >= 0; bit--) | |
554 | if (version & (1<<bit)) | |
555 | return bit; | |
556 | return 0; | |
557 | } | |
558 | ||
559 | static device_method_t ad_methods[] = { | |
560 | /* device interface */ | |
561 | DEVMETHOD(device_probe, ad_probe), | |
562 | DEVMETHOD(device_attach, ad_attach), | |
563 | DEVMETHOD(device_detach, ad_detach), | |
564 | DEVMETHOD(device_shutdown, ad_shutdown), | |
565 | ||
566 | /* ATA methods */ | |
567 | DEVMETHOD(ata_reinit, ad_reinit), | |
568 | ||
d3c9c58e | 569 | DEVMETHOD_END |
c1b3d7c5 TS |
570 | }; |
571 | ||
572 | static driver_t ad_driver = { | |
573 | "ad", | |
574 | ad_methods, | |
575 | 0, | |
576 | }; | |
577 | ||
578 | devclass_t ad_devclass; | |
579 | ||
580 | DRIVER_MODULE(ad, ata, ad_driver, ad_devclass, NULL, NULL); | |
581 | MODULE_VERSION(ad, 1); | |
582 | MODULE_DEPEND(ad, ata, 1, 1, 1); |