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