xref: /dragonfly/sys/dev/disk/nata/ata-sata.c (revision 2458a87a718a37261418254ad47f5f9adc3366d4)
1 /*-
2  * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification, immediately at the beginning of the file.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "opt_ata.h"
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/bus.h>
32 #include <sys/malloc.h>
33 #include <sys/lock.h>
34 #include <sys/taskqueue.h>
35 
36 #include <sys/mplock2.h>                /* for {get,rel}_mplock() */
37 
38 #include "ata-all.h"
39 #include "ata-pci.h"
40 #include "ata_if.h"
41 
42 /*
43  * SATA support functions
44  */
45 void
ata_sata_phy_event(void * context,int dummy)46 ata_sata_phy_event(void *context, int dummy)
47 {
48     struct ata_connect_task *tp = (struct ata_connect_task *)context;
49     struct ata_channel *ch = device_get_softc(tp->dev);
50     device_t *children;
51     int nchildren, i;
52 
53     get_mplock();
54     if (tp->action == ATA_C_ATTACH) {
55           if (bootverbose)
56               device_printf(tp->dev, "CONNECTED\n");
57           ATA_RESET(tp->dev);
58           ata_identify(tp->dev);
59     }
60     if (tp->action == ATA_C_DETACH) {
61           if (!device_get_children(tp->dev, &children, &nchildren)) {
62               for (i = 0; i < nchildren; i++)
63                     if (children[i])
64                         device_delete_child(tp->dev, children[i]);
65               kfree(children, M_TEMP);
66           }
67           lockmgr(&ch->state_mtx, LK_EXCLUSIVE);
68           ch->state = ATA_IDLE;
69           lockmgr(&ch->state_mtx, LK_RELEASE);
70           if (bootverbose)
71               device_printf(tp->dev, "DISCONNECTED\n");
72     }
73     rel_mplock();
74     kfree(tp, M_ATA);
75 }
76 
77 void
ata_sata_phy_check_events(device_t dev)78 ata_sata_phy_check_events(device_t dev)
79 {
80     struct ata_channel *ch = device_get_softc(dev);
81     u_int32_t error = ATA_IDX_INL(ch, ATA_SERROR);
82 
83     /* clear error bits/interrupt */
84     ATA_IDX_OUTL(ch, ATA_SERROR, error);
85 
86     /* do we have any events flagged ? */
87     if (error) {
88           struct ata_connect_task *tp;
89           u_int32_t status = ATA_IDX_INL(ch, ATA_SSTATUS);
90 
91           /* if we have a connection event deal with it */
92           if ((error & ATA_SE_PHY_CHANGED) &&
93               (tp = (struct ata_connect_task *)
94                       kmalloc(sizeof(struct ata_connect_task),
95                                M_ATA, M_INTWAIT | M_ZERO))) {
96 
97               if (((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1) ||
98                     ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2)) {
99                     if (bootverbose)
100                         device_printf(ch->dev, "CONNECT requested\n");
101                     tp->action = ATA_C_ATTACH;
102               }
103               else {
104                     if (bootverbose)
105                         device_printf(ch->dev, "DISCONNECT requested\n");
106                     tp->action = ATA_C_DETACH;
107               }
108               tp->dev = ch->dev;
109               TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp);
110               taskqueue_enqueue(taskqueue_thread[mycpuid], &tp->task);
111           }
112     }
113 }
114 
115 static int
ata_sata_connect(struct ata_channel * ch)116 ata_sata_connect(struct ata_channel *ch)
117 {
118     u_int32_t status;
119     int timeout;
120 
121     /* wait up to 1 second for "connect well" */
122     for (timeout = 0; timeout < 100 ; timeout++) {
123           status = ATA_IDX_INL(ch, ATA_SSTATUS);
124           if ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1 ||
125               (status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2)
126               break;
127           ata_udelay(10000);
128     }
129     if (timeout >= 100) {
130           if (bootverbose)
131               device_printf(ch->dev, "SATA connect status=%08x\n", status);
132           return 0;
133     }
134     if (bootverbose)
135           device_printf(ch->dev, "SATA connect time=%dms\n", timeout * 10);
136 
137     /* clear SATA error register */
138     ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR));
139 
140     return 1;
141 }
142 
143 int
ata_sata_phy_reset(device_t dev)144 ata_sata_phy_reset(device_t dev)
145 {
146     struct ata_channel *ch = device_get_softc(dev);
147     int loop, retry;
148 
149     if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == ATA_SC_DET_IDLE)
150           return ata_sata_connect(ch);
151 
152     for (retry = 0; retry < 10; retry++) {
153           for (loop = 0; loop < 10; loop++) {
154               ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_RESET);
155               ata_udelay(100);
156               if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) ==
157                     ATA_SC_DET_RESET)
158                     break;
159           }
160           ata_udelay(5000);
161           for (loop = 0; loop < 10; loop++) {
162               ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_IDLE |
163                                                      ATA_SC_IPM_DIS_PARTIAL |
164                                                      ATA_SC_IPM_DIS_SLUMBER);
165               ata_udelay(100);
166               if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == 0)
167                     return ata_sata_connect(ch);
168           }
169     }
170     return 0;
171 }
172 
173 void
ata_sata_setmode(device_t dev,int mode)174 ata_sata_setmode(device_t dev, int mode)
175 {
176     struct ata_device *atadev = device_get_softc(dev);
177 
178     /*
179      * if we detect that the device isn't a real SATA device we limit
180      * the transfer mode to UDMA5/ATA100.
181      * this works around the problems some devices has with the
182      * Marvell 88SX8030 SATA->PATA converters and UDMA6/ATA133.
183      */
184     if (atadev->param.satacapabilities != 0x0000 &&
185           atadev->param.satacapabilities != 0xffff) {
186           struct ata_channel *ch = device_get_softc(device_get_parent(dev));
187 
188           /* on some drives we need to set the transfer mode */
189           ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0,
190                            ata_limit_mode(dev, mode, ATA_UDMA6));
191 
192           /* query SATA STATUS for the speed */
193         if (ch->r_io[ATA_SSTATUS].res &&
194              ((ATA_IDX_INL(ch, ATA_SSTATUS) & ATA_SS_CONWELL_MASK) ==
195               ATA_SS_CONWELL_GEN2))
196               atadev->mode = ATA_SA300;
197           else
198               atadev->mode = ATA_SA150;
199     }
200     else {
201           mode = ata_limit_mode(dev, mode, ATA_UDMA5);
202           if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode))
203               atadev->mode = mode;
204     }
205 }
206 
207 int
ata_request2fis_h2d(struct ata_request * request,u_int8_t * fis)208 ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis)
209 {
210     struct ata_device *atadev = device_get_softc(request->dev);
211 
212     if (request->flags & ATA_R_ATAPI) {
213           fis[0] = 0x27;                          /* host to device */
214           fis[1] = 0x80 | (atadev->unit & 0x0f);
215           fis[2] = ATA_PACKET_CMD;
216           if (request->flags & (ATA_R_READ | ATA_R_WRITE))
217               fis[3] = ATA_F_DMA;
218           else {
219               fis[5] = request->transfersize;
220               fis[6] = request->transfersize >> 8;
221           }
222           fis[7] = ATA_D_LBA;
223           fis[15] = ATA_A_4BIT;
224           return 20;
225     }
226     else {
227           ata_modify_if_48bit(request);
228           fis[0] = 0x27;                          /* host to device */
229           fis[1] = 0x80 | (atadev->unit & 0x0f);
230           fis[2] = request->u.ata.command;
231           fis[3] = request->u.ata.feature;
232           fis[4] = request->u.ata.lba;
233           fis[5] = request->u.ata.lba >> 8;
234           fis[6] = request->u.ata.lba >> 16;
235           fis[7] = ATA_D_LBA;
236           if (!(atadev->flags & ATA_D_48BIT_ACTIVE))
237               fis[7] |= (ATA_D_IBM | (request->u.ata.lba >> 24 & 0x0f));
238           fis[8] = request->u.ata.lba >> 24;
239           fis[9] = request->u.ata.lba >> 32;
240           fis[10] = request->u.ata.lba >> 40;
241           fis[11] = request->u.ata.feature >> 8;
242           fis[12] = request->u.ata.count;
243           fis[13] = request->u.ata.count >> 8;
244           fis[15] = ATA_A_4BIT;
245           return 20;
246     }
247     return 0;
248 }
249