commsup.c
来自「linux 内核源代码」· C语言 代码 · 共 1,700 行 · 第 1/4 页
C
1,700 行
* caller. * * Map the hw fib pointer as a 32bit value */ hw_fib->header.Command = cpu_to_le16(command); hw_fib->header.XferState |= cpu_to_le32(SentFromHost); fibptr->hw_fib_va->header.Flags = 0; /* 0 the flags field - internal only*/ /* * Set the size of the Fib we want to send to the adapter */ hw_fib->header.Size = cpu_to_le16(sizeof(struct aac_fibhdr) + size); if (le16_to_cpu(hw_fib->header.Size) > le16_to_cpu(hw_fib->header.SenderSize)) { return -EMSGSIZE; } /* * Get a queue entry connect the FIB to it and send an notify * the adapter a command is ready. */ hw_fib->header.XferState |= cpu_to_le32(NormalPriority); /* * Fill in the Callback and CallbackContext if we are not * going to wait. */ if (!wait) { fibptr->callback = callback; fibptr->callback_data = callback_data; } fibptr->done = 0; fibptr->flags = 0; FIB_COUNTER_INCREMENT(aac_config.FibsSent); dprintk((KERN_DEBUG "Fib contents:.\n")); dprintk((KERN_DEBUG " Command = %d.\n", le32_to_cpu(hw_fib->header.Command))); dprintk((KERN_DEBUG " SubCommand = %d.\n", le32_to_cpu(((struct aac_query_mount *)fib_data(fibptr))->command))); dprintk((KERN_DEBUG " XferState = %x.\n", le32_to_cpu(hw_fib->header.XferState))); dprintk((KERN_DEBUG " hw_fib va being sent=%p\n",fibptr->hw_fib_va)); dprintk((KERN_DEBUG " hw_fib pa being sent=%lx\n",(ulong)fibptr->hw_fib_pa)); dprintk((KERN_DEBUG " fib being sent=%p\n",fibptr)); if (!dev->queues) return -EBUSY; if(wait) spin_lock_irqsave(&fibptr->event_lock, flags); aac_adapter_deliver(fibptr); /* * If the caller wanted us to wait for response wait now. */ if (wait) { spin_unlock_irqrestore(&fibptr->event_lock, flags); /* Only set for first known interruptable command */ if (wait < 0) { /* * *VERY* Dangerous to time out a command, the * assumption is made that we have no hope of * functioning because an interrupt routing or other * hardware failure has occurred. */ unsigned long count = 36000000L; /* 3 minutes */ while (down_trylock(&fibptr->event_wait)) { int blink; if (--count == 0) { struct aac_queue * q = &dev->queues->queue[AdapNormCmdQueue]; spin_lock_irqsave(q->lock, qflags); q->numpending--; spin_unlock_irqrestore(q->lock, qflags); if (wait == -1) { printk(KERN_ERR "aacraid: aac_fib_send: first asynchronous command timed out.\n" "Usually a result of a PCI interrupt routing problem;\n" "update mother board BIOS or consider utilizing one of\n" "the SAFE mode kernel options (acpi, apic etc)\n"); } return -ETIMEDOUT; } if ((blink = aac_adapter_check_health(dev)) > 0) { if (wait == -1) { printk(KERN_ERR "aacraid: aac_fib_send: adapter blinkLED 0x%x.\n" "Usually a result of a serious unrecoverable hardware problem\n", blink); } return -EFAULT; } udelay(5); } } else (void)down_interruptible(&fibptr->event_wait); spin_lock_irqsave(&fibptr->event_lock, flags); if (fibptr->done == 0) { fibptr->done = 2; /* Tell interrupt we aborted */ spin_unlock_irqrestore(&fibptr->event_lock, flags); return -EINTR; } spin_unlock_irqrestore(&fibptr->event_lock, flags); BUG_ON(fibptr->done == 0); if(unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) return -ETIMEDOUT; return 0; } /* * If the user does not want a response than return success otherwise * return pending */ if (reply) return -EINPROGRESS; else return 0;}/** * aac_consumer_get - get the top of the queue * @dev: Adapter * @q: Queue * @entry: Return entry * * Will return a pointer to the entry on the top of the queue requested that * we are a consumer of, and return the address of the queue entry. It does * not change the state of the queue. */int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry){ u32 index; int status; if (le32_to_cpu(*q->headers.producer) == le32_to_cpu(*q->headers.consumer)) { status = 0; } else { /* * The consumer index must be wrapped if we have reached * the end of the queue, else we just use the entry * pointed to by the header index */ if (le32_to_cpu(*q->headers.consumer) >= q->entries) index = 0; else index = le32_to_cpu(*q->headers.consumer); *entry = q->base + index; status = 1; } return(status);}/** * aac_consumer_free - free consumer entry * @dev: Adapter * @q: Queue * @qid: Queue ident * * Frees up the current top of the queue we are a consumer of. If the * queue was full notify the producer that the queue is no longer full. */void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid){ int wasfull = 0; u32 notify; if ((le32_to_cpu(*q->headers.producer)+1) == le32_to_cpu(*q->headers.consumer)) wasfull = 1; if (le32_to_cpu(*q->headers.consumer) >= q->entries) *q->headers.consumer = cpu_to_le32(1); else *q->headers.consumer = cpu_to_le32(le32_to_cpu(*q->headers.consumer)+1); if (wasfull) { switch (qid) { case HostNormCmdQueue: notify = HostNormCmdNotFull; break; case HostNormRespQueue: notify = HostNormRespNotFull; break; default: BUG(); return; } aac_adapter_notify(dev, notify); }} /** * aac_fib_adapter_complete - complete adapter issued fib * @fibptr: fib to complete * @size: size of fib * * Will do all necessary work to complete a FIB that was sent from * the adapter. */int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size){ struct hw_fib * hw_fib = fibptr->hw_fib_va; struct aac_dev * dev = fibptr->dev; struct aac_queue * q; unsigned long nointr = 0; unsigned long qflags; if (hw_fib->header.XferState == 0) { if (dev->comm_interface == AAC_COMM_MESSAGE) kfree (hw_fib); return 0; } /* * If we plan to do anything check the structure type first. */ if ( hw_fib->header.StructType != FIB_MAGIC ) { if (dev->comm_interface == AAC_COMM_MESSAGE) kfree (hw_fib); return -EINVAL; } /* * This block handles the case where the adapter had sent us a * command and we have finished processing the command. We * call completeFib when we are done processing the command * and want to send a response back to the adapter. This will * send the completed cdb to the adapter. */ if (hw_fib->header.XferState & cpu_to_le32(SentFromAdapter)) { if (dev->comm_interface == AAC_COMM_MESSAGE) { kfree (hw_fib); } else { u32 index; hw_fib->header.XferState |= cpu_to_le32(HostProcessed); if (size) { size += sizeof(struct aac_fibhdr); if (size > le16_to_cpu(hw_fib->header.SenderSize)) return -EMSGSIZE; hw_fib->header.Size = cpu_to_le16(size); } q = &dev->queues->queue[AdapNormRespQueue]; spin_lock_irqsave(q->lock, qflags); aac_queue_get(dev, &index, AdapNormRespQueue, hw_fib, 1, NULL, &nointr); *(q->headers.producer) = cpu_to_le32(index + 1); spin_unlock_irqrestore(q->lock, qflags); if (!(nointr & (int)aac_config.irq_mod)) aac_adapter_notify(dev, AdapNormRespQueue); } } else { printk(KERN_WARNING "aac_fib_adapter_complete: Unknown xferstate detected.\n"); BUG(); } return 0;}/** * aac_fib_complete - fib completion handler * @fib: FIB to complete * * Will do all necessary work to complete a FIB. */ int aac_fib_complete(struct fib *fibptr){ struct hw_fib * hw_fib = fibptr->hw_fib_va; /* * Check for a fib which has already been completed */ if (hw_fib->header.XferState == 0) return 0; /* * If we plan to do anything check the structure type first. */ if (hw_fib->header.StructType != FIB_MAGIC) return -EINVAL; /* * This block completes a cdb which orginated on the host and we * just need to deallocate the cdb or reinit it. At this point the * command is complete that we had sent to the adapter and this * cdb could be reused. */ if((hw_fib->header.XferState & cpu_to_le32(SentFromHost)) && (hw_fib->header.XferState & cpu_to_le32(AdapterProcessed))) { fib_dealloc(fibptr); } else if(hw_fib->header.XferState & cpu_to_le32(SentFromHost)) { /* * This handles the case when the host has aborted the I/O * to the adapter because the adapter is not responding */ fib_dealloc(fibptr); } else if(hw_fib->header.XferState & cpu_to_le32(HostOwned)) { fib_dealloc(fibptr); } else { BUG(); } return 0;}/** * aac_printf - handle printf from firmware * @dev: Adapter * @val: Message info * * Print a message passed to us by the controller firmware on the * Adaptec board */void aac_printf(struct aac_dev *dev, u32 val){ char *cp = dev->printfbuf; if (dev->printf_enabled) { int length = val & 0xffff; int level = (val >> 16) & 0xffff; /* * The size of the printfbuf is set in port.c * There is no variable or define for it */ if (length > 255) length = 255; if (cp[length] != 0) cp[length] = 0; if (level == LOG_AAC_HIGH_ERROR) printk(KERN_WARNING "%s:%s", dev->name, cp); else printk(KERN_INFO "%s:%s", dev->name, cp); } memset(cp, 0, 256);}/** * aac_handle_aif - Handle a message from the firmware * @dev: Which adapter this fib is from * @fibptr: Pointer to fibptr from adapter * * This routine handles a driver notify fib from the adapter and * dispatches it to the appropriate routine for handling. */#define AIF_SNIFF_TIMEOUT (30*HZ)static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr){ struct hw_fib * hw_fib = fibptr->hw_fib_va; struct aac_aifcmd * aifcmd = (struct aac_aifcmd *)hw_fib->data; u32 container; struct scsi_device *device; enum { NOTHING, DELETE, ADD, CHANGE } device_config_needed; /* Sniff for container changes */ if (!dev || !dev->fsa_dev) return; container = (u32)-1; /* * We have set this up to try and minimize the number of * re-configures that take place. As a result of this when * certain AIF's come in we will set a flag waiting for another * type of AIF before setting the re-config flag. */ switch (le32_to_cpu(aifcmd->command)) { case AifCmdDriverNotify: switch (le32_to_cpu(((u32 *)aifcmd->data)[0])) { /* * Morph or Expand complete */ case AifDenMorphComplete: case AifDenVolumeExtendComplete: container = le32_to_cpu(((u32 *)aifcmd->data)[1]); if (container >= dev->maximum_num_containers) break; /* * Find the scsi_device associated with the SCSI * address. Make sure we have the right array, and if * so set the flag to initiate a new re-config once we * see an AifEnConfigChange AIF come through. */ if ((dev != NULL) && (dev->scsi_host_ptr != NULL)) { device = scsi_device_lookup(dev->scsi_host_ptr, CONTAINER_TO_CHANNEL(container), CONTAINER_TO_ID(container), CONTAINER_TO_LUN(container)); if (device) { dev->fsa_dev[container].config_needed = CHANGE; dev->fsa_dev[container].config_waiting_on = AifEnConfigChange; dev->fsa_dev[container].config_waiting_stamp = jiffies; scsi_device_put(device); } } } /* * If we are waiting on something and this happens to be * that thing then set the re-configure flag. */ if (container != (u32)-1) { if (container >= dev->maximum_num_containers) break; if ((dev->fsa_dev[container].config_waiting_on == le32_to_cpu(*(u32 *)aifcmd->data)) && time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) dev->fsa_dev[container].config_waiting_on = 0; } else for (container = 0; container < dev->maximum_num_containers; ++container) { if ((dev->fsa_dev[container].config_waiting_on == le32_to_cpu(*(u32 *)aifcmd->data)) && time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) dev->fsa_dev[container].config_waiting_on = 0; } break; case AifCmdEventNotify:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?