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