siop.c revision 1.3 1 1.3 kiyohara /* $NetBSD: siop.c,v 1.3 2013/01/03 14:03:39 kiyohara 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 ALLOC(T, A) \
37 1.1 kiyohara (T *)(((uint32_t)alloc(sizeof(T) + (A)) + (A)) & ~((A) - 1))
38 1.1 kiyohara #define VTOPHYS(va) (uint32_t)(va)
39 1.1 kiyohara #define DEVTOV(pa) (uint32_t)(pa)
40 1.1 kiyohara #define wbinv(adr, siz) _wbinv(VTOPHYS(adr), (uint32_t)(siz))
41 1.1 kiyohara #define inv(adr, siz) _inv(VTOPHYS(adr), (uint32_t)(siz))
42 1.1 kiyohara
43 1.1 kiyohara /* 53c810 supports little endian */
44 1.1 kiyohara #define htoc32(x) htole32(x)
45 1.1 kiyohara #define ctoh32(x) le32toh(x)
46 1.1 kiyohara
47 1.1 kiyohara static void siop_pci_reset(int);
48 1.1 kiyohara
49 1.1 kiyohara static void siop_setuptables(struct siop_adapter *, struct siop_xfer *,
50 1.1 kiyohara struct scsi_xfer *);
51 1.1 kiyohara static void siop_ma(struct siop_adapter *, struct scsi_xfer *);
52 1.1 kiyohara static void siop_sdp(struct siop_adapter *, struct siop_xfer *,
53 1.1 kiyohara struct scsi_xfer *, int);
54 1.1 kiyohara static void siop_update_resid(struct siop_adapter *, struct siop_xfer *,
55 1.1 kiyohara struct scsi_xfer *, int);
56 1.1 kiyohara
57 1.1 kiyohara static int siop_intr(struct siop_adapter *);
58 1.1 kiyohara static void siop_scsicmd_end(struct siop_adapter *, struct scsi_xfer *);
59 1.1 kiyohara static int siop_scsi_request(struct siop_adapter *, struct scsi_xfer *);
60 1.1 kiyohara static void siop_start(struct siop_adapter *, struct scsi_xfer *);
61 1.1 kiyohara static void siop_xfer_setup(struct siop_xfer *, void *);
62 1.1 kiyohara
63 1.1 kiyohara static int siop_add_reselsw(struct siop_adapter *, int, int);
64 1.1 kiyohara static void siop_update_scntl3(struct siop_adapter *, int, int);
65 1.1 kiyohara
66 1.1 kiyohara static int _scsi_inquire(struct siop_adapter *, int, int, int, char *);
67 1.1 kiyohara static void scsi_request_sense(struct siop_adapter *, struct scsi_xfer *);
68 1.1 kiyohara static int scsi_interpret_sense(struct siop_adapter *, struct scsi_xfer *);
69 1.1 kiyohara static int scsi_probe(struct siop_adapter *);
70 1.1 kiyohara
71 1.1 kiyohara static struct siop_adapter adapt;
72 1.1 kiyohara
73 1.1 kiyohara
74 1.1 kiyohara static void
75 1.1 kiyohara siop_pci_reset(int addr)
76 1.1 kiyohara {
77 1.1 kiyohara int dmode, ctest5;
78 1.1 kiyohara const int maxburst = 4; /* 53c810 */
79 1.1 kiyohara
80 1.1 kiyohara dmode = readb(addr + SIOP_DMODE);
81 1.1 kiyohara
82 1.1 kiyohara ctest5 = readb(addr + SIOP_CTEST5);
83 1.1 kiyohara writeb(addr + SIOP_CTEST4, readb(addr + SIOP_CTEST4) & ~CTEST4_BDIS);
84 1.1 kiyohara ctest5 &= ~CTEST5_BBCK;
85 1.1 kiyohara ctest5 |= (maxburst - 1) & CTEST5_BBCK;
86 1.1 kiyohara writeb(addr + SIOP_CTEST5, ctest5);
87 1.1 kiyohara
88 1.1 kiyohara dmode |= DMODE_ERL;
89 1.1 kiyohara dmode &= ~DMODE_BL_MASK;
90 1.1 kiyohara dmode |= ((maxburst - 1) << DMODE_BL_SHIFT) & DMODE_BL_MASK;
91 1.1 kiyohara writeb(addr + SIOP_DMODE, dmode);
92 1.1 kiyohara }
93 1.1 kiyohara
94 1.1 kiyohara
95 1.1 kiyohara static void
96 1.1 kiyohara siop_setuptables(struct siop_adapter *adp, struct siop_xfer *xfer,
97 1.1 kiyohara struct scsi_xfer *xs)
98 1.1 kiyohara {
99 1.1 kiyohara int msgoffset = 1;
100 1.1 kiyohara
101 1.1 kiyohara xfer->siop_tables.id =
102 1.1 kiyohara htoc32((adp->clock_div << 24) | (xs->target << 16));
103 1.1 kiyohara memset(xfer->siop_tables.msg_out, 0, sizeof(xfer->siop_tables.msg_out));
104 1.1 kiyohara /* request sense doesn't disconnect */
105 1.1 kiyohara if (xs->cmd->opcode == SCSI_REQUEST_SENSE)
106 1.1 kiyohara xfer->siop_tables.msg_out[0] = MSG_IDENTIFY(xs->lun, 0);
107 1.1 kiyohara else
108 1.1 kiyohara xfer->siop_tables.msg_out[0] = MSG_IDENTIFY(xs->lun, 1);
109 1.1 kiyohara
110 1.1 kiyohara xfer->siop_tables.t_msgout.count = htoc32(msgoffset);
111 1.1 kiyohara xfer->siop_tables.status =
112 1.1 kiyohara htoc32(SCSI_SIOP_NOSTATUS); /* set invalid status */
113 1.1 kiyohara
114 1.1 kiyohara xfer->siop_tables.cmd.count = htoc32(xs->cmdlen);
115 1.1 kiyohara xfer->siop_tables.cmd.addr = htoc32(local_to_PCI((u_long)xs->cmd));
116 1.1 kiyohara if (xs->datalen != 0) {
117 1.1 kiyohara xfer->siop_tables.data[0].count = htoc32(xs->datalen);
118 1.1 kiyohara xfer->siop_tables.data[0].addr =
119 1.1 kiyohara htoc32(local_to_PCI((u_long)xs->data));
120 1.1 kiyohara }
121 1.1 kiyohara }
122 1.1 kiyohara
123 1.1 kiyohara static void
124 1.1 kiyohara siop_ma(struct siop_adapter *adp, struct scsi_xfer *xs)
125 1.1 kiyohara {
126 1.1 kiyohara int offset, dbc;
127 1.1 kiyohara
128 1.1 kiyohara /*
129 1.1 kiyohara * compute how much of the current table didn't get handled when
130 1.1 kiyohara * a phase mismatch occurs
131 1.1 kiyohara */
132 1.1 kiyohara if (xs->datalen == 0)
133 1.1 kiyohara return; /* no valid data transfer */
134 1.1 kiyohara
135 1.1 kiyohara offset = readb(adp->addr + SIOP_SCRATCHA + 1);
136 1.1 kiyohara if (offset >= SIOP_NSG) {
137 1.1 kiyohara printf("bad offset in siop_sdp (%d)\n", offset);
138 1.1 kiyohara return;
139 1.1 kiyohara }
140 1.1 kiyohara dbc = readl(adp->addr + SIOP_DBC) & 0x00ffffff;
141 1.1 kiyohara xs->resid = dbc;
142 1.1 kiyohara }
143 1.1 kiyohara
144 1.1 kiyohara static void
145 1.1 kiyohara siop_sdp(struct siop_adapter *adp, struct siop_xfer *xfer, struct scsi_xfer *xs,
146 1.1 kiyohara int offset)
147 1.1 kiyohara {
148 1.1 kiyohara
149 1.1 kiyohara if (xs->datalen == 0)
150 1.1 kiyohara return; /* no data pointers to save */
151 1.1 kiyohara
152 1.1 kiyohara /*
153 1.1 kiyohara * offset == SIOP_NSG may be a valid condition if we get a Save data
154 1.1 kiyohara * pointer when the xfer is done. Just ignore the Save data pointer
155 1.1 kiyohara * in this case
156 1.1 kiyohara */
157 1.1 kiyohara if (offset == SIOP_NSG)
158 1.1 kiyohara return;
159 1.1 kiyohara /*
160 1.1 kiyohara * Save data pointer. We do this by adjusting the tables to point
161 1.1 kiyohara * at the begginning of the data not yet transfered.
162 1.1 kiyohara * offset points to the first table with untransfered data.
163 1.1 kiyohara */
164 1.1 kiyohara
165 1.1 kiyohara /*
166 1.1 kiyohara * before doing that we decrease resid from the ammount of data which
167 1.1 kiyohara * has been transfered.
168 1.1 kiyohara */
169 1.1 kiyohara siop_update_resid(adp, xfer, xs, offset);
170 1.1 kiyohara
171 1.1 kiyohara #if 0
172 1.1 kiyohara /*
173 1.1 kiyohara * First let see if we have a resid from a phase mismatch. If so,
174 1.1 kiyohara * we have to adjst the table at offset to remove transfered data.
175 1.1 kiyohara */
176 1.1 kiyohara if (siop_cmd->flags & CMDFL_RESID) {
177 1.1 kiyohara scr_table_t *table;
178 1.1 kiyohara
179 1.1 kiyohara siop_cmd->flags &= ~CMDFL_RESID;
180 1.1 kiyohara table = &xfer->siop_tables.data[offset];
181 1.1 kiyohara /* "cut" already transfered data from this table */
182 1.1 kiyohara table->addr =
183 1.1 kiyohara htoc32(ctoh32(table->addr) + ctoh32(table->count) -
184 1.1 kiyohara siop_cmd->resid);
185 1.1 kiyohara table->count = htoc32(siop_cmd->resid);
186 1.1 kiyohara }
187 1.1 kiyohara #endif
188 1.1 kiyohara
189 1.1 kiyohara /*
190 1.1 kiyohara * now we can remove entries which have been transfered.
191 1.1 kiyohara * We just move the entries with data left at the beggining of the
192 1.1 kiyohara * tables
193 1.1 kiyohara */
194 1.1 kiyohara memmove(xfer->siop_tables.data, &xfer->siop_tables.data[offset],
195 1.1 kiyohara (SIOP_NSG - offset) * sizeof(scr_table_t));
196 1.1 kiyohara }
197 1.1 kiyohara
198 1.1 kiyohara static void
199 1.1 kiyohara siop_update_resid(struct siop_adapter *adp, struct siop_xfer *xfer,
200 1.1 kiyohara struct scsi_xfer *xs, int offset)
201 1.1 kiyohara {
202 1.1 kiyohara int i;
203 1.1 kiyohara
204 1.1 kiyohara if (xs->datalen == 0)
205 1.1 kiyohara return; /* no data to transfer */
206 1.1 kiyohara
207 1.1 kiyohara /*
208 1.1 kiyohara * update resid. First account for the table entries which have
209 1.1 kiyohara * been fully completed.
210 1.1 kiyohara */
211 1.1 kiyohara for (i = 0; i < offset; i++)
212 1.1 kiyohara xs->resid -= ctoh32(xfer->siop_tables.data[i].count);
213 1.1 kiyohara #if 0
214 1.1 kiyohara /*
215 1.1 kiyohara * if CMDFL_RESID is set, the last table (pointed by offset) is a
216 1.1 kiyohara * partial transfers. If not, offset points to the entry folloing
217 1.1 kiyohara * the last full transfer.
218 1.1 kiyohara */
219 1.1 kiyohara if (siop_cmd->flags & CMDFL_RESID) {
220 1.1 kiyohara scr_table_t *table = &xfer->siop_tables.data[offset];
221 1.1 kiyohara
222 1.1 kiyohara xs->resid -= ctoh32(table->count) - xs->resid;
223 1.1 kiyohara }
224 1.1 kiyohara #endif
225 1.1 kiyohara }
226 1.1 kiyohara
227 1.1 kiyohara
228 1.1 kiyohara #define CALL_SCRIPT(ent) writel(adp->addr + SIOP_DSP, scriptaddr + ent);
229 1.1 kiyohara
230 1.1 kiyohara static int
231 1.1 kiyohara siop_intr(struct siop_adapter *adp)
232 1.1 kiyohara {
233 1.1 kiyohara struct siop_xfer *siop_xfer = NULL;
234 1.1 kiyohara struct scsi_xfer *xs = NULL;
235 1.1 kiyohara u_long scriptaddr = local_to_PCI((u_long)adp->script);
236 1.1 kiyohara int offset, target, lun, tag, restart = 0, need_reset = 0;
237 1.1 kiyohara uint32_t dsa, irqcode;
238 1.1 kiyohara uint16_t sist;
239 1.1 kiyohara uint8_t dstat, sstat1, istat;
240 1.1 kiyohara
241 1.1 kiyohara istat = readb(adp->addr + SIOP_ISTAT);
242 1.1 kiyohara if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0)
243 1.1 kiyohara return 0;
244 1.1 kiyohara if (istat & ISTAT_INTF) {
245 1.1 kiyohara printf("INTRF\n");
246 1.1 kiyohara writeb(adp->addr + SIOP_ISTAT, ISTAT_INTF);
247 1.1 kiyohara }
248 1.1 kiyohara if ((istat & (ISTAT_DIP | ISTAT_SIP | ISTAT_ABRT)) ==
249 1.1 kiyohara (ISTAT_DIP | ISTAT_ABRT))
250 1.1 kiyohara /* clear abort */
251 1.1 kiyohara writeb(adp->addr + SIOP_ISTAT, 0);
252 1.1 kiyohara /* use DSA to find the current siop_cmd */
253 1.1 kiyohara dsa = readl(adp->addr + SIOP_DSA);
254 1.1 kiyohara if (dsa >= local_to_PCI((u_long)adp->xfer) &&
255 1.1 kiyohara dsa < local_to_PCI((u_long)adp->xfer) + SIOP_TABLE_SIZE) {
256 1.1 kiyohara dsa -= local_to_PCI((u_long)adp->xfer);
257 1.1 kiyohara siop_xfer = adp->xfer;
258 1.1 kiyohara _inv((u_long)siop_xfer, sizeof(*siop_xfer));
259 1.1 kiyohara
260 1.1 kiyohara xs = adp->xs;
261 1.1 kiyohara }
262 1.1 kiyohara
263 1.1 kiyohara if (istat & ISTAT_DIP)
264 1.1 kiyohara dstat = readb(adp->addr + SIOP_DSTAT);
265 1.1 kiyohara if (istat & ISTAT_SIP) {
266 1.1 kiyohara if (istat & ISTAT_DIP)
267 1.1 kiyohara delay(10);
268 1.1 kiyohara /*
269 1.1 kiyohara * Can't read sist0 & sist1 independently, or we have to
270 1.1 kiyohara * insert delay
271 1.1 kiyohara */
272 1.1 kiyohara sist = readw(adp->addr + SIOP_SIST0);
273 1.1 kiyohara sstat1 = readb(adp->addr + SIOP_SSTAT1);
274 1.1 kiyohara
275 1.1 kiyohara if ((sist & SIST0_MA) && need_reset == 0) {
276 1.1 kiyohara if (siop_xfer) {
277 1.1 kiyohara int scratcha0;
278 1.1 kiyohara
279 1.1 kiyohara dstat = readb(adp->addr + SIOP_DSTAT);
280 1.1 kiyohara /*
281 1.1 kiyohara * first restore DSA, in case we were in a S/G
282 1.1 kiyohara * operation.
283 1.1 kiyohara */
284 1.1 kiyohara writel(adp->addr + SIOP_DSA,
285 1.1 kiyohara local_to_PCI((u_long)siop_xfer));
286 1.1 kiyohara scratcha0 = readb(adp->addr + SIOP_SCRATCHA);
287 1.1 kiyohara switch (sstat1 & SSTAT1_PHASE_MASK) {
288 1.1 kiyohara case SSTAT1_PHASE_STATUS:
289 1.1 kiyohara /*
290 1.1 kiyohara * previous phase may be aborted for any reason
291 1.1 kiyohara * ( for example, the target has less data to
292 1.1 kiyohara * transfer than requested). Compute resid and
293 1.1 kiyohara * just go to status, the command should
294 1.1 kiyohara * terminate.
295 1.1 kiyohara */
296 1.1 kiyohara if (scratcha0 & A_flag_data)
297 1.1 kiyohara siop_ma(adp, xs);
298 1.1 kiyohara else if ((dstat & DSTAT_DFE) == 0)
299 1.1 kiyohara printf("PHASE STATUS: siop_clearfifo...\n");
300 1.1 kiyohara // siop_clearfifo(adp);
301 1.1 kiyohara CALL_SCRIPT(Ent_status);
302 1.1 kiyohara return 1;
303 1.1 kiyohara case SSTAT1_PHASE_MSGIN:
304 1.1 kiyohara /*
305 1.1 kiyohara * target may be ready to disconnect
306 1.1 kiyohara * Compute resid which would be used later
307 1.1 kiyohara * if a save data pointer is needed.
308 1.1 kiyohara */
309 1.1 kiyohara if (scratcha0 & A_flag_data)
310 1.1 kiyohara siop_ma(adp, xs);
311 1.1 kiyohara else if ((dstat & DSTAT_DFE) == 0)
312 1.1 kiyohara printf("PHASE MSGIN: siop_clearfifo...\n");
313 1.1 kiyohara // siop_clearfifo(adp);
314 1.1 kiyohara writeb(adp->addr + SIOP_SCRATCHA,
315 1.1 kiyohara scratcha0 & ~A_flag_data);
316 1.1 kiyohara CALL_SCRIPT(Ent_msgin);
317 1.1 kiyohara return 1;
318 1.1 kiyohara }
319 1.1 kiyohara printf("unexpected phase mismatch %d\n",
320 1.1 kiyohara sstat1 & SSTAT1_PHASE_MASK);
321 1.1 kiyohara } else
322 1.1 kiyohara printf("phase mismatch without command\n");
323 1.1 kiyohara need_reset = 1;
324 1.1 kiyohara }
325 1.1 kiyohara if (sist & (SIST1_STO << 8)) {
326 1.1 kiyohara /* selection time out, assume there's no device here */
327 1.1 kiyohara if (siop_xfer) {
328 1.1 kiyohara xs->error = XS_SELTIMEOUT;
329 1.1 kiyohara goto end;
330 1.1 kiyohara } else
331 1.1 kiyohara printf("selection timeout without command\n");
332 1.1 kiyohara }
333 1.1 kiyohara
334 1.1 kiyohara /* Else it's an unhandled exception (for now). */
335 1.1 kiyohara printf("unhandled scsi interrupt,"
336 1.1 kiyohara " sist=0x%x sstat1=0x%x DSA=0x%x DSP=0x%lx\n",
337 1.1 kiyohara sist, sstat1, dsa,
338 1.1 kiyohara readl(adp->addr + SIOP_DSP) - scriptaddr);
339 1.1 kiyohara if (siop_xfer) {
340 1.1 kiyohara xs->error = XS_SELTIMEOUT;
341 1.1 kiyohara goto end;
342 1.1 kiyohara }
343 1.1 kiyohara need_reset = 1;
344 1.1 kiyohara }
345 1.1 kiyohara if (need_reset) {
346 1.1 kiyohara reset:
347 1.1 kiyohara printf("XXXXX: fatal error, need reset the bus...\n");
348 1.1 kiyohara return 1;
349 1.1 kiyohara }
350 1.1 kiyohara
351 1.1 kiyohara //scintr:
352 1.1 kiyohara if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */
353 1.1 kiyohara irqcode = readl(adp->addr + SIOP_DSPS);
354 1.1 kiyohara /*
355 1.1 kiyohara * no command, or an inactive command is only valid for a
356 1.1 kiyohara * reselect interrupt
357 1.1 kiyohara */
358 1.1 kiyohara if ((irqcode & 0x80) == 0) {
359 1.1 kiyohara if (siop_xfer == NULL) {
360 1.1 kiyohara printf(
361 1.1 kiyohara "script interrupt 0x%x with invalid DSA\n",
362 1.1 kiyohara irqcode);
363 1.1 kiyohara goto reset;
364 1.1 kiyohara }
365 1.1 kiyohara }
366 1.1 kiyohara switch(irqcode) {
367 1.1 kiyohara case A_int_err:
368 1.1 kiyohara printf("error, DSP=0x%lx\n",
369 1.1 kiyohara readl(adp->addr + SIOP_DSP) - scriptaddr);
370 1.1 kiyohara if (xs) {
371 1.1 kiyohara xs->error = XS_SELTIMEOUT;
372 1.1 kiyohara goto end;
373 1.1 kiyohara } else {
374 1.1 kiyohara goto reset;
375 1.1 kiyohara }
376 1.1 kiyohara case A_int_reseltarg:
377 1.1 kiyohara printf("reselect with invalid target\n");
378 1.1 kiyohara goto reset;
379 1.1 kiyohara case A_int_resellun:
380 1.1 kiyohara target = readb(adp->addr + SIOP_SCRATCHA) & 0xf;
381 1.1 kiyohara lun = readb(adp->addr + SIOP_SCRATCHA + 1);
382 1.1 kiyohara tag = readb(adp->addr + SIOP_SCRATCHA + 2);
383 1.1 kiyohara if (target != adp->xs->target ||
384 1.1 kiyohara lun != adp->xs->lun ||
385 1.1 kiyohara tag != 0) {
386 1.1 kiyohara printf("unknwon resellun:"
387 1.1 kiyohara " target %d lun %d tag %d\n",
388 1.1 kiyohara target, lun, tag);
389 1.1 kiyohara goto reset;
390 1.1 kiyohara }
391 1.1 kiyohara siop_xfer = adp->xfer;
392 1.1 kiyohara dsa = local_to_PCI((u_long)siop_xfer);
393 1.1 kiyohara writel(adp->addr + SIOP_DSP,
394 1.1 kiyohara dsa + sizeof(struct siop_common_xfer) +
395 1.1 kiyohara Ent_ldsa_reload_dsa);
396 1.1 kiyohara _wbinv((u_long)siop_xfer, sizeof(*siop_xfer));
397 1.1 kiyohara return 1;
398 1.1 kiyohara case A_int_reseltag:
399 1.1 kiyohara printf("reselect with invalid tag\n");
400 1.1 kiyohara goto reset;
401 1.1 kiyohara case A_int_disc:
402 1.1 kiyohara offset = readb(adp->addr + SIOP_SCRATCHA + 1);
403 1.1 kiyohara siop_sdp(adp, siop_xfer, xs, offset);
404 1.1 kiyohara #if 0
405 1.1 kiyohara /* we start again with no offset */
406 1.1 kiyohara siop_cmd->saved_offset = SIOP_NOOFFSET;
407 1.1 kiyohara #endif
408 1.1 kiyohara _wbinv((u_long)siop_xfer, sizeof(*siop_xfer));
409 1.1 kiyohara CALL_SCRIPT(Ent_script_sched);
410 1.1 kiyohara return 1;
411 1.1 kiyohara case A_int_resfail:
412 1.1 kiyohara printf("reselect failed\n");
413 1.1 kiyohara return 1;
414 1.1 kiyohara case A_int_done:
415 1.1 kiyohara if (xs == NULL) {
416 1.1 kiyohara printf("done without command, DSA=0x%lx\n",
417 1.1 kiyohara local_to_PCI((u_long)adp->xfer));
418 1.1 kiyohara return 1;
419 1.1 kiyohara }
420 1.1 kiyohara /* update resid. */
421 1.1 kiyohara offset = readb(adp->addr + SIOP_SCRATCHA + 1);
422 1.1 kiyohara #if 0
423 1.1 kiyohara /*
424 1.1 kiyohara * if we got a disconnect between the last data phase
425 1.1 kiyohara * and the status phase, offset will be 0. In this
426 1.1 kiyohara * case, siop_cmd->saved_offset will have the proper
427 1.1 kiyohara * value if it got updated by the controller
428 1.1 kiyohara */
429 1.1 kiyohara if (offset == 0 &&
430 1.1 kiyohara siop_cmd->saved_offset != SIOP_NOOFFSET)
431 1.1 kiyohara offset = siop_cmd->saved_offset;
432 1.1 kiyohara #endif
433 1.1 kiyohara siop_update_resid(adp, siop_xfer, xs, offset);
434 1.1 kiyohara goto end;
435 1.1 kiyohara default:
436 1.1 kiyohara printf("unknown irqcode %x\n", irqcode);
437 1.1 kiyohara if (xs) {
438 1.1 kiyohara xs->error = XS_SELTIMEOUT;
439 1.1 kiyohara goto end;
440 1.1 kiyohara }
441 1.1 kiyohara goto reset;
442 1.1 kiyohara }
443 1.1 kiyohara return 1;
444 1.1 kiyohara }
445 1.1 kiyohara /* We just should't get there */
446 1.1 kiyohara panic("siop_intr: I shouldn't be there !");
447 1.1 kiyohara
448 1.1 kiyohara return 1;
449 1.1 kiyohara
450 1.1 kiyohara end:
451 1.1 kiyohara /*
452 1.1 kiyohara * restart the script now if command completed properly
453 1.1 kiyohara * Otherwise wait for siop_scsicmd_end(), we may need to cleanup the
454 1.1 kiyohara * queue
455 1.1 kiyohara */
456 1.1 kiyohara xs->status = ctoh32(siop_xfer->siop_tables.status);
457 1.1 kiyohara if (xs->status == SCSI_OK)
458 1.1 kiyohara writel(adp->addr + SIOP_DSP, scriptaddr + Ent_script_sched);
459 1.1 kiyohara else
460 1.1 kiyohara restart = 1;
461 1.1 kiyohara siop_scsicmd_end(adp, xs);
462 1.1 kiyohara if (restart)
463 1.1 kiyohara writel(adp->addr + SIOP_DSP, scriptaddr + Ent_script_sched);
464 1.1 kiyohara
465 1.1 kiyohara return 1;
466 1.1 kiyohara }
467 1.1 kiyohara
468 1.1 kiyohara static void
469 1.1 kiyohara siop_scsicmd_end(struct siop_adapter *adp, struct scsi_xfer *xs)
470 1.1 kiyohara {
471 1.1 kiyohara
472 1.1 kiyohara switch(xs->status) {
473 1.1 kiyohara case SCSI_OK:
474 1.1 kiyohara xs->error = XS_NOERROR;
475 1.1 kiyohara break;
476 1.1 kiyohara case SCSI_BUSY:
477 1.1 kiyohara case SCSI_CHECK:
478 1.1 kiyohara case SCSI_QUEUE_FULL:
479 1.1 kiyohara xs->error = XS_BUSY;
480 1.1 kiyohara break;
481 1.1 kiyohara case SCSI_SIOP_NOCHECK:
482 1.1 kiyohara /*
483 1.1 kiyohara * don't check status, xs->error is already valid
484 1.1 kiyohara */
485 1.1 kiyohara break;
486 1.1 kiyohara case SCSI_SIOP_NOSTATUS:
487 1.1 kiyohara /*
488 1.1 kiyohara * the status byte was not updated, cmd was
489 1.1 kiyohara * aborted
490 1.1 kiyohara */
491 1.1 kiyohara xs->error = XS_SELTIMEOUT;
492 1.1 kiyohara break;
493 1.1 kiyohara default:
494 1.1 kiyohara printf("invalid status code %d\n", xs->status);
495 1.1 kiyohara xs->error = XS_DRIVER_STUFFUP;
496 1.1 kiyohara }
497 1.1 kiyohara _inv((u_long)xs->cmd, xs->cmdlen);
498 1.1 kiyohara if (xs->datalen != 0)
499 1.1 kiyohara _inv((u_long)xs->data, xs->datalen);
500 1.1 kiyohara xs->xs_status = XS_STS_DONE;
501 1.1 kiyohara }
502 1.1 kiyohara
503 1.1 kiyohara static int
504 1.1 kiyohara siop_scsi_request(struct siop_adapter *adp, struct scsi_xfer *xs)
505 1.1 kiyohara {
506 1.1 kiyohara void *xfer = adp->xfer;
507 1.1 kiyohara int timo, error;
508 1.1 kiyohara
509 1.1 kiyohara if (adp->sel_t != xs->target) {
510 1.1 kiyohara const int free_lo = __arraycount(siop_script);
511 1.1 kiyohara int i;
512 1.1 kiyohara void *scriptaddr = (void *)local_to_PCI((u_long)adp->script);
513 1.1 kiyohara
514 1.1 kiyohara if (adp->sel_t != -1)
515 1.1 kiyohara adp->script[Ent_resel_targ0 / 4 + adp->sel_t * 2] =
516 1.1 kiyohara htoc32(0x800c00ff);
517 1.1 kiyohara
518 1.1 kiyohara for (i = 0; i < __arraycount(lun_switch); i++)
519 1.1 kiyohara adp->script[free_lo + i] = htoc32(lun_switch[i]);
520 1.1 kiyohara adp->script[free_lo + E_abs_lunsw_return_Used[0]] =
521 1.1 kiyohara htoc32(scriptaddr + Ent_lunsw_return);
522 1.1 kiyohara
523 1.1 kiyohara siop_add_reselsw(adp, xs->target, free_lo);
524 1.1 kiyohara
525 1.1 kiyohara adp->sel_t = xs->target;
526 1.1 kiyohara }
527 1.1 kiyohara
528 1.1 kiyohara restart:
529 1.1 kiyohara
530 1.1 kiyohara siop_setuptables(adp, xfer, xs);
531 1.1 kiyohara
532 1.1 kiyohara /* load the DMA maps */
533 1.1 kiyohara if (xs->datalen != 0)
534 1.1 kiyohara _inv((u_long)xs->data, xs->datalen);
535 1.1 kiyohara _wbinv((u_long)xs->cmd, xs->cmdlen);
536 1.1 kiyohara
537 1.1 kiyohara _wbinv((u_long)xfer, sizeof(struct siop_xfer));
538 1.1 kiyohara siop_start(adp, xs);
539 1.1 kiyohara
540 1.1 kiyohara adp->xs = xs;
541 1.1 kiyohara timo = 0;
542 1.1 kiyohara while (!(xs->xs_status & XS_STS_DONE)) {
543 1.1 kiyohara delay(1000);
544 1.1 kiyohara siop_intr(adp);
545 1.1 kiyohara
546 1.1 kiyohara if (timo++ > 3000) { /* XXXX: 3sec */
547 1.1 kiyohara printf("%s: timeout\n", __func__);
548 1.1 kiyohara return ETIMEDOUT;
549 1.1 kiyohara }
550 1.1 kiyohara }
551 1.1 kiyohara
552 1.1 kiyohara if (xs->error != XS_NOERROR) {
553 1.1 kiyohara if (xs->error == XS_BUSY || xs->status == SCSI_CHECK)
554 1.1 kiyohara scsi_request_sense(adp, xs);
555 1.1 kiyohara
556 1.1 kiyohara switch (xs->error) {
557 1.1 kiyohara case XS_SENSE:
558 1.1 kiyohara case XS_SHORTSENSE:
559 1.1 kiyohara error = scsi_interpret_sense(adp, xs);
560 1.1 kiyohara break;
561 1.1 kiyohara case XS_RESOURCE_SHORTAGE:
562 1.1 kiyohara printf("adapter resource shortage\n");
563 1.1 kiyohara
564 1.1 kiyohara /* FALLTHROUGH */
565 1.1 kiyohara case XS_BUSY:
566 1.1 kiyohara error = EBUSY;
567 1.1 kiyohara break;
568 1.1 kiyohara case XS_REQUEUE:
569 1.1 kiyohara printf("XXXX: requeue...\n");
570 1.1 kiyohara error = ERESTART;
571 1.1 kiyohara break;
572 1.1 kiyohara case XS_SELTIMEOUT:
573 1.1 kiyohara case XS_TIMEOUT:
574 1.1 kiyohara error = EIO;
575 1.1 kiyohara break;
576 1.1 kiyohara case XS_RESET:
577 1.1 kiyohara error = EIO;
578 1.1 kiyohara break;
579 1.1 kiyohara case XS_DRIVER_STUFFUP:
580 1.1 kiyohara printf("generic HBA error\n");
581 1.1 kiyohara error = EIO;
582 1.1 kiyohara break;
583 1.1 kiyohara default:
584 1.1 kiyohara printf("invalid return code from adapter: %d\n",
585 1.1 kiyohara xs->error);
586 1.1 kiyohara error = EIO;
587 1.1 kiyohara break;
588 1.1 kiyohara }
589 1.1 kiyohara if (error == ERESTART) {
590 1.1 kiyohara xs->error = XS_NOERROR;
591 1.1 kiyohara xs->status = SCSI_OK;
592 1.1 kiyohara xs->xs_status &= ~XS_STS_DONE;
593 1.1 kiyohara goto restart;
594 1.1 kiyohara }
595 1.1 kiyohara return error;
596 1.1 kiyohara }
597 1.1 kiyohara return 0;
598 1.1 kiyohara }
599 1.1 kiyohara
600 1.1 kiyohara static void
601 1.1 kiyohara siop_start(struct siop_adapter *adp, struct scsi_xfer *xs)
602 1.1 kiyohara {
603 1.1 kiyohara struct siop_xfer *siop_xfer = adp->xfer;
604 1.1 kiyohara uint32_t dsa, *script = adp->script;
605 1.1 kiyohara int target, lun, slot;
606 1.1 kiyohara void *scriptaddr = (void *)local_to_PCI((u_long)script);
607 1.1 kiyohara const int siop_common_xfer_size = sizeof(struct siop_common_xfer);
608 1.1 kiyohara
609 1.1 kiyohara /*
610 1.1 kiyohara * The queue management here is a bit tricky: the script always looks
611 1.1 kiyohara * at the slot from first to last, so if we always use the first
612 1.1 kiyohara * free slot commands can stay at the tail of the queue ~forever.
613 1.1 kiyohara * The algorithm used here is to restart from the head when we know
614 1.1 kiyohara * that the queue is empty, and only add commands after the last one.
615 1.1 kiyohara * When we're at the end of the queue wait for the script to clear it.
616 1.1 kiyohara * The best thing to do here would be to implement a circular queue,
617 1.1 kiyohara * but using only 53c720 features this can be "interesting".
618 1.1 kiyohara * A mid-way solution could be to implement 2 queues and swap orders.
619 1.1 kiyohara */
620 1.1 kiyohara slot = adp->currschedslot;
621 1.1 kiyohara /*
622 1.1 kiyohara * If the instruction is 0x80000000 (JUMP foo, IF FALSE) the slot is
623 1.1 kiyohara * free. As this is the last used slot, all previous slots are free,
624 1.1 kiyohara * we can restart from 0.
625 1.1 kiyohara */
626 1.1 kiyohara if (ctoh32(script[(Ent_script_sched_slot0 / 4) + slot * 2]) ==
627 1.1 kiyohara 0x80000000) {
628 1.1 kiyohara slot = adp->currschedslot = 0;
629 1.1 kiyohara } else {
630 1.1 kiyohara slot++;
631 1.1 kiyohara }
632 1.1 kiyohara target = xs->target;
633 1.1 kiyohara lun = xs->lun;
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.1 kiyohara /* request sense coudn'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.1 kiyohara * NOTE: If we return ERESTART, we are expected to haved
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.1 kiyohara int error;
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 error = 0;
927 1.1 kiyohara break;
928 1.1 kiyohara case SKEY_NOT_READY:
929 1.1 kiyohara if (adp->sd->sc_flags & FLAGS_REMOVABLE)
930 1.1 kiyohara adp->sd->sc_flags &= ~FLAGS_MEDIA_LOADED;
931 1.1 kiyohara if (sense->asc == 0x3A) {
932 1.1 kiyohara error = ENODEV; /* Medium not present */
933 1.1 kiyohara } else
934 1.1 kiyohara error = EIO;
935 1.1 kiyohara break;
936 1.1 kiyohara case SKEY_ILLEGAL_REQUEST:
937 1.1 kiyohara error = EINVAL;
938 1.1 kiyohara break;
939 1.1 kiyohara case SKEY_UNIT_ATTENTION:
940 1.1 kiyohara if (sense->asc == 0x29 &&
941 1.1 kiyohara sense->ascq == 0x00) {
942 1.1 kiyohara /* device or bus reset */
943 1.1 kiyohara return ERESTART;
944 1.1 kiyohara }
945 1.1 kiyohara if (adp->sd->sc_flags & FLAGS_REMOVABLE)
946 1.1 kiyohara adp->sd->sc_flags &= ~FLAGS_MEDIA_LOADED;
947 1.1 kiyohara if (!(adp->sd->sc_flags & FLAGS_REMOVABLE))
948 1.1 kiyohara return ERESTART;
949 1.1 kiyohara error = EIO;
950 1.1 kiyohara break;
951 1.1 kiyohara case SKEY_DATA_PROTECT:
952 1.1 kiyohara error = EROFS;
953 1.1 kiyohara break;
954 1.1 kiyohara case SKEY_BLANK_CHECK:
955 1.1 kiyohara error = 0;
956 1.1 kiyohara break;
957 1.1 kiyohara case SKEY_ABORTED_COMMAND:
958 1.1 kiyohara break;
959 1.1 kiyohara case SKEY_VOLUME_OVERFLOW:
960 1.1 kiyohara error = ENOSPC;
961 1.1 kiyohara break;
962 1.1 kiyohara default:
963 1.1 kiyohara error = EIO;
964 1.1 kiyohara break;
965 1.1 kiyohara }
966 1.1 kiyohara
967 1.1 kiyohara /* Print brief(er) sense information */
968 1.1 kiyohara printf("%s", error_mes[key - 1]);
969 1.1 kiyohara if ((sense->response_code & SSD_RCODE_VALID) != 0) {
970 1.1 kiyohara switch (key) {
971 1.1 kiyohara case SKEY_NOT_READY:
972 1.1 kiyohara case SKEY_ILLEGAL_REQUEST:
973 1.1 kiyohara case SKEY_UNIT_ATTENTION:
974 1.1 kiyohara case SKEY_DATA_PROTECT:
975 1.1 kiyohara break;
976 1.1 kiyohara case SKEY_BLANK_CHECK:
977 1.1 kiyohara printf(", requested size: %d (decimal)",
978 1.1 kiyohara info);
979 1.1 kiyohara break;
980 1.1 kiyohara case SKEY_ABORTED_COMMAND:
981 1.1 kiyohara printf(", cmd 0x%x, info 0x%x",
982 1.1 kiyohara xs->cmd->opcode, info);
983 1.1 kiyohara break;
984 1.1 kiyohara default:
985 1.1 kiyohara printf(", info = %d (decimal)", info);
986 1.1 kiyohara }
987 1.1 kiyohara }
988 1.1 kiyohara if (sense->extra_len != 0) {
989 1.1 kiyohara int n;
990 1.1 kiyohara printf(", data =");
991 1.1 kiyohara for (n = 0; n < sense->extra_len; n++)
992 1.1 kiyohara printf(" %x", sense->csi[n]);
993 1.1 kiyohara }
994 1.1 kiyohara printf("\n");
995 1.1 kiyohara return error;
996 1.1 kiyohara
997 1.1 kiyohara /*
998 1.1 kiyohara * Some other code, just report it
999 1.1 kiyohara */
1000 1.1 kiyohara default:
1001 1.1 kiyohara printf("Sense Error Code 0x%x",
1002 1.1 kiyohara SSD_RCODE(sense->response_code));
1003 1.1 kiyohara if ((sense->response_code & SSD_RCODE_VALID) != 0) {
1004 1.1 kiyohara struct scsi_sense_data_unextended *usense =
1005 1.1 kiyohara (struct scsi_sense_data_unextended *)sense;
1006 1.1 kiyohara printf(" at block no. %d (decimal)",
1007 1.1 kiyohara _3btol(usense->block));
1008 1.1 kiyohara }
1009 1.1 kiyohara printf("\n");
1010 1.1 kiyohara return EIO;
1011 1.1 kiyohara }
1012 1.1 kiyohara }
1013 1.1 kiyohara
1014 1.1 kiyohara static int
1015 1.1 kiyohara scsi_probe(struct siop_adapter *adp)
1016 1.1 kiyohara {
1017 1.1 kiyohara struct scsipi_inquiry_data *inqbuf;
1018 1.1 kiyohara int found, t, l;
1019 1.1 kiyohara uint8_t device;
1020 1.1 kiyohara char buf[SCSIPI_INQUIRY_LENGTH_SCSI2],
1021 1.1 kiyohara product[sizeof(inqbuf->product) + 1];
1022 1.1 kiyohara
1023 1.1 kiyohara found = 0;
1024 1.1 kiyohara for (t = 0; t < 8; t++) {
1025 1.1 kiyohara if (t == adp->id)
1026 1.1 kiyohara continue;
1027 1.1 kiyohara for (l = 0; l < 8; l++) {
1028 1.1 kiyohara if (_scsi_inquire(adp, t, l, sizeof(buf), buf) != 0)
1029 1.1 kiyohara continue;
1030 1.1 kiyohara
1031 1.1 kiyohara inqbuf = (struct scsipi_inquiry_data *)buf;
1032 1.1 kiyohara device = inqbuf->device & SID_TYPE;
1033 1.1 kiyohara if (device == T_NODEVICE)
1034 1.1 kiyohara continue;
1035 1.1 kiyohara if (device != T_DIRECT &&
1036 1.1 kiyohara device != T_OPTICAL &&
1037 1.1 kiyohara device != T_SIMPLE_DIRECT)
1038 1.1 kiyohara continue;
1039 1.1 kiyohara
1040 1.1 kiyohara memset(product, 0, sizeof(product));
1041 1.1 kiyohara strncpy(product, inqbuf->product, sizeof(product) - 1);
1042 1.3 kiyohara printf("/dev/disk/scsi/0%d%d: <%s>\n", t, l, product);
1043 1.1 kiyohara found++;
1044 1.1 kiyohara }
1045 1.1 kiyohara }
1046 1.1 kiyohara return found;
1047 1.1 kiyohara }
1048 1.1 kiyohara
1049 1.1 kiyohara int
1050 1.1 kiyohara scsi_inquire(struct sd_softc *sd, int buflen, void *buf)
1051 1.1 kiyohara {
1052 1.1 kiyohara struct siop_adapter *adp;
1053 1.1 kiyohara int error;
1054 1.1 kiyohara
1055 1.1 kiyohara if (sd->sc_bus != 0)
1056 1.1 kiyohara return ENOTSUP;
1057 1.1 kiyohara if (adapt.addr == 0)
1058 1.1 kiyohara return ENOENT;
1059 1.1 kiyohara adp = &adapt;
1060 1.1 kiyohara
1061 1.1 kiyohara adp->sd = sd;
1062 1.1 kiyohara error = _scsi_inquire(adp, sd->sc_target, sd->sc_lun, buflen, buf);
1063 1.1 kiyohara adp->sd = NULL;
1064 1.1 kiyohara
1065 1.1 kiyohara return error;
1066 1.1 kiyohara }
1067 1.1 kiyohara
1068 1.1 kiyohara /*
1069 1.1 kiyohara * scsi_mode_sense
1070 1.1 kiyohara * get a sense page from a device
1071 1.1 kiyohara */
1072 1.1 kiyohara
1073 1.1 kiyohara int
1074 1.1 kiyohara scsi_mode_sense(struct sd_softc *sd, int byte2, int page,
1075 1.1 kiyohara struct scsi_mode_parameter_header_6 *data, int len)
1076 1.1 kiyohara {
1077 1.1 kiyohara struct scsi_mode_sense_6 cmd;
1078 1.1 kiyohara
1079 1.1 kiyohara memset(&cmd, 0, sizeof(cmd));
1080 1.1 kiyohara cmd.opcode = SCSI_MODE_SENSE_6;
1081 1.1 kiyohara cmd.byte2 = byte2;
1082 1.1 kiyohara cmd.page = page;
1083 1.1 kiyohara cmd.length = len & 0xff;
1084 1.1 kiyohara
1085 1.1 kiyohara return scsi_command(sd, (void *)&cmd, sizeof(cmd), (void *)data, len);
1086 1.1 kiyohara }
1087 1.1 kiyohara
1088 1.1 kiyohara int
1089 1.1 kiyohara scsi_command(struct sd_softc *sd, void *cmd, int cmdlen, void *data,
1090 1.1 kiyohara int datalen)
1091 1.1 kiyohara {
1092 1.1 kiyohara struct siop_adapter *adp;
1093 1.1 kiyohara struct scsi_xfer xs;
1094 1.1 kiyohara int error;
1095 1.1 kiyohara
1096 1.1 kiyohara if (sd->sc_bus != 0)
1097 1.1 kiyohara return ENOTSUP;
1098 1.1 kiyohara if (adapt.addr == 0)
1099 1.1 kiyohara return ENOENT;
1100 1.1 kiyohara adp = &adapt;
1101 1.1 kiyohara
1102 1.1 kiyohara memcpy(adp->cmd, cmd, cmdlen);
1103 1.1 kiyohara adp->sd = sd;
1104 1.1 kiyohara
1105 1.1 kiyohara memset(&xs, 0, sizeof(xs));
1106 1.1 kiyohara xs.target = sd->sc_target;
1107 1.1 kiyohara xs.lun = sd->sc_lun;
1108 1.1 kiyohara xs.cmdlen = cmdlen;
1109 1.1 kiyohara xs.cmd = adp->cmd;
1110 1.1 kiyohara xs.datalen = datalen;
1111 1.1 kiyohara xs.data = adp->data;
1112 1.1 kiyohara
1113 1.1 kiyohara xs.error = XS_NOERROR;
1114 1.1 kiyohara xs.resid = datalen;
1115 1.1 kiyohara xs.status = SCSI_OK;
1116 1.1 kiyohara
1117 1.1 kiyohara error = siop_scsi_request(adp, &xs);
1118 1.1 kiyohara adp->sd = NULL;
1119 1.1 kiyohara if (error != 0)
1120 1.1 kiyohara return error;
1121 1.1 kiyohara
1122 1.1 kiyohara if (datalen > 0)
1123 1.1 kiyohara memcpy(data, adp->data, datalen);
1124 1.1 kiyohara return 0;
1125 1.1 kiyohara }
1126 1.1 kiyohara
1127 1.1 kiyohara /*
1128 1.1 kiyohara * Initialize the device.
1129 1.1 kiyohara */
1130 1.1 kiyohara int
1131 1.1 kiyohara siop_init(int bus, int dev, int func)
1132 1.1 kiyohara {
1133 1.1 kiyohara struct siop_adapter tmp;
1134 1.1 kiyohara struct siop_xfer *xfer;
1135 1.1 kiyohara struct scsipi_generic *cmd;
1136 1.1 kiyohara struct scsi_request_sense *sense;
1137 1.1 kiyohara uint32_t reg;
1138 1.1 kiyohara u_long addr;
1139 1.1 kiyohara uint32_t *script;
1140 1.1 kiyohara int slot, id, i;
1141 1.1 kiyohara void *scriptaddr;
1142 1.1 kiyohara u_char *data;
1143 1.1 kiyohara const int clock_div = 3; /* 53c810 */
1144 1.1 kiyohara
1145 1.1 kiyohara slot = PCISlotnum(bus, dev, func);
1146 1.1 kiyohara if (slot == -1)
1147 1.1 kiyohara return ENOENT;
1148 1.1 kiyohara
1149 1.1 kiyohara addr = PCIAddress(slot, 1, PCI_MAPREG_TYPE_MEM);
1150 1.1 kiyohara if (addr == 0xffffffff)
1151 1.1 kiyohara return EINVAL;
1152 1.1 kiyohara enablePCI(slot, 0, 1, 1);
1153 1.1 kiyohara
1154 1.1 kiyohara script = ALLOC(uint32_t, SIOP_SCRIPT_SIZE);
1155 1.1 kiyohara if (script == NULL)
1156 1.1 kiyohara return ENOMEM;
1157 1.1 kiyohara scriptaddr = (void *)local_to_PCI((u_long)script);
1158 1.1 kiyohara cmd = ALLOC(struct scsipi_generic, SIOP_SCSI_COMMAND_SIZE);
1159 1.1 kiyohara if (cmd == NULL)
1160 1.1 kiyohara return ENOMEM;
1161 1.1 kiyohara sense = ALLOC(struct scsi_request_sense, SIOP_SCSI_COMMAND_SIZE);
1162 1.1 kiyohara if (sense == NULL)
1163 1.1 kiyohara return ENOMEM;
1164 1.1 kiyohara data = ALLOC(u_char, SIOP_SCSI_DATA_SIZE);
1165 1.1 kiyohara if (data == NULL)
1166 1.1 kiyohara return ENOMEM;
1167 1.1 kiyohara xfer = ALLOC(struct siop_xfer, sizeof(struct siop_xfer));
1168 1.1 kiyohara if (xfer == NULL)
1169 1.1 kiyohara return ENOMEM;
1170 1.1 kiyohara siop_xfer_setup(xfer, scriptaddr);
1171 1.1 kiyohara
1172 1.1 kiyohara id = readb(addr + SIOP_SCID) & SCID_ENCID_MASK;
1173 1.1 kiyohara
1174 1.1 kiyohara /* reset bus */
1175 1.1 kiyohara reg = readb(addr + SIOP_SCNTL1);
1176 1.1 kiyohara writeb(addr + SIOP_SCNTL1, reg | SCNTL1_RST);
1177 1.1 kiyohara delay(100);
1178 1.1 kiyohara writeb(addr + SIOP_SCNTL1, reg);
1179 1.1 kiyohara
1180 1.1 kiyohara /* reset the chip */
1181 1.1 kiyohara writeb(addr + SIOP_ISTAT, ISTAT_SRST);
1182 1.1 kiyohara delay(1000);
1183 1.1 kiyohara writeb(addr + SIOP_ISTAT, 0);
1184 1.1 kiyohara
1185 1.1 kiyohara /* init registers */
1186 1.1 kiyohara writeb(addr + SIOP_SCNTL0, SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP);
1187 1.1 kiyohara writeb(addr + SIOP_SCNTL1, 0);
1188 1.1 kiyohara writeb(addr + SIOP_SCNTL3, clock_div);
1189 1.1 kiyohara writeb(addr + SIOP_SXFER, 0);
1190 1.1 kiyohara writeb(addr + SIOP_DIEN, 0xff);
1191 1.1 kiyohara writeb(addr + SIOP_SIEN0, 0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL));
1192 1.1 kiyohara writeb(addr + SIOP_SIEN1, 0xff & ~(SIEN1_HTH | SIEN1_GEN));
1193 1.1 kiyohara writeb(addr + SIOP_STEST2, 0);
1194 1.1 kiyohara writeb(addr + SIOP_STEST3, STEST3_TE);
1195 1.1 kiyohara writeb(addr + SIOP_STIME0, (0xb << STIME0_SEL_SHIFT));
1196 1.1 kiyohara writeb(addr + SIOP_SCID, id | SCID_RRE);
1197 1.1 kiyohara writeb(addr + SIOP_RESPID0, 1 << id);
1198 1.1 kiyohara writeb(addr + SIOP_DCNTL, DCNTL_COM);
1199 1.1 kiyohara
1200 1.1 kiyohara /* BeBox uses PCIC */
1201 1.1 kiyohara writeb(addr + SIOP_STEST1, STEST1_SCLK);
1202 1.1 kiyohara
1203 1.1 kiyohara siop_pci_reset(addr);
1204 1.1 kiyohara
1205 1.1 kiyohara /* copy and patch the script */
1206 1.1 kiyohara for (i = 0; i < __arraycount(siop_script); i++)
1207 1.1 kiyohara script[i] = htoc32(siop_script[i]);
1208 1.1 kiyohara for (i = 0; i < __arraycount(E_abs_msgin_Used); i++)
1209 1.1 kiyohara script[E_abs_msgin_Used[i]] =
1210 1.1 kiyohara htoc32(scriptaddr + Ent_msgin_space);
1211 1.1 kiyohara
1212 1.1 kiyohara /* start script */
1213 1.1 kiyohara _wbinv((u_long)script, SIOP_SCRIPT_SIZE);
1214 1.1 kiyohara writel(addr + SIOP_DSP, (int)scriptaddr + Ent_reselect);
1215 1.1 kiyohara
1216 1.1 kiyohara memset(&tmp, 0, sizeof(tmp));
1217 1.1 kiyohara tmp.id = id;
1218 1.1 kiyohara tmp.clock_div = clock_div;
1219 1.1 kiyohara tmp.addr = addr;
1220 1.1 kiyohara tmp.script = script;
1221 1.1 kiyohara tmp.xfer = xfer;
1222 1.1 kiyohara tmp.cmd = cmd;
1223 1.1 kiyohara tmp.sense = sense;
1224 1.1 kiyohara tmp.data = data;
1225 1.1 kiyohara tmp.currschedslot = 0;
1226 1.1 kiyohara tmp.sel_t = -1;
1227 1.1 kiyohara
1228 1.1 kiyohara if (scsi_probe(&tmp) == 0)
1229 1.1 kiyohara return ENXIO;
1230 1.1 kiyohara adapt = tmp;
1231 1.1 kiyohara return 0;
1232 1.1 kiyohara }
1233