| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
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: src/sys/dev/pst/pst-iop.c,v 1.2.2.1 2002/08/18 12:32:36 sos Exp $ | |
| 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/buf.h> | |
| 37 | #include <sys/malloc.h> | |
| 1f7ab7c9 MD |
38 | #include <sys/rman.h> |
| 39 | ||
| 984263bc MD |
40 | #include <vm/vm.h> |
| 41 | #include <vm/pmap.h> | |
| 1f7ab7c9 | 42 | |
| 984263bc MD |
43 | #include <machine/clock.h> |
| 44 | #include <machine/stdarg.h> | |
| 1f7ab7c9 | 45 | |
| 1f2de5d4 MD |
46 | #include <bus/pci/pcivar.h> |
| 47 | #include <bus/pci/pcireg.h> | |
| 984263bc | 48 | |
| 1f2de5d4 | 49 | #include "pst-iop.h" |
| 984263bc MD |
50 | |
| 51 | /* local vars */ | |
| 52 | MALLOC_DEFINE(M_PSTIOP, "PSTIOP", "Promise SuperTrak IOP driver"); | |
| 53 | ||
| 54 | int | |
| 55 | iop_init(struct iop_softc *sc) | |
| 56 | { | |
| 57 | int mfa, timeout = 10000; | |
| 58 | ||
| 59 | while ((mfa = sc->reg->iqueue) == 0xffffffff && --timeout) | |
| 60 | DELAY(1000); | |
| 61 | if (!timeout) { | |
| e3869ec7 | 62 | kprintf("pstiop: no free mfa\n"); |
| 984263bc MD |
63 | return 0; |
| 64 | } | |
| 65 | iop_free_mfa(sc, mfa); | |
| 66 | ||
| 67 | sc->reg->oqueue_intr_mask = 0xffffffff; | |
| 68 | ||
| 69 | if (!iop_reset(sc)) { | |
| e3869ec7 | 70 | kprintf("pstiop: no reset response\n"); |
| 984263bc MD |
71 | return 0; |
| 72 | } | |
| 73 | ||
| 74 | if (!iop_init_outqueue(sc)) { | |
| e3869ec7 | 75 | kprintf("pstiop: init outbound queue failed\n"); |
| 984263bc MD |
76 | return 0; |
| 77 | } | |
| 78 | ||
| 79 | /* register iop_attach to be run when interrupts are enabled */ | |
| 77652cad | 80 | sc->iop_delayed_attach = kmalloc(sizeof(struct intr_config_hook), |
| 076ae0ab | 81 | M_PSTIOP, M_INTWAIT | M_ZERO); |
| 984263bc MD |
82 | sc->iop_delayed_attach->ich_func = (void *)iop_attach; |
| 83 | sc->iop_delayed_attach->ich_arg = (void *)sc; | |
| a1e26a0c | 84 | sc->iop_delayed_attach->ich_desc = "pst"; |
| 984263bc | 85 | if (config_intrhook_establish(sc->iop_delayed_attach)) { |
| e3869ec7 | 86 | kprintf("pstiop: config_intrhook_establish failed\n"); |
| efda3bd0 | 87 | kfree(sc->iop_delayed_attach, M_PSTIOP); |
| 984263bc MD |
88 | } |
| 89 | return 1; | |
| 90 | } | |
| 91 | ||
| 92 | void | |
| 93 | iop_attach(struct iop_softc *sc) | |
| 94 | { | |
| 95 | int i; | |
| 96 | ||
| 97 | if (sc->iop_delayed_attach) { | |
| 98 | config_intrhook_disestablish(sc->iop_delayed_attach); | |
| efda3bd0 | 99 | kfree(sc->iop_delayed_attach, M_PSTIOP); |
| 984263bc MD |
100 | sc->iop_delayed_attach = NULL; |
| 101 | } | |
| 102 | ||
| 103 | if (!iop_get_lct(sc)) { | |
| e3869ec7 | 104 | kprintf("pstiop: get LCT failed\n"); |
| 984263bc MD |
105 | return; |
| 106 | } | |
| 107 | ||
| 108 | /* figure out what devices are here and config as needed */ | |
| 109 | for (i = 0; sc->lct[i].entry_size == I2O_LCT_ENTRYSIZE; i++) { | |
| 110 | #ifdef PSTDEBUG | |
| 111 | struct i2o_get_param_reply *reply; | |
| 112 | ||
| e3869ec7 SW |
113 | kprintf("pstiop: LCT entry %d ", i); |
| 114 | kprintf("class=%04x ", sc->lct[i].class); | |
| 115 | kprintf("sub=%04x ", sc->lct[i].sub_class); | |
| 116 | kprintf("localtid=%04x ", sc->lct[i].local_tid); | |
| 117 | kprintf("usertid=%04x ", sc->lct[i].user_tid); | |
| 118 | kprintf("parentid=%04x\n", sc->lct[i].parent_tid); | |
| 984263bc MD |
119 | |
| 120 | if ((reply = iop_get_util_params(sc, sc->lct[i].local_tid, | |
| 121 | I2O_PARAMS_OPERATION_FIELD_GET, | |
| 122 | I2O_UTIL_DEVICE_IDENTITY_GROUP_NO))) { | |
| 123 | struct i2o_device_identity *ident = | |
| 124 | (struct i2o_device_identity *)reply->result; | |
| e3869ec7 | 125 | kprintf("pstiop: vendor=<%.16s> product=<%.16s>\n", |
| 984263bc | 126 | ident->vendor, ident->product); |
| e3869ec7 | 127 | kprintf("pstiop: description=<%.16s> revision=<%.8s>\n", |
| 984263bc MD |
128 | ident->description, ident->revision); |
| 129 | contigfree(reply, PAGE_SIZE, M_PSTIOP); | |
| 130 | } | |
| 131 | #endif | |
| 132 | ||
| 133 | if (sc->lct[i].user_tid != I2O_TID_NONE && | |
| 134 | sc->lct[i].user_tid != I2O_TID_HOST) | |
| 135 | continue; | |
| 136 | ||
| 137 | switch (sc->lct[i].class) { | |
| 138 | case I2O_CLASS_RANDOM_BLOCK_STORAGE: | |
| 139 | pst_add_raid(sc, &sc->lct[i]); | |
| 140 | break; | |
| 141 | } | |
| 142 | } | |
| 143 | /* setup and enable interrupts */ | |
| ee61f228 | 144 | bus_setup_intr(sc->dev, sc->r_irq, 0, iop_intr, sc, &sc->handle, NULL); |
| 984263bc MD |
145 | sc->reg->oqueue_intr_mask = 0x0; |
| 146 | } | |
| 147 | ||
| 148 | void | |
| 149 | iop_intr(void *data) | |
| 150 | { | |
| 151 | struct iop_softc *sc = (struct iop_softc *)data; | |
| 152 | struct i2o_single_reply *reply; | |
| 153 | u_int32_t mfa; | |
| 154 | ||
| 155 | /* we might get more than one finished request pr interrupt */ | |
| 156 | while (1) { | |
| 157 | if ((mfa = sc->reg->oqueue) == 0xffffffff) | |
| 158 | if ((mfa = sc->reg->oqueue) == 0xffffffff) | |
| 159 | return; | |
| 160 | ||
| 161 | reply = (struct i2o_single_reply *)(sc->obase + (mfa - sc->phys_obase)); | |
| 162 | ||
| 163 | /* if this is a event register reply, shout! */ | |
| 164 | if (reply->function == I2O_UTIL_EVENT_REGISTER) { | |
| 165 | struct i2o_util_event_reply_message *event = | |
| 166 | (struct i2o_util_event_reply_message *)reply; | |
| 167 | ||
| e3869ec7 | 168 | kprintf("pstiop: EVENT!! idx=%08x data=%08x\n", |
| 984263bc MD |
169 | event->event_mask, event->event_data[0]); |
| 170 | return; | |
| 171 | } | |
| 172 | ||
| 173 | /* if reply is a failurenotice we need to free the original mfa */ | |
| 174 | if (reply->message_flags & I2O_MESSAGE_FLAGS_FAIL) | |
| 175 | iop_free_mfa(sc,((struct i2o_fault_reply *)(reply))->preserved_mfa); | |
| 176 | ||
| 177 | /* reply->initiator_context points to the service routine */ | |
| 178 | ((void (*)(struct iop_softc *, u_int32_t, struct i2o_single_reply *)) | |
| 179 | (reply->initiator_context))(sc, mfa, reply); | |
| 180 | } | |
| 181 | } | |
| 182 | ||
| 183 | int | |
| 184 | iop_reset(struct iop_softc *sc) | |
| 185 | { | |
| 186 | struct i2o_exec_iop_reset_message *msg; | |
| 187 | int mfa, timeout = 5000; | |
| 188 | volatile u_int32_t reply = 0; | |
| 189 | ||
| 190 | mfa = iop_get_mfa(sc); | |
| 191 | msg = (struct i2o_exec_iop_reset_message *)(sc->ibase + mfa); | |
| 192 | bzero(msg, sizeof(struct i2o_exec_iop_reset_message)); | |
| 193 | msg->version_offset = 0x1; | |
| 194 | msg->message_flags = 0x0; | |
| 195 | msg->message_size = sizeof(struct i2o_exec_iop_reset_message) >> 2; | |
| 196 | msg->target_address = I2O_TID_IOP; | |
| 197 | msg->initiator_address = I2O_TID_HOST; | |
| 198 | msg->function = I2O_EXEC_IOP_RESET; | |
| 199 | msg->status_word_low_addr = vtophys(&reply); | |
| 200 | msg->status_word_high_addr = 0; | |
| 201 | ||
| 202 | sc->reg->iqueue = mfa; | |
| 203 | ||
| 204 | while (--timeout && !reply) | |
| 205 | DELAY(1000); | |
| 206 | ||
| 207 | /* wait for iqueue ready */ | |
| 208 | timeout = 10000; | |
| 209 | while ((mfa = sc->reg->iqueue) == 0xffffffff && --timeout) | |
| 210 | DELAY(1000); | |
| 211 | ||
| 212 | iop_free_mfa(sc, mfa); | |
| 213 | return reply; | |
| 214 | } | |
| 215 | ||
| 216 | int | |
| 217 | iop_init_outqueue(struct iop_softc *sc) | |
| 218 | { | |
| 219 | struct i2o_exec_init_outqueue_message *msg; | |
| 220 | int i, mfa, timeout = 5000; | |
| 221 | volatile u_int32_t reply = 0; | |
| 222 | ||
| 223 | if (!(sc->obase = contigmalloc(I2O_IOP_OUTBOUND_FRAME_COUNT * | |
| 224 | I2O_IOP_OUTBOUND_FRAME_SIZE, | |
| 225 | M_PSTIOP, M_NOWAIT, | |
| 226 | 0x00010000, 0xFFFFFFFF, | |
| 227 | sizeof(u_int32_t), 0))) { | |
| e3869ec7 | 228 | kprintf("pstiop: contigmalloc of outqueue buffers failed!\n"); |
| 984263bc MD |
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) { | |
| e3869ec7 | 258 | kprintf("pstiop: timeout waiting for init-complete response\n"); |
| 984263bc MD |
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 | ||
| 273 | int | |
| 274 | iop_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 | 0x00010000, 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 | } | |
| 77652cad | 305 | sc->lct = kmalloc(reply->table_size * sizeof(struct i2o_lct_entry), |
| 076ae0ab | 306 | M_PSTIOP, M_INTWAIT | M_ZERO); |
| 984263bc MD |
307 | bcopy(&reply->entry[0], sc->lct, |
| 308 | reply->table_size * sizeof(struct i2o_lct_entry)); | |
| 309 | sc->lct_count = reply->table_size; | |
| 310 | contigfree(reply, ALLOCSIZE, M_PSTIOP); | |
| 311 | return 1; | |
| 312 | } | |
| 313 | ||
| 314 | struct i2o_get_param_reply * | |
| 315 | iop_get_util_params(struct iop_softc *sc, int target, int operation, int group) | |
| 316 | { | |
| 317 | struct i2o_util_get_param_message *msg; | |
| 318 | struct i2o_get_param_operation *param; | |
| 319 | struct i2o_get_param_reply *reply; | |
| 320 | int mfa; | |
| 321 | ||
| 322 | if (!(param = contigmalloc(PAGE_SIZE, M_PSTIOP, M_NOWAIT | M_ZERO, | |
| 323 | 0x00010000, 0xFFFFFFFF, sizeof(u_int32_t), 0))) | |
| 324 | return NULL; | |
| 325 | ||
| 326 | if (!(reply = contigmalloc(PAGE_SIZE, M_PSTIOP, M_NOWAIT | M_ZERO, | |
| 327 | 0x00010000, 0xFFFFFFFF, sizeof(u_int32_t), 0))) | |
| 2e32384e SW |
328 | { |
| 329 | contigfree(param, PAGE_SIZE, M_PSTIOP); | |
| 984263bc | 330 | return NULL; |
| 2e32384e | 331 | } |
| 984263bc MD |
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 | ||
| 366 | u_int32_t | |
| 367 | iop_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) | |
| e3869ec7 | 377 | kprintf("pstiop: no free mfa\n"); |
| 984263bc MD |
378 | return mfa; |
| 379 | } | |
| 380 | ||
| 381 | void | |
| 382 | iop_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 | ||
| 396 | int | |
| 397 | iop_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) { | |
| e3869ec7 | 407 | kprintf("pstiop: timeout waiting for message response\n"); |
| 984263bc MD |
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 | ||
| 418 | int | |
| 419 | iop_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)) { | |
| e3869ec7 | 426 | kprintf("pstiop: non aligned DMA transfer attempted\n"); |
| 984263bc MD |
427 | return 0; |
| 428 | } | |
| 429 | if (!count) { | |
| e3869ec7 | 430 | kprintf("pstiop: zero length DMA transfer attempted\n"); |
| 984263bc MD |
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) { | |
| e3869ec7 | 447 | kprintf("pstiop: too many segments in SGL\n"); |
| 984263bc MD |
448 | return 0; |
| 449 | } | |
| 450 | } | |
| 451 | sgl->phys_addr[i] = sgl_phys; | |
| 452 | msg->message_size += i; | |
| 453 | return 1; | |
| 454 | } |