1 /* $NetBSD: umass_isdata.c,v 1.9 2003/12/30 19:30:39 thorpej Exp $ */
2
3 /*
4 * TODO:
5 * get ATA registers on any kind of error
6 * implement more commands (what is needed)
7 */
8
9 /*
10 * Copyright (c) 2001 The NetBSD Foundation, Inc.
11 * All rights reserved.
12 *
13 * This code is derived from software contributed to The NetBSD Foundation
14 * by Lennart Augustsson (lennart@augustsson.net) at
15 * Carlstedt Research & Technology.
16 *
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.
25 * 3. All advertising materials mentioning features or use of this software
26 * must display the following acknowledgement:
27 * This product includes software developed by the NetBSD
28 * Foundation, Inc. and its contributors.
29 * 4. Neither the name of The NetBSD Foundation nor the names of its
30 * contributors may be used to endorse or promote products derived
31 * from this software without specific prior written permission.
32 *
33 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
34 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
35 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
36 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
37 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
38 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
39 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
40 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
41 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
43 * POSSIBILITY OF SUCH DAMAGE.
44 */
45
46 #include <sys/cdefs.h>
47 __KERNEL_RCSID(0, "$NetBSD: umass_isdata.c,v 1.9 2003/12/30 19:30:39 thorpej Exp $");
48
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/kernel.h>
52 #include <sys/conf.h>
53 #include <sys/buf.h>
54 #include <sys/device.h>
55 #include <sys/proc.h>
56 #include <sys/disklabel.h>
57 #include <sys/malloc.h>
58
59 #include <dev/usb/usb.h>
60 #include <dev/usb/usbdi.h>
61 #include <dev/usb/usbdi_util.h>
62
63 #include <dev/usb/umassvar.h>
64 #include <dev/usb/umass_isdata.h>
65
66 int umass_wd_attach(struct umass_softc *);
67
68 #include <dev/ata/atareg.h>
69 #include <dev/ata/atavar.h>
70
71 /* XXX move this */
72 struct isd200_config {
73 uByte EventNotification;
74 uByte ExternalClock;
75 uByte ATAInitTimeout;
76 uByte ATAMisc1;
77 #define ATATiming 0x0f
78 #define ATAPIReset 0x10
79 #define MasterSlaveSelection 0x20
80 #define ATAPICommandBlockSize 0xc0
81 uByte ATAMajorCommand;
82 uByte ATAMinorCommand;
83 uByte ATAMisc2;
84 #define LastLUNIdentifier 0x07
85 #define DescriptOverride 0x08
86 #define ATA3StateSuspend 0x10
87 #define SkipDeviceBoot 0x20
88 #define ConfigDescriptor2 0x40
89 #define InitStatus 0x80
90 uByte ATAMisc3;
91 #define SRSTEnable 0x01
92 };
93
94 struct uisdata_softc {
95 struct umassbus_softc base;
96
97 struct ata_drive_datas sc_drv_data;
98 struct isd200_config sc_isd_config;
99 void *sc_ata_bio;
100 u_long sc_skip;
101 };
102
103 #undef DPRINTF
104 #undef DPRINTFN
105 #ifdef UISDATA_DEBUG
106 #define DPRINTF(x) if (uisdatadebug) logprintf x
107 #define DPRINTFN(n,x) if (uisdatadebug>(n)) logprintf x
108 int uisdatadebug = 0;
109 #else
110 #define DPRINTF(x)
111 #define DPRINTFN(n,x)
112 #endif
113
114 int uisdata_bio(struct ata_drive_datas *, struct ata_bio *);
115 int uisdata_bio1(struct ata_drive_datas *, struct ata_bio *);
116 void uisdata_reset_channel(struct ata_drive_datas *, int);
117 int uisdata_exec_command(struct ata_drive_datas *, struct wdc_command *);
118 int uisdata_get_params(struct ata_drive_datas *, u_int8_t, struct ataparams *);
119 int uisdata_addref(struct ata_drive_datas *);
120 void uisdata_delref(struct ata_drive_datas *);
121 void uisdata_kill_pending(struct ata_drive_datas *);
122
123 void uisdata_bio_cb(struct umass_softc *, void *, int, int);
124 void uisdata_exec_cb(struct umass_softc *, void *, int, int);
125 int uwdprint(void *, const char *);
126
127 const struct ata_bustype uisdata_bustype = {
128 SCSIPI_BUSTYPE_ATA,
129 uisdata_bio,
130 uisdata_reset_channel,
131 uisdata_exec_command,
132 uisdata_get_params,
133 uisdata_addref,
134 uisdata_delref,
135 uisdata_kill_pending,
136 };
137
138 struct ata_cmd {
139 u_int8_t ac_signature0;
140 u_int8_t ac_signature1;
141
142 u_int8_t ac_action_select;
143 #define AC_ReadRegisterAccess 0x01
144 #define AC_NoDeviceSelectionBit 0x02
145 #define AC_NoBSYPollBit 0x04
146 #define AC_IgnorePhaseErrorBit 0x08
147 #define AC_IgnoreDeviceErrorBit 0x10
148
149 u_int8_t ac_register_select;
150 #define AC_SelectAlternateStatus 0x01 /* R */
151 #define AC_SelectDeviceControl 0x01 /* W */
152 #define AC_SelectError 0x02 /* R */
153 #define AC_SelectFeatures 0x02 /* W */
154 #define AC_SelectSectorCount 0x04 /* RW */
155 #define AC_SelectSectorNumber 0x08 /* RW */
156 #define AC_SelectCylinderLow 0x10 /* RW */
157 #define AC_SelectCylinderHigh 0x20 /* RW */
158 #define AC_SelectDeviceHead 0x40 /* RW */
159 #define AC_SelectStatus 0x80 /* R */
160 #define AC_SelectCommand 0x80 /* W */
161
162 u_int8_t ac_transfer_blocksize;
163
164 u_int8_t ac_alternate_status;
165 #define ac_device_control ac_alternate_status
166 u_int8_t ac_error;
167 #define ac_features ac_error
168
169 u_int8_t ac_sector_count;
170 u_int8_t ac_sector_number;
171 u_int8_t ac_cylinder_low;
172 u_int8_t ac_cylinder_high;
173 u_int8_t ac_device_head;
174
175 u_int8_t ac_status;
176 #define ac_command ac_status
177
178 u_int8_t ac_reserved[3];
179 };
180
181 #define ATA_DELAY 10000 /* 10s for a drive I/O */
182
183 int
184 umass_isdata_attach(struct umass_softc *sc)
185 {
186 usb_device_request_t req;
187 usbd_status err;
188 struct ata_device adev;
189 struct uisdata_softc *scbus;
190 struct isd200_config *cf;
191
192 scbus = malloc(sizeof *scbus, M_DEVBUF, M_WAITOK | M_ZERO);
193 sc->bus = &scbus->base;
194 cf = &scbus->sc_isd_config;
195
196 req.bmRequestType = UT_READ_VENDOR_DEVICE;
197 req.bRequest = 0x02;
198 USETW(req.wValue, 0);
199 USETW(req.wIndex, 2);
200 USETW(req.wLength, sizeof *cf);
201
202 err = usbd_do_request(sc->sc_udev, &req, cf);
203 if (err)
204 return (EIO);
205 DPRINTF(("umass_wd_attach info:\n EventNotification=0x%02x "
206 "ExternalClock=0x%02x ATAInitTimeout=0x%02x\n"
207 " ATAMisc1=0x%02x ATAMajorCommand=0x%02x "
208 "ATAMinorCommand=0x%02x\n"
209 " ATAMisc2=0x%02x ATAMisc3=0x%02x\n",
210 cf->EventNotification, cf->ExternalClock, cf->ATAInitTimeout,
211 cf->ATAMisc1, cf->ATAMajorCommand, cf->ATAMinorCommand,
212 cf->ATAMisc2, cf->ATAMisc3));
213
214 memset(&adev, 0, sizeof(struct ata_device));
215 adev.adev_bustype = &uisdata_bustype;
216 adev.adev_channel = 1; /* XXX */
217 adev.adev_openings = 1;
218 adev.adev_drv_data = &scbus->sc_drv_data;
219 scbus->sc_drv_data.drive_flags = DRIVE_ATA;
220 scbus->sc_drv_data.chnl_softc = sc;
221 scbus->base.sc_child = config_found(&sc->sc_dev, &adev, uwdprint);
222
223 return (0);
224 }
225
226
227 void
228 uisdata_bio_cb(struct umass_softc *sc, void *priv, int residue, int status)
229 {
230 struct uisdata_softc *scbus = (struct uisdata_softc *)sc->bus;
231 struct ata_bio *ata_bio = priv;
232 int s;
233
234 DPRINTF(("%s: residue=%d status=%d\n", __func__, residue, status));
235
236 s = splbio();
237 scbus->sc_ata_bio = NULL;
238 if (status != STATUS_CMD_OK)
239 ata_bio->error = ERR_DF; /* ??? */
240 else
241 ata_bio->error = NOERROR;
242 ata_bio->flags |= ATA_ITSDONE;
243
244 ata_bio->blkdone += ata_bio->nblks;
245 ata_bio->blkno += ata_bio->nblks;
246 ata_bio->bcount -= ata_bio->nbytes;
247 scbus->sc_skip += ata_bio->nbytes;
248 if (residue != 0) {
249 ata_bio->bcount += residue;
250 } else if (ata_bio->bcount > 0) {
251 DPRINTF(("%s: continue\n", __func__));
252 (void)uisdata_bio1(&scbus->sc_drv_data, ata_bio); /*XXX save drv*/
253 splx(s);
254 return;
255 }
256
257 if (ata_bio->flags & ATA_POLL) {
258 DPRINTF(("%s: wakeup %p\n", __func__, ata_bio));
259 wakeup(ata_bio);
260 } else {
261 (*scbus->sc_drv_data.drv_done)(scbus->sc_drv_data.drv_softc);
262 }
263 splx(s);
264 }
265
266 int
267 uisdata_bio(struct ata_drive_datas *drv, struct ata_bio *ata_bio)
268 {
269 struct umass_softc *sc = drv->chnl_softc;
270 struct uisdata_softc *scbus = (struct uisdata_softc *)sc->bus;
271
272 scbus->sc_skip = 0;
273 return (uisdata_bio1(drv, ata_bio));
274 }
275
276 int
277 uisdata_bio1(struct ata_drive_datas *drv, struct ata_bio *ata_bio)
278 {
279 struct umass_softc *sc = drv->chnl_softc;
280 struct uisdata_softc *scbus = (struct uisdata_softc *)sc->bus;
281 struct isd200_config *cf = &scbus->sc_isd_config;
282 struct ata_cmd ata;
283 u_int16_t cyl;
284 u_int8_t head, sect;
285 int dir;
286 long nbytes;
287 u_int nblks;
288
289 DPRINTF(("%s\n", __func__));
290 /* XXX */
291
292 if (ata_bio->flags & ATA_NOSLEEP) {
293 printf("%s: ATA_NOSLEEP not supported\n", __func__);
294 ata_bio->error = TIMEOUT;
295 ata_bio->flags |= ATA_ITSDONE;
296 return (WDC_COMPLETE);
297 }
298
299 if (scbus->sc_ata_bio != NULL) {
300 printf("%s: multiple uisdata_bio\n", __func__);
301 return (WDC_TRY_AGAIN);
302 } else
303 scbus->sc_ata_bio = ata_bio;
304
305 if (ata_bio->flags & ATA_LBA) {
306 sect = (ata_bio->blkno >> 0) & 0xff;
307 cyl = (ata_bio->blkno >> 8) & 0xffff;
308 head = (ata_bio->blkno >> 24) & 0x0f;
309 head |= WDSD_LBA;
310 } else {
311 int blkno = ata_bio->blkno;
312 sect = blkno % ata_bio->lp->d_nsectors;
313 sect++; /* Sectors begin with 1, not 0. */
314 blkno /= ata_bio->lp->d_nsectors;
315 head = blkno % ata_bio->lp->d_ntracks;
316 blkno /= ata_bio->lp->d_ntracks;
317 cyl = blkno;
318 head |= WDSD_CHS;
319 }
320
321 nbytes = ata_bio->bcount;
322 if (ata_bio->flags & ATA_SINGLE)
323 nblks = 1;
324 else
325 nblks = min(ata_bio->multi, nbytes / ata_bio->lp->d_secsize);
326 nbytes = nblks * ata_bio->lp->d_secsize;
327 ata_bio->nblks = nblks;
328 ata_bio->nbytes = nbytes;
329
330 memset(&ata, 0, sizeof ata);
331 ata.ac_signature0 = cf->ATAMajorCommand;
332 ata.ac_signature1 = cf->ATAMinorCommand;
333 ata.ac_transfer_blocksize = 1;
334 ata.ac_sector_count = nblks;
335 ata.ac_sector_number = sect;
336 ata.ac_cylinder_high = cyl >> 8;
337 ata.ac_cylinder_low = cyl;
338 ata.ac_device_head = head;
339 ata.ac_register_select = AC_SelectSectorCount | AC_SelectSectorNumber |
340 AC_SelectCylinderLow | AC_SelectCylinderHigh | AC_SelectDeviceHead |
341 AC_SelectCommand;
342
343 dir = DIR_NONE;
344 if (ata_bio->bcount != 0) {
345 if (ata_bio->flags & ATA_READ)
346 dir = DIR_IN;
347 else
348 dir = DIR_OUT;
349 }
350
351 if (ata_bio->flags & ATA_READ) {
352 ata.ac_command = WDCC_READ;
353 } else {
354 ata.ac_command = WDCC_WRITE;
355 }
356 DPRINTF(("%s: bno=%" PRId64 " LBA=%d cyl=%d head=%d sect=%d "
357 "count=%d multi=%d\n",
358 __func__, ata_bio->blkno,
359 (ata_bio->flags & ATA_LBA) != 0, cyl, head, sect,
360 ata.ac_sector_count, ata_bio->multi));
361 DPRINTF((" data=%p bcount=%ld, drive=%d\n", ata_bio->databuf,
362 ata_bio->bcount, drv->drive));
363 sc->sc_methods->wire_xfer(sc, drv->drive, &ata, sizeof ata,
364 ata_bio->databuf + scbus->sc_skip, nbytes,
365 dir, ATA_DELAY, uisdata_bio_cb, ata_bio);
366
367 while (ata_bio->flags & ATA_POLL) {
368 DPRINTF(("%s: tsleep %p\n", __func__, ata_bio));
369 if (tsleep(ata_bio, PZERO, "uisdatabl", 0)) {
370 ata_bio->error = TIMEOUT;
371 ata_bio->flags |= ATA_ITSDONE;
372 return (WDC_COMPLETE);
373 }
374 }
375
376 return (ata_bio->flags & ATA_ITSDONE) ? WDC_COMPLETE : WDC_QUEUED;
377 }
378
379 void
380 uisdata_reset_channel(struct ata_drive_datas *drv, int flags)
381 {
382 DPRINTFN(-1,("%s\n", __func__));
383 /* XXX what? */
384 }
385
386 void
387 uisdata_exec_cb(struct umass_softc *sc, void *priv, int residue, int status)
388 {
389 struct wdc_command *cmd = priv;
390
391 DPRINTF(("%s: status=%d\n", __func__, status));
392 if (status != STATUS_CMD_OK)
393 cmd->flags |= AT_DF; /* XXX */
394 cmd->flags |= AT_DONE;
395 if (cmd->flags & (AT_POLL | AT_WAIT)) {
396 DPRINTF(("%s: wakeup %p\n", __func__, cmd));
397 wakeup(cmd);
398 }
399 }
400
401 int
402 uisdata_exec_command(struct ata_drive_datas *drv, struct wdc_command *cmd)
403 {
404 struct umass_softc *sc = drv->chnl_softc;
405 struct uisdata_softc *scbus = (struct uisdata_softc *)sc->bus;
406 struct isd200_config *cf = &scbus->sc_isd_config;
407 int dir;
408 struct ata_cmd ata;
409
410 DPRINTF(("%s\n", __func__));
411 DPRINTF((" r_command=0x%02x timeout=%d flags=0x%x bcount=%d\n",
412 cmd->r_command, cmd->timeout, cmd->flags, cmd->bcount));
413
414 dir = DIR_NONE;
415 if (cmd->bcount != 0) {
416 if (cmd->flags & AT_READ)
417 dir = DIR_IN;
418 else
419 dir = DIR_OUT;
420 }
421
422 if (cmd->bcount > UMASS_MAX_TRANSFER_SIZE) {
423 printf("uisdata_exec_command: large datalen %d\n", cmd->bcount);
424 cmd->flags |= AT_ERROR;
425 goto done;
426 }
427
428 memset(&ata, 0, sizeof ata);
429 ata.ac_signature0 = cf->ATAMajorCommand;
430 ata.ac_signature1 = cf->ATAMinorCommand;
431 ata.ac_transfer_blocksize = 1;
432
433 switch (cmd->r_command) {
434 case WDCC_IDENTIFY:
435 ata.ac_register_select |= AC_SelectCommand;
436 ata.ac_command = WDCC_IDENTIFY;
437 break;
438 default:
439 printf("uisdata_exec_command: bad command 0x%02x\n",
440 cmd->r_command);
441 cmd->flags |= AT_ERROR;
442 goto done;
443 }
444
445 DPRINTF(("%s: execute ATA command 0x%02x, drive=%d\n", __func__,
446 ata.ac_command, drv->drive));
447 sc->sc_methods->wire_xfer(sc, drv->drive, &ata,
448 sizeof ata, cmd->data, cmd->bcount, dir,
449 cmd->timeout, uisdata_exec_cb, cmd);
450 if (cmd->flags & (AT_POLL | AT_WAIT)) {
451 #if 0
452 if (cmd->flags & AT_POLL)
453 printf("%s: AT_POLL not supported\n", __func__);
454 #endif
455 DPRINTF(("%s: tsleep %p\n", __func__, cmd));
456 if (tsleep(cmd, PZERO, "uisdataex", 0)) {
457 cmd->flags |= AT_ERROR;
458 goto done;
459 }
460 }
461
462 done:
463 return (WDC_COMPLETE);
464 }
465
466 int
467 uisdata_addref(struct ata_drive_datas *drv)
468 {
469 DPRINTF(("%s\n", __func__));
470 /* Nothing to do */
471 return (0);
472 }
473
474 void
475 uisdata_delref(struct ata_drive_datas *drv)
476 {
477 DPRINTF(("%s\n", __func__));
478 /* Nothing to do */
479 }
480
481 void
482 uisdata_kill_pending(struct ata_drive_datas *drv)
483 {
484 struct umass_softc *sc = drv->chnl_softc;
485 struct uisdata_softc *scbus = (struct uisdata_softc *)sc->bus;
486 struct ata_bio *ata_bio = scbus->sc_ata_bio;
487
488 DPRINTFN(-1,("%s\n", __func__));
489
490 if (ata_bio == NULL)
491 return;
492 scbus->sc_ata_bio = NULL;
493 ata_bio->flags |= ATA_ITSDONE;
494 ata_bio->error = ERR_NODEV;
495 ata_bio->r_error = WDCE_ABRT;
496 (*scbus->sc_drv_data.drv_done)(scbus->sc_drv_data.drv_softc);
497 }
498
499 int
500 uisdata_get_params(struct ata_drive_datas *drvp, u_int8_t flags,
501 struct ataparams *prms)
502 {
503 char tb[DEV_BSIZE];
504 struct wdc_command wdc_c;
505
506 #if BYTE_ORDER == LITTLE_ENDIAN
507 int i;
508 u_int16_t *p;
509 #endif
510
511 DPRINTF(("%s\n", __func__));
512
513 memset(tb, 0, DEV_BSIZE);
514 memset(prms, 0, sizeof(struct ataparams));
515 memset(&wdc_c, 0, sizeof(struct wdc_command));
516
517 wdc_c.r_command = WDCC_IDENTIFY;
518 wdc_c.timeout = 1000; /* 1s */
519 wdc_c.flags = AT_READ | flags;
520 wdc_c.data = tb;
521 wdc_c.bcount = DEV_BSIZE;
522 if (uisdata_exec_command(drvp, &wdc_c) != WDC_COMPLETE) {
523 DPRINTF(("uisdata_get_parms: wdc_exec_command failed\n"));
524 return (CMD_AGAIN);
525 }
526 if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
527 DPRINTF(("uisdata_get_parms: wdc_c.flags=0x%x\n",
528 wdc_c.flags));
529 return (CMD_ERR);
530 } else {
531 /* Read in parameter block. */
532 memcpy(prms, tb, sizeof(struct ataparams));
533 #if BYTE_ORDER == LITTLE_ENDIAN
534 /* XXX copied from ata.c */
535 /*
536 * Shuffle string byte order.
537 * ATAPI Mitsumi and NEC drives don't need this.
538 */
539 if ((prms->atap_config & WDC_CFG_ATAPI_MASK) ==
540 WDC_CFG_ATAPI &&
541 ((prms->atap_model[0] == 'N' &&
542 prms->atap_model[1] == 'E') ||
543 (prms->atap_model[0] == 'F' &&
544 prms->atap_model[1] == 'X')))
545 return 0;
546 for (i = 0; i < sizeof(prms->atap_model); i += 2) {
547 p = (u_short *)(prms->atap_model + i);
548 *p = ntohs(*p);
549 }
550 for (i = 0; i < sizeof(prms->atap_serial); i += 2) {
551 p = (u_short *)(prms->atap_serial + i);
552 *p = ntohs(*p);
553 }
554 for (i = 0; i < sizeof(prms->atap_revision); i += 2) {
555 p = (u_short *)(prms->atap_revision + i);
556 *p = ntohs(*p);
557 }
558 #endif
559 return CMD_OK;
560 }
561 }
562
563
564 /* XXX join with wdc.c routine? */
565 int
566 uwdprint(void *aux, const char *pnp)
567 {
568 //struct ata_device *adev = aux;
569 if (pnp)
570 aprint_normal("wd at %s", pnp);
571 #if 0
572 aprint_normal(" channel %d drive %d", adev->adev_channel,
573 adev->adev_drv_data->drive);
574 #endif
575 return (UNCONF);
576 }
577
578
579 #if 0
580
581 int umass_wd_attach(struct umass_softc *);
582
583 #if NWD > 0
584 case UMASS_CPROTO_ISD_ATA:
585 return (umass_wd_attach(sc));
586 #endif
587
588 #endif
Cache object: 96ea9def041e9158f177bebf3775abca
|