📄 zfcp_qdio.c
字号:
atomic_set(&queue->free_count, count); ZFCP_LOG_DEBUG("clearing of inbound data regions failed, " "queues may be down " "(count=%d, start=%d, retval=%d)\n", count, start, retval); } else { queue->free_index += count; queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; atomic_set(&queue->free_count, 0); ZFCP_LOG_TRACE("%i buffers enqueued to response " "queue at position %i\n", count, start); } out: return;}/* * function: zfcp_qdio_reqid_check * * purpose: checks for valid reqids or unsolicited status * * returns: 0 - valid request id or unsolicited status * !0 - otherwise */intzfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr){ struct zfcp_fsf_req *fsf_req; /* invalid (per convention used in this driver) */ if (unlikely(!sbale_addr)) { ZFCP_LOG_NORMAL("bug: invalid reqid\n"); return -EINVAL; } /* valid request id and thus (hopefully :) valid fsf_req address */ fsf_req = (struct zfcp_fsf_req *) sbale_addr; /* serialize with zfcp_fsf_req_dismiss_all */ spin_lock(&adapter->fsf_req_list_lock); if (list_empty(&adapter->fsf_req_list_head)) { spin_unlock(&adapter->fsf_req_list_lock); return 0; } list_del(&fsf_req->list); atomic_dec(&adapter->fsf_reqs_active); spin_unlock(&adapter->fsf_req_list_lock); if (unlikely(adapter != fsf_req->adapter)) { ZFCP_LOG_NORMAL("bug: invalid reqid (fsf_req=%p, " "fsf_req->adapter=%p, adapter=%p)\n", fsf_req, fsf_req->adapter, adapter); return -EINVAL; } /* finish the FSF request */ zfcp_fsf_req_complete(fsf_req); return 0;}/** * zfcp_qdio_sbale_get - return pointer to SBALE of qdio_queue * @queue: queue from which SBALE should be returned * @sbal: specifies number of SBAL in queue * @sbale: specifes number of SBALE in SBAL */static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_get(struct zfcp_qdio_queue *queue, int sbal, int sbale){ return &queue->buffer[sbal]->element[sbale];}/** * zfcp_qdio_sbale_req - return pointer to SBALE of request_queue for * a struct zfcp_fsf_req */inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_fsf_req *fsf_req, int sbal, int sbale){ return zfcp_qdio_sbale_get(&fsf_req->adapter->request_queue, sbal, sbale);}/** * zfcp_qdio_sbale_resp - return pointer to SBALE of response_queue for * a struct zfcp_fsf_req */static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_resp(struct zfcp_fsf_req *fsf_req, int sbal, int sbale){ return zfcp_qdio_sbale_get(&fsf_req->adapter->response_queue, sbal, sbale);}/** * zfcp_qdio_sbale_curr - return current SBALE on request_queue for * a struct zfcp_fsf_req */inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req){ return zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, fsf_req->sbale_curr);}/** * zfcp_qdio_sbal_limit - determine maximum number of SBALs that can be used * on the request_queue for a struct zfcp_fsf_req * @fsf_req: the number of the last SBAL that can be used is stored herein * @max_sbals: used to pass an upper limit for the number of SBALs * * Note: We can assume at least one free SBAL in the request_queue when called. */static inline voidzfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals){ int count = atomic_read(&fsf_req->adapter->request_queue.free_count); count = min(count, max_sbals); fsf_req->sbal_last = fsf_req->sbal_first; fsf_req->sbal_last += (count - 1); fsf_req->sbal_last %= QDIO_MAX_BUFFERS_PER_Q;}/** * zfcp_qdio_sbal_chain - chain SBALs if more than one SBAL is needed for a * request * @fsf_req: zfcp_fsf_req to be processed * @sbtype: SBAL flags which have to be set in first SBALE of new SBAL * * This function changes sbal_curr, sbale_curr, sbal_number of fsf_req. */static inline volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype){ volatile struct qdio_buffer_element *sbale; /* set last entry flag in current SBALE of current SBAL */ sbale = zfcp_qdio_sbale_curr(fsf_req); sbale->flags |= SBAL_FLAGS_LAST_ENTRY; /* don't exceed last allowed SBAL */ if (fsf_req->sbal_curr == fsf_req->sbal_last) return NULL; /* set chaining flag in first SBALE of current SBAL */ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); sbale->flags |= SBAL_FLAGS0_MORE_SBALS; /* calculate index of next SBAL */ fsf_req->sbal_curr++; fsf_req->sbal_curr %= QDIO_MAX_BUFFERS_PER_Q; /* keep this requests number of SBALs up-to-date */ fsf_req->sbal_number++; /* start at first SBALE of new SBAL */ fsf_req->sbale_curr = 0; /* set storage-block type for new SBAL */ sbale = zfcp_qdio_sbale_curr(fsf_req); sbale->flags |= sbtype; return sbale;}/** * zfcp_qdio_sbale_next - switch to next SBALE, chain SBALs if needed */static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype){ if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL) return zfcp_qdio_sbal_chain(fsf_req, sbtype); fsf_req->sbale_curr++; return zfcp_qdio_sbale_curr(fsf_req);}/** * zfcp_qdio_sbals_zero - initialize SBALs between first and last in queue * with zero from */static inline intzfcp_qdio_sbals_zero(struct zfcp_qdio_queue *queue, int first, int last){ struct qdio_buffer **buf = queue->buffer; int curr = first; int count = 0; for(;;) { curr %= QDIO_MAX_BUFFERS_PER_Q; count++; memset(buf[curr], 0, sizeof(struct qdio_buffer)); if (curr == last) break; curr++; } return count;}/** * zfcp_qdio_sbals_wipe - reset all changes in SBALs for an fsf_req */static inline intzfcp_qdio_sbals_wipe(struct zfcp_fsf_req *fsf_req){ return zfcp_qdio_sbals_zero(&fsf_req->adapter->request_queue, fsf_req->sbal_first, fsf_req->sbal_curr);}/** * zfcp_qdio_sbale_fill - set address and lenght in current SBALE * on request_queue */static inline voidzfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, void *addr, int length){ volatile struct qdio_buffer_element *sbale; sbale = zfcp_qdio_sbale_curr(fsf_req); sbale->addr = addr; sbale->length = length;}/** * zfcp_qdio_sbals_from_segment - map memory segment to SBALE(s) * @fsf_req: request to be processed * @sbtype: SBALE flags * @start_addr: address of memory segment * @total_length: length of memory segment * * Alignment and length of the segment determine how many SBALEs are needed * for the memory segment. */static inline intzfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, void *start_addr, unsigned long total_length){ unsigned long remaining, length; void *addr; /* split segment up heeding page boundaries */ for (addr = start_addr, remaining = total_length; remaining > 0; addr += length, remaining -= length) { /* get next free SBALE for new piece */ if (NULL == zfcp_qdio_sbale_next(fsf_req, sbtype)) { /* no SBALE left, clean up and leave */ zfcp_qdio_sbals_wipe(fsf_req); return -EINVAL; } /* calculate length of new piece */ length = min(remaining, (PAGE_SIZE - ((unsigned long) addr & (PAGE_SIZE - 1)))); /* fill current SBALE with calculated piece */ zfcp_qdio_sbale_fill(fsf_req, sbtype, addr, length); } return total_length;}/** * zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list * @fsf_req: request to be processed * @sbtype: SBALE flags * @sg: scatter-gather list * @sg_count: number of elements in scatter-gather list * @max_sbals: upper bound for number of SBALs to be used */inline intzfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, struct scatterlist *sg, int sg_count, int max_sbals){ int sg_index; struct scatterlist *sg_segment; int retval; volatile struct qdio_buffer_element *sbale; int bytes = 0; /* figure out last allowed SBAL */ zfcp_qdio_sbal_limit(fsf_req, max_sbals); /* set storage-block type for current SBAL */ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); sbale->flags |= sbtype; /* process all segements of scatter-gather list */ for (sg_index = 0, sg_segment = sg, bytes = 0; sg_index < sg_count; sg_index++, sg_segment++) { retval = zfcp_qdio_sbals_from_segment( fsf_req, sbtype, zfcp_sg_to_address(sg_segment), sg_segment->length); if (retval < 0) { bytes = retval; goto out; } else bytes += retval; } /* assume that no other SBALEs are to follow in the same SBAL */ sbale = zfcp_qdio_sbale_curr(fsf_req); sbale->flags |= SBAL_FLAGS_LAST_ENTRY;out: return bytes;}/** * zfcp_qdio_sbals_from_buffer - fill SBALs from buffer * @fsf_req: request to be processed * @sbtype: SBALE flags * @buffer: data buffer * @length: length of buffer * @max_sbals: upper bound for number of SBALs to be used */static inline intzfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, void *buffer, unsigned long length, int max_sbals){ struct scatterlist sg_segment; zfcp_address_to_sg(buffer, &sg_segment); sg_segment.length = length; return zfcp_qdio_sbals_from_sg(fsf_req, sbtype, &sg_segment, 1, max_sbals);}/** * zfcp_qdio_sbals_from_scsicmnd - fill SBALs from scsi command * @fsf_req: request to be processed * @sbtype: SBALE flags * @scsi_cmnd: either scatter-gather list or buffer contained herein is used * to fill SBALs */inline intzfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, struct scsi_cmnd *scsi_cmnd){ if (scsi_cmnd->use_sg) { return zfcp_qdio_sbals_from_sg(fsf_req, sbtype, (struct scatterlist *) scsi_cmnd->request_buffer, scsi_cmnd->use_sg, ZFCP_MAX_SBALS_PER_REQ); } else { return zfcp_qdio_sbals_from_buffer(fsf_req, sbtype, scsi_cmnd->request_buffer, scsi_cmnd->request_bufflen, ZFCP_MAX_SBALS_PER_REQ); }}/** * zfcp_qdio_determine_pci - set PCI flag in first SBALE on qdio queue if needed */intzfcp_qdio_determine_pci(struct zfcp_qdio_queue *req_queue, struct zfcp_fsf_req *fsf_req){ int new_distance_from_int; int pci_pos; volatile struct qdio_buffer_element *sbale; new_distance_from_int = req_queue->distance_from_int + fsf_req->sbal_number; if (unlikely(new_distance_from_int >= ZFCP_QDIO_PCI_INTERVAL)) { new_distance_from_int %= ZFCP_QDIO_PCI_INTERVAL; pci_pos = fsf_req->sbal_first; pci_pos += fsf_req->sbal_number; pci_pos -= new_distance_from_int; pci_pos -= 1; pci_pos %= QDIO_MAX_BUFFERS_PER_Q; sbale = zfcp_qdio_sbale_req(fsf_req, pci_pos, 0); sbale->flags |= SBAL_FLAGS0_PCI; } return new_distance_from_int;}/* * function: zfcp_zero_sbals * * purpose: zeros specified range of SBALs * * returns: */voidzfcp_qdio_zero_sbals(struct qdio_buffer *buf[], int first, int clean_count){ int cur_pos; int index; for (cur_pos = first; cur_pos < (first + clean_count); cur_pos++) { index = cur_pos % QDIO_MAX_BUFFERS_PER_Q; memset(buf[index], 0, sizeof (struct qdio_buffer)); ZFCP_LOG_TRACE("zeroing BUFFER %d at address %p\n", index, buf[index]); }}#undef ZFCP_LOG_AREA
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -