diff options
author | Mike Christie <michaelc@cs.wisc.edu> | 2006-01-13 19:05:47 -0500 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.(none)> | 2006-01-14 11:55:18 -0500 |
commit | 7cae5159dd2623300cf9820865bfbf6dcdb7c1b9 (patch) | |
tree | 68cd331b75515e90f79f4902de0620b293adcfd4 /drivers/scsi | |
parent | 56851698c23430f0f291d6e50da344e6b414f3b9 (diff) |
[SCSI] iscsi: add high mem support
From Mike Christie <michaelc@cs.wisc.edu> and FUJITA Tomonori <tomof@acm.org>:
We cannot use page_address becuase some pages could be highmem.
Instead, we can use sock_no_sendpage which does kmap for us.
Signed-off-by: Alex Aizman <itn780@yahoo.com>
Signed-off-by: Dmitry Yusupov <dmitry_yus@yahoo.com>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/iscsi_tcp.c | 84 | ||||
-rw-r--r-- | drivers/scsi/iscsi_tcp.h | 2 |
2 files changed, 31 insertions, 55 deletions
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 5e8b3135574c..0acc4b235d9b 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c | |||
@@ -87,35 +87,32 @@ iscsi_buf_init_virt(struct iscsi_buf *ibuf, char *vbuf, int size) | |||
87 | { | 87 | { |
88 | sg_init_one(&ibuf->sg, (u8 *)vbuf, size); | 88 | sg_init_one(&ibuf->sg, (u8 *)vbuf, size); |
89 | ibuf->sent = 0; | 89 | ibuf->sent = 0; |
90 | ibuf->use_sendmsg = 0; | ||
90 | } | 91 | } |
91 | 92 | ||
92 | static inline void | 93 | static inline void |
93 | iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size) | 94 | iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size) |
94 | { | 95 | { |
95 | ibuf->sg.page = (void*)vbuf; | 96 | ibuf->sg.page = virt_to_page(vbuf); |
96 | ibuf->sg.offset = (unsigned int)-1; | 97 | ibuf->sg.offset = offset_in_page(vbuf); |
97 | ibuf->sg.length = size; | 98 | ibuf->sg.length = size; |
98 | ibuf->sent = 0; | 99 | ibuf->sent = 0; |
99 | } | 100 | ibuf->use_sendmsg = 1; |
100 | |||
101 | static inline void* | ||
102 | iscsi_buf_iov_base(struct iscsi_buf *ibuf) | ||
103 | { | ||
104 | return (char*)ibuf->sg.page + ibuf->sent; | ||
105 | } | 101 | } |
106 | 102 | ||
107 | static inline void | 103 | static inline void |
108 | iscsi_buf_init_sg(struct iscsi_buf *ibuf, struct scatterlist *sg) | 104 | iscsi_buf_init_sg(struct iscsi_buf *ibuf, struct scatterlist *sg) |
109 | { | 105 | { |
106 | ibuf->sg.page = sg->page; | ||
107 | ibuf->sg.offset = sg->offset; | ||
108 | ibuf->sg.length = sg->length; | ||
110 | /* | 109 | /* |
111 | * Fastpath: sg element fits into single page | 110 | * Fastpath: sg element fits into single page |
112 | */ | 111 | */ |
113 | if (sg->length + sg->offset <= PAGE_SIZE && page_count(sg->page) >= 2) { | 112 | if (sg->length + sg->offset <= PAGE_SIZE && page_count(sg->page) >= 2) |
114 | ibuf->sg.page = sg->page; | 113 | ibuf->use_sendmsg = 0; |
115 | ibuf->sg.offset = sg->offset; | 114 | else |
116 | ibuf->sg.length = sg->length; | 115 | ibuf->use_sendmsg = 1; |
117 | } else | ||
118 | iscsi_buf_init_iov(ibuf, page_address(sg->page), sg->length); | ||
119 | ibuf->sent = 0; | 116 | ibuf->sent = 0; |
120 | } | 117 | } |
121 | 118 | ||
@@ -1311,35 +1308,25 @@ iscsi_conn_restore_callbacks(struct iscsi_conn *conn) | |||
1311 | * @buf: buffer to write from | 1308 | * @buf: buffer to write from |
1312 | * @size: actual size to write | 1309 | * @size: actual size to write |
1313 | * @flags: socket's flags | 1310 | * @flags: socket's flags |
1314 | * | ||
1315 | * Notes: | ||
1316 | * depending on buffer will use tcp_sendpage() or tcp_sendmsg(). | ||
1317 | * buf->sg.offset == -1 tells us that buffer is non S/G and forces | ||
1318 | * to use tcp_sendmsg(). | ||
1319 | */ | 1311 | */ |
1320 | static inline int | 1312 | static inline int |
1321 | iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags) | 1313 | iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags) |
1322 | { | 1314 | { |
1323 | struct socket *sk = conn->sock; | 1315 | struct socket *sk = conn->sock; |
1324 | int res; | 1316 | int offset = buf->sg.offset + buf->sent; |
1325 | |||
1326 | if ((int)buf->sg.offset >= 0) { | ||
1327 | int offset = buf->sg.offset + buf->sent; | ||
1328 | |||
1329 | res = conn->sendpage(sk, buf->sg.page, offset, size, flags); | ||
1330 | } else { | ||
1331 | struct msghdr msg; | ||
1332 | |||
1333 | buf->iov.iov_base = iscsi_buf_iov_base(buf); | ||
1334 | buf->iov.iov_len = size; | ||
1335 | |||
1336 | memset(&msg, 0, sizeof(struct msghdr)); | ||
1337 | |||
1338 | /* tcp_sendmsg */ | ||
1339 | res = kernel_sendmsg(sk, &msg, &buf->iov, 1, size); | ||
1340 | } | ||
1341 | 1317 | ||
1342 | return res; | 1318 | /* |
1319 | * if we got use_sg=0 or are sending something we kmallocd | ||
1320 | * then we did not have to do kmap (kmap returns page_address) | ||
1321 | * | ||
1322 | * if we got use_sg > 0, but had to drop down, we do not | ||
1323 | * set clustering so this should only happen for that | ||
1324 | * slab case. | ||
1325 | */ | ||
1326 | if (buf->use_sendmsg) | ||
1327 | return sock_no_sendpage(sk, buf->sg.page, offset, size, flags); | ||
1328 | else | ||
1329 | return conn->sendpage(sk, buf->sg.page, offset, size, flags); | ||
1343 | } | 1330 | } |
1344 | 1331 | ||
1345 | /** | 1332 | /** |
@@ -1431,19 +1418,6 @@ iscsi_data_digest_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
1431 | ctask->digest_count = 4; | 1418 | ctask->digest_count = 4; |
1432 | } | 1419 | } |
1433 | 1420 | ||
1434 | static inline void | ||
1435 | iscsi_buf_data_digest_update(struct iscsi_conn *conn, struct iscsi_buf *buf) | ||
1436 | { | ||
1437 | struct scatterlist sg; | ||
1438 | |||
1439 | if (buf->sg.offset != -1) | ||
1440 | crypto_digest_update(conn->data_tx_tfm, &buf->sg, 1); | ||
1441 | else { | ||
1442 | sg_init_one(&sg, (char *)buf->sg.page, buf->sg.length); | ||
1443 | crypto_digest_update(conn->data_tx_tfm, &sg, 1); | ||
1444 | } | ||
1445 | } | ||
1446 | |||
1447 | static inline int | 1421 | static inline int |
1448 | iscsi_digest_final_send(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | 1422 | iscsi_digest_final_send(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, |
1449 | struct iscsi_buf *buf, uint32_t *digest, int final) | 1423 | struct iscsi_buf *buf, uint32_t *digest, int final) |
@@ -1806,7 +1780,8 @@ handle_xmstate_imm_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
1806 | return -EAGAIN; | 1780 | return -EAGAIN; |
1807 | } | 1781 | } |
1808 | if (conn->datadgst_en) | 1782 | if (conn->datadgst_en) |
1809 | iscsi_buf_data_digest_update(conn, &ctask->sendbuf); | 1783 | crypto_digest_update(conn->data_tx_tfm, |
1784 | &ctask->sendbuf.sg, 1); | ||
1810 | 1785 | ||
1811 | if (!ctask->imm_count) | 1786 | if (!ctask->imm_count) |
1812 | break; | 1787 | break; |
@@ -1891,7 +1866,8 @@ handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
1891 | * so pass it | 1866 | * so pass it |
1892 | */ | 1867 | */ |
1893 | if (conn->datadgst_en && ctask->sent - start > 0) | 1868 | if (conn->datadgst_en && ctask->sent - start > 0) |
1894 | iscsi_buf_data_digest_update(conn, &ctask->sendbuf); | 1869 | crypto_digest_update(conn->data_tx_tfm, |
1870 | &ctask->sendbuf.sg, 1); | ||
1895 | 1871 | ||
1896 | if (!ctask->data_count) | 1872 | if (!ctask->data_count) |
1897 | break; | 1873 | break; |
@@ -1969,7 +1945,7 @@ solicit_again: | |||
1969 | 1945 | ||
1970 | BUG_ON(r2t->data_count < 0); | 1946 | BUG_ON(r2t->data_count < 0); |
1971 | if (conn->datadgst_en) | 1947 | if (conn->datadgst_en) |
1972 | iscsi_buf_data_digest_update(conn, &r2t->sendbuf); | 1948 | crypto_digest_update(conn->data_tx_tfm, &r2t->sendbuf.sg, 1); |
1973 | 1949 | ||
1974 | if (r2t->data_count) { | 1950 | if (r2t->data_count) { |
1975 | BUG_ON(ctask->sc->use_sg == 0); | 1951 | BUG_ON(ctask->sc->use_sg == 0); |
@@ -2051,7 +2027,7 @@ handle_xmstate_w_pad(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
2051 | } | 2027 | } |
2052 | 2028 | ||
2053 | if (conn->datadgst_en) { | 2029 | if (conn->datadgst_en) { |
2054 | iscsi_buf_data_digest_update(conn, &ctask->sendbuf); | 2030 | crypto_digest_update(conn->data_tx_tfm, &ctask->sendbuf.sg, 1); |
2055 | /* imm data? */ | 2031 | /* imm data? */ |
2056 | if (!dtask) { | 2032 | if (!dtask) { |
2057 | if (iscsi_digest_final_send(conn, ctask, &ctask->immbuf, | 2033 | if (iscsi_digest_final_send(conn, ctask, &ctask->immbuf, |
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h index c8bb5b0bcb4b..f95e61b76f70 100644 --- a/drivers/scsi/iscsi_tcp.h +++ b/drivers/scsi/iscsi_tcp.h | |||
@@ -242,8 +242,8 @@ struct iscsi_session { | |||
242 | 242 | ||
243 | struct iscsi_buf { | 243 | struct iscsi_buf { |
244 | struct scatterlist sg; | 244 | struct scatterlist sg; |
245 | struct kvec iov; | ||
246 | unsigned int sent; | 245 | unsigned int sent; |
246 | char use_sendmsg; | ||
247 | }; | 247 | }; |
248 | 248 | ||
249 | struct iscsi_data_task { | 249 | struct iscsi_data_task { |