timeout/untimeout ==> callout_*
[dragonfly.git] / sys / dev / raid / pst / pst-iop.c
1 /*-
2  * Copyright (c) 2001,2002 Søren Schmidt <sos@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification, immediately at the beginning of the file.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/dev/pst/pst-iop.c,v 1.2.2.1 2002/08/18 12:32:36 sos Exp $
29  * $DragonFly: src/sys/dev/raid/pst/pst-iop.c,v 1.4 2004/06/21 15:39:31 dillon Exp $
30  */
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/module.h>
36 #include <sys/bus.h>
37 #include <sys/buf.h>
38 #include <sys/malloc.h>
39 #include <vm/vm.h>
40 #include <vm/pmap.h>
41 #include <machine/clock.h>
42 #include <machine/stdarg.h>
43 #include <machine/resource.h>
44 #include <machine/bus.h>
45 #include <sys/rman.h>
46 #include <bus/pci/pcivar.h>
47 #include <bus/pci/pcireg.h>
48
49 #include "pst-iop.h"
50
51 /* local vars */
52 MALLOC_DEFINE(M_PSTIOP, "PSTIOP", "Promise SuperTrak IOP driver");
53
54 int
55 iop_init(struct iop_softc *sc)
56 {
57     int mfa, timeout = 10000;
58
59     while ((mfa = sc->reg->iqueue) == 0xffffffff && --timeout)
60         DELAY(1000);
61     if (!timeout) {
62         printf("pstiop: no free mfa\n");
63         return 0;
64     }
65     iop_free_mfa(sc, mfa);
66
67     sc->reg->oqueue_intr_mask = 0xffffffff;
68
69     if (!iop_reset(sc)) {
70         printf("pstiop: no reset response\n");
71         return 0;
72     }
73
74     if (!iop_init_outqueue(sc)) {
75         printf("pstiop: init outbound queue failed\n");
76         return 0;
77     }
78
79     /* register iop_attach to be run when interrupts are enabled */
80     sc->iop_delayed_attach = malloc(sizeof(struct intr_config_hook), 
81                                    M_PSTIOP, M_INTWAIT | M_ZERO);
82     sc->iop_delayed_attach->ich_func = (void *)iop_attach;
83     sc->iop_delayed_attach->ich_arg = (void *)sc;
84     if (config_intrhook_establish(sc->iop_delayed_attach)) {
85         printf("pstiop: config_intrhook_establish failed\n");
86         free(sc->iop_delayed_attach, M_PSTIOP);
87     }
88     return 1;
89 }
90
91 void
92 iop_attach(struct iop_softc *sc)
93 {
94     int i;
95
96     if (sc->iop_delayed_attach) {
97         config_intrhook_disestablish(sc->iop_delayed_attach);
98         free(sc->iop_delayed_attach, M_PSTIOP);
99         sc->iop_delayed_attach = NULL;
100     }
101
102     if (!iop_get_lct(sc)) {
103         printf("pstiop: get LCT failed\n");
104         return;
105     }
106
107     /* figure out what devices are here and config as needed */
108     for (i = 0; sc->lct[i].entry_size == I2O_LCT_ENTRYSIZE; i++) {
109 #ifdef PSTDEBUG
110         struct i2o_get_param_reply *reply;
111
112         printf("pstiop: LCT entry %d ", i);
113         printf("class=%04x ", sc->lct[i].class);
114         printf("sub=%04x ", sc->lct[i].sub_class);
115         printf("localtid=%04x ", sc->lct[i].local_tid);
116         printf("usertid=%04x ", sc->lct[i].user_tid);
117         printf("parentid=%04x\n", sc->lct[i].parent_tid);
118
119         if ((reply = iop_get_util_params(sc, sc->lct[i].local_tid,
120                                          I2O_PARAMS_OPERATION_FIELD_GET,
121                                          I2O_UTIL_DEVICE_IDENTITY_GROUP_NO))) {
122             struct i2o_device_identity *ident =
123                 (struct i2o_device_identity *)reply->result;
124             printf("pstiop: vendor=<%.16s> product=<%.16s>\n",
125                    ident->vendor, ident->product);
126             printf("pstiop: description=<%.16s> revision=<%.8s>\n",
127                    ident->description, ident->revision);
128             contigfree(reply, PAGE_SIZE, M_PSTIOP);
129         }
130 #endif
131
132         if (sc->lct[i].user_tid != I2O_TID_NONE &&
133             sc->lct[i].user_tid != I2O_TID_HOST)
134             continue;
135
136         switch (sc->lct[i].class) {
137         case I2O_CLASS_RANDOM_BLOCK_STORAGE:
138             pst_add_raid(sc, &sc->lct[i]);
139             break;
140         }
141     }
142     /* setup and enable interrupts */
143     bus_setup_intr(sc->dev, sc->r_irq, INTR_TYPE_BIO, iop_intr, sc,&sc->handle);
144     sc->reg->oqueue_intr_mask = 0x0;
145 }
146
147 void
148 iop_intr(void *data)
149 {
150     struct iop_softc *sc = (struct iop_softc *)data;
151     struct i2o_single_reply *reply;
152     u_int32_t mfa;
153
154     /* we might get more than one finished request pr interrupt */
155     while (1) {
156         if ((mfa = sc->reg->oqueue) == 0xffffffff)
157             if ((mfa = sc->reg->oqueue) == 0xffffffff)
158                 return;
159
160         reply = (struct i2o_single_reply *)(sc->obase + (mfa - sc->phys_obase));
161
162         /* if this is a event register reply, shout! */
163         if (reply->function == I2O_UTIL_EVENT_REGISTER) {
164             struct i2o_util_event_reply_message *event = 
165                 (struct i2o_util_event_reply_message *)reply;
166
167             printf("pstiop: EVENT!! idx=%08x data=%08x\n",
168                    event->event_mask, event->event_data[0]);
169             return;
170         }
171
172         /* if reply is a failurenotice we need to free the original mfa */
173         if (reply->message_flags & I2O_MESSAGE_FLAGS_FAIL)
174             iop_free_mfa(sc,((struct i2o_fault_reply *)(reply))->preserved_mfa);
175         
176         /* reply->initiator_context points to the service routine */
177         ((void (*)(struct iop_softc *, u_int32_t, struct i2o_single_reply *))
178             (reply->initiator_context))(sc, mfa, reply);
179     }
180 }
181
182 int
183 iop_reset(struct iop_softc *sc)
184 {
185     struct i2o_exec_iop_reset_message *msg;
186     int mfa, timeout = 5000;
187     volatile u_int32_t reply = 0;
188
189     mfa = iop_get_mfa(sc);
190     msg = (struct i2o_exec_iop_reset_message *)(sc->ibase + mfa);
191     bzero(msg, sizeof(struct i2o_exec_iop_reset_message));
192     msg->version_offset = 0x1;
193     msg->message_flags = 0x0;
194     msg->message_size = sizeof(struct i2o_exec_iop_reset_message) >> 2;
195     msg->target_address = I2O_TID_IOP;
196     msg->initiator_address = I2O_TID_HOST;
197     msg->function = I2O_EXEC_IOP_RESET;
198     msg->status_word_low_addr = vtophys(&reply);
199     msg->status_word_high_addr = 0;
200
201     sc->reg->iqueue = mfa;
202
203     while (--timeout && !reply)
204         DELAY(1000);
205
206     /* wait for iqueue ready */
207     timeout = 10000;
208     while ((mfa = sc->reg->iqueue) == 0xffffffff && --timeout)
209         DELAY(1000);
210
211     iop_free_mfa(sc, mfa);
212     return reply;
213 }
214
215 int
216 iop_init_outqueue(struct iop_softc *sc)
217 {
218     struct i2o_exec_init_outqueue_message *msg;
219     int i, mfa, timeout = 5000;
220     volatile u_int32_t reply = 0;
221
222     if (!(sc->obase = contigmalloc(I2O_IOP_OUTBOUND_FRAME_COUNT *
223                                    I2O_IOP_OUTBOUND_FRAME_SIZE,
224                                    M_PSTIOP, M_NOWAIT,
225                                    0x00010000, 0xFFFFFFFF,
226                                    sizeof(u_int32_t), 0))) {
227         printf("pstiop: contigmalloc of outqueue buffers failed!\n");
228         return 0;
229     }
230     sc->phys_obase = vtophys(sc->obase);
231     mfa = iop_get_mfa(sc);
232     msg = (struct i2o_exec_init_outqueue_message *)(sc->ibase + mfa);
233     bzero(msg, sizeof(struct i2o_exec_init_outqueue_message));
234     msg->version_offset = 0x61;
235     msg->message_flags = 0x0;
236     msg->message_size = sizeof(struct i2o_exec_init_outqueue_message) >> 2;
237     msg->target_address = I2O_TID_IOP;
238     msg->initiator_address = I2O_TID_HOST;
239     msg->function = I2O_EXEC_OUTBOUND_INIT;
240     msg->host_pagesize = PAGE_SIZE;
241     msg->init_code = 0x00; /* SOS XXX should be 0x80 == OS */
242     msg->queue_framesize = I2O_IOP_OUTBOUND_FRAME_SIZE / sizeof(u_int32_t);
243     msg->sgl[0].flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
244     msg->sgl[0].count = sizeof(reply);
245     msg->sgl[0].phys_addr[0] = vtophys(&reply);
246     msg->sgl[1].flags = I2O_SGL_END | I2O_SGL_EOB;
247     msg->sgl[1].count = 1;
248     msg->sgl[1].phys_addr[0] = 0;
249
250     sc->reg->iqueue = mfa;
251
252     /* wait for init to complete */
253     while (--timeout && reply != I2O_EXEC_OUTBOUND_INIT_COMPLETE)
254         DELAY(1000);
255     
256     if (!timeout) {
257         printf("pstiop: timeout waiting for init-complete response\n");
258         iop_free_mfa(sc, mfa);
259         return 0;
260     }
261
262     /* now init our oqueue bufs */
263     for (i = 0; i < I2O_IOP_OUTBOUND_FRAME_COUNT; i++) {
264         sc->reg->oqueue = sc->phys_obase + (i * I2O_IOP_OUTBOUND_FRAME_SIZE);
265         DELAY(1000);
266     }
267
268     iop_free_mfa(sc, mfa);
269     return 1;
270 }
271
272 int
273 iop_get_lct(struct iop_softc *sc)
274 {
275     struct i2o_exec_get_lct_message *msg;
276     struct i2o_get_lct_reply *reply;
277     int mfa;
278 #define ALLOCSIZE        (PAGE_SIZE + (256 * sizeof(struct i2o_lct_entry)))
279
280     if (!(reply = contigmalloc(ALLOCSIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
281                                0x00010000, 0xFFFFFFFF, sizeof(u_int32_t), 0)))
282         return 0;
283
284     mfa = iop_get_mfa(sc);
285     msg = (struct i2o_exec_get_lct_message *)(sc->ibase + mfa);
286     bzero(msg, sizeof(struct i2o_exec_get_lct_message));
287     msg->version_offset = 0x61;
288     msg->message_flags = 0x0;
289     msg->message_size = sizeof(struct i2o_exec_get_lct_message) >> 2;
290     msg->target_address = I2O_TID_IOP;
291     msg->initiator_address = I2O_TID_HOST;
292     msg->function = I2O_EXEC_LCT_NOTIFY;
293     msg->class = I2O_CLASS_MATCH_ANYCLASS;
294     msg->last_change_id = 0;
295
296     msg->sgl.flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
297     msg->sgl.count = ALLOCSIZE;
298     msg->sgl.phys_addr[0] = vtophys(reply);
299
300     if (iop_queue_wait_msg(sc, mfa, (struct i2o_basic_message *)msg)) {
301         contigfree(reply, ALLOCSIZE, M_PSTIOP);
302         return 0;
303     }
304     sc->lct = malloc(reply->table_size * sizeof(struct i2o_lct_entry),
305                            M_PSTIOP, M_INTWAIT | M_ZERO);
306     bcopy(&reply->entry[0], sc->lct, 
307           reply->table_size * sizeof(struct i2o_lct_entry));
308     sc->lct_count = reply->table_size;
309     contigfree(reply, ALLOCSIZE, M_PSTIOP);
310     return 1;
311 }
312
313 struct i2o_get_param_reply *
314 iop_get_util_params(struct iop_softc *sc, int target, int operation, int group)
315 {
316     struct i2o_util_get_param_message *msg;
317     struct i2o_get_param_operation *param;
318     struct i2o_get_param_reply *reply;
319     int mfa;
320
321     if (!(param = contigmalloc(PAGE_SIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
322                                0x00010000, 0xFFFFFFFF, sizeof(u_int32_t), 0)))
323         return NULL;
324
325     if (!(reply = contigmalloc(PAGE_SIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
326                                0x00010000, 0xFFFFFFFF, sizeof(u_int32_t), 0)))
327         return NULL;
328
329     mfa = iop_get_mfa(sc);
330     msg = (struct i2o_util_get_param_message *)(sc->ibase + mfa);
331     bzero(msg, sizeof(struct i2o_util_get_param_message));
332     msg->version_offset = 0x51;
333     msg->message_flags = 0x0;
334     msg->message_size = sizeof(struct i2o_util_get_param_message) >> 2;
335     msg->target_address = target;
336     msg->initiator_address = I2O_TID_HOST;
337     msg->function = I2O_UTIL_PARAMS_GET;
338     msg->operation_flags = 0;
339
340     param->operation_count = 1;
341     param->operation[0].operation = operation;
342     param->operation[0].group = group;
343     param->operation[0].field_count = 0xffff;
344
345     msg->sgl[0].flags = I2O_SGL_SIMPLE | I2O_SGL_DIR | I2O_SGL_EOB;
346     msg->sgl[0].count = sizeof(struct i2o_get_param_operation);
347     msg->sgl[0].phys_addr[0] = vtophys(param);
348
349     msg->sgl[1].flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
350     msg->sgl[1].count = PAGE_SIZE;
351     msg->sgl[1].phys_addr[0] = vtophys(reply);
352
353     if (iop_queue_wait_msg(sc, mfa, (struct i2o_basic_message *)msg) ||
354         reply->error_info_size) {
355         contigfree(reply, PAGE_SIZE, M_PSTIOP);
356         reply = NULL;
357     }
358     contigfree(param, PAGE_SIZE, M_PSTIOP);
359     return reply;
360 }
361
362 u_int32_t
363 iop_get_mfa(struct iop_softc *sc)
364 {
365     u_int32_t mfa;
366     int timeout = 10000;
367
368     while ((mfa = sc->reg->iqueue) == 0xffffffff && timeout) {
369         DELAY(1000);
370         timeout--;
371     }
372     if (!timeout)
373         printf("pstiop: no free mfa\n");
374     return mfa;
375 }
376
377 void
378 iop_free_mfa(struct iop_softc *sc, int mfa)
379 {
380     struct i2o_basic_message *msg = (struct i2o_basic_message *)(sc->ibase+mfa);
381
382     bzero(msg, sizeof(struct i2o_basic_message));
383     msg->version = 0x01;
384     msg->message_flags = 0x0;
385     msg->message_size = sizeof(struct i2o_basic_message) >> 2;
386     msg->target_address = I2O_TID_IOP;
387     msg->initiator_address = I2O_TID_HOST;
388     msg->function = I2O_UTIL_NOP;
389     sc->reg->iqueue = mfa;
390 }
391
392 int
393 iop_queue_wait_msg(struct iop_softc *sc, int mfa, struct i2o_basic_message *msg)
394 {
395     struct i2o_single_reply *reply;
396     int out_mfa, status, timeout = 10000;
397
398     sc->reg->iqueue = mfa;
399
400     while (--timeout && ((out_mfa = sc->reg->oqueue) == 0xffffffff))
401         DELAY(1000);
402     if (!timeout) {
403         printf("pstiop: timeout waiting for message response\n");
404         iop_free_mfa(sc, mfa);
405         return -1;
406     }
407
408     reply = (struct i2o_single_reply *)(sc->obase + (out_mfa - sc->phys_obase));
409     status = reply->status;
410     sc->reg->oqueue = out_mfa;
411     return status;
412 }
413
414 int
415 iop_create_sgl(struct i2o_basic_message *msg, caddr_t data, int count, int dir)
416 {
417     struct i2o_sgl *sgl = (struct i2o_sgl *)((int32_t *)msg + msg->offset);
418     u_int32_t sgl_count, sgl_phys;
419     int i = 0;
420
421     if (((uintptr_t)data & 3) || (count & 3)) {
422         printf("pstiop: non aligned DMA transfer attempted\n");
423         return 0;
424     }
425     if (!count) {
426         printf("pstiop: zero length DMA transfer attempted\n");
427         return 0;
428     }
429     
430     sgl_count = min(count, (PAGE_SIZE - ((uintptr_t)data & PAGE_MASK)));
431     sgl_phys = vtophys(data);
432     sgl->flags = dir | I2O_SGL_PAGELIST | I2O_SGL_EOB | I2O_SGL_END;
433     sgl->count = count;
434     data += sgl_count;
435     count -= sgl_count;
436
437     while (count) {
438         sgl->phys_addr[i] = sgl_phys;
439         sgl_phys = vtophys(data);
440         data += min(count, PAGE_SIZE);
441         count -= min(count, PAGE_SIZE);
442         if (++i >= I2O_SGL_MAX_SEGS) {
443             printf("pstiop: too many segments in SGL\n");
444             return 0;
445         }
446     }
447     sgl->phys_addr[i] = sgl_phys;
448     msg->message_size += i;
449     return 1;
450 }