1101100Ssos/*-
2114154Ssos * Copyright (c) 2001,2002,2003 S�ren Schmidt <sos@FreeBSD.org>
3101100Ssos * All rights reserved.
4101100Ssos *
5101100Ssos * Redistribution and use in source and binary forms, with or without
6101100Ssos * modification, are permitted provided that the following conditions
7101100Ssos * are met:
8101100Ssos * 1. Redistributions of source code must retain the above copyright
9101100Ssos *    notice, this list of conditions and the following disclaimer,
10101100Ssos *    without modification, immediately at the beginning of the file.
11101100Ssos * 2. Redistributions in binary form must reproduce the above copyright
12101100Ssos *    notice, this list of conditions and the following disclaimer in the
13101100Ssos *    documentation and/or other materials provided with the distribution.
14101100Ssos * 3. The name of the author may not be used to endorse or promote products
15101100Ssos *    derived from this software without specific prior written permission.
16101100Ssos *
17101100Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18101100Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19101100Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20101100Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21101100Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22101100Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23101100Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24101100Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25101100Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26101100Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27101100Ssos */
28101100Ssos
29119418Sobrien#include <sys/cdefs.h>
30119418Sobrien__FBSDID("$FreeBSD$");
31119418Sobrien
32101100Ssos#include <sys/param.h>
33101100Ssos#include <sys/systm.h>
34101100Ssos#include <sys/kernel.h>
35101100Ssos#include <sys/module.h>
36101100Ssos#include <sys/bus.h>
37101100Ssos#include <sys/bio.h>
38101100Ssos#include <sys/malloc.h>
39114154Ssos#include <sys/lock.h>
40114154Ssos#include <sys/mutex.h>
41101100Ssos#include <vm/vm.h>
42101100Ssos#include <vm/pmap.h>
43101100Ssos#include <machine/stdarg.h>
44101100Ssos#include <machine/resource.h>
45101100Ssos#include <machine/bus.h>
46101100Ssos#include <sys/rman.h>
47119285Simp#include <dev/pci/pcivar.h>
48119285Simp#include <dev/pci/pcireg.h>
49101100Ssos
50101100Ssos#include "dev/pst/pst-iop.h"
51101100Ssos
52114154Ssosstruct iop_request {
53114154Ssos    struct i2o_single_reply *reply;
54114154Ssos    u_int32_t mfa;
55114154Ssos};
56114154Ssos
57101100Ssos/* local vars */
58101100SsosMALLOC_DEFINE(M_PSTIOP, "PSTIOP", "Promise SuperTrak IOP driver");
59101100Ssos
60101100Ssosint
61101100Ssosiop_init(struct iop_softc *sc)
62101100Ssos{
63101100Ssos    int mfa, timeout = 10000;
64101100Ssos
65101100Ssos    while ((mfa = sc->reg->iqueue) == 0xffffffff && --timeout)
66101100Ssos	DELAY(1000);
67101100Ssos    if (!timeout) {
68101100Ssos	printf("pstiop: no free mfa\n");
69101100Ssos	return 0;
70101100Ssos    }
71101100Ssos    iop_free_mfa(sc, mfa);
72101100Ssos
73101100Ssos    sc->reg->oqueue_intr_mask = 0xffffffff;
74101100Ssos
75101100Ssos    if (!iop_reset(sc)) {
76101100Ssos	printf("pstiop: no reset response\n");
77101100Ssos	return 0;
78101100Ssos    }
79101100Ssos
80101100Ssos    if (!iop_init_outqueue(sc)) {
81101100Ssos	printf("pstiop: init outbound queue failed\n");
82101100Ssos	return 0;
83101100Ssos    }
84101100Ssos
85101100Ssos    /* register iop_attach to be run when interrupts are enabled */
86101100Ssos    if (!(sc->iop_delayed_attach = (struct intr_config_hook *)
87108533Sschweikh				   malloc(sizeof(struct intr_config_hook),
88101100Ssos				   M_PSTIOP, M_NOWAIT | M_ZERO))) {
89101100Ssos	printf("pstiop: malloc of delayed attach hook failed\n");
90101100Ssos	return 0;
91101100Ssos    }
92136094Sstefanf    sc->iop_delayed_attach->ich_func = iop_attach;
93136094Sstefanf    sc->iop_delayed_attach->ich_arg = sc;
94101100Ssos    if (config_intrhook_establish(sc->iop_delayed_attach)) {
95101100Ssos	printf("pstiop: config_intrhook_establish failed\n");
96101100Ssos	free(sc->iop_delayed_attach, M_PSTIOP);
97101100Ssos    }
98101100Ssos    return 1;
99101100Ssos}
100101100Ssos
101101100Ssosvoid
102136094Sstefanfiop_attach(void *arg)
103101100Ssos{
104136094Sstefanf    struct iop_softc *sc;
105101100Ssos    int i;
106101100Ssos
107136094Sstefanf    sc = arg;
108101100Ssos    if (sc->iop_delayed_attach) {
109101100Ssos	config_intrhook_disestablish(sc->iop_delayed_attach);
110101100Ssos	free(sc->iop_delayed_attach, M_PSTIOP);
111101100Ssos	sc->iop_delayed_attach = NULL;
112101100Ssos    }
113101100Ssos
114101100Ssos    if (!iop_get_lct(sc)) {
115101100Ssos	printf("pstiop: get LCT failed\n");
116101100Ssos	return;
117101100Ssos    }
118101100Ssos
119101100Ssos    /* figure out what devices are here and config as needed */
120101100Ssos    for (i = 0; sc->lct[i].entry_size == I2O_LCT_ENTRYSIZE; i++) {
121101100Ssos#ifdef PSTDEBUG
122101100Ssos	struct i2o_get_param_reply *reply;
123101100Ssos
124101100Ssos	printf("pstiop: LCT entry %d ", i);
125101100Ssos	printf("class=%04x ", sc->lct[i].class);
126101100Ssos	printf("sub=%04x ", sc->lct[i].sub_class);
127101100Ssos	printf("localtid=%04x ", sc->lct[i].local_tid);
128101100Ssos	printf("usertid=%04x ", sc->lct[i].user_tid);
129101100Ssos	printf("parentid=%04x\n", sc->lct[i].parent_tid);
130101100Ssos
131101100Ssos	if ((reply = iop_get_util_params(sc, sc->lct[i].local_tid,
132101100Ssos					 I2O_PARAMS_OPERATION_FIELD_GET,
133101100Ssos					 I2O_UTIL_DEVICE_IDENTITY_GROUP_NO))) {
134101100Ssos	    struct i2o_device_identity *ident =
135101100Ssos		(struct i2o_device_identity *)reply->result;
136101100Ssos	    printf("pstiop: vendor=<%.16s> product=<%.16s>\n",
137101100Ssos		   ident->vendor, ident->product);
138101100Ssos	    printf("pstiop: description=<%.16s> revision=<%.8s>\n",
139101100Ssos		   ident->description, ident->revision);
140101100Ssos	    contigfree(reply, PAGE_SIZE, M_PSTIOP);
141101100Ssos	}
142101100Ssos#endif
143101100Ssos
144101100Ssos	if (sc->lct[i].user_tid != I2O_TID_NONE &&
145101100Ssos	    sc->lct[i].user_tid != I2O_TID_HOST)
146101100Ssos	    continue;
147101100Ssos
148101100Ssos	switch (sc->lct[i].class) {
149114154Ssos	case I2O_CLASS_DDM:
150114154Ssos	    if (sc->lct[i].sub_class == I2O_SUBCLASS_ISM)
151114154Ssos		sc->ism = sc->lct[i].local_tid;
152114154Ssos	    break;
153114154Ssos
154101100Ssos	case I2O_CLASS_RANDOM_BLOCK_STORAGE:
155101100Ssos	    pst_add_raid(sc, &sc->lct[i]);
156101100Ssos	    break;
157101100Ssos	}
158101100Ssos    }
159114154Ssos
160101100Ssos    /* setup and enable interrupts */
161114154Ssos    bus_setup_intr(sc->dev, sc->r_irq, INTR_TYPE_BIO|INTR_ENTROPY|INTR_MPSAFE,
162166901Spiso		   NULL, iop_intr, sc, &sc->handle);
163101100Ssos    sc->reg->oqueue_intr_mask = 0x0;
164101100Ssos}
165101100Ssos
166101100Ssosvoid
167101100Ssosiop_intr(void *data)
168101100Ssos{
169101100Ssos    struct iop_softc *sc = (struct iop_softc *)data;
170101100Ssos    struct i2o_single_reply *reply;
171101100Ssos    u_int32_t mfa;
172101100Ssos
173102058Ssos    /* we might get more than one finished request pr interrupt */
174114154Ssos    mtx_lock(&sc->mtx);
175102058Ssos    while (1) {
176102058Ssos	if ((mfa = sc->reg->oqueue) == 0xffffffff)
177102058Ssos	    if ((mfa = sc->reg->oqueue) == 0xffffffff)
178114154Ssos		break;
179102058Ssos
180102058Ssos	reply = (struct i2o_single_reply *)(sc->obase + (mfa - sc->phys_obase));
181102058Ssos
182114154Ssos	/* if this is an event register reply, shout! */
183102058Ssos	if (reply->function == I2O_UTIL_EVENT_REGISTER) {
184108533Sschweikh	    struct i2o_util_event_reply_message *event =
185102058Ssos		(struct i2o_util_event_reply_message *)reply;
186102058Ssos
187102058Ssos	    printf("pstiop: EVENT!! idx=%08x data=%08x\n",
188102058Ssos		   event->event_mask, event->event_data[0]);
189114154Ssos	    break;
190101100Ssos	}
191101100Ssos
192102058Ssos	/* if reply is a failurenotice we need to free the original mfa */
193102058Ssos	if (reply->message_flags & I2O_MESSAGE_FLAGS_FAIL)
194102058Ssos	    iop_free_mfa(sc,((struct i2o_fault_reply *)(reply))->preserved_mfa);
195108533Sschweikh
196102058Ssos	/* reply->initiator_context points to the service routine */
197102058Ssos	((void (*)(struct iop_softc *, u_int32_t, struct i2o_single_reply *))
198102058Ssos	    (reply->initiator_context))(sc, mfa, reply);
199101100Ssos    }
200114154Ssos    mtx_unlock(&sc->mtx);
201101100Ssos}
202101100Ssos
203101100Ssosint
204101100Ssosiop_reset(struct iop_softc *sc)
205101100Ssos{
206101100Ssos    struct i2o_exec_iop_reset_message *msg;
207101100Ssos    int mfa, timeout = 5000;
208102058Ssos    volatile u_int32_t reply = 0;
209101100Ssos
210101100Ssos    mfa = iop_get_mfa(sc);
211101100Ssos    msg = (struct i2o_exec_iop_reset_message *)(sc->ibase + mfa);
212101100Ssos    bzero(msg, sizeof(struct i2o_exec_iop_reset_message));
213101100Ssos    msg->version_offset = 0x1;
214101100Ssos    msg->message_flags = 0x0;
215101100Ssos    msg->message_size = sizeof(struct i2o_exec_iop_reset_message) >> 2;
216101100Ssos    msg->target_address = I2O_TID_IOP;
217101100Ssos    msg->initiator_address = I2O_TID_HOST;
218101100Ssos    msg->function = I2O_EXEC_IOP_RESET;
219101100Ssos    msg->status_word_low_addr = vtophys(&reply);
220101100Ssos    msg->status_word_high_addr = 0;
221101100Ssos
222101100Ssos    sc->reg->iqueue = mfa;
223101100Ssos
224101100Ssos    while (--timeout && !reply)
225101100Ssos	DELAY(1000);
226101100Ssos
227101100Ssos    /* wait for iqueue ready */
228101100Ssos    timeout = 10000;
229101100Ssos    while ((mfa = sc->reg->iqueue) == 0xffffffff && --timeout)
230101100Ssos	DELAY(1000);
231102058Ssos
232101100Ssos    iop_free_mfa(sc, mfa);
233101100Ssos    return reply;
234101100Ssos}
235101100Ssos
236101100Ssosint
237101100Ssosiop_init_outqueue(struct iop_softc *sc)
238101100Ssos{
239101100Ssos    struct i2o_exec_init_outqueue_message *msg;
240101100Ssos    int i, mfa, timeout = 5000;
241102058Ssos    volatile u_int32_t reply = 0;
242101100Ssos
243101100Ssos    if (!(sc->obase = contigmalloc(I2O_IOP_OUTBOUND_FRAME_COUNT *
244101100Ssos				   I2O_IOP_OUTBOUND_FRAME_SIZE,
245101100Ssos				   M_PSTIOP, M_NOWAIT,
246102058Ssos				   0x00010000, 0xFFFFFFFF,
247114154Ssos				   PAGE_SIZE, 0))) {
248101100Ssos	printf("pstiop: contigmalloc of outqueue buffers failed!\n");
249101100Ssos	return 0;
250101100Ssos    }
251101100Ssos    sc->phys_obase = vtophys(sc->obase);
252101100Ssos    mfa = iop_get_mfa(sc);
253101100Ssos    msg = (struct i2o_exec_init_outqueue_message *)(sc->ibase + mfa);
254101100Ssos    bzero(msg, sizeof(struct i2o_exec_init_outqueue_message));
255101100Ssos    msg->version_offset = 0x61;
256101100Ssos    msg->message_flags = 0x0;
257101100Ssos    msg->message_size = sizeof(struct i2o_exec_init_outqueue_message) >> 2;
258101100Ssos    msg->target_address = I2O_TID_IOP;
259101100Ssos    msg->initiator_address = I2O_TID_HOST;
260101100Ssos    msg->function = I2O_EXEC_OUTBOUND_INIT;
261101100Ssos    msg->host_pagesize = PAGE_SIZE;
262101100Ssos    msg->init_code = 0x00; /* SOS XXX should be 0x80 == OS */
263101100Ssos    msg->queue_framesize = I2O_IOP_OUTBOUND_FRAME_SIZE / sizeof(u_int32_t);
264101100Ssos    msg->sgl[0].flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
265101100Ssos    msg->sgl[0].count = sizeof(reply);
266101100Ssos    msg->sgl[0].phys_addr[0] = vtophys(&reply);
267101100Ssos    msg->sgl[1].flags = I2O_SGL_END | I2O_SGL_EOB;
268101100Ssos    msg->sgl[1].count = 1;
269101100Ssos    msg->sgl[1].phys_addr[0] = 0;
270101100Ssos
271101100Ssos    sc->reg->iqueue = mfa;
272101100Ssos
273101100Ssos    /* wait for init to complete */
274101100Ssos    while (--timeout && reply != I2O_EXEC_OUTBOUND_INIT_COMPLETE)
275101100Ssos	DELAY(1000);
276108533Sschweikh
277101100Ssos    if (!timeout) {
278101100Ssos	printf("pstiop: timeout waiting for init-complete response\n");
279101100Ssos	iop_free_mfa(sc, mfa);
280101100Ssos	return 0;
281101100Ssos    }
282101100Ssos
283101100Ssos    /* now init our oqueue bufs */
284101100Ssos    for (i = 0; i < I2O_IOP_OUTBOUND_FRAME_COUNT; i++) {
285101100Ssos	sc->reg->oqueue = sc->phys_obase + (i * I2O_IOP_OUTBOUND_FRAME_SIZE);
286101100Ssos	DELAY(1000);
287101100Ssos    }
288101100Ssos
289101100Ssos    return 1;
290101100Ssos}
291101100Ssos
292101100Ssosint
293101100Ssosiop_get_lct(struct iop_softc *sc)
294101100Ssos{
295101100Ssos    struct i2o_exec_get_lct_message *msg;
296101100Ssos    struct i2o_get_lct_reply *reply;
297101100Ssos    int mfa;
298101100Ssos#define ALLOCSIZE	 (PAGE_SIZE + (256 * sizeof(struct i2o_lct_entry)))
299101100Ssos
300101100Ssos    if (!(reply = contigmalloc(ALLOCSIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
301114154Ssos			       0x00010000, 0xFFFFFFFF, PAGE_SIZE, 0)))
302101100Ssos	return 0;
303101100Ssos
304101100Ssos    mfa = iop_get_mfa(sc);
305101100Ssos    msg = (struct i2o_exec_get_lct_message *)(sc->ibase + mfa);
306101100Ssos    bzero(msg, sizeof(struct i2o_exec_get_lct_message));
307101100Ssos    msg->version_offset = 0x61;
308101100Ssos    msg->message_flags = 0x0;
309101100Ssos    msg->message_size = sizeof(struct i2o_exec_get_lct_message) >> 2;
310101100Ssos    msg->target_address = I2O_TID_IOP;
311101100Ssos    msg->initiator_address = I2O_TID_HOST;
312101100Ssos    msg->function = I2O_EXEC_LCT_NOTIFY;
313101100Ssos    msg->class = I2O_CLASS_MATCH_ANYCLASS;
314101100Ssos    msg->last_change_id = 0;
315101100Ssos
316101100Ssos    msg->sgl.flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
317101100Ssos    msg->sgl.count = ALLOCSIZE;
318101100Ssos    msg->sgl.phys_addr[0] = vtophys(reply);
319101100Ssos
320101100Ssos    if (iop_queue_wait_msg(sc, mfa, (struct i2o_basic_message *)msg)) {
321101100Ssos	contigfree(reply, ALLOCSIZE, M_PSTIOP);
322101100Ssos	return 0;
323101100Ssos    }
324101100Ssos    if (!(sc->lct = malloc(reply->table_size * sizeof(struct i2o_lct_entry),
325101100Ssos			   M_PSTIOP, M_NOWAIT | M_ZERO))) {
326101100Ssos	contigfree(reply, ALLOCSIZE, M_PSTIOP);
327101100Ssos	return 0;
328101100Ssos    }
329108533Sschweikh    bcopy(&reply->entry[0], sc->lct,
330101100Ssos	  reply->table_size * sizeof(struct i2o_lct_entry));
331101100Ssos    sc->lct_count = reply->table_size;
332101100Ssos    contigfree(reply, ALLOCSIZE, M_PSTIOP);
333101100Ssos    return 1;
334101100Ssos}
335101100Ssos
336101100Ssosstruct i2o_get_param_reply *
337101100Ssosiop_get_util_params(struct iop_softc *sc, int target, int operation, int group)
338101100Ssos{
339101100Ssos    struct i2o_util_get_param_message *msg;
340101100Ssos    struct i2o_get_param_operation *param;
341101100Ssos    struct i2o_get_param_reply *reply;
342101100Ssos    int mfa;
343101100Ssos
344101100Ssos    if (!(param = contigmalloc(PAGE_SIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
345114154Ssos			       0x00010000, 0xFFFFFFFF, PAGE_SIZE, 0)))
346101100Ssos	return NULL;
347101100Ssos
348101100Ssos    if (!(reply = contigmalloc(PAGE_SIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
349114154Ssos			       0x00010000, 0xFFFFFFFF, PAGE_SIZE, 0)))
350101100Ssos	return NULL;
351101100Ssos
352101100Ssos    mfa = iop_get_mfa(sc);
353101100Ssos    msg = (struct i2o_util_get_param_message *)(sc->ibase + mfa);
354101100Ssos    bzero(msg, sizeof(struct i2o_util_get_param_message));
355101100Ssos    msg->version_offset = 0x51;
356101100Ssos    msg->message_flags = 0x0;
357101100Ssos    msg->message_size = sizeof(struct i2o_util_get_param_message) >> 2;
358101100Ssos    msg->target_address = target;
359101100Ssos    msg->initiator_address = I2O_TID_HOST;
360101100Ssos    msg->function = I2O_UTIL_PARAMS_GET;
361101100Ssos    msg->operation_flags = 0;
362101100Ssos
363101100Ssos    param->operation_count = 1;
364101100Ssos    param->operation[0].operation = operation;
365101100Ssos    param->operation[0].group = group;
366101100Ssos    param->operation[0].field_count = 0xffff;
367101100Ssos
368101100Ssos    msg->sgl[0].flags = I2O_SGL_SIMPLE | I2O_SGL_DIR | I2O_SGL_EOB;
369101100Ssos    msg->sgl[0].count = sizeof(struct i2o_get_param_operation);
370101100Ssos    msg->sgl[0].phys_addr[0] = vtophys(param);
371101100Ssos
372101100Ssos    msg->sgl[1].flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
373101100Ssos    msg->sgl[1].count = PAGE_SIZE;
374101100Ssos    msg->sgl[1].phys_addr[0] = vtophys(reply);
375101100Ssos
376101100Ssos    if (iop_queue_wait_msg(sc, mfa, (struct i2o_basic_message *)msg) ||
377101100Ssos	reply->error_info_size) {
378101100Ssos	contigfree(reply, PAGE_SIZE, M_PSTIOP);
379101100Ssos	reply = NULL;
380101100Ssos    }
381101100Ssos    contigfree(param, PAGE_SIZE, M_PSTIOP);
382101100Ssos    return reply;
383101100Ssos}
384101100Ssos
385101100Ssosu_int32_t
386101100Ssosiop_get_mfa(struct iop_softc *sc)
387101100Ssos{
388101100Ssos    u_int32_t mfa;
389101100Ssos    int timeout = 10000;
390101100Ssos
391101100Ssos    while ((mfa = sc->reg->iqueue) == 0xffffffff && timeout) {
392101100Ssos	DELAY(1000);
393101100Ssos	timeout--;
394101100Ssos    }
395101100Ssos    if (!timeout)
396101100Ssos	printf("pstiop: no free mfa\n");
397101100Ssos    return mfa;
398101100Ssos}
399101100Ssos
400101100Ssosvoid
401101100Ssosiop_free_mfa(struct iop_softc *sc, int mfa)
402101100Ssos{
403101100Ssos    struct i2o_basic_message *msg = (struct i2o_basic_message *)(sc->ibase+mfa);
404101100Ssos
405101100Ssos    bzero(msg, sizeof(struct i2o_basic_message));
406101100Ssos    msg->version = 0x01;
407101100Ssos    msg->message_flags = 0x0;
408101100Ssos    msg->message_size = sizeof(struct i2o_basic_message) >> 2;
409101100Ssos    msg->target_address = I2O_TID_IOP;
410101100Ssos    msg->initiator_address = I2O_TID_HOST;
411101100Ssos    msg->function = I2O_UTIL_NOP;
412101100Ssos    sc->reg->iqueue = mfa;
413101100Ssos}
414101100Ssos
415114154Ssosstatic void
416114154Ssosiop_done(struct iop_softc *sc, u_int32_t mfa, struct i2o_single_reply *reply)
417114154Ssos{
418114154Ssos    struct iop_request *request =
419114154Ssos        (struct iop_request *)reply->transaction_context;
420114154Ssos
421114154Ssos    request->reply = reply;
422114154Ssos    request->mfa = mfa;
423114154Ssos    wakeup(request);
424114154Ssos}
425114154Ssos
426101100Ssosint
427101100Ssosiop_queue_wait_msg(struct iop_softc *sc, int mfa, struct i2o_basic_message *msg)
428101100Ssos{
429101100Ssos    struct i2o_single_reply *reply;
430114154Ssos    struct iop_request request;
431114154Ssos    u_int32_t out_mfa;
432114154Ssos    int status, timeout = 10000;
433101100Ssos
434114154Ssos    mtx_lock(&sc->mtx);
435114154Ssos    if (!(sc->reg->oqueue_intr_mask & 0x08)) {
436114154Ssos        msg->transaction_context = (u_int32_t)&request;
437114154Ssos        msg->initiator_context = (u_int32_t)iop_done;
438114154Ssos        sc->reg->iqueue = mfa;
439114154Ssos        if (msleep(&request, &sc->mtx, PRIBIO, "pstwt", 10 * hz)) {
440114154Ssos	    printf("pstiop: timeout waiting for message response\n");
441114154Ssos	    iop_free_mfa(sc, mfa);
442114154Ssos	    mtx_unlock(&sc->mtx);
443114154Ssos	    return -1;
444114154Ssos	}
445114154Ssos        status = request.reply->status;
446114154Ssos        sc->reg->oqueue = request.mfa;
447101100Ssos    }
448114154Ssos    else {
449114154Ssos	sc->reg->iqueue = mfa;
450114154Ssos	while (--timeout && ((out_mfa = sc->reg->oqueue) == 0xffffffff))
451114154Ssos	    DELAY(1000);
452114154Ssos	if (!timeout) {
453114154Ssos	    printf("pstiop: timeout waiting for message response\n");
454114154Ssos	    iop_free_mfa(sc, mfa);
455114154Ssos	    mtx_unlock(&sc->mtx);
456114154Ssos	    return -1;
457114154Ssos	}
458114154Ssos	reply = (struct i2o_single_reply *)(sc->obase+(out_mfa-sc->phys_obase));
459114154Ssos	status = reply->status;
460114154Ssos	sc->reg->oqueue = out_mfa;
461114154Ssos    }
462114154Ssos    mtx_unlock(&sc->mtx);
463101100Ssos    return status;
464101100Ssos}
465101100Ssos
466101100Ssosint
467101100Ssosiop_create_sgl(struct i2o_basic_message *msg, caddr_t data, int count, int dir)
468101100Ssos{
469101100Ssos    struct i2o_sgl *sgl = (struct i2o_sgl *)((int32_t *)msg + msg->offset);
470101100Ssos    u_int32_t sgl_count, sgl_phys;
471101100Ssos    int i = 0;
472101100Ssos
473101100Ssos    if (((uintptr_t)data & 3) || (count & 3)) {
474101100Ssos	printf("pstiop: non aligned DMA transfer attempted\n");
475101100Ssos	return 0;
476101100Ssos    }
477101100Ssos    if (!count) {
478101100Ssos	printf("pstiop: zero length DMA transfer attempted\n");
479101100Ssos	return 0;
480101100Ssos    }
481108533Sschweikh
482101100Ssos    sgl_count = min(count, (PAGE_SIZE - ((uintptr_t)data & PAGE_MASK)));
483101100Ssos    sgl_phys = vtophys(data);
484101100Ssos    sgl->flags = dir | I2O_SGL_PAGELIST | I2O_SGL_EOB | I2O_SGL_END;
485101100Ssos    sgl->count = count;
486101100Ssos    data += sgl_count;
487101100Ssos    count -= sgl_count;
488101100Ssos
489101100Ssos    while (count) {
490101100Ssos	sgl->phys_addr[i] = sgl_phys;
491101100Ssos	sgl_phys = vtophys(data);
492101100Ssos	data += min(count, PAGE_SIZE);
493101100Ssos	count -= min(count, PAGE_SIZE);
494101100Ssos	if (++i >= I2O_SGL_MAX_SEGS) {
495101100Ssos	    printf("pstiop: too many segments in SGL\n");
496101100Ssos	    return 0;
497101100Ssos	}
498101100Ssos    }
499101100Ssos    sgl->phys_addr[i] = sgl_phys;
500101100Ssos    msg->message_size += i;
501101100Ssos    return 1;
502101100Ssos}
503