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