siop.c revision 1.1 1 1.1 kiyohara int siopdbg = 0;
2 1.1 kiyohara /* $NetBSD: siop.c,v 1.1 2010/10/14 06:58:22 kiyohara Exp $ */
3 1.1 kiyohara /*
4 1.1 kiyohara * Copyright (c) 2010 KIYOHARA Takashi
5 1.1 kiyohara * All rights reserved.
6 1.1 kiyohara *
7 1.1 kiyohara * Redistribution and use in source and binary forms, with or without
8 1.1 kiyohara * modification, are permitted provided that the following conditions
9 1.1 kiyohara * are met:
10 1.1 kiyohara * 1. Redistributions of source code must retain the above copyright
11 1.1 kiyohara * notice, this list of conditions and the following disclaimer.
12 1.1 kiyohara * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 kiyohara * notice, this list of conditions and the following disclaimer in the
14 1.1 kiyohara * documentation and/or other materials provided with the distribution.
15 1.1 kiyohara *
16 1.1 kiyohara * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 1.1 kiyohara * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 1.1 kiyohara * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 1.1 kiyohara * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20 1.1 kiyohara * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 1.1 kiyohara * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 1.1 kiyohara * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 1.1 kiyohara * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 1.1 kiyohara * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25 1.1 kiyohara * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.1 kiyohara * POSSIBILITY OF SUCH DAMAGE.
27 1.1 kiyohara */
28 1.1 kiyohara
29 1.1 kiyohara #include <lib/libsa/stand.h>
30 1.1 kiyohara #include <lib/libkern/libkern.h>
31 1.1 kiyohara
32 1.1 kiyohara #include <dev/microcode/siop/siop.out>
33 1.1 kiyohara
34 1.1 kiyohara #include "boot.h"
35 1.1 kiyohara #include "sdvar.h"
36 1.1 kiyohara
37 1.1 kiyohara #define ALLOC(T, A) \
38 1.1 kiyohara (T *)(((uint32_t)alloc(sizeof(T) + (A)) + (A)) & ~((A) - 1))
39 1.1 kiyohara #define VTOPHYS(va) (uint32_t)(va)
40 1.1 kiyohara #define DEVTOV(pa) (uint32_t)(pa)
41 1.1 kiyohara #define wbinv(adr, siz) _wbinv(VTOPHYS(adr), (uint32_t)(siz))
42 1.1 kiyohara #define inv(adr, siz) _inv(VTOPHYS(adr), (uint32_t)(siz))
43 1.1 kiyohara
44 1.1 kiyohara /* 53c810 supports little endian */
45 1.1 kiyohara #define htoc32(x) htole32(x)
46 1.1 kiyohara #define ctoh32(x) le32toh(x)
47 1.1 kiyohara
48 1.1 kiyohara static void siop_pci_reset(int);
49 1.1 kiyohara
50 1.1 kiyohara static void siop_setuptables(struct siop_adapter *, struct siop_xfer *,
51 1.1 kiyohara struct scsi_xfer *);
52 1.1 kiyohara static void siop_ma(struct siop_adapter *, struct scsi_xfer *);
53 1.1 kiyohara static void siop_sdp(struct siop_adapter *, struct siop_xfer *,
54 1.1 kiyohara struct scsi_xfer *, int);
55 1.1 kiyohara static void siop_update_resid(struct siop_adapter *, struct siop_xfer *,
56 1.1 kiyohara struct scsi_xfer *, int);
57 1.1 kiyohara
58 1.1 kiyohara static int siop_intr(struct siop_adapter *);
59 1.1 kiyohara static void siop_scsicmd_end(struct siop_adapter *, struct scsi_xfer *);
60 1.1 kiyohara static int siop_scsi_request(struct siop_adapter *, struct scsi_xfer *);
61 1.1 kiyohara static void siop_start(struct siop_adapter *, struct scsi_xfer *);
62 1.1 kiyohara static void siop_xfer_setup(struct siop_xfer *, void *);
63 1.1 kiyohara
64 1.1 kiyohara static int siop_add_reselsw(struct siop_adapter *, int, int);
65 1.1 kiyohara static void siop_update_scntl3(struct siop_adapter *, int, int);
66 1.1 kiyohara
67 1.1 kiyohara static int _scsi_inquire(struct siop_adapter *, int, int, int, char *);
68 1.1 kiyohara static void scsi_request_sense(struct siop_adapter *, struct scsi_xfer *);
69 1.1 kiyohara static int scsi_interpret_sense(struct siop_adapter *, struct scsi_xfer *);
70 1.1 kiyohara static int scsi_probe(struct siop_adapter *);
71 1.1 kiyohara
72 1.1 kiyohara static struct siop_adapter adapt;
73 1.1 kiyohara
74 1.1 kiyohara
75 1.1 kiyohara static void
76 1.1 kiyohara siop_pci_reset(int addr)
77 1.1 kiyohara {
78 1.1 kiyohara int dmode, ctest5;
79 1.1 kiyohara const int maxburst = 4; /* 53c810 */
80 1.1 kiyohara
81 1.1 kiyohara dmode = readb(addr + SIOP_DMODE);
82 1.1 kiyohara
83 1.1 kiyohara ctest5 = readb(addr + SIOP_CTEST5);
84 1.1 kiyohara writeb(addr + SIOP_CTEST4, readb(addr + SIOP_CTEST4) & ~CTEST4_BDIS);
85 1.1 kiyohara ctest5 &= ~CTEST5_BBCK;
86 1.1 kiyohara ctest5 |= (maxburst - 1) & CTEST5_BBCK;
87 1.1 kiyohara writeb(addr + SIOP_CTEST5, ctest5);
88 1.1 kiyohara
89 1.1 kiyohara dmode |= DMODE_ERL;
90 1.1 kiyohara dmode &= ~DMODE_BL_MASK;
91 1.1 kiyohara dmode |= ((maxburst - 1) << DMODE_BL_SHIFT) & DMODE_BL_MASK;
92 1.1 kiyohara writeb(addr + SIOP_DMODE, dmode);
93 1.1 kiyohara }
94 1.1 kiyohara
95 1.1 kiyohara
96 1.1 kiyohara static void
97 1.1 kiyohara siop_setuptables(struct siop_adapter *adp, struct siop_xfer *xfer,
98 1.1 kiyohara struct scsi_xfer *xs)
99 1.1 kiyohara {
100 1.1 kiyohara int msgoffset = 1;
101 1.1 kiyohara
102 1.1 kiyohara xfer->siop_tables.id =
103 1.1 kiyohara htoc32((adp->clock_div << 24) | (xs->target << 16));
104 1.1 kiyohara memset(xfer->siop_tables.msg_out, 0, sizeof(xfer->siop_tables.msg_out));
105 1.1 kiyohara /* request sense doesn't disconnect */
106 1.1 kiyohara if (xs->cmd->opcode == SCSI_REQUEST_SENSE)
107 1.1 kiyohara xfer->siop_tables.msg_out[0] = MSG_IDENTIFY(xs->lun, 0);
108 1.1 kiyohara else
109 1.1 kiyohara xfer->siop_tables.msg_out[0] = MSG_IDENTIFY(xs->lun, 1);
110 1.1 kiyohara
111 1.1 kiyohara xfer->siop_tables.t_msgout.count = htoc32(msgoffset);
112 1.1 kiyohara xfer->siop_tables.status =
113 1.1 kiyohara htoc32(SCSI_SIOP_NOSTATUS); /* set invalid status */
114 1.1 kiyohara
115 1.1 kiyohara xfer->siop_tables.cmd.count = htoc32(xs->cmdlen);
116 1.1 kiyohara xfer->siop_tables.cmd.addr = htoc32(local_to_PCI((u_long)xs->cmd));
117 1.1 kiyohara if (xs->datalen != 0) {
118 1.1 kiyohara xfer->siop_tables.data[0].count = htoc32(xs->datalen);
119 1.1 kiyohara xfer->siop_tables.data[0].addr =
120 1.1 kiyohara htoc32(local_to_PCI((u_long)xs->data));
121 1.1 kiyohara }
122 1.1 kiyohara }
123 1.1 kiyohara
124 1.1 kiyohara static void
125 1.1 kiyohara siop_ma(struct siop_adapter *adp, struct scsi_xfer *xs)
126 1.1 kiyohara {
127 1.1 kiyohara int offset, dbc;
128 1.1 kiyohara
129 1.1 kiyohara /*
130 1.1 kiyohara * compute how much of the current table didn't get handled when
131 1.1 kiyohara * a phase mismatch occurs
132 1.1 kiyohara */
133 1.1 kiyohara if (xs->datalen == 0)
134 1.1 kiyohara return; /* no valid data transfer */
135 1.1 kiyohara
136 1.1 kiyohara offset = readb(adp->addr + SIOP_SCRATCHA + 1);
137 1.1 kiyohara if (offset >= SIOP_NSG) {
138 1.1 kiyohara printf("bad offset in siop_sdp (%d)\n", offset);
139 1.1 kiyohara return;
140 1.1 kiyohara }
141 1.1 kiyohara dbc = readl(adp->addr + SIOP_DBC) & 0x00ffffff;
142 1.1 kiyohara xs->resid = dbc;
143 1.1 kiyohara }
144 1.1 kiyohara
145 1.1 kiyohara static void
146 1.1 kiyohara siop_sdp(struct siop_adapter *adp, struct siop_xfer *xfer, struct scsi_xfer *xs,
147 1.1 kiyohara int offset)
148 1.1 kiyohara {
149 1.1 kiyohara
150 1.1 kiyohara if (xs->datalen == 0)
151 1.1 kiyohara return; /* no data pointers to save */
152 1.1 kiyohara
153 1.1 kiyohara /*
154 1.1 kiyohara * offset == SIOP_NSG may be a valid condition if we get a Save data
155 1.1 kiyohara * pointer when the xfer is done. Just ignore the Save data pointer
156 1.1 kiyohara * in this case
157 1.1 kiyohara */
158 1.1 kiyohara if (offset == SIOP_NSG)
159 1.1 kiyohara return;
160 1.1 kiyohara /*
161 1.1 kiyohara * Save data pointer. We do this by adjusting the tables to point
162 1.1 kiyohara * at the begginning of the data not yet transfered.
163 1.1 kiyohara * offset points to the first table with untransfered data.
164 1.1 kiyohara */
165 1.1 kiyohara
166 1.1 kiyohara /*
167 1.1 kiyohara * before doing that we decrease resid from the ammount of data which
168 1.1 kiyohara * has been transfered.
169 1.1 kiyohara */
170 1.1 kiyohara siop_update_resid(adp, xfer, xs, offset);
171 1.1 kiyohara
172 1.1 kiyohara #if 0
173 1.1 kiyohara /*
174 1.1 kiyohara * First let see if we have a resid from a phase mismatch. If so,
175 1.1 kiyohara * we have to adjst the table at offset to remove transfered data.
176 1.1 kiyohara */
177 1.1 kiyohara if (siop_cmd->flags & CMDFL_RESID) {
178 1.1 kiyohara scr_table_t *table;
179 1.1 kiyohara
180 1.1 kiyohara siop_cmd->flags &= ~CMDFL_RESID;
181 1.1 kiyohara table = &xfer->siop_tables.data[offset];
182 1.1 kiyohara /* "cut" already transfered data from this table */
183 1.1 kiyohara table->addr =
184 1.1 kiyohara htoc32(ctoh32(table->addr) + ctoh32(table->count) -
185 1.1 kiyohara siop_cmd->resid);
186 1.1 kiyohara table->count = htoc32(siop_cmd->resid);
187 1.1 kiyohara }
188 1.1 kiyohara #endif
189 1.1 kiyohara
190 1.1 kiyohara /*
191 1.1 kiyohara * now we can remove entries which have been transfered.
192 1.1 kiyohara * We just move the entries with data left at the beggining of the
193 1.1 kiyohara * tables
194 1.1 kiyohara */
195 1.1 kiyohara memmove(xfer->siop_tables.data, &xfer->siop_tables.data[offset],
196 1.1 kiyohara (SIOP_NSG - offset) * sizeof(scr_table_t));
197 1.1 kiyohara }
198 1.1 kiyohara
199 1.1 kiyohara static void
200 1.1 kiyohara siop_update_resid(struct siop_adapter *adp, struct siop_xfer *xfer,
201 1.1 kiyohara struct scsi_xfer *xs, int offset)
202 1.1 kiyohara {
203 1.1 kiyohara int i;
204 1.1 kiyohara
205 1.1 kiyohara if (xs->datalen == 0)
206 1.1 kiyohara return; /* no data to transfer */
207 1.1 kiyohara
208 1.1 kiyohara /*
209 1.1 kiyohara * update resid. First account for the table entries which have
210 1.1 kiyohara * been fully completed.
211 1.1 kiyohara */
212 1.1 kiyohara for (i = 0; i < offset; i++)
213 1.1 kiyohara xs->resid -= ctoh32(xfer->siop_tables.data[i].count);
214 1.1 kiyohara #if 0
215 1.1 kiyohara /*
216 1.1 kiyohara * if CMDFL_RESID is set, the last table (pointed by offset) is a
217 1.1 kiyohara * partial transfers. If not, offset points to the entry folloing
218 1.1 kiyohara * the last full transfer.
219 1.1 kiyohara */
220 1.1 kiyohara if (siop_cmd->flags & CMDFL_RESID) {
221 1.1 kiyohara scr_table_t *table = &xfer->siop_tables.data[offset];
222 1.1 kiyohara
223 1.1 kiyohara xs->resid -= ctoh32(table->count) - xs->resid;
224 1.1 kiyohara }
225 1.1 kiyohara #endif
226 1.1 kiyohara }
227 1.1 kiyohara
228 1.1 kiyohara
229 1.1 kiyohara #define CALL_SCRIPT(ent) writel(adp->addr + SIOP_DSP, scriptaddr + ent);
230 1.1 kiyohara
231 1.1 kiyohara static int
232 1.1 kiyohara siop_intr(struct siop_adapter *adp)
233 1.1 kiyohara {
234 1.1 kiyohara struct siop_xfer *siop_xfer = NULL;
235 1.1 kiyohara struct scsi_xfer *xs = NULL;
236 1.1 kiyohara u_long scriptaddr = local_to_PCI((u_long)adp->script);
237 1.1 kiyohara int offset, target, lun, tag, restart = 0, need_reset = 0;
238 1.1 kiyohara uint32_t dsa, irqcode;
239 1.1 kiyohara uint16_t sist;
240 1.1 kiyohara uint8_t dstat, sstat1, istat;
241 1.1 kiyohara
242 1.1 kiyohara istat = readb(adp->addr + SIOP_ISTAT);
243 1.1 kiyohara if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0)
244 1.1 kiyohara return 0;
245 1.1 kiyohara if (istat & ISTAT_INTF) {
246 1.1 kiyohara printf("INTRF\n");
247 1.1 kiyohara writeb(adp->addr + SIOP_ISTAT, ISTAT_INTF);
248 1.1 kiyohara }
249 1.1 kiyohara if ((istat & (ISTAT_DIP | ISTAT_SIP | ISTAT_ABRT)) ==
250 1.1 kiyohara (ISTAT_DIP | ISTAT_ABRT))
251 1.1 kiyohara /* clear abort */
252 1.1 kiyohara writeb(adp->addr + SIOP_ISTAT, 0);
253 1.1 kiyohara /* use DSA to find the current siop_cmd */
254 1.1 kiyohara dsa = readl(adp->addr + SIOP_DSA);
255 1.1 kiyohara if (dsa >= local_to_PCI((u_long)adp->xfer) &&
256 1.1 kiyohara dsa < local_to_PCI((u_long)adp->xfer) + SIOP_TABLE_SIZE) {
257 1.1 kiyohara dsa -= local_to_PCI((u_long)adp->xfer);
258 1.1 kiyohara siop_xfer = adp->xfer;
259 1.1 kiyohara _inv((u_long)siop_xfer, sizeof(*siop_xfer));
260 1.1 kiyohara
261 1.1 kiyohara xs = adp->xs;
262 1.1 kiyohara }
263 1.1 kiyohara
264 1.1 kiyohara if (istat & ISTAT_DIP)
265 1.1 kiyohara dstat = readb(adp->addr + SIOP_DSTAT);
266 1.1 kiyohara if (istat & ISTAT_SIP) {
267 1.1 kiyohara if (istat & ISTAT_DIP)
268 1.1 kiyohara delay(10);
269 1.1 kiyohara /*
270 1.1 kiyohara * Can't read sist0 & sist1 independently, or we have to
271 1.1 kiyohara * insert delay
272 1.1 kiyohara */
273 1.1 kiyohara sist = readw(adp->addr + SIOP_SIST0);
274 1.1 kiyohara sstat1 = readb(adp->addr + SIOP_SSTAT1);
275 1.1 kiyohara
276 1.1 kiyohara if ((sist & SIST0_MA) && need_reset == 0) {
277 1.1 kiyohara if (siop_xfer) {
278 1.1 kiyohara int scratcha0;
279 1.1 kiyohara
280 1.1 kiyohara dstat = readb(adp->addr + SIOP_DSTAT);
281 1.1 kiyohara /*
282 1.1 kiyohara * first restore DSA, in case we were in a S/G
283 1.1 kiyohara * operation.
284 1.1 kiyohara */
285 1.1 kiyohara writel(adp->addr + SIOP_DSA,
286 1.1 kiyohara local_to_PCI((u_long)siop_xfer));
287 1.1 kiyohara scratcha0 = readb(adp->addr + SIOP_SCRATCHA);
288 1.1 kiyohara switch (sstat1 & SSTAT1_PHASE_MASK) {
289 1.1 kiyohara case SSTAT1_PHASE_STATUS:
290 1.1 kiyohara /*
291 1.1 kiyohara * previous phase may be aborted for any reason
292 1.1 kiyohara * ( for example, the target has less data to
293 1.1 kiyohara * transfer than requested). Compute resid and
294 1.1 kiyohara * just go to status, the command should
295 1.1 kiyohara * terminate.
296 1.1 kiyohara */
297 1.1 kiyohara if (scratcha0 & A_flag_data)
298 1.1 kiyohara siop_ma(adp, xs);
299 1.1 kiyohara else if ((dstat & DSTAT_DFE) == 0)
300 1.1 kiyohara printf("PHASE STATUS: siop_clearfifo...\n");
301 1.1 kiyohara // siop_clearfifo(adp);
302 1.1 kiyohara CALL_SCRIPT(Ent_status);
303 1.1 kiyohara return 1;
304 1.1 kiyohara case SSTAT1_PHASE_MSGIN:
305 1.1 kiyohara /*
306 1.1 kiyohara * target may be ready to disconnect
307 1.1 kiyohara * Compute resid which would be used later
308 1.1 kiyohara * if a save data pointer is needed.
309 1.1 kiyohara */
310 1.1 kiyohara if (scratcha0 & A_flag_data)
311 1.1 kiyohara siop_ma(adp, xs);
312 1.1 kiyohara else if ((dstat & DSTAT_DFE) == 0)
313 1.1 kiyohara printf("PHASE MSGIN: siop_clearfifo...\n");
314 1.1 kiyohara // siop_clearfifo(adp);
315 1.1 kiyohara writeb(adp->addr + SIOP_SCRATCHA,
316 1.1 kiyohara scratcha0 & ~A_flag_data);
317 1.1 kiyohara CALL_SCRIPT(Ent_msgin);
318 1.1 kiyohara return 1;
319 1.1 kiyohara }
320 1.1 kiyohara printf("unexpected phase mismatch %d\n",
321 1.1 kiyohara sstat1 & SSTAT1_PHASE_MASK);
322 1.1 kiyohara } else
323 1.1 kiyohara printf("phase mismatch without command\n");
324 1.1 kiyohara need_reset = 1;
325 1.1 kiyohara }
326 1.1 kiyohara if (sist & (SIST1_STO << 8)) {
327 1.1 kiyohara /* selection time out, assume there's no device here */
328 1.1 kiyohara if (siop_xfer) {
329 1.1 kiyohara xs->error = XS_SELTIMEOUT;
330 1.1 kiyohara goto end;
331 1.1 kiyohara } else
332 1.1 kiyohara printf("selection timeout without command\n");
333 1.1 kiyohara }
334 1.1 kiyohara
335 1.1 kiyohara /* Else it's an unhandled exception (for now). */
336 1.1 kiyohara printf("unhandled scsi interrupt,"
337 1.1 kiyohara " sist=0x%x sstat1=0x%x DSA=0x%x DSP=0x%lx\n",
338 1.1 kiyohara sist, sstat1, dsa,
339 1.1 kiyohara readl(adp->addr + SIOP_DSP) - scriptaddr);
340 1.1 kiyohara if (siop_xfer) {
341 1.1 kiyohara xs->error = XS_SELTIMEOUT;
342 1.1 kiyohara goto end;
343 1.1 kiyohara }
344 1.1 kiyohara need_reset = 1;
345 1.1 kiyohara }
346 1.1 kiyohara if (need_reset) {
347 1.1 kiyohara reset:
348 1.1 kiyohara printf("XXXXX: fatal error, need reset the bus...\n");
349 1.1 kiyohara return 1;
350 1.1 kiyohara }
351 1.1 kiyohara
352 1.1 kiyohara //scintr:
353 1.1 kiyohara if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */
354 1.1 kiyohara irqcode = readl(adp->addr + SIOP_DSPS);
355 1.1 kiyohara /*
356 1.1 kiyohara * no command, or an inactive command is only valid for a
357 1.1 kiyohara * reselect interrupt
358 1.1 kiyohara */
359 1.1 kiyohara if ((irqcode & 0x80) == 0) {
360 1.1 kiyohara if (siop_xfer == NULL) {
361 1.1 kiyohara printf(
362 1.1 kiyohara "script interrupt 0x%x with invalid DSA\n",
363 1.1 kiyohara irqcode);
364 1.1 kiyohara goto reset;
365 1.1 kiyohara }
366 1.1 kiyohara }
367 1.1 kiyohara switch(irqcode) {
368 1.1 kiyohara case A_int_err:
369 1.1 kiyohara printf("error, DSP=0x%lx\n",
370 1.1 kiyohara readl(adp->addr + SIOP_DSP) - scriptaddr);
371 1.1 kiyohara if (xs) {
372 1.1 kiyohara xs->error = XS_SELTIMEOUT;
373 1.1 kiyohara goto end;
374 1.1 kiyohara } else {
375 1.1 kiyohara goto reset;
376 1.1 kiyohara }
377 1.1 kiyohara case A_int_reseltarg:
378 1.1 kiyohara printf("reselect with invalid target\n");
379 1.1 kiyohara goto reset;
380 1.1 kiyohara case A_int_resellun:
381 1.1 kiyohara target = readb(adp->addr + SIOP_SCRATCHA) & 0xf;
382 1.1 kiyohara lun = readb(adp->addr + SIOP_SCRATCHA + 1);
383 1.1 kiyohara tag = readb(adp->addr + SIOP_SCRATCHA + 2);
384 1.1 kiyohara if (target != adp->xs->target ||
385 1.1 kiyohara lun != adp->xs->lun ||
386 1.1 kiyohara tag != 0) {
387 1.1 kiyohara printf("unknwon resellun:"
388 1.1 kiyohara " target %d lun %d tag %d\n",
389 1.1 kiyohara target, lun, tag);
390 1.1 kiyohara goto reset;
391 1.1 kiyohara }
392 1.1 kiyohara siop_xfer = adp->xfer;
393 1.1 kiyohara dsa = local_to_PCI((u_long)siop_xfer);
394 1.1 kiyohara writel(adp->addr + SIOP_DSP,
395 1.1 kiyohara dsa + sizeof(struct siop_common_xfer) +
396 1.1 kiyohara Ent_ldsa_reload_dsa);
397 1.1 kiyohara _wbinv((u_long)siop_xfer, sizeof(*siop_xfer));
398 1.1 kiyohara return 1;
399 1.1 kiyohara case A_int_reseltag:
400 1.1 kiyohara printf("reselect with invalid tag\n");
401 1.1 kiyohara goto reset;
402 1.1 kiyohara case A_int_disc:
403 1.1 kiyohara offset = readb(adp->addr + SIOP_SCRATCHA + 1);
404 1.1 kiyohara siop_sdp(adp, siop_xfer, xs, offset);
405 1.1 kiyohara #if 0
406 1.1 kiyohara /* we start again with no offset */
407 1.1 kiyohara siop_cmd->saved_offset = SIOP_NOOFFSET;
408 1.1 kiyohara #endif
409 1.1 kiyohara _wbinv((u_long)siop_xfer, sizeof(*siop_xfer));
410 1.1 kiyohara CALL_SCRIPT(Ent_script_sched);
411 1.1 kiyohara return 1;
412 1.1 kiyohara case A_int_resfail:
413 1.1 kiyohara printf("reselect failed\n");
414 1.1 kiyohara return 1;
415 1.1 kiyohara case A_int_done:
416 1.1 kiyohara if (xs == NULL) {
417 1.1 kiyohara printf("done without command, DSA=0x%lx\n",
418 1.1 kiyohara local_to_PCI((u_long)adp->xfer));
419 1.1 kiyohara return 1;
420 1.1 kiyohara }
421 1.1 kiyohara /* update resid. */
422 1.1 kiyohara offset = readb(adp->addr + SIOP_SCRATCHA + 1);
423 1.1 kiyohara #if 0
424 1.1 kiyohara /*
425 1.1 kiyohara * if we got a disconnect between the last data phase
426 1.1 kiyohara * and the status phase, offset will be 0. In this
427 1.1 kiyohara * case, siop_cmd->saved_offset will have the proper
428 1.1 kiyohara * value if it got updated by the controller
429 1.1 kiyohara */
430 1.1 kiyohara if (offset == 0 &&
431 1.1 kiyohara siop_cmd->saved_offset != SIOP_NOOFFSET)
432 1.1 kiyohara offset = siop_cmd->saved_offset;
433 1.1 kiyohara #endif
434 1.1 kiyohara siop_update_resid(adp, siop_xfer, xs, offset);
435 1.1 kiyohara goto end;
436 1.1 kiyohara default:
437 1.1 kiyohara printf("unknown irqcode %x\n", irqcode);
438 1.1 kiyohara if (xs) {
439 1.1 kiyohara xs->error = XS_SELTIMEOUT;
440 1.1 kiyohara goto end;
441 1.1 kiyohara }
442 1.1 kiyohara goto reset;
443 1.1 kiyohara }
444 1.1 kiyohara return 1;
445 1.1 kiyohara }
446 1.1 kiyohara /* We just should't get there */
447 1.1 kiyohara panic("siop_intr: I shouldn't be there !");
448 1.1 kiyohara
449 1.1 kiyohara return 1;
450 1.1 kiyohara
451 1.1 kiyohara end:
452 1.1 kiyohara /*
453 1.1 kiyohara * restart the script now if command completed properly
454 1.1 kiyohara * Otherwise wait for siop_scsicmd_end(), we may need to cleanup the
455 1.1 kiyohara * queue
456 1.1 kiyohara */
457 1.1 kiyohara xs->status = ctoh32(siop_xfer->siop_tables.status);
458 1.1 kiyohara if (xs->status == SCSI_OK)
459 1.1 kiyohara writel(adp->addr + SIOP_DSP, scriptaddr + Ent_script_sched);
460 1.1 kiyohara else
461 1.1 kiyohara restart = 1;
462 1.1 kiyohara siop_scsicmd_end(adp, xs);
463 1.1 kiyohara if (restart)
464 1.1 kiyohara writel(adp->addr + SIOP_DSP, scriptaddr + Ent_script_sched);
465 1.1 kiyohara
466 1.1 kiyohara return 1;
467 1.1 kiyohara }
468 1.1 kiyohara
469 1.1 kiyohara static void
470 1.1 kiyohara siop_scsicmd_end(struct siop_adapter *adp, struct scsi_xfer *xs)
471 1.1 kiyohara {
472 1.1 kiyohara
473 1.1 kiyohara switch(xs->status) {
474 1.1 kiyohara case SCSI_OK:
475 1.1 kiyohara xs->error = XS_NOERROR;
476 1.1 kiyohara break;
477 1.1 kiyohara case SCSI_BUSY:
478 1.1 kiyohara case SCSI_CHECK:
479 1.1 kiyohara case SCSI_QUEUE_FULL:
480 1.1 kiyohara xs->error = XS_BUSY;
481 1.1 kiyohara break;
482 1.1 kiyohara case SCSI_SIOP_NOCHECK:
483 1.1 kiyohara /*
484 1.1 kiyohara * don't check status, xs->error is already valid
485 1.1 kiyohara */
486 1.1 kiyohara break;
487 1.1 kiyohara case SCSI_SIOP_NOSTATUS:
488 1.1 kiyohara /*
489 1.1 kiyohara * the status byte was not updated, cmd was
490 1.1 kiyohara * aborted
491 1.1 kiyohara */
492 1.1 kiyohara xs->error = XS_SELTIMEOUT;
493 1.1 kiyohara break;
494 1.1 kiyohara default:
495 1.1 kiyohara printf("invalid status code %d\n", xs->status);
496 1.1 kiyohara xs->error = XS_DRIVER_STUFFUP;
497 1.1 kiyohara }
498 1.1 kiyohara _inv((u_long)xs->cmd, xs->cmdlen);
499 1.1 kiyohara if (xs->datalen != 0)
500 1.1 kiyohara _inv((u_long)xs->data, xs->datalen);
501 1.1 kiyohara xs->xs_status = XS_STS_DONE;
502 1.1 kiyohara }
503 1.1 kiyohara
504 1.1 kiyohara static int
505 1.1 kiyohara siop_scsi_request(struct siop_adapter *adp, struct scsi_xfer *xs)
506 1.1 kiyohara {
507 1.1 kiyohara void *xfer = adp->xfer;
508 1.1 kiyohara int timo, error;
509 1.1 kiyohara
510 1.1 kiyohara if (adp->sel_t != xs->target) {
511 1.1 kiyohara const int free_lo = __arraycount(siop_script);
512 1.1 kiyohara int i;
513 1.1 kiyohara void *scriptaddr = (void *)local_to_PCI((u_long)adp->script);
514 1.1 kiyohara
515 1.1 kiyohara if (adp->sel_t != -1)
516 1.1 kiyohara adp->script[Ent_resel_targ0 / 4 + adp->sel_t * 2] =
517 1.1 kiyohara htoc32(0x800c00ff);
518 1.1 kiyohara
519 1.1 kiyohara for (i = 0; i < __arraycount(lun_switch); i++)
520 1.1 kiyohara adp->script[free_lo + i] = htoc32(lun_switch[i]);
521 1.1 kiyohara adp->script[free_lo + E_abs_lunsw_return_Used[0]] =
522 1.1 kiyohara htoc32(scriptaddr + Ent_lunsw_return);
523 1.1 kiyohara
524 1.1 kiyohara siop_add_reselsw(adp, xs->target, free_lo);
525 1.1 kiyohara
526 1.1 kiyohara adp->sel_t = xs->target;
527 1.1 kiyohara }
528 1.1 kiyohara
529 1.1 kiyohara restart:
530 1.1 kiyohara
531 1.1 kiyohara siop_setuptables(adp, xfer, xs);
532 1.1 kiyohara
533 1.1 kiyohara /* load the DMA maps */
534 1.1 kiyohara if (xs->datalen != 0)
535 1.1 kiyohara _inv((u_long)xs->data, xs->datalen);
536 1.1 kiyohara _wbinv((u_long)xs->cmd, xs->cmdlen);
537 1.1 kiyohara
538 1.1 kiyohara _wbinv((u_long)xfer, sizeof(struct siop_xfer));
539 1.1 kiyohara siop_start(adp, xs);
540 1.1 kiyohara
541 1.1 kiyohara adp->xs = xs;
542 1.1 kiyohara timo = 0;
543 1.1 kiyohara while (!(xs->xs_status & XS_STS_DONE)) {
544 1.1 kiyohara delay(1000);
545 1.1 kiyohara siop_intr(adp);
546 1.1 kiyohara
547 1.1 kiyohara if (timo++ > 3000) { /* XXXX: 3sec */
548 1.1 kiyohara printf("%s: timeout\n", __func__);
549 1.1 kiyohara return ETIMEDOUT;
550 1.1 kiyohara }
551 1.1 kiyohara }
552 1.1 kiyohara
553 1.1 kiyohara if (xs->error != XS_NOERROR) {
554 1.1 kiyohara if (xs->error == XS_BUSY || xs->status == SCSI_CHECK)
555 1.1 kiyohara scsi_request_sense(adp, xs);
556 1.1 kiyohara
557 1.1 kiyohara switch (xs->error) {
558 1.1 kiyohara case XS_SENSE:
559 1.1 kiyohara case XS_SHORTSENSE:
560 1.1 kiyohara error = scsi_interpret_sense(adp, xs);
561 1.1 kiyohara break;
562 1.1 kiyohara case XS_RESOURCE_SHORTAGE:
563 1.1 kiyohara printf("adapter resource shortage\n");
564 1.1 kiyohara
565 1.1 kiyohara /* FALLTHROUGH */
566 1.1 kiyohara case XS_BUSY:
567 1.1 kiyohara error = EBUSY;
568 1.1 kiyohara break;
569 1.1 kiyohara case XS_REQUEUE:
570 1.1 kiyohara printf("XXXX: requeue...\n");
571 1.1 kiyohara error = ERESTART;
572 1.1 kiyohara break;
573 1.1 kiyohara case XS_SELTIMEOUT:
574 1.1 kiyohara case XS_TIMEOUT:
575 1.1 kiyohara error = EIO;
576 1.1 kiyohara break;
577 1.1 kiyohara case XS_RESET:
578 1.1 kiyohara error = EIO;
579 1.1 kiyohara break;
580 1.1 kiyohara case XS_DRIVER_STUFFUP:
581 1.1 kiyohara printf("generic HBA error\n");
582 1.1 kiyohara error = EIO;
583 1.1 kiyohara break;
584 1.1 kiyohara default:
585 1.1 kiyohara printf("invalid return code from adapter: %d\n",
586 1.1 kiyohara xs->error);
587 1.1 kiyohara error = EIO;
588 1.1 kiyohara break;
589 1.1 kiyohara }
590 1.1 kiyohara if (error == ERESTART) {
591 1.1 kiyohara xs->error = XS_NOERROR;
592 1.1 kiyohara xs->status = SCSI_OK;
593 1.1 kiyohara xs->xs_status &= ~XS_STS_DONE;
594 1.1 kiyohara goto restart;
595 1.1 kiyohara }
596 1.1 kiyohara return error;
597 1.1 kiyohara }
598 1.1 kiyohara return 0;
599 1.1 kiyohara }
600 1.1 kiyohara
601 1.1 kiyohara static void
602 1.1 kiyohara siop_start(struct siop_adapter *adp, struct scsi_xfer *xs)
603 1.1 kiyohara {
604 1.1 kiyohara struct siop_xfer *siop_xfer = adp->xfer;
605 1.1 kiyohara uint32_t dsa, *script = adp->script;
606 1.1 kiyohara int target, lun, slot;
607 1.1 kiyohara void *scriptaddr = (void *)local_to_PCI((u_long)script);
608 1.1 kiyohara const int siop_common_xfer_size = sizeof(struct siop_common_xfer);
609 1.1 kiyohara
610 1.1 kiyohara /*
611 1.1 kiyohara * The queue management here is a bit tricky: the script always looks
612 1.1 kiyohara * at the slot from first to last, so if we always use the first
613 1.1 kiyohara * free slot commands can stay at the tail of the queue ~forever.
614 1.1 kiyohara * The algorithm used here is to restart from the head when we know
615 1.1 kiyohara * that the queue is empty, and only add commands after the last one.
616 1.1 kiyohara * When we're at the end of the queue wait for the script to clear it.
617 1.1 kiyohara * The best thing to do here would be to implement a circular queue,
618 1.1 kiyohara * but using only 53c720 features this can be "interesting".
619 1.1 kiyohara * A mid-way solution could be to implement 2 queues and swap orders.
620 1.1 kiyohara */
621 1.1 kiyohara slot = adp->currschedslot;
622 1.1 kiyohara /*
623 1.1 kiyohara * If the instruction is 0x80000000 (JUMP foo, IF FALSE) the slot is
624 1.1 kiyohara * free. As this is the last used slot, all previous slots are free,
625 1.1 kiyohara * we can restart from 0.
626 1.1 kiyohara */
627 1.1 kiyohara if (ctoh32(script[(Ent_script_sched_slot0 / 4) + slot * 2]) ==
628 1.1 kiyohara 0x80000000) {
629 1.1 kiyohara slot = adp->currschedslot = 0;
630 1.1 kiyohara } else {
631 1.1 kiyohara slot++;
632 1.1 kiyohara }
633 1.1 kiyohara target = xs->target;
634 1.1 kiyohara lun = xs->lun;
635 1.1 kiyohara /*
636 1.1 kiyohara * find a free scheduler slot and load it.
637 1.1 kiyohara */
638 1.1 kiyohara #define SIOP_NSLOTS 0x40
639 1.1 kiyohara for (; slot < SIOP_NSLOTS; slot++) {
640 1.1 kiyohara /*
641 1.1 kiyohara * If cmd if 0x80000000 the slot is free
642 1.1 kiyohara */
643 1.1 kiyohara if (ctoh32(script[(Ent_script_sched_slot0 / 4) + slot * 2]) ==
644 1.1 kiyohara 0x80000000)
645 1.1 kiyohara break;
646 1.1 kiyohara }
647 1.1 kiyohara if (slot == SIOP_NSLOTS) {
648 1.1 kiyohara /*
649 1.1 kiyohara * no more free slot, no need to continue. freeze the queue
650 1.1 kiyohara * and requeue this command.
651 1.1 kiyohara */
652 1.1 kiyohara printf("no mode free slot\n");
653 1.1 kiyohara return;
654 1.1 kiyohara }
655 1.1 kiyohara
656 1.1 kiyohara /* patch scripts with DSA addr */
657 1.1 kiyohara dsa = local_to_PCI((u_long)siop_xfer);
658 1.1 kiyohara
659 1.1 kiyohara /* CMD script: MOVE MEMORY addr */
660 1.1 kiyohara siop_xfer->resel[E_ldsa_abs_slot_Used[0]] =
661 1.1 kiyohara htoc32(scriptaddr + Ent_script_sched_slot0 + slot * 8);
662 1.1 kiyohara _wbinv((u_long)siop_xfer, sizeof(*siop_xfer));
663 1.1 kiyohara /* scheduler slot: JUMP ldsa_select */
664 1.1 kiyohara script[(Ent_script_sched_slot0 / 4) + slot * 2 + 1] =
665 1.1 kiyohara htoc32(dsa + siop_common_xfer_size + Ent_ldsa_select);
666 1.1 kiyohara /*
667 1.1 kiyohara * Change JUMP cmd so that this slot will be handled
668 1.1 kiyohara */
669 1.1 kiyohara script[(Ent_script_sched_slot0 / 4) + slot * 2] = htoc32(0x80080000);
670 1.1 kiyohara adp->currschedslot = slot;
671 1.1 kiyohara
672 1.1 kiyohara /* make sure SCRIPT processor will read valid data */
673 1.1 kiyohara _wbinv((u_long)script, SIOP_SCRIPT_SIZE);
674 1.1 kiyohara /* Signal script it has some work to do */
675 1.1 kiyohara writeb(adp->addr + SIOP_ISTAT, ISTAT_SIGP);
676 1.1 kiyohara /* and wait for IRQ */
677 1.1 kiyohara }
678 1.1 kiyohara
679 1.1 kiyohara static void
680 1.1 kiyohara siop_xfer_setup(struct siop_xfer *xfer, void *scriptaddr)
681 1.1 kiyohara {
682 1.1 kiyohara const int off_msg_in = offsetof(struct siop_common_xfer, msg_in);
683 1.1 kiyohara const int off_status = offsetof(struct siop_common_xfer, status);
684 1.1 kiyohara uint32_t dsa, *scr;
685 1.1 kiyohara int i;
686 1.1 kiyohara
687 1.1 kiyohara memset(xfer, 0, sizeof(*xfer));
688 1.1 kiyohara dsa = local_to_PCI((u_long)xfer);
689 1.1 kiyohara xfer->siop_tables.t_msgout.count = htoc32(1);
690 1.1 kiyohara xfer->siop_tables.t_msgout.addr = htoc32(dsa);
691 1.1 kiyohara xfer->siop_tables.t_msgin.count = htoc32(1);
692 1.1 kiyohara xfer->siop_tables.t_msgin.addr = htoc32(dsa + off_msg_in);
693 1.1 kiyohara xfer->siop_tables.t_extmsgin.count = htoc32(2);
694 1.1 kiyohara xfer->siop_tables.t_extmsgin.addr = htoc32(dsa + off_msg_in + 1);
695 1.1 kiyohara xfer->siop_tables.t_extmsgdata.addr = htoc32(dsa + off_msg_in + 3);
696 1.1 kiyohara xfer->siop_tables.t_status.count = htoc32(1);
697 1.1 kiyohara xfer->siop_tables.t_status.addr = htoc32(dsa + off_status);
698 1.1 kiyohara
699 1.1 kiyohara /* The select/reselect script */
700 1.1 kiyohara scr = xfer->resel;
701 1.1 kiyohara for (i = 0; i < __arraycount(load_dsa); i++)
702 1.1 kiyohara scr[i] = htoc32(load_dsa[i]);
703 1.1 kiyohara
704 1.1 kiyohara /*
705 1.1 kiyohara * 0x78000000 is a 'move data8 to reg'. data8 is the second
706 1.1 kiyohara * octet, reg offset is the third.
707 1.1 kiyohara */
708 1.1 kiyohara scr[Ent_rdsa0 / 4] = htoc32(0x78100000 | ((dsa & 0x000000ff) << 8));
709 1.1 kiyohara scr[Ent_rdsa1 / 4] = htoc32(0x78110000 | ( dsa & 0x0000ff00 ));
710 1.1 kiyohara scr[Ent_rdsa2 / 4] = htoc32(0x78120000 | ((dsa & 0x00ff0000) >> 8));
711 1.1 kiyohara scr[Ent_rdsa3 / 4] = htoc32(0x78130000 | ((dsa & 0xff000000) >> 16));
712 1.1 kiyohara scr[E_ldsa_abs_reselected_Used[0]] =
713 1.1 kiyohara htoc32(scriptaddr + Ent_reselected);
714 1.1 kiyohara scr[E_ldsa_abs_reselect_Used[0]] = htoc32(scriptaddr + Ent_reselect);
715 1.1 kiyohara scr[E_ldsa_abs_selected_Used[0]] = htoc32(scriptaddr + Ent_selected);
716 1.1 kiyohara scr[E_ldsa_abs_data_Used[0]] =
717 1.1 kiyohara htoc32(dsa + sizeof(struct siop_common_xfer) + Ent_ldsa_data);
718 1.1 kiyohara /* JUMP foo, IF FALSE - used by MOVE MEMORY to clear the slot */
719 1.1 kiyohara scr[Ent_ldsa_data / 4] = htoc32(0x80000000);
720 1.1 kiyohara }
721 1.1 kiyohara
722 1.1 kiyohara static int
723 1.1 kiyohara siop_add_reselsw(struct siop_adapter *adp, int target, int lunsw_off)
724 1.1 kiyohara {
725 1.1 kiyohara uint32_t *script = adp->script;
726 1.1 kiyohara int reseloff;
727 1.1 kiyohara void *scriptaddr = (void *)local_to_PCI((u_long)adp->script);
728 1.1 kiyohara
729 1.1 kiyohara /*
730 1.1 kiyohara * add an entry to resel switch
731 1.1 kiyohara */
732 1.1 kiyohara reseloff = Ent_resel_targ0 / 4 + target * 2;
733 1.1 kiyohara if ((ctoh32(script[reseloff]) & 0xff) != 0xff) {
734 1.1 kiyohara /* it's not free */
735 1.1 kiyohara printf("siop: resel switch full\n");
736 1.1 kiyohara return EBUSY;
737 1.1 kiyohara }
738 1.1 kiyohara
739 1.1 kiyohara /* JUMP abs_foo, IF target | 0x80; */
740 1.1 kiyohara script[reseloff + 0] = htoc32(0x800c0080 | target);
741 1.1 kiyohara script[reseloff + 1] =
742 1.1 kiyohara htoc32(scriptaddr + lunsw_off * 4 + Ent_lun_switch_entry);
743 1.1 kiyohara
744 1.1 kiyohara siop_update_scntl3(adp, target, lunsw_off);
745 1.1 kiyohara return 0;
746 1.1 kiyohara }
747 1.1 kiyohara
748 1.1 kiyohara static void
749 1.1 kiyohara siop_update_scntl3(struct siop_adapter *adp, int target, int lunsw_off)
750 1.1 kiyohara {
751 1.1 kiyohara uint32_t *script = adp->script;
752 1.1 kiyohara
753 1.1 kiyohara /* MOVE target->id >> 24 TO SCNTL3 */
754 1.1 kiyohara script[lunsw_off + (Ent_restore_scntl3 / 4)] =
755 1.1 kiyohara htoc32(0x78030000 | ((adp->clock_div >> 16) & 0x0000ff00));
756 1.1 kiyohara /* MOVE target->id >> 8 TO SXFER */
757 1.1 kiyohara script[lunsw_off + (Ent_restore_scntl3 / 4) + 2] =
758 1.1 kiyohara htoc32(0x78050000 | (0x000000000 & 0x0000ff00));
759 1.1 kiyohara _wbinv((u_long)script, SIOP_SCRIPT_SIZE);
760 1.1 kiyohara }
761 1.1 kiyohara
762 1.1 kiyohara
763 1.1 kiyohara /*
764 1.1 kiyohara * SCSI functions
765 1.1 kiyohara */
766 1.1 kiyohara
767 1.1 kiyohara static int
768 1.1 kiyohara _scsi_inquire(struct siop_adapter *adp, int t, int l, int buflen, char *buf)
769 1.1 kiyohara {
770 1.1 kiyohara struct scsipi_inquiry *cmd = (struct scsipi_inquiry *)adp->cmd;
771 1.1 kiyohara struct scsipi_inquiry_data *inqbuf =
772 1.1 kiyohara (struct scsipi_inquiry_data *)adp->data;
773 1.1 kiyohara struct scsi_xfer xs;
774 1.1 kiyohara int error;
775 1.1 kiyohara
776 1.1 kiyohara memset(cmd, 0, sizeof(*cmd));
777 1.1 kiyohara cmd->opcode = INQUIRY;
778 1.1 kiyohara cmd->length = SCSIPI_INQUIRY_LENGTH_SCSI2;
779 1.1 kiyohara memset(inqbuf, 0, sizeof(*inqbuf));
780 1.1 kiyohara
781 1.1 kiyohara memset(&xs, 0, sizeof(xs));
782 1.1 kiyohara xs.target = t;
783 1.1 kiyohara xs.lun = l;
784 1.1 kiyohara xs.cmdlen = sizeof(*cmd);
785 1.1 kiyohara xs.cmd = (void *)cmd;
786 1.1 kiyohara xs.datalen = SCSIPI_INQUIRY_LENGTH_SCSI2;
787 1.1 kiyohara xs.data = (void *)inqbuf;
788 1.1 kiyohara
789 1.1 kiyohara xs.error = XS_NOERROR;
790 1.1 kiyohara xs.resid = xs.datalen;
791 1.1 kiyohara xs.status = SCSI_OK;
792 1.1 kiyohara
793 1.1 kiyohara error = siop_scsi_request(adp, &xs);
794 1.1 kiyohara if (error != 0)
795 1.1 kiyohara return error;
796 1.1 kiyohara
797 1.1 kiyohara memcpy(buf, inqbuf, buflen);
798 1.1 kiyohara return 0;
799 1.1 kiyohara }
800 1.1 kiyohara
801 1.1 kiyohara static void
802 1.1 kiyohara scsi_request_sense(struct siop_adapter *adp, struct scsi_xfer *xs)
803 1.1 kiyohara {
804 1.1 kiyohara struct scsi_request_sense *cmd = adp->sense;
805 1.1 kiyohara struct scsi_sense_data *data = (struct scsi_sense_data *)adp->data;
806 1.1 kiyohara struct scsi_xfer sense;
807 1.1 kiyohara int error;
808 1.1 kiyohara
809 1.1 kiyohara memset(cmd, 0, sizeof(struct scsi_request_sense));
810 1.1 kiyohara cmd->opcode = SCSI_REQUEST_SENSE;
811 1.1 kiyohara cmd->length = sizeof(struct scsi_sense_data);
812 1.1 kiyohara memset(data, 0, sizeof(struct scsi_sense_data));
813 1.1 kiyohara
814 1.1 kiyohara memset(&sense, 0, sizeof(sense));
815 1.1 kiyohara sense.target = xs->target;
816 1.1 kiyohara sense.lun = xs->lun;
817 1.1 kiyohara sense.cmdlen = sizeof(struct scsi_request_sense);
818 1.1 kiyohara sense.cmd = (void *)cmd;
819 1.1 kiyohara sense.datalen = sizeof(struct scsi_sense_data);
820 1.1 kiyohara sense.data = (void *)data;
821 1.1 kiyohara
822 1.1 kiyohara sense.error = XS_NOERROR;
823 1.1 kiyohara sense.resid = sense.datalen;
824 1.1 kiyohara sense.status = SCSI_OK;
825 1.1 kiyohara
826 1.1 kiyohara error = siop_scsi_request(adp, &sense);
827 1.1 kiyohara switch (error) {
828 1.1 kiyohara case 0:
829 1.1 kiyohara /* we have a valid sense */
830 1.1 kiyohara xs->error = XS_SENSE;
831 1.1 kiyohara return;
832 1.1 kiyohara case EINTR:
833 1.1 kiyohara /* REQUEST_SENSE interrupted by bus reset. */
834 1.1 kiyohara xs->error = XS_RESET;
835 1.1 kiyohara return;
836 1.1 kiyohara case EIO:
837 1.1 kiyohara /* request sense coudn't be performed */
838 1.1 kiyohara /*
839 1.1 kiyohara * XXX this isn't quite right but we don't have anything
840 1.1 kiyohara * better for now
841 1.1 kiyohara */
842 1.1 kiyohara xs->error = XS_DRIVER_STUFFUP;
843 1.1 kiyohara return;
844 1.1 kiyohara default:
845 1.1 kiyohara /* Notify that request sense failed. */
846 1.1 kiyohara xs->error = XS_DRIVER_STUFFUP;
847 1.1 kiyohara printf("request sense failed with error %d\n", error);
848 1.1 kiyohara return;
849 1.1 kiyohara }
850 1.1 kiyohara }
851 1.1 kiyohara
852 1.1 kiyohara /*
853 1.1 kiyohara * scsi_interpret_sense:
854 1.1 kiyohara *
855 1.1 kiyohara * Look at the returned sense and act on the error, determining
856 1.1 kiyohara * the unix error number to pass back. (0 = report no error)
857 1.1 kiyohara *
858 1.1 kiyohara * NOTE: If we return ERESTART, we are expected to haved
859 1.1 kiyohara * thawed the device!
860 1.1 kiyohara *
861 1.1 kiyohara * THIS IS THE DEFAULT ERROR HANDLER FOR SCSI DEVICES.
862 1.1 kiyohara */
863 1.1 kiyohara static int
864 1.1 kiyohara scsi_interpret_sense(struct siop_adapter *adp, struct scsi_xfer *xs)
865 1.1 kiyohara {
866 1.1 kiyohara struct scsi_sense_data *sense;
867 1.1 kiyohara u_int8_t key;
868 1.1 kiyohara int error;
869 1.1 kiyohara uint32_t info;
870 1.1 kiyohara static const char *error_mes[] = {
871 1.1 kiyohara "soft error (corrected)",
872 1.1 kiyohara "not ready", "medium error",
873 1.1 kiyohara "non-media hardware failure", "illegal request",
874 1.1 kiyohara "unit attention", "readonly device",
875 1.1 kiyohara "no data found", "vendor unique",
876 1.1 kiyohara "copy aborted", "command aborted",
877 1.1 kiyohara "search returned equal", "volume overflow",
878 1.1 kiyohara "verify miscompare", "unknown error key"
879 1.1 kiyohara };
880 1.1 kiyohara
881 1.1 kiyohara sense = (struct scsi_sense_data *)xs->data;
882 1.1 kiyohara
883 1.1 kiyohara /* otherwise use the default */
884 1.1 kiyohara switch (SSD_RCODE(sense->response_code)) {
885 1.1 kiyohara
886 1.1 kiyohara /*
887 1.1 kiyohara * Old SCSI-1 and SASI devices respond with
888 1.1 kiyohara * codes other than 70.
889 1.1 kiyohara */
890 1.1 kiyohara case 0x00: /* no error (command completed OK) */
891 1.1 kiyohara return 0;
892 1.1 kiyohara case 0x04: /* drive not ready after it was selected */
893 1.1 kiyohara if (adp->sd->sc_flags & FLAGS_REMOVABLE)
894 1.1 kiyohara adp->sd->sc_flags &= ~FLAGS_MEDIA_LOADED;
895 1.1 kiyohara /* XXX - display some sort of error here? */
896 1.1 kiyohara return EIO;
897 1.1 kiyohara case 0x20: /* invalid command */
898 1.1 kiyohara return EINVAL;
899 1.1 kiyohara case 0x25: /* invalid LUN (Adaptec ACB-4000) */
900 1.1 kiyohara return EACCES;
901 1.1 kiyohara
902 1.1 kiyohara /*
903 1.1 kiyohara * If it's code 70, use the extended stuff and
904 1.1 kiyohara * interpret the key
905 1.1 kiyohara */
906 1.1 kiyohara case 0x71: /* delayed error */
907 1.1 kiyohara key = SSD_SENSE_KEY(sense->flags);
908 1.1 kiyohara printf(" DEFERRED ERROR, key = 0x%x\n", key);
909 1.1 kiyohara /* FALLTHROUGH */
910 1.1 kiyohara case 0x70:
911 1.1 kiyohara if ((sense->response_code & SSD_RCODE_VALID) != 0)
912 1.1 kiyohara info = _4btol(sense->info);
913 1.1 kiyohara else
914 1.1 kiyohara info = 0;
915 1.1 kiyohara key = SSD_SENSE_KEY(sense->flags);
916 1.1 kiyohara
917 1.1 kiyohara switch (key) {
918 1.1 kiyohara case SKEY_NO_SENSE:
919 1.1 kiyohara case SKEY_RECOVERED_ERROR:
920 1.1 kiyohara if (xs->resid == xs->datalen && xs->datalen) {
921 1.1 kiyohara /*
922 1.1 kiyohara * Why is this here?
923 1.1 kiyohara */
924 1.1 kiyohara xs->resid = 0; /* not short read */
925 1.1 kiyohara }
926 1.1 kiyohara case SKEY_EQUAL:
927 1.1 kiyohara error = 0;
928 1.1 kiyohara break;
929 1.1 kiyohara case SKEY_NOT_READY:
930 1.1 kiyohara if (adp->sd->sc_flags & FLAGS_REMOVABLE)
931 1.1 kiyohara adp->sd->sc_flags &= ~FLAGS_MEDIA_LOADED;
932 1.1 kiyohara if (sense->asc == 0x3A) {
933 1.1 kiyohara error = ENODEV; /* Medium not present */
934 1.1 kiyohara } else
935 1.1 kiyohara error = EIO;
936 1.1 kiyohara break;
937 1.1 kiyohara case SKEY_ILLEGAL_REQUEST:
938 1.1 kiyohara error = EINVAL;
939 1.1 kiyohara break;
940 1.1 kiyohara case SKEY_UNIT_ATTENTION:
941 1.1 kiyohara if (sense->asc == 0x29 &&
942 1.1 kiyohara sense->ascq == 0x00) {
943 1.1 kiyohara /* device or bus reset */
944 1.1 kiyohara return ERESTART;
945 1.1 kiyohara }
946 1.1 kiyohara if (adp->sd->sc_flags & FLAGS_REMOVABLE)
947 1.1 kiyohara adp->sd->sc_flags &= ~FLAGS_MEDIA_LOADED;
948 1.1 kiyohara if (!(adp->sd->sc_flags & FLAGS_REMOVABLE))
949 1.1 kiyohara return ERESTART;
950 1.1 kiyohara error = EIO;
951 1.1 kiyohara break;
952 1.1 kiyohara case SKEY_DATA_PROTECT:
953 1.1 kiyohara error = EROFS;
954 1.1 kiyohara break;
955 1.1 kiyohara case SKEY_BLANK_CHECK:
956 1.1 kiyohara error = 0;
957 1.1 kiyohara break;
958 1.1 kiyohara case SKEY_ABORTED_COMMAND:
959 1.1 kiyohara break;
960 1.1 kiyohara case SKEY_VOLUME_OVERFLOW:
961 1.1 kiyohara error = ENOSPC;
962 1.1 kiyohara break;
963 1.1 kiyohara default:
964 1.1 kiyohara error = EIO;
965 1.1 kiyohara break;
966 1.1 kiyohara }
967 1.1 kiyohara
968 1.1 kiyohara /* Print brief(er) sense information */
969 1.1 kiyohara printf("%s", error_mes[key - 1]);
970 1.1 kiyohara if ((sense->response_code & SSD_RCODE_VALID) != 0) {
971 1.1 kiyohara switch (key) {
972 1.1 kiyohara case SKEY_NOT_READY:
973 1.1 kiyohara case SKEY_ILLEGAL_REQUEST:
974 1.1 kiyohara case SKEY_UNIT_ATTENTION:
975 1.1 kiyohara case SKEY_DATA_PROTECT:
976 1.1 kiyohara break;
977 1.1 kiyohara case SKEY_BLANK_CHECK:
978 1.1 kiyohara printf(", requested size: %d (decimal)",
979 1.1 kiyohara info);
980 1.1 kiyohara break;
981 1.1 kiyohara case SKEY_ABORTED_COMMAND:
982 1.1 kiyohara printf(", cmd 0x%x, info 0x%x",
983 1.1 kiyohara xs->cmd->opcode, info);
984 1.1 kiyohara break;
985 1.1 kiyohara default:
986 1.1 kiyohara printf(", info = %d (decimal)", info);
987 1.1 kiyohara }
988 1.1 kiyohara }
989 1.1 kiyohara if (sense->extra_len != 0) {
990 1.1 kiyohara int n;
991 1.1 kiyohara printf(", data =");
992 1.1 kiyohara for (n = 0; n < sense->extra_len; n++)
993 1.1 kiyohara printf(" %x", sense->csi[n]);
994 1.1 kiyohara }
995 1.1 kiyohara printf("\n");
996 1.1 kiyohara return error;
997 1.1 kiyohara
998 1.1 kiyohara /*
999 1.1 kiyohara * Some other code, just report it
1000 1.1 kiyohara */
1001 1.1 kiyohara default:
1002 1.1 kiyohara printf("Sense Error Code 0x%x",
1003 1.1 kiyohara SSD_RCODE(sense->response_code));
1004 1.1 kiyohara if ((sense->response_code & SSD_RCODE_VALID) != 0) {
1005 1.1 kiyohara struct scsi_sense_data_unextended *usense =
1006 1.1 kiyohara (struct scsi_sense_data_unextended *)sense;
1007 1.1 kiyohara printf(" at block no. %d (decimal)",
1008 1.1 kiyohara _3btol(usense->block));
1009 1.1 kiyohara }
1010 1.1 kiyohara printf("\n");
1011 1.1 kiyohara return EIO;
1012 1.1 kiyohara }
1013 1.1 kiyohara }
1014 1.1 kiyohara
1015 1.1 kiyohara static int
1016 1.1 kiyohara scsi_probe(struct siop_adapter *adp)
1017 1.1 kiyohara {
1018 1.1 kiyohara struct scsipi_inquiry_data *inqbuf;
1019 1.1 kiyohara int found, t, l;
1020 1.1 kiyohara uint8_t device;
1021 1.1 kiyohara char buf[SCSIPI_INQUIRY_LENGTH_SCSI2],
1022 1.1 kiyohara product[sizeof(inqbuf->product) + 1];
1023 1.1 kiyohara
1024 1.1 kiyohara found = 0;
1025 1.1 kiyohara for (t = 0; t < 8; t++) {
1026 1.1 kiyohara if (t == adp->id)
1027 1.1 kiyohara continue;
1028 1.1 kiyohara for (l = 0; l < 8; l++) {
1029 1.1 kiyohara if (_scsi_inquire(adp, t, l, sizeof(buf), buf) != 0)
1030 1.1 kiyohara continue;
1031 1.1 kiyohara
1032 1.1 kiyohara inqbuf = (struct scsipi_inquiry_data *)buf;
1033 1.1 kiyohara device = inqbuf->device & SID_TYPE;
1034 1.1 kiyohara if (device == T_NODEVICE)
1035 1.1 kiyohara continue;
1036 1.1 kiyohara if (device != T_DIRECT &&
1037 1.1 kiyohara device != T_OPTICAL &&
1038 1.1 kiyohara device != T_SIMPLE_DIRECT)
1039 1.1 kiyohara continue;
1040 1.1 kiyohara
1041 1.1 kiyohara memset(product, 0, sizeof(product));
1042 1.1 kiyohara strncpy(product, inqbuf->product, sizeof(product) - 1);
1043 1.1 kiyohara printf("/dev/disk/scsi/0/%d/%d: <%s>\n", t, l, product);
1044 1.1 kiyohara found++;
1045 1.1 kiyohara }
1046 1.1 kiyohara }
1047 1.1 kiyohara return found;
1048 1.1 kiyohara }
1049 1.1 kiyohara
1050 1.1 kiyohara int
1051 1.1 kiyohara scsi_inquire(struct sd_softc *sd, int buflen, void *buf)
1052 1.1 kiyohara {
1053 1.1 kiyohara struct siop_adapter *adp;
1054 1.1 kiyohara int error;
1055 1.1 kiyohara
1056 1.1 kiyohara if (sd->sc_bus != 0)
1057 1.1 kiyohara return ENOTSUP;
1058 1.1 kiyohara if (adapt.addr == 0)
1059 1.1 kiyohara return ENOENT;
1060 1.1 kiyohara adp = &adapt;
1061 1.1 kiyohara
1062 1.1 kiyohara adp->sd = sd;
1063 1.1 kiyohara error = _scsi_inquire(adp, sd->sc_target, sd->sc_lun, buflen, buf);
1064 1.1 kiyohara adp->sd = NULL;
1065 1.1 kiyohara
1066 1.1 kiyohara return error;
1067 1.1 kiyohara }
1068 1.1 kiyohara
1069 1.1 kiyohara /*
1070 1.1 kiyohara * scsi_mode_sense
1071 1.1 kiyohara * get a sense page from a device
1072 1.1 kiyohara */
1073 1.1 kiyohara
1074 1.1 kiyohara int
1075 1.1 kiyohara scsi_mode_sense(struct sd_softc *sd, int byte2, int page,
1076 1.1 kiyohara struct scsi_mode_parameter_header_6 *data, int len)
1077 1.1 kiyohara {
1078 1.1 kiyohara struct scsi_mode_sense_6 cmd;
1079 1.1 kiyohara
1080 1.1 kiyohara memset(&cmd, 0, sizeof(cmd));
1081 1.1 kiyohara cmd.opcode = SCSI_MODE_SENSE_6;
1082 1.1 kiyohara cmd.byte2 = byte2;
1083 1.1 kiyohara cmd.page = page;
1084 1.1 kiyohara cmd.length = len & 0xff;
1085 1.1 kiyohara
1086 1.1 kiyohara return scsi_command(sd, (void *)&cmd, sizeof(cmd), (void *)data, len);
1087 1.1 kiyohara }
1088 1.1 kiyohara
1089 1.1 kiyohara int
1090 1.1 kiyohara scsi_command(struct sd_softc *sd, void *cmd, int cmdlen, void *data,
1091 1.1 kiyohara int datalen)
1092 1.1 kiyohara {
1093 1.1 kiyohara struct siop_adapter *adp;
1094 1.1 kiyohara struct scsi_xfer xs;
1095 1.1 kiyohara int error;
1096 1.1 kiyohara
1097 1.1 kiyohara if (sd->sc_bus != 0)
1098 1.1 kiyohara return ENOTSUP;
1099 1.1 kiyohara if (adapt.addr == 0)
1100 1.1 kiyohara return ENOENT;
1101 1.1 kiyohara adp = &adapt;
1102 1.1 kiyohara
1103 1.1 kiyohara memcpy(adp->cmd, cmd, cmdlen);
1104 1.1 kiyohara adp->sd = sd;
1105 1.1 kiyohara
1106 1.1 kiyohara memset(&xs, 0, sizeof(xs));
1107 1.1 kiyohara xs.target = sd->sc_target;
1108 1.1 kiyohara xs.lun = sd->sc_lun;
1109 1.1 kiyohara xs.cmdlen = cmdlen;
1110 1.1 kiyohara xs.cmd = adp->cmd;
1111 1.1 kiyohara xs.datalen = datalen;
1112 1.1 kiyohara xs.data = adp->data;
1113 1.1 kiyohara
1114 1.1 kiyohara xs.error = XS_NOERROR;
1115 1.1 kiyohara xs.resid = datalen;
1116 1.1 kiyohara xs.status = SCSI_OK;
1117 1.1 kiyohara
1118 1.1 kiyohara error = siop_scsi_request(adp, &xs);
1119 1.1 kiyohara adp->sd = NULL;
1120 1.1 kiyohara if (error != 0)
1121 1.1 kiyohara return error;
1122 1.1 kiyohara
1123 1.1 kiyohara if (datalen > 0)
1124 1.1 kiyohara memcpy(data, adp->data, datalen);
1125 1.1 kiyohara return 0;
1126 1.1 kiyohara }
1127 1.1 kiyohara
1128 1.1 kiyohara /*
1129 1.1 kiyohara * Initialize the device.
1130 1.1 kiyohara */
1131 1.1 kiyohara int
1132 1.1 kiyohara siop_init(int bus, int dev, int func)
1133 1.1 kiyohara {
1134 1.1 kiyohara struct siop_adapter tmp;
1135 1.1 kiyohara struct siop_xfer *xfer;
1136 1.1 kiyohara struct scsipi_generic *cmd;
1137 1.1 kiyohara struct scsi_request_sense *sense;
1138 1.1 kiyohara uint32_t reg;
1139 1.1 kiyohara u_long addr;
1140 1.1 kiyohara uint32_t *script;
1141 1.1 kiyohara int slot, id, i;
1142 1.1 kiyohara void *scriptaddr;
1143 1.1 kiyohara u_char *data;
1144 1.1 kiyohara const int clock_div = 3; /* 53c810 */
1145 1.1 kiyohara
1146 1.1 kiyohara slot = PCISlotnum(bus, dev, func);
1147 1.1 kiyohara if (slot == -1)
1148 1.1 kiyohara return ENOENT;
1149 1.1 kiyohara
1150 1.1 kiyohara addr = PCIAddress(slot, 1, PCI_MAPREG_TYPE_MEM);
1151 1.1 kiyohara if (addr == 0xffffffff)
1152 1.1 kiyohara return EINVAL;
1153 1.1 kiyohara enablePCI(slot, 0, 1, 1);
1154 1.1 kiyohara
1155 1.1 kiyohara script = ALLOC(uint32_t, SIOP_SCRIPT_SIZE);
1156 1.1 kiyohara if (script == NULL)
1157 1.1 kiyohara return ENOMEM;
1158 1.1 kiyohara scriptaddr = (void *)local_to_PCI((u_long)script);
1159 1.1 kiyohara cmd = ALLOC(struct scsipi_generic, SIOP_SCSI_COMMAND_SIZE);
1160 1.1 kiyohara if (cmd == NULL)
1161 1.1 kiyohara return ENOMEM;
1162 1.1 kiyohara sense = ALLOC(struct scsi_request_sense, SIOP_SCSI_COMMAND_SIZE);
1163 1.1 kiyohara if (sense == NULL)
1164 1.1 kiyohara return ENOMEM;
1165 1.1 kiyohara data = ALLOC(u_char, SIOP_SCSI_DATA_SIZE);
1166 1.1 kiyohara if (data == NULL)
1167 1.1 kiyohara return ENOMEM;
1168 1.1 kiyohara xfer = ALLOC(struct siop_xfer, sizeof(struct siop_xfer));
1169 1.1 kiyohara if (xfer == NULL)
1170 1.1 kiyohara return ENOMEM;
1171 1.1 kiyohara siop_xfer_setup(xfer, scriptaddr);
1172 1.1 kiyohara
1173 1.1 kiyohara id = readb(addr + SIOP_SCID) & SCID_ENCID_MASK;
1174 1.1 kiyohara
1175 1.1 kiyohara /* reset bus */
1176 1.1 kiyohara reg = readb(addr + SIOP_SCNTL1);
1177 1.1 kiyohara writeb(addr + SIOP_SCNTL1, reg | SCNTL1_RST);
1178 1.1 kiyohara delay(100);
1179 1.1 kiyohara writeb(addr + SIOP_SCNTL1, reg);
1180 1.1 kiyohara
1181 1.1 kiyohara /* reset the chip */
1182 1.1 kiyohara writeb(addr + SIOP_ISTAT, ISTAT_SRST);
1183 1.1 kiyohara delay(1000);
1184 1.1 kiyohara writeb(addr + SIOP_ISTAT, 0);
1185 1.1 kiyohara
1186 1.1 kiyohara /* init registers */
1187 1.1 kiyohara writeb(addr + SIOP_SCNTL0, SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP);
1188 1.1 kiyohara writeb(addr + SIOP_SCNTL1, 0);
1189 1.1 kiyohara writeb(addr + SIOP_SCNTL3, clock_div);
1190 1.1 kiyohara writeb(addr + SIOP_SXFER, 0);
1191 1.1 kiyohara writeb(addr + SIOP_DIEN, 0xff);
1192 1.1 kiyohara writeb(addr + SIOP_SIEN0, 0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL));
1193 1.1 kiyohara writeb(addr + SIOP_SIEN1, 0xff & ~(SIEN1_HTH | SIEN1_GEN));
1194 1.1 kiyohara writeb(addr + SIOP_STEST2, 0);
1195 1.1 kiyohara writeb(addr + SIOP_STEST3, STEST3_TE);
1196 1.1 kiyohara writeb(addr + SIOP_STIME0, (0xb << STIME0_SEL_SHIFT));
1197 1.1 kiyohara writeb(addr + SIOP_SCID, id | SCID_RRE);
1198 1.1 kiyohara writeb(addr + SIOP_RESPID0, 1 << id);
1199 1.1 kiyohara writeb(addr + SIOP_DCNTL, DCNTL_COM);
1200 1.1 kiyohara
1201 1.1 kiyohara /* BeBox uses PCIC */
1202 1.1 kiyohara writeb(addr + SIOP_STEST1, STEST1_SCLK);
1203 1.1 kiyohara
1204 1.1 kiyohara siop_pci_reset(addr);
1205 1.1 kiyohara
1206 1.1 kiyohara /* copy and patch the script */
1207 1.1 kiyohara for (i = 0; i < __arraycount(siop_script); i++)
1208 1.1 kiyohara script[i] = htoc32(siop_script[i]);
1209 1.1 kiyohara for (i = 0; i < __arraycount(E_abs_msgin_Used); i++)
1210 1.1 kiyohara script[E_abs_msgin_Used[i]] =
1211 1.1 kiyohara htoc32(scriptaddr + Ent_msgin_space);
1212 1.1 kiyohara
1213 1.1 kiyohara /* start script */
1214 1.1 kiyohara _wbinv((u_long)script, SIOP_SCRIPT_SIZE);
1215 1.1 kiyohara writel(addr + SIOP_DSP, (int)scriptaddr + Ent_reselect);
1216 1.1 kiyohara
1217 1.1 kiyohara memset(&tmp, 0, sizeof(tmp));
1218 1.1 kiyohara tmp.id = id;
1219 1.1 kiyohara tmp.clock_div = clock_div;
1220 1.1 kiyohara tmp.addr = addr;
1221 1.1 kiyohara tmp.script = script;
1222 1.1 kiyohara tmp.xfer = xfer;
1223 1.1 kiyohara tmp.cmd = cmd;
1224 1.1 kiyohara tmp.sense = sense;
1225 1.1 kiyohara tmp.data = data;
1226 1.1 kiyohara tmp.currschedslot = 0;
1227 1.1 kiyohara tmp.sel_t = -1;
1228 1.1 kiyohara
1229 1.1 kiyohara if (scsi_probe(&tmp) == 0)
1230 1.1 kiyohara return ENXIO;
1231 1.1 kiyohara adapt = tmp;
1232 1.1 kiyohara return 0;
1233 1.1 kiyohara }
1234