1*e7c2d835Sjsg /* $OpenBSD: atapiscsi.c,v 1.122 2024/06/22 10:22:29 jsg Exp $ */
27481efa2Scsapuntz
37481efa2Scsapuntz /*
47481efa2Scsapuntz * This code is derived from code with the copyright below.
57481efa2Scsapuntz */
67481efa2Scsapuntz
77481efa2Scsapuntz /*
87481efa2Scsapuntz * Copyright (c) 1996, 1998 Manuel Bouyer.
97481efa2Scsapuntz *
107481efa2Scsapuntz * Redistribution and use in source and binary forms, with or without
117481efa2Scsapuntz * modification, are permitted provided that the following conditions
127481efa2Scsapuntz * are met:
137481efa2Scsapuntz * 1. Redistributions of source code must retain the above copyright
147481efa2Scsapuntz * notice, this list of conditions and the following disclaimer.
157481efa2Scsapuntz * 2. Redistributions in binary form must reproduce the above copyright
167481efa2Scsapuntz * notice, this list of conditions and the following disclaimer in the
177481efa2Scsapuntz * documentation and/or other materials provided with the distribution.
187481efa2Scsapuntz *
197481efa2Scsapuntz * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
207481efa2Scsapuntz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
217481efa2Scsapuntz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
227481efa2Scsapuntz * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
237481efa2Scsapuntz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
247481efa2Scsapuntz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
257481efa2Scsapuntz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
267481efa2Scsapuntz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
277481efa2Scsapuntz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
287481efa2Scsapuntz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
297481efa2Scsapuntz * SUCH DAMAGE.
307481efa2Scsapuntz *
317481efa2Scsapuntz */
327481efa2Scsapuntz
337481efa2Scsapuntz #include <sys/param.h>
347481efa2Scsapuntz #include <sys/systm.h>
357481efa2Scsapuntz #include <sys/kernel.h>
367481efa2Scsapuntz #include <sys/device.h>
379f5e13a3Sho #include <sys/timeout.h>
387481efa2Scsapuntz #include <scsi/scsi_all.h>
39ec62f1edSniklas #include <scsi/scsi_tape.h>
407481efa2Scsapuntz #include <scsi/scsiconf.h>
417481efa2Scsapuntz
427481efa2Scsapuntz #include <machine/bus.h>
437481efa2Scsapuntz #include <machine/cpu.h>
447481efa2Scsapuntz #include <machine/intr.h>
457481efa2Scsapuntz
467481efa2Scsapuntz #include <dev/ata/atareg.h>
477481efa2Scsapuntz #include <dev/ata/atavar.h>
487481efa2Scsapuntz #include <dev/ic/wdcreg.h>
497481efa2Scsapuntz #include <dev/ic/wdcvar.h>
5095c10403Scsapuntz #include <dev/ic/wdcevent.h>
517481efa2Scsapuntz
520c6728ddScsapuntz /* drive states stored in ata_drive_datas */
5366bb6343Scsapuntz enum atapi_drive_states {
5466bb6343Scsapuntz ATAPI_RESET_BASE_STATE = 0,
5566bb6343Scsapuntz ATAPI_DEVICE_RESET_WAIT_STATE = 1,
562702c783Scsapuntz ATAPI_IDENTIFY_STATE = 2,
572702c783Scsapuntz ATAPI_IDENTIFY_WAIT_STATE = 3,
582702c783Scsapuntz ATAPI_PIOMODE_STATE = 4,
592702c783Scsapuntz ATAPI_PIOMODE_WAIT_STATE = 5,
602702c783Scsapuntz ATAPI_DMAMODE_STATE = 6,
612702c783Scsapuntz ATAPI_DMAMODE_WAIT_STATE = 7,
622702c783Scsapuntz ATAPI_READY_STATE = 8
6366bb6343Scsapuntz };
640c6728ddScsapuntz
657481efa2Scsapuntz #define DEBUG_INTR 0x01
667481efa2Scsapuntz #define DEBUG_XFERS 0x02
677481efa2Scsapuntz #define DEBUG_STATUS 0x04
687481efa2Scsapuntz #define DEBUG_FUNCS 0x08
697481efa2Scsapuntz #define DEBUG_PROBE 0x10
70ec62f1edSniklas #define DEBUG_DSC 0x20
71ec62f1edSniklas #define DEBUG_POLL 0x40
7236acebdeScsapuntz #define DEBUG_ERRORS 0x80 /* Debug error handling code */
7336acebdeScsapuntz
74c9eb5cb9Scsapuntz #if defined(WDCDEBUG)
7582fc695dSgrange #ifndef WDCDEBUG_ATAPI_MASK
7682fc695dSgrange #define WDCDEBUG_ATAPI_MASK 0x00
7782fc695dSgrange #endif
7882fc695dSgrange int wdcdebug_atapi_mask = WDCDEBUG_ATAPI_MASK;
79d6986e4fSgrange #define WDCDEBUG_PRINT(args, level) do { \
80d6986e4fSgrange if ((wdcdebug_atapi_mask & (level)) != 0) \
81d6986e4fSgrange printf args; \
82d6986e4fSgrange } while (0)
837481efa2Scsapuntz #else
847481efa2Scsapuntz #define WDCDEBUG_PRINT(args, level)
857481efa2Scsapuntz #endif
867481efa2Scsapuntz
87ec62f1edSniklas /* 10 ms, this is used only before sending a cmd. */
88ec62f1edSniklas #define ATAPI_DELAY 10
892702c783Scsapuntz #define ATAPI_RESET_DELAY 1000
909ec8daebSderaadt #define ATAPI_RESET_WAIT 2000
91a24b05dfScsapuntz #define ATAPI_CTRL_WAIT 4000
92ec62f1edSniklas
93ec62f1edSniklas /* When polling, let the exponential backoff max out at 1 second's interval. */
94ec62f1edSniklas #define ATAPI_POLL_MAXTIC (hz)
957481efa2Scsapuntz
96c4071fd1Smillert void wdc_atapi_start(struct channel_softc *,struct wdc_xfer *);
97a24b05dfScsapuntz
98c4071fd1Smillert void wdc_atapi_timer_handler(void *);
99a24b05dfScsapuntz
100c4071fd1Smillert void wdc_atapi_real_start(struct channel_softc *, struct wdc_xfer *,
101c4071fd1Smillert int, struct atapi_return_args *);
102c4071fd1Smillert void wdc_atapi_real_start_2(struct channel_softc *, struct wdc_xfer *,
103c4071fd1Smillert int, struct atapi_return_args *);
104c4071fd1Smillert void wdc_atapi_intr_command(struct channel_softc *, struct wdc_xfer *,
105c4071fd1Smillert int, struct atapi_return_args *);
106c4071fd1Smillert void wdc_atapi_intr_data(struct channel_softc *, struct wdc_xfer *,
107c4071fd1Smillert int, struct atapi_return_args *);
108c4071fd1Smillert void wdc_atapi_intr_complete(struct channel_softc *, struct wdc_xfer *,
109c4071fd1Smillert int, struct atapi_return_args *);
110c4071fd1Smillert void wdc_atapi_pio_intr(struct channel_softc *, struct wdc_xfer *,
111c4071fd1Smillert int, struct atapi_return_args *);
112c4071fd1Smillert void wdc_atapi_send_packet(struct channel_softc *, struct wdc_xfer *,
113c4071fd1Smillert int, struct atapi_return_args *);
114c4071fd1Smillert void wdc_atapi_ctrl(struct channel_softc *, struct wdc_xfer *,
115c4071fd1Smillert int, struct atapi_return_args *);
116a24b05dfScsapuntz
117c4071fd1Smillert char *wdc_atapi_in_data_phase(struct wdc_xfer *, int, int);
118a24b05dfScsapuntz
119c4071fd1Smillert int wdc_atapi_intr(struct channel_softc *, struct wdc_xfer *, int);
120c4071fd1Smillert void wdc_atapi_done(struct channel_softc *, struct wdc_xfer *,
121c4071fd1Smillert int, struct atapi_return_args *);
122c4071fd1Smillert void wdc_atapi_reset(struct channel_softc *, struct wdc_xfer *,
123c4071fd1Smillert int, struct atapi_return_args *);
124c4071fd1Smillert void wdc_atapi_reset_2(struct channel_softc *, struct wdc_xfer *,
125c4071fd1Smillert int, struct atapi_return_args *);
1267481efa2Scsapuntz
127c4071fd1Smillert void wdc_atapi_tape_done(struct channel_softc *, struct wdc_xfer *,
128c4071fd1Smillert int, struct atapi_return_args *);
1297481efa2Scsapuntz
130c4071fd1Smillert int atapiscsi_match(struct device *, void *, void *);
131c4071fd1Smillert void atapiscsi_attach(struct device *, struct device *, void *);
1329a379db1Sderaadt int atapiscsi_activate(struct device *, int);
133a3f240fdSmiod int atapiscsi_detach(struct device *, int);
134c4071fd1Smillert int atapi_to_scsi_sense(struct scsi_xfer *, u_int8_t);
1357481efa2Scsapuntz
1360de5a53dSespie enum atapi_state { as_none, as_data, as_completed };
1370de5a53dSespie
1387481efa2Scsapuntz struct atapiscsi_softc {
1397481efa2Scsapuntz struct device sc_dev;
14048d11ec3Scsapuntz struct channel_softc *chp;
141e61c843cScsapuntz enum atapi_state protocol_phase;
1429ec8daebSderaadt
1435252c952Scsapuntz int drive;
1447481efa2Scsapuntz };
1457481efa2Scsapuntz
146fdca2419Sdlg int wdc_atapi_ioctl(struct scsi_link *, u_long, caddr_t, int);
147bae03be6Skrw void wdc_atapi_send_cmd(struct scsi_xfer *sc_xfer);
14866bb6343Scsapuntz
149a454aff3Snaddy static const struct scsi_adapter atapiscsi_switch = {
150f4b58f5aSkrw wdc_atapi_send_cmd, NULL, NULL, NULL, wdc_atapi_ioctl
1517481efa2Scsapuntz };
1527481efa2Scsapuntz
1534b1a56afSjsg /* Initial version shares bus_link structure so it can easily
1547481efa2Scsapuntz be "attached to current" wdc driver */
1557481efa2Scsapuntz
156471aeecfSnaddy const struct cfattach atapiscsi_ca = {
157a3f240fdSmiod sizeof(struct atapiscsi_softc), atapiscsi_match, atapiscsi_attach,
1589a379db1Sderaadt atapiscsi_detach, atapiscsi_activate
1597481efa2Scsapuntz };
1607481efa2Scsapuntz
1617481efa2Scsapuntz struct cfdriver atapiscsi_cd = {
1627481efa2Scsapuntz NULL, "atapiscsi", DV_DULL
1637481efa2Scsapuntz };
1647481efa2Scsapuntz
1657481efa2Scsapuntz
1669ec8daebSderaadt int
atapiscsi_match(struct device * parent,void * match,void * aux)167c28b5ab2Smatthew atapiscsi_match(struct device *parent, void *match, void *aux)
1687481efa2Scsapuntz {
1697481efa2Scsapuntz struct ata_atapi_attach *aa_link = aux;
1707481efa2Scsapuntz struct cfdata *cf = match;
1717481efa2Scsapuntz
1727481efa2Scsapuntz if (aa_link == NULL)
1737481efa2Scsapuntz return (0);
17448d11ec3Scsapuntz
1757481efa2Scsapuntz if (aa_link->aa_type != T_ATAPI)
1767481efa2Scsapuntz return (0);
1777481efa2Scsapuntz
1787481efa2Scsapuntz if (cf->cf_loc[0] != aa_link->aa_channel &&
1797481efa2Scsapuntz cf->cf_loc[0] != -1)
1807481efa2Scsapuntz return (0);
1817481efa2Scsapuntz
1827481efa2Scsapuntz return (1);
1837481efa2Scsapuntz }
1847481efa2Scsapuntz
1857481efa2Scsapuntz void
atapiscsi_attach(struct device * parent,struct device * self,void * aux)186c28b5ab2Smatthew atapiscsi_attach(struct device *parent, struct device *self, void *aux)
1877481efa2Scsapuntz {
1887481efa2Scsapuntz struct atapiscsi_softc *as = (struct atapiscsi_softc *)self;
1897481efa2Scsapuntz struct ata_atapi_attach *aa_link = aux;
19073d09fc5Sdlg struct scsibus_attach_args saa;
1915252c952Scsapuntz struct ata_drive_datas *drvp = aa_link->aa_drv_data;
1925252c952Scsapuntz struct channel_softc *chp = drvp->chnl_softc;
1935252c952Scsapuntz struct ataparams *id = &drvp->id;
194cb45a5fdSdlg struct device *child;
1957481efa2Scsapuntz
196a1f52200Sdlg extern struct scsi_iopool wdc_xfer_iopool;
197a1f52200Sdlg
198a0a14a4eSderaadt printf("\n");
199a0a14a4eSderaadt
200731fd99bSfgsch /* Initialize shared data. */
201731fd99bSfgsch scsi_init();
202731fd99bSfgsch
203551bdc0fSderaadt #ifdef WDCDEBUG
204d348db70Scsapuntz if (chp->wdc->sc_dev.dv_cfdata->cf_flags & WDC_OPTION_PROBE_VERBOSE)
205d348db70Scsapuntz wdcdebug_atapi_mask |= DEBUG_PROBE;
206551bdc0fSderaadt #endif
207d348db70Scsapuntz
20848d11ec3Scsapuntz as->chp = chp;
2095252c952Scsapuntz as->drive = drvp->drive;
2107481efa2Scsapuntz
211f981035cSdlg strlcpy(drvp->drive_name, as->sc_dev.dv_xname,
212f981035cSdlg sizeof(drvp->drive_name));
213f97ca3e4Scsapuntz drvp->cf_flags = as->sc_dev.dv_cfdata->cf_flags;
214f97ca3e4Scsapuntz
21548d11ec3Scsapuntz wdc_probe_caps(drvp, id);
2167481efa2Scsapuntz
217551bdc0fSderaadt WDCDEBUG_PRINT(
218ec62f1edSniklas ("general config %04x capabilities %04x ",
219551bdc0fSderaadt id->atap_config, id->atap_capabilities1),
220551bdc0fSderaadt DEBUG_PROBE);
221ec62f1edSniklas
222ec8802a4Scsapuntz if ((NERRS_MAX - 2) > 0)
223ec8802a4Scsapuntz drvp->n_dmaerrs = NERRS_MAX - 2;
224ec8802a4Scsapuntz else
225ec8802a4Scsapuntz drvp->n_dmaerrs = 0;
22666bb6343Scsapuntz drvp->drive_flags |= DRIVE_DEVICE_RESET;
22766bb6343Scsapuntz
228ec62f1edSniklas /* Tape drives do funny DSC stuff */
229ec62f1edSniklas if (ATAPI_CFG_TYPE(id->atap_config) ==
230ec62f1edSniklas ATAPI_CFG_TYPE_SEQUENTIAL)
231ec62f1edSniklas drvp->atapi_cap |= ACAP_DSC;
232ec62f1edSniklas
233ec62f1edSniklas if ((id->atap_config & ATAPI_CFG_CMD_MASK) ==
234ec62f1edSniklas ATAPI_CFG_CMD_16)
235a077a3e9Scsapuntz drvp->atapi_cap |= ACAP_LEN;
236a077a3e9Scsapuntz
237ec62f1edSniklas drvp->atapi_cap |=
238ec62f1edSniklas (id->atap_config & ATAPI_CFG_DRQ_MASK);
239ec62f1edSniklas
240551bdc0fSderaadt WDCDEBUG_PRINT(("driver caps %04x\n", drvp->atapi_cap),
241551bdc0fSderaadt DEBUG_PROBE);
24248d11ec3Scsapuntz
2433ba66839Skrw
244ead808c4Skrw saa.saa_adapter_softc = as;
245ead808c4Skrw saa.saa_adapter_target = SDEV_NO_ADAPTER_TARGET;
246ead808c4Skrw saa.saa_adapter_buswidth = 2;
247ead808c4Skrw saa.saa_adapter = &atapiscsi_switch;
248ead808c4Skrw saa.saa_luns = 1;
249e5eae15dSkrw saa.saa_openings = 1;
250e5eae15dSkrw saa.saa_flags = SDEV_ATAPI;
251e5eae15dSkrw saa.saa_pool = &wdc_xfer_iopool;
252e5eae15dSkrw saa.saa_quirks = 0;
253e5eae15dSkrw saa.saa_wwpn = saa.saa_wwnn = 0;
25473d09fc5Sdlg
25573d09fc5Sdlg child = config_found((struct device *)as, &saa, scsiprint);
256ad0c6836Scsapuntz
257cb45a5fdSdlg if (child != NULL) {
258cb45a5fdSdlg struct scsibus_softc *scsi = (struct scsibus_softc *)child;
259a0870786Smatthew struct scsi_link *link = scsi_get_link(scsi, 0, 0);
26048d11ec3Scsapuntz
261c1dfe69fSniklas if (link) {
262f981035cSdlg strlcpy(drvp->drive_name,
263f97ca3e4Scsapuntz ((struct device *)(link->device_softc))->dv_xname,
264f981035cSdlg sizeof(drvp->drive_name));
265f97ca3e4Scsapuntz
26648d11ec3Scsapuntz wdc_print_caps(drvp);
2677481efa2Scsapuntz }
26848d11ec3Scsapuntz }
269d348db70Scsapuntz
270551bdc0fSderaadt #ifdef WDCDEBUG
271d348db70Scsapuntz if (chp->wdc->sc_dev.dv_cfdata->cf_flags & WDC_OPTION_PROBE_VERBOSE)
272d348db70Scsapuntz wdcdebug_atapi_mask &= ~DEBUG_PROBE;
273551bdc0fSderaadt #endif
27448d11ec3Scsapuntz }
2757481efa2Scsapuntz
276a3f240fdSmiod int
atapiscsi_activate(struct device * self,int act)2779a379db1Sderaadt atapiscsi_activate(struct device *self, int act)
2789a379db1Sderaadt {
2799a379db1Sderaadt struct atapiscsi_softc *as = (void *)self;
2809a379db1Sderaadt struct channel_softc *chp = as->chp;
2819a379db1Sderaadt struct ata_drive_datas *drvp = &chp->ch_drive[as->drive];
2829a379db1Sderaadt
2839a379db1Sderaadt switch (act) {
2849a379db1Sderaadt case DVACT_SUSPEND:
2859a379db1Sderaadt break;
2869a379db1Sderaadt case DVACT_RESUME:
2879a379db1Sderaadt /*
2889a379db1Sderaadt * Do two resets separated by a small delay. The
2899a379db1Sderaadt * first wakes the controller, the second resets
2909a379db1Sderaadt * the channel
2919a379db1Sderaadt */
2929a379db1Sderaadt wdc_disable_intr(chp);
293ba8cbb4aSmiod wdc_reset_channel(drvp, 1);
2949a379db1Sderaadt delay(10000);
295ba8cbb4aSmiod wdc_reset_channel(drvp, 0);
2969a379db1Sderaadt wdc_enable_intr(chp);
2979a379db1Sderaadt break;
2989a379db1Sderaadt }
2999a379db1Sderaadt return (0);
3009a379db1Sderaadt }
3019a379db1Sderaadt
3029a379db1Sderaadt int
atapiscsi_detach(struct device * dev,int flags)303c28b5ab2Smatthew atapiscsi_detach(struct device *dev, int flags)
304a3f240fdSmiod {
305a3f240fdSmiod return (config_detach_children(dev, flags));
306a3f240fdSmiod }
3077481efa2Scsapuntz
308bae03be6Skrw void
wdc_atapi_send_cmd(struct scsi_xfer * sc_xfer)309c28b5ab2Smatthew wdc_atapi_send_cmd(struct scsi_xfer *sc_xfer)
3107481efa2Scsapuntz {
3110b29cb40Skrw struct atapiscsi_softc *as = sc_xfer->sc_link->bus->sb_adapter_softc;
31248d11ec3Scsapuntz struct channel_softc *chp = as->chp;
3135252c952Scsapuntz struct ata_drive_datas *drvp = &chp->ch_drive[as->drive];
3147481efa2Scsapuntz struct wdc_xfer *xfer;
3158e703ec5Skrw int s;
3163f343521Scsapuntz int idx;
3177481efa2Scsapuntz
3183f343521Scsapuntz WDCDEBUG_PRINT(("wdc_atapi_send_cmd %s:%d:%d start\n",
3194ec4f187Sho chp->wdc->sc_dev.dv_xname, chp->channel, as->drive), DEBUG_XFERS);
3207481efa2Scsapuntz
3215252c952Scsapuntz if (sc_xfer->sc_link->target != 0) {
3227481efa2Scsapuntz sc_xfer->error = XS_DRIVER_STUFFUP;
323b19e1108Sdlg scsi_done(sc_xfer);
324bae03be6Skrw return;
3257481efa2Scsapuntz }
3267481efa2Scsapuntz
327a1f52200Sdlg xfer = sc_xfer->io;
3280f976493Sdlg wdc_scrub_xfer(xfer);
3297481efa2Scsapuntz if (sc_xfer->flags & SCSI_POLL)
3307481efa2Scsapuntz xfer->c_flags |= C_POLL;
3315252c952Scsapuntz xfer->drive = as->drive;
3327481efa2Scsapuntz xfer->c_flags |= C_ATAPI;
3337481efa2Scsapuntz xfer->cmd = sc_xfer;
3347481efa2Scsapuntz xfer->databuf = sc_xfer->data;
3357481efa2Scsapuntz xfer->c_bcount = sc_xfer->datalen;
3367481efa2Scsapuntz xfer->c_start = wdc_atapi_start;
3377481efa2Scsapuntz xfer->c_intr = wdc_atapi_intr;
338ec62f1edSniklas
33954f23ac8Scsapuntz timeout_set(&xfer->atapi_poll_to, wdc_atapi_timer_handler, chp);
3409f5e13a3Sho
3413f343521Scsapuntz WDCDEBUG_PRINT(("wdc_atapi_send_cmd %s:%d:%d ",
3423f343521Scsapuntz chp->wdc->sc_dev.dv_xname, chp->channel, as->drive),
3433f343521Scsapuntz DEBUG_XFERS | DEBUG_ERRORS);
3443f343521Scsapuntz
3453f343521Scsapuntz for (idx = 0; idx < sc_xfer->cmdlen; idx++) {
3463f343521Scsapuntz WDCDEBUG_PRINT((" %02x",
347664c6166Skrw ((unsigned char *)&sc_xfer->cmd)[idx]),
3483f343521Scsapuntz DEBUG_XFERS | DEBUG_ERRORS);
3493f343521Scsapuntz }
3503f343521Scsapuntz WDCDEBUG_PRINT(("\n"), DEBUG_XFERS | DEBUG_ERRORS);
3513f343521Scsapuntz
3527481efa2Scsapuntz s = splbio();
353ec62f1edSniklas
354ec62f1edSniklas if (drvp->atapi_cap & ACAP_DSC) {
35520d226a3Sgrange WDCDEBUG_PRINT(("about to send cmd 0x%x ",
356664c6166Skrw sc_xfer->cmd.opcode), DEBUG_DSC);
357664c6166Skrw switch (sc_xfer->cmd.opcode) {
358ec62f1edSniklas case READ:
359ec62f1edSniklas case WRITE:
360a24b05dfScsapuntz xfer->c_flags |= C_MEDIA_ACCESS;
361a24b05dfScsapuntz
362ec62f1edSniklas /* If we are not in buffer availability mode,
363ec62f1edSniklas we limit the first request to 0 bytes, which
364ec62f1edSniklas gets us into buffer availability mode without
365ec62f1edSniklas holding the bus. */
366ec62f1edSniklas if (!(drvp->drive_flags & DRIVE_DSCBA)) {
367a24b05dfScsapuntz xfer->c_bcount = 0;
368a24b05dfScsapuntz xfer->transfer_len =
369a24b05dfScsapuntz _3btol(((struct scsi_rw_tape *)
370664c6166Skrw &sc_xfer->cmd)->len);
371ec62f1edSniklas _lto3b(0,
372ec62f1edSniklas ((struct scsi_rw_tape *)
373664c6166Skrw &sc_xfer->cmd)->len);
374a24b05dfScsapuntz xfer->c_done = wdc_atapi_tape_done;
375ec62f1edSniklas WDCDEBUG_PRINT(
376ec62f1edSniklas ("R/W in completion mode, do 0 blocks\n"),
377ec62f1edSniklas DEBUG_DSC);
378ec62f1edSniklas } else
379ec62f1edSniklas WDCDEBUG_PRINT(("R/W %d blocks %d bytes\n",
380ec62f1edSniklas _3btol(((struct scsi_rw_tape *)
381664c6166Skrw &sc_xfer->cmd)->len),
382a24b05dfScsapuntz sc_xfer->datalen),
383ec62f1edSniklas DEBUG_DSC);
384ec62f1edSniklas
385ec62f1edSniklas /* DSC will change to buffer availability mode.
386ec62f1edSniklas We reflect this in wdc_atapi_intr. */
387ec62f1edSniklas break;
388ec62f1edSniklas
389ec62f1edSniklas case ERASE: /* Media access commands */
390ec62f1edSniklas case LOAD:
391ec62f1edSniklas case REWIND:
392ec62f1edSniklas case SPACE:
393a24b05dfScsapuntz case WRITE_FILEMARKS:
394ec62f1edSniklas #if 0
395ec62f1edSniklas case LOCATE:
396ec62f1edSniklas case READ_POSITION:
397ec62f1edSniklas #endif
398a24b05dfScsapuntz
399a24b05dfScsapuntz xfer->c_flags |= C_MEDIA_ACCESS;
400ec62f1edSniklas break;
401ec62f1edSniklas
402ec62f1edSniklas default:
403ec62f1edSniklas WDCDEBUG_PRINT(("no media access\n"), DEBUG_DSC);
404ec62f1edSniklas }
405ec62f1edSniklas }
406ec62f1edSniklas
40748d11ec3Scsapuntz wdc_exec_xfer(chp, xfer);
4087481efa2Scsapuntz splx(s);
4097481efa2Scsapuntz }
4107481efa2Scsapuntz
41166bb6343Scsapuntz int
wdc_atapi_ioctl(struct scsi_link * sc_link,u_long cmd,caddr_t addr,int flag)412c28b5ab2Smatthew wdc_atapi_ioctl(struct scsi_link *sc_link, u_long cmd, caddr_t addr, int flag)
41366bb6343Scsapuntz {
4140b29cb40Skrw struct atapiscsi_softc *as = sc_link->bus->sb_adapter_softc;
41566bb6343Scsapuntz struct channel_softc *chp = as->chp;
4165252c952Scsapuntz struct ata_drive_datas *drvp = &chp->ch_drive[as->drive];
41766bb6343Scsapuntz
4185252c952Scsapuntz if (sc_link->target != 0)
41966bb6343Scsapuntz return ENOTTY;
42066bb6343Scsapuntz
421fdca2419Sdlg return (wdc_ioctl(drvp, cmd, addr, flag, curproc));
42266bb6343Scsapuntz }
42366bb6343Scsapuntz
424ab72a97eScsapuntz
425ab72a97eScsapuntz /*
426ab72a97eScsapuntz * Returns 1 if we experienced an ATA-level abort command
427ab72a97eScsapuntz * (ABRT bit set but no additional sense)
428ab72a97eScsapuntz * 0 if normal command processing
429ab72a97eScsapuntz */
430ab72a97eScsapuntz int
atapi_to_scsi_sense(struct scsi_xfer * xfer,u_int8_t flags)431c28b5ab2Smatthew atapi_to_scsi_sense(struct scsi_xfer *xfer, u_int8_t flags)
43236acebdeScsapuntz {
43336acebdeScsapuntz struct scsi_sense_data *sense = &xfer->sense;
434ab72a97eScsapuntz int ret = 0;
435ab72a97eScsapuntz
436ab72a97eScsapuntz xfer->error = XS_SHORTSENSE;
43736acebdeScsapuntz
4387806ac8dSkrw sense->error_code = SSD_ERRCODE_VALID | SSD_ERRCODE_CURRENT;
43936acebdeScsapuntz sense->flags = (flags >> 4);
44036acebdeScsapuntz
44136acebdeScsapuntz WDCDEBUG_PRINT(("Atapi error: %d ", (flags >> 4)), DEBUG_ERRORS);
44236acebdeScsapuntz
443ab72a97eScsapuntz if ((flags & 4) && (sense->flags == 0)) {
44436acebdeScsapuntz sense->flags = SKEY_ABORTED_COMMAND;
44536acebdeScsapuntz WDCDEBUG_PRINT(("ABRT "), DEBUG_ERRORS);
446ab72a97eScsapuntz ret = 1;
44736acebdeScsapuntz }
44836acebdeScsapuntz
44936acebdeScsapuntz if (flags & 0x1) {
45036acebdeScsapuntz sense->flags |= SSD_ILI;
45136acebdeScsapuntz WDCDEBUG_PRINT(("ILI "), DEBUG_ERRORS);
45236acebdeScsapuntz }
45336acebdeScsapuntz
45436acebdeScsapuntz if (flags & 0x2) {
45536acebdeScsapuntz sense->flags |= SSD_EOM;
45636acebdeScsapuntz WDCDEBUG_PRINT(("EOM "), DEBUG_ERRORS);
45736acebdeScsapuntz }
45836acebdeScsapuntz
45936acebdeScsapuntz /* Media change requested */
46036acebdeScsapuntz /* Let's ignore these in version 1 */
46136acebdeScsapuntz if (flags & 0x8) {
46236acebdeScsapuntz WDCDEBUG_PRINT(("MCR "), DEBUG_ERRORS);
463ab72a97eScsapuntz if (sense->flags == 0)
464ab72a97eScsapuntz xfer->error = XS_NOERROR;
46536acebdeScsapuntz }
46636acebdeScsapuntz
46736acebdeScsapuntz WDCDEBUG_PRINT(("\n"), DEBUG_ERRORS);
468ab72a97eScsapuntz return (ret);
46936acebdeScsapuntz }
47036acebdeScsapuntz
471c4071fd1Smillert int wdc_atapi_drive_selected(struct channel_softc *, int);
472ad0c6836Scsapuntz
473ad0c6836Scsapuntz int
wdc_atapi_drive_selected(struct channel_softc * chp,int drive)474c28b5ab2Smatthew wdc_atapi_drive_selected(struct channel_softc *chp, int drive)
475ad0c6836Scsapuntz {
476ad0c6836Scsapuntz u_int8_t reg = CHP_READ_REG(chp, wdr_sdh);
477ad0c6836Scsapuntz
47895c10403Scsapuntz WDC_LOG_REG(chp, wdr_sdh, reg);
47995c10403Scsapuntz
480ad0c6836Scsapuntz return ((reg & 0x10) == (drive << 4));
481ad0c6836Scsapuntz }
48236acebdeScsapuntz
483a24b05dfScsapuntz enum atapi_context {
484a24b05dfScsapuntz ctxt_process = 0,
485a24b05dfScsapuntz ctxt_timer = 1,
486a24b05dfScsapuntz ctxt_interrupt = 2
487a24b05dfScsapuntz };
488a24b05dfScsapuntz
489c4071fd1Smillert void wdc_atapi_the_machine(struct channel_softc *, struct wdc_xfer *,
490c4071fd1Smillert enum atapi_context);
491a24b05dfScsapuntz
492c4071fd1Smillert void wdc_atapi_the_poll_machine(struct channel_softc *, struct wdc_xfer *);
493a24b05dfScsapuntz
49436acebdeScsapuntz void
wdc_atapi_start(struct channel_softc * chp,struct wdc_xfer * xfer)495c28b5ab2Smatthew wdc_atapi_start(struct channel_softc *chp, struct wdc_xfer *xfer)
4967481efa2Scsapuntz {
497a24b05dfScsapuntz xfer->next = wdc_atapi_real_start;
498a24b05dfScsapuntz
499a24b05dfScsapuntz wdc_atapi_the_machine(chp, xfer, ctxt_process);
500a24b05dfScsapuntz }
501a24b05dfScsapuntz
502a24b05dfScsapuntz
503a24b05dfScsapuntz void
wdc_atapi_timer_handler(void * arg)504c28b5ab2Smatthew wdc_atapi_timer_handler(void *arg)
505a24b05dfScsapuntz {
50654f23ac8Scsapuntz struct channel_softc *chp = arg;
50754f23ac8Scsapuntz struct wdc_xfer *xfer;
508a24b05dfScsapuntz int s;
509a24b05dfScsapuntz
510a24b05dfScsapuntz s = splbio();
51154f23ac8Scsapuntz xfer = TAILQ_FIRST(&chp->ch_queue->sc_xfer);
51254f23ac8Scsapuntz if (xfer == NULL ||
51354f23ac8Scsapuntz !timeout_triggered(&xfer->atapi_poll_to)) {
51454f23ac8Scsapuntz splx(s);
51554f23ac8Scsapuntz return;
51654f23ac8Scsapuntz }
51754f23ac8Scsapuntz xfer->c_flags &= ~C_POLL_MACHINE;
51854f23ac8Scsapuntz timeout_del(&xfer->atapi_poll_to);
519fb74e841Sniklas chp->ch_flags &= ~WDCF_IRQ_WAIT;
520a24b05dfScsapuntz wdc_atapi_the_machine(chp, xfer, ctxt_timer);
521a24b05dfScsapuntz splx(s);
522a24b05dfScsapuntz }
523a24b05dfScsapuntz
524a24b05dfScsapuntz
525a24b05dfScsapuntz int
wdc_atapi_intr(struct channel_softc * chp,struct wdc_xfer * xfer,int irq)526c28b5ab2Smatthew wdc_atapi_intr(struct channel_softc *chp, struct wdc_xfer *xfer, int irq)
527a24b05dfScsapuntz {
528b78a0069Scsapuntz timeout_del(&chp->ch_timo);
529b78a0069Scsapuntz
530a24b05dfScsapuntz /* XXX we should consider an alternate signaling regime here */
531a24b05dfScsapuntz if (xfer->c_flags & C_TIMEOU) {
532a24b05dfScsapuntz xfer->c_flags &= ~C_TIMEOU;
5333f343521Scsapuntz wdc_atapi_the_machine(chp, xfer, ctxt_timer);
5343f343521Scsapuntz return (0);
535a24b05dfScsapuntz }
536a24b05dfScsapuntz
5373f343521Scsapuntz wdc_atapi_the_machine(chp, xfer, ctxt_interrupt);
5383f343521Scsapuntz
5393f343521Scsapuntz return (-1);
540a24b05dfScsapuntz }
541a24b05dfScsapuntz
54254f23ac8Scsapuntz struct atapi_return_args {
54354f23ac8Scsapuntz int timeout;
54454f23ac8Scsapuntz int delay;
54554f23ac8Scsapuntz int expect_irq;
54654f23ac8Scsapuntz };
54754f23ac8Scsapuntz
5483f343521Scsapuntz #define ARGS_INIT {-1, 0, 0}
549a24b05dfScsapuntz
5503f343521Scsapuntz void
wdc_atapi_the_poll_machine(struct channel_softc * chp,struct wdc_xfer * xfer)551c28b5ab2Smatthew wdc_atapi_the_poll_machine(struct channel_softc *chp, struct wdc_xfer *xfer)
552a24b05dfScsapuntz {
55354f23ac8Scsapuntz int idx = 0;
554e61c843cScsapuntz int current_timeout = 10;
555a24b05dfScsapuntz
556a24b05dfScsapuntz
557a24b05dfScsapuntz while (1) {
55854f23ac8Scsapuntz struct atapi_return_args retargs = ARGS_INIT;
559a24b05dfScsapuntz idx++;
560a24b05dfScsapuntz
56154f23ac8Scsapuntz (xfer->next)(chp, xfer, (current_timeout * 1000 <= idx),
56254f23ac8Scsapuntz &retargs);
563a24b05dfScsapuntz
56454f23ac8Scsapuntz if (xfer->next == NULL) {
565a24b05dfScsapuntz wdc_free_xfer(chp, xfer);
566a24b05dfScsapuntz wdcstart(chp);
5673f343521Scsapuntz return;
568a24b05dfScsapuntz }
56954f23ac8Scsapuntz
57054f23ac8Scsapuntz if (retargs.timeout != -1) {
57154f23ac8Scsapuntz current_timeout = retargs.timeout;
57254f23ac8Scsapuntz idx = 0;
57354f23ac8Scsapuntz }
57454f23ac8Scsapuntz
57554f23ac8Scsapuntz if (retargs.delay != 0) {
57654f23ac8Scsapuntz delay (1000 * retargs.delay);
57754f23ac8Scsapuntz idx += 1000 * retargs.delay;
57854f23ac8Scsapuntz }
57954f23ac8Scsapuntz
58054f23ac8Scsapuntz DELAY(1);
581a24b05dfScsapuntz }
582a24b05dfScsapuntz }
583a24b05dfScsapuntz
58454f23ac8Scsapuntz
5853f343521Scsapuntz void
wdc_atapi_the_machine(struct channel_softc * chp,struct wdc_xfer * xfer,enum atapi_context ctxt)586c28b5ab2Smatthew wdc_atapi_the_machine(struct channel_softc *chp, struct wdc_xfer *xfer,
587c28b5ab2Smatthew enum atapi_context ctxt)
588a24b05dfScsapuntz {
58954f23ac8Scsapuntz int idx = 0;
590ab72a97eScsapuntz extern int ticks;
591a24b05dfScsapuntz int timeout_delay = hz / 10;
592a24b05dfScsapuntz
593a24b05dfScsapuntz if (xfer->c_flags & C_POLL) {
594e7f35eb1Sgrange wdc_disable_intr(chp);
595e7f35eb1Sgrange
5961d4420b3Scsapuntz if (ctxt != ctxt_process) {
5971d4420b3Scsapuntz if (ctxt == ctxt_interrupt)
5981d4420b3Scsapuntz xfer->endticks = 1;
5991d4420b3Scsapuntz
6003f343521Scsapuntz return;
6011d4420b3Scsapuntz }
602a24b05dfScsapuntz
603a24b05dfScsapuntz wdc_atapi_the_poll_machine(chp, xfer);
6043f343521Scsapuntz return;
605a24b05dfScsapuntz }
606a24b05dfScsapuntz
60754f23ac8Scsapuntz /* Don't go through more than 50 state machine steps
60854f23ac8Scsapuntz before yielding. This tries to limit the amount of time
60954f23ac8Scsapuntz spent at high SPL */
61054f23ac8Scsapuntz for (idx = 0; idx < 50; idx++) {
61154f23ac8Scsapuntz struct atapi_return_args retargs = ARGS_INIT;
612a24b05dfScsapuntz
61354f23ac8Scsapuntz (xfer->next)(chp, xfer,
61454f23ac8Scsapuntz xfer->endticks && (ticks - xfer->endticks >= 0),
61554f23ac8Scsapuntz &retargs);
616a24b05dfScsapuntz
61754f23ac8Scsapuntz if (retargs.timeout != -1)
618fb74e841Sniklas /*
61954f23ac8Scsapuntz * Add 1 tick to compensate for the fact that we
62054f23ac8Scsapuntz * can be just microseconds before the tick changes.
621fb74e841Sniklas */
622fb74e841Sniklas xfer->endticks =
62354f23ac8Scsapuntz max((retargs.timeout * hz) / 1000, 1) + 1 + ticks;
624a24b05dfScsapuntz
62554f23ac8Scsapuntz if (xfer->next == NULL) {
626a24b05dfScsapuntz if (xfer->c_flags & C_POLL_MACHINE)
6279f5e13a3Sho timeout_del(&xfer->atapi_poll_to);
628a24b05dfScsapuntz
629a24b05dfScsapuntz wdc_free_xfer(chp, xfer);
630a24b05dfScsapuntz wdcstart(chp);
631a24b05dfScsapuntz
6323f343521Scsapuntz return;
633a24b05dfScsapuntz }
634a24b05dfScsapuntz
63554f23ac8Scsapuntz if (retargs.expect_irq) {
636fee6ff40Sdrahn int timeout_period;
63754f23ac8Scsapuntz chp->ch_flags |= WDCF_IRQ_WAIT;
638fee6ff40Sdrahn timeout_period = xfer->endticks - ticks;
639fee6ff40Sdrahn if (timeout_period < 1)
640fee6ff40Sdrahn timeout_period = 1;
641fee6ff40Sdrahn timeout_add(&chp->ch_timo, timeout_period);
6423f343521Scsapuntz return;
64354f23ac8Scsapuntz }
64454f23ac8Scsapuntz
6451d4420b3Scsapuntz if (retargs.delay != 0) {
6461d4420b3Scsapuntz timeout_delay = max(retargs.delay * hz / 1000, 1);
64754f23ac8Scsapuntz break;
6481d4420b3Scsapuntz }
64954f23ac8Scsapuntz
65054f23ac8Scsapuntz DELAY(1);
65154f23ac8Scsapuntz }
65254f23ac8Scsapuntz
6539f5e13a3Sho timeout_add(&xfer->atapi_poll_to, timeout_delay);
654a24b05dfScsapuntz xfer->c_flags |= C_POLL_MACHINE;
655caa5053fScsapuntz
6563f343521Scsapuntz return;
657a24b05dfScsapuntz }
658a24b05dfScsapuntz
659a24b05dfScsapuntz
660c4071fd1Smillert void wdc_atapi_update_status(struct channel_softc *);
661a24b05dfScsapuntz
662a24b05dfScsapuntz void
wdc_atapi_update_status(struct channel_softc * chp)663c28b5ab2Smatthew wdc_atapi_update_status(struct channel_softc *chp)
664a24b05dfScsapuntz {
665a24b05dfScsapuntz chp->ch_status = CHP_READ_REG(chp, wdr_status);
666a24b05dfScsapuntz
66795c10403Scsapuntz WDC_LOG_STATUS(chp, chp->ch_status);
66895c10403Scsapuntz
669a24b05dfScsapuntz if (chp->ch_status == 0xff && (chp->ch_flags & WDCF_ONESLAVE)) {
67095c10403Scsapuntz wdc_set_drive(chp, 1);
671a24b05dfScsapuntz
672a24b05dfScsapuntz chp->ch_status = CHP_READ_REG(chp, wdr_status);
67395c10403Scsapuntz WDC_LOG_STATUS(chp, chp->ch_status);
674a24b05dfScsapuntz }
675a24b05dfScsapuntz
67695c10403Scsapuntz if ((chp->ch_status & (WDCS_BSY | WDCS_ERR)) == WDCS_ERR) {
677a24b05dfScsapuntz chp->ch_error = CHP_READ_REG(chp, wdr_error);
67895c10403Scsapuntz WDC_LOG_ERROR(chp, chp->ch_error);
67995c10403Scsapuntz }
680a24b05dfScsapuntz }
681a24b05dfScsapuntz
68254f23ac8Scsapuntz void
wdc_atapi_real_start(struct channel_softc * chp,struct wdc_xfer * xfer,int timeout,struct atapi_return_args * ret)683c28b5ab2Smatthew wdc_atapi_real_start(struct channel_softc *chp, struct wdc_xfer *xfer,
684c28b5ab2Smatthew int timeout, struct atapi_return_args *ret)
685a24b05dfScsapuntz {
686e61c843cScsapuntz #ifdef WDCDEBUG
6877481efa2Scsapuntz struct scsi_xfer *sc_xfer = xfer->cmd;
688e61c843cScsapuntz #endif
6897481efa2Scsapuntz struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
6907481efa2Scsapuntz
691bf07dfc9Scsapuntz /*
692bf07dfc9Scsapuntz * Only set the DMA flag if the transfer is reasonably large.
693bf07dfc9Scsapuntz * At least one older drive failed to complete a 4 byte DMA transfer.
694bf07dfc9Scsapuntz */
695bf07dfc9Scsapuntz
696bf07dfc9Scsapuntz /* Turn off DMA flag on REQUEST SENSE */
697bf07dfc9Scsapuntz
6983f343521Scsapuntz if (!(xfer->c_flags & (C_POLL | C_SENSE | C_MEDIA_ACCESS)) &&
69936acebdeScsapuntz (drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) &&
700c2572690Scsapuntz (xfer->c_bcount > 100))
7017481efa2Scsapuntz xfer->c_flags |= C_DMA;
7027481efa2Scsapuntz else
7037481efa2Scsapuntz xfer->c_flags &= ~C_DMA;
7049ec8daebSderaadt
705a24b05dfScsapuntz
70695c10403Scsapuntz wdc_set_drive(chp, xfer->drive);
707a24b05dfScsapuntz
708a24b05dfScsapuntz DELAY(1);
709a24b05dfScsapuntz
710a24b05dfScsapuntz xfer->next = wdc_atapi_real_start_2;
71154f23ac8Scsapuntz ret->timeout = ATAPI_DELAY;
712a24b05dfScsapuntz
71320d226a3Sgrange WDCDEBUG_PRINT(("wdc_atapi_start %s:%d:%d, scsi flags 0x%x, "
71420d226a3Sgrange "ATA flags 0x%x\n",
7153f343521Scsapuntz chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive,
7163f343521Scsapuntz sc_xfer->flags, xfer->c_flags), DEBUG_XFERS);
7173f343521Scsapuntz
7183f343521Scsapuntz
71954f23ac8Scsapuntz return;
720a24b05dfScsapuntz }
721a24b05dfScsapuntz
722a24b05dfScsapuntz
72354f23ac8Scsapuntz void
wdc_atapi_real_start_2(struct channel_softc * chp,struct wdc_xfer * xfer,int timeout,struct atapi_return_args * ret)724c28b5ab2Smatthew wdc_atapi_real_start_2(struct channel_softc *chp, struct wdc_xfer *xfer,
725c28b5ab2Smatthew int timeout, struct atapi_return_args *ret)
726a24b05dfScsapuntz {
727a24b05dfScsapuntz struct scsi_xfer *sc_xfer = xfer->cmd;
728a24b05dfScsapuntz struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
729a24b05dfScsapuntz
730a24b05dfScsapuntz if (timeout) {
7319ec8daebSderaadt printf("wdc_atapi_start: not ready, st = %02x\n",
7329ec8daebSderaadt chp->ch_status);
733a24b05dfScsapuntz
7349ec8daebSderaadt sc_xfer->error = XS_TIMEOUT;
735a24b05dfScsapuntz xfer->next = wdc_atapi_reset;
73654f23ac8Scsapuntz return;
737a24b05dfScsapuntz } else {
738a24b05dfScsapuntz wdc_atapi_update_status(chp);
739a24b05dfScsapuntz
74066bb6343Scsapuntz if (chp->ch_status & (WDCS_BSY | WDCS_DRQ))
74154f23ac8Scsapuntz return;
7429ec8daebSderaadt }
7439ec8daebSderaadt
7447481efa2Scsapuntz /* Do control operations specially. */
74566bb6343Scsapuntz if (drvp->state < ATAPI_READY_STATE) {
746a24b05dfScsapuntz xfer->next = wdc_atapi_ctrl;
74754f23ac8Scsapuntz return;
7487481efa2Scsapuntz }
749a077a3e9Scsapuntz
750a24b05dfScsapuntz xfer->next = wdc_atapi_send_packet;
75154f23ac8Scsapuntz return;
752ec62f1edSniklas }
753a24b05dfScsapuntz
754a24b05dfScsapuntz
75554f23ac8Scsapuntz void
wdc_atapi_send_packet(struct channel_softc * chp,struct wdc_xfer * xfer,int timeout,struct atapi_return_args * ret)756c28b5ab2Smatthew wdc_atapi_send_packet(struct channel_softc *chp, struct wdc_xfer *xfer,
757c28b5ab2Smatthew int timeout, struct atapi_return_args *ret)
758a24b05dfScsapuntz {
759a24b05dfScsapuntz struct scsi_xfer *sc_xfer = xfer->cmd;
760a24b05dfScsapuntz struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
7613f343521Scsapuntz
7627481efa2Scsapuntz /*
763775cc6c0Ssobrado * Even with WDCS_ERR, the device should accept a command packet.
7647481efa2Scsapuntz * Limit length to what can be stuffed into the cylinder register
7657481efa2Scsapuntz * (16 bits). Some CD-ROMs seem to interpret '0' as 65536,
7667481efa2Scsapuntz * but not all devices do that and it's not obvious from the
767a2fd75e8Stom * ATAPI spec that this behaviour should be expected. If more
7687481efa2Scsapuntz * data is necessary, multiple data transfer phases will be done.
7697481efa2Scsapuntz */
7707481efa2Scsapuntz
7717481efa2Scsapuntz wdccommand(chp, xfer->drive, ATAPI_PKT_CMD,
7729b25e7c1Scsapuntz xfer->c_bcount <= 0xfffe ? xfer->c_bcount : 0xfffe,
7737481efa2Scsapuntz 0, 0, 0,
7747481efa2Scsapuntz (xfer->c_flags & C_DMA) ? ATAPI_PKT_CMD_FTRE_DMA : 0);
7757481efa2Scsapuntz
776ec8802a4Scsapuntz if (xfer->c_flags & C_DMA)
777ec8802a4Scsapuntz drvp->n_xfers++;
7789ec8daebSderaadt
7797481efa2Scsapuntz DELAY(1);
7809ec8daebSderaadt
7813f343521Scsapuntz xfer->next = wdc_atapi_intr_command;
78254f23ac8Scsapuntz ret->timeout = sc_xfer->timeout;
783a24b05dfScsapuntz
784a24b05dfScsapuntz if ((drvp->atapi_cap & ATAPI_CFG_DRQ_MASK) == ATAPI_CFG_IRQ_DRQ) {
785a24b05dfScsapuntz /* We expect an IRQ to tell us of the next state */
78654f23ac8Scsapuntz ret->expect_irq = 1;
7877481efa2Scsapuntz }
7883f343521Scsapuntz
7893f343521Scsapuntz WDCDEBUG_PRINT(("wdc_atapi_send_packet %s:%d:%d command sent\n",
7903f343521Scsapuntz chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive
7913f343521Scsapuntz ), DEBUG_XFERS);
79254f23ac8Scsapuntz return;
7937481efa2Scsapuntz }
7947481efa2Scsapuntz
79554f23ac8Scsapuntz void
wdc_atapi_intr_command(struct channel_softc * chp,struct wdc_xfer * xfer,int timeout,struct atapi_return_args * ret)796c28b5ab2Smatthew wdc_atapi_intr_command(struct channel_softc *chp, struct wdc_xfer *xfer,
797c28b5ab2Smatthew int timeout, struct atapi_return_args *ret)
7989ec8daebSderaadt {
7999ec8daebSderaadt struct scsi_xfer *sc_xfer = xfer->cmd;
8009ec8daebSderaadt struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
8010b29cb40Skrw struct atapiscsi_softc *as = sc_xfer->sc_link->bus->sb_adapter_softc;
8024b7fd08fScsapuntz int i;
8039ec8daebSderaadt u_int8_t cmd[16];
8049ec8daebSderaadt struct scsi_sense *cmd_reqsense;
8059ec8daebSderaadt int cmdlen = (drvp->atapi_cap & ACAP_LEN) ? 16 : 12;
806caa5053fScsapuntz int dma_flags = ((sc_xfer->flags & SCSI_DATA_IN) ||
807caa5053fScsapuntz (xfer->c_flags & C_SENSE)) ? WDC_DMA_READ : 0;
8089ec8daebSderaadt
8093f343521Scsapuntz wdc_atapi_update_status(chp);
8103f343521Scsapuntz
8113f343521Scsapuntz if ((chp->ch_status & WDCS_BSY) || !(chp->ch_status & WDCS_DRQ)) {
8123f343521Scsapuntz if (timeout)
8133f343521Scsapuntz goto timeout;
8143f343521Scsapuntz
8153f343521Scsapuntz return;
8163f343521Scsapuntz }
8173f343521Scsapuntz
8183f343521Scsapuntz if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
8193f343521Scsapuntz chp->wdc->irqack(chp);
8203f343521Scsapuntz
8219ec8daebSderaadt bzero(cmd, sizeof(cmd));
8229ec8daebSderaadt
8239ec8daebSderaadt if (xfer->c_flags & C_SENSE) {
8249ec8daebSderaadt cmd_reqsense = (struct scsi_sense *)&cmd[0];
8259ec8daebSderaadt cmd_reqsense->opcode = REQUEST_SENSE;
8269ec8daebSderaadt cmd_reqsense->length = xfer->c_bcount;
8279ec8daebSderaadt } else
828664c6166Skrw bcopy(&sc_xfer->cmd, cmd, sc_xfer->cmdlen);
8299ec8daebSderaadt
83095c10403Scsapuntz WDC_LOG_ATAPI_CMD(chp, xfer->drive, xfer->c_flags,
8316e645156Scsapuntz cmdlen, cmd);
83295c10403Scsapuntz
8339ec8daebSderaadt for (i = 0; i < 12; i++)
8349ec8daebSderaadt WDCDEBUG_PRINT(("%02x ", cmd[i]), DEBUG_INTR);
8359ec8daebSderaadt WDCDEBUG_PRINT((": PHASE_CMDOUT\n"), DEBUG_INTR);
8369ec8daebSderaadt
8379ec8daebSderaadt /* Init the DMA channel if necessary */
8389ec8daebSderaadt if (xfer->c_flags & C_DMA) {
8399ec8daebSderaadt if ((*chp->wdc->dma_init)(chp->wdc->dma_arg,
8409ec8daebSderaadt chp->channel, xfer->drive, xfer->databuf,
8419ec8daebSderaadt xfer->c_bcount, dma_flags) != 0) {
8429ec8daebSderaadt sc_xfer->error = XS_DRIVER_STUFFUP;
843a24b05dfScsapuntz
8443f343521Scsapuntz xfer->next = wdc_atapi_reset;
84554f23ac8Scsapuntz return;
8469ec8daebSderaadt }
8479ec8daebSderaadt }
8489ec8daebSderaadt
8499ec8daebSderaadt wdc_output_bytes(drvp, cmd, cmdlen);
8509ec8daebSderaadt
8519ec8daebSderaadt /* Start the DMA channel if necessary */
8529ec8daebSderaadt if (xfer->c_flags & C_DMA) {
8539ec8daebSderaadt (*chp->wdc->dma_start)(chp->wdc->dma_arg,
854caa5053fScsapuntz chp->channel, xfer->drive);
8553f343521Scsapuntz xfer->next = wdc_atapi_intr_complete;
8563f343521Scsapuntz } else {
8573f343521Scsapuntz if (xfer->c_bcount == 0)
8580c6728ddScsapuntz as->protocol_phase = as_completed;
8590c6728ddScsapuntz else
8600c6728ddScsapuntz as->protocol_phase = as_data;
8610c6728ddScsapuntz
8623f343521Scsapuntz xfer->next = wdc_atapi_pio_intr;
8633f343521Scsapuntz }
8643f343521Scsapuntz
86554f23ac8Scsapuntz ret->expect_irq = 1;
8669ec8daebSderaadt
8679ec8daebSderaadt /* If we read/write to a tape we will get into buffer
8689ec8daebSderaadt availability mode. */
8699ec8daebSderaadt if (drvp->atapi_cap & ACAP_DSC) {
870664c6166Skrw if ((sc_xfer->cmd.opcode == READ ||
871664c6166Skrw sc_xfer->cmd.opcode == WRITE)) {
8729ec8daebSderaadt drvp->drive_flags |= DRIVE_DSCBA;
8739ec8daebSderaadt WDCDEBUG_PRINT(("set DSCBA\n"), DEBUG_DSC);
874a24b05dfScsapuntz } else if ((xfer->c_flags & C_MEDIA_ACCESS) &&
875a24b05dfScsapuntz (drvp->drive_flags & DRIVE_DSCBA)) {
876a24b05dfScsapuntz /* Clause 3.2.4 of QIC-157 D.
8774b7fd08fScsapuntz
878a24b05dfScsapuntz Any media access command other than read or
879a24b05dfScsapuntz write will switch DSC back to completion
880a24b05dfScsapuntz mode */
881a24b05dfScsapuntz drvp->drive_flags &= ~DRIVE_DSCBA;
882a24b05dfScsapuntz WDCDEBUG_PRINT(("clear DCSBA\n"), DEBUG_DSC);
8839ec8daebSderaadt }
884a24b05dfScsapuntz }
885a24b05dfScsapuntz
88654f23ac8Scsapuntz return;
8873f343521Scsapuntz
8883f343521Scsapuntz timeout:
8893f343521Scsapuntz printf ("%s:%d:%d: device timeout waiting to send SCSI packet\n",
8903f343521Scsapuntz chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive);
8913f343521Scsapuntz
8923f343521Scsapuntz sc_xfer->error = XS_TIMEOUT;
8933f343521Scsapuntz xfer->next = wdc_atapi_reset;
8943f343521Scsapuntz return;
895a24b05dfScsapuntz }
896a24b05dfScsapuntz
8979ec8daebSderaadt
898e61c843cScsapuntz char *
wdc_atapi_in_data_phase(struct wdc_xfer * xfer,int len,int ire)899c28b5ab2Smatthew wdc_atapi_in_data_phase(struct wdc_xfer *xfer, int len, int ire)
9004b7fd08fScsapuntz {
9014b7fd08fScsapuntz struct scsi_xfer *sc_xfer = xfer->cmd;
9020b29cb40Skrw struct atapiscsi_softc *as = sc_xfer->sc_link->bus->sb_adapter_softc;
903a24b05dfScsapuntz char *message;
9049ec8daebSderaadt
905e61c843cScsapuntz if (as->protocol_phase != as_data) {
906e61c843cScsapuntz message = "unexpected data phase";
907e61c843cScsapuntz goto unexpected_state;
908e61c843cScsapuntz }
909e61c843cScsapuntz
9109ec8daebSderaadt if (ire & WDCI_CMD) {
9114b7fd08fScsapuntz message = "unexpectedly in command phase";
9124b7fd08fScsapuntz goto unexpected_state;
9139ec8daebSderaadt }
9144b7fd08fScsapuntz
9154b7fd08fScsapuntz if (!(xfer->c_flags & C_SENSE)) {
9164b7fd08fScsapuntz if (!(sc_xfer->flags & (SCSI_DATA_IN | SCSI_DATA_OUT))) {
9174b7fd08fScsapuntz message = "data phase where none expected";
9184b7fd08fScsapuntz goto unexpected_state;
9199ec8daebSderaadt }
9209ec8daebSderaadt
9219ec8daebSderaadt /* Make sure polarities match */
9229ec8daebSderaadt if (((ire & WDCI_IN) == WDCI_IN) ==
9239ec8daebSderaadt ((sc_xfer->flags & SCSI_DATA_OUT) == SCSI_DATA_OUT)) {
9244b7fd08fScsapuntz message = "data transfer direction disagreement";
9254b7fd08fScsapuntz goto unexpected_state;
9269ec8daebSderaadt }
9274b7fd08fScsapuntz } else {
9284b7fd08fScsapuntz if (!(ire & WDCI_IN)) {
9294b7fd08fScsapuntz message = "data transfer direction disagreement during sense";
9304b7fd08fScsapuntz goto unexpected_state;
9319ec8daebSderaadt }
9324b7fd08fScsapuntz }
9339ec8daebSderaadt
934fd3c9972Scsapuntz if (len == 0) {
9354b7fd08fScsapuntz message = "zero length transfer requested in data phase";
9364b7fd08fScsapuntz goto unexpected_state;
937fd3c9972Scsapuntz }
9389ec8daebSderaadt
939a24b05dfScsapuntz
940e61c843cScsapuntz return (0);
941a24b05dfScsapuntz
942a24b05dfScsapuntz unexpected_state:
943a24b05dfScsapuntz
944e61c843cScsapuntz return (message);
945a24b05dfScsapuntz }
946a24b05dfScsapuntz
94754f23ac8Scsapuntz void
wdc_atapi_intr_data(struct channel_softc * chp,struct wdc_xfer * xfer,int timeout,struct atapi_return_args * ret)948c28b5ab2Smatthew wdc_atapi_intr_data(struct channel_softc *chp, struct wdc_xfer *xfer,
949c28b5ab2Smatthew int timeout, struct atapi_return_args *ret)
950a24b05dfScsapuntz {
951a24b05dfScsapuntz struct scsi_xfer *sc_xfer = xfer->cmd;
952a24b05dfScsapuntz struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
953a24b05dfScsapuntz int len, ire;
954e61c843cScsapuntz char *message;
955fea489f6Sgrange int tohost;
956a24b05dfScsapuntz
957a24b05dfScsapuntz len = (CHP_READ_REG(chp, wdr_cyl_hi) << 8) |
958a24b05dfScsapuntz CHP_READ_REG(chp, wdr_cyl_lo);
95995c10403Scsapuntz WDC_LOG_REG(chp, wdr_cyl_lo, len);
96095c10403Scsapuntz
961a24b05dfScsapuntz ire = CHP_READ_REG(chp, wdr_ireason);
96295c10403Scsapuntz WDC_LOG_REG(chp, wdr_ireason, ire);
963a24b05dfScsapuntz
964e61c843cScsapuntz if ((message = wdc_atapi_in_data_phase(xfer, len, ire))) {
9651d2f5473Scsapuntz /* The drive has dropped BSY before setting up the
9661d2f5473Scsapuntz registers correctly for DATA phase. This drive is
9671d2f5473Scsapuntz not compliant with ATA/ATAPI-4.
9681d2f5473Scsapuntz
9691d2f5473Scsapuntz Give the drive 100ms to get its house in order
9701d2f5473Scsapuntz before we try again. */
9713f343521Scsapuntz WDCDEBUG_PRINT(("wdc_atapi_intr: %s\n", message),
9723f343521Scsapuntz DEBUG_ERRORS);
9733f343521Scsapuntz
9741d2f5473Scsapuntz if (!timeout) {
97554f23ac8Scsapuntz ret->delay = 100;
97654f23ac8Scsapuntz return;
977e61c843cScsapuntz }
9781d2f5473Scsapuntz }
979e61c843cScsapuntz
980fea489f6Sgrange tohost = ((sc_xfer->flags & SCSI_DATA_IN) != 0 ||
981fea489f6Sgrange (xfer->c_flags & C_SENSE) != 0);
982a24b05dfScsapuntz
9839ec8daebSderaadt if (xfer->c_bcount >= len) {
984ab72a97eScsapuntz WDCDEBUG_PRINT(("wdc_atapi_intr: c_bcount %d len %d "
98520d226a3Sgrange "st 0x%b err 0x%x "
986a24b05dfScsapuntz "ire 0x%x\n", xfer->c_bcount,
98720d226a3Sgrange len, chp->ch_status, WDCS_BITS, chp->ch_error, ire),
98820d226a3Sgrange DEBUG_INTR);
989a24b05dfScsapuntz
9909ec8daebSderaadt /* Common case */
991fea489f6Sgrange if (!tohost)
9929ec8daebSderaadt wdc_output_bytes(drvp, (u_int8_t *)xfer->databuf +
9939ec8daebSderaadt xfer->c_skip, len);
9949ec8daebSderaadt else
9959ec8daebSderaadt wdc_input_bytes(drvp, (u_int8_t *)xfer->databuf +
9969ec8daebSderaadt xfer->c_skip, len);
9979ec8daebSderaadt
9989ec8daebSderaadt xfer->c_skip += len;
9999ec8daebSderaadt xfer->c_bcount -= len;
10009ec8daebSderaadt } else {
10010c6728ddScsapuntz /* Exceptional case - drive want to transfer more
10020c6728ddScsapuntz data than we have buffer for */
1003fea489f6Sgrange if (!tohost) {
10040c6728ddScsapuntz /* Wouldn't it be better to just abort here rather
10050c6728ddScsapuntz than to write random stuff to drive? */
10060c6728ddScsapuntz printf("wdc_atapi_intr: warning: device requesting "
10070c6728ddScsapuntz "%d bytes, only %d left in buffer\n", len, xfer->c_bcount);
10089ec8daebSderaadt
10099ec8daebSderaadt wdc_output_bytes(drvp, (u_int8_t *)xfer->databuf +
10109ec8daebSderaadt xfer->c_skip, xfer->c_bcount);
10119ec8daebSderaadt
10124b7fd08fScsapuntz CHP_WRITE_RAW_MULTI_2(chp, NULL,
10134b7fd08fScsapuntz len - xfer->c_bcount);
10149ec8daebSderaadt } else {
10159ec8daebSderaadt printf("wdc_atapi_intr: warning: reading only "
10169ec8daebSderaadt "%d of %d bytes\n", xfer->c_bcount, len);
10179ec8daebSderaadt
10189ec8daebSderaadt wdc_input_bytes(drvp,
10199ec8daebSderaadt (char *)xfer->databuf + xfer->c_skip,
10209ec8daebSderaadt xfer->c_bcount);
10219ec8daebSderaadt wdcbit_bucket(chp, len - xfer->c_bcount);
10229ec8daebSderaadt }
10239ec8daebSderaadt
10249ec8daebSderaadt xfer->c_skip += xfer->c_bcount;
10259ec8daebSderaadt xfer->c_bcount = 0;
10269ec8daebSderaadt }
10279ec8daebSderaadt
102854f23ac8Scsapuntz ret->expect_irq = 1;
10293f343521Scsapuntz xfer->next = wdc_atapi_pio_intr;
10309ec8daebSderaadt
103154f23ac8Scsapuntz return;
10329ec8daebSderaadt }
10339ec8daebSderaadt
103454f23ac8Scsapuntz void
wdc_atapi_intr_complete(struct channel_softc * chp,struct wdc_xfer * xfer,int timeout,struct atapi_return_args * ret)1035c28b5ab2Smatthew wdc_atapi_intr_complete(struct channel_softc *chp, struct wdc_xfer *xfer,
1036c28b5ab2Smatthew int timeout, struct atapi_return_args *ret)
10377481efa2Scsapuntz {
10387481efa2Scsapuntz struct scsi_xfer *sc_xfer = xfer->cmd;
10397481efa2Scsapuntz struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
10400b29cb40Skrw struct atapiscsi_softc *as = sc_xfer->sc_link->bus->sb_adapter_softc;
10419ec8daebSderaadt
10429ec8daebSderaadt WDCDEBUG_PRINT(("PHASE_COMPLETED\n"), DEBUG_INTR);
10439ec8daebSderaadt
10440c6728ddScsapuntz if (xfer->c_flags & C_DMA) {
10453f343521Scsapuntz int retry;
10463f343521Scsapuntz
10473f343521Scsapuntz if (timeout) {
10483f343521Scsapuntz sc_xfer->error = XS_TIMEOUT;
1049ec8802a4Scsapuntz ata_dmaerr(drvp);
10503f343521Scsapuntz
10513f343521Scsapuntz xfer->next = wdc_atapi_reset;
10523f343521Scsapuntz return;
10533f343521Scsapuntz }
10543f343521Scsapuntz
10553f343521Scsapuntz for (retry = 5; retry > 0; retry--) {
10563f343521Scsapuntz wdc_atapi_update_status(chp);
10573f343521Scsapuntz if ((chp->ch_status & (WDCS_BSY | WDCS_DRQ)) == 0)
10583f343521Scsapuntz break;
10593f343521Scsapuntz DELAY(5);
10603f343521Scsapuntz }
10613f343521Scsapuntz if (retry == 0) {
10623f343521Scsapuntz ret->expect_irq = 1;
10633f343521Scsapuntz return;
10643f343521Scsapuntz }
10653f343521Scsapuntz
10663f343521Scsapuntz chp->wdc->dma_status =
10673f343521Scsapuntz (*chp->wdc->dma_finish)
10683f343521Scsapuntz (chp->wdc->dma_arg, chp->channel,
106914235d69Sgrange xfer->drive, 1);
10709ec8daebSderaadt
1071caa5053fScsapuntz if (chp->wdc->dma_status & WDC_DMAST_UNDER)
1072caa5053fScsapuntz xfer->c_bcount = 1;
1073caa5053fScsapuntz else
1074a24b05dfScsapuntz xfer->c_bcount = 0;
10759ec8daebSderaadt }
10769ec8daebSderaadt
10779ec8daebSderaadt as->protocol_phase = as_none;
10789ec8daebSderaadt
10799ec8daebSderaadt if (xfer->c_flags & C_SENSE) {
10809ec8daebSderaadt if (chp->ch_status & WDCS_ERR) {
10819ec8daebSderaadt if (chp->ch_error & WDCE_ABRT) {
10827481efa2Scsapuntz WDCDEBUG_PRINT(("wdc_atapi_intr: request_sense aborted, "
10837481efa2Scsapuntz "calling wdc_atapi_done()"
10847481efa2Scsapuntz ), DEBUG_INTR);
1085a24b05dfScsapuntz xfer->next = wdc_atapi_done;
108654f23ac8Scsapuntz return;
10877481efa2Scsapuntz }
10887481efa2Scsapuntz
10897481efa2Scsapuntz /*
109059a52720Sjmc * request sense failed ! it's not supposed
10917481efa2Scsapuntz * to be possible
10927481efa2Scsapuntz */
109366bb6343Scsapuntz sc_xfer->error = XS_SHORTSENSE;
10949ec8daebSderaadt } else if (xfer->c_bcount < sizeof(sc_xfer->sense)) {
10957481efa2Scsapuntz /* use the sense we just read */
10967481efa2Scsapuntz sc_xfer->error = XS_SENSE;
10977481efa2Scsapuntz } else {
10987481efa2Scsapuntz /*
10997481efa2Scsapuntz * command completed, but no data was read.
110059a52720Sjmc * use the short sense we saved previously.
11017481efa2Scsapuntz */
11027481efa2Scsapuntz sc_xfer->error = XS_SHORTSENSE;
11037481efa2Scsapuntz }
11047481efa2Scsapuntz } else {
11057481efa2Scsapuntz sc_xfer->resid = xfer->c_bcount;
11067481efa2Scsapuntz if (chp->ch_status & WDCS_ERR) {
1107ab72a97eScsapuntz if (!atapi_to_scsi_sense(sc_xfer, chp->ch_error) &&
1108ab72a97eScsapuntz (sc_xfer->sc_link->quirks &
110976fd3256Scsapuntz ADEV_NOSENSE) == 0) {
11107481efa2Scsapuntz /*
11117481efa2Scsapuntz * let the driver issue a
11127481efa2Scsapuntz * 'request sense'
11137481efa2Scsapuntz */
11147481efa2Scsapuntz xfer->databuf = &sc_xfer->sense;
1115a24b05dfScsapuntz xfer->c_bcount = sizeof(sc_xfer->sense);
11167481efa2Scsapuntz xfer->c_skip = 0;
1117a24b05dfScsapuntz xfer->c_done = NULL;
11187481efa2Scsapuntz xfer->c_flags |= C_SENSE;
1119a24b05dfScsapuntz xfer->next = wdc_atapi_real_start;
112054f23ac8Scsapuntz return;
11217481efa2Scsapuntz }
11229ec8daebSderaadt }
11239ec8daebSderaadt }
11249ec8daebSderaadt
11254ba73d8bScsapuntz if ((xfer->c_flags & C_DMA) &&
11264ba73d8bScsapuntz (chp->wdc->dma_status & ~WDC_DMAST_UNDER)) {
1127ec8802a4Scsapuntz ata_dmaerr(drvp);
11287481efa2Scsapuntz sc_xfer->error = XS_RESET;
1129a24b05dfScsapuntz
1130a24b05dfScsapuntz xfer->next = wdc_atapi_reset;
113154f23ac8Scsapuntz return;
11327481efa2Scsapuntz }
11339ec8daebSderaadt
11349ec8daebSderaadt
11357481efa2Scsapuntz if (xfer->c_bcount != 0) {
11367481efa2Scsapuntz WDCDEBUG_PRINT(("wdc_atapi_intr: bcount value is "
11377481efa2Scsapuntz "%d after io\n", xfer->c_bcount), DEBUG_XFERS);
11387481efa2Scsapuntz }
11397481efa2Scsapuntz #ifdef DIAGNOSTIC
11407481efa2Scsapuntz if (xfer->c_bcount < 0) {
11417481efa2Scsapuntz printf("wdc_atapi_intr warning: bcount value "
11427481efa2Scsapuntz "is %d after io\n", xfer->c_bcount);
11437481efa2Scsapuntz }
11447481efa2Scsapuntz #endif
11457481efa2Scsapuntz
11467481efa2Scsapuntz WDCDEBUG_PRINT(("wdc_atapi_intr: wdc_atapi_done() (end), error 0x%x "
11477481efa2Scsapuntz "\n", sc_xfer->error),
11487481efa2Scsapuntz DEBUG_INTR);
1149a24b05dfScsapuntz
1150a24b05dfScsapuntz
1151a24b05dfScsapuntz if (xfer->c_done)
1152a24b05dfScsapuntz xfer->next = xfer->c_done;
1153a24b05dfScsapuntz else
1154a24b05dfScsapuntz xfer->next = wdc_atapi_done;
1155a24b05dfScsapuntz
115654f23ac8Scsapuntz return;
11577481efa2Scsapuntz }
11587481efa2Scsapuntz
115954f23ac8Scsapuntz void
wdc_atapi_pio_intr(struct channel_softc * chp,struct wdc_xfer * xfer,int timeout,struct atapi_return_args * ret)1160c28b5ab2Smatthew wdc_atapi_pio_intr(struct channel_softc *chp, struct wdc_xfer *xfer,
1161c28b5ab2Smatthew int timeout, struct atapi_return_args *ret)
11624b7fd08fScsapuntz {
11634b7fd08fScsapuntz struct scsi_xfer *sc_xfer = xfer->cmd;
11640b29cb40Skrw struct atapiscsi_softc *as = sc_xfer->sc_link->bus->sb_adapter_softc;
11650c6728ddScsapuntz u_int8_t ireason;
11663f343521Scsapuntz
1167ab72a97eScsapuntz wdc_atapi_update_status(chp);
1168ab72a97eScsapuntz
1169caa5053fScsapuntz if (chp->ch_status & WDCS_BSY) {
1170caa5053fScsapuntz if (timeout)
1171caa5053fScsapuntz goto timeout;
1172a24b05dfScsapuntz
117354f23ac8Scsapuntz return;
1174e61c843cScsapuntz }
1175e61c843cScsapuntz
117695c10403Scsapuntz if (!wdc_atapi_drive_selected(chp, xfer->drive)) {
11773f343521Scsapuntz WDCDEBUG_PRINT(("wdc_atapi_intr_for_us: wrong drive selected\n"), DEBUG_INTR);
117895c10403Scsapuntz wdc_set_drive(chp, xfer->drive);
1179ad0c6836Scsapuntz delay (1);
1180ad0c6836Scsapuntz
1181caa5053fScsapuntz if (!timeout)
118254f23ac8Scsapuntz return;
1183ad0c6836Scsapuntz }
1184ad0c6836Scsapuntz
11853f343521Scsapuntz if ((xfer->c_flags & C_MEDIA_ACCESS) &&
11860c6728ddScsapuntz !(chp->ch_status & (WDCS_DSC | WDCS_DRQ))) {
1187caa5053fScsapuntz if (timeout)
1188caa5053fScsapuntz goto timeout;
1189caa5053fScsapuntz
119054f23ac8Scsapuntz ret->delay = 100;
119154f23ac8Scsapuntz return;
1192a24b05dfScsapuntz }
1193a24b05dfScsapuntz
11943f343521Scsapuntz if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
11953f343521Scsapuntz chp->wdc->irqack(chp);
1196a24b05dfScsapuntz
11970c6728ddScsapuntz ireason = CHP_READ_REG(chp, wdr_ireason);
119895c10403Scsapuntz WDC_LOG_REG(chp, wdr_ireason, ireason);
119995c10403Scsapuntz
120020d226a3Sgrange WDCDEBUG_PRINT(("Phase %d, (0x%b, 0x%x) ", as->protocol_phase,
120120d226a3Sgrange chp->ch_status, WDCS_BITS, ireason), DEBUG_INTR );
12020c6728ddScsapuntz
12030c6728ddScsapuntz switch (as->protocol_phase) {
12040c6728ddScsapuntz case as_data:
12050c6728ddScsapuntz if ((chp->ch_status & WDCS_DRQ) ||
120654f23ac8Scsapuntz (ireason & 3) != 3) {
1207caa5053fScsapuntz if (timeout)
1208caa5053fScsapuntz goto timeout;
1209caa5053fScsapuntz
121054f23ac8Scsapuntz wdc_atapi_intr_data(chp, xfer, timeout, ret);
121154f23ac8Scsapuntz return;
121254f23ac8Scsapuntz }
12130c6728ddScsapuntz
1214e7ff6ceeSmpi wdc_atapi_intr_complete(chp, xfer, timeout, ret);
12156836a844Smestre return;
12166836a844Smestre
12170c6728ddScsapuntz case as_completed:
12180c6728ddScsapuntz if ((chp->ch_status & WDCS_DRQ) ||
12190c6728ddScsapuntz (ireason & 3) != 3) {
1220caa5053fScsapuntz if (timeout)
1221caa5053fScsapuntz goto timeout;
1222caa5053fScsapuntz
122354f23ac8Scsapuntz ret->delay = 100;
122454f23ac8Scsapuntz return;
1225a24b05dfScsapuntz }
1226a24b05dfScsapuntz
122754f23ac8Scsapuntz wdc_atapi_intr_complete(chp, xfer, timeout, ret);
122854f23ac8Scsapuntz return;
12290c6728ddScsapuntz
12300c6728ddScsapuntz default:
12310c6728ddScsapuntz printf ("atapiscsi: Shouldn't get here\n");
12320c6728ddScsapuntz sc_xfer->error = XS_DRIVER_STUFFUP;
12330c6728ddScsapuntz xfer->next = wdc_atapi_reset;
123454f23ac8Scsapuntz return;
12350c6728ddScsapuntz }
1236caa5053fScsapuntz
1237caa5053fScsapuntz return;
1238caa5053fScsapuntz timeout:
123966bb6343Scsapuntz ireason = CHP_READ_REG(chp, wdr_ireason);
124095c10403Scsapuntz WDC_LOG_REG(chp, wdr_ireason, ireason);
124166bb6343Scsapuntz
12423f343521Scsapuntz printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip=%d, "
124320d226a3Sgrange "status=0x%b, ireason=0x%x\n",
12443f343521Scsapuntz chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
124520d226a3Sgrange xfer->c_bcount, xfer->c_skip, chp->ch_status, WDCS_BITS, ireason);
1246caa5053fScsapuntz
1247caa5053fScsapuntz sc_xfer->error = XS_TIMEOUT;
1248caa5053fScsapuntz xfer->next = wdc_atapi_reset;
1249caa5053fScsapuntz return;
12504b7fd08fScsapuntz }
12514b7fd08fScsapuntz
125254f23ac8Scsapuntz void
wdc_atapi_ctrl(struct channel_softc * chp,struct wdc_xfer * xfer,int timeout,struct atapi_return_args * ret)1253c28b5ab2Smatthew wdc_atapi_ctrl(struct channel_softc *chp, struct wdc_xfer *xfer,
1254c28b5ab2Smatthew int timeout, struct atapi_return_args *ret)
12557481efa2Scsapuntz {
12567481efa2Scsapuntz struct scsi_xfer *sc_xfer = xfer->cmd;
12577481efa2Scsapuntz struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
12587481efa2Scsapuntz char *errstring = NULL;
12597481efa2Scsapuntz
1260a24b05dfScsapuntz wdc_atapi_update_status(chp);
1261a24b05dfScsapuntz
12622702c783Scsapuntz if (!timeout) {
12632702c783Scsapuntz switch (drvp->state) {
12642702c783Scsapuntz case ATAPI_IDENTIFY_WAIT_STATE:
12652702c783Scsapuntz if (chp->ch_status & WDCS_BSY)
126654f23ac8Scsapuntz return;
12672702c783Scsapuntz break;
12682702c783Scsapuntz default:
12692702c783Scsapuntz if (chp->ch_status & (WDCS_BSY | WDCS_DRQ))
12702702c783Scsapuntz return;
12712702c783Scsapuntz break;
12722702c783Scsapuntz }
12732702c783Scsapuntz }
1274a24b05dfScsapuntz
1275ad0c6836Scsapuntz if (!wdc_atapi_drive_selected(chp, xfer->drive))
1276ad0c6836Scsapuntz {
127795c10403Scsapuntz wdc_set_drive(chp, xfer->drive);
1278ad0c6836Scsapuntz delay (1);
1279ad0c6836Scsapuntz }
1280ad0c6836Scsapuntz
128166bb6343Scsapuntz if (timeout) {
128266bb6343Scsapuntz int trigger_timeout = 1;
1283ad0c6836Scsapuntz
128466bb6343Scsapuntz switch (drvp->state) {
128566bb6343Scsapuntz case ATAPI_DEVICE_RESET_WAIT_STATE:
128666bb6343Scsapuntz errstring = "Device Reset Wait";
128766bb6343Scsapuntz drvp->drive_flags &= ~DRIVE_DEVICE_RESET;
128866bb6343Scsapuntz break;
128966bb6343Scsapuntz
12902702c783Scsapuntz case ATAPI_IDENTIFY_WAIT_STATE:
12912702c783Scsapuntz errstring = "Identify";
12922702c783Scsapuntz if (!(chp->ch_status & WDCS_BSY) &&
12932702c783Scsapuntz (chp->ch_status & (WDCS_DRQ | WDCS_ERR)))
12942702c783Scsapuntz trigger_timeout = 0;
12952702c783Scsapuntz
12962702c783Scsapuntz break;
12972702c783Scsapuntz
12987e610aa1Scsapuntz case ATAPI_PIOMODE_STATE:
12997e610aa1Scsapuntz errstring = "Post-Identify";
13007e610aa1Scsapuntz if (!(chp->ch_status & (WDCS_BSY | WDCS_DRQ)))
13017e610aa1Scsapuntz trigger_timeout = 0;
13027e610aa1Scsapuntz break;
13037e610aa1Scsapuntz
130466bb6343Scsapuntz case ATAPI_PIOMODE_WAIT_STATE:
130566bb6343Scsapuntz errstring = "PIOMODE";
13062702c783Scsapuntz if (chp->ch_status & (WDCS_BSY | WDCS_DRQ))
130766bb6343Scsapuntz drvp->drive_flags &= ~DRIVE_MODE;
130866bb6343Scsapuntz else
130966bb6343Scsapuntz trigger_timeout = 0;
131066bb6343Scsapuntz break;
131166bb6343Scsapuntz case ATAPI_DMAMODE_WAIT_STATE:
131266bb6343Scsapuntz errstring = "dmamode";
13132702c783Scsapuntz if (chp->ch_status & (WDCS_BSY | WDCS_DRQ))
131466bb6343Scsapuntz drvp->drive_flags &= ~(DRIVE_DMA | DRIVE_UDMA);
131566bb6343Scsapuntz else
131666bb6343Scsapuntz trigger_timeout = 0;
131766bb6343Scsapuntz break;
131866bb6343Scsapuntz
131966bb6343Scsapuntz default:
132066bb6343Scsapuntz errstring = "unknown state";
132166bb6343Scsapuntz break;
132266bb6343Scsapuntz }
132366bb6343Scsapuntz
132466bb6343Scsapuntz if (trigger_timeout)
132566bb6343Scsapuntz goto timeout;
132666bb6343Scsapuntz }
1327a24b05dfScsapuntz
13287481efa2Scsapuntz WDCDEBUG_PRINT(("wdc_atapi_ctrl %s:%d:%d state %d\n",
13297481efa2Scsapuntz chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive, drvp->state),
13307481efa2Scsapuntz DEBUG_INTR | DEBUG_FUNCS);
1331a077a3e9Scsapuntz
13327481efa2Scsapuntz switch (drvp->state) {
133366bb6343Scsapuntz /* My ATAPI slave device likes to assert DASP-/PDIAG- until
133466bb6343Scsapuntz it is DEVICE RESET. This causes the LED to stay on.
1335a077a3e9Scsapuntz
133666bb6343Scsapuntz There is a trade-off here. This drive will cause any
133766bb6343Scsapuntz play-back or seeks happening to be interrupted.
1338a077a3e9Scsapuntz
133966bb6343Scsapuntz Note that the bus reset that triggered this state
134066bb6343Scsapuntz (which may have been caused by the other drive on
134166bb6343Scsapuntz the chain) need not interrupt this playback. It happens
134266bb6343Scsapuntz to on my Smart & Friendly CD burner.
134366bb6343Scsapuntz
134466bb6343Scsapuntz - csapuntz@
134566bb6343Scsapuntz */
134666bb6343Scsapuntz case ATAPI_RESET_BASE_STATE:
134766bb6343Scsapuntz if ((drvp->drive_flags & DRIVE_DEVICE_RESET) == 0) {
13482702c783Scsapuntz drvp->state = ATAPI_IDENTIFY_STATE;
1349a24b05dfScsapuntz break;
135048d11ec3Scsapuntz }
135136acebdeScsapuntz
135266bb6343Scsapuntz wdccommandshort(chp, drvp->drive, ATAPI_DEVICE_RESET);
135366bb6343Scsapuntz drvp->state = ATAPI_DEVICE_RESET_WAIT_STATE;
13542702c783Scsapuntz ret->delay = ATAPI_RESET_DELAY;
135566bb6343Scsapuntz ret->timeout = ATAPI_RESET_WAIT;
135666bb6343Scsapuntz break;
1357a24b05dfScsapuntz
135866bb6343Scsapuntz case ATAPI_DEVICE_RESET_WAIT_STATE:
135983344e41Sjsg /* FALLTHROUGH */
13602702c783Scsapuntz
13612702c783Scsapuntz case ATAPI_IDENTIFY_STATE:
13622702c783Scsapuntz wdccommandshort(chp, drvp->drive, ATAPI_IDENTIFY_DEVICE);
13632702c783Scsapuntz drvp->state = ATAPI_IDENTIFY_WAIT_STATE;
13642702c783Scsapuntz ret->delay = 10;
136566bb6343Scsapuntz ret->timeout = ATAPI_RESET_WAIT;
136666bb6343Scsapuntz break;
136766bb6343Scsapuntz
13682702c783Scsapuntz case ATAPI_IDENTIFY_WAIT_STATE: {
13692702c783Scsapuntz int idx = 0;
13702702c783Scsapuntz
13712702c783Scsapuntz while ((chp->ch_status & WDCS_DRQ) &&
13722702c783Scsapuntz idx++ < 20) {
13732702c783Scsapuntz wdcbit_bucket(chp, 512);
13742702c783Scsapuntz
13752702c783Scsapuntz DELAY(1);
13762702c783Scsapuntz wdc_atapi_update_status(chp);
13772702c783Scsapuntz }
13782702c783Scsapuntz
13792702c783Scsapuntz drvp->state = ATAPI_PIOMODE_STATE;
13807e610aa1Scsapuntz /*
13817e610aa1Scsapuntz * Note, we can't go directly to set PIO mode
13827e610aa1Scsapuntz * because the drive is free to assert BSY
13837e610aa1Scsapuntz * after the transfer
13847e610aa1Scsapuntz */
13857e610aa1Scsapuntz break;
13862702c783Scsapuntz }
13872702c783Scsapuntz
138866bb6343Scsapuntz case ATAPI_PIOMODE_STATE:
13897481efa2Scsapuntz /* Don't try to set mode if controller can't be adjusted */
13907481efa2Scsapuntz if ((chp->wdc->cap & WDC_CAPABILITY_MODE) == 0)
13917481efa2Scsapuntz goto ready;
13927481efa2Scsapuntz /* Also don't try if the drive didn't report its mode */
13937481efa2Scsapuntz if ((drvp->drive_flags & DRIVE_MODE) == 0)
1394ec62f1edSniklas goto ready;
1395d9aa2812Sgrange /* SET FEATURES 0x08 is only for PIO mode > 2 */
1396d9aa2812Sgrange if (drvp->PIO_mode <= 2)
1397d9aa2812Sgrange goto ready;
13987481efa2Scsapuntz wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
13997481efa2Scsapuntz 0x08 | drvp->PIO_mode, WDSF_SET_MODE);
140066bb6343Scsapuntz drvp->state = ATAPI_PIOMODE_WAIT_STATE;
140154f23ac8Scsapuntz ret->timeout = ATAPI_CTRL_WAIT;
140254f23ac8Scsapuntz ret->expect_irq = 1;
14037481efa2Scsapuntz break;
140466bb6343Scsapuntz case ATAPI_PIOMODE_WAIT_STATE:
1405caa5053fScsapuntz if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
1406caa5053fScsapuntz chp->wdc->irqack(chp);
14077481efa2Scsapuntz if (chp->ch_status & WDCS_ERR) {
1408d9aa2812Sgrange /* Downgrade straight to PIO mode 3 */
140953b549e4Scsapuntz drvp->PIO_mode = 3;
141066bb6343Scsapuntz chp->wdc->set_modes(chp);
14117481efa2Scsapuntz }
141283344e41Sjsg /* FALLTHROUGH */
14137481efa2Scsapuntz
141466bb6343Scsapuntz case ATAPI_DMAMODE_STATE:
14157481efa2Scsapuntz if (drvp->drive_flags & DRIVE_UDMA) {
14167481efa2Scsapuntz wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
14177481efa2Scsapuntz 0x40 | drvp->UDMA_mode, WDSF_SET_MODE);
14187481efa2Scsapuntz } else if (drvp->drive_flags & DRIVE_DMA) {
14197481efa2Scsapuntz wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
14207481efa2Scsapuntz 0x20 | drvp->DMA_mode, WDSF_SET_MODE);
14217481efa2Scsapuntz } else {
14227481efa2Scsapuntz goto ready;
14237481efa2Scsapuntz }
142466bb6343Scsapuntz drvp->state = ATAPI_DMAMODE_WAIT_STATE;
1425a24b05dfScsapuntz
142654f23ac8Scsapuntz ret->timeout = ATAPI_CTRL_WAIT;
142754f23ac8Scsapuntz ret->expect_irq = 1;
14287481efa2Scsapuntz break;
1429a24b05dfScsapuntz
143066bb6343Scsapuntz case ATAPI_DMAMODE_WAIT_STATE:
1431caa5053fScsapuntz if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
1432caa5053fScsapuntz chp->wdc->irqack(chp);
14337481efa2Scsapuntz if (chp->ch_status & WDCS_ERR)
1434ab72a97eScsapuntz drvp->drive_flags &= ~(DRIVE_DMA | DRIVE_UDMA);
143583344e41Sjsg /* FALLTHROUGH */
14367481efa2Scsapuntz
143766bb6343Scsapuntz case ATAPI_READY_STATE:
14387481efa2Scsapuntz ready:
143966bb6343Scsapuntz drvp->state = ATAPI_READY_STATE;
1440a24b05dfScsapuntz xfer->next = wdc_atapi_real_start;
1441a24b05dfScsapuntz break;
14427481efa2Scsapuntz }
144354f23ac8Scsapuntz return;
14447481efa2Scsapuntz
14457481efa2Scsapuntz timeout:
14467481efa2Scsapuntz printf("%s:%d:%d: %s timed out\n",
14477481efa2Scsapuntz chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, errstring);
14487481efa2Scsapuntz sc_xfer->error = XS_TIMEOUT;
1449a24b05dfScsapuntz xfer->next = wdc_atapi_reset;
145054f23ac8Scsapuntz return;
1451a24b05dfScsapuntz
14527481efa2Scsapuntz }
14537481efa2Scsapuntz
145454f23ac8Scsapuntz void
wdc_atapi_tape_done(struct channel_softc * chp,struct wdc_xfer * xfer,int timeout,struct atapi_return_args * ret)1455c28b5ab2Smatthew wdc_atapi_tape_done(struct channel_softc *chp, struct wdc_xfer *xfer,
1456c28b5ab2Smatthew int timeout, struct atapi_return_args *ret)
1457a24b05dfScsapuntz {
1458a24b05dfScsapuntz struct scsi_xfer *sc_xfer = xfer->cmd;
1459a24b05dfScsapuntz
1460a24b05dfScsapuntz if (sc_xfer->error != XS_NOERROR) {
1461a24b05dfScsapuntz xfer->next = wdc_atapi_done;
146254f23ac8Scsapuntz return;
1463a24b05dfScsapuntz }
1464a24b05dfScsapuntz
1465a24b05dfScsapuntz _lto3b(xfer->transfer_len,
1466a24b05dfScsapuntz ((struct scsi_rw_tape *)
1467664c6166Skrw &sc_xfer->cmd)->len);
1468a24b05dfScsapuntz
1469a24b05dfScsapuntz xfer->c_bcount = sc_xfer->datalen;
1470a24b05dfScsapuntz xfer->c_done = NULL;
1471a24b05dfScsapuntz xfer->c_skip = 0;
1472a24b05dfScsapuntz
1473a24b05dfScsapuntz xfer->next = wdc_atapi_real_start;
147454f23ac8Scsapuntz return;
1475a24b05dfScsapuntz }
1476a24b05dfScsapuntz
1477a24b05dfScsapuntz
147854f23ac8Scsapuntz void
wdc_atapi_done(struct channel_softc * chp,struct wdc_xfer * xfer,int timeout,struct atapi_return_args * ret)1479c28b5ab2Smatthew wdc_atapi_done(struct channel_softc *chp, struct wdc_xfer *xfer,
1480c28b5ab2Smatthew int timeout, struct atapi_return_args *ret)
14817481efa2Scsapuntz {
14827481efa2Scsapuntz struct scsi_xfer *sc_xfer = xfer->cmd;
14837481efa2Scsapuntz
14844ba73d8bScsapuntz WDCDEBUG_PRINT(("wdc_atapi_done %s:%d:%d: flags 0x%x error 0x%x\n",
14857481efa2Scsapuntz chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
14864ba73d8bScsapuntz (u_int)xfer->c_flags, sc_xfer->error), DEBUG_XFERS);
148795c10403Scsapuntz WDC_LOG_ATAPI_DONE(chp, xfer->drive, xfer->c_flags, sc_xfer->error);
1488a24b05dfScsapuntz
14898e703ec5Skrw if (xfer->c_flags & C_POLL)
1490e7f35eb1Sgrange wdc_enable_intr(chp);
14918e703ec5Skrw
14927481efa2Scsapuntz scsi_done(sc_xfer);
1493a24b05dfScsapuntz
149454f23ac8Scsapuntz xfer->next = NULL;
149554f23ac8Scsapuntz return;
14967481efa2Scsapuntz }
14977481efa2Scsapuntz
1498ec62f1edSniklas
149954f23ac8Scsapuntz void
wdc_atapi_reset(struct channel_softc * chp,struct wdc_xfer * xfer,int timeout,struct atapi_return_args * ret)1500c28b5ab2Smatthew wdc_atapi_reset(struct channel_softc *chp, struct wdc_xfer *xfer,
1501c28b5ab2Smatthew int timeout, struct atapi_return_args *ret)
15027481efa2Scsapuntz {
15037481efa2Scsapuntz struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
15047481efa2Scsapuntz
1505ec8802a4Scsapuntz if (drvp->state == 0) {
1506ec8802a4Scsapuntz xfer->next = wdc_atapi_done;
1507ec8802a4Scsapuntz return;
1508ec8802a4Scsapuntz }
1509ec8802a4Scsapuntz
15104ba73d8bScsapuntz WDCDEBUG_PRINT(("wdc_atapi_reset\n"), DEBUG_XFERS);
15117481efa2Scsapuntz wdccommandshort(chp, xfer->drive, ATAPI_SOFT_RESET);
15122702c783Scsapuntz drvp->state = ATAPI_IDENTIFY_STATE;
1513a077a3e9Scsapuntz
151466bb6343Scsapuntz drvp->n_resets++;
1515a077a3e9Scsapuntz /* Some ATAPI devices need extra time to find their
1516a077a3e9Scsapuntz brains after a reset
1517a077a3e9Scsapuntz */
1518a24b05dfScsapuntz xfer->next = wdc_atapi_reset_2;
15192702c783Scsapuntz ret->delay = ATAPI_RESET_DELAY;
152054f23ac8Scsapuntz ret->timeout = ATAPI_RESET_WAIT;
152154f23ac8Scsapuntz return;
1522a24b05dfScsapuntz }
1523a077a3e9Scsapuntz
152454f23ac8Scsapuntz void
wdc_atapi_reset_2(struct channel_softc * chp,struct wdc_xfer * xfer,int timeout,struct atapi_return_args * ret)1525c28b5ab2Smatthew wdc_atapi_reset_2(struct channel_softc *chp, struct wdc_xfer *xfer,
1526c28b5ab2Smatthew int timeout, struct atapi_return_args *ret)
1527a24b05dfScsapuntz {
1528a24b05dfScsapuntz struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
1529a24b05dfScsapuntz struct scsi_xfer *sc_xfer = xfer->cmd;
1530a24b05dfScsapuntz
1531a24b05dfScsapuntz if (timeout) {
1532bf07dfc9Scsapuntz printf("%s:%d:%d: soft reset failed\n",
15337481efa2Scsapuntz chp->wdc->sc_dev.dv_xname, chp->channel,
15347481efa2Scsapuntz xfer->drive);
15357481efa2Scsapuntz sc_xfer->error = XS_SELTIMEOUT;
1536ba8cbb4aSmiod wdc_reset_channel(drvp, 0);
1537a24b05dfScsapuntz
1538a24b05dfScsapuntz xfer->next = wdc_atapi_done;
153954f23ac8Scsapuntz return;
15407481efa2Scsapuntz }
1541a077a3e9Scsapuntz
1542a24b05dfScsapuntz wdc_atapi_update_status(chp);
1543a24b05dfScsapuntz
1544a24b05dfScsapuntz if (chp->ch_status & (WDCS_BSY | WDCS_DRQ)) {
154554f23ac8Scsapuntz return;
15467481efa2Scsapuntz }
1547a24b05dfScsapuntz
1548a24b05dfScsapuntz xfer->next = wdc_atapi_done;
154954f23ac8Scsapuntz return;
1550a24b05dfScsapuntz }
1551