📄 cciss.c
字号:
} else{ /* reading number of logical volumes failed */ printk(KERN_WARNING "cciss: report logical volume" " command failed\n"); listlength = 0; goto freeret; } num_luns = listlength / 8; /* 8 bytes per entry */ if (num_luns > CISS_MAX_LUN){ num_luns = CISS_MAX_LUN; printk(KERN_WARNING "cciss: more luns configured" " on controller than can be handled by" " this driver.\n"); } /* Compare controller drive array to drivers drive array. * Check for updates in the drive information and any new drives * on the controller. */ for (i=0; i < num_luns; i++){ int j; drv_found = 0; lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24; lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16; lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8; lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]); /* Find if the LUN is already in the drive array * of the controller. If so then update its info * if not is use. If it does not exist then find * the first free index and add it. */ for (j=0; j <= h->highest_lun; j++){ if (h->drv[j].LunID == lunid){ drv_index = j; drv_found = 1; } } /* check if the drive was found already in the array */ if (!drv_found){ drv_index = cciss_find_free_drive_index(ctlr); if (drv_index == -1) goto freeret; } h->drv[drv_index].LunID = lunid; cciss_update_drive_info(ctlr, drv_index); } /* end for */ } /* end else */freeret: kfree(ld_buff); h->busy_configuring = 0; /* We return -1 here to tell the ACU that we have registered/updated * all of the drives that we can and to keep it from calling us * additional times. */ return -1;mem_msg: printk(KERN_ERR "cciss: out of memory\n"); goto freeret;}/* This function will deregister the disk and it's queue from the * kernel. It must be called with the controller lock held and the * drv structures busy_configuring flag set. It's parameters are: * * disk = This is the disk to be deregistered * drv = This is the drive_info_struct associated with the disk to be * deregistered. It contains information about the disk used * by the driver. * clear_all = This flag determines whether or not the disk information * is going to be completely cleared out and the highest_lun * reset. Sometimes we want to clear out information about * the disk in preperation for re-adding it. In this case * the highest_lun should be left unchanged and the LunID * should not be cleared.*/static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, int clear_all){ ctlr_info_t *h = get_host(disk); if (!capable(CAP_SYS_RAWIO)) return -EPERM; /* make sure logical volume is NOT is use */ if(clear_all || (h->gendisk[0] == disk)) { if (drv->usage_count > 1) return -EBUSY; } else if( drv->usage_count > 0 ) return -EBUSY; /* invalidate the devices and deregister the disk. If it is disk * zero do not deregister it but just zero out it's values. This * allows us to delete disk zero but keep the controller registered. */ if (h->gendisk[0] != disk){ if (disk->flags & GENHD_FL_UP){ blk_cleanup_queue(disk->queue); del_gendisk(disk); drv->queue = NULL; } } --h->num_luns; /* zero out the disk size info */ drv->nr_blocks = 0; drv->block_size = 0; drv->heads = 0; drv->sectors = 0; drv->cylinders = 0; drv->raid_level = -1; /* This can be used as a flag variable to * indicate that this element of the drive * array is free. */ if (clear_all){ /* check to see if it was the last disk */ if (drv == h->drv + h->highest_lun) { /* if so, find the new hightest lun */ int i, newhighest =-1; for(i=0; i<h->highest_lun; i++) { /* if the disk has size > 0, it is available */ if (h->drv[i].heads) newhighest = i; } h->highest_lun = newhighest; } drv->LunID = 0; } return(0);}static int fill_cmd(CommandList_struct *c, __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){ ctlr_info_t *h= hba[ctlr]; u64bit buff_dma_handle; int status = IO_OK; c->cmd_type = CMD_IOCTL_PEND; c->Header.ReplyQueue = 0; if( buff != NULL) { c->Header.SGList = 1; c->Header.SGTotal= 1; } else { c->Header.SGList = 0; c->Header.SGTotal= 0; } c->Header.Tag.lower = c->busaddr; c->Request.Type.Type = cmd_type; if (cmd_type == TYPE_CMD) { 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, if use_unit_num == 1, mode = 1(volume set addressing) target = LUNID otherwise, if use_unit_num == 2, mode = 0(periph dev addr) target = scsi3addr */ if (use_unit_num == 1) { c->Header.LUN.LogDev.VolId= h->drv[log_unit].LunID; c->Header.LUN.LogDev.Mode = 1; } else if (use_unit_num == 2) { memcpy(c->Header.LUN.LunAddrBytes,scsi3addr,8); c->Header.LUN.LogDev.Mode = 0; } /* 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.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = XFER_READ; c->Request.Timeout = 0; c->Request.CDB[0] = CISS_INQUIRY; c->Request.CDB[4] = size & 0xFF; break; case CISS_REPORT_LOG: case CISS_REPORT_PHYS: /* Talking to controller so It's a physical command mode = 00 target = 0. Nothing to write. */ c->Request.CDBLen = 12; c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = XFER_READ; c->Request.Timeout = 0; c->Request.CDB[0] = cmd; 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 = h->drv[log_unit].LunID; c->Header.LUN.LogDev.Mode = 1; c->Request.CDBLen = 10; c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = XFER_READ; c->Request.Timeout = 0; c->Request.CDB[0] = cmd; break; case CCISS_CACHE_FLUSH: c->Request.CDBLen = 12; c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = XFER_WRITE; c->Request.Timeout = 0; c->Request.CDB[0] = BMIC_WRITE; c->Request.CDB[6] = BMIC_CACHE_FLUSH; break; default: printk(KERN_WARNING "cciss%d: Unknown Command 0x%c\n", ctlr, cmd); return(IO_ERROR); } } else if (cmd_type == TYPE_MSG) { switch (cmd) { case 3: /* No-Op message */ c->Request.CDBLen = 1; c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = XFER_WRITE; c->Request.Timeout = 0; c->Request.CDB[0] = cmd; break; default: printk(KERN_WARNING "cciss%d: unknown message type %d\n", ctlr, cmd); return IO_ERROR; } } else { printk(KERN_WARNING "cciss%d: unknown command type %d\n", ctlr, cmd_type); return IO_ERROR; } /* Fill in the scatter gather information */ if (size > 0) { buff_dma_handle.val = (__u64) pci_map_single(h->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 */ } return status;}static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num, unsigned int log_unit, __u8 page_code, int cmd_type){ ctlr_info_t *h = hba[ctlr]; CommandList_struct *c; u64bit buff_dma_handle; unsigned long flags; int return_status; DECLARE_COMPLETION(wait); if ((c = cmd_alloc(h , 0)) == NULL) return -ENOMEM; return_status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num, log_unit, page_code, NULL, cmd_type); if (return_status != IO_OK) { cmd_free(h, c, 0); return return_status; }resend_cmd2: c->waiting = &wait; /* Put the request on the tail of the queue and send it */ spin_lock_irqsave(CCISS_LOCK(ctlr), flags); addQ(&h->reqQ, c); h->Qdepth++; start_io(h); spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); wait_for_completion(&wait); if(c->err_info->CommandStatus != 0) { /* an error has occurred */ switch(c->err_info->CommandStatus) { case CMD_TARGET_STATUS: printk(KERN_WARNING "cciss: cmd %p has " " completed with errors\n", c); if( c->err_info->ScsiStatus) { printk(KERN_WARNING "cciss: cmd %p " "has SCSI Status = %x\n", c, c->err_info->ScsiStatus); } break; case CMD_DATA_UNDERRUN: case CMD_DATA_OVERRUN: /* expected for inquire and report lun commands */ break; case CMD_INVALID: printk(KERN_WARNING "cciss: Cmd %p is " "reported invalid\n", c); return_status = IO_ERROR; break; case CMD_PROTOCOL_ERR: printk(KERN_WARNING "cciss: cmd %p has " "protocol error \n", c); return_status = IO_ERROR; break;case CMD_HARDWARE_ERR: printk(KERN_WARNING "cciss: cmd %p had " " hardware error\n", c); return_status = IO_ERROR; break; case CMD_CONNECTION_LOST: printk(KERN_WARNING "cciss: cmd %p had " "connection lost\n", c); return_status = IO_ERROR; break; case CMD_ABORTED: printk(KERN_WARNING "cciss: cmd %p was " "aborted\n", c); return_status = IO_ERROR; break; case CMD_ABORT_FAILED: printk(KERN_WARNING "cciss: cmd %p reports " "abort failed\n", c); return_status = IO_ERROR; break; case 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)); return_status = IO_OK; INIT_COMPLETION(wait); goto resend_cmd2; } return_status = IO_ERROR; break; default: printk(KERN_WARNING "cciss: cmd %p returned " "unknown status %x\n", c, c->err_info->CommandStatus); return_status = IO_ERROR; } } /* unlock the buffers 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( h->pdev, (dma_addr_t) buff_dma_handle.val, c->SG[0].Len, PCI_DMA_BIDIRECTIONAL); cmd_free(h, c, 0); return(return_status);}static void cciss_geometry_inquiry(int ctlr, int logvol, int withirq, unsigned int total_size, unsigned int block_size, InquiryData_struct *inq_buff, drive_info_struct *drv){ int return_code; memset(inq_buff, 0, sizeof(InquiryData_struct)); if (withirq) return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buff, sizeof(*inq_buff), 1, logvol ,0xC1, TYPE_CMD); else return_code = sendcmd(CISS_INQUIRY, ctlr, inq_buff, sizeof(*inq_buff), 1, logvol ,0xC1, NULL, TYPE_CMD); if (return_code == IO_OK) { if(inq_buff->data_byte[8] == 0xFF) { printk(KERN_WARNING "cciss: reading geometry failed, volume " "does not support reading geometry\n"); drv->block_size = block_size; drv->nr_blocks = total_size; drv->heads = 255; drv->sectors = 32; // Sectors per track drv->cylinders = total_size / 255 / 32; } else { unsigned int t; drv->block_size = block_size; drv->nr_blocks = total_size; drv->heads = inq_buff->data_byte[6]; drv->sectors = inq_buff->data_byte[7]; drv->cylinders = (inq_buff->data_byte[4] & 0xff) << 8; drv->cylinders += inq_buff->data_byte[5]; drv->raid_level = inq_buff->data_byte[8]; t = drv->heads * drv->sectors; if (t > 1) { drv->cylinders = total_size/t; } } } else { /* Get geometry failed */ printk(KERN_WARNING "cciss: reading geometry failed\n"); } printk(KERN_INFO " heads= %d, sectors= %d, cylinders= %d\n\n", drv->heads, drv->sectors, drv->cylinders);}static voidcciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf, int withirq, unsigned int *total_size, unsigned int *block_size){ int return_code; memset(buf, 0, sizeof(*buf)); if (withirq) return_code = sendcmd_withirq(CCISS_READ_CAPACITY, ctlr, buf, sizeof(*buf), 1, logvol, 0, TYPE_CMD); else return_code = sendcmd(CCISS_READ_CAPACITY, ctlr, buf, sizeof(*buf), 1, logvol, 0, NULL, TYPE_CMD); if (return_code == IO_OK) { *total_size = be32_to_cpu(*((__be32 *) &buf->total_size[0]))+1; *block_size = be32_to_cpu(*((__be32 *) &buf->block_size[0])); } else { /* read capacity command failed */ printk(KERN_WARNING "cciss: read capacity failed\n"); *total_size = 0; *block_size = BLOCK_SIZE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -