📄 ibmvscsi.c
字号:
"ibmvscsi: partner initialization complete\n"); /* Now login */ send_srp_login(hostdata); break; default: printk(KERN_ERR "ibmvscsi: unknown crq message type\n"); } return; case 0xFF: /* Hypervisor telling us the connection is closed */ printk(KERN_INFO "ibmvscsi: Virtual adapter failed!\n"); atomic_set(&hostdata->request_limit, -1); purge_requests(hostdata); ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata); return; case 0x80: /* real payload */ break; default: printk(KERN_ERR "ibmvscsi: got an invalid message type 0x%02x\n", crq->valid); return; } /* The only kind of payload CRQs we should get are responses to * things we send. Make sure this response is to something we * actually sent */ if (!valid_event_struct(&hostdata->pool, evt_struct)) { printk(KERN_ERR "ibmvscsi: returned correlation_token 0x%p is invalid!\n", (void *)crq->IU_data_ptr); return; } if (atomic_read(&evt_struct->free)) { printk(KERN_ERR "ibmvscsi: received duplicate correlation_token 0x%p!\n", (void *)crq->IU_data_ptr); return; } if (crq->format == VIOSRP_SRP_FORMAT) atomic_add(evt_struct->xfer_iu->srp.rsp.request_limit_delta, &hostdata->request_limit); if (evt_struct->done) evt_struct->done(evt_struct); else printk(KERN_ERR "ibmvscsi: returned done() is NULL; not running it!\n"); /* * Lock the host_lock before messing with these structures, since we * are running in a task context */ spin_lock_irqsave(evt_struct->hostdata->host->host_lock, flags); list_del(&evt_struct->list); free_event_struct(&evt_struct->hostdata->pool, evt_struct); spin_unlock_irqrestore(evt_struct->hostdata->host->host_lock, flags);}/** * ibmvscsi_get_host_config: Send the command to the server to get host * configuration data. The data is opaque to us. */static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata, unsigned char *buffer, int length){ struct viosrp_host_config *host_config; struct srp_event_struct *evt_struct; int rc; evt_struct = get_event_struct(&hostdata->pool); if (!evt_struct) { printk(KERN_ERR "ibmvscsi: could't allocate event for HOST_CONFIG!\n"); return -1; } init_event_struct(evt_struct, sync_completion, VIOSRP_MAD_FORMAT, init_timeout * HZ); host_config = &evt_struct->iu.mad.host_config; /* Set up a lun reset SRP command */ memset(host_config, 0x00, sizeof(*host_config)); host_config->common.type = VIOSRP_HOST_CONFIG_TYPE; host_config->common.length = length; host_config->buffer = dma_map_single(hostdata->dev, buffer, length, DMA_BIDIRECTIONAL); if (dma_mapping_error(host_config->buffer)) { printk(KERN_ERR "ibmvscsi: dma_mapping error " "getting host config\n"); free_event_struct(&hostdata->pool, evt_struct); return -1; } init_completion(&evt_struct->comp); rc = ibmvscsi_send_srp_event(evt_struct, hostdata); if (rc == 0) { wait_for_completion(&evt_struct->comp); dma_unmap_single(hostdata->dev, host_config->buffer, length, DMA_BIDIRECTIONAL); } return rc;}/* ------------------------------------------------------------ * sysfs attributes */static ssize_t show_host_srp_version(struct class_device *class_dev, char *buf){ struct Scsi_Host *shost = class_to_shost(class_dev); struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)shost->hostdata; int len; len = snprintf(buf, PAGE_SIZE, "%s\n", hostdata->madapter_info.srp_version); return len;}static struct class_device_attribute ibmvscsi_host_srp_version = { .attr = { .name = "srp_version", .mode = S_IRUGO, }, .show = show_host_srp_version,};static ssize_t show_host_partition_name(struct class_device *class_dev, char *buf){ struct Scsi_Host *shost = class_to_shost(class_dev); struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)shost->hostdata; int len; len = snprintf(buf, PAGE_SIZE, "%s\n", hostdata->madapter_info.partition_name); return len;}static struct class_device_attribute ibmvscsi_host_partition_name = { .attr = { .name = "partition_name", .mode = S_IRUGO, }, .show = show_host_partition_name,};static ssize_t show_host_partition_number(struct class_device *class_dev, char *buf){ struct Scsi_Host *shost = class_to_shost(class_dev); struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)shost->hostdata; int len; len = snprintf(buf, PAGE_SIZE, "%d\n", hostdata->madapter_info.partition_number); return len;}static struct class_device_attribute ibmvscsi_host_partition_number = { .attr = { .name = "partition_number", .mode = S_IRUGO, }, .show = show_host_partition_number,};static ssize_t show_host_mad_version(struct class_device *class_dev, char *buf){ struct Scsi_Host *shost = class_to_shost(class_dev); struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)shost->hostdata; int len; len = snprintf(buf, PAGE_SIZE, "%d\n", hostdata->madapter_info.mad_version); return len;}static struct class_device_attribute ibmvscsi_host_mad_version = { .attr = { .name = "mad_version", .mode = S_IRUGO, }, .show = show_host_mad_version,};static ssize_t show_host_os_type(struct class_device *class_dev, char *buf){ struct Scsi_Host *shost = class_to_shost(class_dev); struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)shost->hostdata; int len; len = snprintf(buf, PAGE_SIZE, "%d\n", hostdata->madapter_info.os_type); return len;}static struct class_device_attribute ibmvscsi_host_os_type = { .attr = { .name = "os_type", .mode = S_IRUGO, }, .show = show_host_os_type,};static ssize_t show_host_config(struct class_device *class_dev, char *buf){ struct Scsi_Host *shost = class_to_shost(class_dev); struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)shost->hostdata; /* returns null-terminated host config data */ if (ibmvscsi_do_host_config(hostdata, buf, PAGE_SIZE) == 0) return strlen(buf); else return 0;}static struct class_device_attribute ibmvscsi_host_config = { .attr = { .name = "config", .mode = S_IRUGO, }, .show = show_host_config,};static struct class_device_attribute *ibmvscsi_attrs[] = { &ibmvscsi_host_srp_version, &ibmvscsi_host_partition_name, &ibmvscsi_host_partition_number, &ibmvscsi_host_mad_version, &ibmvscsi_host_os_type, &ibmvscsi_host_config, NULL};/* ------------------------------------------------------------ * SCSI driver registration */static struct scsi_host_template driver_template = { .module = THIS_MODULE, .name = "IBM POWER Virtual SCSI Adapter " IBMVSCSI_VERSION, .proc_name = "ibmvscsi", .queuecommand = ibmvscsi_queuecommand, .eh_abort_handler = ibmvscsi_eh_abort_handler, .eh_device_reset_handler = ibmvscsi_eh_device_reset_handler, .cmd_per_lun = 16, .can_queue = 1, /* Updated after SRP_LOGIN */ .this_id = -1, .sg_tablesize = SG_ALL, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = ibmvscsi_attrs,};/** * Called by bus code for each adapter */static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id){ struct ibmvscsi_host_data *hostdata; struct Scsi_Host *host; struct device *dev = &vdev->dev; unsigned long wait_switch = 0; vdev->dev.driver_data = NULL; host = scsi_host_alloc(&driver_template, sizeof(*hostdata)); if (!host) { printk(KERN_ERR "ibmvscsi: couldn't allocate host data\n"); goto scsi_host_alloc_failed; } hostdata = (struct ibmvscsi_host_data *)host->hostdata; memset(hostdata, 0x00, sizeof(*hostdata)); INIT_LIST_HEAD(&hostdata->sent); hostdata->host = host; hostdata->dev = dev; atomic_set(&hostdata->request_limit, -1); hostdata->host->max_sectors = 32 * 8; /* default max I/O 32 pages */ if (ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, max_requests) != 0) { printk(KERN_ERR "ibmvscsi: couldn't initialize crq\n"); goto init_crq_failed; } if (initialize_event_pool(&hostdata->pool, max_requests, hostdata) != 0) { printk(KERN_ERR "ibmvscsi: couldn't initialize event pool\n"); goto init_pool_failed; } host->max_lun = 8; host->max_id = max_id; host->max_channel = max_channel; if (scsi_add_host(hostdata->host, hostdata->dev)) goto add_host_failed; /* Try to send an initialization message. Note that this is allowed * to fail if the other end is not acive. In that case we don't * want to scan */ if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0) { /* * Wait around max init_timeout secs for the adapter to finish * initializing. When we are done initializing, we will have a * valid request_limit. We don't want Linux scanning before * we are ready. */ for (wait_switch = jiffies + (init_timeout * HZ); time_before(jiffies, wait_switch) && atomic_read(&hostdata->request_limit) < 2;) { msleep(10); } /* if we now have a valid request_limit, initiate a scan */ if (atomic_read(&hostdata->request_limit) > 0) scsi_scan_host(host); } vdev->dev.driver_data = hostdata; return 0; add_host_failed: release_event_pool(&hostdata->pool, hostdata); init_pool_failed: ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, max_requests); init_crq_failed: scsi_host_put(host); scsi_host_alloc_failed: return -1;}static int ibmvscsi_remove(struct vio_dev *vdev){ struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data; release_event_pool(&hostdata->pool, hostdata); ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, max_requests); scsi_remove_host(hostdata->host); scsi_host_put(hostdata->host); return 0;}/** * ibmvscsi_device_table: Used by vio.c to match devices in the device tree we * support. */static struct vio_device_id ibmvscsi_device_table[] __devinitdata = { {"vscsi", "IBM,v-scsi"}, { "", "" }};MODULE_DEVICE_TABLE(vio, ibmvscsi_device_table);static struct vio_driver ibmvscsi_driver = { .id_table = ibmvscsi_device_table, .probe = ibmvscsi_probe, .remove = ibmvscsi_remove, .driver = { .name = "ibmvscsi", .owner = THIS_MODULE, }};int __init ibmvscsi_module_init(void){ return vio_register_driver(&ibmvscsi_driver);}void __exit ibmvscsi_module_exit(void){ vio_unregister_driver(&ibmvscsi_driver);}module_init(ibmvscsi_module_init);module_exit(ibmvscsi_module_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -