1 /* $NetBSD: umass_isdata.c,v 1.17 2008/04/28 20:24:00 martin Exp $ */
5 * get ATA registers on any kind of error
6 * implement more commands (what is needed)
10 * Copyright (c) 2001 The NetBSD Foundation, Inc.
11 * All rights reserved.
13 * This code is derived from software contributed to The NetBSD Foundation
14 * by Lennart Augustsson (lennart@augustsson.net) at
15 * Carlstedt Research & Technology.
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: umass_isdata.c,v 1.17 2008/04/28 20:24:00 martin Exp $");
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
47 #include <sys/device.h>
49 #include <sys/disklabel.h>
50 #include <sys/malloc.h>
52 #include <dev/usb/usb.h>
53 #include <dev/usb/usbdi.h>
54 #include <dev/usb/usbdi_util.h>
56 #include <dev/usb/umassvar.h>
57 #include <dev/usb/umass_isdata.h>
59 int umass_wd_attach(struct umass_softc
*);
61 #include <dev/ata/atareg.h>
62 #include <dev/ata/atavar.h>
65 struct isd200_config
{
66 uByte EventNotification
;
70 #define ATATiming 0x0f
71 #define ATAPIReset 0x10
72 #define MasterSlaveSelection 0x20
73 #define ATAPICommandBlockSize 0xc0
74 uByte ATAMajorCommand
;
75 uByte ATAMinorCommand
;
77 #define LastLUNIdentifier 0x07
78 #define DescriptOverride 0x08
79 #define ATA3StateSuspend 0x10
80 #define SkipDeviceBoot 0x20
81 #define ConfigDescriptor2 0x40
82 #define InitStatus 0x80
84 #define SRSTEnable 0x01
87 struct uisdata_softc
{
88 struct umassbus_softc base
;
90 struct ata_drive_datas sc_drv_data
;
91 struct isd200_config sc_isd_config
;
99 #define DPRINTF(x) if (uisdatadebug) logprintf x
100 #define DPRINTFN(n,x) if (uisdatadebug>(n)) logprintf x
101 int uisdatadebug
= 0;
104 #define DPRINTFN(n,x)
107 int uisdata_bio(struct ata_drive_datas
*, struct ata_bio
*);
108 int uisdata_bio1(struct ata_drive_datas
*, struct ata_bio
*);
109 void uisdata_reset_drive(struct ata_drive_datas
*, int);
110 void uisdata_reset_channel(struct ata_channel
*, int);
111 int uisdata_exec_command(struct ata_drive_datas
*, struct ata_command
*);
112 int uisdata_get_params(struct ata_drive_datas
*, u_int8_t
, struct ataparams
*);
113 int uisdata_addref(struct ata_drive_datas
*);
114 void uisdata_delref(struct ata_drive_datas
*);
115 void uisdata_kill_pending(struct ata_drive_datas
*);
117 void uisdata_bio_cb(struct umass_softc
*, void *, int, int);
118 void uisdata_exec_cb(struct umass_softc
*, void *, int, int);
119 int uwdprint(void *, const char *);
121 const struct ata_bustype uisdata_bustype
= {
125 uisdata_reset_channel
,
126 uisdata_exec_command
,
130 uisdata_kill_pending
,
134 u_int8_t ac_signature0
;
135 u_int8_t ac_signature1
;
137 u_int8_t ac_action_select
;
138 #define AC_ReadRegisterAccess 0x01
139 #define AC_NoDeviceSelectionBit 0x02
140 #define AC_NoBSYPollBit 0x04
141 #define AC_IgnorePhaseErrorBit 0x08
142 #define AC_IgnoreDeviceErrorBit 0x10
144 u_int8_t ac_register_select
;
145 #define AC_SelectAlternateStatus 0x01 /* R */
146 #define AC_SelectDeviceControl 0x01 /* W */
147 #define AC_SelectError 0x02 /* R */
148 #define AC_SelectFeatures 0x02 /* W */
149 #define AC_SelectSectorCount 0x04 /* RW */
150 #define AC_SelectSectorNumber 0x08 /* RW */
151 #define AC_SelectCylinderLow 0x10 /* RW */
152 #define AC_SelectCylinderHigh 0x20 /* RW */
153 #define AC_SelectDeviceHead 0x40 /* RW */
154 #define AC_SelectStatus 0x80 /* R */
155 #define AC_SelectCommand 0x80 /* W */
157 u_int8_t ac_transfer_blocksize
;
159 u_int8_t ac_alternate_status
;
160 #define ac_device_control ac_alternate_status
162 #define ac_features ac_error
164 u_int8_t ac_sector_count
;
165 u_int8_t ac_sector_number
;
166 u_int8_t ac_cylinder_low
;
167 u_int8_t ac_cylinder_high
;
168 u_int8_t ac_device_head
;
171 #define ac_command ac_status
173 u_int8_t ac_reserved
[3];
176 #define ATA_DELAY 10000 /* 10s for a drive I/O */
179 umass_isdata_attach(struct umass_softc
*sc
)
181 usb_device_request_t req
;
183 struct ata_device adev
;
184 struct uisdata_softc
*scbus
;
185 struct isd200_config
*cf
;
187 scbus
= malloc(sizeof *scbus
, M_DEVBUF
, M_WAITOK
| M_ZERO
);
188 sc
->bus
= &scbus
->base
;
189 cf
= &scbus
->sc_isd_config
;
191 req
.bmRequestType
= UT_READ_VENDOR_DEVICE
;
193 USETW(req
.wValue
, 0);
194 USETW(req
.wIndex
, 2);
195 USETW(req
.wLength
, sizeof *cf
);
197 err
= usbd_do_request(sc
->sc_udev
, &req
, cf
);
200 DPRINTF(("umass_wd_attach info:\n EventNotification=0x%02x "
201 "ExternalClock=0x%02x ATAInitTimeout=0x%02x\n"
202 " ATAMisc1=0x%02x ATAMajorCommand=0x%02x "
203 "ATAMinorCommand=0x%02x\n"
204 " ATAMisc2=0x%02x ATAMisc3=0x%02x\n",
205 cf
->EventNotification
, cf
->ExternalClock
, cf
->ATAInitTimeout
,
206 cf
->ATAMisc1
, cf
->ATAMajorCommand
, cf
->ATAMinorCommand
,
207 cf
->ATAMisc2
, cf
->ATAMisc3
));
209 memset(&adev
, 0, sizeof(struct ata_device
));
210 adev
.adev_bustype
= &uisdata_bustype
;
211 adev
.adev_channel
= 1; /* XXX */
212 adev
.adev_openings
= 1;
213 adev
.adev_drv_data
= &scbus
->sc_drv_data
;
214 scbus
->sc_drv_data
.drive_flags
= DRIVE_ATA
;
215 scbus
->sc_drv_data
.chnl_softc
= sc
;
216 scbus
->base
.sc_child
= config_found(sc
->sc_dev
, &adev
, uwdprint
);
223 uisdata_bio_cb(struct umass_softc
*sc
, void *priv
, int residue
, int status
)
225 struct uisdata_softc
*scbus
= (struct uisdata_softc
*)sc
->bus
;
226 struct ata_bio
*ata_bio
= priv
;
229 DPRINTF(("%s: residue=%d status=%d\n", __func__
, residue
, status
));
232 scbus
->sc_ata_bio
= NULL
;
233 if (status
!= STATUS_CMD_OK
)
234 ata_bio
->error
= ERR_DF
; /* ??? */
236 ata_bio
->error
= NOERROR
;
237 ata_bio
->flags
|= ATA_ITSDONE
;
239 ata_bio
->blkdone
+= ata_bio
->nblks
;
240 ata_bio
->blkno
+= ata_bio
->nblks
;
241 ata_bio
->bcount
-= ata_bio
->nbytes
;
242 scbus
->sc_skip
+= ata_bio
->nbytes
;
244 ata_bio
->bcount
+= residue
;
245 } else if (ata_bio
->bcount
> 0) {
246 DPRINTF(("%s: continue\n", __func__
));
247 (void)uisdata_bio1(&scbus
->sc_drv_data
, ata_bio
); /*XXX save drv*/
252 if (ata_bio
->flags
& ATA_POLL
) {
253 DPRINTF(("%s: wakeup %p\n", __func__
, ata_bio
));
256 (*scbus
->sc_drv_data
.drv_done
)(scbus
->sc_drv_data
.drv_softc
);
262 uisdata_bio(struct ata_drive_datas
*drv
, struct ata_bio
*ata_bio
)
264 struct umass_softc
*sc
= drv
->chnl_softc
;
265 struct uisdata_softc
*scbus
= (struct uisdata_softc
*)sc
->bus
;
268 return (uisdata_bio1(drv
, ata_bio
));
272 uisdata_bio1(struct ata_drive_datas
*drv
, struct ata_bio
*ata_bio
)
274 struct umass_softc
*sc
= drv
->chnl_softc
;
275 struct uisdata_softc
*scbus
= (struct uisdata_softc
*)sc
->bus
;
276 struct isd200_config
*cf
= &scbus
->sc_isd_config
;
284 DPRINTF(("%s\n", __func__
));
287 if (ata_bio
->flags
& ATA_NOSLEEP
) {
288 printf("%s: ATA_NOSLEEP not supported\n", __func__
);
289 ata_bio
->error
= TIMEOUT
;
290 ata_bio
->flags
|= ATA_ITSDONE
;
291 return (ATACMD_COMPLETE
);
294 if (scbus
->sc_ata_bio
!= NULL
) {
295 printf("%s: multiple uisdata_bio\n", __func__
);
296 return (ATACMD_TRY_AGAIN
);
298 scbus
->sc_ata_bio
= ata_bio
;
300 if (ata_bio
->flags
& ATA_LBA
) {
301 sect
= (ata_bio
->blkno
>> 0) & 0xff;
302 cyl
= (ata_bio
->blkno
>> 8) & 0xffff;
303 head
= (ata_bio
->blkno
>> 24) & 0x0f;
306 int blkno
= ata_bio
->blkno
;
307 sect
= blkno
% ata_bio
->lp
->d_nsectors
;
308 sect
++; /* Sectors begin with 1, not 0. */
309 blkno
/= ata_bio
->lp
->d_nsectors
;
310 head
= blkno
% ata_bio
->lp
->d_ntracks
;
311 blkno
/= ata_bio
->lp
->d_ntracks
;
316 nbytes
= ata_bio
->bcount
;
317 if (ata_bio
->flags
& ATA_SINGLE
)
320 nblks
= min(ata_bio
->multi
, nbytes
/ ata_bio
->lp
->d_secsize
);
321 nbytes
= nblks
* ata_bio
->lp
->d_secsize
;
322 ata_bio
->nblks
= nblks
;
323 ata_bio
->nbytes
= nbytes
;
325 memset(&ata
, 0, sizeof ata
);
326 ata
.ac_signature0
= cf
->ATAMajorCommand
;
327 ata
.ac_signature1
= cf
->ATAMinorCommand
;
328 ata
.ac_transfer_blocksize
= 1;
329 ata
.ac_sector_count
= nblks
;
330 ata
.ac_sector_number
= sect
;
331 ata
.ac_cylinder_high
= cyl
>> 8;
332 ata
.ac_cylinder_low
= cyl
;
333 ata
.ac_device_head
= head
;
334 ata
.ac_register_select
= AC_SelectSectorCount
| AC_SelectSectorNumber
|
335 AC_SelectCylinderLow
| AC_SelectCylinderHigh
| AC_SelectDeviceHead
|
339 if (ata_bio
->bcount
!= 0) {
340 if (ata_bio
->flags
& ATA_READ
)
346 if (ata_bio
->flags
& ATA_READ
) {
347 ata
.ac_command
= WDCC_READ
;
349 ata
.ac_command
= WDCC_WRITE
;
351 DPRINTF(("%s: bno=%" PRId64
" LBA=%d cyl=%d head=%d sect=%d "
352 "count=%d multi=%d\n",
353 __func__
, ata_bio
->blkno
,
354 (ata_bio
->flags
& ATA_LBA
) != 0, cyl
, head
, sect
,
355 ata
.ac_sector_count
, ata_bio
->multi
));
356 DPRINTF((" data=%p bcount=%ld, drive=%d\n", ata_bio
->databuf
,
357 ata_bio
->bcount
, drv
->drive
));
358 sc
->sc_methods
->wire_xfer(sc
, drv
->drive
, &ata
, sizeof ata
,
359 ata_bio
->databuf
+ scbus
->sc_skip
, nbytes
,
360 dir
, ATA_DELAY
, uisdata_bio_cb
, ata_bio
);
362 while (ata_bio
->flags
& ATA_POLL
) {
363 DPRINTF(("%s: tsleep %p\n", __func__
, ata_bio
));
364 if (tsleep(ata_bio
, PZERO
, "uisdatabl", 0)) {
365 ata_bio
->error
= TIMEOUT
;
366 ata_bio
->flags
|= ATA_ITSDONE
;
367 return (ATACMD_COMPLETE
);
371 return (ata_bio
->flags
& ATA_ITSDONE
) ? ATACMD_COMPLETE
: ATACMD_QUEUED
;
375 uisdata_reset_drive(struct ata_drive_datas
*drv
, int flags
)
377 DPRINTFN(-1,("%s\n", __func__
));
382 uisdata_reset_channel(struct ata_channel
*chp
, int flags
)
384 DPRINTFN(-1,("%s\n", __func__
));
389 uisdata_exec_cb(struct umass_softc
*sc
, void *priv
,
390 int residue
, int status
)
392 struct ata_command
*cmd
= priv
;
394 DPRINTF(("%s: status=%d\n", __func__
, status
));
395 if (status
!= STATUS_CMD_OK
)
396 cmd
->flags
|= AT_DF
; /* XXX */
397 cmd
->flags
|= AT_DONE
;
398 if (cmd
->flags
& (AT_READ
| AT_WRITE
))
399 cmd
->flags
|= AT_XFDONE
;
400 if (cmd
->flags
& (AT_POLL
| AT_WAIT
)) {
401 DPRINTF(("%s: wakeup %p\n", __func__
, cmd
));
407 uisdata_exec_command(struct ata_drive_datas
*drv
, struct ata_command
*cmd
)
409 struct umass_softc
*sc
= drv
->chnl_softc
;
410 struct uisdata_softc
*scbus
= (struct uisdata_softc
*)sc
->bus
;
411 struct isd200_config
*cf
= &scbus
->sc_isd_config
;
415 DPRINTF(("%s\n", __func__
));
416 DPRINTF((" r_command=0x%02x timeout=%d flags=0x%x bcount=%d\n",
417 cmd
->r_command
, cmd
->timeout
, cmd
->flags
, cmd
->bcount
));
420 if (cmd
->bcount
!= 0) {
421 if (cmd
->flags
& AT_READ
)
427 if (cmd
->bcount
> UMASS_MAX_TRANSFER_SIZE
) {
428 printf("uisdata_exec_command: large datalen %d\n", cmd
->bcount
);
429 cmd
->flags
|= AT_ERROR
;
433 memset(&ata
, 0, sizeof ata
);
434 ata
.ac_signature0
= cf
->ATAMajorCommand
;
435 ata
.ac_signature1
= cf
->ATAMinorCommand
;
436 ata
.ac_transfer_blocksize
= 1;
438 switch (cmd
->r_command
) {
440 ata
.ac_register_select
|= AC_SelectCommand
;
441 ata
.ac_command
= WDCC_IDENTIFY
;
444 printf("uisdata_exec_command: bad command 0x%02x\n",
446 cmd
->flags
|= AT_ERROR
;
450 DPRINTF(("%s: execute ATA command 0x%02x, drive=%d\n", __func__
,
451 ata
.ac_command
, drv
->drive
));
452 sc
->sc_methods
->wire_xfer(sc
, drv
->drive
, &ata
,
453 sizeof ata
, cmd
->data
, cmd
->bcount
, dir
,
454 cmd
->timeout
, uisdata_exec_cb
, cmd
);
455 if (cmd
->flags
& (AT_POLL
| AT_WAIT
)) {
457 if (cmd
->flags
& AT_POLL
)
458 printf("%s: AT_POLL not supported\n", __func__
);
460 DPRINTF(("%s: tsleep %p\n", __func__
, cmd
));
461 if (tsleep(cmd
, PZERO
, "uisdataex", 0)) {
462 cmd
->flags
|= AT_ERROR
;
468 return (ATACMD_COMPLETE
);
472 uisdata_addref(struct ata_drive_datas
*drv
)
474 DPRINTF(("%s\n", __func__
));
480 uisdata_delref(struct ata_drive_datas
*drv
)
482 DPRINTF(("%s\n", __func__
));
487 uisdata_kill_pending(struct ata_drive_datas
*drv
)
489 struct umass_softc
*sc
= drv
->chnl_softc
;
490 struct uisdata_softc
*scbus
= (struct uisdata_softc
*)sc
->bus
;
491 struct ata_bio
*ata_bio
= scbus
->sc_ata_bio
;
493 DPRINTFN(-1,("%s\n", __func__
));
497 scbus
->sc_ata_bio
= NULL
;
498 ata_bio
->flags
|= ATA_ITSDONE
;
499 ata_bio
->error
= ERR_NODEV
;
500 ata_bio
->r_error
= WDCE_ABRT
;
501 (*scbus
->sc_drv_data
.drv_done
)(scbus
->sc_drv_data
.drv_softc
);
505 uisdata_get_params(struct ata_drive_datas
*drvp
, u_int8_t flags
,
506 struct ataparams
*prms
)
509 struct ata_command ata_c
;
511 #if BYTE_ORDER == LITTLE_ENDIAN
516 DPRINTF(("%s\n", __func__
));
518 memset(tb
, 0, DEV_BSIZE
);
519 memset(prms
, 0, sizeof(struct ataparams
));
520 memset(&ata_c
, 0, sizeof(struct ata_command
));
522 ata_c
.r_command
= WDCC_IDENTIFY
;
523 ata_c
.timeout
= 1000; /* 1s */
524 ata_c
.flags
= AT_READ
| flags
;
526 ata_c
.bcount
= DEV_BSIZE
;
527 if (uisdata_exec_command(drvp
, &ata_c
) != ATACMD_COMPLETE
) {
528 DPRINTF(("uisdata_get_parms: wdc_exec_command failed\n"));
531 if (ata_c
.flags
& (AT_ERROR
| AT_TIMEOU
| AT_DF
)) {
532 DPRINTF(("uisdata_get_parms: ata_c.flags=0x%x\n",
536 /* Read in parameter block. */
537 memcpy(prms
, tb
, sizeof(struct ataparams
));
538 #if BYTE_ORDER == LITTLE_ENDIAN
539 /* XXX copied from ata.c */
541 * Shuffle string byte order.
542 * ATAPI Mitsumi and NEC drives don't need this.
544 if ((prms
->atap_config
& WDC_CFG_ATAPI_MASK
) ==
546 ((prms
->atap_model
[0] == 'N' &&
547 prms
->atap_model
[1] == 'E') ||
548 (prms
->atap_model
[0] == 'F' &&
549 prms
->atap_model
[1] == 'X')))
551 for (i
= 0; i
< sizeof(prms
->atap_model
); i
+= 2) {
552 p
= (u_short
*)(prms
->atap_model
+ i
);
555 for (i
= 0; i
< sizeof(prms
->atap_serial
); i
+= 2) {
556 p
= (u_short
*)(prms
->atap_serial
+ i
);
559 for (i
= 0; i
< sizeof(prms
->atap_revision
); i
+= 2) {
560 p
= (u_short
*)(prms
->atap_revision
+ i
);
569 /* XXX join with wdc.c routine? */
571 uwdprint(void *aux
, const char *pnp
)
573 //struct ata_device *adev = aux;
575 aprint_normal("wd at %s", pnp
);
577 aprint_normal(" channel %d drive %d", adev
->adev_channel
,
578 adev
->adev_drv_data
->drive
);
586 int umass_wd_attach(struct umass_softc
*);
589 case UMASS_CPROTO_ISD_ATA
:
590 return (umass_wd_attach(sc
));