📄 cciss.c
字号:
static int cpq_front_merge_fn(request_queue_t *q, struct request *rq, struct buffer_head *bh, int max_segments){ if (bh->b_data + bh->b_size == rq->bh->b_data) return 1; return cpq_new_segment(q, rq, max_segments);}static int cpq_merge_requests_fn(request_queue_t *q, struct request *rq, struct request *nxt, int max_segments){ int total_segments = rq->nr_segments + nxt->nr_segments; if (rq->bhtail->b_data + rq->bhtail->b_size == nxt->bh->b_data) total_segments--; if (total_segments > MAXSGENTRIES) return 0; rq->nr_segments = total_segments; return 1;}/* * 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(request_queue_t *q){ ctlr_info_t *h= q->queuedata; CommandList_struct *c; int log_unit, start_blk, seg; char *lastdataend; struct buffer_head *bh; struct list_head *queue_head = &q->queue_head; struct request *creq; u64bit temp64; struct my_sg tmp_sg[MAXSGENTRIES]; int i; if (q->plugged) goto startio;queue_next: if (list_empty(queue_head)) goto startio; creq = blkdev_entry_next_request(queue_head); if (creq->nr_segments > MAXSGENTRIES) BUG(); if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR ) { printk(KERN_WARNING "doreq cmd for %d, %x at %p\n", h->ctlr, creq->rq_dev, creq); blkdev_dequeue_request(creq); complete_buffers(creq->bh, 0); end_that_request_last(creq); goto startio; } if (( c = cmd_alloc(h, 1)) == NULL) goto startio; blkdev_dequeue_request(creq); spin_unlock_irq(&io_request_lock); c->cmd_type = CMD_RWREQ; bh = creq->bh; c->rq = creq; /* 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[h->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[h->ctlr]->hd[MINOR(creq->rq_dev)].start_sect + creq->sector;#ifdef CCISS_DEBUG if (bh == NULL) panic("cciss: bh== NULL?"); printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n",(int) creq->sector, (int) creq->nr_sectors); #endif /* CCISS_DEBUG */ seg = 0; lastdataend = NULL; while(bh) { if (bh->b_data == lastdataend) { // tack it on to the last segment tmp_sg[seg-1].len +=bh->b_size; lastdataend += bh->b_size; } else { if (seg == MAXSGENTRIES) BUG(); tmp_sg[seg].len = bh->b_size; tmp_sg[seg].start_addr = bh->b_data; lastdataend = bh->b_data + bh->b_size; seg++; } bh = bh->b_reqnext; } /* get the DMA records for the setup */ for (i=0; i<seg; i++) { c->SG[i].Len = tmp_sg[i].len; temp64.val = (__u64) pci_map_single( h->pdev, tmp_sg[i].start_addr, tmp_sg[i].len, (c->Request.Type.Direction == XFER_READ) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); c->SG[i].Addr.lower = temp64.val32.lower; c->SG[i].Addr.upper = temp64.val32.upper; c->SG[i].Ext = 0; // we are not chaining } /* track how many SG entries we are using */ if( seg > h->maxSG) h->maxSG = seg; #ifdef CCISS_DEBUG printk(KERN_DEBUG "cciss: Submitting %d sectors in %d segments\n", creq->nr_sectors, 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]= (creq->nr_sectors >> 8) & 0xff; c->Request.CDB[8]= creq->nr_sectors & 0xff; c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0; spin_lock_irq(&io_request_lock); addQ(&(h->reqQ),c); h->Qdepth++; if(h->Qdepth > h->maxQsinceinit) h->maxQsinceinit = h->Qdepth; goto queue_next;startio: 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 "cciss: 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, 1); } 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(BLK_DEFAULT_QUEUE(MAJOR_NR + 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, struct pci_dev *pdev){ ushort vendor_id, device_id, command; unchar cache_line_size, latency_timer; unchar irq, revision; uint addr[6]; __u32 board_id; int cfg_offset; int cfg_base_addr; int cfg_base_addr_index; int i; vendor_id = pdev->vendor; device_id = pdev->device; irq = pdev->irq; for(i=0; i<6; i++) addr[i] = pdev->resource[i].start; if (pci_enable_device(pdev)) { printk(KERN_ERR "cciss: Unable to Enable PCI device\n"); return( -1); } if (pci_set_dma_mask(pdev, CCISS_DMA_MASK ) != 0) { printk(KERN_ERR "cciss: Unable to set DMA mask\n"); return(-1); } (void) pci_read_config_word(pdev, PCI_COMMAND,&command); (void) pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); (void) pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line_size); (void) pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_timer); (void) pci_read_config_dword(pdev, PCI_SUBSYSTEM_VENDOR_ID, &board_id);#ifdef CCISS_DEBUG printk("vendor_id = %x\n", vendor_id); printk("device_id = %x\n", device_id); printk("command = %x\n", command); for(i=0; i<6; i++) printk("addr[%d] = %x\n", i, addr[i]); printk("revision = %x\n", revision); printk("irq = %x\n", irq); printk("cache_line_size = %x\n", cache_line_size); printk("latency_timer = %x\n", latency_timer); printk("board_id = %x\n", board_id);#endif /* CCISS_DEBUG */ c->intr = irq; /* * Memory base addr is first addr , the second points to the config * table */ c->paddr = addr[0] & 0xfffffff0; /* remove the addressing mode bits */#ifdef CCISS_DEBUG printk("address 0 = %x\n", c->paddr);#endif /* CCISS_DEBUG */ c->vaddr = remap_pci_mem(c->paddr, 200); /* get the address index number */ cfg_base_addr = readl(c->vaddr + SA5_CTCFG_OFFSET); /* I am not prepared to deal with a 64 bit address value */ cfg_base_addr &= 0xffff;#ifdef CCISS_DEBUG printk("cfg base address = %x\n", cfg_base_addr);#endif /* CCISS_DEBUG */ cfg_base_addr_index = (cfg_base_addr - PCI_BASE_ADDRESS_0)/4;#ifdef CCISS_DEBUG printk("cfg base address index = %x\n", cfg_base_addr_index);#endif /* CCISS_DEBUG */ cfg_offset = readl(c->vaddr + SA5_CTMEM_OFFSET);#ifdef CCISS_DEBUG printk("cfg offset = %x\n", cfg_offset);#endif /* CCISS_DEBUG */ c->cfgtable = (CfgTable_struct *) remap_pci_mem((addr[cfg_base_addr_index] & 0xfffffff0) + cfg_offset, sizeof(CfgTable_struct)); c->board_id = board_id;#ifdef CCISS_DEBUG print_cfg_table(c->cfgtable); #endif /* CCISS_DEBUG */ for(i=0; i<NR_PRODUCTS; i++) { if (board_id == products[i].board_id) { c->product_name = products[i].product_name; c->access = *(products[i].access); break; } } if (i == NR_PRODUCTS) { printk(KERN_WARNING "cciss: Sorry, I don't know how" " to access the Smart Array controller %08lx\n", (unsigned long)board_id); return -1; } if ( (readb(&c->cfgtable->Signature[0]) != 'C') || (readb(&c->cfgtable->Signature[1]) != 'I') || (readb(&c->cfgtable->Signature[2]) != 'S') || (readb(&c->cfgtable->Signature[3]) != 'S') ) { printk("Does not appear to be a valid CISS config table\n"); return -1; }#ifdef CCISS_DEBUG printk("Trying to put board into Simple mode\n");#endif /* CCISS_DEBUG */ c->max_commands = readl(&(c->cfgtable->CmdsOutMax)); /* Update the field, and then ring the doorbell */ writel( CFGTBL_Trans_Simple, &(c->cfgtable->HostWrite.TransportRequest)); writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL); for(i=0;i<MAX_CONFIG_WAIT;i++) { if (!(readl(c->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq)) break; /* delay and try again */ udelay(1000); } #ifdef CCISS_DEBUG printk(KERN_DEBUG "I counter got to %d %x\n", i, readl(c->vaddr + SA5_DOORBELL));#endif /* CCISS_DEBUG */#ifdef CCISS_DEBUG print_cfg_table(c->cfgtable); #endif /* CCISS_DEBUG */ if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) { printk(KERN_WARNING "cciss: unable to get board into" " simple mode\n"); return -1; } return 0;}/* * Gets information about the local volumes attached to the controller. */ static void cciss_getgeometry(int cntl_num){ ReportLunData_struct *ld_buff; ReadCapdata_struct *size_buff; InquiryData_struct *inq_buff; int return_code; int i; int listlength = 0; int lunid = 0; int block_size; int total_size;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -