Sync usage with man page.
[netbsd-mini2440.git] / sys / dev / usb / umass_isdata.c
blob0d19070aca5e48e3023a3211dacef56f47ec7307
1 /* $NetBSD: umass_isdata.c,v 1.17 2008/04/28 20:24:00 martin Exp $ */
3 /*
4 * TODO:
5 * get ATA registers on any kind of error
6 * implement more commands (what is needed)
7 */
9 /*
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
19 * are met:
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>
45 #include <sys/conf.h>
46 #include <sys/buf.h>
47 #include <sys/device.h>
48 #include <sys/proc.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>
64 /* XXX move this */
65 struct isd200_config {
66 uByte EventNotification;
67 uByte ExternalClock;
68 uByte ATAInitTimeout;
69 uByte ATAMisc1;
70 #define ATATiming 0x0f
71 #define ATAPIReset 0x10
72 #define MasterSlaveSelection 0x20
73 #define ATAPICommandBlockSize 0xc0
74 uByte ATAMajorCommand;
75 uByte ATAMinorCommand;
76 uByte ATAMisc2;
77 #define LastLUNIdentifier 0x07
78 #define DescriptOverride 0x08
79 #define ATA3StateSuspend 0x10
80 #define SkipDeviceBoot 0x20
81 #define ConfigDescriptor2 0x40
82 #define InitStatus 0x80
83 uByte ATAMisc3;
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;
92 void *sc_ata_bio;
93 u_long sc_skip;
96 #undef DPRINTF
97 #undef DPRINTFN
98 #ifdef UISDATA_DEBUG
99 #define DPRINTF(x) if (uisdatadebug) logprintf x
100 #define DPRINTFN(n,x) if (uisdatadebug>(n)) logprintf x
101 int uisdatadebug = 0;
102 #else
103 #define DPRINTF(x)
104 #define DPRINTFN(n,x)
105 #endif
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 = {
122 SCSIPI_BUSTYPE_ATA,
123 uisdata_bio,
124 uisdata_reset_drive,
125 uisdata_reset_channel,
126 uisdata_exec_command,
127 uisdata_get_params,
128 uisdata_addref,
129 uisdata_delref,
130 uisdata_kill_pending,
133 struct ata_cmd {
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
161 u_int8_t ac_error;
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;
170 u_int8_t ac_status;
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;
182 usbd_status err;
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;
192 req.bRequest = 0x02;
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);
198 if (err)
199 return (EIO);
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);
218 return (0);
222 void
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;
227 int s;
229 DPRINTF(("%s: residue=%d status=%d\n", __func__, residue, status));
231 s = splbio();
232 scbus->sc_ata_bio = NULL;
233 if (status != STATUS_CMD_OK)
234 ata_bio->error = ERR_DF; /* ??? */
235 else
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;
243 if (residue != 0) {
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*/
248 splx(s);
249 return;
252 if (ata_bio->flags & ATA_POLL) {
253 DPRINTF(("%s: wakeup %p\n", __func__, ata_bio));
254 wakeup(ata_bio);
255 } else {
256 (*scbus->sc_drv_data.drv_done)(scbus->sc_drv_data.drv_softc);
258 splx(s);
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;
267 scbus->sc_skip = 0;
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;
277 struct ata_cmd ata;
278 u_int16_t cyl;
279 u_int8_t head, sect;
280 int dir;
281 long nbytes;
282 u_int nblks;
284 DPRINTF(("%s\n", __func__));
285 /* XXX */
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);
297 } else
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;
304 head |= WDSD_LBA;
305 } else {
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;
312 cyl = blkno;
313 head |= WDSD_CHS;
316 nbytes = ata_bio->bcount;
317 if (ata_bio->flags & ATA_SINGLE)
318 nblks = 1;
319 else
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 |
336 AC_SelectCommand;
338 dir = DIR_NONE;
339 if (ata_bio->bcount != 0) {
340 if (ata_bio->flags & ATA_READ)
341 dir = DIR_IN;
342 else
343 dir = DIR_OUT;
346 if (ata_bio->flags & ATA_READ) {
347 ata.ac_command = WDCC_READ;
348 } else {
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;
374 void
375 uisdata_reset_drive(struct ata_drive_datas *drv, int flags)
377 DPRINTFN(-1,("%s\n", __func__));
378 /* XXX what? */
381 void
382 uisdata_reset_channel(struct ata_channel *chp, int flags)
384 DPRINTFN(-1,("%s\n", __func__));
385 /* XXX what? */
388 void
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));
402 wakeup(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;
412 int dir;
413 struct ata_cmd ata;
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));
419 dir = DIR_NONE;
420 if (cmd->bcount != 0) {
421 if (cmd->flags & AT_READ)
422 dir = DIR_IN;
423 else
424 dir = DIR_OUT;
427 if (cmd->bcount > UMASS_MAX_TRANSFER_SIZE) {
428 printf("uisdata_exec_command: large datalen %d\n", cmd->bcount);
429 cmd->flags |= AT_ERROR;
430 goto done;
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) {
439 case WDCC_IDENTIFY:
440 ata.ac_register_select |= AC_SelectCommand;
441 ata.ac_command = WDCC_IDENTIFY;
442 break;
443 default:
444 printf("uisdata_exec_command: bad command 0x%02x\n",
445 cmd->r_command);
446 cmd->flags |= AT_ERROR;
447 goto done;
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)) {
456 #if 0
457 if (cmd->flags & AT_POLL)
458 printf("%s: AT_POLL not supported\n", __func__);
459 #endif
460 DPRINTF(("%s: tsleep %p\n", __func__, cmd));
461 if (tsleep(cmd, PZERO, "uisdataex", 0)) {
462 cmd->flags |= AT_ERROR;
463 goto done;
467 done:
468 return (ATACMD_COMPLETE);
472 uisdata_addref(struct ata_drive_datas *drv)
474 DPRINTF(("%s\n", __func__));
475 /* Nothing to do */
476 return (0);
479 void
480 uisdata_delref(struct ata_drive_datas *drv)
482 DPRINTF(("%s\n", __func__));
483 /* Nothing to do */
486 void
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__));
495 if (ata_bio == NULL)
496 return;
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)
508 char tb[DEV_BSIZE];
509 struct ata_command ata_c;
511 #if BYTE_ORDER == LITTLE_ENDIAN
512 int i;
513 u_int16_t *p;
514 #endif
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;
525 ata_c.data = tb;
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"));
529 return (CMD_AGAIN);
531 if (ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
532 DPRINTF(("uisdata_get_parms: ata_c.flags=0x%x\n",
533 ata_c.flags));
534 return (CMD_ERR);
535 } else {
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) ==
545 WDC_CFG_ATAPI &&
546 ((prms->atap_model[0] == 'N' &&
547 prms->atap_model[1] == 'E') ||
548 (prms->atap_model[0] == 'F' &&
549 prms->atap_model[1] == 'X')))
550 return 0;
551 for (i = 0; i < sizeof(prms->atap_model); i += 2) {
552 p = (u_short *)(prms->atap_model + i);
553 *p = ntohs(*p);
555 for (i = 0; i < sizeof(prms->atap_serial); i += 2) {
556 p = (u_short *)(prms->atap_serial + i);
557 *p = ntohs(*p);
559 for (i = 0; i < sizeof(prms->atap_revision); i += 2) {
560 p = (u_short *)(prms->atap_revision + i);
561 *p = ntohs(*p);
563 #endif
564 return CMD_OK;
569 /* XXX join with wdc.c routine? */
571 uwdprint(void *aux, const char *pnp)
573 //struct ata_device *adev = aux;
574 if (pnp)
575 aprint_normal("wd at %s", pnp);
576 #if 0
577 aprint_normal(" channel %d drive %d", adev->adev_channel,
578 adev->adev_drv_data->drive);
579 #endif
580 return (UNCONF);
584 #if 0
586 int umass_wd_attach(struct umass_softc *);
588 #if NWD > 0
589 case UMASS_CPROTO_ISD_ATA:
590 return (umass_wd_attach(sc));
591 #endif
593 #endif