📄 cpqarray.c
字号:
if (!got_from_pool) { pci_free_consistent(h->pci_dev, sizeof(cmdlist_t), c, c->busaddr); } else { i = c - h->cmd_pool; clear_bit(i&(BITS_PER_LONG-1), h->cmd_pool_bits+(i/BITS_PER_LONG)); h->nr_frees++; }}/*********************************************************************** name: sendcmd Send a command to an IDA using the memory mapped FIFO interface and wait for it to complete. This routine should only be called at init time.***********************************************************************/static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size, unsigned int blk, unsigned int blkcnt, unsigned int log_unit ){ cmdlist_t *c; int complete; unsigned long temp; unsigned long i; ctlr_info_t *info_p = hba[ctlr]; c = cmd_alloc(info_p, 1); if(!c) return IO_ERROR; c->ctlr = ctlr; c->hdr.unit = log_unit; c->hdr.prio = 0; c->hdr.size = sizeof(rblk_t) >> 2; c->size += sizeof(rblk_t); /* The request information. */ c->req.hdr.next = 0; c->req.hdr.rcode = 0; c->req.bp = 0; c->req.hdr.sg_cnt = 1; c->req.hdr.reserved = 0; if (size == 0) c->req.sg[0].size = 512; else c->req.sg[0].size = size; c->req.hdr.blk = blk; c->req.hdr.blk_cnt = blkcnt; c->req.hdr.cmd = (unsigned char) cmd; c->req.sg[0].addr = (__u32) pci_map_single(info_p->pci_dev, buff, c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL); /* * Disable interrupt */ info_p->access.set_intr_mask(info_p, 0); /* Make sure there is room in the command FIFO */ /* Actually it should be completely empty at this time. */ for (i = 200000; i > 0; i--) { temp = info_p->access.fifo_full(info_p); if (temp != 0) { break; } udelay(10);DBG( printk(KERN_WARNING "cpqarray ida%d: idaSendPciCmd FIFO full," " waiting!\n", ctlr);); } /* * Send the cmd */ info_p->access.submit_command(info_p, c); complete = pollcomplete(ctlr); pci_unmap_single(info_p->pci_dev, (dma_addr_t) c->req.sg[0].addr, c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL); if (complete != 1) { if (complete != c->busaddr) { printk( KERN_WARNING "cpqarray ida%d: idaSendPciCmd " "Invalid command list address returned! (%08lx)\n", ctlr, (unsigned long)complete); cmd_free(info_p, c, 1); return (IO_ERROR); } } else { printk( KERN_WARNING "cpqarray ida%d: idaSendPciCmd Timeout out, " "No command list address returned!\n", ctlr); cmd_free(info_p, c, 1); return (IO_ERROR); } if (c->req.hdr.rcode & 0x00FE) { if (!(c->req.hdr.rcode & BIG_PROBLEM)) { printk( KERN_WARNING "cpqarray ida%d: idaSendPciCmd, error: " "Controller failed at init time " "cmd: 0x%x, return code = 0x%x\n", ctlr, c->req.hdr.cmd, c->req.hdr.rcode); cmd_free(info_p, c, 1); return (IO_ERROR); } } cmd_free(info_p, c, 1); return (IO_OK);}/* * revalidate_allvol is for online array config utilities. After a * utility reconfigures the drives in the array, it can use this function * (through an ioctl) to make the driver zap any previous disk structs for * that controller and get new ones. * * Right now I'm using the getgeometry() function to do this, but this * function should probably be finer grained and allow you to revalidate one * particualar logical volume (instead of all of them on a particular * controller). */static int revalidate_allvol(ctlr_info_t *host){ int ctlr = host->ctlr; int i; unsigned long flags; spin_lock_irqsave(IDA_LOCK(ctlr), flags); if (host->usage_count > 1) { spin_unlock_irqrestore(IDA_LOCK(ctlr), flags); printk(KERN_WARNING "cpqarray: Device busy for volume" " revalidation (usage=%d)\n", host->usage_count); return -EBUSY; } host->usage_count++; spin_unlock_irqrestore(IDA_LOCK(ctlr), flags); /* * Set the partition and block size structures for all volumes * on this controller to zero. We will reread all of this data */ set_capacity(ida_gendisk[ctlr][0], 0); for (i = 1; i < NWD; i++) { struct gendisk *disk = ida_gendisk[ctlr][i]; if (disk->flags & GENHD_FL_UP) del_gendisk(disk); } memset(host->drv, 0, sizeof(drv_info_t)*NWD); /* * Tell the array controller not to give us any interrupts while * we check the new geometry. Then turn interrupts back on when * we're done. */ host->access.set_intr_mask(host, 0); getgeometry(ctlr); host->access.set_intr_mask(host, FIFO_NOT_EMPTY); for(i=0; i<NWD; i++) { struct gendisk *disk = ida_gendisk[ctlr][i]; drv_info_t *drv = &host->drv[i]; if (i && !drv->nr_blks) continue; blk_queue_hardsect_size(host->queue, drv->blk_size); set_capacity(disk, drv->nr_blks); disk->queue = host->queue; disk->private_data = drv; if (i) add_disk(disk); } host->usage_count--; return 0;}static int ida_revalidate(struct gendisk *disk){ drv_info_t *drv = disk->private_data; set_capacity(disk, drv->nr_blks); return 0;}/******************************************************************** name: pollcomplete Wait polling for a command to complete. The memory mapped FIFO is polled for the completion. Used only at init time, interrupts disabled. ********************************************************************/static int pollcomplete(int ctlr){ int done; 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 == 0) { udelay(10); /* a short fixed delay */ } else return (done); } /* Invalid address to tell caller we ran out of time */ return 1;}/***************************************************************** start_fwbk Starts controller firmwares background processing. Currently only the Integrated Raid controller needs this done. If the PCI mem address registers are written to after this, data corruption may occur*****************************************************************/static void start_fwbk(int ctlr){ id_ctlr_t *id_ctlr_buf; int ret_code; if( (hba[ctlr]->board_id != 0x40400E11) && (hba[ctlr]->board_id != 0x40480E11) ) /* Not a Integrated Raid, so there is nothing for us to do */ return; printk(KERN_DEBUG "cpqarray: Starting firmware's background" " processing\n"); /* Command does not return anything, but idasend command needs a buffer */ id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL); if(id_ctlr_buf==NULL) { printk(KERN_WARNING "cpqarray: Out of memory. " "Unable to start background processing.\n"); return; } ret_code = sendcmd(RESUME_BACKGROUND_ACTIVITY, ctlr, id_ctlr_buf, 0, 0, 0, 0); if(ret_code != IO_OK) printk(KERN_WARNING "cpqarray: Unable to start" " background processing\n"); kfree(id_ctlr_buf);}/***************************************************************** getgeometry Get ida logical volume geometry from the controller This is a large bit of code which once existed in two flavors, It is used only at init time.*****************************************************************/static void getgeometry(int ctlr){ id_log_drv_t *id_ldrive; id_ctlr_t *id_ctlr_buf; sense_log_drv_stat_t *id_lstatus_buf; config_t *sense_config_buf; unsigned int log_unit, log_index; int ret_code, size; drv_info_t *drv; ctlr_info_t *info_p = hba[ctlr]; int i; info_p->log_drv_map = 0; id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL); if(id_ldrive == NULL) { printk( KERN_ERR "cpqarray: out of memory.\n"); return; } id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL); if(id_ctlr_buf == NULL) { kfree(id_ldrive); printk( KERN_ERR "cpqarray: out of memory.\n"); return; } id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL); if(id_lstatus_buf == NULL) { kfree(id_ctlr_buf); kfree(id_ldrive); printk( KERN_ERR "cpqarray: out of memory.\n"); return; } sense_config_buf = (config_t *)kmalloc(sizeof(config_t), GFP_KERNEL); if(sense_config_buf == NULL) { kfree(id_lstatus_buf); kfree(id_ctlr_buf); kfree(id_ldrive); printk( KERN_ERR "cpqarray: out of memory.\n"); return; } memset(id_ldrive, 0, sizeof(id_log_drv_t)); memset(id_ctlr_buf, 0, sizeof(id_ctlr_t)); memset(id_lstatus_buf, 0, sizeof(sense_log_drv_stat_t)); memset(sense_config_buf, 0, sizeof(config_t)); info_p->phys_drives = 0; info_p->log_drv_map = 0; info_p->drv_assign_map = 0; info_p->drv_spare_map = 0; info_p->mp_failed_drv_map = 0; /* only initialized here */ /* Get controllers info for this logical drive */ ret_code = sendcmd(ID_CTLR, ctlr, id_ctlr_buf, 0, 0, 0, 0); if (ret_code == IO_ERROR) { /* * If can't get controller info, set the logical drive map to 0, * so the idastubopen will fail on all logical drives * on the controller. */ /* Free all the buffers and return */ printk(KERN_ERR "cpqarray: error sending ID controller\n"); kfree(sense_config_buf); kfree(id_lstatus_buf); kfree(id_ctlr_buf); kfree(id_ldrive); return; } info_p->log_drives = id_ctlr_buf->nr_drvs; for(i=0;i<4;i++) info_p->firm_rev[i] = id_ctlr_buf->firm_rev[i]; info_p->ctlr_sig = id_ctlr_buf->cfg_sig; printk(" (%s)\n", info_p->product_name); /* * Initialize logical drive map to zero */ log_index = 0; /* * Get drive geometry for all logical drives */ if (id_ctlr_buf->nr_drvs > 16) printk(KERN_WARNING "cpqarray ida%d: This driver supports " "16 logical drives per controller.\n. " " Additional drives will not be " "detected\n", ctlr); for (log_unit = 0; (log_index < id_ctlr_buf->nr_drvs) && (log_unit < NWD); log_unit++) { struct gendisk *disk = ida_gendisk[ctlr][log_unit]; size = sizeof(sense_log_drv_stat_t); /* Send "Identify logical drive status" cmd */ ret_code = sendcmd(SENSE_LOG_DRV_STAT, ctlr, id_lstatus_buf, size, 0, 0, log_unit); if (ret_code == IO_ERROR) { /* If can't get logical drive status, set the logical drive map to 0, so the idastubopen will fail for all logical drives on the controller. */ info_p->log_drv_map = 0; printk( KERN_WARNING "cpqarray ida%d: idaGetGeometry - Controller" " failed to report status of logical drive %d\n" "Access to this controller has been disabled\n", ctlr, log_unit); /* Free all the buffers and return */ kfree(sense_config_buf); kfree(id_lstatus_buf); kfree(id_ctlr_buf); kfree(id_ldrive); return; } /* Make sure the logical drive is configured */ if (id_lstatus_buf->status != LOG_NOT_CONF) { ret_code = sendcmd(ID_LOG_DRV, ctlr, id_ldrive, sizeof(id_log_drv_t), 0, 0, log_unit); /* If error, the bit for this logical drive won't be set and idastubopen will return error. */ if (ret_code != IO_ERROR) { drv = &info_p->drv[log_unit]; drv->blk_size = id_ldrive->blk_size; drv->nr_blks = id_ldrive->nr_blks; drv->cylinders = id_ldrive->drv.cyl; drv->heads = id_ldrive->drv.heads; drv->sectors = id_ldrive->drv.sect_per_track; info_p->log_drv_map |= (1 << log_unit); printk(KERN_INFO "cpqarray ida/c%dd%d: blksz=%d nr_blks=%d\n", ctlr, log_unit, drv->blk_size, drv->nr_blks); ret_code = sendcmd(SENSE_CONFIG, ctlr, sense_config_buf, sizeof(config_t), 0, 0, log_unit); if (ret_code == IO_ERROR) { info_p->log_drv_map = 0; /* Free all the buffers and return */ printk(KERN_ERR "cpqarray: error sending sense config\n"); kfree(sense_config_buf); kfree(id_lstatus_buf); kfree(id_ctlr_buf); kfree(id_ldrive); return; } sprintf(disk->devfs_name, "ida/c%dd%d", ctlr, log_unit); info_p->phys_drives = sense_config_buf->ctlr_phys_drv; info_p->drv_assign_map |= sense_config_buf->drv_asgn_map; info_p->drv_assign_map |= sense_config_buf->spare_asgn_map; info_p->drv_spare_map |= sense_config_buf->spare_asgn_map; } /* end of if no error on id_ldrive */ log_index = log_index + 1; } /* end of if logical drive configured */ } /* end of for log_unit */ kfree(sense_config_buf); kfree(id_ldrive); kfree(id_lstatus_buf); kfree(id_ctlr_buf); return;}static void __exit cpqarray_exit(void){ int i; pci_unregister_driver(&cpqarray_pci_driver); /* Double check that all controller entries have been removed */ for(i=0; i<MAX_CTLR; i++) { if (hba[i] != NULL) { printk(KERN_WARNING "cpqarray: Removing EISA " "controller %d\n", i); cpqarray_remove_one_eisa(i); } } devfs_remove("ida"); remove_proc_entry("cpqarray", proc_root_driver);}module_init(cpqarray_init)module_exit(cpqarray_exit)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -