📄 cciss.c
字号:
} printk(KERN_INFO " blocks= %u block_size= %d\n", *total_size, *block_size); return;}static int cciss_revalidate(struct gendisk *disk){ ctlr_info_t *h = get_host(disk); drive_info_struct *drv = get_drv(disk); int logvol; int FOUND=0; unsigned int block_size; unsigned int total_size; ReadCapdata_struct *size_buff = NULL; InquiryData_struct *inq_buff = NULL; for(logvol=0; logvol < CISS_MAX_LUN; logvol++) { if(h->drv[logvol].LunID == drv->LunID) { FOUND=1; break; } } if (!FOUND) return 1; size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL); if (size_buff == NULL) { printk(KERN_WARNING "cciss: out of memory\n"); return 1; } inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL); if (inq_buff == NULL) { printk(KERN_WARNING "cciss: out of memory\n"); kfree(size_buff); return 1; } cciss_read_capacity(h->ctlr, logvol, size_buff, 1, &total_size, &block_size); cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size, inq_buff, drv); blk_queue_hardsect_size(drv->queue, drv->block_size); set_capacity(disk, drv->nr_blocks); kfree(size_buff); kfree(inq_buff); return 0;}/* * Wait polling for a command to complete. * The memory mapped FIFO is polled for the completion. * Used only at init time, interrupts from the HBA are disabled. */static unsigned long pollcomplete(int ctlr){ unsigned long done; int i; /* Wait (up to 20 seconds) for a command to complete */ for (i = 20 * HZ; i > 0; i--) { done = hba[ctlr]->access.command_completed(hba[ctlr]); if (done == FIFO_EMPTY) schedule_timeout_uninterruptible(1); 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, /* 0: address the controller, 1: address logical volume log_unit, 2: periph device address is scsi3addr */ unsigned int log_unit, __u8 page_code, unsigned char *scsi3addr, int cmd_type){ CommandList_struct *c; int i; unsigned long complete; ctlr_info_t *info_p= hba[ctlr]; u64bit buff_dma_handle; int status; if ((c = cmd_alloc(info_p, 1)) == NULL) { printk(KERN_WARNING "cciss: unable to get memory"); return(IO_ERROR); } status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num, log_unit, page_code, scsi3addr, cmd_type); if (status != IO_OK) { cmd_free(info_p, c, 1); return status; }resend_cmd1: /* * 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 */ 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_REPORT_PHYS) || (c->Request.CDB[0] == CISS_INQUIRY)) && ((c->err_info->CommandStatus == CMD_DATA_OVERRUN) || (c->err_info->CommandStatus == CMD_DATA_UNDERRUN) )) { complete = c->busaddr; } else { if (c->err_info->CommandStatus == CMD_UNSOLICITED_ABORT) { printk(KERN_WARNING "cciss%d: " "unsolicited abort %p\n", ctlr, c); if (c->retry_count < MAX_CMD_RETRIES) { printk(KERN_WARNING "cciss%d: retrying %p\n", ctlr, c); c->retry_count++; /* erase the old error */ /* information */ memset(c->err_info, 0, sizeof(ErrorInfo_struct)); goto resend_cmd1; } else { printk(KERN_WARNING "cciss%d: retried %p too " "many times\n", ctlr, c); status = IO_ERROR; goto cleanup1; } } 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); status = IO_ERROR; goto cleanup1; } } if (complete != c->busaddr) { printk( KERN_WARNING "cciss cciss%d: SendCmd " "Invalid command list address returned! (%lx)\n", ctlr, complete); status = IO_ERROR; goto cleanup1; } } else { printk( KERN_WARNING "cciss cciss%d: SendCmd Timeout out, " "No command list address returned!\n", ctlr); status = IO_ERROR; } cleanup1: /* unlock the data buffer from DMA */ buff_dma_handle.val32.lower = c->SG[0].Addr.lower; buff_dma_handle.val32.upper = c->SG[0].Addr.upper; pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val, c->SG[0].Len, PCI_DMA_BIDIRECTIONAL); cmd_free(info_p, c, 1); return (status);} /* * Map (physical) PCI mem into (virtual) kernel space */static void __iomem *remap_pci_mem(ulong base, ulong size){ ulong page_base = ((ulong) base) & PAGE_MASK; ulong page_offs = ((ulong) base) - page_base; void __iomem *page_remapped = ioremap(page_base, page_offs+size); return page_remapped ? (page_remapped + page_offs) : NULL;}/* * 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"); break; } /* 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 bio *bio, int status){ while (bio) { struct bio *xbh = bio->bi_next; int nr_sectors = bio_sectors(bio); bio->bi_next = NULL; blk_finished_io(len); bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO); bio = xbh; }} /* Assumes that CCISS_LOCK(h->ctlr) is held. *//* Zeros out the error record and then resends the command back *//* to the controller */static inline void resend_cciss_cmd( ctlr_info_t *h, CommandList_struct *c){ /* erase the old error information */ memset(c->err_info, 0, sizeof(ErrorInfo_struct)); /* add it to software queue and then send it to the controller */ addQ(&(h->reqQ),c); h->Qdepth++; if(h->Qdepth > h->maxQsinceinit) h->maxQsinceinit = h->Qdepth; start_io(h);}/* checks the status of the job and calls complete buffers to mark all * buffers for the completed job. */ static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd, int timeout){ int status = 1; int i; int retry_cmd = 0; u64bit temp64; if (timeout) status = 0; if(cmd->err_info->CommandStatus != 0) { /* an error has occurred */ switch(cmd->err_info->CommandStatus) { unsigned char sense_key; case CMD_TARGET_STATUS: status = 0; if( cmd->err_info->ScsiStatus == 0x02) { printk(KERN_WARNING "cciss: cmd %p " "has CHECK CONDITION " " byte 2 = 0x%x\n", cmd, cmd->err_info->SenseInfo[2] ); /* check the sense key */ sense_key = 0xf & cmd->err_info->SenseInfo[2]; /* no status or recovered error */ if((sense_key == 0x0) || (sense_key == 0x1)) { status = 1; } } else { printk(KERN_WARNING "cciss: cmd %p " "has SCSI Status 0x%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%d: unsolicited " "abort %p\n", h->ctlr, cmd); if (cmd->retry_count < MAX_CMD_RETRIES) { retry_cmd=1; printk(KERN_WARNING "cciss%d: retrying %p\n", h->ctlr, cmd); cmd->retry_count++; } else printk(KERN_WARNING "cciss%d: %p retried too " "many times\n", h->ctlr, 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; } } /* We need to return this command */ if(retry_cmd) { resend_cciss_cmd(h,cmd); return; } /* command did not need to be retried */ /* 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_page(hba[cmd->ctlr]->pdev, temp64.val, cmd->SG[i].Len, (cmd->Request.Type.Direction == XFER_READ) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); } complete_buffers(cmd->rq->bio, status);#ifdef CCISS_DEBUG printk("Done with %p\n", cmd->rq);#endif /* CCISS_DEBUG */ end_that_request_last(cmd->rq); cmd_free(h,cmd,1);}/* * Get a request and submit it to the controller. */static void do_cciss_request(request_queue_t *q){ ctlr_info_t *h= q->queuedata; CommandList_struct *c; int start_blk, seg; struct request *creq; u64bit temp64; struct scatterlist tmp_sg[MAXSGENTRIES]; drive_info_struct *drv; int i, dir; /* We call start_io here in case there is a command waiting on the * queue that has not been sent. */ if (blk_queue_plugged(q)) goto startio;queue: creq = elv_next_requ
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -