📄 sx8.c
字号:
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 + -