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/sched.h> 26#include <linux/types.h> 27#include <linux/fcntl.h> 28#include <linux/interrupt.h> 29#include <linux/ptrace.h> 30#include <linux/ioport.h> 31#include <linux/in.h> 32#include <linux/slab.h> 33#include <linux/string.h> 34#include <linux/init.h> 35#include <asm/bitops.h> 36#include <asm/io.h> 37#include <asm/dma.h> 38#include <linux/errno.h> 39#include <asm/byteorder.h> 40 41#include <asm/openprom.h> 42#include <asm/oplib.h> 43#include <asm/auxio.h> 44#include <asm/pgtable.h> 45#include <asm/irq.h> 46 47/* #define SOCDEBUG */ 48/* #define HAVE_SOC_UCODE */ 49 50#include "fcp_impl.h" 51#include "soc.h" 52#ifdef HAVE_SOC_UCODE 53#include "soc_asm.h" 54#endif 55 56#define soc_printk printk ("soc%d: ", s->soc_no); printk 57 58#ifdef SOCDEBUG 59#define SOD(x) soc_printk x; 60#else 61#define SOD(x) 62#endif 63 64#define for_each_soc(s) for (s = socs; s; s = s->next) 65struct soc *socs = NULL; 66 67static inline void soc_disable(struct soc *s) 68{ 69 sbus_writel(0, s->regs + IMASK); 70 sbus_writel(SOC_CMD_SOFT_RESET, s->regs + CMD); 71} 72 73static inline void soc_enable(struct soc *s) 74{ 75 SOD(("enable %08x\n", s->cfg)) 76 sbus_writel(0, s->regs + SAE); 77 sbus_writel(s->cfg, s->regs + CFG); 78 sbus_writel(SOC_CMD_RSP_QALL, s->regs + CMD); 79 SOC_SETIMASK(s, SOC_IMASK_RSP_QALL | SOC_IMASK_SAE); 80 SOD(("imask %08lx %08lx\n", s->imask, sbus_readl(s->regs + IMAK))); 81} 82 83static void soc_reset(fc_channel *fc) 84{ 85 soc_port *port = (soc_port *)fc; 86 struct soc *s = port->s; 87 88 soc_disable(s); 89 s->req[0].seqno = 1; 90 s->req[1].seqno = 1; 91 s->rsp[0].seqno = 1; 92 s->rsp[1].seqno = 1; 93 s->req[0].in = 0; 94 s->req[1].in = 0; 95 s->rsp[0].in = 0; 96 s->rsp[1].in = 0; 97 s->req[0].out = 0; 98 s->req[1].out = 0; 99 s->rsp[0].out = 0; 100 s->rsp[1].out = 0; 101 102 soc_enable(s); 103} 104 105static void inline soc_solicited (struct soc *s) 106{ 107 fc_hdr fchdr; 108 soc_rsp *hwrsp; 109 soc_cq *sw_cq; 110 int token; 111 int status; 112 fc_channel *fc; 113 114 sw_cq = &s->rsp[SOC_SOLICITED_RSP_Q]; 115 116 if (sw_cq->pool == NULL) 117 sw_cq->pool = (soc_req *) 118 (s->xram + xram_get_32low ((xram_p)&sw_cq->hw_cq->address)); 119 sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); 120 SOD (("soc_solicited, %d pkts arrived\n", (sw_cq->in-sw_cq->out) & sw_cq->last)) 121 for (;;) { 122 hwrsp = (soc_rsp *)sw_cq->pool + sw_cq->out; 123 token = xram_get_32low ((xram_p)&hwrsp->shdr.token); 124 status = xram_get_32low ((xram_p)&hwrsp->status); 125 fc = (fc_channel *)(&s->port[(token >> 11) & 1]); 126 127 if (status == SOC_OK) { 128 fcp_receive_solicited(fc, token >> 12, 129 token & ((1 << 11) - 1), 130 FC_STATUS_OK, NULL); 131 } else { 132 xram_copy_from(&fchdr, (xram_p)&hwrsp->fchdr, sizeof(fchdr)); 133 /* We have intentionally defined FC_STATUS_* constants 134 * to match SOC_* constants, otherwise we'd have to 135 * translate status. 136 */ 137 fcp_receive_solicited(fc, token >> 12, 138 token & ((1 << 11) - 1), 139 status, &fchdr); 140 } 141 142 if (++sw_cq->out > sw_cq->last) { 143 sw_cq->seqno++; 144 sw_cq->out = 0; 145 } 146 147 if (sw_cq->out == sw_cq->in) { 148 sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); 149 if (sw_cq->out == sw_cq->in) { 150 /* Tell the hardware about it */ 151 sbus_writel((sw_cq->out << 24) | 152 (SOC_CMD_RSP_QALL & 153 ~(SOC_CMD_RSP_Q0 << SOC_SOLICITED_RSP_Q)), 154 s->regs + CMD); 155 156 /* Read it, so that we're sure it has been updated */ 157 sbus_readl(s->regs + CMD); 158 sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); 159 if (sw_cq->out == sw_cq->in) 160 break; 161 } 162 } 163 } 164} 165 166static void inline soc_request (struct soc *s, u32 cmd) 167{ 168 SOC_SETIMASK(s, s->imask & ~(cmd & SOC_CMD_REQ_QALL)); 169 SOD(("imask %08lx %08lx\n", s->imask, sbus_readl(s->regs + IMASK))); 170 171 SOD(("Queues available %08x OUT %X %X\n", cmd, 172 xram_get_8((xram_p)&s->req[0].hw_cq->out), 173 xram_get_8((xram_p)&s->req[0].hw_cq->out))) 174 if (s->port[s->curr_port].fc.state != FC_STATE_OFFLINE) { 175 fcp_queue_empty ((fc_channel *)&(s->port[s->curr_port])); 176 if (((s->req[1].in + 1) & s->req[1].last) != (s->req[1].out)) 177 fcp_queue_empty ((fc_channel *)&(s->port[1 - s->curr_port])); 178 } else { 179 fcp_queue_empty ((fc_channel *)&(s->port[1 - s->curr_port])); 180 } 181 if (s->port[1 - s->curr_port].fc.state != FC_STATE_OFFLINE) 182 s->curr_port ^= 1; 183} 184 185static void inline soc_unsolicited (struct soc *s) 186{ 187 soc_rsp *hwrsp, *hwrspc; 188 soc_cq *sw_cq; 189 int count; 190 int status; 191 int flags; 192 fc_channel *fc; 193 194 sw_cq = &s->rsp[SOC_UNSOLICITED_RSP_Q]; 195 if (sw_cq->pool == NULL) 196 sw_cq->pool = (soc_req *) 197 (s->xram + (xram_get_32low ((xram_p)&sw_cq->hw_cq->address))); 198 199 sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); 200 SOD (("soc_unsolicited, %d packets arrived\n", (sw_cq->in - sw_cq->out) & sw_cq->last)) 201 while (sw_cq->in != sw_cq->out) { 202 /* ...real work per entry here... */ 203 hwrsp = (soc_rsp *)sw_cq->pool + sw_cq->out; 204 205 hwrspc = NULL; 206 flags = xram_get_16 ((xram_p)&hwrsp->shdr.flags); 207 count = xram_get_8 ((xram_p)&hwrsp->count); 208 fc = (fc_channel *)&s->port[flags & SOC_PORT_B]; 209 SOD(("FC %08lx fcp_state_change %08lx\n", 210 (long)fc, (long)fc->fcp_state_change)) 211 212 if (count != 1) { 213 /* Ugh, continuation entries */ 214 u8 in; 215 216 if (count != 2) { 217 printk("%s: Too many continuations entries %d\n", 218 fc->name, count); 219 goto update_out; 220 } 221 222 in = sw_cq->in; 223 if (in < sw_cq->out) in += sw_cq->last + 1; 224 if (in < sw_cq->out + 2) { 225 /* Ask the hardware if they haven't arrived yet. */ 226 sbus_writel((sw_cq->out << 24) | 227 (SOC_CMD_RSP_QALL & 228 ~(SOC_CMD_RSP_Q0 << SOC_UNSOLICITED_RSP_Q)), 229 s->regs + CMD); 230 231 /* Read it, so that we're sure it has been updated */ 232 sbus_readl(s->regs + CMD); 233 sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); 234 in = sw_cq->in; 235 if (in < sw_cq->out) 236 in += sw_cq->last + 1; 237 if (in < sw_cq->out + 2) /* Nothing came, let us wait */ 238 return; 239 } 240 if (sw_cq->out == sw_cq->last) 241 hwrspc = (soc_rsp *)sw_cq->pool; 242 else 243 hwrspc = hwrsp + 1; 244 } 245 246 switch (flags & ~SOC_PORT_B) { 247 case SOC_STATUS: 248 status = xram_get_32low ((xram_p)&hwrsp->status); 249 switch (status) { 250 case SOC_ONLINE: 251 SOD(("State change to ONLINE\n")); 252 fcp_state_change(fc, FC_STATE_ONLINE); 253 break; 254 case SOC_OFFLINE: 255 SOD(("State change to OFFLINE\n")); 256 fcp_state_change(fc, FC_STATE_OFFLINE); 257 break; 258 default: 259 printk ("%s: Unknown STATUS no %d\n", 260 fc->name, status); 261 break; 262 } 263 break; 264 case (SOC_UNSOLICITED|SOC_FC_HDR): 265 { 266 int r_ctl = xram_get_8 ((xram_p)&hwrsp->fchdr); 267 unsigned len; 268 char buf[64]; 269 270 if ((r_ctl & 0xf0) == R_CTL_EXTENDED_SVC) { 271 len = xram_get_32 ((xram_p)&hwrsp->shdr.bytecnt); 272 if (len < 4 || !hwrspc) { 273 printk ("%s: Invalid R_CTL %02x " 274 "continuation entries\n", 275 fc->name, r_ctl); 276 } else { 277 if (len > 60) 278 len = 60; 279 xram_copy_from (buf, (xram_p)hwrspc, 280 (len + 3) & ~3); 281 if (*(u32 *)buf == LS_DISPLAY) { 282 int i; 283 284 for (i = 4; i < len; i++) 285 if (buf[i] == '\n') 286 buf[i] = ' '; 287 buf[len] = 0; 288 printk ("%s message: %s\n", 289 fc->name, buf + 4); 290 } else { 291 printk ("%s: Unknown LS_CMD " 292 "%02x\n", fc->name, 293 buf[0]); 294 } 295 } 296 } else { 297 printk ("%s: Unsolicited R_CTL %02x " 298 "not handled\n", fc->name, r_ctl); 299 } 300 } 301 break; 302 default: 303 printk ("%s: Unexpected flags %08x\n", fc->name, flags); 304 break; 305 }; 306update_out: 307 if (++sw_cq->out > sw_cq->last) { 308 sw_cq->seqno++; 309 sw_cq->out = 0; 310 } 311 312 if (hwrspc) { 313 if (++sw_cq->out > sw_cq->last) { 314 sw_cq->seqno++; 315 sw_cq->out = 0; 316 } 317 } 318 319 if (sw_cq->out == sw_cq->in) { 320 sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); 321 if (sw_cq->out == sw_cq->in) { 322 /* Tell the hardware about it */ 323 sbus_writel((sw_cq->out << 24) | 324 (SOC_CMD_RSP_QALL & 325 ~(SOC_CMD_RSP_Q0 << SOC_UNSOLICITED_RSP_Q)), 326 s->regs + CMD); 327 328 /* Read it, so that we're sure it has been updated */ 329 sbus_readl(s->regs + CMD); 330 sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in); 331 } 332 } 333 } 334} 335 336static void soc_intr(int irq, void *dev_id, struct pt_regs *regs) 337{ 338 u32 cmd; 339 unsigned long flags; 340 register struct soc *s = (struct soc *)dev_id; 341 342 spin_lock_irqsave(&io_request_lock, flags); 343 cmd = sbus_readl(s->regs + CMD); 344 for (; (cmd = SOC_INTR (s, cmd)); cmd = sbus_readl(s->regs + CMD)) { 345 if (cmd & SOC_CMD_RSP_Q1) soc_unsolicited (s); 346 if (cmd & SOC_CMD_RSP_Q0) soc_solicited (s); 347 if (cmd & SOC_CMD_REQ_QALL) soc_request (s, cmd); 348 } 349 spin_unlock_irqrestore(&io_request_lock, flags); 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 *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 = kmalloc (sizeof (struct soc), GFP_KERNEL); 557 if (s == NULL) 558 return; 559 memset (s, 0, sizeof(struct soc)); 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, SA_SHIRQ, "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%s\n", __irq_itoa(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 *)(s->xram + SOC_CQ_REQ_OFFSET); 671 s->req[1].hw_cq = (soc_hw_cq *)(s->xram + SOC_CQ_REQ_OFFSET + sizeof(soc_hw_cq)); 672 s->rsp[0].hw_cq = (soc_hw_cq *)(s->xram + SOC_CQ_RSP_OFFSET); 673 s->rsp[1].hw_cq = (soc_hw_cq *)(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 = 0; 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 760EXPORT_NO_SYMBOLS; 761 762module_init(soc_probe); 763module_exit(soc_cleanup); 764MODULE_LICENSE("GPL"); 765