pst-iop.c revision 101100
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: head/sys/dev/pst/pst-iop.c 101100 2002-07-31 18:26:30Z sos $
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/bio.h>
37#include <sys/malloc.h>
38#include <vm/vm.h>
39#include <vm/pmap.h>
40#include <machine/stdarg.h>
41#include <machine/resource.h>
42#include <machine/bus.h>
43#include <sys/rman.h>
44#include <pci/pcivar.h>
45#include <pci/pcireg.h>
46
47#include "dev/pst/pst-iop.h"
48
49/* local vars */
50MALLOC_DEFINE(M_PSTIOP, "PSTIOP", "Promise SuperTrak IOP driver");
51
52int
53iop_init(struct iop_softc *sc)
54{
55    int mfa, timeout = 10000;
56
57    while ((mfa = sc->reg->iqueue) == 0xffffffff && --timeout)
58	DELAY(1000);
59    if (!timeout) {
60	printf("pstiop: no free mfa\n");
61	return 0;
62    }
63    iop_free_mfa(sc, mfa);
64
65    sc->reg->oqueue_intr_mask = 0xffffffff;
66
67    if (!iop_reset(sc)) {
68	printf("pstiop: no reset response\n");
69	return 0;
70    }
71
72    if (!iop_init_outqueue(sc)) {
73	printf("pstiop: init outbound queue failed\n");
74	return 0;
75    }
76
77    /* register iop_attach to be run when interrupts are enabled */
78    if (!(sc->iop_delayed_attach = (struct intr_config_hook *)
79				   malloc(sizeof(struct intr_config_hook),
80				   M_PSTIOP, M_NOWAIT | M_ZERO))) {
81	printf("pstiop: malloc of delayed attach hook failed\n");
82	return 0;
83    }
84    sc->iop_delayed_attach->ich_func = (void *)iop_attach;
85    sc->iop_delayed_attach->ich_arg = (void *)sc;
86    if (config_intrhook_establish(sc->iop_delayed_attach)) {
87	printf("pstiop: config_intrhook_establish failed\n");
88	free(sc->iop_delayed_attach, M_PSTIOP);
89    }
90    return 1;
91}
92
93void
94iop_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	free(sc->iop_delayed_attach, M_PSTIOP);
101	sc->iop_delayed_attach = NULL;
102    }
103
104    if (!iop_get_lct(sc)) {
105	printf("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	printf("pstiop: LCT entry %d ", i);
115	printf("class=%04x ", sc->lct[i].class);
116	printf("sub=%04x ", sc->lct[i].sub_class);
117	printf("localtid=%04x ", sc->lct[i].local_tid);
118	printf("usertid=%04x ", sc->lct[i].user_tid);
119	printf("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	    printf("pstiop: vendor=<%.16s> product=<%.16s>\n",
127		   ident->vendor, ident->product);
128	    printf("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, INTR_TYPE_BIO | INTR_ENTROPY,
146		   iop_intr, sc, &sc->handle);
147    sc->reg->oqueue_intr_mask = 0x0;
148}
149
150void
151iop_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    if ((mfa = sc->reg->oqueue) == 0xffffffff) {
158	if ((mfa = sc->reg->oqueue) == 0xffffffff) {
159	    printf("pstiop: no mfa on interrupt ?\n");
160	    return;
161	}
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
184int
185iop_reset(struct iop_softc *sc)
186{
187    struct i2o_exec_iop_reset_message *msg;
188    int mfa, timeout = 5000;
189    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    iop_free_mfa(sc, mfa);
213
214    return reply;
215}
216
217int
218iop_init_outqueue(struct iop_softc *sc)
219{
220    struct i2o_exec_init_outqueue_message *msg;
221    int i, mfa, timeout = 5000;
222    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				   0, 0xFFFFFFFF, sizeof(u_int32_t), 0))) {
228	printf("pstiop: contigmalloc of outqueue buffers failed!\n");
229	return 0;
230    }
231    sc->phys_obase = vtophys(sc->obase);
232    mfa = iop_get_mfa(sc);
233    msg = (struct i2o_exec_init_outqueue_message *)(sc->ibase + mfa);
234    bzero(msg, sizeof(struct i2o_exec_init_outqueue_message));
235    msg->version_offset = 0x61;
236    msg->message_flags = 0x0;
237    msg->message_size = sizeof(struct i2o_exec_init_outqueue_message) >> 2;
238    msg->target_address = I2O_TID_IOP;
239    msg->initiator_address = I2O_TID_HOST;
240    msg->function = I2O_EXEC_OUTBOUND_INIT;
241    msg->host_pagesize = PAGE_SIZE;
242    msg->init_code = 0x00; /* SOS XXX should be 0x80 == OS */
243    msg->queue_framesize = I2O_IOP_OUTBOUND_FRAME_SIZE / sizeof(u_int32_t);
244    msg->sgl[0].flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
245    msg->sgl[0].count = sizeof(reply);
246    msg->sgl[0].phys_addr[0] = vtophys(&reply);
247    msg->sgl[1].flags = I2O_SGL_END | I2O_SGL_EOB;
248    msg->sgl[1].count = 1;
249    msg->sgl[1].phys_addr[0] = 0;
250
251    sc->reg->iqueue = mfa;
252
253    /* wait for init to complete */
254    while (--timeout && reply != I2O_EXEC_OUTBOUND_INIT_COMPLETE)
255	DELAY(1000);
256
257    if (!timeout) {
258	printf("pstiop: timeout waiting for init-complete response\n");
259	iop_free_mfa(sc, mfa);
260	return 0;
261    }
262
263    /* now init our oqueue bufs */
264    for (i = 0; i < I2O_IOP_OUTBOUND_FRAME_COUNT; i++) {
265	sc->reg->oqueue = sc->phys_obase + (i * I2O_IOP_OUTBOUND_FRAME_SIZE);
266	DELAY(1000);
267    }
268
269    iop_free_mfa(sc, mfa);
270    return 1;
271}
272
273int
274iop_get_lct(struct iop_softc *sc)
275{
276    struct i2o_exec_get_lct_message *msg;
277    struct i2o_get_lct_reply *reply;
278    int mfa;
279#define ALLOCSIZE	 (PAGE_SIZE + (256 * sizeof(struct i2o_lct_entry)))
280
281    if (!(reply = contigmalloc(ALLOCSIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
282			       0, 0xFFFFFFFF, sizeof(u_int32_t), 0)))
283	return 0;
284
285    mfa = iop_get_mfa(sc);
286    msg = (struct i2o_exec_get_lct_message *)(sc->ibase + mfa);
287    bzero(msg, sizeof(struct i2o_exec_get_lct_message));
288    msg->version_offset = 0x61;
289    msg->message_flags = 0x0;
290    msg->message_size = sizeof(struct i2o_exec_get_lct_message) >> 2;
291    msg->target_address = I2O_TID_IOP;
292    msg->initiator_address = I2O_TID_HOST;
293    msg->function = I2O_EXEC_LCT_NOTIFY;
294    msg->class = I2O_CLASS_MATCH_ANYCLASS;
295    msg->last_change_id = 0;
296
297    msg->sgl.flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
298    msg->sgl.count = ALLOCSIZE;
299    msg->sgl.phys_addr[0] = vtophys(reply);
300
301    if (iop_queue_wait_msg(sc, mfa, (struct i2o_basic_message *)msg)) {
302	contigfree(reply, ALLOCSIZE, M_PSTIOP);
303	return 0;
304    }
305    if (!(sc->lct = malloc(reply->table_size * sizeof(struct i2o_lct_entry),
306			   M_PSTIOP, M_NOWAIT | M_ZERO))) {
307	contigfree(reply, ALLOCSIZE, M_PSTIOP);
308	return 0;
309    }
310    bcopy(&reply->entry[0], sc->lct,
311	  reply->table_size * sizeof(struct i2o_lct_entry));
312    sc->lct_count = reply->table_size;
313    contigfree(reply, ALLOCSIZE, M_PSTIOP);
314    return 1;
315}
316
317struct i2o_get_param_reply *
318iop_get_util_params(struct iop_softc *sc, int target, int operation, int group)
319{
320    struct i2o_util_get_param_message *msg;
321    struct i2o_get_param_operation *param;
322    struct i2o_get_param_reply *reply;
323    int mfa;
324
325    if (!(param = contigmalloc(PAGE_SIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
326			       0, 0xFFFFFFFF, sizeof(u_int32_t), 0)))
327	return NULL;
328
329    if (!(reply = contigmalloc(PAGE_SIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
330			       0, 0xFFFFFFFF, sizeof(u_int32_t), 0)))
331	return NULL;
332
333    mfa = iop_get_mfa(sc);
334    msg = (struct i2o_util_get_param_message *)(sc->ibase + mfa);
335    bzero(msg, sizeof(struct i2o_util_get_param_message));
336    msg->version_offset = 0x51;
337    msg->message_flags = 0x0;
338    msg->message_size = sizeof(struct i2o_util_get_param_message) >> 2;
339    msg->target_address = target;
340    msg->initiator_address = I2O_TID_HOST;
341    msg->function = I2O_UTIL_PARAMS_GET;
342    msg->operation_flags = 0;
343
344    param->operation_count = 1;
345    param->operation[0].operation = operation;
346    param->operation[0].group = group;
347    param->operation[0].field_count = 0xffff;
348
349    msg->sgl[0].flags = I2O_SGL_SIMPLE | I2O_SGL_DIR | I2O_SGL_EOB;
350    msg->sgl[0].count = sizeof(struct i2o_get_param_operation);
351    msg->sgl[0].phys_addr[0] = vtophys(param);
352
353    msg->sgl[1].flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
354    msg->sgl[1].count = PAGE_SIZE;
355    msg->sgl[1].phys_addr[0] = vtophys(reply);
356
357    if (iop_queue_wait_msg(sc, mfa, (struct i2o_basic_message *)msg) ||
358	reply->error_info_size) {
359	contigfree(reply, PAGE_SIZE, M_PSTIOP);
360	reply = NULL;
361    }
362    contigfree(param, PAGE_SIZE, M_PSTIOP);
363    return reply;
364}
365
366u_int32_t
367iop_get_mfa(struct iop_softc *sc)
368{
369    u_int32_t mfa;
370    int timeout = 10000;
371
372    while ((mfa = sc->reg->iqueue) == 0xffffffff && timeout) {
373	DELAY(1000);
374	timeout--;
375    }
376    if (!timeout)
377	printf("pstiop: no free mfa\n");
378    return mfa;
379}
380
381void
382iop_free_mfa(struct iop_softc *sc, int mfa)
383{
384    struct i2o_basic_message *msg = (struct i2o_basic_message *)(sc->ibase+mfa);
385
386    bzero(msg, sizeof(struct i2o_basic_message));
387    msg->version = 0x01;
388    msg->message_flags = 0x0;
389    msg->message_size = sizeof(struct i2o_basic_message) >> 2;
390    msg->target_address = I2O_TID_IOP;
391    msg->initiator_address = I2O_TID_HOST;
392    msg->function = I2O_UTIL_NOP;
393    sc->reg->iqueue = mfa;
394}
395
396int
397iop_queue_wait_msg(struct iop_softc *sc, int mfa, struct i2o_basic_message *msg)
398{
399    struct i2o_single_reply *reply;
400    int out_mfa, status, timeout = 10000;
401
402    sc->reg->iqueue = mfa;
403
404    while (--timeout && ((out_mfa = sc->reg->oqueue) == 0xffffffff))
405	DELAY(1000);
406    if (!timeout) {
407	printf("pstiop: timeout waiting for message response\n");
408	iop_free_mfa(sc, mfa);
409	return -1;
410    }
411
412    reply = (struct i2o_single_reply *)(sc->obase + (out_mfa - sc->phys_obase));
413    status = reply->status;
414    sc->reg->oqueue = out_mfa;
415    return status;
416}
417
418int
419iop_create_sgl(struct i2o_basic_message *msg, caddr_t data, int count, int dir)
420{
421    struct i2o_sgl *sgl = (struct i2o_sgl *)((int32_t *)msg + msg->offset);
422    u_int32_t sgl_count, sgl_phys;
423    int i = 0;
424
425    if (((uintptr_t)data & 3) || (count & 3)) {
426	printf("pstiop: non aligned DMA transfer attempted\n");
427	return 0;
428    }
429    if (!count) {
430	printf("pstiop: zero length DMA transfer attempted\n");
431	return 0;
432    }
433
434    sgl_count = min(count, (PAGE_SIZE - ((uintptr_t)data & PAGE_MASK)));
435    sgl_phys = vtophys(data);
436    sgl->flags = dir | I2O_SGL_PAGELIST | I2O_SGL_EOB | I2O_SGL_END;
437    sgl->count = count;
438    data += sgl_count;
439    count -= sgl_count;
440
441    while (count) {
442	sgl->phys_addr[i] = sgl_phys;
443	sgl_phys = vtophys(data);
444	data += min(count, PAGE_SIZE);
445	count -= min(count, PAGE_SIZE);
446	if (++i >= I2O_SGL_MAX_SEGS) {
447	    printf("pstiop: too many segments in SGL\n");
448	    return 0;
449	}
450    }
451    sgl->phys_addr[i] = sgl_phys;
452    msg->message_size += i;
453    return 1;
454}
455