Initial import from FreeBSD RELENG_4:
[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  */
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/module.h>
35 #include <sys/bus.h>
36 #include <sys/buf.h>
37 #include <sys/malloc.h>
38 #include <vm/vm.h>
39 #include <vm/pmap.h>
40 #include <machine/clock.h>
41 #include <machine/stdarg.h>
42 #include <machine/resource.h>
43 #include <machine/bus.h>
44 #include <sys/rman.h>
45 #include <pci/pcivar.h>
46 #include <pci/pcireg.h>
47
48 #include "dev/pst/pst-iop.h"
49
50 /* local vars */
51 MALLOC_DEFINE(M_PSTIOP, "PSTIOP", "Promise SuperTrak IOP driver");
52
53 int
54 iop_init(struct iop_softc *sc)
55 {
56     int mfa, timeout = 10000;
57
58     while ((mfa = sc->reg->iqueue) == 0xffffffff && --timeout)
59         DELAY(1000);
60     if (!timeout) {
61         printf("pstiop: no free mfa\n");
62         return 0;
63     }
64     iop_free_mfa(sc, mfa);
65
66     sc->reg->oqueue_intr_mask = 0xffffffff;
67
68     if (!iop_reset(sc)) {
69         printf("pstiop: no reset response\n");
70         return 0;
71     }
72
73     if (!iop_init_outqueue(sc)) {
74         printf("pstiop: init outbound queue failed\n");
75         return 0;
76     }
77
78     /* register iop_attach to be run when interrupts are enabled */
79     if (!(sc->iop_delayed_attach = (struct intr_config_hook *)
80                                    malloc(sizeof(struct intr_config_hook), 
81                                    M_PSTIOP, M_NOWAIT | M_ZERO))) {
82         printf("pstiop: malloc of delayed attach hook failed\n");
83         return 0;
84     }
85     sc->iop_delayed_attach->ich_func = (void *)iop_attach;
86     sc->iop_delayed_attach->ich_arg = (void *)sc;
87     if (config_intrhook_establish(sc->iop_delayed_attach)) {
88         printf("pstiop: config_intrhook_establish failed\n");
89         free(sc->iop_delayed_attach, M_PSTIOP);
90     }
91     return 1;
92 }
93
94 void
95 iop_attach(struct iop_softc *sc)
96 {
97     int i;
98
99     if (sc->iop_delayed_attach) {
100         config_intrhook_disestablish(sc->iop_delayed_attach);
101         free(sc->iop_delayed_attach, M_PSTIOP);
102         sc->iop_delayed_attach = NULL;
103     }
104
105     if (!iop_get_lct(sc)) {
106         printf("pstiop: get LCT failed\n");
107         return;
108     }
109
110     /* figure out what devices are here and config as needed */
111     for (i = 0; sc->lct[i].entry_size == I2O_LCT_ENTRYSIZE; i++) {
112 #ifdef PSTDEBUG
113         struct i2o_get_param_reply *reply;
114
115         printf("pstiop: LCT entry %d ", i);
116         printf("class=%04x ", sc->lct[i].class);
117         printf("sub=%04x ", sc->lct[i].sub_class);
118         printf("localtid=%04x ", sc->lct[i].local_tid);
119         printf("usertid=%04x ", sc->lct[i].user_tid);
120         printf("parentid=%04x\n", sc->lct[i].parent_tid);
121
122         if ((reply = iop_get_util_params(sc, sc->lct[i].local_tid,
123                                          I2O_PARAMS_OPERATION_FIELD_GET,
124                                          I2O_UTIL_DEVICE_IDENTITY_GROUP_NO))) {
125             struct i2o_device_identity *ident =
126                 (struct i2o_device_identity *)reply->result;
127             printf("pstiop: vendor=<%.16s> product=<%.16s>\n",
128                    ident->vendor, ident->product);
129             printf("pstiop: description=<%.16s> revision=<%.8s>\n",
130                    ident->description, ident->revision);
131             contigfree(reply, PAGE_SIZE, M_PSTIOP);
132         }
133 #endif
134
135         if (sc->lct[i].user_tid != I2O_TID_NONE &&
136             sc->lct[i].user_tid != I2O_TID_HOST)
137             continue;
138
139         switch (sc->lct[i].class) {
140         case I2O_CLASS_RANDOM_BLOCK_STORAGE:
141             pst_add_raid(sc, &sc->lct[i]);
142             break;
143         }
144     }
145     /* setup and enable interrupts */
146     bus_setup_intr(sc->dev, sc->r_irq, INTR_TYPE_BIO, iop_intr, sc,&sc->handle);
147     sc->reg->oqueue_intr_mask = 0x0;
148 }
149
150 void
151 iop_intr(void *data)
152 {
153     struct iop_softc *sc = (struct iop_softc *)data;
154     struct i2o_single_reply *reply;
155     u_int32_t mfa;
156
157     /* we might get more than one finished request pr interrupt */
158     while (1) {
159         if ((mfa = sc->reg->oqueue) == 0xffffffff)
160             if ((mfa = sc->reg->oqueue) == 0xffffffff)
161                 return;
162
163         reply = (struct i2o_single_reply *)(sc->obase + (mfa - sc->phys_obase));
164
165         /* if this is a event register reply, shout! */
166         if (reply->function == I2O_UTIL_EVENT_REGISTER) {
167             struct i2o_util_event_reply_message *event = 
168                 (struct i2o_util_event_reply_message *)reply;
169
170             printf("pstiop: EVENT!! idx=%08x data=%08x\n",
171                    event->event_mask, event->event_data[0]);
172             return;
173         }
174
175         /* if reply is a failurenotice we need to free the original mfa */
176         if (reply->message_flags & I2O_MESSAGE_FLAGS_FAIL)
177             iop_free_mfa(sc,((struct i2o_fault_reply *)(reply))->preserved_mfa);
178         
179         /* reply->initiator_context points to the service routine */
180         ((void (*)(struct iop_softc *, u_int32_t, struct i2o_single_reply *))
181             (reply->initiator_context))(sc, mfa, reply);
182     }
183 }
184
185 int
186 iop_reset(struct iop_softc *sc)
187 {
188     struct i2o_exec_iop_reset_message *msg;
189     int mfa, timeout = 5000;
190     volatile u_int32_t reply = 0;
191
192     mfa = iop_get_mfa(sc);
193     msg = (struct i2o_exec_iop_reset_message *)(sc->ibase + mfa);
194     bzero(msg, sizeof(struct i2o_exec_iop_reset_message));
195     msg->version_offset = 0x1;
196     msg->message_flags = 0x0;
197     msg->message_size = sizeof(struct i2o_exec_iop_reset_message) >> 2;
198     msg->target_address = I2O_TID_IOP;
199     msg->initiator_address = I2O_TID_HOST;
200     msg->function = I2O_EXEC_IOP_RESET;
201     msg->status_word_low_addr = vtophys(&reply);
202     msg->status_word_high_addr = 0;
203
204     sc->reg->iqueue = mfa;
205
206     while (--timeout && !reply)
207         DELAY(1000);
208
209     /* wait for iqueue ready */
210     timeout = 10000;
211     while ((mfa = sc->reg->iqueue) == 0xffffffff && --timeout)
212         DELAY(1000);
213
214     iop_free_mfa(sc, mfa);
215     return reply;
216 }
217
218 int
219 iop_init_outqueue(struct iop_softc *sc)
220 {
221     struct i2o_exec_init_outqueue_message *msg;
222     int i, mfa, timeout = 5000;
223     volatile u_int32_t reply = 0;
224
225     if (!(sc->obase = contigmalloc(I2O_IOP_OUTBOUND_FRAME_COUNT *
226                                    I2O_IOP_OUTBOUND_FRAME_SIZE,
227                                    M_PSTIOP, M_NOWAIT,
228                                    0x00010000, 0xFFFFFFFF,
229                                    sizeof(u_int32_t), 0))) {
230         printf("pstiop: contigmalloc of outqueue buffers failed!\n");
231         return 0;
232     }
233     sc->phys_obase = vtophys(sc->obase);
234     mfa = iop_get_mfa(sc);
235     msg = (struct i2o_exec_init_outqueue_message *)(sc->ibase + mfa);
236     bzero(msg, sizeof(struct i2o_exec_init_outqueue_message));
237     msg->version_offset = 0x61;
238     msg->message_flags = 0x0;
239     msg->message_size = sizeof(struct i2o_exec_init_outqueue_message) >> 2;
240     msg->target_address = I2O_TID_IOP;
241     msg->initiator_address = I2O_TID_HOST;
242     msg->function = I2O_EXEC_OUTBOUND_INIT;
243     msg->host_pagesize = PAGE_SIZE;
244     msg->init_code = 0x00; /* SOS XXX should be 0x80 == OS */
245     msg->queue_framesize = I2O_IOP_OUTBOUND_FRAME_SIZE / sizeof(u_int32_t);
246     msg->sgl[0].flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
247     msg->sgl[0].count = sizeof(reply);
248     msg->sgl[0].phys_addr[0] = vtophys(&reply);
249     msg->sgl[1].flags = I2O_SGL_END | I2O_SGL_EOB;
250     msg->sgl[1].count = 1;
251     msg->sgl[1].phys_addr[0] = 0;
252
253     sc->reg->iqueue = mfa;
254
255     /* wait for init to complete */
256     while (--timeout && reply != I2O_EXEC_OUTBOUND_INIT_COMPLETE)
257         DELAY(1000);
258     
259     if (!timeout) {
260         printf("pstiop: timeout waiting for init-complete response\n");
261         iop_free_mfa(sc, mfa);
262         return 0;
263     }
264
265     /* now init our oqueue bufs */
266     for (i = 0; i < I2O_IOP_OUTBOUND_FRAME_COUNT; i++) {
267         sc->reg->oqueue = sc->phys_obase + (i * I2O_IOP_OUTBOUND_FRAME_SIZE);
268         DELAY(1000);
269     }
270
271     iop_free_mfa(sc, mfa);
272     return 1;
273 }
274
275 int
276 iop_get_lct(struct iop_softc *sc)
277 {
278     struct i2o_exec_get_lct_message *msg;
279     struct i2o_get_lct_reply *reply;
280     int mfa;
281 #define ALLOCSIZE        (PAGE_SIZE + (256 * sizeof(struct i2o_lct_entry)))
282
283     if (!(reply = contigmalloc(ALLOCSIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
284                                0x00010000, 0xFFFFFFFF, sizeof(u_int32_t), 0)))
285         return 0;
286
287     mfa = iop_get_mfa(sc);
288     msg = (struct i2o_exec_get_lct_message *)(sc->ibase + mfa);
289     bzero(msg, sizeof(struct i2o_exec_get_lct_message));
290     msg->version_offset = 0x61;
291     msg->message_flags = 0x0;
292     msg->message_size = sizeof(struct i2o_exec_get_lct_message) >> 2;
293     msg->target_address = I2O_TID_IOP;
294     msg->initiator_address = I2O_TID_HOST;
295     msg->function = I2O_EXEC_LCT_NOTIFY;
296     msg->class = I2O_CLASS_MATCH_ANYCLASS;
297     msg->last_change_id = 0;
298
299     msg->sgl.flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
300     msg->sgl.count = ALLOCSIZE;
301     msg->sgl.phys_addr[0] = vtophys(reply);
302
303     if (iop_queue_wait_msg(sc, mfa, (struct i2o_basic_message *)msg)) {
304         contigfree(reply, ALLOCSIZE, M_PSTIOP);
305         return 0;
306     }
307     if (!(sc->lct = malloc(reply->table_size * sizeof(struct i2o_lct_entry),
308                            M_PSTIOP, M_NOWAIT | M_ZERO))) {
309         contigfree(reply, ALLOCSIZE, M_PSTIOP);
310         return 0;
311     }
312     bcopy(&reply->entry[0], sc->lct, 
313           reply->table_size * sizeof(struct i2o_lct_entry));
314     sc->lct_count = reply->table_size;
315     contigfree(reply, ALLOCSIZE, M_PSTIOP);
316     return 1;
317 }
318
319 struct i2o_get_param_reply *
320 iop_get_util_params(struct iop_softc *sc, int target, int operation, int group)
321 {
322     struct i2o_util_get_param_message *msg;
323     struct i2o_get_param_operation *param;
324     struct i2o_get_param_reply *reply;
325     int mfa;
326
327     if (!(param = contigmalloc(PAGE_SIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
328                                0x00010000, 0xFFFFFFFF, sizeof(u_int32_t), 0)))
329         return NULL;
330
331     if (!(reply = contigmalloc(PAGE_SIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
332                                0x00010000, 0xFFFFFFFF, sizeof(u_int32_t), 0)))
333         return NULL;
334
335     mfa = iop_get_mfa(sc);
336     msg = (struct i2o_util_get_param_message *)(sc->ibase + mfa);
337     bzero(msg, sizeof(struct i2o_util_get_param_message));
338     msg->version_offset = 0x51;
339     msg->message_flags = 0x0;
340     msg->message_size = sizeof(struct i2o_util_get_param_message) >> 2;
341     msg->target_address = target;
342     msg->initiator_address = I2O_TID_HOST;
343     msg->function = I2O_UTIL_PARAMS_GET;
344     msg->operation_flags = 0;
345
346     param->operation_count = 1;
347     param->operation[0].operation = operation;
348     param->operation[0].group = group;
349     param->operation[0].field_count = 0xffff;
350
351     msg->sgl[0].flags = I2O_SGL_SIMPLE | I2O_SGL_DIR | I2O_SGL_EOB;
352     msg->sgl[0].count = sizeof(struct i2o_get_param_operation);
353     msg->sgl[0].phys_addr[0] = vtophys(param);
354
355     msg->sgl[1].flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
356     msg->sgl[1].count = PAGE_SIZE;
357     msg->sgl[1].phys_addr[0] = vtophys(reply);
358
359     if (iop_queue_wait_msg(sc, mfa, (struct i2o_basic_message *)msg) ||
360         reply->error_info_size) {
361         contigfree(reply, PAGE_SIZE, M_PSTIOP);
362         reply = NULL;
363     }
364     contigfree(param, PAGE_SIZE, M_PSTIOP);
365     return reply;
366 }
367
368 u_int32_t
369 iop_get_mfa(struct iop_softc *sc)
370 {
371     u_int32_t mfa;
372     int timeout = 10000;
373
374     while ((mfa = sc->reg->iqueue) == 0xffffffff && timeout) {
375         DELAY(1000);
376         timeout--;
377     }
378     if (!timeout)
379         printf("pstiop: no free mfa\n");
380     return mfa;
381 }
382
383 void
384 iop_free_mfa(struct iop_softc *sc, int mfa)
385 {
386     struct i2o_basic_message *msg = (struct i2o_basic_message *)(sc->ibase+mfa);
387
388     bzero(msg, sizeof(struct i2o_basic_message));
389     msg->version = 0x01;
390     msg->message_flags = 0x0;
391     msg->message_size = sizeof(struct i2o_basic_message) >> 2;
392     msg->target_address = I2O_TID_IOP;
393     msg->initiator_address = I2O_TID_HOST;
394     msg->function = I2O_UTIL_NOP;
395     sc->reg->iqueue = mfa;
396 }
397
398 int
399 iop_queue_wait_msg(struct iop_softc *sc, int mfa, struct i2o_basic_message *msg)
400 {
401     struct i2o_single_reply *reply;
402     int out_mfa, status, timeout = 10000;
403
404     sc->reg->iqueue = mfa;
405
406     while (--timeout && ((out_mfa = sc->reg->oqueue) == 0xffffffff))
407         DELAY(1000);
408     if (!timeout) {
409         printf("pstiop: timeout waiting for message response\n");
410         iop_free_mfa(sc, mfa);
411         return -1;
412     }
413
414     reply = (struct i2o_single_reply *)(sc->obase + (out_mfa - sc->phys_obase));
415     status = reply->status;
416     sc->reg->oqueue = out_mfa;
417     return status;
418 }
419
420 int
421 iop_create_sgl(struct i2o_basic_message *msg, caddr_t data, int count, int dir)
422 {
423     struct i2o_sgl *sgl = (struct i2o_sgl *)((int32_t *)msg + msg->offset);
424     u_int32_t sgl_count, sgl_phys;
425     int i = 0;
426
427     if (((uintptr_t)data & 3) || (count & 3)) {
428         printf("pstiop: non aligned DMA transfer attempted\n");
429         return 0;
430     }
431     if (!count) {
432         printf("pstiop: zero length DMA transfer attempted\n");
433         return 0;
434     }
435     
436     sgl_count = min(count, (PAGE_SIZE - ((uintptr_t)data & PAGE_MASK)));
437     sgl_phys = vtophys(data);
438     sgl->flags = dir | I2O_SGL_PAGELIST | I2O_SGL_EOB | I2O_SGL_END;
439     sgl->count = count;
440     data += sgl_count;
441     count -= sgl_count;
442
443     while (count) {
444         sgl->phys_addr[i] = sgl_phys;
445         sgl_phys = vtophys(data);
446         data += min(count, PAGE_SIZE);
447         count -= min(count, PAGE_SIZE);
448         if (++i >= I2O_SGL_MAX_SEGS) {
449             printf("pstiop: too many segments in SGL\n");
450             return 0;
451         }
452     }
453     sgl->phys_addr[i] = sgl_phys;
454     msg->message_size += i;
455     return 1;
456 }