⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sx8.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	crq = carm_get_special(host);	if (!crq) {		rc = -ENOMEM;		goto err_out;	}	idx = crq->tag;	ioc = carm_ref_msg(host, idx);	msg_dma = carm_ref_msg_dma(host, idx);	msg_data = (u32) (msg_dma + sizeof(struct carm_array_info));	crq->msg_type = CARM_MSG_ARRAY;	crq->msg_subtype = CARM_ARRAY_INFO;	rc = carm_lookup_bucket(sizeof(struct carm_msg_ioctl) +				sizeof(struct carm_array_info));	BUG_ON(rc < 0);	crq->msg_bucket = (u32) rc;	memset(ioc, 0, sizeof(*ioc));	ioc->type	= CARM_MSG_ARRAY;	ioc->subtype	= CARM_ARRAY_INFO;	ioc->array_id	= (u8) array_idx;	ioc->handle	= cpu_to_le32(TAG_ENCODE(idx));	ioc->data_addr	= cpu_to_le32(msg_data);	spin_lock_irq(&host->lock);	assert(host->state == HST_DEV_SCAN_START ||	       host->state == HST_DEV_SCAN);	spin_unlock_irq(&host->lock);	DPRINTK("blk_insert_request, tag == %u\n", idx);	blk_insert_request(host->oob_q, crq->rq, 1, crq);	return 0;err_out:	spin_lock_irq(&host->lock);	host->state = HST_ERROR;	spin_unlock_irq(&host->lock);	return rc;}typedef unsigned int (*carm_sspc_t)(struct carm_host *, unsigned int, void *);static int carm_send_special (struct carm_host *host, carm_sspc_t func){	struct carm_request *crq;	struct carm_msg_ioctl *ioc;	void *mem;	unsigned int idx, msg_size;	int rc;	crq = carm_get_special(host);	if (!crq)		return -ENOMEM;	idx = crq->tag;	mem = carm_ref_msg(host, idx);	msg_size = func(host, idx, mem);	ioc = mem;	crq->msg_type = ioc->type;	crq->msg_subtype = ioc->subtype;	rc = carm_lookup_bucket(msg_size);	BUG_ON(rc < 0);	crq->msg_bucket = (u32) rc;	DPRINTK("blk_insert_request, tag == %u\n", idx);	blk_insert_request(host->oob_q, crq->rq, 1, crq);	return 0;}static unsigned int carm_fill_sync_time(struct carm_host *host,					unsigned int idx, void *mem){	struct timeval tv;	struct carm_msg_sync_time *st = mem;	do_gettimeofday(&tv);	memset(st, 0, sizeof(*st));	st->type	= CARM_MSG_MISC;	st->subtype	= MISC_SET_TIME;	st->handle	= cpu_to_le32(TAG_ENCODE(idx));	st->timestamp	= cpu_to_le32(tv.tv_sec);	return sizeof(struct carm_msg_sync_time);}static unsigned int carm_fill_alloc_buf(struct carm_host *host,					unsigned int idx, void *mem){	struct carm_msg_allocbuf *ab = mem;	memset(ab, 0, sizeof(*ab));	ab->type	= CARM_MSG_MISC;	ab->subtype	= MISC_ALLOC_MEM;	ab->handle	= cpu_to_le32(TAG_ENCODE(idx));	ab->n_sg	= 1;	ab->sg_type	= SGT_32BIT;	ab->addr	= cpu_to_le32(host->shm_dma + (PDC_SHM_SIZE >> 1));	ab->len		= cpu_to_le32(PDC_SHM_SIZE >> 1);	ab->evt_pool	= cpu_to_le32(host->shm_dma + (16 * 1024));	ab->n_evt	= cpu_to_le32(1024);	ab->rbuf_pool	= cpu_to_le32(host->shm_dma);	ab->n_rbuf	= cpu_to_le32(RMSG_Q_LEN);	ab->msg_pool	= cpu_to_le32(host->shm_dma + RBUF_LEN);	ab->n_msg	= cpu_to_le32(CARM_Q_LEN);	ab->sg[0].start	= cpu_to_le32(host->shm_dma + (PDC_SHM_SIZE >> 1));	ab->sg[0].len	= cpu_to_le32(65536);	return sizeof(struct carm_msg_allocbuf);}static unsigned int carm_fill_scan_channels(struct carm_host *host,					    unsigned int idx, void *mem){	struct carm_msg_ioctl *ioc = mem;	u32 msg_data = (u32) (carm_ref_msg_dma(host, idx) +			      IOC_SCAN_CHAN_OFFSET);	memset(ioc, 0, sizeof(*ioc));	ioc->type	= CARM_MSG_IOCTL;	ioc->subtype	= CARM_IOC_SCAN_CHAN;	ioc->handle	= cpu_to_le32(TAG_ENCODE(idx));	ioc->data_addr	= cpu_to_le32(msg_data);	/* fill output data area with "no device" default values */	mem += IOC_SCAN_CHAN_OFFSET;	memset(mem, IOC_SCAN_CHAN_NODEV, CARM_MAX_PORTS);	return IOC_SCAN_CHAN_OFFSET + CARM_MAX_PORTS;}static unsigned int carm_fill_get_fw_ver(struct carm_host *host,					 unsigned int idx, void *mem){	struct carm_msg_get_fw_ver *ioc = mem;	u32 msg_data = (u32) (carm_ref_msg_dma(host, idx) + sizeof(*ioc));	memset(ioc, 0, sizeof(*ioc));	ioc->type	= CARM_MSG_MISC;	ioc->subtype	= MISC_GET_FW_VER;	ioc->handle	= cpu_to_le32(TAG_ENCODE(idx));	ioc->data_addr	= cpu_to_le32(msg_data);	return sizeof(struct carm_msg_get_fw_ver) +	       sizeof(struct carm_fw_ver);}static inline void carm_end_request_queued(struct carm_host *host,					   struct carm_request *crq,					   int uptodate){	struct request *req = crq->rq;	int rc;	rc = end_that_request_first(req, uptodate, req->hard_nr_sectors);	assert(rc == 0);	end_that_request_last(req, uptodate);	rc = carm_put_request(host, crq);	assert(rc == 0);}static inline void carm_push_q (struct carm_host *host, struct request_queue *q){	unsigned int idx = host->wait_q_prod % CARM_MAX_WAIT_Q;	blk_stop_queue(q);	VPRINTK("STOPPED QUEUE %p\n", q);	host->wait_q[idx] = q;	host->wait_q_prod++;	BUG_ON(host->wait_q_prod == host->wait_q_cons); /* overrun */}static inline struct request_queue *carm_pop_q(struct carm_host *host){	unsigned int idx;	if (host->wait_q_prod == host->wait_q_cons)		return NULL;	idx = host->wait_q_cons % CARM_MAX_WAIT_Q;	host->wait_q_cons++;	return host->wait_q[idx];}static inline void carm_round_robin(struct carm_host *host){	struct request_queue *q = carm_pop_q(host);	if (q) {		blk_start_queue(q);		VPRINTK("STARTED QUEUE %p\n", q);	}}static inline void carm_end_rq(struct carm_host *host, struct carm_request *crq,			int is_ok){	carm_end_request_queued(host, crq, is_ok);	if (max_queue == 1)		carm_round_robin(host);	else if ((host->n_msgs <= CARM_MSG_LOW_WATER) &&		 (host->hw_sg_used <= CARM_SG_LOW_WATER)) {		carm_round_robin(host);	}}static void carm_oob_rq_fn(struct request_queue *q){	struct carm_host *host = q->queuedata;	struct carm_request *crq;	struct request *rq;	int rc;	while (1) {		DPRINTK("get req\n");		rq = elv_next_request(q);		if (!rq)			break;		blkdev_dequeue_request(rq);		crq = rq->special;		assert(crq != NULL);		assert(crq->rq == rq);		crq->n_elem = 0;		DPRINTK("send req\n");		rc = carm_send_msg(host, crq);		if (rc) {			blk_requeue_request(q, rq);			carm_push_q(host, q);			return;		/* call us again later, eventually */		}	}}static void carm_rq_fn(struct request_queue *q){	struct carm_port *port = q->queuedata;	struct carm_host *host = port->host;	struct carm_msg_rw *msg;	struct carm_request *crq;	struct request *rq;	struct scatterlist *sg;	int writing = 0, pci_dir, i, n_elem, rc;	u32 tmp;	unsigned int msg_size;queue_one_request:	VPRINTK("get req\n");	rq = elv_next_request(q);	if (!rq)		return;	crq = carm_get_request(host);	if (!crq) {		carm_push_q(host, q);		return;		/* call us again later, eventually */	}	crq->rq = rq;	blkdev_dequeue_request(rq);	if (rq_data_dir(rq) == WRITE) {		writing = 1;		pci_dir = PCI_DMA_TODEVICE;	} else {		pci_dir = PCI_DMA_FROMDEVICE;	}	/* get scatterlist from block layer */	sg = &crq->sg[0];	n_elem = blk_rq_map_sg(q, rq, sg);	if (n_elem <= 0) {		carm_end_rq(host, crq, 0);		return;		/* request with no s/g entries? */	}	/* map scatterlist to PCI bus addresses */	n_elem = pci_map_sg(host->pdev, sg, n_elem, pci_dir);	if (n_elem <= 0) {		carm_end_rq(host, crq, 0);		return;		/* request with no s/g entries? */	}	crq->n_elem = n_elem;	crq->port = port;	host->hw_sg_used += n_elem;	/*	 * build read/write message	 */	VPRINTK("build msg\n");	msg = (struct carm_msg_rw *) carm_ref_msg(host, crq->tag);	if (writing) {		msg->type = CARM_MSG_WRITE;		crq->msg_type = CARM_MSG_WRITE;	} else {		msg->type = CARM_MSG_READ;		crq->msg_type = CARM_MSG_READ;	}	msg->id		= port->port_no;	msg->sg_count	= n_elem;	msg->sg_type	= SGT_32BIT;	msg->handle	= cpu_to_le32(TAG_ENCODE(crq->tag));	msg->lba	= cpu_to_le32(rq->sector & 0xffffffff);	tmp		= (rq->sector >> 16) >> 16;	msg->lba_high	= cpu_to_le16( (u16) tmp );	msg->lba_count	= cpu_to_le16(rq->nr_sectors);	msg_size = sizeof(struct carm_msg_rw) - sizeof(msg->sg);	for (i = 0; i < n_elem; i++) {		struct carm_msg_sg *carm_sg = &msg->sg[i];		carm_sg->start = cpu_to_le32(sg_dma_address(&crq->sg[i]));		carm_sg->len = cpu_to_le32(sg_dma_len(&crq->sg[i]));		msg_size += sizeof(struct carm_msg_sg);	}	rc = carm_lookup_bucket(msg_size);	BUG_ON(rc < 0);	crq->msg_bucket = (u32) rc;	/*	 * queue read/write message to hardware	 */	VPRINTK("send msg, tag == %u\n", crq->tag);	rc = carm_send_msg(host, crq);	if (rc) {		carm_put_request(host, crq);		blk_requeue_request(q, rq);		carm_push_q(host, q);		return;		/* call us again later, eventually */	}	goto queue_one_request;}static void carm_handle_array_info(struct carm_host *host,				   struct carm_request *crq, u8 *mem,				   int is_ok){	struct carm_port *port;	u8 *msg_data = mem + sizeof(struct carm_array_info);	struct carm_array_info *desc = (struct carm_array_info *) msg_data;	u64 lo, hi;	int cur_port;	size_t slen;	DPRINTK("ENTER\n");	carm_end_rq(host, crq, is_ok);	if (!is_ok)		goto out;	if (le32_to_cpu(desc->array_status) & ARRAY_NO_EXIST)		goto out;	cur_port = host->cur_scan_dev;	/* should never occur */	if ((cur_port < 0) || (cur_port >= CARM_MAX_PORTS)) {		printk(KERN_ERR PFX "BUG: cur_scan_dev==%d, array_id==%d\n",		       cur_port, (int) desc->array_id);		goto out;	}	port = &host->port[cur_port];	lo = (u64) le32_to_cpu(desc->size);	hi = (u64) le16_to_cpu(desc->size_hi);	port->capacity = lo | (hi << 32);	port->dev_geom_head = le16_to_cpu(desc->head);	port->dev_geom_sect = le16_to_cpu(desc->sect);	port->dev_geom_cyl = le16_to_cpu(desc->cyl);	host->dev_active |= (1 << cur_port);	strncpy(port->name, desc->name, sizeof(port->name));	port->name[sizeof(port->name) - 1] = 0;	slen = strlen(port->name);	while (slen && (port->name[slen - 1] == ' ')) {		port->name[slen - 1] = 0;		slen--;	}	printk(KERN_INFO DRV_NAME "(%s): port %u device %Lu sectors\n",	       pci_name(host->pdev), port->port_no,	       (unsigned long long) port->capacity);	printk(KERN_INFO DRV_NAME "(%s): port %u device \"%s\"\n",	       pci_name(host->pdev), port->port_no, port->name);out:	assert(host->state == HST_DEV_SCAN);	schedule_work(&host->fsm_task);}static void carm_handle_scan_chan(struct carm_host *host,				  struct carm_request *crq, u8 *mem,				  int is_ok){	u8 *msg_data = mem + IOC_SCAN_CHAN_OFFSET;	unsigned int i, dev_count = 0;	int new_state = HST_DEV_SCAN_START;	DPRINTK("ENTER\n");	carm_end_rq(host, crq, is_ok);	if (!is_ok) {		new_state = HST_ERROR;		goto out;	}	/* TODO: scan and support non-disk devices */	for (i = 0; i < 8; i++)		if (msg_data[i] == 0) { /* direct-access device (disk) */			host->dev_present |= (1 << i);			dev_count++;		}	printk(KERN_INFO DRV_NAME "(%s): found %u interesting devices\n",	       pci_name(host->pdev), dev_count);out:	assert(host->state == HST_PORT_SCAN);	host->state = new_state;	schedule_work(&host->fsm_task);}static void carm_handle_generic(struct carm_host *host,				struct carm_request *crq, int is_ok,				int cur_state, int next_state){	DPRINTK("ENTER\n");	carm_end_rq(host, crq, is_ok);	assert(host->state == cur_state);	if (is_ok)		host->state = next_state;	else		host->state = HST_ERROR;	schedule_work(&host->fsm_task);}static inline void carm_handle_rw(struct carm_host *host,				  struct carm_request *crq, int is_ok){	int pci_dir;	VPRINTK("ENTER\n");	if (rq_data_dir(crq->rq) == WRITE)		pci_dir = PCI_DMA_TODEVICE;	else		pci_dir = PCI_DMA_FROMDEVICE;	pci_unmap_sg(host->pdev, &crq->sg[0], crq->n_elem, pci_dir);	carm_end_rq(host, crq, is_ok);}static inline void carm_handle_resp(struct carm_host *host,				    __le32 ret_handle_le, u32 status){	u32 handle = le32_to_cpu(ret_handle_le);	unsigned int msg_idx;	struct carm_request *crq;	int is_ok = (status == RMSG_OK);	u8 *mem;	VPRINTK("ENTER, handle == 0x%x\n", handle);	if (unlikely(!TAG_VALID(handle))) {		printk(KERN_ERR DRV_NAME "(%s): BUG: invalid tag 0x%x\n",		       pci_name(host->pdev), handle);		return;	}	msg_idx = TAG_DECODE(handle);	VPRINTK("tag == %u\n", msg_idx);	crq = &host->req[msg_idx];	/* fast path */	if (likely(crq->msg_type == CARM_MSG_READ ||		   crq->msg_type == CARM_MSG_WRITE)) {		carm_handle_rw(host, crq, is_ok);		return;	}	mem = carm_ref_msg(host, msg_idx);	switch (crq->msg_type) {	case CARM_MSG_IOCTL: {		switch (crq->msg_subtype) {		case CARM_IOC_SCAN_CHAN:			carm_handle_scan_chan(host, crq, mem, is_ok);			break;		default:			/* unknown / invalid response */			goto err_out;		}		break;	}	case CARM_MSG_MISC: {		switch (crq->msg_subtype) {		case MISC_ALLOC_MEM:			carm_handle_generic(host, crq, is_ok,					    HST_ALLOC_BUF, HST_SYNC_TIME);			break;		case MISC_SET_TIME:			carm_handle_generic(host, crq, is_ok,					    HST_SYNC_TIME, HST_GET_FW_VER);			break;		case MISC_GET_FW_VER: {			struct carm_fw_ver *ver = (struct carm_fw_ver *)				mem + sizeof(struct carm_msg_get_fw_ver);			if (is_ok) {				host->fw_ver = le32_to_cpu(ver->version);				host->flags |= (ver->features & FL_FW_VER_MASK);			}			carm_handle_generic(host, crq, is_ok,					    HST_GET_FW_VER, HST_PORT_SCAN);			break;		}		default:			/* unknown / invalid response */			goto err_out;		}		break;	}	case CARM_MSG_ARRAY: {		switch (crq->msg_subtype) {		case CARM_ARRAY_INFO:			carm_handle_array_info(host, crq, mem, is_ok);			break;		default:			/* unknown / invalid response */			goto err_out;		}		break;	}	default:		/* unknown / invalid response */		goto err_out;	}	return;err_out:	printk(KERN_WARNING DRV_NAME "(%s): BUG: unhandled message type %d/%d\n",	       pci_name(host->pdev), crq->msg_type, crq->msg_subtype);	carm_end_rq(host, crq, 0);}static inline void carm_handle_responses(struct carm_host *host){	void __iomem *mmio = host->mmio;	struct carm_response *resp = (struct carm_response *) host->shm;	unsigned int work = 0;	unsigned int idx = host->resp_idx % RMSG_Q_LEN;	while (1) {		u32 status = le32_to_cpu(resp[idx].status);		if (status == 0xffffffff) {			VPRINTK("ending response on index %u\n", idx);			writel(idx << 3, mmio + CARM_RESP_IDX);			break;		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -