+/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
+static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
+ int arr_len)
+{
+ int k, req_len, act_len, len, active;
+ void * kaddr;
+ void * kaddr_off;
+ struct scatterlist * sgpnt;
+
+ if (0 == scp->request_bufflen)
+ return 0;
+ if (NULL == scp->request_buffer)
+ return (DID_ERROR << 16);
+ if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
+ (scp->sc_data_direction == DMA_FROM_DEVICE)))
+ return (DID_ERROR << 16);
+ if (0 == scp->use_sg) {
+ req_len = scp->request_bufflen;
+ act_len = (req_len < arr_len) ? req_len : arr_len;
+ memcpy(scp->request_buffer, arr, act_len);
+ scp->resid = req_len - act_len;
+ return 0;
+ }
+ sgpnt = (struct scatterlist *)scp->request_buffer;
+ active = 1;
+ for (k = 0, req_len = 0, act_len = 0; k < scp->use_sg; ++k, ++sgpnt) {
+ if (active) {
+ kaddr = (unsigned char *)
+ kmap_atomic(sgpnt->page, KM_USER0);
+ if (NULL == kaddr)
+ return (DID_ERROR << 16);
+ kaddr_off = (unsigned char *)kaddr + sgpnt->offset;
+ len = sgpnt->length;
+ if ((req_len + len) > arr_len) {
+ active = 0;
+ len = arr_len - req_len;
+ }
+ memcpy(kaddr_off, arr + req_len, len);
+ kunmap_atomic(kaddr, KM_USER0);
+ act_len += len;
+ }
+ req_len += sgpnt->length;
+ }
+ scp->resid = req_len - act_len;
+ return 0;
+}
+
+/* Returns number of bytes fetched into 'arr' or -1 if error. */
+static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
+ int max_arr_len)
+{
+ int k, req_len, len, fin;
+ void * kaddr;
+ void * kaddr_off;
+ struct scatterlist * sgpnt;
+
+ if (0 == scp->request_bufflen)
+ return 0;
+ if (NULL == scp->request_buffer)
+ return -1;
+ if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
+ (scp->sc_data_direction == DMA_TO_DEVICE)))
+ return -1;
+ if (0 == scp->use_sg) {
+ req_len = scp->request_bufflen;
+ len = (req_len < max_arr_len) ? req_len : max_arr_len;
+ memcpy(arr, scp->request_buffer, len);
+ return len;
+ }
+ sgpnt = (struct scatterlist *)scp->request_buffer;
+ for (k = 0, req_len = 0, fin = 0; k < scp->use_sg; ++k, ++sgpnt) {
+ kaddr = (unsigned char *)kmap_atomic(sgpnt->page, KM_USER0);
+ if (NULL == kaddr)
+ return -1;
+ kaddr_off = (unsigned char *)kaddr + sgpnt->offset;
+ len = sgpnt->length;
+ if ((req_len + len) > max_arr_len) {
+ len = max_arr_len - req_len;
+ fin = 1;
+ }
+ memcpy(arr + req_len, kaddr_off, len);
+ kunmap_atomic(kaddr, KM_USER0);
+ if (fin)
+ return req_len + len;
+ req_len += sgpnt->length;
+ }
+ return req_len;
+}
+