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