1/* soc.c: Sparc SUNW,soc (Serial Optical Channel) Fibre Channel Sbus adapter support. 2 * 3 * Copyright (C) 1996,1997,1999 Jakub Jelinek (jj@ultra.linux.cz) 4 * Copyright (C) 1997,1998 Jirka Hanika (geo@ff.cuni.cz) 5 * 6 * Sources: 7 * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994 8 * dpANS Fibre Channel Protocol for SCSI (X3.269-199X), Rev. 012, 1995 9 * 10 * Supported hardware: 11 * Tested on SOC sbus card bought with SS1000 in Linux running on SS5 and Ultra1. 12 * For SOC sbus cards, you have to make sure your FCode is 1.52 or later. 13 * If you have older FCode, you should try to upgrade or get SOC microcode from Sun 14 * (the microcode is present in Solaris soc driver as well). In that case you need 15 * to #define HAVE_SOC_UCODE and format the microcode into soc_asm.c. For the exact 16 * format mail me and I will tell you. I cannot offer you the actual microcode though, 17 * unless Sun confirms they don't mind. 18 */ 19 20static char *version = 21 "soc.c:v1.3 9/Feb/99 Jakub Jelinek (jj@ultra.linux.cz), Jirka Hanika (geo@ff.cuni.cz)\n"; 22 23#include <linux/module.h> 24#include <linux/kernel.h> 25#include <linux/types.h> 26#include <linux/fcntl.h> 27#include <linux/interrupt.h> 28#include <linux/ptrace.h> 29#include <linux/ioport.h> 30#include <linux/in.h> 31#include <linux/slab.h> 32#include <linux/string.h> 33#include <linux/init.h> 34#include <linux/bitops.h> 35#include <asm/io.h> 36#include <asm/dma.h> 37#include <linux/errno.h> 38#include <asm/byteorder.h> 39 40#include <asm/openprom.h> 41#include <asm/oplib.h> 42#include <asm/pgtable.h> 43#include <asm/irq.h> 44 45/* #define SOCDEBUG */ 46/* #define HAVE_SOC_UCODE */ 47 48#include "fcp_impl.h" 49#include "soc.h" 50#ifdef HAVE_SOC_UCODE 51#include "soc_asm.h" 52#endif 53 54#define soc_printk printk ("soc%d: ", s->soc_no); printk 55 56#ifdef SOCDEBUG 57#define SOD(x) soc_printk x; 58#else 59#define SOD(x) 60#endif 61 62#define for_each_soc(s) for (s = socs; s; s = s->next) 63struct soc *socs = NULL; 64 65static inline void soc_disable(struct soc *s) 66{ 67 sbus_writel(0, s->regs + IMASK); 68 sbus_writel(SOC_CMD_SOFT_RESET, s->regs + CMD); 69} 70 71static inline void soc_enable(struct soc *s) 72{ 73 SOD(("enable %08x\n", s->cfg)) 74 sbus_writel(0, s->regs + SAE); 75 sbus_writel(s->cfg, s->regs + CFG); 76 sbus_writel(SOC_CMD_RSP_QALL, s->regs + CMD); 77 SOC_SETIMASK(s, SOC_IMASK_RSP_QALL | SOC_IMASK_SAE); 78 SOD(("imask %08lx %08lx\n", s->imask, sbus_readl(s->regs + IMAK))); 79} 80 81static void soc_reset(fc_channel *fc) 82{ 83 soc_port *port = (soc_port *)fc; 84 struct soc *s = port->s; 85 86 soc_disable(s); 87 s->req[0].seqno = 1; 88 s->req[1].seqno = 1; 89 s->rsp[0].seqno = 1; 90 s->rsp[1].seqno = 1; 91 s->req[0].in = 0; 92 s->req[1].in = 0; 93 s->rsp[0].in = 0; 94 s->rsp[1].in = 0; 95 s->req[0].out = 0; 96 s->req[1].out = 0; 97 s->rsp[0].out = 0; 98 s->rsp[1].out = 0; 99 100 soc_enable(s); 101} 102 103static inline void soc_solicited (struct soc *s) 104{ 105 fc_hdr fchdr; 106 soc_rsp __iomem *hwrsp; 107 soc_cq_rsp *sw_cq; 108 int token; 109 int status; 110 fc_channel *fc; 111 112 sw_cq = &s->rsp[SOC_SOLICITED_RSP_Q]; 113 114 if (sw_cq->pool == NULL) 115 sw_cq->pool = (soc_req __iomem *) 116 (s->xram + xram_get_32low ((xram_p)&sw_cq->hw_cq->address)); 117 sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); 118 SOD (("soc_solicited, %d pkts arrived\n", (sw_cq->in-sw_cq->out) & sw_cq->last)) 119 for (;;) { 120 hwrsp = (soc_rsp __iomem *)sw_cq->pool + sw_cq->out; 121 token = xram_get_32low ((xram_p)&hwrsp->shdr.token); 122 status = xram_get_32low ((xram_p)&hwrsp->status); 123 fc = (fc_channel *)(&s->port[(token >> 11) & 1]); 124 125 if (status == SOC_OK) { 126 fcp_receive_solicited(fc, token >> 12, 127 token & ((1 << 11) - 1), 128 FC_STATUS_OK, NULL); 129 } else { 130 xram_copy_from(&fchdr, (xram_p)&hwrsp->fchdr, sizeof(fchdr)); 131 /* We have intentionally defined FC_STATUS_* constants 132 * to match SOC_* constants, otherwise we'd have to 133 * translate status. 134 */ 135 fcp_receive_solicited(fc, token >> 12, 136 token & ((1 << 11) - 1), 137 status, &fchdr); 138 } 139 140 if (++sw_cq->out > sw_cq->last) { 141 sw_cq->seqno++; 142 sw_cq->out = 0; 143 } 144 145 if (sw_cq->out == sw_cq->in) { 146 sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); 147 if (sw_cq->out == sw_cq->in) { 148 /* Tell the hardware about it */ 149 sbus_writel((sw_cq->out << 24) | 150 (SOC_CMD_RSP_QALL & 151 ~(SOC_CMD_RSP_Q0 << SOC_SOLICITED_RSP_Q)), 152 s->regs + CMD); 153 154 /* Read it, so that we're sure it has been updated */ 155 sbus_readl(s->regs + CMD); 156 sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); 157 if (sw_cq->out == sw_cq->in) 158 break; 159 } 160 } 161 } 162} 163 164static inline void soc_request (struct soc *s, u32 cmd) 165{ 166 SOC_SETIMASK(s, s->imask & ~(cmd & SOC_CMD_REQ_QALL)); 167 SOD(("imask %08lx %08lx\n", s->imask, sbus_readl(s->regs + IMASK))); 168 169 SOD(("Queues available %08x OUT %X %X\n", cmd, 170 xram_get_8((xram_p)&s->req[0].hw_cq->out), 171 xram_get_8((xram_p)&s->req[0].hw_cq->out))) 172 if (s->port[s->curr_port].fc.state != FC_STATE_OFFLINE) { 173 fcp_queue_empty ((fc_channel *)&(s->port[s->curr_port])); 174 if (((s->req[1].in + 1) & s->req[1].last) != (s->req[1].out)) 175 fcp_queue_empty ((fc_channel *)&(s->port[1 - s->curr_port])); 176 } else { 177 fcp_queue_empty ((fc_channel *)&(s->port[1 - s->curr_port])); 178 } 179 if (s->port[1 - s->curr_port].fc.state != FC_STATE_OFFLINE) 180 s->curr_port ^= 1; 181} 182 183static inline void soc_unsolicited (struct soc *s) 184{ 185 soc_rsp __iomem *hwrsp, *hwrspc; 186 soc_cq_rsp *sw_cq; 187 int count; 188 int status; 189 int flags; 190 fc_channel *fc; 191 192 sw_cq = &s->rsp[SOC_UNSOLICITED_RSP_Q]; 193 if (sw_cq->pool == NULL) 194 sw_cq->pool = (soc_req __iomem *) 195 (s->xram + (xram_get_32low ((xram_p)&sw_cq->hw_cq->address))); 196 197 sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); 198 SOD (("soc_unsolicited, %d packets arrived\n", (sw_cq->in - sw_cq->out) & sw_cq->last)) 199 while (sw_cq->in != sw_cq->out) { 200 /* ...real work per entry here... */ 201 hwrsp = (soc_rsp __iomem *)sw_cq->pool + sw_cq->out; 202 203 hwrspc = NULL; 204 flags = xram_get_16 ((xram_p)&hwrsp->shdr.flags); 205 count = xram_get_8 ((xram_p)&hwrsp->count); 206 fc = (fc_channel *)&s->port[flags & SOC_PORT_B]; 207 SOD(("FC %08lx fcp_state_change %08lx\n", 208 (long)fc, (long)fc->fcp_state_change)) 209 210 if (count != 1) { 211 /* Ugh, continuation entries */ 212 u8 in; 213 214 if (count != 2) { 215 printk("%s: Too many continuations entries %d\n", 216 fc->name, count); 217 goto update_out; 218 } 219 220 in = sw_cq->in; 221 if (in < sw_cq->out) in += sw_cq->last + 1; 222 if (in < sw_cq->out + 2) { 223 /* Ask the hardware if they haven't arrived yet. */ 224 sbus_writel((sw_cq->out << 24) | 225 (SOC_CMD_RSP_QALL & 226 ~(SOC_CMD_RSP_Q0 << SOC_UNSOLICITED_RSP_Q)), 227 s->regs + CMD); 228 229 /* Read it, so that we're sure it has been updated */ 230 sbus_readl(s->regs + CMD); 231 sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); 232 in = sw_cq->in; 233 if (in < sw_cq->out) 234 in += sw_cq->last + 1; 235 if (in < sw_cq->out + 2) /* Nothing came, let us wait */ 236 return; 237 } 238 if (sw_cq->out == sw_cq->last) 239 hwrspc = (soc_rsp __iomem *)sw_cq->pool; 240 else 241 hwrspc = hwrsp + 1; 242 } 243 244 switch (flags & ~SOC_PORT_B) { 245 case SOC_STATUS: 246 status = xram_get_32low ((xram_p)&hwrsp->status); 247 switch (status) { 248 case SOC_ONLINE: 249 SOD(("State change to ONLINE\n")); 250 fcp_state_change(fc, FC_STATE_ONLINE); 251 break; 252 case SOC_OFFLINE: 253 SOD(("State change to OFFLINE\n")); 254 fcp_state_change(fc, FC_STATE_OFFLINE); 255 break; 256 default: 257 printk ("%s: Unknown STATUS no %d\n", 258 fc->name, status); 259 break; 260 } 261 break; 262 case (SOC_UNSOLICITED|SOC_FC_HDR): 263 { 264 int r_ctl = xram_get_8 ((xram_p)&hwrsp->fchdr); 265 unsigned len; 266 char buf[64]; 267 268 if ((r_ctl & 0xf0) == R_CTL_EXTENDED_SVC) { 269 len = xram_get_32 ((xram_p)&hwrsp->shdr.bytecnt); 270 if (len < 4 || !hwrspc) { 271 printk ("%s: Invalid R_CTL %02x " 272 "continuation entries\n", 273 fc->name, r_ctl); 274 } else { 275 if (len > 60) 276 len = 60; 277 xram_copy_from (buf, (xram_p)hwrspc, 278 (len + 3) & ~3); 279 if (*(u32 *)buf == LS_DISPLAY) { 280 int i; 281 282 for (i = 4; i < len; i++) 283 if (buf[i] == '\n') 284 buf[i] = ' '; 285 buf[len] = 0; 286 printk ("%s message: %s\n", 287 fc->name, buf + 4); 288 } else { 289 printk ("%s: Unknown LS_CMD " 290 "%02x\n", fc->name, 291 buf[0]); 292 } 293 } 294 } else { 295 printk ("%s: Unsolicited R_CTL %02x " 296 "not handled\n", fc->name, r_ctl); 297 } 298 } 299 break; 300 default: 301 printk ("%s: Unexpected flags %08x\n", fc->name, flags); 302 break; 303 }; 304update_out: 305 if (++sw_cq->out > sw_cq->last) { 306 sw_cq->seqno++; 307 sw_cq->out = 0; 308 } 309 310 if (hwrspc) { 311 if (++sw_cq->out > sw_cq->last) { 312 sw_cq->seqno++; 313 sw_cq->out = 0; 314 } 315 } 316 317 if (sw_cq->out == sw_cq->in) { 318 sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); 319 if (sw_cq->out == sw_cq->in) { 320 /* Tell the hardware about it */ 321 sbus_writel((sw_cq->out << 24) | 322 (SOC_CMD_RSP_QALL & 323 ~(SOC_CMD_RSP_Q0 << SOC_UNSOLICITED_RSP_Q)), 324 s->regs + CMD); 325 326 /* Read it, so that we're sure it has been updated */ 327 sbus_readl(s->regs + CMD); 328 sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); 329 } 330 } 331 } 332} 333 334static irqreturn_t soc_intr(int irq, void *dev_id) 335{ 336 u32 cmd; 337 unsigned long flags; 338 register struct soc *s = (struct soc *)dev_id; 339 340 spin_lock_irqsave(&s->lock, flags); 341 cmd = sbus_readl(s->regs + CMD); 342 for (; (cmd = SOC_INTR (s, cmd)); cmd = sbus_readl(s->regs + CMD)) { 343 if (cmd & SOC_CMD_RSP_Q1) soc_unsolicited (s); 344 if (cmd & SOC_CMD_RSP_Q0) soc_solicited (s); 345 if (cmd & SOC_CMD_REQ_QALL) soc_request (s, cmd); 346 } 347 spin_unlock_irqrestore(&s->lock, flags); 348 349 return IRQ_HANDLED; 350} 351 352#define TOKEN(proto, port, token) (((proto)<<12)|(token)|(port)) 353 354static int soc_hw_enque (fc_channel *fc, fcp_cmnd *fcmd) 355{ 356 soc_port *port = (soc_port *)fc; 357 struct soc *s = port->s; 358 int qno; 359 soc_cq_req *sw_cq; 360 int cq_next_in; 361 soc_req *request; 362 fc_hdr *fch; 363 int i; 364 365 if (fcmd->proto == TYPE_SCSI_FCP) 366 qno = 1; 367 else 368 qno = 0; 369 SOD(("Putting a FCP packet type %d into hw queue %d\n", fcmd->proto, qno)) 370 if (s->imask & (SOC_IMASK_REQ_Q0 << qno)) { 371 SOD(("EIO %08x\n", s->imask)) 372 return -EIO; 373 } 374 sw_cq = s->req + qno; 375 cq_next_in = (sw_cq->in + 1) & sw_cq->last; 376 377 if (cq_next_in == sw_cq->out && 378 cq_next_in == (sw_cq->out = xram_get_8((xram_p)&sw_cq->hw_cq->out))) { 379 SOD(("%d IN %d OUT %d LAST %d\n", qno, sw_cq->in, sw_cq->out, sw_cq->last)) 380 SOC_SETIMASK(s, s->imask | (SOC_IMASK_REQ_Q0 << qno)); 381 SOD(("imask %08lx %08lx\n", s->imask, sbus_readl(s->regs + IMASK))); 382 /* If queue is full, just say NO */ 383 return -EBUSY; 384 } 385 386 request = sw_cq->pool + sw_cq->in; 387 fch = &request->fchdr; 388 389 switch (fcmd->proto) { 390 case TYPE_SCSI_FCP: 391 request->shdr.token = TOKEN(TYPE_SCSI_FCP, port->mask, fcmd->token); 392 request->data[0].base = fc->dma_scsi_cmd + fcmd->token * sizeof(fcp_cmd); 393 request->data[0].count = sizeof(fcp_cmd); 394 request->data[1].base = fc->dma_scsi_rsp + fcmd->token * fc->rsp_size; 395 request->data[1].count = fc->rsp_size; 396 if (fcmd->data) { 397 request->shdr.segcnt = 3; 398 i = fc->scsi_cmd_pool[fcmd->token].fcp_data_len; 399 request->shdr.bytecnt = i; 400 request->data[2].base = fcmd->data; 401 request->data[2].count = i; 402 request->type = 403 (fc->scsi_cmd_pool[fcmd->token].fcp_cntl & FCP_CNTL_WRITE) ? 404 SOC_CQTYPE_IO_WRITE : SOC_CQTYPE_IO_READ; 405 } else { 406 request->shdr.segcnt = 2; 407 request->shdr.bytecnt = 0; 408 request->data[2].base = 0; 409 request->data[2].count = 0; 410 request->type = SOC_CQTYPE_SIMPLE; 411 } 412 FILL_FCHDR_RCTL_DID(fch, R_CTL_COMMAND, fc->did); 413 FILL_FCHDR_SID(fch, fc->sid); 414 FILL_FCHDR_TYPE_FCTL(fch, TYPE_SCSI_FCP, 415 F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); 416 FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); 417 FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); 418 fch->param = 0; 419 request->shdr.flags = port->flags; 420 request->shdr.class = 2; 421 break; 422 423 case PROTO_OFFLINE: 424 memset (request, 0, sizeof(*request)); 425 request->shdr.token = TOKEN(PROTO_OFFLINE, port->mask, fcmd->token); 426 request->type = SOC_CQTYPE_OFFLINE; 427 FILL_FCHDR_RCTL_DID(fch, R_CTL_COMMAND, fc->did); 428 FILL_FCHDR_SID(fch, fc->sid); 429 FILL_FCHDR_TYPE_FCTL(fch, TYPE_SCSI_FCP, 430 F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); 431 FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); 432 FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); 433 request->shdr.flags = port->flags; 434 break; 435 436 case PROTO_REPORT_AL_MAP: 437 /* SOC only supports Point-to-Point topology, no FC-AL, sorry... */ 438 return -ENOSYS; 439 440 default: 441 request->shdr.token = TOKEN(fcmd->proto, port->mask, fcmd->token); 442 request->shdr.class = 2; 443 request->shdr.flags = port->flags; 444 memcpy (fch, &fcmd->fch, sizeof(fc_hdr)); 445 request->data[0].count = fcmd->cmdlen; 446 request->data[1].count = fcmd->rsplen; 447 request->type = fcmd->class; 448 switch (fcmd->class) { 449 case FC_CLASS_OUTBOUND: 450 request->data[0].base = fcmd->cmd; 451 request->data[0].count = fcmd->cmdlen; 452 request->type = SOC_CQTYPE_OUTBOUND; 453 request->shdr.bytecnt = fcmd->cmdlen; 454 request->shdr.segcnt = 1; 455 break; 456 case FC_CLASS_INBOUND: 457 request->data[0].base = fcmd->rsp; 458 request->data[0].count = fcmd->rsplen; 459 request->type = SOC_CQTYPE_INBOUND; 460 request->shdr.bytecnt = 0; 461 request->shdr.segcnt = 1; 462 break; 463 case FC_CLASS_SIMPLE: 464 request->data[0].base = fcmd->cmd; 465 request->data[1].base = fcmd->rsp; 466 request->data[0].count = fcmd->cmdlen; 467 request->data[1].count = fcmd->rsplen; 468 request->type = SOC_CQTYPE_SIMPLE; 469 request->shdr.bytecnt = fcmd->cmdlen; 470 request->shdr.segcnt = 2; 471 break; 472 case FC_CLASS_IO_READ: 473 case FC_CLASS_IO_WRITE: 474 request->data[0].base = fcmd->cmd; 475 request->data[1].base = fcmd->rsp; 476 request->data[0].count = fcmd->cmdlen; 477 request->data[1].count = fcmd->rsplen; 478 request->type = 479 (fcmd->class == FC_CLASS_IO_READ) ? 480 SOC_CQTYPE_IO_READ : SOC_CQTYPE_IO_WRITE; 481 if (fcmd->data) { 482 request->data[2].base = fcmd->data; 483 request->data[2].count = fcmd->datalen; 484 request->shdr.bytecnt = fcmd->datalen; 485 request->shdr.segcnt = 3; 486 } else { 487 request->shdr.bytecnt = 0; 488 request->shdr.segcnt = 2; 489 } 490 break; 491 }; 492 break; 493 }; 494 495 request->count = 1; 496 request->flags = 0; 497 request->seqno = sw_cq->seqno; 498 499 /* And now tell the SOC about it */ 500 501 if (++sw_cq->in > sw_cq->last) { 502 sw_cq->in = 0; 503 sw_cq->seqno++; 504 } 505 506 SOD(("Putting %08x into cmd\n", 507 SOC_CMD_RSP_QALL | (sw_cq->in << 24) | (SOC_CMD_REQ_Q0 << qno))) 508 509 sbus_writel(SOC_CMD_RSP_QALL | (sw_cq->in << 24) | (SOC_CMD_REQ_Q0 << qno), 510 s->regs + CMD); 511 512 /* Read so that command is completed. */ 513 sbus_readl(s->regs + CMD); 514 515 return 0; 516} 517 518static inline void soc_download_fw(struct soc *s) 519{ 520#ifdef HAVE_SOC_UCODE 521 xram_copy_to (s->xram, soc_ucode, sizeof(soc_ucode)); 522 xram_bzero (s->xram + sizeof(soc_ucode), 32768 - sizeof(soc_ucode)); 523#endif 524} 525 526/* Check for what the best SBUS burst we can use happens 527 * to be on this machine. 528 */ 529static inline void soc_init_bursts(struct soc *s, struct sbus_dev *sdev) 530{ 531 int bsizes, bsizes_more; 532 533 bsizes = (prom_getintdefault(sdev->prom_node,"burst-sizes",0xff) & 0xff); 534 bsizes_more = (prom_getintdefault(sdev->bus->prom_node, "burst-sizes", 0xff) & 0xff); 535 bsizes &= bsizes_more; 536 if ((bsizes & 0x7f) == 0x7f) 537 s->cfg = SOC_CFG_BURST_64; 538 else if ((bsizes & 0x3f) == 0x3f) 539 s->cfg = SOC_CFG_BURST_32; 540 else if ((bsizes & 0x1f) == 0x1f) 541 s->cfg = SOC_CFG_BURST_16; 542 else 543 s->cfg = SOC_CFG_BURST_4; 544} 545 546static inline void soc_init(struct sbus_dev *sdev, int no) 547{ 548 unsigned char tmp[60]; 549 int propl; 550 struct soc *s; 551 static int version_printed = 0; 552 soc_hw_cq cq[8]; 553 int size, i; 554 int irq; 555 556 s = kzalloc (sizeof (struct soc), GFP_KERNEL); 557 if (s == NULL) 558 return; 559 spin_lock_init(&s->lock); 560 s->soc_no = no; 561 562 SOD(("socs %08lx soc_intr %08lx soc_hw_enque %08x\n", 563 (long)socs, (long)soc_intr, (long)soc_hw_enque)) 564 if (version_printed++ == 0) 565 printk (version); 566 567 s->port[0].fc.module = THIS_MODULE; 568 s->port[1].fc.module = THIS_MODULE; 569 570 s->next = socs; 571 socs = s; 572 s->port[0].fc.dev = sdev; 573 s->port[1].fc.dev = sdev; 574 s->port[0].s = s; 575 s->port[1].s = s; 576 577 s->port[0].fc.next = &s->port[1].fc; 578 579 /* World Wide Name of SOC */ 580 propl = prom_getproperty (sdev->prom_node, "soc-wwn", tmp, sizeof(tmp)); 581 if (propl != sizeof (fc_wwn)) { 582 s->wwn.naaid = NAAID_IEEE; 583 s->wwn.lo = 0x12345678; 584 } else 585 memcpy (&s->wwn, tmp, sizeof (fc_wwn)); 586 587 propl = prom_getproperty (sdev->prom_node, "port-wwns", tmp, sizeof(tmp)); 588 if (propl != 2 * sizeof (fc_wwn)) { 589 s->port[0].fc.wwn_nport.naaid = NAAID_IEEE_EXT; 590 s->port[0].fc.wwn_nport.hi = s->wwn.hi; 591 s->port[0].fc.wwn_nport.lo = s->wwn.lo; 592 s->port[1].fc.wwn_nport.naaid = NAAID_IEEE_EXT; 593 s->port[1].fc.wwn_nport.nportid = 1; 594 s->port[1].fc.wwn_nport.hi = s->wwn.hi; 595 s->port[1].fc.wwn_nport.lo = s->wwn.lo; 596 } else { 597 memcpy (&s->port[0].fc.wwn_nport, tmp, sizeof (fc_wwn)); 598 memcpy (&s->port[1].fc.wwn_nport, tmp + sizeof (fc_wwn), sizeof (fc_wwn)); 599 } 600 memcpy (&s->port[0].fc.wwn_node, &s->wwn, sizeof (fc_wwn)); 601 memcpy (&s->port[1].fc.wwn_node, &s->wwn, sizeof (fc_wwn)); 602 SOD(("Got wwns %08x%08x ports %08x%08x and %08x%08x\n", 603 *(u32 *)&s->port[0].fc.wwn_nport, s->port[0].fc.wwn_nport.lo, 604 *(u32 *)&s->port[0].fc.wwn_nport, s->port[0].fc.wwn_nport.lo, 605 *(u32 *)&s->port[1].fc.wwn_nport, s->port[1].fc.wwn_nport.lo)) 606 607 s->port[0].fc.sid = 1; 608 s->port[1].fc.sid = 17; 609 s->port[0].fc.did = 2; 610 s->port[1].fc.did = 18; 611 612 s->port[0].fc.reset = soc_reset; 613 s->port[1].fc.reset = soc_reset; 614 615 if (sdev->num_registers == 1) { 616 /* Probably SunFire onboard SOC */ 617 s->xram = sbus_ioremap(&sdev->resource[0], 0, 618 0x10000UL, "soc xram"); 619 s->regs = sbus_ioremap(&sdev->resource[0], 0x10000UL, 620 0x10UL, "soc regs"); 621 } else { 622 /* Probably SOC sbus card */ 623 s->xram = sbus_ioremap(&sdev->resource[1], 0, 624 sdev->reg_addrs[1].reg_size, "soc xram"); 625 s->regs = sbus_ioremap(&sdev->resource[2], 0, 626 sdev->reg_addrs[2].reg_size, "soc regs"); 627 } 628 629 soc_init_bursts(s, sdev); 630 631 SOD(("Disabling SOC\n")) 632 633 soc_disable (s); 634 635 irq = sdev->irqs[0]; 636 637 if (request_irq (irq, soc_intr, IRQF_SHARED, "SOC", (void *)s)) { 638 soc_printk ("Cannot order irq %d to go\n", irq); 639 socs = s->next; 640 return; 641 } 642 643 SOD(("SOC uses IRQ %d\n", irq)) 644 645 s->port[0].fc.irq = irq; 646 s->port[1].fc.irq = irq; 647 648 sprintf (s->port[0].fc.name, "soc%d port A", no); 649 sprintf (s->port[1].fc.name, "soc%d port B", no); 650 s->port[0].flags = SOC_FC_HDR | SOC_PORT_A; 651 s->port[1].flags = SOC_FC_HDR | SOC_PORT_B; 652 s->port[1].mask = (1 << 11); 653 654 s->port[0].fc.hw_enque = soc_hw_enque; 655 s->port[1].fc.hw_enque = soc_hw_enque; 656 657 soc_download_fw (s); 658 659 SOD(("Downloaded firmware\n")) 660 661 /* Now setup xram circular queues */ 662 memset (cq, 0, sizeof(cq)); 663 664 size = (SOC_CQ_REQ0_SIZE + SOC_CQ_REQ1_SIZE) * sizeof(soc_req); 665 s->req_cpu = sbus_alloc_consistent(sdev, size, &s->req_dvma); 666 s->req[0].pool = s->req_cpu; 667 cq[0].address = s->req_dvma; 668 s->req[1].pool = s->req[0].pool + SOC_CQ_REQ0_SIZE; 669 670 s->req[0].hw_cq = (soc_hw_cq __iomem *)(s->xram + SOC_CQ_REQ_OFFSET); 671 s->req[1].hw_cq = (soc_hw_cq __iomem *)(s->xram + SOC_CQ_REQ_OFFSET + sizeof(soc_hw_cq)); 672 s->rsp[0].hw_cq = (soc_hw_cq __iomem *)(s->xram + SOC_CQ_RSP_OFFSET); 673 s->rsp[1].hw_cq = (soc_hw_cq __iomem *)(s->xram + SOC_CQ_RSP_OFFSET + sizeof(soc_hw_cq)); 674 675 cq[1].address = cq[0].address + (SOC_CQ_REQ0_SIZE * sizeof(soc_req)); 676 cq[4].address = 1; 677 cq[5].address = 1; 678 cq[0].last = SOC_CQ_REQ0_SIZE - 1; 679 cq[1].last = SOC_CQ_REQ1_SIZE - 1; 680 cq[4].last = SOC_CQ_RSP0_SIZE - 1; 681 cq[5].last = SOC_CQ_RSP1_SIZE - 1; 682 for (i = 0; i < 8; i++) 683 cq[i].seqno = 1; 684 685 s->req[0].last = SOC_CQ_REQ0_SIZE - 1; 686 s->req[1].last = SOC_CQ_REQ1_SIZE - 1; 687 s->rsp[0].last = SOC_CQ_RSP0_SIZE - 1; 688 s->rsp[1].last = SOC_CQ_RSP1_SIZE - 1; 689 690 s->req[0].seqno = 1; 691 s->req[1].seqno = 1; 692 s->rsp[0].seqno = 1; 693 s->rsp[1].seqno = 1; 694 695 xram_copy_to (s->xram + SOC_CQ_REQ_OFFSET, cq, sizeof(cq)); 696 697 /* Make our sw copy of SOC service parameters */ 698 xram_copy_from (s->serv_params, s->xram + 0x140, sizeof (s->serv_params)); 699 700 s->port[0].fc.common_svc = (common_svc_parm *)s->serv_params; 701 s->port[0].fc.class_svcs = (svc_parm *)(s->serv_params + 0x20); 702 s->port[1].fc.common_svc = (common_svc_parm *)&s->serv_params; 703 s->port[1].fc.class_svcs = (svc_parm *)(s->serv_params + 0x20); 704 705 soc_enable (s); 706 707 SOD(("Enabled SOC\n")) 708} 709 710static int __init soc_probe(void) 711{ 712 struct sbus_bus *sbus; 713 struct sbus_dev *sdev = NULL; 714 struct soc *s; 715 int cards = 0; 716 717 for_each_sbus(sbus) { 718 for_each_sbusdev(sdev, sbus) { 719 if(!strcmp(sdev->prom_name, "SUNW,soc")) { 720 soc_init(sdev, cards); 721 cards++; 722 } 723 } 724 } 725 if (!cards) return -EIO; 726 727 for_each_soc(s) 728 if (s->next) 729 s->port[1].fc.next = &s->next->port[0].fc; 730 fcp_init (&socs->port[0].fc); 731 return 0; 732} 733 734static void __exit soc_cleanup(void) 735{ 736 struct soc *s; 737 int irq; 738 struct sbus_dev *sdev; 739 740 for_each_soc(s) { 741 irq = s->port[0].fc.irq; 742 free_irq (irq, s); 743 744 fcp_release(&(s->port[0].fc), 2); 745 746 sdev = s->port[0].fc.dev; 747 if (sdev->num_registers == 1) { 748 sbus_iounmap(s->xram, 0x10000UL); 749 sbus_iounmap(s->regs, 0x10UL); 750 } else { 751 sbus_iounmap(s->xram, sdev->reg_addrs[1].reg_size); 752 sbus_iounmap(s->regs, sdev->reg_addrs[2].reg_size); 753 } 754 sbus_free_consistent(sdev, 755 (SOC_CQ_REQ0_SIZE+SOC_CQ_REQ1_SIZE)*sizeof(soc_req), 756 s->req_cpu, s->req_dvma); 757 } 758} 759 760module_init(soc_probe); 761module_exit(soc_cleanup); 762MODULE_LICENSE("GPL"); 763