 /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_enable_int_copperhead_memio                            */ /*                                                                          */ /* Routine Description:                                                     */ /*   Turn on interrupts                                                     */ /*                                                                          */ /****************************************************************************/ static void ips_enable_int_copperhead_memio(ips_ha_t * ha) { METHOD_TRACE("ips_enable_int_copperhead_memio", 1);  writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR); readb(ha->mem_ptr + IPS_REG_HISR);	/*Ensure PCI Posting Completes*/ }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_enable_int_morpheus                                    */ /*                                                                          */ /* Routine Description:                                                     */ /*   Turn on interrupts                                                     */ /*                                                                          */ /****************************************************************************/ static void ips_enable_int_morpheus(ips_ha_t * ha) { uint32_t Oimr;  METHOD_TRACE("ips_enable_int_morpheus", 1);  Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR); Oimr &= ~0x08; writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR); readl(ha->mem_ptr + IPS_REG_I960_OIMR);	/*Ensure PCI Posting Completes*/ }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_init_copperhead                                        */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Initialize a copperhead controller                                     */ /*                                                                          */ /****************************************************************************/ static int ips_init_copperhead(ips_ha_t * ha) { uint8_t Isr; uint8_t Cbsp; uint8_t PostByte[IPS_MAX_POST_BYTES]; uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES]; int i, j;  METHOD_TRACE("ips_init_copperhead", 1);  for (i = 0; i < IPS_MAX_POST_BYTES; i++) { for (j = 0; j < 45; j++) { Isr = inb(ha->io_addr + IPS_REG_HISR); if (Isr & IPS_BIT_GHI) break;  /* Delay for 1 Second */ MDELAY(IPS_ONE_SEC); }  if (j >= 45) /* error occurred */ return (0);  PostByte[i] = inb(ha->io_addr + IPS_REG_ISPR); outb(Isr, ha->io_addr + IPS_REG_HISR); }  if (PostByte[0] < IPS_GOOD_POST_STATUS) { IPS_PRINTK(KERN_WARNING, ha->pcidev, "reset controller fails (post status %x %x).\n", PostByte[0], PostByte[1]);  return (0); }  for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) { for (j = 0; j < 240; j++) { Isr = inb(ha->io_addr + IPS_REG_HISR); if (Isr & IPS_BIT_GHI) break;  /* Delay for 1 Second */ MDELAY(IPS_ONE_SEC); }  if (j >= 240) /* error occurred */ return (0);  ConfigByte[i] = inb(ha->io_addr + IPS_REG_ISPR); outb(Isr, ha->io_addr + IPS_REG_HISR); }  for (i = 0; i < 240; i++) { Cbsp = inb(ha->io_addr + IPS_REG_CBSP);  if ((Cbsp & IPS_BIT_OP) == 0) break;  /* Delay for 1 Second */ MDELAY(IPS_ONE_SEC); }  if (i >= 240) /* reset failed */ return (0);  /* setup CCCR */ outl(cpu_to_le32(0x1010), ha->io_addr + IPS_REG_CCCR);  /* Enable busmastering */ outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR);  if (ha->revision_id == IPS_REVID_TROMBONE64) /* fix for anaconda64 */ outl(0, ha->io_addr + IPS_REG_NDAE);  /* Enable interrupts */ outb(IPS_BIT_EI, ha->io_addr + IPS_REG_HISR);  return (1); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_init_copperhead_memio                                  */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Initialize a copperhead controller with memory mapped I/O              */ /*                                                                          */ /****************************************************************************/ static int ips_init_copperhead_memio(ips_ha_t * ha) { uint8_t Isr = 0; uint8_t Cbsp; uint8_t PostByte[IPS_MAX_POST_BYTES]; uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES]; int i, j;  METHOD_TRACE("ips_init_copperhead_memio", 1);  for (i = 0; i < IPS_MAX_POST_BYTES; i++) { for (j = 0; j < 45; j++) { Isr = readb(ha->mem_ptr + IPS_REG_HISR); if (Isr & IPS_BIT_GHI) break;  /* Delay for 1 Second */ MDELAY(IPS_ONE_SEC); }  if (j >= 45) /* error occurred */ return (0);  PostByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR); writeb(Isr, ha->mem_ptr + IPS_REG_HISR); }  if (PostByte[0] < IPS_GOOD_POST_STATUS) { IPS_PRINTK(KERN_WARNING, ha->pcidev, "reset controller fails (post status %x %x).\n", PostByte[0], PostByte[1]);  return (0); }  for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) { for (j = 0; j < 240; j++) { Isr = readb(ha->mem_ptr + IPS_REG_HISR); if (Isr & IPS_BIT_GHI) break;  /* Delay for 1 Second */ MDELAY(IPS_ONE_SEC); }  if (j >= 240) /* error occurred */ return (0);  ConfigByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR); writeb(Isr, ha->mem_ptr + IPS_REG_HISR); }  for (i = 0; i < 240; i++) { Cbsp = readb(ha->mem_ptr + IPS_REG_CBSP);  if ((Cbsp & IPS_BIT_OP) == 0) break;  /* Delay for 1 Second */ MDELAY(IPS_ONE_SEC); }  if (i >= 240) /* error occurred */ return (0);  /* setup CCCR */ writel(0x1010, ha->mem_ptr + IPS_REG_CCCR);  /* Enable busmastering */ writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR);  if (ha->revision_id == IPS_REVID_TROMBONE64) /* fix for anaconda64 */ writel(0, ha->mem_ptr + IPS_REG_NDAE);  /* Enable interrupts */ writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR);  /* if we get here then everything went OK */ return (1); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_init_morpheus                                          */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Initialize a morpheus controller                                       */ /*                                                                          */ /****************************************************************************/ static int ips_init_morpheus(ips_ha_t * ha) { uint32_t Post; uint32_t Config; uint32_t Isr; uint32_t Oimr; int i;  METHOD_TRACE("ips_init_morpheus", 1);  /* Wait up to 45 secs for Post */ for (i = 0; i < 45; i++) { Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);  if (Isr & IPS_BIT_I960_MSG0I) break;  /* Delay for 1 Second */ MDELAY(IPS_ONE_SEC); }  if (i >= 45) { /* error occurred */ IPS_PRINTK(KERN_WARNING, ha->pcidev, "timeout waiting for post.\n");  return (0); }  Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);  if (Post == 0x4F00) {	/* If Flashing the Battery PIC         */ IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flashing Battery PIC, Please wait ...\n");  /* Clear the interrupt bit */ Isr = (uint32_t) IPS_BIT_I960_MSG0I; writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);  for (i = 0; i < 120; i++) {	/*    Wait Up to 2 Min. for Completion */ Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0); if (Post != 0x4F00) break; /* Delay for 1 Second */ MDELAY(IPS_ONE_SEC); }  if (i >= 120) { IPS_PRINTK(KERN_WARNING, ha->pcidev, "timeout waiting for Battery PIC Flash\n"); return (0); }  }  /* Clear the interrupt bit */ Isr = (uint32_t) IPS_BIT_I960_MSG0I; writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);  if (Post < (IPS_GOOD_POST_STATUS << 8)) { IPS_PRINTK(KERN_WARNING, ha->pcidev, "reset controller fails (post status %x).\n", Post);  return (0); }  /* Wait up to 240 secs for config bytes */ for (i = 0; i < 240; i++) { Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);  if (Isr & IPS_BIT_I960_MSG1I) break;  /* Delay for 1 Second */ MDELAY(IPS_ONE_SEC); }  if (i >= 240) { /* error occurred */ IPS_PRINTK(KERN_WARNING, ha->pcidev, "timeout waiting for config.\n");  return (0); }  Config = readl(ha->mem_ptr + IPS_REG_I960_MSG1);  /* Clear interrupt bit */ Isr = (uint32_t) IPS_BIT_I960_MSG1I; writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);  /* Turn on the interrupts */ Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR); Oimr &= ~0x8; writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR);  /* if we get here then everything went OK */  /* Since we did a RESET, an EraseStripeLock may be needed */ if (Post == 0xEF10) { if ((Config == 0x000F) || (Config == 0x0009)) ha->requires_esl = 1; }  return (1); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_reset_copperhead                                       */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Reset the controller                                                   */ /*                                                                          */ /****************************************************************************/ static int ips_reset_copperhead(ips_ha_t * ha) { int reset_counter;  METHOD_TRACE("ips_reset_copperhead", 1);  DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d", ips_name, ha->host_num, ha->io_addr, ha->irq);  reset_counter = 0;  while (reset_counter < 2) { reset_counter++;  outb(IPS_BIT_RST, ha->io_addr + IPS_REG_SCPR);  /* Delay for 1 Second */ MDELAY(IPS_ONE_SEC);  outb(0, ha->io_addr + IPS_REG_SCPR);  /* Delay for 1 Second */ MDELAY(IPS_ONE_SEC);  if ((*ha->func.init) (ha)) break; else if (reset_counter >= 2) {  return (0); } }  return (1); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_reset_copperhead_memio                                 */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Reset the controller                                                   */ /*                                                                          */ /****************************************************************************/ static int ips_reset_copperhead_memio(ips_ha_t * ha) { int reset_counter;  METHOD_TRACE("ips_reset_copperhead_memio", 1);  DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d", ips_name, ha->host_num, ha->mem_addr, ha->irq);  reset_counter = 0;  while (reset_counter < 2) { reset_counter++;  writeb(IPS_BIT_RST, ha->mem_ptr + IPS_REG_SCPR);  /* Delay for 1 Second */ MDELAY(IPS_ONE_SEC);  writeb(0, ha->mem_ptr + IPS_REG_SCPR);  /* Delay for 1 Second */ MDELAY(IPS_ONE_SEC);  if ((*ha->func.init) (ha)) break; else if (reset_counter >= 2) {  return (0); } }  return (1); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_reset_morpheus                                         */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Reset the controller                                                   */ /*                                                                          */ /****************************************************************************/ static int ips_reset_morpheus(ips_ha_t * ha) { int reset_counter; uint8_t junk;  METHOD_TRACE("ips_reset_morpheus", 1);  DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d", ips_name, ha->host_num, ha->mem_addr, ha->irq);  reset_counter = 0;  while (reset_counter < 2) { reset_counter++;  writel(0x80000000, ha->mem_ptr + IPS_REG_I960_IDR);  /* Delay for 5 Seconds */ MDELAY(5 * IPS_ONE_SEC);  /* Do a PCI config read to wait for adapter */ pci_read_config_byte(ha->pcidev, 4, &junk);  if ((*ha->func.init) (ha)) break; else if (reset_counter >= 2) {  return (0); } }  return (1); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_statinit                                               */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Initialize the status queues on the controller                         */ /*                                                                          */ /****************************************************************************/ static void ips_statinit(ips_ha_t * ha) { uint32_t phys_status_start;  METHOD_TRACE("ips_statinit", 1);  ha->adapt->p_status_start = ha->adapt->status; ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS; ha->adapt->p_status_tail = ha->adapt->status;  phys_status_start = ha->adapt->hw_status_start; outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQSR); outl(cpu_to_le32(phys_status_start + IPS_STATUS_Q_SIZE), ha->io_addr + IPS_REG_SQER); outl(cpu_to_le32(phys_status_start + IPS_STATUS_SIZE), ha->io_addr + IPS_REG_SQHR); outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQTR);  ha->adapt->hw_status_tail = phys_status_start; }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_statinit_memio                                         */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Initialize the status queues on the controller                         */ /*                                                                          */ /****************************************************************************/ static void ips_statinit_memio(ips_ha_t * ha) { uint32_t phys_status_start;  METHOD_TRACE("ips_statinit_memio", 1);  ha->adapt->p_status_start = ha->adapt->status; ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS; ha->adapt->p_status_tail = ha->adapt->status;  phys_status_start = ha->adapt->hw_status_start; writel(phys_status_start, ha->mem_ptr + IPS_REG_SQSR); writel(phys_status_start + IPS_STATUS_Q_SIZE, ha->mem_ptr + IPS_REG_SQER); writel(phys_status_start + IPS_STATUS_SIZE, ha->mem_ptr + IPS_REG_SQHR); writel(phys_status_start, ha->mem_ptr + IPS_REG_SQTR);  ha->adapt->hw_status_tail = phys_status_start; }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_statupd_copperhead                                     */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Remove an element from the status queue                                */ /*                                                                          */ /****************************************************************************/ static uint32_t ips_statupd_copperhead(ips_ha_t * ha) { METHOD_TRACE("ips_statupd_copperhead", 1);  if (ha->adapt->p_status_tail != ha->adapt->p_status_end) { ha->adapt->p_status_tail++; ha->adapt->hw_status_tail += sizeof (IPS_STATUS); } else { ha->adapt->p_status_tail = ha->adapt->p_status_start; ha->adapt->hw_status_tail = ha->adapt->hw_status_start; }  outl(cpu_to_le32(ha->adapt->hw_status_tail), ha->io_addr + IPS_REG_SQTR);  return (ha->adapt->p_status_tail->value); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_statupd_copperhead_memio                               */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Remove an element from the status queue                                */ /*                                                                          */ /****************************************************************************/ static uint32_t ips_statupd_copperhead_memio(ips_ha_t * ha) { METHOD_TRACE("ips_statupd_copperhead_memio", 1);  if (ha->adapt->p_status_tail != ha->adapt->p_status_end) { ha->adapt->p_status_tail++; ha->adapt->hw_status_tail += sizeof (IPS_STATUS); } else { ha->adapt->p_status_tail = ha->adapt->p_status_start; ha->adapt->hw_status_tail = ha->adapt->hw_status_start; }  writel(ha->adapt->hw_status_tail, ha->mem_ptr + IPS_REG_SQTR);  return (ha->adapt->p_status_tail->value); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_statupd_morpheus                                       */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Remove an element from the status queue                                */ /*                                                                          */ /****************************************************************************/ static uint32_t ips_statupd_morpheus(ips_ha_t * ha) { uint32_t val;  METHOD_TRACE("ips_statupd_morpheus", 1);  val = readl(ha->mem_ptr + IPS_REG_I2O_OUTMSGQ);  return (val); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_issue_copperhead                                       */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Send a command down to the controller                                  */ /*                                                                          */ /****************************************************************************/ static int ips_issue_copperhead(ips_ha_t * ha, ips_scb_t * scb) { uint32_t TimeOut; uint32_t val;  METHOD_TRACE("ips_issue_copperhead", 1);  if (scb->scsi_cmd) { DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", ips_name, ha->host_num, scb->cdb[0], scb->cmd.basic_io.command_id, scb->bus, scb->target_id, scb->lun); } else { DEBUG_VAR(2, KERN_NOTICE "(%s%d) ips_issue: logical cmd id %d", ips_name, ha->host_num, scb->cmd.basic_io.command_id); }  TimeOut = 0;  while ((val = le32_to_cpu(inl(ha->io_addr + IPS_REG_CCCR))) & IPS_BIT_SEM) { udelay(1000);  if (++TimeOut >= IPS_SEM_TIMEOUT) { if (!(val & IPS_BIT_START_STOP)) break;  IPS_PRINTK(KERN_WARNING, ha->pcidev, "ips_issue val [0x%x].\n", val); IPS_PRINTK(KERN_WARNING, ha->pcidev, "ips_issue semaphore chk timeout.\n");  return (IPS_FAILURE); }		/* end if */ }			/* end while */  outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_CCSAR); outw(cpu_to_le32(IPS_BIT_START_CMD), ha->io_addr + IPS_REG_CCCR);  return (IPS_SUCCESS); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_issue_copperhead_memio                                 */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Send a command down to the controller                                  */ /*                                                                          */ /****************************************************************************/ static int ips_issue_copperhead_memio(ips_ha_t * ha, ips_scb_t * scb) { uint32_t TimeOut; uint32_t val;  METHOD_TRACE("ips_issue_copperhead_memio", 1);  if (scb->scsi_cmd) { DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", ips_name, ha->host_num, scb->cdb[0], scb->cmd.basic_io.command_id, scb->bus, scb->target_id, scb->lun); } else { DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", ips_name, ha->host_num, scb->cmd.basic_io.command_id); }  TimeOut = 0;  while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) { udelay(1000);  if (++TimeOut >= IPS_SEM_TIMEOUT) { if (!(val & IPS_BIT_START_STOP)) break;  IPS_PRINTK(KERN_WARNING, ha->pcidev, "ips_issue val [0x%x].\n", val); IPS_PRINTK(KERN_WARNING, ha->pcidev, "ips_issue semaphore chk timeout.\n");  return (IPS_FAILURE); }		/* end if */ }			/* end while */  writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_CCSAR); writel(IPS_BIT_START_CMD, ha->mem_ptr + IPS_REG_CCCR);  return (IPS_SUCCESS); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_issue_i2o                                              */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Send a command down to the controller                                  */ /*                                                                          */ /****************************************************************************/ static int ips_issue_i2o(ips_ha_t * ha, ips_scb_t * scb) {  METHOD_TRACE("ips_issue_i2o", 1);  if (scb->scsi_cmd) { DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", ips_name, ha->host_num, scb->cdb[0], scb->cmd.basic_io.command_id, scb->bus, scb->target_id, scb->lun); } else { DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", ips_name, ha->host_num, scb->cmd.basic_io.command_id); }  outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_I2O_INMSGQ);  return (IPS_SUCCESS); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_issue_i2o_memio                                        */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Send a command down to the controller                                  */ /*                                                                          */ /****************************************************************************/ static int ips_issue_i2o_memio(ips_ha_t * ha, ips_scb_t * scb) {  METHOD_TRACE("ips_issue_i2o_memio", 1);  if (scb->scsi_cmd) { DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", ips_name, ha->host_num, scb->cdb[0], scb->cmd.basic_io.command_id, scb->bus, scb->target_id, scb->lun); } else { DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", ips_name, ha->host_num, scb->cmd.basic_io.command_id); }  writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_I2O_INMSGQ);  return (IPS_SUCCESS); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_isintr_copperhead                                      */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Test to see if an interrupt is for us                                  */ /*                                                                          */ /****************************************************************************/ static int ips_isintr_copperhead(ips_ha_t * ha) { uint8_t Isr;  METHOD_TRACE("ips_isintr_copperhead", 2);  Isr = inb(ha->io_addr + IPS_REG_HISR);  if (Isr == 0xFF) /* ?!?! Nothing really there */ return (0);  if (Isr & IPS_BIT_SCE) return (1); else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) { /* status queue overflow or GHI */ /* just clear the interrupt */ outb(Isr, ha->io_addr + IPS_REG_HISR); }  return (0); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_isintr_copperhead_memio                                */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Test to see if an interrupt is for us                                  */ /*                                                                          */ /****************************************************************************/ static int ips_isintr_copperhead_memio(ips_ha_t * ha) { uint8_t Isr;  METHOD_TRACE("ips_isintr_memio", 2);  Isr = readb(ha->mem_ptr + IPS_REG_HISR);  if (Isr == 0xFF) /* ?!?! Nothing really there */ return (0);  if (Isr & IPS_BIT_SCE) return (1); else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) { /* status queue overflow or GHI */ /* just clear the interrupt */ writeb(Isr, ha->mem_ptr + IPS_REG_HISR); }  return (0); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_isintr_morpheus                                        */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Test to see if an interrupt is for us                                  */ /*                                                                          */ /****************************************************************************/ static int ips_isintr_morpheus(ips_ha_t * ha) { uint32_t Isr;  METHOD_TRACE("ips_isintr_morpheus", 2);  Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);  if (Isr & IPS_BIT_I2O_OPQI) return (1); else return (0); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_wait                                                   */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Wait for a command to complete                                         */ /*                                                                          */ /****************************************************************************/ static int ips_wait(ips_ha_t * ha, int time, int intr) { int ret; int done;  METHOD_TRACE("ips_wait", 1);  ret = IPS_FAILURE; done = FALSE;  time *= IPS_ONE_SEC;	/* convert seconds */  while ((time > 0) && (!done)) { if (intr == IPS_INTR_ON) { if (ha->waitflag == FALSE) { ret = IPS_SUCCESS; done = TRUE; break; } } else if (intr == IPS_INTR_IORL) { if (ha->waitflag == FALSE) { /* * controller generated an interrupt to * acknowledge completion of the command * and ips_intr() has serviced the interrupt. */ ret = IPS_SUCCESS; done = TRUE; break; }  /* * NOTE: we already have the io_request_lock so * even if we get an interrupt it won't get serviced * until after we finish. */  (*ha->func.intr) (ha); }  /* This looks like a very evil loop, but it only does this during start-up */ udelay(1000); time--; }  return (ret); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_write_driver_status                                    */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Write OS/Driver version to Page 5 of the nvram on the controller       */ /*                                                                          */ /****************************************************************************/ static int ips_write_driver_status(ips_ha_t * ha, int intr) { METHOD_TRACE("ips_write_driver_status", 1);  if (!ips_readwrite_page5(ha, FALSE, intr)) { IPS_PRINTK(KERN_WARNING, ha->pcidev, "unable to read NVRAM page 5.\n");  return (0); }  /* check to make sure the page has a valid */ /* signature */ if (le32_to_cpu(ha->nvram->signature) != IPS_NVRAM_P5_SIG) { DEBUG_VAR(1, "(%s%d) NVRAM page 5 has an invalid signature: %X.", ips_name, ha->host_num, ha->nvram->signature); ha->nvram->signature = IPS_NVRAM_P5_SIG; }  DEBUG_VAR(2, "(%s%d) Ad Type: %d, Ad Slot: %d, BIOS: %c%c%c%c %c%c%c%c.", ips_name, ha->host_num, le16_to_cpu(ha->nvram->adapter_type), ha->nvram->adapter_slot, ha->nvram->bios_high[0], ha->nvram->bios_high[1], ha->nvram->bios_high[2], ha->nvram->bios_high[3], ha->nvram->bios_low[0], ha->nvram->bios_low[1], ha->nvram->bios_low[2], ha->nvram->bios_low[3]);  ips_get_bios_version(ha, intr);  /* change values (as needed) */ ha->nvram->operating_system = IPS_OS_LINUX; ha->nvram->adapter_type = ha->ad_type; strncpy((char *) ha->nvram->driver_high, IPS_VERSION_HIGH, 4); strncpy((char *) ha->nvram->driver_low, IPS_VERSION_LOW, 4); strncpy((char *) ha->nvram->bios_high, ha->bios_version, 4); strncpy((char *) ha->nvram->bios_low, ha->bios_version + 4, 4);  ips_version_check(ha, intr);	/* Check BIOS/FW/Driver Versions */  /* now update the page */ if (!ips_readwrite_page5(ha, TRUE, intr)) { IPS_PRINTK(KERN_WARNING, ha->pcidev, "unable to write NVRAM page 5.\n");  return (0); }  /* IF NVRAM Page 5 is OK, Use it for Slot Number Info Because Linux Doesn't Do Slots */ ha->slot_num = ha->nvram->adapter_slot;  return (1); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_read_adapter_status                                    */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Do an Inquiry command to the adapter                                   */ /*                                                                          */ /****************************************************************************/ static int ips_read_adapter_status(ips_ha_t * ha, int intr) { ips_scb_t *scb; int ret;  METHOD_TRACE("ips_read_adapter_status", 1);  scb = &ha->scbs[ha->max_cmds - 1];  ips_init_scb(ha, scb);  scb->timeout = ips_cmd_timeout; scb->cdb[0] = IPS_CMD_ENQUIRY;  scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY; scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); scb->cmd.basic_io.sg_count = 0; scb->cmd.basic_io.lba = 0; scb->cmd.basic_io.sector_count = 0; scb->cmd.basic_io.log_drv = 0; scb->data_len = sizeof (*ha->enq); scb->cmd.basic_io.sg_addr = ha->enq_busaddr;  /* send command */ if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM) || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) return (0);  return (1); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_read_subsystem_parameters                              */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Read subsystem parameters from the adapter                             */ /*                                                                          */ /****************************************************************************/ static int ips_read_subsystem_parameters(ips_ha_t * ha, int intr) { ips_scb_t *scb; int ret;  METHOD_TRACE("ips_read_subsystem_parameters", 1);  scb = &ha->scbs[ha->max_cmds - 1];  ips_init_scb(ha, scb);  scb->timeout = ips_cmd_timeout; scb->cdb[0] = IPS_CMD_GET_SUBSYS;  scb->cmd.basic_io.op_code = IPS_CMD_GET_SUBSYS; scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); scb->cmd.basic_io.sg_count = 0; scb->cmd.basic_io.lba = 0; scb->cmd.basic_io.sector_count = 0; scb->cmd.basic_io.log_drv = 0; scb->data_len = sizeof (*ha->subsys); scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr;  /* send command */ if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM) || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) return (0);  memcpy(ha->subsys, ha->ioctl_data, sizeof(*ha->subsys)); return (1); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_read_config                                            */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Read the configuration on the adapter                                  */ /*                                                                          */ /****************************************************************************/ static int ips_read_config(ips_ha_t * ha, int intr) { ips_scb_t *scb; int i; int ret;  METHOD_TRACE("ips_read_config", 1);  /* set defaults for initiator IDs */ for (i = 0; i < 4; i++) ha->conf->init_id[i] = 7;  scb = &ha->scbs[ha->max_cmds - 1];  ips_init_scb(ha, scb);  scb->timeout = ips_cmd_timeout; scb->cdb[0] = IPS_CMD_READ_CONF;  scb->cmd.basic_io.op_code = IPS_CMD_READ_CONF; scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); scb->data_len = sizeof (*ha->conf); scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr;  /* send command */ if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM) || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {  memset(ha->conf, 0, sizeof (IPS_CONF));  /* reset initiator IDs */ for (i = 0; i < 4; i++) ha->conf->init_id[i] = 7;  /* Allow Completed with Errors, so JCRM can access the Adapter to fix the problems */ if ((scb->basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_CMPLT_WERROR) return (1);  return (0); }  memcpy(ha->conf, ha->ioctl_data, sizeof(*ha->conf)); return (1); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_readwrite_page5                                        */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Read nvram page 5 from the adapter                                     */ /*                                                                          */ /****************************************************************************/ static int ips_readwrite_page5(ips_ha_t * ha, int write, int intr) { ips_scb_t *scb; int ret;  METHOD_TRACE("ips_readwrite_page5", 1);  scb = &ha->scbs[ha->max_cmds - 1];  ips_init_scb(ha, scb);  scb->timeout = ips_cmd_timeout; scb->cdb[0] = IPS_CMD_RW_NVRAM_PAGE;  scb->cmd.nvram.op_code = IPS_CMD_RW_NVRAM_PAGE; scb->cmd.nvram.command_id = IPS_COMMAND_ID(ha, scb); scb->cmd.nvram.page = 5; scb->cmd.nvram.write = write; scb->cmd.nvram.reserved = 0; scb->cmd.nvram.reserved2 = 0; scb->data_len = sizeof (*ha->nvram); scb->cmd.nvram.buffer_addr = ha->ioctl_busaddr; if (write) memcpy(ha->ioctl_data, ha->nvram, sizeof(*ha->nvram));  /* issue the command */ if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM) || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {  memset(ha->nvram, 0, sizeof (IPS_NVRAM_P5));  return (0); } if (!write) memcpy(ha->nvram, ha->ioctl_data, sizeof(*ha->nvram)); return (1); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_clear_adapter                                          */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   Clear the stripe lock tables                                           */ /*                                                                          */ /****************************************************************************/ static int ips_clear_adapter(ips_ha_t * ha, int intr) { ips_scb_t *scb; int ret;  METHOD_TRACE("ips_clear_adapter", 1);  scb = &ha->scbs[ha->max_cmds - 1];  ips_init_scb(ha, scb);  scb->timeout = ips_reset_timeout; scb->cdb[0] = IPS_CMD_CONFIG_SYNC;  scb->cmd.config_sync.op_code = IPS_CMD_CONFIG_SYNC; scb->cmd.config_sync.command_id = IPS_COMMAND_ID(ha, scb); scb->cmd.config_sync.channel = 0; scb->cmd.config_sync.source_target = IPS_POCL; scb->cmd.config_sync.reserved = 0; scb->cmd.config_sync.reserved2 = 0; scb->cmd.config_sync.reserved3 = 0;  /* issue command */ if (((ret = ips_send_wait(ha, scb, ips_reset_timeout, intr)) == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM) || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) return (0);  /* send unlock stripe command */ ips_init_scb(ha, scb);  scb->cdb[0] = IPS_CMD_ERROR_TABLE; scb->timeout = ips_reset_timeout;  scb->cmd.unlock_stripe.op_code = IPS_CMD_ERROR_TABLE; scb->cmd.unlock_stripe.command_id = IPS_COMMAND_ID(ha, scb); scb->cmd.unlock_stripe.log_drv = 0; scb->cmd.unlock_stripe.control = IPS_CSL; scb->cmd.unlock_stripe.reserved = 0; scb->cmd.unlock_stripe.reserved2 = 0; scb->cmd.unlock_stripe.reserved3 = 0;  /* issue command */ if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM) || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) return (0);  return (1); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_ffdc_reset                                             */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   FFDC: write reset info                                                 */ /*                                                                          */ /****************************************************************************/ static void ips_ffdc_reset(ips_ha_t * ha, int intr) { ips_scb_t *scb;  METHOD_TRACE("ips_ffdc_reset", 1);  scb = &ha->scbs[ha->max_cmds - 1];  ips_init_scb(ha, scb);  scb->timeout = ips_cmd_timeout; scb->cdb[0] = IPS_CMD_FFDC; scb->cmd.ffdc.op_code = IPS_CMD_FFDC; scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb); scb->cmd.ffdc.reset_count = ha->reset_count; scb->cmd.ffdc.reset_type = 0x80;  /* convert time to what the card wants */ ips_fix_ffdc_time(ha, scb, ha->last_ffdc);  /* issue command */ ips_send_wait(ha, scb, ips_cmd_timeout, intr); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_ffdc_time                                              */ /*                                                                          */ /* Routine Description:                                                     */ /*                                                                          */ /*   FFDC: write time info                                                  */ /*                                                                          */ /****************************************************************************/ static void ips_ffdc_time(ips_ha_t * ha) { ips_scb_t *scb;  METHOD_TRACE("ips_ffdc_time", 1);  DEBUG_VAR(1, "(%s%d) Sending time update.", ips_name, ha->host_num);  scb = &ha->scbs[ha->max_cmds - 1];  ips_init_scb(ha, scb);  scb->timeout = ips_cmd_timeout; scb->cdb[0] = IPS_CMD_FFDC; scb->cmd.ffdc.op_code = IPS_CMD_FFDC; scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb); scb->cmd.ffdc.reset_count = 0; scb->cmd.ffdc.reset_type = 0;  /* convert time to what the card wants */ ips_fix_ffdc_time(ha, scb, ha->last_ffdc);  /* issue command */ ips_send_wait(ha, scb, ips_cmd_timeout, IPS_FFDC); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_fix_ffdc_time                                          */ /*                                                                          */ /* Routine Description:                                                     */ /*   Adjust time_t to what the card wants                                   */ /*                                                                          */ /****************************************************************************/ static void ips_fix_ffdc_time(ips_ha_t * ha, ips_scb_t * scb, time_t current_time) { long days; long rem; int i; int year; int yleap; int year_lengths[2] = { IPS_DAYS_NORMAL_YEAR, IPS_DAYS_LEAP_YEAR }; int month_lengths[12][2] = { {31, 31}, {28, 29}, {31, 31}, {30, 30}, {31, 31}, {30, 30}, {31, 31}, {31, 31}, {30, 30}, {31, 31}, {30, 30}, {31, 31} };  METHOD_TRACE("ips_fix_ffdc_time", 1);  days = current_time / IPS_SECS_DAY; rem = current_time % IPS_SECS_DAY;  scb->cmd.ffdc.hour = (rem / IPS_SECS_HOUR); rem = rem % IPS_SECS_HOUR; scb->cmd.ffdc.minute = (rem / IPS_SECS_MIN); scb->cmd.ffdc.second = (rem % IPS_SECS_MIN);  year = IPS_EPOCH_YEAR; while (days < 0 || days >= year_lengths[yleap = IPS_IS_LEAP_YEAR(year)]) { int newy;  newy = year + (days / IPS_DAYS_NORMAL_YEAR); if (days < 0) --newy; days -= (newy - year) * IPS_DAYS_NORMAL_YEAR + IPS_NUM_LEAP_YEARS_THROUGH(newy - 1) - IPS_NUM_LEAP_YEARS_THROUGH(year - 1); year = newy; }  scb->cmd.ffdc.yearH = year / 100; scb->cmd.ffdc.yearL = year % 100;  for (i = 0; days >= month_lengths[i][yleap]; ++i) days -= month_lengths[i][yleap];  scb->cmd.ffdc.month = i + 1; scb->cmd.ffdc.day = days + 1; }  /**************************************************************************** * BIOS Flash Routines                                                      * ****************************************************************************/  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_erase_bios                                             */ /*                                                                          */ /* Routine Description:                                                     */ /*   Erase the BIOS on the adapter                                          */ /*                                                                          */ /****************************************************************************/ static int ips_erase_bios(ips_ha_t * ha) { int timeout; uint8_t status = 0;  METHOD_TRACE("ips_erase_bios", 1);  status = 0;  /* Clear the status register */ outl(0, ha->io_addr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  outb(0x50, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  /* Erase Setup */ outb(0x20, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  /* Erase Confirm */ outb(0xD0, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  /* Erase Status */ outb(0x70, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  timeout = 80000;	/* 80 seconds */  while (timeout > 0) { if (ha->revision_id == IPS_REVID_TROMBONE64) { outl(0, ha->io_addr + IPS_REG_FLAP); udelay(25);	/* 25 us */ }  status = inb(ha->io_addr + IPS_REG_FLDP);  if (status & 0x80) break;  MDELAY(1); timeout--; }  /* check for timeout */ if (timeout <= 0) { /* timeout */  /* try to suspend the erase */ outb(0xB0, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  /* wait for 10 seconds */ timeout = 10000; while (timeout > 0) { if (ha->revision_id == IPS_REVID_TROMBONE64) { outl(0, ha->io_addr + IPS_REG_FLAP); udelay(25);	/* 25 us */ }  status = inb(ha->io_addr + IPS_REG_FLDP);  if (status & 0xC0) break;  MDELAY(1); timeout--; }  return (1); }  /* check for valid VPP */ if (status & 0x08) /* VPP failure */ return (1);  /* check for succesful flash */ if (status & 0x30) /* sequence error */ return (1);  /* Otherwise, we were successful */ /* clear status */ outb(0x50, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  /* enable reads */ outb(0xFF, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  return (0); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_erase_bios_memio                                       */ /*                                                                          */ /* Routine Description:                                                     */ /*   Erase the BIOS on the adapter                                          */ /*                                                                          */ /****************************************************************************/ static int ips_erase_bios_memio(ips_ha_t * ha) { int timeout; uint8_t status;  METHOD_TRACE("ips_erase_bios_memio", 1);  status = 0;  /* Clear the status register */ writel(0, ha->mem_ptr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  writeb(0x50, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  /* Erase Setup */ writeb(0x20, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  /* Erase Confirm */ writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  /* Erase Status */ writeb(0x70, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  timeout = 80000;	/* 80 seconds */  while (timeout > 0) { if (ha->revision_id == IPS_REVID_TROMBONE64) { writel(0, ha->mem_ptr + IPS_REG_FLAP); udelay(25);	/* 25 us */ }  status = readb(ha->mem_ptr + IPS_REG_FLDP);  if (status & 0x80) break;  MDELAY(1); timeout--; }  /* check for timeout */ if (timeout <= 0) { /* timeout */  /* try to suspend the erase */ writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  /* wait for 10 seconds */ timeout = 10000; while (timeout > 0) { if (ha->revision_id == IPS_REVID_TROMBONE64) { writel(0, ha->mem_ptr + IPS_REG_FLAP); udelay(25);	/* 25 us */ }  status = readb(ha->mem_ptr + IPS_REG_FLDP);  if (status & 0xC0) break;  MDELAY(1); timeout--; }  return (1); }  /* check for valid VPP */ if (status & 0x08) /* VPP failure */ return (1);  /* check for succesful flash */ if (status & 0x30) /* sequence error */ return (1);  /* Otherwise, we were successful */ /* clear status */ writeb(0x50, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  /* enable reads */ writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  return (0); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_program_bios                                           */ /*                                                                          */ /* Routine Description:                                                     */ /*   Program the BIOS on the adapter                                        */ /*                                                                          */ /****************************************************************************/ static int ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, uint32_t offset) { int i; int timeout; uint8_t status = 0;  METHOD_TRACE("ips_program_bios", 1);  status = 0;  for (i = 0; i < buffersize; i++) { /* write a byte */ outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  outb(0x40, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  outb(buffer[i], ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  /* wait up to one second */ timeout = 1000; while (timeout > 0) { if (ha->revision_id == IPS_REVID_TROMBONE64) { outl(0, ha->io_addr + IPS_REG_FLAP); udelay(25);	/* 25 us */ }  status = inb(ha->io_addr + IPS_REG_FLDP);  if (status & 0x80) break;  MDELAY(1); timeout--; }  if (timeout == 0) { /* timeout error */ outl(0, ha->io_addr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  outb(0xFF, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  return (1); }  /* check the status */ if (status & 0x18) { /* programming error */ outl(0, ha->io_addr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  outb(0xFF, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  return (1); } }			/* end for */  /* Enable reading */ outl(0, ha->io_addr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  outb(0xFF, ha->io_addr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  return (0); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_program_bios_memio                                     */ /*                                                                          */ /* Routine Description:                                                     */ /*   Program the BIOS on the adapter                                        */ /*                                                                          */ /****************************************************************************/ static int ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize, uint32_t offset) { int i; int timeout; uint8_t status = 0;  METHOD_TRACE("ips_program_bios_memio", 1);  status = 0;  for (i = 0; i < buffersize; i++) { /* write a byte */ writel(i + offset, ha->mem_ptr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  writeb(0x40, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  /* wait up to one second */ timeout = 1000; while (timeout > 0) { if (ha->revision_id == IPS_REVID_TROMBONE64) { writel(0, ha->mem_ptr + IPS_REG_FLAP); udelay(25);	/* 25 us */ }  status = readb(ha->mem_ptr + IPS_REG_FLDP);  if (status & 0x80) break;  MDELAY(1); timeout--; }  if (timeout == 0) { /* timeout error */ writel(0, ha->mem_ptr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  return (1); }  /* check the status */ if (status & 0x18) { /* programming error */ writel(0, ha->mem_ptr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  return (1); } }			/* end for */  /* Enable reading */ writel(0, ha->mem_ptr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  return (0); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_verify_bios                                            */ /*                                                                          */ /* Routine Description:                                                     */ /*   Verify the BIOS on the adapter                                         */ /*                                                                          */ /****************************************************************************/ static int ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, uint32_t offset) { uint8_t checksum; int i;  METHOD_TRACE("ips_verify_bios", 1);  /* test 1st byte */ outl(0, ha->io_addr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55) return (1);  outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */ if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA) return (1);  checksum = 0xff; for (i = 2; i < buffersize; i++) {  outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  checksum = (uint8_t) checksum + inb(ha->io_addr + IPS_REG_FLDP); }  if (checksum != 0) /* failure */ return (1); else /* success */ return (0); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_verify_bios_memio                                      */ /*                                                                          */ /* Routine Description:                                                     */ /*   Verify the BIOS on the adapter                                         */ /*                                                                          */ /****************************************************************************/ static int ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize, uint32_t offset) { uint8_t checksum; int i;  METHOD_TRACE("ips_verify_bios_memio", 1);  /* test 1st byte */ writel(0, ha->mem_ptr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55) return (1);  writel(1, ha->mem_ptr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */ if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA) return (1);  checksum = 0xff; for (i = 2; i < buffersize; i++) {  writel(i + offset, ha->mem_ptr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) udelay(25);	/* 25 us */  checksum = (uint8_t) checksum + readb(ha->mem_ptr + IPS_REG_FLDP); }  if (checksum != 0) /* failure */ return (1); else /* success */ return (0); }  /*---------------------------------------------------------------------------*/ /*   Routine Name: ips_version_check                                         */ /*                                                                           */ /*   Dependencies:                                                           */ /*     Assumes that ips_read_adapter_status() is called first filling in     */ /*     the data for SubSystem Parameters.                                    */ /*     Called from ips_write_driver_status() so it also assumes NVRAM Page 5 */ /*     Data is available.                                                    */ /*                                                                           */ /*---------------------------------------------------------------------------*/ static void ips_version_check(ips_ha_t * ha, int intr) { IPS_VERSION_DATA *VersionInfo; uint8_t FirmwareVersion[IPS_COMPAT_ID_LENGTH + 1]; uint8_t BiosVersion[IPS_COMPAT_ID_LENGTH + 1]; int MatchError; int rc; char BiosString[10]; char FirmwareString[10];  METHOD_TRACE("ips_version_check", 1);  VersionInfo = ( IPS_VERSION_DATA * ) ha->ioctl_data;  memset(FirmwareVersion, 0, IPS_COMPAT_ID_LENGTH + 1); memset(BiosVersion, 0, IPS_COMPAT_ID_LENGTH + 1);  /* Get the Compatible BIOS Version from NVRAM Page 5 */ memcpy(BiosVersion, ha->nvram->BiosCompatibilityID, IPS_COMPAT_ID_LENGTH);  rc = IPS_FAILURE; if (ha->subsys->param[4] & IPS_GET_VERSION_SUPPORT) {	/* If Versioning is Supported */ /* Get the Version Info with a Get Version Command */ memset( VersionInfo, 0, sizeof (IPS_VERSION_DATA)); rc = ips_get_version_info(ha, ha->ioctl_busaddr, intr); if (rc == IPS_SUCCESS) memcpy(FirmwareVersion, VersionInfo->compatibilityId, IPS_COMPAT_ID_LENGTH); }  if (rc != IPS_SUCCESS) {	/* If Data Not Obtainable from a GetVersion Command */ /* Get the Firmware Version from Enquiry Data */ memcpy(FirmwareVersion, ha->enq->CodeBlkVersion, IPS_COMPAT_ID_LENGTH); }  /* printk(KERN_WARNING "Adapter's BIOS Version  = %s\n", BiosVersion);          */ /* printk(KERN_WARNING "BIOS Compatible Version = %s\n", IPS_COMPAT_BIOS);      */ /* printk(KERN_WARNING "Adapter's Firmware Version  = %s\n", FirmwareVersion);  */ /* printk(KERN_WARNING "Firmware Compatible Version = %s \n", Compatable[ ha->nvram->adapter_type ]); */  MatchError = 0;  if (strncmp (FirmwareVersion, Compatable[ha->nvram->adapter_type], IPS_COMPAT_ID_LENGTH) != 0) MatchError = 1;  if (strncmp(BiosVersion, IPS_COMPAT_BIOS, IPS_COMPAT_ID_LENGTH) != 0) MatchError = 1;  ha->nvram->versioning = 1;	/* Indicate the Driver Supports Versioning */  if (MatchError) { ha->nvram->version_mismatch = 1; if (ips_cd_boot == 0) { strncpy(&BiosString[0], ha->nvram->bios_high, 4); strncpy(&BiosString[4], ha->nvram->bios_low, 4); BiosString[8] = 0;  strncpy(&FirmwareString[0], ha->enq->CodeBlkVersion, 8); FirmwareString[8] = 0;  IPS_PRINTK(KERN_WARNING, ha->pcidev, "Warning ! ! ! ServeRAID Version Mismatch\n"); IPS_PRINTK(KERN_WARNING, ha->pcidev, "Bios = %s, Firmware = %s, Device Driver = %s%s\n", BiosString, FirmwareString, IPS_VERSION_HIGH, IPS_VERSION_LOW); IPS_PRINTK(KERN_WARNING, ha->pcidev, "These levels should match to avoid possible compatibility problems.\n"); } } else { ha->nvram->version_mismatch = 0; }  return; }  /*---------------------------------------------------------------------------*/ /*   Routine Name: ips_get_version_info                                      */ /*                                                                           */ /*   Routine Description:                                                    */ /*     Issue an internal GETVERSION Command                                  */ /*                                                                           */ /*   Return Value:                                                           */ /*     0 if Successful, else non-zero                                        */ /*---------------------------------------------------------------------------*/ static int ips_get_version_info(ips_ha_t * ha, dma_addr_t Buffer, int intr) { ips_scb_t *scb; int rc;  METHOD_TRACE("ips_get_version_info", 1);  scb = &ha->scbs[ha->max_cmds - 1];  ips_init_scb(ha, scb);  scb->timeout = ips_cmd_timeout; scb->cdb[0] = IPS_CMD_GET_VERSION_INFO; scb->cmd.version_info.op_code = IPS_CMD_GET_VERSION_INFO; scb->cmd.version_info.command_id = IPS_COMMAND_ID(ha, scb); scb->cmd.version_info.reserved = 0; scb->cmd.version_info.count = sizeof (IPS_VERSION_DATA); scb->cmd.version_info.reserved2 = 0; scb->data_len = sizeof (IPS_VERSION_DATA); scb->data_busaddr = Buffer; scb->cmd.version_info.buffer_addr = Buffer; scb->flags = 0;  /* issue command */ rc = ips_send_wait(ha, scb, ips_cmd_timeout, intr); return (rc); }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_abort_init                                             */ /*                                                                          */ /* Routine Description:                                                     */ /*   cleanup routine for a failed adapter initialization                    */ /****************************************************************************/ static int ips_abort_init(ips_ha_t * ha, int index) { ha->active = 0; ips_free(ha); ips_ha[index] = NULL; ips_sh[index] = NULL; return -1; }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_shift_controllers                                      */ /*                                                                          */ /* Routine Description:                                                     */ /*   helper function for ordering adapters                                  */ /****************************************************************************/ static void ips_shift_controllers(int lowindex, int highindex) { ips_ha_t *ha_sav = ips_ha[highindex]; struct Scsi_Host *sh_sav = ips_sh[highindex]; int i;  for (i = highindex; i > lowindex; i--) { ips_ha[i] = ips_ha[i - 1]; ips_sh[i] = ips_sh[i - 1]; ips_ha[i]->host_num = i; } ha_sav->host_num = lowindex; ips_ha[lowindex] = ha_sav; ips_sh[lowindex] = sh_sav; }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_order_controllers                                      */ /*                                                                          */ /* Routine Description:                                                     */ /*   place controllers is the "proper" boot order                           */ /****************************************************************************/ static void ips_order_controllers(void) { int i, j, tmp, position = 0; IPS_NVRAM_P5 *nvram; if (!ips_ha[0]) return; nvram = ips_ha[0]->nvram;  if (nvram->adapter_order[0]) { for (i = 1; i <= nvram->adapter_order[0]; i++) { for (j = position; j < ips_num_controllers; j++) { switch (ips_ha[j]->ad_type) { case IPS_ADTYPE_SERVERAID6M: case IPS_ADTYPE_SERVERAID7M: if (nvram->adapter_order[i] == 'M') { ips_shift_controllers(position, j); position++; } break; case IPS_ADTYPE_SERVERAID4L: case IPS_ADTYPE_SERVERAID4M: case IPS_ADTYPE_SERVERAID4MX: case IPS_ADTYPE_SERVERAID4LX: if (nvram->adapter_order[i] == 'N') { ips_shift_controllers(position, j); position++; } break; case IPS_ADTYPE_SERVERAID6I: case IPS_ADTYPE_SERVERAID5I2: case IPS_ADTYPE_SERVERAID5I1: case IPS_ADTYPE_SERVERAID7k: if (nvram->adapter_order[i] == 'S') { ips_shift_controllers(position, j); position++; } break; case IPS_ADTYPE_SERVERAID: case IPS_ADTYPE_SERVERAID2: case IPS_ADTYPE_NAVAJO: case IPS_ADTYPE_KIOWA: case IPS_ADTYPE_SERVERAID3L: case IPS_ADTYPE_SERVERAID3: case IPS_ADTYPE_SERVERAID4H: if (nvram->adapter_order[i] == 'A') { ips_shift_controllers(position, j); position++; } break; default: break; } } } /* if adapter_order[0], then ordering is complete */ return; } /* old bios, use older ordering */ tmp = 0; for (i = position; i < ips_num_controllers; i++) { if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I2 || ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I1) { ips_shift_controllers(position, i); position++; tmp = 1; } } /* if there were no 5I cards, then don't do any extra ordering */ if (!tmp) return; for (i = position; i < ips_num_controllers; i++) { if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4L || ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4M || ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4LX || ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4MX) { ips_shift_controllers(position, i); position++; } }  return; }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_register_scsi                                          */ /*                                                                          */ /* Routine Description:                                                     */ /*   perform any registration and setup with the scsi layer                 */ /****************************************************************************/ static int ips_register_scsi(int index) { struct Scsi_Host *sh; ips_ha_t *ha, *oldha = ips_ha[index]; sh = scsi_host_alloc(&ips_driver_template, sizeof (ips_ha_t)); if (!sh) { IPS_PRINTK(KERN_WARNING, oldha->pcidev, "Unable to register controller with SCSI subsystem\n"); return -1; } ha = IPS_HA(sh); memcpy(ha, oldha, sizeof (ips_ha_t)); free_irq(oldha->irq, oldha); /* Install the interrupt handler with the new ha */ if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) { IPS_PRINTK(KERN_WARNING, ha->pcidev, "Unable to install interrupt handler\n"); scsi_host_put(sh); return -1; }  kfree(oldha); ips_sh[index] = sh; ips_ha[index] = ha; IPS_SCSI_SET_DEVICE(sh, ha);  /* Store away needed values for later use */ sh->io_port = ha->io_addr; sh->n_io_port = ha->io_addr ? 255 : 0; sh->unique_id = (ha->io_addr) ? ha->io_addr : ha->mem_addr; sh->irq = ha->irq; sh->sg_tablesize = sh->hostt->sg_tablesize; sh->can_queue = sh->hostt->can_queue; sh->cmd_per_lun = sh->hostt->cmd_per_lun; sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma; sh->use_clustering = sh->hostt->use_clustering;  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7) sh->max_sectors = 128; #endif  sh->max_id = ha->ntargets; sh->max_lun = ha->nlun; sh->max_channel = ha->nbus - 1; sh->can_queue = ha->max_cmds - 1;  IPS_ADD_HOST(sh, NULL); return 0; }  /*---------------------------------------------------------------------------*/ /*   Routine Name: ips_remove_device                                         */ /*                                                                           */ /*   Routine Description:                                                    */ /*     Remove one Adapter ( Hot Plugging )                                   */ /*---------------------------------------------------------------------------*/ static void __devexit ips_remove_device(struct pci_dev *pci_dev) { int i; struct Scsi_Host *sh; ips_ha_t *ha;  for (i = 0; i < IPS_MAX_ADAPTERS; i++) { ha = ips_ha[i]; if (ha) { if ((pci_dev->bus->number == ha->pcidev->bus->number) && (pci_dev->devfn == ha->pcidev->devfn)) { sh = ips_sh[i]; ips_release(sh); } } } }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_module_init                                            */ /*                                                                          */ /* Routine Description:                                                     */ /*   function called on module load                                         */ /****************************************************************************/ static int __init ips_module_init(void) { if (pci_module_init(&ips_pci_driver) < 0) return -ENODEV; ips_driver_template.module = THIS_MODULE; ips_order_controllers(); if (IPS_REGISTER_HOSTS(&ips_driver_template)) { pci_unregister_driver(&ips_pci_driver); return -ENODEV; } register_reboot_notifier(&ips_notifier); return 0; }  /****************************************************************************/ /*                                                                          */ /* Routine Name: ips_module_exit                                            */ /*                                                                          */ /* Routine Description:                                                     */ /*   function called on module unload                                       */ /****************************************************************************/ static void __exit ips_module_exit(void) { IPS_UNREGISTER_HOSTS(&ips_driver_template); pci_unregister_driver(&ips_pci_driver); unregister_reboot_notifier(&ips_notifier); }  module_init(ips_module_init); module_exit(ips_module_exit);  /*---------------------------------------------------------------------------*/ /*   Routine Name: ips_insert_device                                         */ /*                                                                           */ /*   Routine Description:                                                    */ /*     Add One Adapter ( Hot Plug )                                          */ /*                                                                           */ /*   Return Value:                                                           */ /*     0 if Successful, else non-zero                                        */ /*---------------------------------------------------------------------------*/ static int __devinit ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent) { int index; int rc;  METHOD_TRACE("ips_insert_device", 1); if (pci_enable_device(pci_dev)) return -1;  rc = ips_init_phase1(pci_dev, &index); if (rc == SUCCESS) rc = ips_init_phase2(index);  if (ips_hotplug) if (ips_register_scsi(index)) { ips_free(ips_ha[index]); rc = -1; }  if (rc == SUCCESS) ips_num_controllers++;  ips_next_controller = ips_num_controllers; return rc; }  /*---------------------------------------------------------------------------*/ /*   Routine Name: ips_init_phase1                                           */ /*                                                                           */ /*   Routine Description:                                                    */ /*     Adapter Initialization                                                */ /*                                                                           */ /*   Return Value:                                                           */ /*     0 if Successful, else non-zero                                        */ /*---------------------------------------------------------------------------*/ static int ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) { ips_ha_t *ha; uint32_t io_addr; uint32_t mem_addr; uint32_t io_len; uint32_t mem_len; uint8_t revision_id; uint8_t bus; uint8_t func; uint8_t irq; uint16_t subdevice_id; int j; int index; dma_addr_t dma_address; char __iomem *ioremap_ptr; char __iomem *mem_ptr; uint32_t IsDead;  METHOD_TRACE("ips_init_phase1", 1); index = IPS_MAX_ADAPTERS; for (j = 0; j < IPS_MAX_ADAPTERS; j++) { if (ips_ha[j] == 0) { index = j; break; } }  if (index >= IPS_MAX_ADAPTERS) return -1;  /* stuff that we get in dev */ irq = pci_dev->irq; bus = pci_dev->bus->number; func = pci_dev->devfn;  /* Init MEM/IO addresses to 0 */ mem_addr = 0; io_addr = 0; mem_len = 0; io_len = 0;  for (j = 0; j < 2; j++) { if (!pci_resource_start(pci_dev, j)) break;  if (pci_resource_flags(pci_dev, j) & IORESOURCE_IO) { io_addr = pci_resource_start(pci_dev, j); io_len = pci_resource_len(pci_dev, j); } else { mem_addr = pci_resource_start(pci_dev, j); mem_len = pci_resource_len(pci_dev, j); } }  /* setup memory mapped area (if applicable) */ if (mem_addr) { uint32_t base; uint32_t offs;  if (!request_mem_region(mem_addr, mem_len, "ips")) { IPS_PRINTK(KERN_WARNING, pci_dev, "Couldn't allocate IO Memory space %x len %d.\n", mem_addr, mem_len); return -1; }  base = mem_addr & PAGE_MASK; offs = mem_addr - base; ioremap_ptr = ioremap(base, PAGE_SIZE); mem_ptr = ioremap_ptr + offs; } else { ioremap_ptr = NULL; mem_ptr = NULL; }  /* setup I/O mapped area (if applicable) */ if (io_addr) { if (!request_region(io_addr, io_len, "ips")) { IPS_PRINTK(KERN_WARNING, pci_dev, "Couldn't allocate IO space %x len %d.\n", io_addr, io_len); return -1; } }  /* get the revision ID */ if (pci_read_config_byte(pci_dev, PCI_REVISION_ID, &revision_id)) { IPS_PRINTK(KERN_WARNING, pci_dev, "Can't get revision id.\n"); return -1; }  subdevice_id = pci_dev->subsystem_device;  /* found a controller */ ha = kmalloc(sizeof (ips_ha_t), GFP_KERNEL); if (ha == NULL) { IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to allocate temporary ha struct\n"); return -1; }  memset(ha, 0, sizeof (ips_ha_t));  ips_sh[index] = NULL; ips_ha[index] = ha; ha->active = 1;  /* Store info in HA structure */ ha->irq = irq; ha->io_addr = io_addr; ha->io_len = io_len; ha->mem_addr = mem_addr; ha->mem_len = mem_len; ha->mem_ptr = mem_ptr; ha->ioremap_ptr = ioremap_ptr; ha->host_num = (uint32_t) index; ha->revision_id = revision_id; ha->slot_num = PCI_SLOT(pci_dev->devfn); ha->device_id = pci_dev->device; ha->subdevice_id = subdevice_id; ha->pcidev = pci_dev;  /* * Set the pci_dev's dma_mask.  Not all adapters support 64bit * addressing so don't enable it if the adapter can't support * it!  Also, don't use 64bit addressing if dma addresses * are guaranteed to be < 4G. */ if (IPS_ENABLE_DMA64 && IPS_HAS_ENH_SGLIST(ha) && !pci_set_dma_mask(ha->pcidev, 0xffffffffffffffffULL)) { (ha)->flags |= IPS_HA_ENH_SG; } else { if (pci_set_dma_mask(ha->pcidev, 0xffffffffULL) != 0) { printk(KERN_WARNING "Unable to set DMA Mask\n"); return ips_abort_init(ha, index); } } if(ips_cd_boot && !ips_FlashData){ ips_FlashData = pci_alloc_consistent(pci_dev, PAGE_SIZE << 7, &ips_flashbusaddr); }  ha->enq = pci_alloc_consistent(pci_dev, sizeof (IPS_ENQ), &ha->enq_busaddr); if (!ha->enq) { IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to allocate host inquiry structure\n"); return ips_abort_init(ha, index); }  ha->adapt = pci_alloc_consistent(pci_dev, sizeof (IPS_ADAPTER) + sizeof (IPS_IO_CMD), &dma_address); if (!ha->adapt) { IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to allocate host adapt & dummy structures\n"); return ips_abort_init(ha, index); } ha->adapt->hw_status_start = dma_address; ha->dummy = (void *) (ha->adapt + 1);    ha->logical_drive_info = pci_alloc_consistent(pci_dev, sizeof (IPS_LD_INFO), &dma_address); if (!ha->logical_drive_info) { IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to allocate logical drive info structure\n"); return ips_abort_init(ha, index); } ha->logical_drive_info_dma_addr = dma_address;   ha->conf = kmalloc(sizeof (IPS_CONF), GFP_KERNEL);  if (!ha->conf) { IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to allocate host conf structure\n"); return ips_abort_init(ha, index); }  ha->nvram = kmalloc(sizeof (IPS_NVRAM_P5), GFP_KERNEL);  if (!ha->nvram) { IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to allocate host NVRAM structure\n"); return ips_abort_init(ha, index); }  ha->subsys = kmalloc(sizeof (IPS_SUBSYS), GFP_KERNEL);  if (!ha->subsys) { IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to allocate host subsystem structure\n"); return ips_abort_init(ha, index); }  /* the ioctl buffer is now used during adapter initialization, so its * successful allocation is now required */ if (ips_ioctlsize < PAGE_SIZE) ips_ioctlsize = PAGE_SIZE;  ha->ioctl_data = pci_alloc_consistent(pci_dev, ips_ioctlsize, &ha->ioctl_busaddr); ha->ioctl_len = ips_ioctlsize; if (!ha->ioctl_data) { IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to allocate IOCTL data\n"); return ips_abort_init(ha, index); }  /* * Setup Functions */ ips_setup_funclist(ha);  if ((IPS_IS_MORPHEUS(ha)) || (IPS_IS_MARCO(ha))) { /* If Morpheus appears dead, reset it */ IsDead = readl(ha->mem_ptr + IPS_REG_I960_MSG1); if (IsDead == 0xDEADBEEF) { ips_reset_morpheus(ha); } }  /* * Initialize the card if it isn't already */  if (!(*ha->func.isinit) (ha)) { if (!(*ha->func.init) (ha)) { /* * Initialization failed */ IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to initialize controller\n"); return ips_abort_init(ha, index); } }  *indexPtr = index; return SUCCESS; }  /*---------------------------------------------------------------------------*/ /*   Routine Name: ips_init_phase2                                           */ /*                                                                           */ /*   Routine Description:                                                    */ /*     Adapter Initialization Phase 2                                        */ /*                                                                           */ /*   Return Value:                                                           */ /*     0 if Successful, else non-zero                                        */ /*---------------------------------------------------------------------------*/ static int ips_init_phase2(int index) { ips_ha_t *ha;  ha = ips_ha[index];  METHOD_TRACE("ips_init_phase2", 1); if (!ha->active) { ips_ha[index] = NULL; return -1; }  /* Install the interrupt handler */ if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) { IPS_PRINTK(KERN_WARNING, ha->pcidev, "Unable to install interrupt handler\n"); return ips_abort_init(ha, index); }  /* * Allocate a temporary SCB for initialization */ ha->max_cmds = 1; if (!ips_allocatescbs(ha)) { IPS_PRINTK(KERN_WARNING, ha->pcidev, "Unable to allocate a CCB\n"); free_irq(ha->irq, ha); return ips_abort_init(ha, index); }  if (!ips_hainit(ha)) { IPS_PRINTK(KERN_WARNING, ha->pcidev, "Unable to initialize controller\n"); free_irq(ha->irq, ha); return ips_abort_init(ha, index); } /* Free the temporary SCB */ ips_deallocatescbs(ha, 1);  /* allocate CCBs */ if (!ips_allocatescbs(ha)) { IPS_PRINTK(KERN_WARNING, ha->pcidev, "Unable to allocate CCBs\n"); free_irq(ha->irq, ha); return ips_abort_init(ha, index); }  return SUCCESS; }  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9) MODULE_LICENSE("GPL"); #endif  MODULE_DESCRIPTION("IBM ServeRAID Adapter Driver " IPS_VER_STRING);  #ifdef MODULE_VERSION MODULE_VERSION(IPS_VER_STRING); #endif   /* * Overrides for Emacs so that we almost follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only.  This must remain at the end * of the file. * --------------------------------------------------------------------------- * Local variables: * c-indent-level: 2 * c-brace-imaginary-offset: 0 * c-brace-offset: -2 * c-argdecl-indent: 2 * c-label-offset: -2 * c-continued-statement-offset: 2 * c-continued-brace-offset: 0 * indent-tabs-mode: nil * tab-width: 8 * End: */ 
ips_poll_for_flush_complete(ips_ha_t * ha){	IPS_STATUS cstatus;    	while (TRUE) {	    cstatus.value = (*ha->func.statupd) (ha);	    if (cstatus.value == 0xffffffff)      /* If No Interrupt to process */			break;            	    /* Success is when we see the Flush Command ID */	    if (cstatus.fields.command_id == IPS_MAX_CMDS ) 	        return 1;	 }		return 0;/****************************************************************************//*                                                                          *//* Routine Name: ips_enable_int_copperhead                                  *//*                                                                          *//* Routine Description:                                                     *//*   Turn on interrupts                                                     *//*                                                                          *//****************************************************************************/static voidips_enable_int_copperhead(ips_ha_t * ha){	METHOD_TRACE("ips_enable_int_copperhead", 1);	outb(ha->io_addr + IPS_REG_HISR, IPS_BIT_EI);	inb(ha->io_addr + IPS_REG_HISR);	/*Ensure PCI Posting Completes*/}/****************************************************************************//*                                                                          *//* Routine Name: ips_enable_int_copperhead_memio                            *//*                                                                          *//* Routine Description:                                                     *//*   Turn on interrupts                                                     *//*                                                                          *//****************************************************************************/static voidips_enable_int_copperhead_memio(ips_ha_t * ha){	METHOD_TRACE("ips_enable_int_copperhead_memio", 1);	writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR);	readb(ha->mem_ptr + IPS_REG_HISR);	/*Ensure PCI Posting Completes*/}/****************************************************************************//*                                                                          *//* Routine Name: ips_enable_int_morpheus                                    *//*                                                                          *//* Routine Description:                                                     *//*   Turn on interrupts                                                     *//*                                                                          *//****************************************************************************/static voidips_enable_int_morpheus(ips_ha_t * ha){	uint32_t Oimr;	METHOD_TRACE("ips_enable_int_morpheus", 1);	Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR);	Oimr &= ~0x08;	writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR);	readl(ha->mem_ptr + IPS_REG_I960_OIMR);	/*Ensure PCI Posting Completes*/}/****************************************************************************//*                                                                          *//* Routine Name: ips_init_copperhead                                        *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Initialize a copperhead controller                                     *//*                                                                          *//****************************************************************************/static intips_init_copperhead(ips_ha_t * ha){	uint8_t Isr;	uint8_t Cbsp;	uint8_t PostByte[IPS_MAX_POST_BYTES];	uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES];	int i, j;	METHOD_TRACE("ips_init_copperhead", 1);	for (i = 0; i < IPS_MAX_POST_BYTES; i++) {		for (j = 0; j < 45; j++) {			Isr = inb(ha->io_addr + IPS_REG_HISR);			if (Isr & IPS_BIT_GHI)				break;			/* Delay for 1 Second */			MDELAY(IPS_ONE_SEC);		}		if (j >= 45)			/* error occurred */			return (0);		PostByte[i] = inb(ha->io_addr + IPS_REG_ISPR);		outb(Isr, ha->io_addr + IPS_REG_HISR);	}	if (PostByte[0] < IPS_GOOD_POST_STATUS) {		IPS_PRINTK(KERN_WARNING, ha->pcidev,			   "reset controller fails (post status %x %x).\n",			   PostByte[0], PostByte[1]);		return (0);	}	for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) {		for (j = 0; j < 240; j++) {			Isr = inb(ha->io_addr + IPS_REG_HISR);			if (Isr & IPS_BIT_GHI)				break;			/* Delay for 1 Second */			MDELAY(IPS_ONE_SEC);		}		if (j >= 240)			/* error occurred */			return (0);		ConfigByte[i] = inb(ha->io_addr + IPS_REG_ISPR);		outb(Isr, ha->io_addr + IPS_REG_HISR);	}	for (i = 0; i < 240; i++) {		Cbsp = inb(ha->io_addr + IPS_REG_CBSP);		if ((Cbsp & IPS_BIT_OP) == 0)			break;		/* Delay for 1 Second */		MDELAY(IPS_ONE_SEC);	}	if (i >= 240)		/* reset failed */		return (0);	/* setup CCCR */	outl(cpu_to_le32(0x1010), ha->io_addr + IPS_REG_CCCR);	/* Enable busmastering */	outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR);	if (ha->revision_id == IPS_REVID_TROMBONE64)		/* fix for anaconda64 */		outl(0, ha->io_addr + IPS_REG_NDAE);	/* Enable interrupts */	outb(IPS_BIT_EI, ha->io_addr + IPS_REG_HISR);	return (1);}/****************************************************************************//*                                                                          *//* Routine Name: ips_init_copperhead_memio                                  *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Initialize a copperhead controller with memory mapped I/O              *//*                                                                          *//****************************************************************************/static intips_init_copperhead_memio(ips_ha_t * ha){	uint8_t Isr = 0;	uint8_t Cbsp;	uint8_t PostByte[IPS_MAX_POST_BYTES];	uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES];	int i, j;	METHOD_TRACE("ips_init_copperhead_memio", 1);	for (i = 0; i < IPS_MAX_POST_BYTES; i++) {		for (j = 0; j < 45; j++) {			Isr = readb(ha->mem_ptr + IPS_REG_HISR);			if (Isr & IPS_BIT_GHI)				break;			/* Delay for 1 Second */			MDELAY(IPS_ONE_SEC);		}		if (j >= 45)			/* error occurred */			return (0);		PostByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR);		writeb(Isr, ha->mem_ptr + IPS_REG_HISR);	}	if (PostByte[0] < IPS_GOOD_POST_STATUS) {		IPS_PRINTK(KERN_WARNING, ha->pcidev,			   "reset controller fails (post status %x %x).\n",			   PostByte[0], PostByte[1]);		return (0);	}	for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) {		for (j = 0; j < 240; j++) {			Isr = readb(ha->mem_ptr + IPS_REG_HISR);			if (Isr & IPS_BIT_GHI)				break;			/* Delay for 1 Second */			MDELAY(IPS_ONE_SEC);		}		if (j >= 240)			/* error occurred */			return (0);		ConfigByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR);		writeb(Isr, ha->mem_ptr + IPS_REG_HISR);	}	for (i = 0; i < 240; i++) {		Cbsp = readb(ha->mem_ptr + IPS_REG_CBSP);		if ((Cbsp & IPS_BIT_OP) == 0)			break;		/* Delay for 1 Second */		MDELAY(IPS_ONE_SEC);	}	if (i >= 240)		/* error occurred */		return (0);	/* setup CCCR */	writel(0x1010, ha->mem_ptr + IPS_REG_CCCR);	/* Enable busmastering */	writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR);	if (ha->revision_id == IPS_REVID_TROMBONE64)		/* fix for anaconda64 */		writel(0, ha->mem_ptr + IPS_REG_NDAE);	/* Enable interrupts */	writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR);	/* if we get here then everything went OK */	return (1);}/****************************************************************************//*                                                                          *//* Routine Name: ips_init_morpheus                                          *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Initialize a morpheus controller                                       *//*                                                                          *//****************************************************************************/static intips_init_morpheus(ips_ha_t * ha){	uint32_t Post;	uint32_t Config;	uint32_t Isr;	uint32_t Oimr;	int i;	METHOD_TRACE("ips_init_morpheus", 1);	/* Wait up to 45 secs for Post */	for (i = 0; i < 45; i++) {		Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);		if (Isr & IPS_BIT_I960_MSG0I)			break;		/* Delay for 1 Second */		MDELAY(IPS_ONE_SEC);	}	if (i >= 45) {		/* error occurred */		IPS_PRINTK(KERN_WARNING, ha->pcidev,			   "timeout waiting for post.\n");		return (0);	}	Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);	if (Post == 0x4F00) {	/* If Flashing the Battery PIC         */		IPS_PRINTK(KERN_WARNING, ha->pcidev,			   "Flashing Battery PIC, Please wait ...\n");		/* Clear the interrupt bit */		Isr = (uint32_t) IPS_BIT_I960_MSG0I;		writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);		for (i = 0; i < 120; i++) {	/*    Wait Up to 2 Min. for Completion */			Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);			if (Post != 0x4F00)				break;			/* Delay for 1 Second */			MDELAY(IPS_ONE_SEC);		}		if (i >= 120) {			IPS_PRINTK(KERN_WARNING, ha->pcidev,				   "timeout waiting for Battery PIC Flash\n");			return (0);		}	}	/* Clear the interrupt bit */	Isr = (uint32_t) IPS_BIT_I960_MSG0I;	writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);	if (Post < (IPS_GOOD_POST_STATUS << 8)) {		IPS_PRINTK(KERN_WARNING, ha->pcidev,			   "reset controller fails (post status %x).\n", Post);		return (0);	}	/* Wait up to 240 secs for config bytes */	for (i = 0; i < 240; i++) {		Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);		if (Isr & IPS_BIT_I960_MSG1I)			break;		/* Delay for 1 Second */		MDELAY(IPS_ONE_SEC);	}	if (i >= 240) {		/* error occurred */		IPS_PRINTK(KERN_WARNING, ha->pcidev,			   "timeout waiting for config.\n");		return (0);	}	Config = readl(ha->mem_ptr + IPS_REG_I960_MSG1);	/* Clear interrupt bit */	Isr = (uint32_t) IPS_BIT_I960_MSG1I;	writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);	/* Turn on the interrupts */	Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR);	Oimr &= ~0x8;	writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR);	/* if we get here then everything went OK */	/* Since we did a RESET, an EraseStripeLock may be needed */	if (Post == 0xEF10) {		if ((Config == 0x000F) || (Config == 0x0009))			ha->requires_esl = 1;	}	return (1);}/****************************************************************************//*                                                                          *//* Routine Name: ips_reset_copperhead                                       *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Reset the controller                                                   *//*                                                                          *//****************************************************************************/static intips_reset_copperhead(ips_ha_t * ha){	int reset_counter;	METHOD_TRACE("ips_reset_copperhead", 1);	DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d",		  ips_name, ha->host_num, ha->io_addr, ha->irq);	reset_counter = 0;	while (reset_counter < 2) {		reset_counter++;		outb(IPS_BIT_RST, ha->io_addr + IPS_REG_SCPR);		/* Delay for 1 Second */		MDELAY(IPS_ONE_SEC);		outb(0, ha->io_addr + IPS_REG_SCPR);		/* Delay for 1 Second */		MDELAY(IPS_ONE_SEC);		if ((*ha->func.init) (ha))			break;		else if (reset_counter >= 2) {			return (0);		}	}	return (1);}/****************************************************************************//*                                                                          *//* Routine Name: ips_reset_copperhead_memio                                 *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Reset the controller                                                   *//*                                                                          *//****************************************************************************/static intips_reset_copperhead_memio(ips_ha_t * ha){	int reset_counter;	METHOD_TRACE("ips_reset_copperhead_memio", 1);	DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d",		  ips_name, ha->host_num, ha->mem_addr, ha->irq);	reset_counter = 0;	while (reset_counter < 2) {		reset_counter++;		writeb(IPS_BIT_RST, ha->mem_ptr + IPS_REG_SCPR);		/* Delay for 1 Second */		MDELAY(IPS_ONE_SEC);		writeb(0, ha->mem_ptr + IPS_REG_SCPR);		/* Delay for 1 Second */		MDELAY(IPS_ONE_SEC);		if ((*ha->func.init) (ha))			break;		else if (reset_counter >= 2) {			return (0);		}	}	return (1);}/****************************************************************************//*                                                                          *//* Routine Name: ips_reset_morpheus                                         *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Reset the controller                                                   *//*                                                                          *//****************************************************************************/static intips_reset_morpheus(ips_ha_t * ha){	int reset_counter;	uint8_t junk;	METHOD_TRACE("ips_reset_morpheus", 1);	DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d",		  ips_name, ha->host_num, ha->mem_addr, ha->irq);	reset_counter = 0;	while (reset_counter < 2) {		reset_counter++;		writel(0x80000000, ha->mem_ptr + IPS_REG_I960_IDR);		/* Delay for 5 Seconds */		MDELAY(5 * IPS_ONE_SEC);		/* Do a PCI config read to wait for adapter */		pci_read_config_byte(ha->pcidev, 4, &junk);		if ((*ha->func.init) (ha))			break;		else if (reset_counter >= 2) {			return (0);		}	}	return (1);}/****************************************************************************//*                                                                          *//* Routine Name: ips_statinit                                               *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Initialize the status queues on the controller                         *//*                                                                          *//****************************************************************************/static voidips_statinit(ips_ha_t * ha){	uint32_t phys_status_start;	METHOD_TRACE("ips_statinit", 1);	ha->adapt->p_status_start = ha->adapt->status;	ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS;	ha->adapt->p_status_tail = ha->adapt->status;	phys_status_start = ha->adapt->hw_status_start;	outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQSR);	outl(cpu_to_le32(phys_status_start + IPS_STATUS_Q_SIZE),	     ha->io_addr + IPS_REG_SQER);	outl(cpu_to_le32(phys_status_start + IPS_STATUS_SIZE),	     ha->io_addr + IPS_REG_SQHR);	outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQTR);	ha->adapt->hw_status_tail = phys_status_start;}/****************************************************************************//*                                                                          *//* Routine Name: ips_statinit_memio                                         *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Initialize the status queues on the controller                         *//*                                                                          *//****************************************************************************/static voidips_statinit_memio(ips_ha_t * ha){	uint32_t phys_status_start;	METHOD_TRACE("ips_statinit_memio", 1);	ha->adapt->p_status_start = ha->adapt->status;	ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS;	ha->adapt->p_status_tail = ha->adapt->status;	phys_status_start = ha->adapt->hw_status_start;	writel(phys_status_start, ha->mem_ptr + IPS_REG_SQSR);	writel(phys_status_start + IPS_STATUS_Q_SIZE,	       ha->mem_ptr + IPS_REG_SQER);	writel(phys_status_start + IPS_STATUS_SIZE, ha->mem_ptr + IPS_REG_SQHR);	writel(phys_status_start, ha->mem_ptr + IPS_REG_SQTR);	ha->adapt->hw_status_tail = phys_status_start;}/****************************************************************************//*                                                                          *//* Routine Name: ips_statupd_copperhead                                     *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Remove an element from the status queue                                *//*                                                                          *//****************************************************************************/static uint32_tips_statupd_copperhead(ips_ha_t * ha){	METHOD_TRACE("ips_statupd_copperhead", 1);	if (ha->adapt->p_status_tail != ha->adapt->p_status_end) {		ha->adapt->p_status_tail++;		ha->adapt->hw_status_tail += sizeof (IPS_STATUS);	} else {		ha->adapt->p_status_tail = ha->adapt->p_status_start;		ha->adapt->hw_status_tail = ha->adapt->hw_status_start;	}	outl(cpu_to_le32(ha->adapt->hw_status_tail),	     ha->io_addr + IPS_REG_SQTR);	return (ha->adapt->p_status_tail->value);}/****************************************************************************//*                                                                          *//* Routine Name: ips_statupd_copperhead_memio                               *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Remove an element from the status queue                                *//*                                                                          *//****************************************************************************/static uint32_tips_statupd_copperhead_memio(ips_ha_t * ha){	METHOD_TRACE("ips_statupd_copperhead_memio", 1);	if (ha->adapt->p_status_tail != ha->adapt->p_status_end) {		ha->adapt->p_status_tail++;		ha->adapt->hw_status_tail += sizeof (IPS_STATUS);	} else {		ha->adapt->p_status_tail = ha->adapt->p_status_start;		ha->adapt->hw_status_tail = ha->adapt->hw_status_start;	}	writel(ha->adapt->hw_status_tail, ha->mem_ptr + IPS_REG_SQTR);	return (ha->adapt->p_status_tail->value);}/****************************************************************************//*                                                                          *//* Routine Name: ips_statupd_morpheus                                       *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Remove an element from the status queue                                *//*                                                                          *//****************************************************************************/static uint32_tips_statupd_morpheus(ips_ha_t * ha){	uint32_t val;	METHOD_TRACE("ips_statupd_morpheus", 1);	val = readl(ha->mem_ptr + IPS_REG_I2O_OUTMSGQ);	return (val);}/****************************************************************************//*                                                                          *//* Routine Name: ips_issue_copperhead                                       *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Send a command down to the controller                                  *//*                                                                          *//****************************************************************************/static intips_issue_copperhead(ips_ha_t * ha, ips_scb_t * scb){	uint32_t TimeOut;	uint32_t val;	METHOD_TRACE("ips_issue_copperhead", 1);	if (scb->scsi_cmd) {		DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",			  ips_name,			  ha->host_num,			  scb->cdb[0],			  scb->cmd.basic_io.command_id,			  scb->bus, scb->target_id, scb->lun);	} else {		DEBUG_VAR(2, KERN_NOTICE "(%s%d) ips_issue: logical cmd id %d",			  ips_name, ha->host_num, scb->cmd.basic_io.command_id);	}	TimeOut = 0;	while ((val =		le32_to_cpu(inl(ha->io_addr + IPS_REG_CCCR))) & IPS_BIT_SEM) {		udelay(1000);		if (++TimeOut >= IPS_SEM_TIMEOUT) {			if (!(val & IPS_BIT_START_STOP))				break;			IPS_PRINTK(KERN_WARNING, ha->pcidev,				   "ips_issue val [0x%x].\n", val);			IPS_PRINTK(KERN_WARNING, ha->pcidev,				   "ips_issue semaphore chk timeout.\n");			return (IPS_FAILURE);		}		/* end if */	}			/* end while */	outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_CCSAR);	outw(cpu_to_le32(IPS_BIT_START_CMD), ha->io_addr + IPS_REG_CCCR);	return (IPS_SUCCESS);}/****************************************************************************//*                                                                          *//* Routine Name: ips_issue_copperhead_memio                                 *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Send a command down to the controller                                  *//*                                                                          *//****************************************************************************/static intips_issue_copperhead_memio(ips_ha_t * ha, ips_scb_t * scb){	uint32_t TimeOut;	uint32_t val;	METHOD_TRACE("ips_issue_copperhead_memio", 1);	if (scb->scsi_cmd) {		DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",			  ips_name,			  ha->host_num,			  scb->cdb[0],			  scb->cmd.basic_io.command_id,			  scb->bus, scb->target_id, scb->lun);	} else {		DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",			  ips_name, ha->host_num, scb->cmd.basic_io.command_id);	}	TimeOut = 0;	while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) {		udelay(1000);		if (++TimeOut >= IPS_SEM_TIMEOUT) {			if (!(val & IPS_BIT_START_STOP))				break;			IPS_PRINTK(KERN_WARNING, ha->pcidev,				   "ips_issue val [0x%x].\n", val);			IPS_PRINTK(KERN_WARNING, ha->pcidev,				   "ips_issue semaphore chk timeout.\n");			return (IPS_FAILURE);		}		/* end if */	}			/* end while */	writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_CCSAR);	writel(IPS_BIT_START_CMD, ha->mem_ptr + IPS_REG_CCCR);	return (IPS_SUCCESS);}/****************************************************************************//*                                                                          *//* Routine Name: ips_issue_i2o                                              *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Send a command down to the controller                                  *//*                                                                          *//****************************************************************************/static intips_issue_i2o(ips_ha_t * ha, ips_scb_t * scb){	METHOD_TRACE("ips_issue_i2o", 1);	if (scb->scsi_cmd) {		DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",			  ips_name,			  ha->host_num,			  scb->cdb[0],			  scb->cmd.basic_io.command_id,			  scb->bus, scb->target_id, scb->lun);	} else {		DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",			  ips_name, ha->host_num, scb->cmd.basic_io.command_id);	}	outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_I2O_INMSGQ);	return (IPS_SUCCESS);}/****************************************************************************//*                                                                          *//* Routine Name: ips_issue_i2o_memio                                        *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Send a command down to the controller                                  *//*                                                                          *//****************************************************************************/static intips_issue_i2o_memio(ips_ha_t * ha, ips_scb_t * scb){	METHOD_TRACE("ips_issue_i2o_memio", 1);	if (scb->scsi_cmd) {		DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",			  ips_name,			  ha->host_num,			  scb->cdb[0],			  scb->cmd.basic_io.command_id,			  scb->bus, scb->target_id, scb->lun);	} else {		DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",			  ips_name, ha->host_num, scb->cmd.basic_io.command_id);	}	writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_I2O_INMSGQ);	return (IPS_SUCCESS);}/****************************************************************************//*                                                                          *//* Routine Name: ips_isintr_copperhead                                      *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Test to see if an interrupt is for us                                  *//*                                                                          *//****************************************************************************/static intips_isintr_copperhead(ips_ha_t * ha){	uint8_t Isr;	METHOD_TRACE("ips_isintr_copperhead", 2);	Isr = inb(ha->io_addr + IPS_REG_HISR);	if (Isr == 0xFF)		/* ?!?! Nothing really there */		return (0);	if (Isr & IPS_BIT_SCE)		return (1);	else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) {		/* status queue overflow or GHI */		/* just clear the interrupt */		outb(Isr, ha->io_addr + IPS_REG_HISR);	}	return (0);}/****************************************************************************//*                                                                          *//* Routine Name: ips_isintr_copperhead_memio                                *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Test to see if an interrupt is for us                                  *//*                                                                          *//****************************************************************************/static intips_isintr_copperhead_memio(ips_ha_t * ha){	uint8_t Isr;	METHOD_TRACE("ips_isintr_memio", 2);	Isr = readb(ha->mem_ptr + IPS_REG_HISR);	if (Isr == 0xFF)		/* ?!?! Nothing really there */		return (0);	if (Isr & IPS_BIT_SCE)		return (1);	else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) {		/* status queue overflow or GHI */		/* just clear the interrupt */		writeb(Isr, ha->mem_ptr + IPS_REG_HISR);	}	return (0);}/****************************************************************************//*                                                                          *//* Routine Name: ips_isintr_morpheus                                        *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Test to see if an interrupt is for us                                  *//*                                                                          *//****************************************************************************/static intips_isintr_morpheus(ips_ha_t * ha){	uint32_t Isr;	METHOD_TRACE("ips_isintr_morpheus", 2);	Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);	if (Isr & IPS_BIT_I2O_OPQI)		return (1);	else		return (0);}/****************************************************************************//*                                                                          *//* Routine Name: ips_wait                                                   *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Wait for a command to complete                                         *//*                                                                          *//****************************************************************************/static intips_wait(ips_ha_t * ha, int time, int intr){	int ret;	int done;	METHOD_TRACE("ips_wait", 1);	ret = IPS_FAILURE;	done = FALSE;	time *= IPS_ONE_SEC;	/* convert seconds */	while ((time > 0) && (!done)) {		if (intr == IPS_INTR_ON) {			if (ha->waitflag == FALSE) {				ret = IPS_SUCCESS;				done = TRUE;				break;			}		} else if (intr == IPS_INTR_IORL) {			if (ha->waitflag == FALSE) {				/*				 * controller generated an interrupt to				 * acknowledge completion of the command				 * and ips_intr() has serviced the interrupt.				 */				ret = IPS_SUCCESS;				done = TRUE;				break;			}			/*			 * NOTE: we already have the io_request_lock so			 * even if we get an interrupt it won't get serviced			 * until after we finish.			 */			(*ha->func.intr) (ha);		}		/* This looks like a very evil loop, but it only does this during start-up */		udelay(1000);		time--;	}	return (ret);}/****************************************************************************//*                                                                          *//* Routine Name: ips_write_driver_status                                    *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Write OS/Driver version to Page 5 of the nvram on the controller       *//*                                                                          *//****************************************************************************/static intips_write_driver_status(ips_ha_t * ha, int intr){	METHOD_TRACE("ips_write_driver_status", 1);	if (!ips_readwrite_page5(ha, FALSE, intr)) {		IPS_PRINTK(KERN_WARNING, ha->pcidev,			   "unable to read NVRAM page 5.\n");		return (0);	}	/* check to make sure the page has a valid */	/* signature */	if (le32_to_cpu(ha->nvram->signature) != IPS_NVRAM_P5_SIG) {		DEBUG_VAR(1,			  "(%s%d) NVRAM page 5 has an invalid signature: %X.",			  ips_name, ha->host_num, ha->nvram->signature);		ha->nvram->signature = IPS_NVRAM_P5_SIG;	}	DEBUG_VAR(2,		  "(%s%d) Ad Type: %d, Ad Slot: %d, BIOS: %c%c%c%c %c%c%c%c.",		  ips_name, ha->host_num, le16_to_cpu(ha->nvram->adapter_type),		  ha->nvram->adapter_slot, ha->nvram->bios_high[0],		  ha->nvram->bios_high[1], ha->nvram->bios_high[2],		  ha->nvram->bios_high[3], ha->nvram->bios_low[0],		  ha->nvram->bios_low[1], ha->nvram->bios_low[2],		  ha->nvram->bios_low[3]);	ips_get_bios_version(ha, intr);	/* change values (as needed) */	ha->nvram->operating_system = IPS_OS_LINUX;	ha->nvram->adapter_type = ha->ad_type;	strncpy((char *) ha->nvram->driver_high, IPS_VERSION_HIGH, 4);	strncpy((char *) ha->nvram->driver_low, IPS_VERSION_LOW, 4);	strncpy((char *) ha->nvram->bios_high, ha->bios_version, 4);	strncpy((char *) ha->nvram->bios_low, ha->bios_version + 4, 4);	ips_version_check(ha, intr);	/* Check BIOS/FW/Driver Versions */	/* now update the page */	if (!ips_readwrite_page5(ha, TRUE, intr)) {		IPS_PRINTK(KERN_WARNING, ha->pcidev,			   "unable to write NVRAM page 5.\n");		return (0);	}	/* IF NVRAM Page 5 is OK, Use it for Slot Number Info Because Linux Doesn't Do Slots */	ha->slot_num = ha->nvram->adapter_slot;	return (1);}/****************************************************************************//*                                                                          *//* Routine Name: ips_read_adapter_status                                    *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Do an Inquiry command to the adapter                                   *//*                                                                          *//****************************************************************************/static intips_read_adapter_status(ips_ha_t * ha, int intr){	ips_scb_t *scb;	int ret;	METHOD_TRACE("ips_read_adapter_status", 1);	scb = &ha->scbs[ha->max_cmds - 1];	ips_init_scb(ha, scb);	scb->timeout = ips_cmd_timeout;	scb->cdb[0] = IPS_CMD_ENQUIRY;	scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY;	scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);	scb->cmd.basic_io.sg_count = 0;	scb->cmd.basic_io.lba = 0;	scb->cmd.basic_io.sector_count = 0;	scb->cmd.basic_io.log_drv = 0;	scb->data_len = sizeof (*ha->enq);	scb->cmd.basic_io.sg_addr = ha->enq_busaddr;	/* send command */	if (((ret =	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)	    || (ret == IPS_SUCCESS_IMM)	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))		return (0);	return (1);}/****************************************************************************//*                                                                          *//* Routine Name: ips_read_subsystem_parameters                              *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Read subsystem parameters from the adapter                             *//*                                                                          *//****************************************************************************/static intips_read_subsystem_parameters(ips_ha_t * ha, int intr){	ips_scb_t *scb;	int ret;	METHOD_TRACE("ips_read_subsystem_parameters", 1);	scb = &ha->scbs[ha->max_cmds - 1];	ips_init_scb(ha, scb);	scb->timeout = ips_cmd_timeout;	scb->cdb[0] = IPS_CMD_GET_SUBSYS;	scb->cmd.basic_io.op_code = IPS_CMD_GET_SUBSYS;	scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);	scb->cmd.basic_io.sg_count = 0;	scb->cmd.basic_io.lba = 0;	scb->cmd.basic_io.sector_count = 0;	scb->cmd.basic_io.log_drv = 0;	scb->data_len = sizeof (*ha->subsys);	scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr;	/* send command */	if (((ret =	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)	    || (ret == IPS_SUCCESS_IMM)	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))		return (0);	memcpy(ha->subsys, ha->ioctl_data, sizeof(*ha->subsys));	return (1);}/****************************************************************************//*                                                                          *//* Routine Name: ips_read_config                                            *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Read the configuration on the adapter                                  *//*                                                                          *//****************************************************************************/static intips_read_config(ips_ha_t * ha, int intr){	ips_scb_t *scb;	int i;	int ret;	METHOD_TRACE("ips_read_config", 1);	/* set defaults for initiator IDs */	for (i = 0; i < 4; i++)		ha->conf->init_id[i] = 7;	scb = &ha->scbs[ha->max_cmds - 1];	ips_init_scb(ha, scb);	scb->timeout = ips_cmd_timeout;	scb->cdb[0] = IPS_CMD_READ_CONF;	scb->cmd.basic_io.op_code = IPS_CMD_READ_CONF;	scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);	scb->data_len = sizeof (*ha->conf);	scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr;	/* send command */	if (((ret =	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)	    || (ret == IPS_SUCCESS_IMM)	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {		memset(ha->conf, 0, sizeof (IPS_CONF));		/* reset initiator IDs */		for (i = 0; i < 4; i++)			ha->conf->init_id[i] = 7;		/* Allow Completed with Errors, so JCRM can access the Adapter to fix the problems */		if ((scb->basic_status & IPS_GSC_STATUS_MASK) ==		    IPS_CMD_CMPLT_WERROR)			return (1);		return (0);	}		memcpy(ha->conf, ha->ioctl_data, sizeof(*ha->conf));	return (1);}/****************************************************************************//*                                                                          *//* Routine Name: ips_readwrite_page5                                        *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Read nvram page 5 from the adapter                                     *//*                                                                          *//****************************************************************************/static intips_readwrite_page5(ips_ha_t * ha, int write, int intr){	ips_scb_t *scb;	int ret;	METHOD_TRACE("ips_readwrite_page5", 1);	scb = &ha->scbs[ha->max_cmds - 1];	ips_init_scb(ha, scb);	scb->timeout = ips_cmd_timeout;	scb->cdb[0] = IPS_CMD_RW_NVRAM_PAGE;	scb->cmd.nvram.op_code = IPS_CMD_RW_NVRAM_PAGE;	scb->cmd.nvram.command_id = IPS_COMMAND_ID(ha, scb);	scb->cmd.nvram.page = 5;	scb->cmd.nvram.write = write;	scb->cmd.nvram.reserved = 0;	scb->cmd.nvram.reserved2 = 0;	scb->data_len = sizeof (*ha->nvram);	scb->cmd.nvram.buffer_addr = ha->ioctl_busaddr;	if (write)		memcpy(ha->ioctl_data, ha->nvram, sizeof(*ha->nvram));		/* issue the command */	if (((ret =	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)	    || (ret == IPS_SUCCESS_IMM)	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {		memset(ha->nvram, 0, sizeof (IPS_NVRAM_P5));		return (0);	}	if (!write)		memcpy(ha->nvram, ha->ioctl_data, sizeof(*ha->nvram));	return (1);}/****************************************************************************//*                                                                          *//* Routine Name: ips_clear_adapter                                          *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Clear the stripe lock tables                                           *//*                                                                          *//****************************************************************************/static intips_clear_adapter(ips_ha_t * ha, int intr){	ips_scb_t *scb;	int ret;	METHOD_TRACE("ips_clear_adapter", 1);	scb = &ha->scbs[ha->max_cmds - 1];	ips_init_scb(ha, scb);	scb->timeout = ips_reset_timeout;	scb->cdb[0] = IPS_CMD_CONFIG_SYNC;	scb->cmd.config_sync.op_code = IPS_CMD_CONFIG_SYNC;	scb->cmd.config_sync.command_id = IPS_COMMAND_ID(ha, scb);	scb->cmd.config_sync.channel = 0;	scb->cmd.config_sync.source_target = IPS_POCL;	scb->cmd.config_sync.reserved = 0;	scb->cmd.config_sync.reserved2 = 0;	scb->cmd.config_sync.reserved3 = 0;	/* issue command */	if (((ret =	      ips_send_wait(ha, scb, ips_reset_timeout, intr)) == IPS_FAILURE)	    || (ret == IPS_SUCCESS_IMM)	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))		return (0);	/* send unlock stripe command */	ips_init_scb(ha, scb);	scb->cdb[0] = IPS_CMD_ERROR_TABLE;	scb->timeout = ips_reset_timeout;	scb->cmd.unlock_stripe.op_code = IPS_CMD_ERROR_TABLE;	scb->cmd.unlock_stripe.command_id = IPS_COMMAND_ID(ha, scb);	scb->cmd.unlock_stripe.log_drv = 0;	scb->cmd.unlock_stripe.control = IPS_CSL;	scb->cmd.unlock_stripe.reserved = 0;	scb->cmd.unlock_stripe.reserved2 = 0;	scb->cmd.unlock_stripe.reserved3 = 0;	/* issue command */	if (((ret =	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)	    || (ret == IPS_SUCCESS_IMM)	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))		return (0);	return (1);}/****************************************************************************//*                                                                          *//* Routine Name: ips_ffdc_reset                                             *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   FFDC: write reset info                                                 *//*                                                                          *//****************************************************************************/static voidips_ffdc_reset(ips_ha_t * ha, int intr){	ips_scb_t *scb;	METHOD_TRACE("ips_ffdc_reset", 1);	scb = &ha->scbs[ha->max_cmds - 1];	ips_init_scb(ha, scb);	scb->timeout = ips_cmd_timeout;	scb->cdb[0] = IPS_CMD_FFDC;	scb->cmd.ffdc.op_code = IPS_CMD_FFDC;	scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb);	scb->cmd.ffdc.reset_count = ha->reset_count;	scb->cmd.ffdc.reset_type = 0x80;	/* convert time to what the card wants */	ips_fix_ffdc_time(ha, scb, ha->last_ffdc);	/* issue command */	ips_send_wait(ha, scb, ips_cmd_timeout, intr);}/****************************************************************************//*                                                                          *//* Routine Name: ips_ffdc_time                                              *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   FFDC: write time info                                                  *//*                                                                          *//****************************************************************************/static voidips_ffdc_time(ips_ha_t * ha){	ips_scb_t *scb;	METHOD_TRACE("ips_ffdc_time", 1);	DEBUG_VAR(1, "(%s%d) Sending time update.", ips_name, ha->host_num);	scb = &ha->scbs[ha->max_cmds - 1];	ips_init_scb(ha, scb);	scb->timeout = ips_cmd_timeout;	scb->cdb[0] = IPS_CMD_FFDC;	scb->cmd.ffdc.op_code = IPS_CMD_FFDC;	scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb);	scb->cmd.ffdc.reset_count = 0;	scb->cmd.ffdc.reset_type = 0;	/* convert time to what the card wants */	ips_fix_ffdc_time(ha, scb, ha->last_ffdc);	/* issue command */	ips_send_wait(ha, scb, ips_cmd_timeout, IPS_FFDC);}/****************************************************************************//*                                                                          *//* Routine Name: ips_fix_ffdc_time                                          *//*                                                                          *//* Routine Description:                                                     *//*   Adjust time_t to what the card wants                                   *//*                                                                          *//****************************************************************************/static voidips_fix_ffdc_time(ips_ha_t * ha, ips_scb_t * scb, time_t current_time){	long days;	long rem;	int i;	int year;	int yleap;	int year_lengths[2] = { IPS_DAYS_NORMAL_YEAR, IPS_DAYS_LEAP_YEAR };	int month_lengths[12][2] = { {31, 31},	{28, 29},	{31, 31},	{30, 30},	{31, 31},	{30, 30},	{31, 31},	{31, 31},	{30, 30},	{31, 31},	{30, 30},	{31, 31}	};	METHOD_TRACE("ips_fix_ffdc_time", 1);	days = current_time / IPS_SECS_DAY;	rem = current_time % IPS_SECS_DAY;	scb->cmd.ffdc.hour = (rem / IPS_SECS_HOUR);	rem = rem % IPS_SECS_HOUR;	scb->cmd.ffdc.minute = (rem / IPS_SECS_MIN);	scb->cmd.ffdc.second = (rem % IPS_SECS_MIN);	year = IPS_EPOCH_YEAR;	while (days < 0 || days >= year_lengths[yleap = IPS_IS_LEAP_YEAR(year)]) {		int newy;		newy = year + (days / IPS_DAYS_NORMAL_YEAR);		if (days < 0)			--newy;		days -= (newy - year) * IPS_DAYS_NORMAL_YEAR +		    IPS_NUM_LEAP_YEARS_THROUGH(newy - 1) -		    IPS_NUM_LEAP_YEARS_THROUGH(year - 1);		year = newy;	}	scb->cmd.ffdc.yearH = year / 100;	scb->cmd.ffdc.yearL = year % 100;	for (i = 0; days >= month_lengths[i][yleap]; ++i)		days -= month_lengths[i][yleap];	scb->cmd.ffdc.month = i + 1;	scb->cmd.ffdc.day = days + 1;}/**************************************************************************** * BIOS Flash Routines                                                      * ****************************************************************************//****************************************************************************//*                                                                          *//* Routine Name: ips_erase_bios                                             *//*                                                                          *//* Routine Description:                                                     *//*   Erase the BIOS on the adapter                                          *//*                                                                          *//****************************************************************************/static intips_erase_bios(ips_ha_t * ha){	int timeout;	uint8_t status = 0;	METHOD_TRACE("ips_erase_bios", 1);	status = 0;	/* Clear the status register */	outl(0, ha->io_addr + IPS_REG_FLAP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	outb(0x50, ha->io_addr + IPS_REG_FLDP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	/* Erase Setup */	outb(0x20, ha->io_addr + IPS_REG_FLDP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	/* Erase Confirm */	outb(0xD0, ha->io_addr + IPS_REG_FLDP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	/* Erase Status */	outb(0x70, ha->io_addr + IPS_REG_FLDP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	timeout = 80000;	/* 80 seconds */	while (timeout > 0) {		if (ha->revision_id == IPS_REVID_TROMBONE64) {			outl(0, ha->io_addr + IPS_REG_FLAP);			udelay(25);	/* 25 us */		}		status = inb(ha->io_addr + IPS_REG_FLDP);		if (status & 0x80)			break;		MDELAY(1);		timeout--;	}	/* check for timeout */	if (timeout <= 0) {		/* timeout */		/* try to suspend the erase */		outb(0xB0, ha->io_addr + IPS_REG_FLDP);		if (ha->revision_id == IPS_REVID_TROMBONE64)			udelay(25);	/* 25 us */		/* wait for 10 seconds */		timeout = 10000;		while (timeout > 0) {			if (ha->revision_id == IPS_REVID_TROMBONE64) {				outl(0, ha->io_addr + IPS_REG_FLAP);				udelay(25);	/* 25 us */			}			status = inb(ha->io_addr + IPS_REG_FLDP);			if (status & 0xC0)				break;			MDELAY(1);			timeout--;		}		return (1);	}	/* check for valid VPP */	if (status & 0x08)		/* VPP failure */		return (1);	/* check for succesful flash */	if (status & 0x30)		/* sequence error */		return (1);	/* Otherwise, we were successful */	/* clear status */	outb(0x50, ha->io_addr + IPS_REG_FLDP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	/* enable reads */	outb(0xFF, ha->io_addr + IPS_REG_FLDP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	return (0);}/****************************************************************************//*                                                                          *//* Routine Name: ips_erase_bios_memio                                       *//*                                                                          *//* Routine Description:                                                     *//*   Erase the BIOS on the adapter                                          *//*                                                                          *//****************************************************************************/static intips_erase_bios_memio(ips_ha_t * ha){	int timeout;	uint8_t status;	METHOD_TRACE("ips_erase_bios_memio", 1);	status = 0;	/* Clear the status register */	writel(0, ha->mem_ptr + IPS_REG_FLAP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	/* Erase Setup */	writeb(0x20, ha->mem_ptr + IPS_REG_FLDP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	/* Erase Confirm */	writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	/* Erase Status */	writeb(0x70, ha->mem_ptr + IPS_REG_FLDP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	timeout = 80000;	/* 80 seconds */	while (timeout > 0) {		if (ha->revision_id == IPS_REVID_TROMBONE64) {			writel(0, ha->mem_ptr + IPS_REG_FLAP);			udelay(25);	/* 25 us */		}		status = readb(ha->mem_ptr + IPS_REG_FLDP);		if (status & 0x80)			break;		MDELAY(1);		timeout--;	}	/* check for timeout */	if (timeout <= 0) {		/* timeout */		/* try to suspend the erase */		writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP);		if (ha->revision_id == IPS_REVID_TROMBONE64)			udelay(25);	/* 25 us */		/* wait for 10 seconds */		timeout = 10000;		while (timeout > 0) {			if (ha->revision_id == IPS_REVID_TROMBONE64) {				writel(0, ha->mem_ptr + IPS_REG_FLAP);				udelay(25);	/* 25 us */			}			status = readb(ha->mem_ptr + IPS_REG_FLDP);			if (status & 0xC0)				break;			MDELAY(1);			timeout--;		}		return (1);	}	/* check for valid VPP */	if (status & 0x08)		/* VPP failure */		return (1);	/* check for succesful flash */	if (status & 0x30)		/* sequence error */		return (1);	/* Otherwise, we were successful */	/* clear status */	writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	/* enable reads */	writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	return (0);}/****************************************************************************//*                                                                          *//* Routine Name: ips_program_bios                                           *//*                                                                          *//* Routine Description:                                                     *//*   Program the BIOS on the adapter                                        *//*                                                                          *//****************************************************************************/static intips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,		 uint32_t offset){	int i;	int timeout;	uint8_t status = 0;	METHOD_TRACE("ips_program_bios", 1);	status = 0;	for (i = 0; i < buffersize; i++) {		/* write a byte */		outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);		if (ha->revision_id == IPS_REVID_TROMBONE64)			udelay(25);	/* 25 us */		outb(0x40, ha->io_addr + IPS_REG_FLDP);		if (ha->revision_id == IPS_REVID_TROMBONE64)			udelay(25);	/* 25 us */		outb(buffer[i], ha->io_addr + IPS_REG_FLDP);		if (ha->revision_id == IPS_REVID_TROMBONE64)			udelay(25);	/* 25 us */		/* wait up to one second */		timeout = 1000;		while (timeout > 0) {			if (ha->revision_id == IPS_REVID_TROMBONE64) {				outl(0, ha->io_addr + IPS_REG_FLAP);				udelay(25);	/* 25 us */			}			status = inb(ha->io_addr + IPS_REG_FLDP);			if (status & 0x80)				break;			MDELAY(1);			timeout--;		}		if (timeout == 0) {			/* timeout error */			outl(0, ha->io_addr + IPS_REG_FLAP);			if (ha->revision_id == IPS_REVID_TROMBONE64)				udelay(25);	/* 25 us */			outb(0xFF, ha->io_addr + IPS_REG_FLDP);			if (ha->revision_id == IPS_REVID_TROMBONE64)				udelay(25);	/* 25 us */			return (1);		}		/* check the status */		if (status & 0x18) {			/* programming error */			outl(0, ha->io_addr + IPS_REG_FLAP);			if (ha->revision_id == IPS_REVID_TROMBONE64)				udelay(25);	/* 25 us */			outb(0xFF, ha->io_addr + IPS_REG_FLDP);			if (ha->revision_id == IPS_REVID_TROMBONE64)				udelay(25);	/* 25 us */			return (1);		}	}			/* end for */	/* Enable reading */	outl(0, ha->io_addr + IPS_REG_FLAP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	outb(0xFF, ha->io_addr + IPS_REG_FLDP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	return (0);}/****************************************************************************//*                                                                          *//* Routine Name: ips_program_bios_memio                                     *//*                                                                          *//* Routine Description:                                                     *//*   Program the BIOS on the adapter                                        *//*                                                                          *//****************************************************************************/static intips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,		       uint32_t offset){	int i;	int timeout;	uint8_t status = 0;	METHOD_TRACE("ips_program_bios_memio", 1);	status = 0;	for (i = 0; i < buffersize; i++) {		/* write a byte */		writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);		if (ha->revision_id == IPS_REVID_TROMBONE64)			udelay(25);	/* 25 us */		writeb(0x40, ha->mem_ptr + IPS_REG_FLDP);		if (ha->revision_id == IPS_REVID_TROMBONE64)			udelay(25);	/* 25 us */		writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP);		if (ha->revision_id == IPS_REVID_TROMBONE64)			udelay(25);	/* 25 us */		/* wait up to one second */		timeout = 1000;		while (timeout > 0) {			if (ha->revision_id == IPS_REVID_TROMBONE64) {				writel(0, ha->mem_ptr + IPS_REG_FLAP);				udelay(25);	/* 25 us */			}			status = readb(ha->mem_ptr + IPS_REG_FLDP);			if (status & 0x80)				break;			MDELAY(1);			timeout--;		}		if (timeout == 0) {			/* timeout error */			writel(0, ha->mem_ptr + IPS_REG_FLAP);			if (ha->revision_id == IPS_REVID_TROMBONE64)				udelay(25);	/* 25 us */			writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);			if (ha->revision_id == IPS_REVID_TROMBONE64)				udelay(25);	/* 25 us */			return (1);		}		/* check the status */		if (status & 0x18) {			/* programming error */			writel(0, ha->mem_ptr + IPS_REG_FLAP);			if (ha->revision_id == IPS_REVID_TROMBONE64)				udelay(25);	/* 25 us */			writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);			if (ha->revision_id == IPS_REVID_TROMBONE64)				udelay(25);	/* 25 us */			return (1);		}	}			/* end for */	/* Enable reading */	writel(0, ha->mem_ptr + IPS_REG_FLAP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	return (0);}/****************************************************************************//*                                                                          *//* Routine Name: ips_verify_bios                                            *//*                                                                          *//* Routine Description:                                                     *//*   Verify the BIOS on the adapter                                         *//*                                                                          *//****************************************************************************/static intips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,		uint32_t offset){	uint8_t checksum;	int i;	METHOD_TRACE("ips_verify_bios", 1);	/* test 1st byte */	outl(0, ha->io_addr + IPS_REG_FLAP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)		return (1);	outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)		return (1);	checksum = 0xff;	for (i = 2; i < buffersize; i++) {		outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);		if (ha->revision_id == IPS_REVID_TROMBONE64)			udelay(25);	/* 25 us */		checksum = (uint8_t) checksum + inb(ha->io_addr + IPS_REG_FLDP);	}	if (checksum != 0)		/* failure */		return (1);	else		/* success */		return (0);}/****************************************************************************//*                                                                          *//* Routine Name: ips_verify_bios_memio                                      *//*                                                                          *//* Routine Description:                                                     *//*   Verify the BIOS on the adapter                                         *//*                                                                          *//****************************************************************************/static intips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,		      uint32_t offset){	uint8_t checksum;	int i;	METHOD_TRACE("ips_verify_bios_memio", 1);	/* test 1st byte */	writel(0, ha->mem_ptr + IPS_REG_FLAP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)		return (1);	writel(1, ha->mem_ptr + IPS_REG_FLAP);	if (ha->revision_id == IPS_REVID_TROMBONE64)		udelay(25);	/* 25 us */	if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)		return (1);	checksum = 0xff;	for (i = 2; i < buffersize; i++) {		writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);		if (ha->revision_id == IPS_REVID_TROMBONE64)			udelay(25);	/* 25 us */		checksum =		    (uint8_t) checksum + readb(ha->mem_ptr + IPS_REG_FLDP);	}	if (checksum != 0)		/* failure */		return (1);	else		/* success */		return (0);}/*---------------------------------------------------------------------------*//*   Routine Name: ips_version_check                                         *//*                                                                           *//*   Dependencies:                                                           *//*     Assumes that ips_read_adapter_status() is called first filling in     *//*     the data for SubSystem Parameters.                                    *//*     Called from ips_write_driver_status() so it also assumes NVRAM Page 5 *//*     Data is available.                                                    *//*                                                                           *//*---------------------------------------------------------------------------*/static voidips_version_check(ips_ha_t * ha, int intr){	IPS_VERSION_DATA *VersionInfo;	uint8_t FirmwareVersion[IPS_COMPAT_ID_LENGTH + 1];	uint8_t BiosVersion[IPS_COMPAT_ID_LENGTH + 1];	int MatchError;	int rc;	char BiosString[10];	char FirmwareString[10];	METHOD_TRACE("ips_version_check", 1);	VersionInfo = ( IPS_VERSION_DATA * ) ha->ioctl_data;	memset(FirmwareVersion, 0, IPS_COMPAT_ID_LENGTH + 1);	memset(BiosVersion, 0, IPS_COMPAT_ID_LENGTH + 1);	/* Get the Compatible BIOS Version from NVRAM Page 5 */	memcpy(BiosVersion, ha->nvram->BiosCompatibilityID,	       IPS_COMPAT_ID_LENGTH);	rc = IPS_FAILURE;	if (ha->subsys->param[4] & IPS_GET_VERSION_SUPPORT) {	/* If Versioning is Supported */		/* Get the Version Info with a Get Version Command */		memset( VersionInfo, 0, sizeof (IPS_VERSION_DATA));		rc = ips_get_version_info(ha, ha->ioctl_busaddr, intr);		if (rc == IPS_SUCCESS)			memcpy(FirmwareVersion, VersionInfo->compatibilityId,			       IPS_COMPAT_ID_LENGTH);	}	if (rc != IPS_SUCCESS) {	/* If Data Not Obtainable from a GetVersion Command */		/* Get the Firmware Version from Enquiry Data */		memcpy(FirmwareVersion, ha->enq->CodeBlkVersion,		       IPS_COMPAT_ID_LENGTH);	}	/* printk(KERN_WARNING "Adapter's BIOS Version  = %s\n", BiosVersion);          */	/* printk(KERN_WARNING "BIOS Compatible Version = %s\n", IPS_COMPAT_BIOS);      */	/* printk(KERN_WARNING "Adapter's Firmware Version  = %s\n", FirmwareVersion);  */	/* printk(KERN_WARNING "Firmware Compatible Version = %s \n", Compatable[ ha->nvram->adapter_type ]); */	MatchError = 0;	if (strncmp	    (FirmwareVersion, Compatable[ha->nvram->adapter_type],	     IPS_COMPAT_ID_LENGTH) != 0)		MatchError = 1;	if (strncmp(BiosVersion, IPS_COMPAT_BIOS, IPS_COMPAT_ID_LENGTH) != 0)		MatchError = 1;	ha->nvram->versioning = 1;	/* Indicate the Driver Supports Versioning */	if (MatchError) {		ha->nvram->version_mismatch = 1;		if (ips_cd_boot == 0) {			strncpy(&BiosString[0], ha->nvram->bios_high, 4);			strncpy(&BiosString[4], ha->nvram->bios_low, 4);			BiosString[8] = 0;			strncpy(&FirmwareString[0], ha->enq->CodeBlkVersion, 8);			FirmwareString[8] = 0;			IPS_PRINTK(KERN_WARNING, ha->pcidev,				   "Warning ! ! ! ServeRAID Version Mismatch\n");			IPS_PRINTK(KERN_WARNING, ha->pcidev,				   "Bios = %s, Firmware = %s, Device Driver = %s%s\n",				   BiosString, FirmwareString, IPS_VERSION_HIGH,				   IPS_VERSION_LOW);			IPS_PRINTK(KERN_WARNING, ha->pcidev,				   "These levels should match to avoid possible compatibility problems.\n");		}	} else {		ha->nvram->version_mismatch = 0;	}	return;}/*---------------------------------------------------------------------------*//*   Routine Name: ips_get_version_info                                      *//*                                                                           *//*   Routine Description:                                                    *//*     Issue an internal GETVERSION Command                                  *//*                                                                           *//*   Return Value:                                                           *//*     0 if Successful, else non-zero                                        *//*---------------------------------------------------------------------------*/static intips_get_version_info(ips_ha_t * ha, dma_addr_t Buffer, int intr){	ips_scb_t *scb;	int rc;	METHOD_TRACE("ips_get_version_info", 1);	scb = &ha->scbs[ha->max_cmds - 1];	ips_init_scb(ha, scb);	scb->timeout = ips_cmd_timeout;	scb->cdb[0] = IPS_CMD_GET_VERSION_INFO;	scb->cmd.version_info.op_code = IPS_CMD_GET_VERSION_INFO;	scb->cmd.version_info.command_id = IPS_COMMAND_ID(ha, scb);	scb->cmd.version_info.reserved = 0;	scb->cmd.version_info.count = sizeof (IPS_VERSION_DATA);	scb->cmd.version_info.reserved2 = 0;	scb->data_len = sizeof (IPS_VERSION_DATA);	scb->data_busaddr = Buffer;	scb->cmd.version_info.buffer_addr = Buffer;	scb->flags = 0;	/* issue command */	rc = ips_send_wait(ha, scb, ips_cmd_timeout, intr);	return (rc);}/****************************************************************************//*                                                                          *//* Routine Name: ips_abort_init                                             *//*                                                                          *//* Routine Description:                                                     *//*   cleanup routine for a failed adapter initialization                    *//****************************************************************************/static intips_abort_init(ips_ha_t * ha, int index){	ha->active = 0;	ips_free(ha);	ips_ha[index] = NULL;	ips_sh[index] = NULL;	return -1;}/****************************************************************************//*                                                                          *//* Routine Name: ips_shift_controllers                                      *//*                                                                          *//* Routine Description:                                                     *//*   helper function for ordering adapters                                  *//****************************************************************************/static voidips_shift_controllers(int lowindex, int highindex){	ips_ha_t *ha_sav = ips_ha[highindex];	struct Scsi_Host *sh_sav = ips_sh[highindex];	int i;	for (i = highindex; i > lowindex; i--) {		ips_ha[i] = ips_ha[i - 1];		ips_sh[i] = ips_sh[i - 1];		ips_ha[i]->host_num = i;	}	ha_sav->host_num = lowindex;	ips_ha[lowindex] = ha_sav;	ips_sh[lowindex] = sh_sav;}/****************************************************************************//*                                                                          *//* Routine Name: ips_order_controllers                                      *//*                                                                          *//* Routine Description:                                                     *//*   place controllers is the "proper" boot order                           *//****************************************************************************/static voidips_order_controllers(void){	int i, j, tmp, position = 0;	IPS_NVRAM_P5 *nvram;	if (!ips_ha[0])		return;	nvram = ips_ha[0]->nvram;	if (nvram->adapter_order[0]) {		for (i = 1; i <= nvram->adapter_order[0]; i++) {			for (j = position; j < ips_num_controllers; j++) {				switch (ips_ha[j]->ad_type) {				case IPS_ADTYPE_SERVERAID6M:				case IPS_ADTYPE_SERVERAID7M:					if (nvram->adapter_order[i] == 'M') {						ips_shift_controllers(position,								      j);						position++;					}					break;				case IPS_ADTYPE_SERVERAID4L:				case IPS_ADTYPE_SERVERAID4M:				case IPS_ADTYPE_SERVERAID4MX:				case IPS_ADTYPE_SERVERAID4LX:					if (nvram->adapter_order[i] == 'N') {						ips_shift_controllers(position,								      j);						position++;					}					break;				case IPS_ADTYPE_SERVERAID6I:				case IPS_ADTYPE_SERVERAID5I2:				case IPS_ADTYPE_SERVERAID5I1:				case IPS_ADTYPE_SERVERAID7k:					if (nvram->adapter_order[i] == 'S') {						ips_shift_controllers(position,								      j);						position++;					}					break;				case IPS_ADTYPE_SERVERAID:				case IPS_ADTYPE_SERVERAID2:				case IPS_ADTYPE_NAVAJO:				case IPS_ADTYPE_KIOWA:				case IPS_ADTYPE_SERVERAID3L:				case IPS_ADTYPE_SERVERAID3:				case IPS_ADTYPE_SERVERAID4H:					if (nvram->adapter_order[i] == 'A') {						ips_shift_controllers(position,								      j);						position++;					}					break;				default:					break;				}			}		}		/* if adapter_order[0], then ordering is complete */		return;	}	/* old bios, use older ordering */	tmp = 0;	for (i = position; i < ips_num_controllers; i++) {		if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I2 ||		    ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I1) {			ips_shift_controllers(position, i);			position++;			tmp = 1;		}	}	/* if there were no 5I cards, then don't do any extra ordering */	if (!tmp)		return;	for (i = position; i < ips_num_controllers; i++) {		if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4L ||		    ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4M ||		    ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4LX ||		    ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4MX) {			ips_shift_controllers(position, i);			position++;		}	}	return;}/****************************************************************************//*                                                                          *//* Routine Name: ips_register_scsi                                          *//*                                                                          *//* Routine Description:                                                     *//*   perform any registration and setup with the scsi layer                 *//****************************************************************************/static intips_register_scsi(int index){	struct Scsi_Host *sh;	ips_ha_t *ha, *oldha = ips_ha[index];	sh = scsi_host_alloc(&ips_driver_template, sizeof (ips_ha_t));	if (!sh) {		IPS_PRINTK(KERN_WARNING, oldha->pcidev,			   "Unable to register controller with SCSI subsystem\n");		return -1;	}	ha = IPS_HA(sh);	memcpy(ha, oldha, sizeof (ips_ha_t));	free_irq(oldha->irq, oldha);	/* Install the interrupt handler with the new ha */	if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {		IPS_PRINTK(KERN_WARNING, ha->pcidev,			   "Unable to install interrupt handler\n");		scsi_host_put(sh);		return -1;	}	kfree(oldha);	ips_sh[index] = sh;	ips_ha[index] = ha;	IPS_SCSI_SET_DEVICE(sh, ha);	/* Store away needed values for later use */	sh->io_port = ha->io_addr;	sh->n_io_port = ha->io_addr ? 255 : 0;	sh->unique_id = (ha->io_addr) ? ha->io_addr : ha->mem_addr;	sh->irq = ha->irq;	sh->sg_tablesize = sh->hostt->sg_tablesize;	sh->can_queue = sh->hostt->can_queue;	sh->cmd_per_lun = sh->hostt->cmd_per_lun;	sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma;	sh->use_clustering = sh->hostt->use_clustering;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)	sh->max_sectors = 128;#endif	sh->max_id = ha->ntargets;	sh->max_lun = ha->nlun;	sh->max_channel = ha->nbus - 1;	sh->can_queue = ha->max_cmds - 1;	IPS_ADD_HOST(sh, NULL);	return 0;}/*---------------------------------------------------------------------------*//*   Routine Name: ips_remove_device                                         *//*                                                                           *//*   Routine Description:                                                    *//*     Remove one Adapter ( Hot Plugging )                                   *//*---------------------------------------------------------------------------*/static void __devexitips_remove_device(struct pci_dev *pci_dev){	int i;	struct Scsi_Host *sh;	ips_ha_t *ha;	for (i = 0; i < IPS_MAX_ADAPTERS; i++) {		ha = ips_ha[i];		if (ha) {			if ((pci_dev->bus->number == ha->pcidev->bus->number) &&			    (pci_dev->devfn == ha->pcidev->devfn)) {				sh = ips_sh[i];				ips_release(sh);			}		}	}}/****************************************************************************//*                                                                          *//* Routine Name: ips_module_init                                            *//*                                                                          *//* Routine Description:                                                     *//*   function called on module load                                         *//****************************************************************************/static int __initips_module_init(void){	if (pci_module_init(&ips_pci_driver) < 0)		return -ENODEV;	ips_driver_template.module = THIS_MODULE;	ips_order_controllers();	if (IPS_REGISTER_HOSTS(&ips_driver_template)) {		pci_unregister_driver(&ips_pci_driver);		return -ENODEV;	}	register_reboot_notifier(&ips_notifier);	return 0;}/****************************************************************************//*                                                                          *//* Routine Name: ips_module_exit                                            *//*                                                                          *//* Routine Description:                                                     *//*   function called on module unload                                       *//****************************************************************************/static void __exitips_module_exit(void){	IPS_UNREGISTER_HOSTS(&ips_driver_template);	pci_unregister_driver(&ips_pci_driver);	unregister_reboot_notifier(&ips_notifier);}module_init(ips_module_init);module_exit(ips_module_exit);/*---------------------------------------------------------------------------*//*   Routine Name: ips_insert_device                                         *//*                                                                           *//*   Routine Description:                                                    *//*     Add One Adapter ( Hot Plug )                                          *//*                                                                           *//*   Return Value:                                                           *//*     0 if Successful, else non-zero                                        *//*---------------------------------------------------------------------------*/static int __devinitips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent){	int index;	int rc;	METHOD_TRACE("ips_insert_device", 1);	if (pci_enable_device(pci_dev))		return -1;	rc = ips_init_phase1(pci_dev, &index);	if (rc == SUCCESS)		rc = ips_init_phase2(index);	if (ips_hotplug)		if (ips_register_scsi(index)) {			ips_free(ips_ha[index]);			rc = -1;		}	if (rc == SUCCESS)		ips_num_controllers++;	ips_next_controller = ips_num_controllers;	return rc;}/*---------------------------------------------------------------------------*//*   Routine Name: ips_init_phase1                                           *//*                                                                           *//*   Routine Description:                                                    *//*     Adapter Initialization                                                *//*                                                                           *//*   Return Value:                                                           *//*     0 if Successful, else non-zero                                        *//*---------------------------------------------------------------------------*/static intips_init_phase1(struct pci_dev *pci_dev, int *indexPtr){	ips_ha_t *ha;	uint32_t io_addr;	uint32_t mem_addr;	uint32_t io_len;	uint32_t mem_len;	uint8_t revision_id;	uint8_t bus;	uint8_t func;	uint8_t irq;	uint16_t subdevice_id;	int j;	int index;	dma_addr_t dma_address;	char __iomem *ioremap_ptr;	char __iomem *mem_ptr;	uint32_t IsDead;	METHOD_TRACE("ips_init_phase1", 1);	index = IPS_MAX_ADAPTERS;	for (j = 0; j < IPS_MAX_ADAPTERS; j++) {		if (ips_ha[j] == 0) {			index = j;			break;		}	}	if (index >= IPS_MAX_ADAPTERS)		return -1;	/* stuff that we get in dev */	irq = pci_dev->irq;	bus = pci_dev->bus->number;	func = pci_dev->devfn;	/* Init MEM/IO addresses to 0 */	mem_addr = 0;	io_addr = 0;	mem_len = 0;	io_len = 0;	for (j = 0; j < 2; j++) {		if (!pci_resource_start(pci_dev, j))			break;		if (pci_resource_flags(pci_dev, j) & IORESOURCE_IO) {			io_addr = pci_resource_start(pci_dev, j);			io_len = pci_resource_len(pci_dev, j);		} else {			mem_addr = pci_resource_start(pci_dev, j);			mem_len = pci_resource_len(pci_dev, j);		}	}	/* setup memory mapped area (if applicable) */	if (mem_addr) {		uint32_t base;		uint32_t offs;		if (!request_mem_region(mem_addr, mem_len, "ips")) {			IPS_PRINTK(KERN_WARNING, pci_dev,				   "Couldn't allocate IO Memory space %x len %d.\n",				   mem_addr, mem_len);			return -1;		}		base = mem_addr & PAGE_MASK;		offs = mem_addr - base;		ioremap_ptr = ioremap(base, PAGE_SIZE);		mem_ptr = ioremap_ptr + offs;	} else {		ioremap_ptr = NULL;		mem_ptr = NULL;	}	/* setup I/O mapped area (if applicable) */	if (io_addr) {		if (!request_region(io_addr, io_len, "ips")) {			IPS_PRINTK(KERN_WARNING, pci_dev,				   "Couldn't allocate IO space %x len %d.\n",				   io_addr, io_len);			return -1;		}	}	/* get the revision ID */	if (pci_read_config_byte(pci_dev, PCI_REVISION_ID, &revision_id)) {		IPS_PRINTK(KERN_WARNING, pci_dev, "Can't get revision id.\n");		return -1;	}	subdevice_id = pci_dev->subsystem_device;	/* found a controller */	ha = kmalloc(sizeof (ips_ha_t), GFP_KERNEL);	if (ha == NULL) {		IPS_PRINTK(KERN_WARNING, pci_dev,			   "Unable to allocate temporary ha struct\n");		return -1;	}	memset(ha, 0, sizeof (ips_ha_t));	ips_sh[index] = NULL;	ips_ha[index] = ha;	ha->active = 1;	/* Store info in HA structure */	ha->irq = irq;	ha->io_addr = io_addr;	ha->io_len = io_len;	ha->mem_addr = mem_addr;	ha->mem_len = mem_len;	ha->mem_ptr = mem_ptr;	ha->ioremap_ptr = ioremap_ptr;	ha->host_num = (uint32_t) index;	ha->revision_id = revision_id;	ha->slot_num = PCI_SLOT(pci_dev->devfn);	ha->device_id = pci_dev->device;	ha->subdevice_id = subdevice_id;	ha->pcidev = pci_dev;	/*	 * Set the pci_dev's dma_mask.  Not all adapters support 64bit	 * addressing so don't enable it if the adapter can't support	 * it!  Also, don't use 64bit addressing if dma addresses	 * are guaranteed to be < 4G.	 */	if (IPS_ENABLE_DMA64 && IPS_HAS_ENH_SGLIST(ha) &&	    !pci_set_dma_mask(ha->pcidev, 0xffffffffffffffffULL)) {		(ha)->flags |= IPS_HA_ENH_SG;	} else {		if (pci_set_dma_mask(ha->pcidev, 0xffffffffULL) != 0) {			printk(KERN_WARNING "Unable to set DMA Mask\n");			return ips_abort_init(ha, index);		}	}	if(ips_cd_boot && !ips_FlashData){		ips_FlashData = pci_alloc_consistent(pci_dev, PAGE_SIZE << 7,						     &ips_flashbusaddr);	}	ha->enq = pci_alloc_consistent(pci_dev, sizeof (IPS_ENQ),				       &ha->enq_busaddr);	if (!ha->enq) {		IPS_PRINTK(KERN_WARNING, pci_dev,			   "Unable to allocate host inquiry structure\n");		return ips_abort_init(ha, index);	}	ha->adapt = pci_alloc_consistent(pci_dev, sizeof (IPS_ADAPTER) +					 sizeof (IPS_IO_CMD), &dma_address);	if (!ha->adapt) {		IPS_PRINTK(KERN_WARNING, pci_dev,			   "Unable to allocate host adapt & dummy structures\n");		return ips_abort_init(ha, index);	}	ha->adapt->hw_status_start = dma_address;	ha->dummy = (void *) (ha->adapt + 1);	ha->logical_drive_info = pci_alloc_consistent(pci_dev, sizeof (IPS_LD_INFO), &dma_address);	if (!ha->logical_drive_info) {		IPS_PRINTK(KERN_WARNING, pci_dev,			   "Unable to allocate logical drive info structure\n");		return ips_abort_init(ha, index);	}	ha->logical_drive_info_dma_addr = dma_address;	ha->conf = kmalloc(sizeof (IPS_CONF), GFP_KERNEL);	if (!ha->conf) {		IPS_PRINTK(KERN_WARNING, pci_dev,			   "Unable to allocate host conf structure\n");		return ips_abort_init(ha, index);	}	ha->nvram = kmalloc(sizeof (IPS_NVRAM_P5), GFP_KERNEL);	if (!ha->nvram) {		IPS_PRINTK(KERN_WARNING, pci_dev,			   "Unable to allocate host NVRAM structure\n");		return ips_abort_init(ha, index);	}	ha->subsys = kmalloc(sizeof (IPS_SUBSYS), GFP_KERNEL);	if (!ha->subsys) {		IPS_PRINTK(KERN_WARNING, pci_dev,			   "Unable to allocate host subsystem structure\n");		return ips_abort_init(ha, index);	}	/* the ioctl buffer is now used during adapter initialization, so its	 * successful allocation is now required */	if (ips_ioctlsize < PAGE_SIZE)		ips_ioctlsize = PAGE_SIZE;	ha->ioctl_data = pci_alloc_consistent(pci_dev, ips_ioctlsize,					      &ha->ioctl_busaddr);	ha->ioctl_len = ips_ioctlsize;	if (!ha->ioctl_data) {		IPS_PRINTK(KERN_WARNING, pci_dev,			   "Unable to allocate IOCTL data\n");		return ips_abort_init(ha, index);	}	/*	 * Setup Functions	 */	ips_setup_funclist(ha);	if ((IPS_IS_MORPHEUS(ha)) || (IPS_IS_MARCO(ha))) {		/* If Morpheus appears dead, reset it */		IsDead = readl(ha->mem_ptr + IPS_REG_I960_MSG1);		if (IsDead == 0xDEADBEEF) {			ips_reset_morpheus(ha);		}	}	/*	 * Initialize the card if it isn't already	 */	if (!(*ha->func.isinit) (ha)) {		if (!(*ha->func.init) (ha)) {			/*			 * Initialization failed			 */			IPS_PRINTK(KERN_WARNING, pci_dev,				   "Unable to initialize controller\n");			return ips_abort_init(ha, index);		}	}	*indexPtr = index;	return SUCCESS;}/*---------------------------------------------------------------------------*//*   Routine Name: ips_init_phase2                                           *//*                                                                           *//*   Routine Description:                                                    *//*     Adapter Initialization Phase 2                                        *//*                                                                           *//*   Return Value:                                                           *//*     0 if Successful, else non-zero                                        *//*---------------------------------------------------------------------------*/static intips_init_phase2(int index){	ips_ha_t *ha;	ha = ips_ha[index];	METHOD_TRACE("ips_init_phase2", 1);	if (!ha->active) {		ips_ha[index] = NULL;		return -1;	}	/* Install the interrupt handler */	if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {		IPS_PRINTK(KERN_WARNING, ha->pcidev,			   "Unable to install interrupt handler\n");		return ips_abort_init(ha, index);	}	/*	 * Allocate a temporary SCB for initialization	 */	ha->max_cmds = 1;	if (!ips_allocatescbs(ha)) {		IPS_PRINTK(KERN_WARNING, ha->pcidev,			   "Unable to allocate a CCB\n");		free_irq(ha->irq, ha);		return ips_abort_init(ha, index);	}	if (!ips_hainit(ha)) {		IPS_PRINTK(KERN_WARNING, ha->pcidev,			   "Unable to initialize controller\n");		free_irq(ha->irq, ha);		return ips_abort_init(ha, index);	}	/* Free the temporary SCB */	ips_deallocatescbs(ha, 1);	/* allocate CCBs */	if (!ips_allocatescbs(ha)) {		IPS_PRINTK(KERN_WARNING, ha->pcidev,			   "Unable to allocate CCBs\n");		free_irq(ha->irq, ha);		return ips_abort_init(ha, index);	}	return SUCCESS;}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9)MODULE_LICENSE("GPL");#endifMODULE_DESCRIPTION("IBM ServeRAID Adapter Driver " IPS_VER_STRING);#ifdef MODULE_VERSIONMODULE_VERSION(IPS_VER_STRING);#endif/* * Overrides for Emacs so that we almost follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only.  This must remain at the end * of the file. * --------------------------------------------------------------------------- * Local variables: * c-indent-level: 2 * c-brace-imaginary-offset: 0 * c-brace-offset: -2 * c-argdecl-indent: 2 * c-label-offset: -2 * c-continued-statement-offset: 2 * c-continued-brace-offset: 0 * indent-tabs-mode: nil * tab-width: 8 * End: */
10457	/local/tlutelli/issta_data/temp/c/2005_temp/2005/10457/0ee957cb7a8f6e4fb8c6f943dbc451957bc0c6bc/ips.c/buggy/drivers/scsi/ips.c