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