pst-iop.c revision 101100
1101100Ssos/*- 2101100Ssos * Copyright (c) 2001,2002 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 * $FreeBSD: head/sys/dev/pst/pst-iop.c 101100 2002-07-31 18:26:30Z sos $ 29101100Ssos */ 30101100Ssos 31101100Ssos#include <sys/param.h> 32101100Ssos#include <sys/systm.h> 33101100Ssos#include <sys/kernel.h> 34101100Ssos#include <sys/module.h> 35101100Ssos#include <sys/bus.h> 36101100Ssos#include <sys/bio.h> 37101100Ssos#include <sys/malloc.h> 38101100Ssos#include <vm/vm.h> 39101100Ssos#include <vm/pmap.h> 40101100Ssos#include <machine/stdarg.h> 41101100Ssos#include <machine/resource.h> 42101100Ssos#include <machine/bus.h> 43101100Ssos#include <sys/rman.h> 44101100Ssos#include <pci/pcivar.h> 45101100Ssos#include <pci/pcireg.h> 46101100Ssos 47101100Ssos#include "dev/pst/pst-iop.h" 48101100Ssos 49101100Ssos/* local vars */ 50101100SsosMALLOC_DEFINE(M_PSTIOP, "PSTIOP", "Promise SuperTrak IOP driver"); 51101100Ssos 52101100Ssosint 53101100Ssosiop_init(struct iop_softc *sc) 54101100Ssos{ 55101100Ssos int mfa, timeout = 10000; 56101100Ssos 57101100Ssos while ((mfa = sc->reg->iqueue) == 0xffffffff && --timeout) 58101100Ssos DELAY(1000); 59101100Ssos if (!timeout) { 60101100Ssos printf("pstiop: no free mfa\n"); 61101100Ssos return 0; 62101100Ssos } 63101100Ssos iop_free_mfa(sc, mfa); 64101100Ssos 65101100Ssos sc->reg->oqueue_intr_mask = 0xffffffff; 66101100Ssos 67101100Ssos if (!iop_reset(sc)) { 68101100Ssos printf("pstiop: no reset response\n"); 69101100Ssos return 0; 70101100Ssos } 71101100Ssos 72101100Ssos if (!iop_init_outqueue(sc)) { 73101100Ssos printf("pstiop: init outbound queue failed\n"); 74101100Ssos return 0; 75101100Ssos } 76101100Ssos 77101100Ssos /* register iop_attach to be run when interrupts are enabled */ 78101100Ssos if (!(sc->iop_delayed_attach = (struct intr_config_hook *) 79101100Ssos malloc(sizeof(struct intr_config_hook), 80101100Ssos M_PSTIOP, M_NOWAIT | M_ZERO))) { 81101100Ssos printf("pstiop: malloc of delayed attach hook failed\n"); 82101100Ssos return 0; 83101100Ssos } 84101100Ssos sc->iop_delayed_attach->ich_func = (void *)iop_attach; 85101100Ssos sc->iop_delayed_attach->ich_arg = (void *)sc; 86101100Ssos if (config_intrhook_establish(sc->iop_delayed_attach)) { 87101100Ssos printf("pstiop: config_intrhook_establish failed\n"); 88101100Ssos free(sc->iop_delayed_attach, M_PSTIOP); 89101100Ssos } 90101100Ssos return 1; 91101100Ssos} 92101100Ssos 93101100Ssosvoid 94101100Ssosiop_attach(struct iop_softc *sc) 95101100Ssos{ 96101100Ssos int i; 97101100Ssos 98101100Ssos if (sc->iop_delayed_attach) { 99101100Ssos config_intrhook_disestablish(sc->iop_delayed_attach); 100101100Ssos free(sc->iop_delayed_attach, M_PSTIOP); 101101100Ssos sc->iop_delayed_attach = NULL; 102101100Ssos } 103101100Ssos 104101100Ssos if (!iop_get_lct(sc)) { 105101100Ssos printf("pstiop: get LCT failed\n"); 106101100Ssos return; 107101100Ssos } 108101100Ssos 109101100Ssos /* figure out what devices are here and config as needed */ 110101100Ssos for (i = 0; sc->lct[i].entry_size == I2O_LCT_ENTRYSIZE; i++) { 111101100Ssos#ifdef PSTDEBUG 112101100Ssos struct i2o_get_param_reply *reply; 113101100Ssos 114101100Ssos printf("pstiop: LCT entry %d ", i); 115101100Ssos printf("class=%04x ", sc->lct[i].class); 116101100Ssos printf("sub=%04x ", sc->lct[i].sub_class); 117101100Ssos printf("localtid=%04x ", sc->lct[i].local_tid); 118101100Ssos printf("usertid=%04x ", sc->lct[i].user_tid); 119101100Ssos printf("parentid=%04x\n", sc->lct[i].parent_tid); 120101100Ssos 121101100Ssos if ((reply = iop_get_util_params(sc, sc->lct[i].local_tid, 122101100Ssos I2O_PARAMS_OPERATION_FIELD_GET, 123101100Ssos I2O_UTIL_DEVICE_IDENTITY_GROUP_NO))) { 124101100Ssos struct i2o_device_identity *ident = 125101100Ssos (struct i2o_device_identity *)reply->result; 126101100Ssos printf("pstiop: vendor=<%.16s> product=<%.16s>\n", 127101100Ssos ident->vendor, ident->product); 128101100Ssos printf("pstiop: description=<%.16s> revision=<%.8s>\n", 129101100Ssos ident->description, ident->revision); 130101100Ssos contigfree(reply, PAGE_SIZE, M_PSTIOP); 131101100Ssos } 132101100Ssos#endif 133101100Ssos 134101100Ssos if (sc->lct[i].user_tid != I2O_TID_NONE && 135101100Ssos sc->lct[i].user_tid != I2O_TID_HOST) 136101100Ssos continue; 137101100Ssos 138101100Ssos switch (sc->lct[i].class) { 139101100Ssos case I2O_CLASS_RANDOM_BLOCK_STORAGE: 140101100Ssos pst_add_raid(sc, &sc->lct[i]); 141101100Ssos break; 142101100Ssos } 143101100Ssos } 144101100Ssos /* setup and enable interrupts */ 145101100Ssos bus_setup_intr(sc->dev, sc->r_irq, INTR_TYPE_BIO | INTR_ENTROPY, 146101100Ssos iop_intr, sc, &sc->handle); 147101100Ssos sc->reg->oqueue_intr_mask = 0x0; 148101100Ssos} 149101100Ssos 150101100Ssosvoid 151101100Ssosiop_intr(void *data) 152101100Ssos{ 153101100Ssos struct iop_softc *sc = (struct iop_softc *)data; 154101100Ssos struct i2o_single_reply *reply; 155101100Ssos u_int32_t mfa; 156101100Ssos 157101100Ssos if ((mfa = sc->reg->oqueue) == 0xffffffff) { 158101100Ssos if ((mfa = sc->reg->oqueue) == 0xffffffff) { 159101100Ssos printf("pstiop: no mfa on interrupt ?\n"); 160101100Ssos return; 161101100Ssos } 162101100Ssos } 163101100Ssos reply = (struct i2o_single_reply *)(sc->obase + (mfa - sc->phys_obase)); 164101100Ssos 165101100Ssos /* if this is a event register reply, shout! */ 166101100Ssos if (reply->function == I2O_UTIL_EVENT_REGISTER) { 167101100Ssos struct i2o_util_event_reply_message *event = 168101100Ssos (struct i2o_util_event_reply_message *)reply; 169101100Ssos 170101100Ssos printf("pstiop: EVENT!! idx=%08x data=%08x\n", 171101100Ssos event->event_mask, event->event_data[0]); 172101100Ssos return; 173101100Ssos } 174101100Ssos 175101100Ssos /* if reply is a failurenotice we need to free the original mfa */ 176101100Ssos if (reply->message_flags & I2O_MESSAGE_FLAGS_FAIL) 177101100Ssos iop_free_mfa(sc,((struct i2o_fault_reply *)(reply))->preserved_mfa); 178101100Ssos 179101100Ssos /* reply->initiator_context points to the service routine */ 180101100Ssos ((void (*)(struct iop_softc *, u_int32_t, struct i2o_single_reply *)) 181101100Ssos (reply->initiator_context))(sc, mfa, reply); 182101100Ssos} 183101100Ssos 184101100Ssosint 185101100Ssosiop_reset(struct iop_softc *sc) 186101100Ssos{ 187101100Ssos struct i2o_exec_iop_reset_message *msg; 188101100Ssos int mfa, timeout = 5000; 189101100Ssos u_int32_t reply = 0; 190101100Ssos 191101100Ssos mfa = iop_get_mfa(sc); 192101100Ssos msg = (struct i2o_exec_iop_reset_message *)(sc->ibase + mfa); 193101100Ssos bzero(msg, sizeof(struct i2o_exec_iop_reset_message)); 194101100Ssos msg->version_offset = 0x1; 195101100Ssos msg->message_flags = 0x0; 196101100Ssos msg->message_size = sizeof(struct i2o_exec_iop_reset_message) >> 2; 197101100Ssos msg->target_address = I2O_TID_IOP; 198101100Ssos msg->initiator_address = I2O_TID_HOST; 199101100Ssos msg->function = I2O_EXEC_IOP_RESET; 200101100Ssos msg->status_word_low_addr = vtophys(&reply); 201101100Ssos msg->status_word_high_addr = 0; 202101100Ssos 203101100Ssos sc->reg->iqueue = mfa; 204101100Ssos 205101100Ssos while (--timeout && !reply) 206101100Ssos DELAY(1000); 207101100Ssos 208101100Ssos /* wait for iqueue ready */ 209101100Ssos timeout = 10000; 210101100Ssos while ((mfa = sc->reg->iqueue) == 0xffffffff && --timeout) 211101100Ssos DELAY(1000); 212101100Ssos iop_free_mfa(sc, mfa); 213101100Ssos 214101100Ssos return reply; 215101100Ssos} 216101100Ssos 217101100Ssosint 218101100Ssosiop_init_outqueue(struct iop_softc *sc) 219101100Ssos{ 220101100Ssos struct i2o_exec_init_outqueue_message *msg; 221101100Ssos int i, mfa, timeout = 5000; 222101100Ssos u_int32_t reply = 0; 223101100Ssos 224101100Ssos if (!(sc->obase = contigmalloc(I2O_IOP_OUTBOUND_FRAME_COUNT * 225101100Ssos I2O_IOP_OUTBOUND_FRAME_SIZE, 226101100Ssos M_PSTIOP, M_NOWAIT, 227101100Ssos 0, 0xFFFFFFFF, sizeof(u_int32_t), 0))) { 228101100Ssos printf("pstiop: contigmalloc of outqueue buffers failed!\n"); 229101100Ssos return 0; 230101100Ssos } 231101100Ssos sc->phys_obase = vtophys(sc->obase); 232101100Ssos mfa = iop_get_mfa(sc); 233101100Ssos msg = (struct i2o_exec_init_outqueue_message *)(sc->ibase + mfa); 234101100Ssos bzero(msg, sizeof(struct i2o_exec_init_outqueue_message)); 235101100Ssos msg->version_offset = 0x61; 236101100Ssos msg->message_flags = 0x0; 237101100Ssos msg->message_size = sizeof(struct i2o_exec_init_outqueue_message) >> 2; 238101100Ssos msg->target_address = I2O_TID_IOP; 239101100Ssos msg->initiator_address = I2O_TID_HOST; 240101100Ssos msg->function = I2O_EXEC_OUTBOUND_INIT; 241101100Ssos msg->host_pagesize = PAGE_SIZE; 242101100Ssos msg->init_code = 0x00; /* SOS XXX should be 0x80 == OS */ 243101100Ssos msg->queue_framesize = I2O_IOP_OUTBOUND_FRAME_SIZE / sizeof(u_int32_t); 244101100Ssos msg->sgl[0].flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB; 245101100Ssos msg->sgl[0].count = sizeof(reply); 246101100Ssos msg->sgl[0].phys_addr[0] = vtophys(&reply); 247101100Ssos msg->sgl[1].flags = I2O_SGL_END | I2O_SGL_EOB; 248101100Ssos msg->sgl[1].count = 1; 249101100Ssos msg->sgl[1].phys_addr[0] = 0; 250101100Ssos 251101100Ssos sc->reg->iqueue = mfa; 252101100Ssos 253101100Ssos /* wait for init to complete */ 254101100Ssos while (--timeout && reply != I2O_EXEC_OUTBOUND_INIT_COMPLETE) 255101100Ssos DELAY(1000); 256101100Ssos 257101100Ssos if (!timeout) { 258101100Ssos printf("pstiop: timeout waiting for init-complete response\n"); 259101100Ssos iop_free_mfa(sc, mfa); 260101100Ssos return 0; 261101100Ssos } 262101100Ssos 263101100Ssos /* now init our oqueue bufs */ 264101100Ssos for (i = 0; i < I2O_IOP_OUTBOUND_FRAME_COUNT; i++) { 265101100Ssos sc->reg->oqueue = sc->phys_obase + (i * I2O_IOP_OUTBOUND_FRAME_SIZE); 266101100Ssos DELAY(1000); 267101100Ssos } 268101100Ssos 269101100Ssos iop_free_mfa(sc, mfa); 270101100Ssos return 1; 271101100Ssos} 272101100Ssos 273101100Ssosint 274101100Ssosiop_get_lct(struct iop_softc *sc) 275101100Ssos{ 276101100Ssos struct i2o_exec_get_lct_message *msg; 277101100Ssos struct i2o_get_lct_reply *reply; 278101100Ssos int mfa; 279101100Ssos#define ALLOCSIZE (PAGE_SIZE + (256 * sizeof(struct i2o_lct_entry))) 280101100Ssos 281101100Ssos if (!(reply = contigmalloc(ALLOCSIZE, M_PSTIOP, M_NOWAIT | M_ZERO, 282101100Ssos 0, 0xFFFFFFFF, sizeof(u_int32_t), 0))) 283101100Ssos return 0; 284101100Ssos 285101100Ssos mfa = iop_get_mfa(sc); 286101100Ssos msg = (struct i2o_exec_get_lct_message *)(sc->ibase + mfa); 287101100Ssos bzero(msg, sizeof(struct i2o_exec_get_lct_message)); 288101100Ssos msg->version_offset = 0x61; 289101100Ssos msg->message_flags = 0x0; 290101100Ssos msg->message_size = sizeof(struct i2o_exec_get_lct_message) >> 2; 291101100Ssos msg->target_address = I2O_TID_IOP; 292101100Ssos msg->initiator_address = I2O_TID_HOST; 293101100Ssos msg->function = I2O_EXEC_LCT_NOTIFY; 294101100Ssos msg->class = I2O_CLASS_MATCH_ANYCLASS; 295101100Ssos msg->last_change_id = 0; 296101100Ssos 297101100Ssos msg->sgl.flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB; 298101100Ssos msg->sgl.count = ALLOCSIZE; 299101100Ssos msg->sgl.phys_addr[0] = vtophys(reply); 300101100Ssos 301101100Ssos if (iop_queue_wait_msg(sc, mfa, (struct i2o_basic_message *)msg)) { 302101100Ssos contigfree(reply, ALLOCSIZE, M_PSTIOP); 303101100Ssos return 0; 304101100Ssos } 305101100Ssos if (!(sc->lct = malloc(reply->table_size * sizeof(struct i2o_lct_entry), 306101100Ssos M_PSTIOP, M_NOWAIT | M_ZERO))) { 307101100Ssos contigfree(reply, ALLOCSIZE, M_PSTIOP); 308101100Ssos return 0; 309101100Ssos } 310101100Ssos bcopy(&reply->entry[0], sc->lct, 311101100Ssos reply->table_size * sizeof(struct i2o_lct_entry)); 312101100Ssos sc->lct_count = reply->table_size; 313101100Ssos contigfree(reply, ALLOCSIZE, M_PSTIOP); 314101100Ssos return 1; 315101100Ssos} 316101100Ssos 317101100Ssosstruct i2o_get_param_reply * 318101100Ssosiop_get_util_params(struct iop_softc *sc, int target, int operation, int group) 319101100Ssos{ 320101100Ssos struct i2o_util_get_param_message *msg; 321101100Ssos struct i2o_get_param_operation *param; 322101100Ssos struct i2o_get_param_reply *reply; 323101100Ssos int mfa; 324101100Ssos 325101100Ssos if (!(param = contigmalloc(PAGE_SIZE, M_PSTIOP, M_NOWAIT | M_ZERO, 326101100Ssos 0, 0xFFFFFFFF, sizeof(u_int32_t), 0))) 327101100Ssos return NULL; 328101100Ssos 329101100Ssos if (!(reply = contigmalloc(PAGE_SIZE, M_PSTIOP, M_NOWAIT | M_ZERO, 330101100Ssos 0, 0xFFFFFFFF, sizeof(u_int32_t), 0))) 331101100Ssos return NULL; 332101100Ssos 333101100Ssos mfa = iop_get_mfa(sc); 334101100Ssos msg = (struct i2o_util_get_param_message *)(sc->ibase + mfa); 335101100Ssos bzero(msg, sizeof(struct i2o_util_get_param_message)); 336101100Ssos msg->version_offset = 0x51; 337101100Ssos msg->message_flags = 0x0; 338101100Ssos msg->message_size = sizeof(struct i2o_util_get_param_message) >> 2; 339101100Ssos msg->target_address = target; 340101100Ssos msg->initiator_address = I2O_TID_HOST; 341101100Ssos msg->function = I2O_UTIL_PARAMS_GET; 342101100Ssos msg->operation_flags = 0; 343101100Ssos 344101100Ssos param->operation_count = 1; 345101100Ssos param->operation[0].operation = operation; 346101100Ssos param->operation[0].group = group; 347101100Ssos param->operation[0].field_count = 0xffff; 348101100Ssos 349101100Ssos msg->sgl[0].flags = I2O_SGL_SIMPLE | I2O_SGL_DIR | I2O_SGL_EOB; 350101100Ssos msg->sgl[0].count = sizeof(struct i2o_get_param_operation); 351101100Ssos msg->sgl[0].phys_addr[0] = vtophys(param); 352101100Ssos 353101100Ssos msg->sgl[1].flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB; 354101100Ssos msg->sgl[1].count = PAGE_SIZE; 355101100Ssos msg->sgl[1].phys_addr[0] = vtophys(reply); 356101100Ssos 357101100Ssos if (iop_queue_wait_msg(sc, mfa, (struct i2o_basic_message *)msg) || 358101100Ssos reply->error_info_size) { 359101100Ssos contigfree(reply, PAGE_SIZE, M_PSTIOP); 360101100Ssos reply = NULL; 361101100Ssos } 362101100Ssos contigfree(param, PAGE_SIZE, M_PSTIOP); 363101100Ssos return reply; 364101100Ssos} 365101100Ssos 366101100Ssosu_int32_t 367101100Ssosiop_get_mfa(struct iop_softc *sc) 368101100Ssos{ 369101100Ssos u_int32_t mfa; 370101100Ssos int timeout = 10000; 371101100Ssos 372101100Ssos while ((mfa = sc->reg->iqueue) == 0xffffffff && timeout) { 373101100Ssos DELAY(1000); 374101100Ssos timeout--; 375101100Ssos } 376101100Ssos if (!timeout) 377101100Ssos printf("pstiop: no free mfa\n"); 378101100Ssos return mfa; 379101100Ssos} 380101100Ssos 381101100Ssosvoid 382101100Ssosiop_free_mfa(struct iop_softc *sc, int mfa) 383101100Ssos{ 384101100Ssos struct i2o_basic_message *msg = (struct i2o_basic_message *)(sc->ibase+mfa); 385101100Ssos 386101100Ssos bzero(msg, sizeof(struct i2o_basic_message)); 387101100Ssos msg->version = 0x01; 388101100Ssos msg->message_flags = 0x0; 389101100Ssos msg->message_size = sizeof(struct i2o_basic_message) >> 2; 390101100Ssos msg->target_address = I2O_TID_IOP; 391101100Ssos msg->initiator_address = I2O_TID_HOST; 392101100Ssos msg->function = I2O_UTIL_NOP; 393101100Ssos sc->reg->iqueue = mfa; 394101100Ssos} 395101100Ssos 396101100Ssosint 397101100Ssosiop_queue_wait_msg(struct iop_softc *sc, int mfa, struct i2o_basic_message *msg) 398101100Ssos{ 399101100Ssos struct i2o_single_reply *reply; 400101100Ssos int out_mfa, status, timeout = 10000; 401101100Ssos 402101100Ssos sc->reg->iqueue = mfa; 403101100Ssos 404101100Ssos while (--timeout && ((out_mfa = sc->reg->oqueue) == 0xffffffff)) 405101100Ssos DELAY(1000); 406101100Ssos if (!timeout) { 407101100Ssos printf("pstiop: timeout waiting for message response\n"); 408101100Ssos iop_free_mfa(sc, mfa); 409101100Ssos return -1; 410101100Ssos } 411101100Ssos 412101100Ssos reply = (struct i2o_single_reply *)(sc->obase + (out_mfa - sc->phys_obase)); 413101100Ssos status = reply->status; 414101100Ssos sc->reg->oqueue = out_mfa; 415101100Ssos return status; 416101100Ssos} 417101100Ssos 418101100Ssosint 419101100Ssosiop_create_sgl(struct i2o_basic_message *msg, caddr_t data, int count, int dir) 420101100Ssos{ 421101100Ssos struct i2o_sgl *sgl = (struct i2o_sgl *)((int32_t *)msg + msg->offset); 422101100Ssos u_int32_t sgl_count, sgl_phys; 423101100Ssos int i = 0; 424101100Ssos 425101100Ssos if (((uintptr_t)data & 3) || (count & 3)) { 426101100Ssos printf("pstiop: non aligned DMA transfer attempted\n"); 427101100Ssos return 0; 428101100Ssos } 429101100Ssos if (!count) { 430101100Ssos printf("pstiop: zero length DMA transfer attempted\n"); 431101100Ssos return 0; 432101100Ssos } 433101100Ssos 434101100Ssos sgl_count = min(count, (PAGE_SIZE - ((uintptr_t)data & PAGE_MASK))); 435101100Ssos sgl_phys = vtophys(data); 436101100Ssos sgl->flags = dir | I2O_SGL_PAGELIST | I2O_SGL_EOB | I2O_SGL_END; 437101100Ssos sgl->count = count; 438101100Ssos data += sgl_count; 439101100Ssos count -= sgl_count; 440101100Ssos 441101100Ssos while (count) { 442101100Ssos sgl->phys_addr[i] = sgl_phys; 443101100Ssos sgl_phys = vtophys(data); 444101100Ssos data += min(count, PAGE_SIZE); 445101100Ssos count -= min(count, PAGE_SIZE); 446101100Ssos if (++i >= I2O_SGL_MAX_SEGS) { 447101100Ssos printf("pstiop: too many segments in SGL\n"); 448101100Ssos return 0; 449101100Ssos } 450101100Ssos } 451101100Ssos sgl->phys_addr[i] = sgl_phys; 452101100Ssos msg->message_size += i; 453101100Ssos return 1; 454101100Ssos} 455