📄 cciss.c
字号:
#endif /* CCISS_DEBUG */ if (complete != 1) { if ( (complete & CISS_ERROR_BIT) && (complete & ~CISS_ERROR_BIT) == c->busaddr) { /* if data overrun or underun on Report command ignore it */ if (((c->Request.CDB[0] == CISS_REPORT_LOG) || (c->Request.CDB[0] == CISS_INQUIRY)) && ((c->err_info->CommandStatus == CMD_DATA_OVERRUN) || (c->err_info->CommandStatus == CMD_DATA_UNDERRUN) )) { complete = c->busaddr; } else { printk(KERN_WARNING "ciss ciss%d: sendcmd" " Error %x \n", ctlr, c->err_info->CommandStatus); printk(KERN_WARNING "ciss ciss%d: sendcmd" " offensive info\n" " size %x\n num %x value %x\n", ctlr, c->err_info->MoreErrInfo.Invalid_Cmd.offense_size, c->err_info->MoreErrInfo.Invalid_Cmd.offense_num, c->err_info->MoreErrInfo.Invalid_Cmd.offense_value); cmd_free(info_p,c); return(IO_ERROR); } } if (complete != c->busaddr) { printk( KERN_WARNING "cciss cciss%d: SendCmd " "Invalid command list address returned! (%lx)\n", ctlr, complete); cmd_free(info_p, c); return (IO_ERROR); } } else { printk( KERN_WARNING "cciss cciss%d: SendCmd Timeout out, " "No command list address returned!\n", ctlr); cmd_free(info_p, c); return (IO_ERROR); } cmd_free(info_p, c); return (IO_OK);} /* * Map (physical) PCI mem into (virtual) kernel space */static ulong remap_pci_mem(ulong base, ulong size){ ulong page_base = ((ulong) base) & PAGE_MASK; ulong page_offs = ((ulong) base) - page_base; ulong page_remapped = (ulong) ioremap(page_base, page_offs+size); return (ulong) (page_remapped ? (page_remapped + page_offs) : 0UL);}/* * Enqueuing and dequeuing functions for cmdlists. */static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c){ if (*Qptr == NULL) { *Qptr = c; c->next = c->prev = c; } else { c->prev = (*Qptr)->prev; c->next = (*Qptr); (*Qptr)->prev->next = c; (*Qptr)->prev = c; }}static inline CommandList_struct *removeQ(CommandList_struct **Qptr, CommandList_struct *c){ if (c && c->next != c) { if (*Qptr == c) *Qptr = c->next; c->prev->next = c->next; c->next->prev = c->prev; } else { *Qptr = NULL; } return c;}/* * Takes jobs of the Q and sends them to the hardware, then puts it on * the Q to wait for completion. */ static void start_io( ctlr_info_t *h){ CommandList_struct *c; while(( c = h->reqQ) != NULL ) { /* can't do anything if fifo is full */ if ((h->access.fifo_full(h))) { printk(KERN_WARNING "cciss: fifo full \n"); return; } /* Get the frist entry from the Request Q */ removeQ(&(h->reqQ), c); h->Qdepth--; /* Tell the controller execute command */ h->access.submit_command(h, c); /* Put job onto the completed Q */ addQ (&(h->cmpQ), c); }}static inline void complete_buffers( struct buffer_head *bh, int status){ struct buffer_head *xbh; while(bh) { xbh = bh->b_reqnext; bh->b_reqnext = NULL; bh->b_end_io(bh, status); bh = xbh; }} /* checks the status of the job and calls complete buffers to mark all * buffers for the completed job. */ static inline void complete_command( CommandList_struct *cmd, int timeout){ int status = 1; if (timeout) status = 0; if(cmd->err_info->CommandStatus != 0) { /* an error has occured */ switch(cmd->err_info->CommandStatus) { case CMD_TARGET_STATUS: printk(KERN_WARNING "cciss: cmd %p has " " completed with errors\n", cmd); if( cmd->err_info->ScsiStatus) { printk(KERN_WARNING "cciss: cmd %p " "has SCSI Status = %x\n", cmd, cmd->err_info->ScsiStatus); } break; case CMD_DATA_UNDERRUN: printk(KERN_WARNING "cciss: cmd %p has" " completed with data underrun " "reported\n", cmd); break; case CMD_DATA_OVERRUN: printk(KERN_WARNING "cciss: cmd %p has" " completed with data overrun " "reported\n", cmd); break; case CMD_INVALID: printk(KERN_WARNING "cciss: cmd %p is " "reported invalid\n", cmd); status = 0; break; case CMD_PROTOCOL_ERR: printk(KERN_WARNING "cciss: cmd %p has " "protocol error \n", cmd); status = 0; break; case CMD_HARDWARE_ERR: printk(KERN_WARNING "cciss: cmd %p had " " hardware error\n", cmd); status = 0; break; case CMD_CONNECTION_LOST: printk(KERN_WARNING "cciss: cmd %p had " "connection lost\n", cmd); status=0; break; case CMD_ABORTED: printk(KERN_WARNING "cciss: cmd %p was " "aborted\n", cmd); status=0; break; case CMD_ABORT_FAILED: printk(KERN_WARNING "cciss: cmd %p reports " "abort failed\n", cmd); status=0; break; case CMD_UNSOLICITED_ABORT: printk(KERN_WARNING "cciss: cmd %p aborted " "do to an unsolicited abort\n", cmd); status=0; break; case CMD_TIMEOUT: printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd); status=0; break; default: printk(KERN_WARNING "cciss: cmd %p returned " "unknown status %x\n", cmd, cmd->err_info->CommandStatus); status=0; } } complete_buffers(cmd->bh, status);}/* * Get a request and submit it to the controller. * Currently we do one request at a time. Ideally we would like to send * everything to the controller on the first call, but there is a danger * of holding the io_request_lock for to long. */static void do_cciss_request(int ctlr){ ctlr_info_t *h= hba[ctlr]; CommandList_struct *c; int log_unit, start_blk, seg, sect; char *lastdataend; struct buffer_head *bh; struct list_head *queue_head; struct request *creq; u64bit temp64; queue_head = &blk_dev[MAJOR_NR+ctlr].request_queue.queue_head; if (list_empty(queue_head)) { /* nothing to do... */ start_io(h); return; } creq = blkdev_entry_next_request(queue_head); if ((creq == NULL) || (creq->rq_status == RQ_INACTIVE)) { /* nothing to do... restart processing and return */ start_io(h); return; } if ((ctlr != (MAJOR(creq->rq_dev)-MAJOR_NR)) || (ctlr > nr_ctlr) || (h == NULL)) {#ifdef CCISS_DEBUG printk(KERN_WARNING "cciss: doreq cmd of %d, %x at %p\n", ctlr, creq->rq_dev, creq);#endif /* CCISS_DEBUG */ complete_buffers(creq->bh, 0); start_io(h); return; } if (( c = cmd_alloc(h)) == NULL) { start_io(h); return; } c->cmd_type = CMD_RWREQ; bh = c->bh = creq->bh; /* fill in the request */ log_unit = MINOR(creq->rq_dev) >> NWD_SHIFT; c->Header.ReplyQueue = 0; // unused in simple mode c->Header.Tag.lower = c->busaddr; // use the physical address the cmd block for tag c->Header.LUN.LogDev.VolId= hba[ctlr]->drv[log_unit].LunID; c->Header.LUN.LogDev.Mode = 1; c->Request.CDBLen = 10; // 12 byte commands not in FW yet; c->Request.Type.Type = TYPE_CMD; // It is a command. c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = (creq->cmd == READ) ? XFER_READ: XFER_WRITE; c->Request.Timeout = 0; // Don't time out c->Request.CDB[0] = (creq->cmd == READ) ? CCISS_READ : CCISS_WRITE; start_blk = hba[ctlr]->hd[MINOR(creq->rq_dev)].start_sect + creq->sector; if (bh == NULL) panic("cciss: bh== NULL?");#ifdef CCISS_DEBUG printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n",(int) creq->sector, (int) creq->nr_sectors); #endif /* CCISS_DEBUG */ seg = 0; lastdataend = NULL; sect = 0; while(bh) { sect += bh->b_size/512; if (bh->b_size % 512) { printk(KERN_CRIT "cciss: Oh Man. %d+%d, size=%d\n", (int) creq->sector, sect, (int) bh->b_size); panic("b_size 512 != 0\n"); } if (bh->b_data == lastdataend) { // tack it on to the last segment c->SG[seg-1].Len +=bh->b_size; lastdataend += bh->b_size; } else { c->SG[seg].Len = bh->b_size; temp64.val = (__u64) virt_to_bus(bh->b_data); c->SG[seg].Addr.lower = temp64.val32.lower; c->SG[seg].Addr.upper = temp64.val32.upper; c->SG[0].Ext = 0; // we are not chaining lastdataend = bh->b_data + bh->b_size; if( ++seg == MAXSGENTRIES) { break; } } bh = bh->b_reqnext; } /* track how many SG entries we are using */ if( seg > h->maxSG) h->maxSG = seg; /* adjusting the remaining request, if any */ creq-> sector+= sect; creq->nr_sectors -= sect; #ifdef CCISS_DEBUG printk(KERN_DEBUG "cciss: Submitting %d sectors in %d segments\n", sect, seg);#endif /* CCISS_DEBUG */ c->Header.SGList = c->Header.SGTotal = seg; c->Request.CDB[1]= 0; c->Request.CDB[2]= (start_blk >> 24) & 0xff; //MSB c->Request.CDB[3]= (start_blk >> 16) & 0xff; c->Request.CDB[4]= (start_blk >> 8) & 0xff; c->Request.CDB[5]= start_blk & 0xff; c->Request.CDB[6]= 0; // (sect >> 24) & 0xff; MSB // c->Request.CDB[7]= (sect >> 16) & 0xff; c->Request.CDB[7]= (sect >> 8) & 0xff; c->Request.CDB[8]= sect & 0xff; c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0; /* check to see if we going to complete the entire request */ /* if so, mark this request as Done and ready the next one */ if (creq->nr_sectors) {#ifdef CCISS_DEBUG printk(KERN_DEBUG "cciss: More to do on the same request %p %ld\n", creq, creq->nr_sectors);#endif /* CCISS_DEBUG */ creq->bh = bh->b_reqnext; bh->b_reqnext = NULL; } else {#ifdef CCISS_DEBUG printk("cciss: Done with %p, queueing %p\n", creq);#endif /* CCISS_DEBUG */ blkdev_dequeue_request(creq); end_that_request_last(creq); } addQ(&(h->reqQ),c); h->Qdepth++; if(h->Qdepth > h->maxQsinceinit) h->maxQsinceinit = h->Qdepth; start_io(h);}static void do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs){ ctlr_info_t *h = dev_id; CommandList_struct *c; unsigned long flags; __u32 a, a1; /* Is this interrupt for us? */ if ( h->access.intr_pending(h) == 0) return; /* * If there are completed commands in the completion queue, * we had better do something about it. */ spin_lock_irqsave(&io_request_lock, flags); while( h->access.intr_pending(h)) { while((a = h->access.command_completed(h)) != FIFO_EMPTY) { a1 = a; a &= ~3; if ((c = h->cmpQ) == NULL) { printk(KERN_WARNING "cpqarray: Completion of %08lx ignored\n", (unsigned long)a1); continue; } while(c->busaddr != a) { c = c->next; if (c == h->cmpQ) break; } /* * If we've found the command, take it off the * completion Q and free it */ if (c->busaddr == a) { removeQ(&h->cmpQ, c); if (c->cmd_type == CMD_RWREQ) { complete_command(c, 0); cmd_free(h, c); } else if (c->cmd_type == CMD_IOCTL_PEND) { c->cmd_type = CMD_IOCTL_DONE; } continue; } } } /* * See if we can queue up some more IO */ do_cciss_request(h->ctlr); spin_unlock_irqrestore(&io_request_lock, flags);}/* * We cannot read the structure directly, for portablity we must use * the io functions. * This is for debug only. */#ifdef CCISS_DEBUGstatic void print_cfg_table( CfgTable_struct *tb){ int i; char temp_name[17]; printk("Controller Configuration information\n"); printk("------------------------------------\n"); for(i=0;i<4;i++) temp_name[i] = readb(&(tb->Signature[i])); temp_name[4]='\0'; printk(" Signature = %s\n", temp_name); printk(" Spec Number = %d\n", readl(&(tb->SpecValence))); printk(" Transport methods supported = 0x%x\n", readl(&(tb-> TransportSupport))); printk(" Transport methods active = 0x%x\n", readl(&(tb->TransportActive))); printk(" Requested transport Method = 0x%x\n", readl(&(tb->HostWrite.TransportRequest))); printk(" Coalese Interrupt Delay = 0x%x\n", readl(&(tb->HostWrite.CoalIntDelay))); printk(" Coalese Interrupt Count = 0x%x\n", readl(&(tb->HostWrite.CoalIntCount))); printk(" Max outstanding commands = 0x%d\n", readl(&(tb->CmdsOutMax))); printk(" Bus Types = 0x%x\n", readl(&(tb-> BusTypes))); for(i=0;i<16;i++) temp_name[i] = readb(&(tb->ServerName[i])); temp_name[16] = '\0'; printk(" Server Name = %s\n", temp_name); printk(" Heartbeat Counter = 0x%x\n\n\n", readl(&(tb->HeartBeat)));}#endif /* CCISS_DEBUG */static int cciss_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn){ ushort vendor_id, device_id, command; unchar cache_line_size, latency_timer; unchar irq, revision; uint addr[6]; __u32 board_id; struct pci_dev *pdev; int i; pdev = pci_find_slot(bus, device_fn); vendor_id = pdev->vendor; device_id = pdev->device; irq = pdev->irq; for(i=0; i<6; i++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -