📄 cciss.c
字号:
int i; /* Wait (up to 2 seconds) for a command to complete */ for (i = 200000; i > 0; i--) { done = hba[ctlr]->access.command_completed(hba[ctlr]); if (done == FIFO_EMPTY) { udelay(10); /* a short fixed delay */ } else return (done); } /* Invalid address to tell caller we ran out of time */ return 1;}/* * Send a command to the controller, and wait for it to complete. * Only used at init time. */static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num, unsigned int log_unit, __u8 page_code ){ CommandList_struct *c; int i; unsigned long complete; ctlr_info_t *info_p= hba[ctlr]; u64bit buff_dma_handle; c = cmd_alloc(info_p, 1); if (c == NULL) { printk(KERN_WARNING "cciss: unable to get memory"); return(IO_ERROR); } // Fill in Command Header c->Header.ReplyQueue = 0; // unused in simple mode if( buff != NULL) // buffer to fill { c->Header.SGList = 1; c->Header.SGTotal= 1; } else // no buffers to fill { c->Header.SGList = 0; c->Header.SGTotal= 0; } c->Header.Tag.lower = c->busaddr; // use the kernel address the cmd block for tag // Fill in Request block switch(cmd) { case CISS_INQUIRY: /* If the logical unit number is 0 then, this is going to controller so It's a physical command mode = 0 target = 0. So we have nothing to write. Otherwise mode = 1 target = LUNID */ if(use_unit_num != 0) { c->Header.LUN.LogDev.VolId= hba[ctlr]->drv[log_unit].LunID; c->Header.LUN.LogDev.Mode = 1; } /* are we trying to read a vital product page */ if(page_code != 0) { c->Request.CDB[1] = 0x01; c->Request.CDB[2] = page_code; } c->Request.CDBLen = 6; c->Request.Type.Type = TYPE_CMD; // It is a command. c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = XFER_READ; // Read c->Request.Timeout = 0; // Don't time out c->Request.CDB[0] = CISS_INQUIRY; c->Request.CDB[4] = size & 0xFF; break; case CISS_REPORT_LOG: /* Talking to controller so It's a physical command mode = 00 target = 0. So we have nothing to write. */ c->Request.CDBLen = 12; c->Request.Type.Type = TYPE_CMD; // It is a command. c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = XFER_READ; // Read c->Request.Timeout = 0; // Don't time out c->Request.CDB[0] = CISS_REPORT_LOG; c->Request.CDB[6] = (size >> 24) & 0xFF; //MSB c->Request.CDB[7] = (size >> 16) & 0xFF; c->Request.CDB[8] = (size >> 8) & 0xFF; c->Request.CDB[9] = size & 0xFF; break; case CCISS_READ_CAPACITY: c->Header.LUN.LogDev.VolId= hba[ctlr]->drv[log_unit].LunID; c->Header.LUN.LogDev.Mode = 1; c->Request.CDBLen = 10; c->Request.Type.Type = TYPE_CMD; // It is a command. c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = XFER_READ; // Read c->Request.Timeout = 0; // Don't time out c->Request.CDB[0] = CCISS_READ_CAPACITY; break; default: printk(KERN_WARNING "cciss: Unknown Command 0x%c sent attempted\n", cmd); cmd_free(info_p, c, 1); return(IO_ERROR); }; // Fill in the scatter gather information if (size > 0 ) { buff_dma_handle.val = (__u64) pci_map_single( info_p->pdev, buff, size, PCI_DMA_BIDIRECTIONAL); c->SG[0].Addr.lower = buff_dma_handle.val32.lower; c->SG[0].Addr.upper = buff_dma_handle.val32.upper; c->SG[0].Len = size; c->SG[0].Ext = 0; // we are not chaining } /* * Disable interrupt */#ifdef CCISS_DEBUG printk(KERN_DEBUG "cciss: turning intr off\n");#endif /* CCISS_DEBUG */ info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF); /* Make sure there is room in the command FIFO */ /* Actually it should be completely empty at this time. */ for (i = 200000; i > 0; i--) { /* if fifo isn't full go */ if (!(info_p->access.fifo_full(info_p))) { break; } udelay(10); printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full," " waiting!\n", ctlr); } /* * Send the cmd */ info_p->access.submit_command(info_p, c); complete = pollcomplete(ctlr);#ifdef CCISS_DEBUG printk(KERN_DEBUG "cciss: command completed\n");#endif /* CCISS_DEBUG */ /* unlock the data buffer from DMA */ pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val, size, PCI_DMA_BIDIRECTIONAL); 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, 1); 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, 1); 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, 1); return (IO_ERROR); } cmd_free(info_p, c, 1); 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; blk_finished_io(bh->b_size >> 9); 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; int i; u64bit temp64; if (timeout) status = 0; /* unmap the DMA mapping for all the scatter gather elements */ for(i=0; i<cmd->Header.SGList; i++) { temp64.val32.lower = cmd->SG[i].Addr.lower; temp64.val32.upper = cmd->SG[i].Addr.upper; pci_unmap_single(hba[cmd->ctlr]->pdev, temp64.val, cmd->SG[i].Len, (cmd->Request.Type.Direction == XFER_READ) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); } if(cmd->err_info->CommandStatus != 0) { /* an error has occurred */ 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->rq->bh, status);#ifdef CCISS_DEBUG printk("Done with %p\n", cmd->rq);#endif /* CCISS_DEBUG */ end_that_request_last(cmd->rq);}static inline int cpq_new_segment(request_queue_t *q, struct request *rq, int max_segments){ if (rq->nr_segments < MAXSGENTRIES) { rq->nr_segments++; return 1; } return 0;}static int cpq_back_merge_fn(request_queue_t *q, struct request *rq, struct buffer_head *bh, int max_segments){ if (rq->bhtail->b_data + rq->bhtail->b_size == bh->b_data) return 1; return cpq_new_segment(q, rq, max_segments);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -