static int zfcp_qdio_fill_sbals(struct zfcp_qdio *qdio, struct zfcp_queue_req *q_req, unsigned int sbtype, void *start_addr, unsigned int total_length) { struct qdio_buffer_element *sbale; unsigned long remaining, length; void *addr; /* split segment up */ for (addr = start_addr, remaining = total_length; remaining > 0; addr += length, remaining -= length) { sbale = zfcp_qdio_sbale_next(qdio, q_req, sbtype); if (!sbale) { atomic_inc(&qdio->req_q_full); zfcp_qdio_undo_sbals(qdio, q_req); return -EINVAL; } /* new piece must not exceed next page boundary */ length = min(remaining, (PAGE_SIZE - ((unsigned long)addr & (PAGE_SIZE - 1)))); sbale->addr = addr; sbale->length = length; } return 0; }
/** * 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 int zfcp_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 * @qdio: pointer to struct zfcp_qdio * @q_req: pointer to struct zfcp_qdio_req * @sg: scatter-gather list * @max_sbals: upper bound for number of SBALs to be used * Returns: number of bytes, or error (negativ) */ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, struct scatterlist *sg) { struct qdio_buffer_element *sbale; int bytes = 0; /* set storage-block type for this request */ sbale = zfcp_qdio_sbale_req(qdio, q_req); sbale->sflags |= q_req->sbtype; for (; sg; sg = sg_next(sg)) { sbale = zfcp_qdio_sbale_next(qdio, q_req); if (!sbale) { atomic_inc(&qdio->req_q_full); zfcp_qdio_zero_sbals(qdio->req_q, q_req->sbal_first, q_req->sbal_number); return -EINVAL; } sbale->addr = sg_virt(sg); sbale->length = sg->length; bytes += sg->length; } return bytes; }