diff options
-rw-r--r-- | drivers/scsi/iscsi_tcp.c | 118 | ||||
-rw-r--r-- | drivers/scsi/scsi_transport_iscsi.c | 845 | ||||
-rw-r--r-- | include/scsi/iscsi_if.h | 6 | ||||
-rw-r--r-- | include/scsi/scsi_transport_iscsi.h | 75 |
4 files changed, 583 insertions, 461 deletions
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 0acc4b235d9b..e31d350e6b67 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c | |||
@@ -2435,17 +2435,20 @@ iscsi_pool_free(struct iscsi_queue *q, void **items) | |||
2435 | kfree(items); | 2435 | kfree(items); |
2436 | } | 2436 | } |
2437 | 2437 | ||
2438 | static iscsi_connh_t | 2438 | static struct iscsi_cls_conn * |
2439 | iscsi_conn_create(iscsi_sessionh_t sessionh, uint32_t conn_idx) | 2439 | iscsi_conn_create(struct Scsi_Host *shost, uint32_t conn_idx) |
2440 | { | 2440 | { |
2441 | struct iscsi_session *session = iscsi_ptr(sessionh); | 2441 | struct iscsi_session *session = iscsi_hostdata(shost->hostdata); |
2442 | struct iscsi_conn *conn = NULL; | 2442 | struct iscsi_conn *conn; |
2443 | struct iscsi_cls_conn *cls_conn; | ||
2443 | 2444 | ||
2444 | conn = kmalloc(sizeof(struct iscsi_conn), GFP_KERNEL); | 2445 | cls_conn = iscsi_create_conn(hostdata_session(shost->hostdata), |
2445 | if (conn == NULL) | 2446 | conn_idx); |
2446 | goto conn_alloc_fail; | 2447 | if (!cls_conn) |
2447 | memset(conn, 0, sizeof(struct iscsi_conn)); | 2448 | return NULL; |
2449 | conn = cls_conn->dd_data; | ||
2448 | 2450 | ||
2451 | memset(conn, 0, sizeof(struct iscsi_conn)); | ||
2449 | conn->c_stage = ISCSI_CONN_INITIAL_STAGE; | 2452 | conn->c_stage = ISCSI_CONN_INITIAL_STAGE; |
2450 | conn->in_progress = IN_PROGRESS_WAIT_HEADER; | 2453 | conn->in_progress = IN_PROGRESS_WAIT_HEADER; |
2451 | conn->id = conn_idx; | 2454 | conn->id = conn_idx; |
@@ -2507,7 +2510,7 @@ iscsi_conn_create(iscsi_sessionh_t sessionh, uint32_t conn_idx) | |||
2507 | mutex_init(&conn->xmitmutex); | 2510 | mutex_init(&conn->xmitmutex); |
2508 | init_waitqueue_head(&conn->ehwait); | 2511 | init_waitqueue_head(&conn->ehwait); |
2509 | 2512 | ||
2510 | return iscsi_handle(conn); | 2513 | return cls_conn; |
2511 | 2514 | ||
2512 | max_recv_dlenght_alloc_fail: | 2515 | max_recv_dlenght_alloc_fail: |
2513 | spin_lock_bh(&session->lock); | 2516 | spin_lock_bh(&session->lock); |
@@ -2523,15 +2526,14 @@ immqueue_alloc_fail: | |||
2523 | writequeue_alloc_fail: | 2526 | writequeue_alloc_fail: |
2524 | kfifo_free(conn->xmitqueue); | 2527 | kfifo_free(conn->xmitqueue); |
2525 | xmitqueue_alloc_fail: | 2528 | xmitqueue_alloc_fail: |
2526 | kfree(conn); | 2529 | iscsi_destroy_conn(cls_conn); |
2527 | conn_alloc_fail: | 2530 | return NULL; |
2528 | return iscsi_handle(NULL); | ||
2529 | } | 2531 | } |
2530 | 2532 | ||
2531 | static void | 2533 | static void |
2532 | iscsi_conn_destroy(iscsi_connh_t connh) | 2534 | iscsi_conn_destroy(struct iscsi_cls_conn *cls_conn) |
2533 | { | 2535 | { |
2534 | struct iscsi_conn *conn = iscsi_ptr(connh); | 2536 | struct iscsi_conn *conn = cls_conn->dd_data; |
2535 | struct iscsi_session *session = conn->session; | 2537 | struct iscsi_session *session = conn->session; |
2536 | unsigned long flags; | 2538 | unsigned long flags; |
2537 | 2539 | ||
@@ -2626,7 +2628,8 @@ iscsi_conn_destroy(iscsi_connh_t connh) | |||
2626 | kfifo_free(conn->writequeue); | 2628 | kfifo_free(conn->writequeue); |
2627 | kfifo_free(conn->immqueue); | 2629 | kfifo_free(conn->immqueue); |
2628 | kfifo_free(conn->mgmtqueue); | 2630 | kfifo_free(conn->mgmtqueue); |
2629 | kfree(conn); | 2631 | |
2632 | iscsi_destroy_conn(cls_conn); | ||
2630 | } | 2633 | } |
2631 | 2634 | ||
2632 | static int | 2635 | static int |
@@ -3257,17 +3260,23 @@ static struct scsi_host_template iscsi_sht = { | |||
3257 | .this_id = -1, | 3260 | .this_id = -1, |
3258 | }; | 3261 | }; |
3259 | 3262 | ||
3260 | static iscsi_sessionh_t | 3263 | static struct iscsi_transport iscsi_tcp_transport; |
3261 | iscsi_session_create(uint32_t initial_cmdsn, struct Scsi_Host *host) | 3264 | |
3265 | static struct Scsi_Host * | ||
3266 | iscsi_session_create(struct scsi_transport_template *scsit, | ||
3267 | uint32_t initial_cmdsn) | ||
3262 | { | 3268 | { |
3263 | int cmd_i; | 3269 | struct Scsi_Host *shost; |
3264 | struct iscsi_session *session; | 3270 | struct iscsi_session *session; |
3271 | int cmd_i; | ||
3265 | 3272 | ||
3266 | session = iscsi_hostdata(host->hostdata); | 3273 | shost = iscsi_transport_create_session(scsit, &iscsi_tcp_transport); |
3267 | memset(session, 0, sizeof(struct iscsi_session)); | 3274 | if (!shost) |
3275 | return NULL; | ||
3268 | 3276 | ||
3269 | session->host = host; | 3277 | session = iscsi_hostdata(shost->hostdata); |
3270 | session->id = host->host_no; | 3278 | memset(session, 0, sizeof(struct iscsi_session)); |
3279 | session->host = shost; | ||
3271 | session->state = ISCSI_STATE_LOGGED_IN; | 3280 | session->state = ISCSI_STATE_LOGGED_IN; |
3272 | session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX; | 3281 | session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX; |
3273 | session->cmds_max = ISCSI_XMIT_CMDS_MAX; | 3282 | session->cmds_max = ISCSI_XMIT_CMDS_MAX; |
@@ -3311,7 +3320,7 @@ iscsi_session_create(uint32_t initial_cmdsn, struct Scsi_Host *host) | |||
3311 | if (iscsi_r2tpool_alloc(session)) | 3320 | if (iscsi_r2tpool_alloc(session)) |
3312 | goto r2tpool_alloc_fail; | 3321 | goto r2tpool_alloc_fail; |
3313 | 3322 | ||
3314 | return iscsi_handle(session); | 3323 | return shost; |
3315 | 3324 | ||
3316 | r2tpool_alloc_fail: | 3325 | r2tpool_alloc_fail: |
3317 | for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) | 3326 | for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) |
@@ -3321,15 +3330,15 @@ immdata_alloc_fail: | |||
3321 | mgmtpool_alloc_fail: | 3330 | mgmtpool_alloc_fail: |
3322 | iscsi_pool_free(&session->cmdpool, (void**)session->cmds); | 3331 | iscsi_pool_free(&session->cmdpool, (void**)session->cmds); |
3323 | cmdpool_alloc_fail: | 3332 | cmdpool_alloc_fail: |
3324 | return iscsi_handle(NULL); | 3333 | return NULL; |
3325 | } | 3334 | } |
3326 | 3335 | ||
3327 | static void | 3336 | static void |
3328 | iscsi_session_destroy(iscsi_sessionh_t sessionh) | 3337 | iscsi_session_destroy(struct Scsi_Host *shost) |
3329 | { | 3338 | { |
3339 | struct iscsi_session *session = iscsi_hostdata(shost->hostdata); | ||
3330 | int cmd_i; | 3340 | int cmd_i; |
3331 | struct iscsi_data_task *dtask, *n; | 3341 | struct iscsi_data_task *dtask, *n; |
3332 | struct iscsi_session *session = iscsi_ptr(sessionh); | ||
3333 | 3342 | ||
3334 | for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { | 3343 | for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { |
3335 | struct iscsi_cmd_task *ctask = session->cmds[cmd_i]; | 3344 | struct iscsi_cmd_task *ctask = session->cmds[cmd_i]; |
@@ -3345,6 +3354,8 @@ iscsi_session_destroy(iscsi_sessionh_t sessionh) | |||
3345 | iscsi_r2tpool_free(session); | 3354 | iscsi_r2tpool_free(session); |
3346 | iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds); | 3355 | iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds); |
3347 | iscsi_pool_free(&session->cmdpool, (void**)session->cmds); | 3356 | iscsi_pool_free(&session->cmdpool, (void**)session->cmds); |
3357 | |||
3358 | iscsi_transport_destroy_session(shost); | ||
3348 | } | 3359 | } |
3349 | 3360 | ||
3350 | static int | 3361 | static int |
@@ -3493,25 +3504,12 @@ iscsi_conn_set_param(iscsi_connh_t connh, enum iscsi_param param, | |||
3493 | } | 3504 | } |
3494 | 3505 | ||
3495 | static int | 3506 | static int |
3496 | iscsi_conn_get_param(iscsi_connh_t connh, enum iscsi_param param, | 3507 | iscsi_session_get_param(struct Scsi_Host *shost, |
3497 | uint32_t *value) | 3508 | enum iscsi_param param, uint32_t *value) |
3498 | { | 3509 | { |
3499 | struct iscsi_conn *conn = iscsi_ptr(connh); | 3510 | struct iscsi_session *session = iscsi_hostdata(shost->hostdata); |
3500 | struct iscsi_session *session = conn->session; | ||
3501 | 3511 | ||
3502 | switch(param) { | 3512 | switch(param) { |
3503 | case ISCSI_PARAM_MAX_RECV_DLENGTH: | ||
3504 | *value = conn->max_recv_dlength; | ||
3505 | break; | ||
3506 | case ISCSI_PARAM_MAX_XMIT_DLENGTH: | ||
3507 | *value = conn->max_xmit_dlength; | ||
3508 | break; | ||
3509 | case ISCSI_PARAM_HDRDGST_EN: | ||
3510 | *value = conn->hdrdgst_en; | ||
3511 | break; | ||
3512 | case ISCSI_PARAM_DATADGST_EN: | ||
3513 | *value = conn->datadgst_en; | ||
3514 | break; | ||
3515 | case ISCSI_PARAM_INITIAL_R2T_EN: | 3513 | case ISCSI_PARAM_INITIAL_R2T_EN: |
3516 | *value = session->initial_r2t_en; | 3514 | *value = session->initial_r2t_en; |
3517 | break; | 3515 | break; |
@@ -3549,6 +3547,31 @@ iscsi_conn_get_param(iscsi_connh_t connh, enum iscsi_param param, | |||
3549 | return 0; | 3547 | return 0; |
3550 | } | 3548 | } |
3551 | 3549 | ||
3550 | static int | ||
3551 | iscsi_conn_get_param(void *data, enum iscsi_param param, uint32_t *value) | ||
3552 | { | ||
3553 | struct iscsi_conn *conn = data; | ||
3554 | |||
3555 | switch(param) { | ||
3556 | case ISCSI_PARAM_MAX_RECV_DLENGTH: | ||
3557 | *value = conn->max_recv_dlength; | ||
3558 | break; | ||
3559 | case ISCSI_PARAM_MAX_XMIT_DLENGTH: | ||
3560 | *value = conn->max_xmit_dlength; | ||
3561 | break; | ||
3562 | case ISCSI_PARAM_HDRDGST_EN: | ||
3563 | *value = conn->hdrdgst_en; | ||
3564 | break; | ||
3565 | case ISCSI_PARAM_DATADGST_EN: | ||
3566 | *value = conn->datadgst_en; | ||
3567 | break; | ||
3568 | default: | ||
3569 | return ISCSI_ERR_PARAM_NOT_FOUND; | ||
3570 | } | ||
3571 | |||
3572 | return 0; | ||
3573 | } | ||
3574 | |||
3552 | static void | 3575 | static void |
3553 | iscsi_conn_get_stats(iscsi_connh_t connh, struct iscsi_stats *stats) | 3576 | iscsi_conn_get_stats(iscsi_connh_t connh, struct iscsi_stats *stats) |
3554 | { | 3577 | { |
@@ -3593,6 +3616,7 @@ static struct iscsi_transport iscsi_tcp_transport = { | |||
3593 | | CAP_DATADGST, | 3616 | | CAP_DATADGST, |
3594 | .host_template = &iscsi_sht, | 3617 | .host_template = &iscsi_sht, |
3595 | .hostdata_size = sizeof(struct iscsi_session), | 3618 | .hostdata_size = sizeof(struct iscsi_session), |
3619 | .conndata_size = sizeof(struct iscsi_conn), | ||
3596 | .max_conn = 1, | 3620 | .max_conn = 1, |
3597 | .max_cmd_len = ISCSI_TCP_MAX_CMD_LEN, | 3621 | .max_cmd_len = ISCSI_TCP_MAX_CMD_LEN, |
3598 | .create_session = iscsi_session_create, | 3622 | .create_session = iscsi_session_create, |
@@ -3601,7 +3625,8 @@ static struct iscsi_transport iscsi_tcp_transport = { | |||
3601 | .bind_conn = iscsi_conn_bind, | 3625 | .bind_conn = iscsi_conn_bind, |
3602 | .destroy_conn = iscsi_conn_destroy, | 3626 | .destroy_conn = iscsi_conn_destroy, |
3603 | .set_param = iscsi_conn_set_param, | 3627 | .set_param = iscsi_conn_set_param, |
3604 | .get_param = iscsi_conn_get_param, | 3628 | .get_conn_param = iscsi_conn_get_param, |
3629 | .get_session_param = iscsi_session_get_param, | ||
3605 | .start_conn = iscsi_conn_start, | 3630 | .start_conn = iscsi_conn_start, |
3606 | .stop_conn = iscsi_conn_stop, | 3631 | .stop_conn = iscsi_conn_stop, |
3607 | .send_pdu = iscsi_conn_send_pdu, | 3632 | .send_pdu = iscsi_conn_send_pdu, |
@@ -3611,8 +3636,6 @@ static struct iscsi_transport iscsi_tcp_transport = { | |||
3611 | static int __init | 3636 | static int __init |
3612 | iscsi_tcp_init(void) | 3637 | iscsi_tcp_init(void) |
3613 | { | 3638 | { |
3614 | int error; | ||
3615 | |||
3616 | if (iscsi_max_lun < 1) { | 3639 | if (iscsi_max_lun < 1) { |
3617 | printk(KERN_ERR "Invalid max_lun value of %u\n", iscsi_max_lun); | 3640 | printk(KERN_ERR "Invalid max_lun value of %u\n", iscsi_max_lun); |
3618 | return -EINVAL; | 3641 | return -EINVAL; |
@@ -3625,11 +3648,10 @@ iscsi_tcp_init(void) | |||
3625 | if (!taskcache) | 3648 | if (!taskcache) |
3626 | return -ENOMEM; | 3649 | return -ENOMEM; |
3627 | 3650 | ||
3628 | error = iscsi_register_transport(&iscsi_tcp_transport); | 3651 | if (!iscsi_register_transport(&iscsi_tcp_transport)) |
3629 | if (error) | ||
3630 | kmem_cache_destroy(taskcache); | 3652 | kmem_cache_destroy(taskcache); |
3631 | 3653 | ||
3632 | return error; | 3654 | return 0; |
3633 | } | 3655 | } |
3634 | 3656 | ||
3635 | static void __exit | 3657 | static void __exit |
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 50ed88f98f46..45e31635a595 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c | |||
@@ -21,12 +21,9 @@ | |||
21 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 21 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
22 | */ | 22 | */ |
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/string.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/mempool.h> | 24 | #include <linux/mempool.h> |
27 | #include <linux/mutex.h> | 25 | #include <linux/mutex.h> |
28 | #include <net/tcp.h> | 26 | #include <net/tcp.h> |
29 | |||
30 | #include <scsi/scsi.h> | 27 | #include <scsi/scsi.h> |
31 | #include <scsi/scsi_host.h> | 28 | #include <scsi/scsi_host.h> |
32 | #include <scsi/scsi_device.h> | 29 | #include <scsi/scsi_device.h> |
@@ -46,11 +43,6 @@ struct iscsi_internal { | |||
46 | */ | 43 | */ |
47 | struct list_head sessions; | 44 | struct list_head sessions; |
48 | /* | 45 | /* |
49 | * lock to serialize access to the sessions list which must | ||
50 | * be taken after the rx_queue_mutex | ||
51 | */ | ||
52 | spinlock_t session_lock; | ||
53 | /* | ||
54 | * based on transport capabilities, at register time we set these | 46 | * based on transport capabilities, at register time we set these |
55 | * bits to tell the transport class it wants attributes displayed | 47 | * bits to tell the transport class it wants attributes displayed |
56 | * in sysfs or that it can support different iSCSI Data-Path | 48 | * in sysfs or that it can support different iSCSI Data-Path |
@@ -157,7 +149,7 @@ struct mempool_zone { | |||
157 | spinlock_t freelock; | 149 | spinlock_t freelock; |
158 | }; | 150 | }; |
159 | 151 | ||
160 | static struct mempool_zone z_reply; | 152 | static struct mempool_zone *z_reply; |
161 | 153 | ||
162 | /* | 154 | /* |
163 | * Z_MAX_* - actual mempool size allocated at the mempool_zone_init() time | 155 | * Z_MAX_* - actual mempool size allocated at the mempool_zone_init() time |
@@ -172,50 +164,270 @@ static struct mempool_zone z_reply; | |||
172 | #define Z_MAX_ERROR 16 | 164 | #define Z_MAX_ERROR 16 |
173 | #define Z_HIWAT_ERROR 12 | 165 | #define Z_HIWAT_ERROR 12 |
174 | 166 | ||
175 | struct iscsi_if_conn { | 167 | static LIST_HEAD(connlist); |
176 | struct list_head conn_list; /* item in connlist */ | 168 | static DEFINE_SPINLOCK(connlock); |
177 | struct list_head session_list; /* item in session->connections */ | ||
178 | iscsi_connh_t connh; | ||
179 | int active; /* must be accessed with the connlock */ | ||
180 | struct Scsi_Host *host; /* originated shost */ | ||
181 | struct device dev; /* sysfs transport/container device */ | ||
182 | struct iscsi_transport *transport; | ||
183 | struct mempool_zone z_error; | ||
184 | struct mempool_zone z_pdu; | ||
185 | struct list_head freequeue; | ||
186 | }; | ||
187 | 169 | ||
188 | #define iscsi_dev_to_if_conn(_dev) \ | 170 | /* |
189 | container_of(_dev, struct iscsi_if_conn, dev) | 171 | * The following functions can be used by LLDs that allocate |
172 | * their own scsi_hosts or by software iscsi LLDs | ||
173 | */ | ||
174 | static void iscsi_session_release(struct device *dev) | ||
175 | { | ||
176 | struct iscsi_cls_session *session = iscsi_dev_to_session(dev); | ||
177 | struct iscsi_transport *transport = session->transport; | ||
178 | struct Scsi_Host *shost; | ||
190 | 179 | ||
191 | #define iscsi_cdev_to_if_conn(_cdev) \ | 180 | shost = iscsi_session_to_shost(session); |
192 | iscsi_dev_to_if_conn(_cdev->dev) | 181 | scsi_host_put(shost); |
182 | kfree(session); | ||
183 | module_put(transport->owner); | ||
184 | } | ||
193 | 185 | ||
194 | static LIST_HEAD(connlist); | 186 | static int iscsi_is_session_dev(const struct device *dev) |
195 | static DEFINE_SPINLOCK(connlock); | 187 | { |
188 | return dev->release == iscsi_session_release; | ||
189 | } | ||
196 | 190 | ||
197 | struct iscsi_if_session { | 191 | /** |
198 | struct list_head list; /* item in session_list */ | 192 | * iscsi_create_session - create iscsi class session |
199 | struct list_head connections; | 193 | * @shost: scsi host |
200 | iscsi_sessionh_t sessionh; | 194 | * @transport: iscsi transport |
201 | struct iscsi_transport *transport; | 195 | * |
202 | struct device dev; /* sysfs transport/container device */ | 196 | * This can be called from a LLD or iscsi_transport |
203 | }; | 197 | **/ |
198 | struct iscsi_cls_session * | ||
199 | iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport) | ||
200 | { | ||
201 | struct iscsi_cls_session *session; | ||
202 | int err; | ||
203 | |||
204 | if (!try_module_get(transport->owner)) | ||
205 | return NULL; | ||
206 | |||
207 | session = kzalloc(sizeof(*session), GFP_KERNEL); | ||
208 | if (!session) | ||
209 | goto module_put; | ||
210 | session->transport = transport; | ||
211 | |||
212 | /* this is released in the dev's release function */ | ||
213 | scsi_host_get(shost); | ||
214 | snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", shost->host_no); | ||
215 | session->dev.parent = &shost->shost_gendev; | ||
216 | session->dev.release = iscsi_session_release; | ||
217 | err = device_register(&session->dev); | ||
218 | if (err) { | ||
219 | dev_printk(KERN_ERR, &session->dev, "iscsi: could not " | ||
220 | "register session's dev\n"); | ||
221 | goto free_session; | ||
222 | } | ||
223 | transport_register_device(&session->dev); | ||
224 | |||
225 | return session; | ||
226 | |||
227 | free_session: | ||
228 | kfree(session); | ||
229 | module_put: | ||
230 | module_put(transport->owner); | ||
231 | return NULL; | ||
232 | } | ||
233 | |||
234 | EXPORT_SYMBOL_GPL(iscsi_create_session); | ||
235 | |||
236 | /** | ||
237 | * iscsi_destroy_session - destroy iscsi session | ||
238 | * @session: iscsi_session | ||
239 | * | ||
240 | * Can be called by a LLD or iscsi_transport. There must not be | ||
241 | * any running connections. | ||
242 | **/ | ||
243 | int iscsi_destroy_session(struct iscsi_cls_session *session) | ||
244 | { | ||
245 | transport_unregister_device(&session->dev); | ||
246 | device_unregister(&session->dev); | ||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | EXPORT_SYMBOL_GPL(iscsi_destroy_session); | ||
251 | |||
252 | static void iscsi_conn_release(struct device *dev) | ||
253 | { | ||
254 | struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev); | ||
255 | struct device *parent = conn->dev.parent; | ||
256 | |||
257 | kfree(conn); | ||
258 | put_device(parent); | ||
259 | } | ||
260 | |||
261 | static int iscsi_is_conn_dev(const struct device *dev) | ||
262 | { | ||
263 | return dev->release == iscsi_conn_release; | ||
264 | } | ||
265 | |||
266 | /** | ||
267 | * iscsi_create_conn - create iscsi class connection | ||
268 | * @session: iscsi cls session | ||
269 | * @cid: connection id | ||
270 | * | ||
271 | * This can be called from a LLD or iscsi_transport. The connection | ||
272 | * is child of the session so cid must be unique for all connections | ||
273 | * on the session. | ||
274 | **/ | ||
275 | struct iscsi_cls_conn * | ||
276 | iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) | ||
277 | { | ||
278 | struct iscsi_transport *transport = session->transport; | ||
279 | struct Scsi_Host *shost = iscsi_session_to_shost(session); | ||
280 | struct iscsi_cls_conn *conn; | ||
281 | int err; | ||
282 | |||
283 | conn = kzalloc(sizeof(*conn) + transport->conndata_size, GFP_KERNEL); | ||
284 | if (!conn) | ||
285 | return NULL; | ||
286 | |||
287 | if (transport->conndata_size) | ||
288 | conn->dd_data = &conn[1]; | ||
289 | |||
290 | INIT_LIST_HEAD(&conn->conn_list); | ||
291 | conn->transport = transport; | ||
292 | |||
293 | /* this is released in the dev's release function */ | ||
294 | if (!get_device(&session->dev)) | ||
295 | goto free_conn; | ||
296 | snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u", | ||
297 | shost->host_no, cid); | ||
298 | conn->dev.parent = &session->dev; | ||
299 | conn->dev.release = iscsi_conn_release; | ||
300 | err = device_register(&conn->dev); | ||
301 | if (err) { | ||
302 | dev_printk(KERN_ERR, &conn->dev, "iscsi: could not register " | ||
303 | "connection's dev\n"); | ||
304 | goto release_parent_ref; | ||
305 | } | ||
306 | transport_register_device(&conn->dev); | ||
307 | return conn; | ||
308 | |||
309 | release_parent_ref: | ||
310 | put_device(&session->dev); | ||
311 | free_conn: | ||
312 | kfree(conn); | ||
313 | return NULL; | ||
314 | } | ||
315 | |||
316 | EXPORT_SYMBOL_GPL(iscsi_create_conn); | ||
317 | |||
318 | /** | ||
319 | * iscsi_destroy_conn - destroy iscsi class connection | ||
320 | * @session: iscsi cls session | ||
321 | * | ||
322 | * This can be called from a LLD or iscsi_transport. | ||
323 | **/ | ||
324 | int iscsi_destroy_conn(struct iscsi_cls_conn *conn) | ||
325 | { | ||
326 | transport_unregister_device(&conn->dev); | ||
327 | device_unregister(&conn->dev); | ||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | EXPORT_SYMBOL_GPL(iscsi_destroy_conn); | ||
332 | |||
333 | /* | ||
334 | * These functions are used only by software iscsi_transports | ||
335 | * which do not allocate and more their scsi_hosts since this | ||
336 | * is initiated from userspace. | ||
337 | */ | ||
338 | |||
339 | /* | ||
340 | * iSCSI Session's hostdata organization: | ||
341 | * | ||
342 | * *------------------* <== hostdata_session(host->hostdata) | ||
343 | * | ptr to class sess| | ||
344 | * |------------------| <== iscsi_hostdata(host->hostdata) | ||
345 | * | transport's data | | ||
346 | * *------------------* | ||
347 | */ | ||
348 | |||
349 | #define hostdata_privsize(_t) (sizeof(unsigned long) + _t->hostdata_size + \ | ||
350 | _t->hostdata_size % sizeof(unsigned long)) | ||
351 | |||
352 | #define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata)) | ||
353 | |||
354 | /** | ||
355 | * iscsi_transport_create_session - create iscsi cls session and host | ||
356 | * scsit: scsi transport template | ||
357 | * transport: iscsi transport template | ||
358 | * | ||
359 | * This can be used by software iscsi_transports that allocate | ||
360 | * a session per scsi host. | ||
361 | **/ | ||
362 | struct Scsi_Host * | ||
363 | iscsi_transport_create_session(struct scsi_transport_template *scsit, | ||
364 | struct iscsi_transport *transport) | ||
365 | { | ||
366 | struct iscsi_cls_session *session; | ||
367 | struct Scsi_Host *shost; | ||
368 | |||
369 | shost = scsi_host_alloc(transport->host_template, | ||
370 | hostdata_privsize(transport)); | ||
371 | if (!shost) { | ||
372 | printk(KERN_ERR "iscsi: can not allocate SCSI host for " | ||
373 | "session\n"); | ||
374 | return NULL; | ||
375 | } | ||
376 | |||
377 | shost->max_id = 1; | ||
378 | shost->max_channel = 0; | ||
379 | shost->max_lun = transport->max_lun; | ||
380 | shost->max_cmd_len = transport->max_cmd_len; | ||
381 | shost->transportt = scsit; | ||
382 | |||
383 | if (scsi_add_host(shost, NULL)) | ||
384 | goto free_host; | ||
385 | |||
386 | session = iscsi_create_session(shost, transport); | ||
387 | if (!session) | ||
388 | goto remove_host; | ||
204 | 389 | ||
205 | #define iscsi_dev_to_if_session(_dev) \ | 390 | *(unsigned long*)shost->hostdata = (unsigned long)session; |
206 | container_of(_dev, struct iscsi_if_session, dev) | 391 | return shost; |
392 | |||
393 | remove_host: | ||
394 | scsi_remove_host(shost); | ||
395 | free_host: | ||
396 | scsi_host_put(shost); | ||
397 | return NULL; | ||
398 | } | ||
207 | 399 | ||
208 | #define iscsi_cdev_to_if_session(_cdev) \ | 400 | EXPORT_SYMBOL_GPL(iscsi_transport_create_session); |
209 | iscsi_dev_to_if_session(_cdev->dev) | ||
210 | 401 | ||
211 | #define iscsi_if_session_to_shost(_session) \ | 402 | /** |
212 | dev_to_shost(_session->dev.parent) | 403 | * iscsi_transport_destroy_session - destroy session and scsi host |
404 | * shost: scsi host | ||
405 | * | ||
406 | * This can be used by software iscsi_transports that allocate | ||
407 | * a session per scsi host. | ||
408 | **/ | ||
409 | int iscsi_transport_destroy_session(struct Scsi_Host *shost) | ||
410 | { | ||
411 | struct iscsi_cls_session *session; | ||
213 | 412 | ||
214 | static struct iscsi_if_conn* | 413 | scsi_remove_host(shost); |
414 | session = hostdata_session(shost->hostdata); | ||
415 | iscsi_destroy_session(session); | ||
416 | /* ref from host alloc */ | ||
417 | scsi_host_put(shost); | ||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | EXPORT_SYMBOL_GPL(iscsi_transport_destroy_session); | ||
422 | |||
423 | /* | ||
424 | * iscsi interface functions | ||
425 | */ | ||
426 | static struct iscsi_cls_conn* | ||
215 | iscsi_if_find_conn(uint64_t key) | 427 | iscsi_if_find_conn(uint64_t key) |
216 | { | 428 | { |
217 | unsigned long flags; | 429 | unsigned long flags; |
218 | struct iscsi_if_conn *conn; | 430 | struct iscsi_cls_conn *conn; |
219 | 431 | ||
220 | spin_lock_irqsave(&connlock, flags); | 432 | spin_lock_irqsave(&connlock, flags); |
221 | list_for_each_entry(conn, &connlist, conn_list) | 433 | list_for_each_entry(conn, &connlist, conn_list) |
@@ -250,7 +462,7 @@ static inline struct list_head *skb_to_lh(struct sk_buff *skb) | |||
250 | } | 462 | } |
251 | 463 | ||
252 | static void* | 464 | static void* |
253 | mempool_zone_alloc_skb(gfp_t gfp_mask, void *pool_data) | 465 | mempool_zone_alloc_skb(unsigned int gfp_mask, void *pool_data) |
254 | { | 466 | { |
255 | struct mempool_zone *zone = pool_data; | 467 | struct mempool_zone *zone = pool_data; |
256 | 468 | ||
@@ -282,14 +494,21 @@ mempool_zone_complete(struct mempool_zone *zone) | |||
282 | spin_unlock_irqrestore(&zone->freelock, flags); | 494 | spin_unlock_irqrestore(&zone->freelock, flags); |
283 | } | 495 | } |
284 | 496 | ||
285 | static int | 497 | static struct mempool_zone * |
286 | mempool_zone_init(struct mempool_zone *zp, unsigned max, unsigned size, | 498 | mempool_zone_init(unsigned max, unsigned size, unsigned hiwat) |
287 | unsigned hiwat) | ||
288 | { | 499 | { |
500 | struct mempool_zone *zp; | ||
501 | |||
502 | zp = kzalloc(sizeof(*zp), GFP_KERNEL); | ||
503 | if (!zp) | ||
504 | return NULL; | ||
505 | |||
289 | zp->pool = mempool_create(max, mempool_zone_alloc_skb, | 506 | zp->pool = mempool_create(max, mempool_zone_alloc_skb, |
290 | mempool_zone_free_skb, zp); | 507 | mempool_zone_free_skb, zp); |
291 | if (!zp->pool) | 508 | if (!zp->pool) { |
292 | return -ENOMEM; | 509 | kfree(zp); |
510 | return NULL; | ||
511 | } | ||
293 | 512 | ||
294 | zp->size = size; | 513 | zp->size = size; |
295 | zp->hiwat = hiwat; | 514 | zp->hiwat = hiwat; |
@@ -298,9 +517,14 @@ mempool_zone_init(struct mempool_zone *zp, unsigned max, unsigned size, | |||
298 | spin_lock_init(&zp->freelock); | 517 | spin_lock_init(&zp->freelock); |
299 | atomic_set(&zp->allocated, 0); | 518 | atomic_set(&zp->allocated, 0); |
300 | 519 | ||
301 | return 0; | 520 | return zp; |
302 | } | 521 | } |
303 | 522 | ||
523 | static void mempool_zone_destroy(struct mempool_zone *zp) | ||
524 | { | ||
525 | mempool_destroy(zp->pool); | ||
526 | kfree(zp); | ||
527 | } | ||
304 | 528 | ||
305 | static struct sk_buff* | 529 | static struct sk_buff* |
306 | mempool_zone_get_skb(struct mempool_zone *zone) | 530 | mempool_zone_get_skb(struct mempool_zone *zone) |
@@ -340,7 +564,7 @@ int iscsi_recv_pdu(iscsi_connh_t connh, struct iscsi_hdr *hdr, | |||
340 | struct nlmsghdr *nlh; | 564 | struct nlmsghdr *nlh; |
341 | struct sk_buff *skb; | 565 | struct sk_buff *skb; |
342 | struct iscsi_uevent *ev; | 566 | struct iscsi_uevent *ev; |
343 | struct iscsi_if_conn *conn; | 567 | struct iscsi_cls_conn *conn; |
344 | char *pdu; | 568 | char *pdu; |
345 | int len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct iscsi_hdr) + | 569 | int len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct iscsi_hdr) + |
346 | data_size); | 570 | data_size); |
@@ -348,13 +572,13 @@ int iscsi_recv_pdu(iscsi_connh_t connh, struct iscsi_hdr *hdr, | |||
348 | conn = iscsi_if_find_conn(connh); | 572 | conn = iscsi_if_find_conn(connh); |
349 | BUG_ON(!conn); | 573 | BUG_ON(!conn); |
350 | 574 | ||
351 | mempool_zone_complete(&conn->z_pdu); | 575 | mempool_zone_complete(conn->z_pdu); |
352 | 576 | ||
353 | skb = mempool_zone_get_skb(&conn->z_pdu); | 577 | skb = mempool_zone_get_skb(conn->z_pdu); |
354 | if (!skb) { | 578 | if (!skb) { |
355 | iscsi_conn_error(connh, ISCSI_ERR_CONN_FAILED); | 579 | iscsi_conn_error(connh, ISCSI_ERR_CONN_FAILED); |
356 | printk(KERN_ERR "iscsi%d: can not deliver control PDU: OOM\n", | 580 | dev_printk(KERN_ERR, &conn->dev, "iscsi: can not deliver " |
357 | conn->host->host_no); | 581 | "control PDU: OOM\n"); |
358 | return -ENOMEM; | 582 | return -ENOMEM; |
359 | } | 583 | } |
360 | 584 | ||
@@ -363,14 +587,14 @@ int iscsi_recv_pdu(iscsi_connh_t connh, struct iscsi_hdr *hdr, | |||
363 | memset(ev, 0, sizeof(*ev)); | 587 | memset(ev, 0, sizeof(*ev)); |
364 | ev->transport_handle = iscsi_handle(conn->transport); | 588 | ev->transport_handle = iscsi_handle(conn->transport); |
365 | ev->type = ISCSI_KEVENT_RECV_PDU; | 589 | ev->type = ISCSI_KEVENT_RECV_PDU; |
366 | if (atomic_read(&conn->z_pdu.allocated) >= conn->z_pdu.hiwat) | 590 | if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat) |
367 | ev->iferror = -ENOMEM; | 591 | ev->iferror = -ENOMEM; |
368 | ev->r.recv_req.conn_handle = connh; | 592 | ev->r.recv_req.conn_handle = connh; |
369 | pdu = (char*)ev + sizeof(*ev); | 593 | pdu = (char*)ev + sizeof(*ev); |
370 | memcpy(pdu, hdr, sizeof(struct iscsi_hdr)); | 594 | memcpy(pdu, hdr, sizeof(struct iscsi_hdr)); |
371 | memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size); | 595 | memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size); |
372 | 596 | ||
373 | return iscsi_unicast_skb(&conn->z_pdu, skb); | 597 | return iscsi_unicast_skb(conn->z_pdu, skb); |
374 | } | 598 | } |
375 | EXPORT_SYMBOL_GPL(iscsi_recv_pdu); | 599 | EXPORT_SYMBOL_GPL(iscsi_recv_pdu); |
376 | 600 | ||
@@ -379,18 +603,18 @@ void iscsi_conn_error(iscsi_connh_t connh, enum iscsi_err error) | |||
379 | struct nlmsghdr *nlh; | 603 | struct nlmsghdr *nlh; |
380 | struct sk_buff *skb; | 604 | struct sk_buff *skb; |
381 | struct iscsi_uevent *ev; | 605 | struct iscsi_uevent *ev; |
382 | struct iscsi_if_conn *conn; | 606 | struct iscsi_cls_conn *conn; |
383 | int len = NLMSG_SPACE(sizeof(*ev)); | 607 | int len = NLMSG_SPACE(sizeof(*ev)); |
384 | 608 | ||
385 | conn = iscsi_if_find_conn(connh); | 609 | conn = iscsi_if_find_conn(connh); |
386 | BUG_ON(!conn); | 610 | BUG_ON(!conn); |
387 | 611 | ||
388 | mempool_zone_complete(&conn->z_error); | 612 | mempool_zone_complete(conn->z_error); |
389 | 613 | ||
390 | skb = mempool_zone_get_skb(&conn->z_error); | 614 | skb = mempool_zone_get_skb(conn->z_error); |
391 | if (!skb) { | 615 | if (!skb) { |
392 | printk(KERN_ERR "iscsi%d: gracefully ignored conn error (%d)\n", | 616 | dev_printk(KERN_ERR, &conn->dev, "iscsi: gracefully ignored " |
393 | conn->host->host_no, error); | 617 | "conn error (%d)\n", error); |
394 | return; | 618 | return; |
395 | } | 619 | } |
396 | 620 | ||
@@ -398,15 +622,15 @@ void iscsi_conn_error(iscsi_connh_t connh, enum iscsi_err error) | |||
398 | ev = NLMSG_DATA(nlh); | 622 | ev = NLMSG_DATA(nlh); |
399 | ev->transport_handle = iscsi_handle(conn->transport); | 623 | ev->transport_handle = iscsi_handle(conn->transport); |
400 | ev->type = ISCSI_KEVENT_CONN_ERROR; | 624 | ev->type = ISCSI_KEVENT_CONN_ERROR; |
401 | if (atomic_read(&conn->z_error.allocated) >= conn->z_error.hiwat) | 625 | if (atomic_read(&conn->z_error->allocated) >= conn->z_error->hiwat) |
402 | ev->iferror = -ENOMEM; | 626 | ev->iferror = -ENOMEM; |
403 | ev->r.connerror.error = error; | 627 | ev->r.connerror.error = error; |
404 | ev->r.connerror.conn_handle = connh; | 628 | ev->r.connerror.conn_handle = connh; |
405 | 629 | ||
406 | iscsi_unicast_skb(&conn->z_error, skb); | 630 | iscsi_unicast_skb(conn->z_error, skb); |
407 | 631 | ||
408 | printk(KERN_INFO "iscsi%d: detected conn error (%d)\n", | 632 | dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n", |
409 | conn->host->host_no, error); | 633 | error); |
410 | } | 634 | } |
411 | EXPORT_SYMBOL_GPL(iscsi_conn_error); | 635 | EXPORT_SYMBOL_GPL(iscsi_conn_error); |
412 | 636 | ||
@@ -420,9 +644,9 @@ iscsi_if_send_reply(int pid, int seq, int type, int done, int multi, | |||
420 | int flags = multi ? NLM_F_MULTI : 0; | 644 | int flags = multi ? NLM_F_MULTI : 0; |
421 | int t = done ? NLMSG_DONE : type; | 645 | int t = done ? NLMSG_DONE : type; |
422 | 646 | ||
423 | mempool_zone_complete(&z_reply); | 647 | mempool_zone_complete(z_reply); |
424 | 648 | ||
425 | skb = mempool_zone_get_skb(&z_reply); | 649 | skb = mempool_zone_get_skb(z_reply); |
426 | /* | 650 | /* |
427 | * FIXME: | 651 | * FIXME: |
428 | * user is supposed to react on iferror == -ENOMEM; | 652 | * user is supposed to react on iferror == -ENOMEM; |
@@ -433,366 +657,197 @@ iscsi_if_send_reply(int pid, int seq, int type, int done, int multi, | |||
433 | nlh = __nlmsg_put(skb, pid, seq, t, (len - sizeof(*nlh)), 0); | 657 | nlh = __nlmsg_put(skb, pid, seq, t, (len - sizeof(*nlh)), 0); |
434 | nlh->nlmsg_flags = flags; | 658 | nlh->nlmsg_flags = flags; |
435 | memcpy(NLMSG_DATA(nlh), payload, size); | 659 | memcpy(NLMSG_DATA(nlh), payload, size); |
436 | return iscsi_unicast_skb(&z_reply, skb); | 660 | return iscsi_unicast_skb(z_reply, skb); |
437 | } | 661 | } |
438 | 662 | ||
439 | /* | 663 | static int |
440 | * iSCSI Session's hostdata organization: | 664 | iscsi_if_get_stats(struct iscsi_transport *transport, struct sk_buff *skb, |
441 | * | 665 | struct nlmsghdr *nlh) |
442 | * *------------------* <== host->hostdata | 666 | { |
443 | * | transport | | 667 | struct iscsi_uevent *ev = NLMSG_DATA(nlh); |
444 | * |------------------| <== iscsi_hostdata(host->hostdata) | 668 | struct iscsi_stats *stats; |
445 | * | transport's data | | 669 | struct sk_buff *skbstat; |
446 | * |------------------| <== hostdata_session(host->hostdata) | 670 | struct iscsi_cls_conn *conn; |
447 | * | interface's data | | 671 | struct nlmsghdr *nlhstat; |
448 | * *------------------* | 672 | struct iscsi_uevent *evstat; |
449 | */ | 673 | int len = NLMSG_SPACE(sizeof(*ev) + |
674 | sizeof(struct iscsi_stats) + | ||
675 | sizeof(struct iscsi_stats_custom) * | ||
676 | ISCSI_STATS_CUSTOM_MAX); | ||
677 | int err = 0; | ||
450 | 678 | ||
451 | #define hostdata_privsize(_t) (sizeof(unsigned long) + _t->hostdata_size + \ | 679 | conn = iscsi_if_find_conn(ev->u.get_stats.conn_handle); |
452 | _t->hostdata_size % sizeof(unsigned long) + \ | 680 | if (!conn) |
453 | sizeof(struct iscsi_if_session)) | 681 | return -EEXIST; |
454 | 682 | ||
455 | #define hostdata_session(_hostdata) ((void*)_hostdata + sizeof(unsigned long) + \ | 683 | do { |
456 | ((struct iscsi_transport *) \ | 684 | int actual_size; |
457 | iscsi_ptr(*(uint64_t *)_hostdata))->hostdata_size) | ||
458 | 685 | ||
459 | static void iscsi_if_session_dev_release(struct device *dev) | 686 | mempool_zone_complete(conn->z_pdu); |
460 | { | ||
461 | struct iscsi_if_session *session = iscsi_dev_to_if_session(dev); | ||
462 | struct iscsi_transport *transport = session->transport; | ||
463 | struct Scsi_Host *shost = iscsi_if_session_to_shost(session); | ||
464 | struct iscsi_if_conn *conn, *tmp; | ||
465 | unsigned long flags; | ||
466 | 687 | ||
467 | /* now free connections */ | 688 | skbstat = mempool_zone_get_skb(conn->z_pdu); |
468 | spin_lock_irqsave(&connlock, flags); | 689 | if (!skbstat) { |
469 | list_for_each_entry_safe(conn, tmp, &session->connections, | 690 | dev_printk(KERN_ERR, &conn->dev, "iscsi: can not " |
470 | session_list) { | 691 | "deliver stats: OOM\n"); |
471 | list_del(&conn->session_list); | 692 | return -ENOMEM; |
472 | mempool_destroy(conn->z_pdu.pool); | 693 | } |
473 | mempool_destroy(conn->z_error.pool); | 694 | |
474 | kfree(conn); | 695 | nlhstat = __nlmsg_put(skbstat, daemon_pid, 0, 0, |
475 | } | 696 | (len - sizeof(*nlhstat)), 0); |
476 | spin_unlock_irqrestore(&connlock, flags); | 697 | evstat = NLMSG_DATA(nlhstat); |
477 | scsi_host_put(shost); | 698 | memset(evstat, 0, sizeof(*evstat)); |
478 | module_put(transport->owner); | 699 | evstat->transport_handle = iscsi_handle(conn->transport); |
700 | evstat->type = nlh->nlmsg_type; | ||
701 | if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat) | ||
702 | evstat->iferror = -ENOMEM; | ||
703 | evstat->u.get_stats.conn_handle = | ||
704 | ev->u.get_stats.conn_handle; | ||
705 | stats = (struct iscsi_stats *) | ||
706 | ((char*)evstat + sizeof(*evstat)); | ||
707 | memset(stats, 0, sizeof(*stats)); | ||
708 | |||
709 | transport->get_stats(ev->u.get_stats.conn_handle, stats); | ||
710 | actual_size = NLMSG_SPACE(sizeof(struct iscsi_uevent) + | ||
711 | sizeof(struct iscsi_stats) + | ||
712 | sizeof(struct iscsi_stats_custom) * | ||
713 | stats->custom_length); | ||
714 | actual_size -= sizeof(*nlhstat); | ||
715 | actual_size = NLMSG_LENGTH(actual_size); | ||
716 | skb_trim(skb, NLMSG_ALIGN(actual_size)); | ||
717 | nlhstat->nlmsg_len = actual_size; | ||
718 | |||
719 | err = iscsi_unicast_skb(conn->z_pdu, skbstat); | ||
720 | } while (err < 0 && err != -ECONNREFUSED); | ||
721 | |||
722 | return err; | ||
479 | } | 723 | } |
480 | 724 | ||
481 | static int | 725 | static int |
482 | iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev) | 726 | iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev) |
483 | { | 727 | { |
484 | struct iscsi_transport *transport = priv->iscsi_transport; | 728 | struct iscsi_transport *transport = priv->iscsi_transport; |
485 | struct iscsi_if_session *session; | ||
486 | struct Scsi_Host *shost; | 729 | struct Scsi_Host *shost; |
487 | unsigned long flags; | ||
488 | int error; | ||
489 | |||
490 | if (!try_module_get(transport->owner)) | ||
491 | return -EPERM; | ||
492 | 730 | ||
493 | shost = scsi_host_alloc(transport->host_template, | 731 | if (!transport->create_session) |
494 | hostdata_privsize(transport)); | 732 | return -EINVAL; |
495 | if (!shost) { | ||
496 | ev->r.c_session_ret.session_handle = iscsi_handle(NULL); | ||
497 | printk(KERN_ERR "iscsi: can not allocate SCSI host for " | ||
498 | "session\n"); | ||
499 | error = -ENOMEM; | ||
500 | goto out_module_put; | ||
501 | } | ||
502 | shost->max_id = 1; | ||
503 | shost->max_channel = 0; | ||
504 | shost->max_lun = transport->max_lun; | ||
505 | shost->max_cmd_len = transport->max_cmd_len; | ||
506 | shost->transportt = &priv->t; | ||
507 | |||
508 | /* store struct iscsi_transport in hostdata */ | ||
509 | *(uint64_t*)shost->hostdata = ev->transport_handle; | ||
510 | 733 | ||
511 | ev->r.c_session_ret.session_handle = transport->create_session( | 734 | shost = transport->create_session(&priv->t, |
512 | ev->u.c_session.initial_cmdsn, shost); | 735 | ev->u.c_session.initial_cmdsn); |
513 | if (ev->r.c_session_ret.session_handle == iscsi_handle(NULL)) { | 736 | if (!shost) |
514 | error = 0; | 737 | return -ENOMEM; |
515 | goto out_host_put; | ||
516 | } | ||
517 | 738 | ||
518 | /* host_no becomes assigned SID */ | 739 | ev->r.c_session_ret.session_handle = iscsi_handle(iscsi_hostdata(shost->hostdata)); |
519 | ev->r.c_session_ret.sid = shost->host_no; | 740 | ev->r.c_session_ret.sid = shost->host_no; |
520 | /* initialize session */ | ||
521 | session = hostdata_session(shost->hostdata); | ||
522 | INIT_LIST_HEAD(&session->connections); | ||
523 | INIT_LIST_HEAD(&session->list); | ||
524 | session->sessionh = ev->r.c_session_ret.session_handle; | ||
525 | session->transport = transport; | ||
526 | |||
527 | error = scsi_add_host(shost, NULL); | ||
528 | if (error) | ||
529 | goto out_destroy_session; | ||
530 | |||
531 | /* | ||
532 | * this is released in the dev's release function) | ||
533 | */ | ||
534 | scsi_host_get(shost); | ||
535 | snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", shost->host_no); | ||
536 | session->dev.parent = &shost->shost_gendev; | ||
537 | session->dev.release = iscsi_if_session_dev_release; | ||
538 | error = device_register(&session->dev); | ||
539 | if (error) { | ||
540 | printk(KERN_ERR "iscsi: could not register session%d's dev\n", | ||
541 | shost->host_no); | ||
542 | goto out_remove_host; | ||
543 | } | ||
544 | transport_register_device(&session->dev); | ||
545 | |||
546 | /* add this session to the list of active sessions */ | ||
547 | spin_lock_irqsave(&priv->session_lock, flags); | ||
548 | list_add(&session->list, &priv->sessions); | ||
549 | spin_unlock_irqrestore(&priv->session_lock, flags); | ||
550 | |||
551 | return 0; | 741 | return 0; |
552 | |||
553 | out_remove_host: | ||
554 | scsi_remove_host(shost); | ||
555 | out_destroy_session: | ||
556 | transport->destroy_session(ev->r.c_session_ret.session_handle); | ||
557 | ev->r.c_session_ret.session_handle = iscsi_handle(NULL); | ||
558 | out_host_put: | ||
559 | scsi_host_put(shost); | ||
560 | out_module_put: | ||
561 | module_put(transport->owner); | ||
562 | return error; | ||
563 | } | 742 | } |
564 | 743 | ||
565 | static int | 744 | static int |
566 | iscsi_if_destroy_session(struct iscsi_internal *priv, struct iscsi_uevent *ev) | 745 | iscsi_if_destroy_session(struct iscsi_internal *priv, struct iscsi_uevent *ev) |
567 | { | 746 | { |
568 | struct iscsi_transport *transport = priv->iscsi_transport; | 747 | struct iscsi_transport *transport = priv->iscsi_transport; |
748 | |||
569 | struct Scsi_Host *shost; | 749 | struct Scsi_Host *shost; |
570 | struct iscsi_if_session *session; | 750 | |
571 | unsigned long flags; | 751 | if (!transport->destroy_session) |
572 | struct iscsi_if_conn *conn; | 752 | return -EINVAL; |
573 | int error = 0; | ||
574 | 753 | ||
575 | shost = scsi_host_lookup(ev->u.d_session.sid); | 754 | shost = scsi_host_lookup(ev->u.d_session.sid); |
576 | if (shost == ERR_PTR(-ENXIO)) | 755 | if (shost == ERR_PTR(-ENXIO)) |
577 | return -EEXIST; | 756 | return -EEXIST; |
578 | session = hostdata_session(shost->hostdata); | ||
579 | 757 | ||
580 | /* check if we have active connections */ | 758 | if (transport->destroy_session) |
581 | spin_lock_irqsave(&connlock, flags); | 759 | transport->destroy_session(shost); |
582 | list_for_each_entry(conn, &session->connections, session_list) { | 760 | /* ref from host lookup */ |
583 | if (conn->active) { | 761 | scsi_host_put(shost); |
584 | printk(KERN_ERR "iscsi%d: can not destroy session: " | 762 | return 0; |
585 | "has active connection (%p)\n", | ||
586 | shost->host_no, iscsi_ptr(conn->connh)); | ||
587 | spin_unlock_irqrestore(&connlock, flags); | ||
588 | error = EIO; | ||
589 | goto out_release_ref; | ||
590 | } | ||
591 | } | ||
592 | spin_unlock_irqrestore(&connlock, flags); | ||
593 | |||
594 | scsi_remove_host(shost); | ||
595 | transport->destroy_session(ev->u.d_session.session_handle); | ||
596 | transport_unregister_device(&session->dev); | ||
597 | device_unregister(&session->dev); | ||
598 | |||
599 | /* remove this session from the list of active sessions */ | ||
600 | spin_lock_irqsave(&priv->session_lock, flags); | ||
601 | list_del(&session->list); | ||
602 | spin_unlock_irqrestore(&priv->session_lock, flags); | ||
603 | |||
604 | /* ref from host alloc */ | ||
605 | scsi_host_put(shost); | ||
606 | out_release_ref: | ||
607 | /* ref from host lookup */ | ||
608 | scsi_host_put(shost); | ||
609 | return error; | ||
610 | } | ||
611 | |||
612 | static void iscsi_if_conn_dev_release(struct device *dev) | ||
613 | { | ||
614 | struct iscsi_if_conn *conn = iscsi_dev_to_if_conn(dev); | ||
615 | struct Scsi_Host *shost = conn->host; | ||
616 | |||
617 | scsi_host_put(shost); | ||
618 | } | 763 | } |
619 | 764 | ||
620 | static int | 765 | static int |
621 | iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) | 766 | iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev){ |
622 | { | ||
623 | struct iscsi_if_session *session; | ||
624 | struct Scsi_Host *shost; | 767 | struct Scsi_Host *shost; |
625 | struct iscsi_if_conn *conn; | 768 | struct iscsi_cls_conn *conn; |
626 | unsigned long flags; | 769 | unsigned long flags; |
627 | int error; | 770 | |
771 | if (!transport->create_conn) | ||
772 | return -EINVAL; | ||
628 | 773 | ||
629 | shost = scsi_host_lookup(ev->u.c_conn.sid); | 774 | shost = scsi_host_lookup(ev->u.c_conn.sid); |
630 | if (shost == ERR_PTR(-ENXIO)) | 775 | if (shost == ERR_PTR(-ENXIO)) |
631 | return -EEXIST; | 776 | return -EEXIST; |
632 | session = hostdata_session(shost->hostdata); | ||
633 | 777 | ||
634 | conn = kmalloc(sizeof(struct iscsi_if_conn), GFP_KERNEL); | 778 | conn = transport->create_conn(shost, ev->u.c_conn.cid); |
635 | if (!conn) { | 779 | if (!conn) |
636 | error = -ENOMEM; | 780 | goto release_ref; |
637 | goto out_release_ref; | ||
638 | } | ||
639 | memset(conn, 0, sizeof(struct iscsi_if_conn)); | ||
640 | INIT_LIST_HEAD(&conn->session_list); | ||
641 | INIT_LIST_HEAD(&conn->conn_list); | ||
642 | conn->host = shost; | ||
643 | conn->transport = transport; | ||
644 | 781 | ||
645 | error = mempool_zone_init(&conn->z_pdu, Z_MAX_PDU, | 782 | conn->z_pdu = mempool_zone_init(Z_MAX_PDU, |
646 | NLMSG_SPACE(sizeof(struct iscsi_uevent) + | 783 | NLMSG_SPACE(sizeof(struct iscsi_uevent) + |
647 | sizeof(struct iscsi_hdr) + | 784 | sizeof(struct iscsi_hdr) + |
648 | DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH), | 785 | DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH), |
649 | Z_HIWAT_PDU); | 786 | Z_HIWAT_PDU); |
650 | if (error) { | 787 | if (!conn->z_pdu) { |
651 | printk(KERN_ERR "iscsi%d: can not allocate pdu zone for new " | 788 | dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate " |
652 | "conn\n", shost->host_no); | 789 | "pdu zone for new conn\n"); |
653 | goto out_free_conn; | 790 | goto destroy_conn; |
654 | } | 791 | } |
655 | error = mempool_zone_init(&conn->z_error, Z_MAX_ERROR, | 792 | |
793 | conn->z_error = mempool_zone_init(Z_MAX_ERROR, | ||
656 | NLMSG_SPACE(sizeof(struct iscsi_uevent)), | 794 | NLMSG_SPACE(sizeof(struct iscsi_uevent)), |
657 | Z_HIWAT_ERROR); | 795 | Z_HIWAT_ERROR); |
658 | if (error) { | 796 | if (!conn->z_error) { |
659 | printk(KERN_ERR "iscsi%d: can not allocate error zone for " | 797 | dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate " |
660 | "new conn\n", shost->host_no); | 798 | "error zone for new conn\n"); |
661 | goto out_free_pdu_pool; | 799 | goto free_pdu_pool; |
662 | } | ||
663 | |||
664 | ev->r.handle = transport->create_conn(ev->u.c_conn.session_handle, | ||
665 | ev->u.c_conn.cid); | ||
666 | if (!ev->r.handle) { | ||
667 | error = -ENODEV; | ||
668 | goto out_free_error_pool; | ||
669 | } | 800 | } |
670 | 801 | ||
671 | conn->connh = ev->r.handle; | 802 | ev->r.handle = conn->connh = iscsi_handle(conn->dd_data); |
672 | |||
673 | /* | ||
674 | * this is released in the dev's release function | ||
675 | */ | ||
676 | if (!scsi_host_get(shost)) | ||
677 | goto out_destroy_conn; | ||
678 | snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u", | ||
679 | shost->host_no, ev->u.c_conn.cid); | ||
680 | conn->dev.parent = &session->dev; | ||
681 | conn->dev.release = iscsi_if_conn_dev_release; | ||
682 | error = device_register(&conn->dev); | ||
683 | if (error) { | ||
684 | printk(KERN_ERR "iscsi%d: could not register connections%u " | ||
685 | "dev\n", shost->host_no, ev->u.c_conn.cid); | ||
686 | goto out_release_parent_ref; | ||
687 | } | ||
688 | transport_register_device(&conn->dev); | ||
689 | 803 | ||
690 | spin_lock_irqsave(&connlock, flags); | 804 | spin_lock_irqsave(&connlock, flags); |
691 | list_add(&conn->conn_list, &connlist); | 805 | list_add(&conn->conn_list, &connlist); |
692 | list_add(&conn->session_list, &session->connections); | ||
693 | conn->active = 1; | 806 | conn->active = 1; |
694 | spin_unlock_irqrestore(&connlock, flags); | 807 | spin_unlock_irqrestore(&connlock, flags); |
695 | 808 | ||
696 | scsi_host_put(shost); | 809 | scsi_host_put(shost); |
697 | return 0; | 810 | return 0; |
698 | 811 | ||
699 | out_release_parent_ref: | 812 | free_pdu_pool: |
813 | mempool_zone_destroy(conn->z_pdu); | ||
814 | destroy_conn: | ||
815 | if (transport->destroy_conn) | ||
816 | transport->destroy_conn(conn->dd_data); | ||
817 | release_ref: | ||
700 | scsi_host_put(shost); | 818 | scsi_host_put(shost); |
701 | out_destroy_conn: | 819 | return -ENOMEM; |
702 | transport->destroy_conn(ev->r.handle); | ||
703 | out_free_error_pool: | ||
704 | mempool_destroy(conn->z_error.pool); | ||
705 | out_free_pdu_pool: | ||
706 | mempool_destroy(conn->z_pdu.pool); | ||
707 | out_free_conn: | ||
708 | kfree(conn); | ||
709 | out_release_ref: | ||
710 | scsi_host_put(shost); | ||
711 | return error; | ||
712 | } | 820 | } |
713 | 821 | ||
714 | static int | 822 | static int |
715 | iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) | 823 | iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) |
716 | { | 824 | { |
717 | unsigned long flags; | 825 | unsigned long flags; |
718 | struct iscsi_if_conn *conn; | 826 | struct iscsi_cls_conn *conn; |
827 | struct mempool_zone *z_error, *z_pdu; | ||
719 | 828 | ||
720 | conn = iscsi_if_find_conn(ev->u.d_conn.conn_handle); | 829 | conn = iscsi_if_find_conn(ev->u.d_conn.conn_handle); |
721 | if (!conn) | 830 | if (!conn) |
722 | return -EEXIST; | 831 | return -EEXIST; |
723 | 832 | ||
724 | transport->destroy_conn(ev->u.d_conn.conn_handle); | 833 | if (!transport->destroy_conn) |
834 | return -EINVAL; | ||
725 | 835 | ||
726 | spin_lock_irqsave(&connlock, flags); | 836 | spin_lock_irqsave(&connlock, flags); |
727 | conn->active = 0; | 837 | conn->active = 0; |
728 | list_del(&conn->conn_list); | 838 | list_del(&conn->conn_list); |
729 | spin_unlock_irqrestore(&connlock, flags); | 839 | spin_unlock_irqrestore(&connlock, flags); |
730 | 840 | ||
731 | transport_unregister_device(&conn->dev); | 841 | z_pdu = conn->z_pdu; |
732 | device_unregister(&conn->dev); | 842 | z_error = conn->z_error; |
733 | return 0; | ||
734 | } | ||
735 | |||
736 | static int | ||
737 | iscsi_if_get_stats(struct iscsi_transport *transport, struct sk_buff *skb, | ||
738 | struct nlmsghdr *nlh) | ||
739 | { | ||
740 | struct iscsi_uevent *ev = NLMSG_DATA(nlh); | ||
741 | struct iscsi_stats *stats; | ||
742 | struct sk_buff *skbstat; | ||
743 | struct iscsi_if_conn *conn; | ||
744 | struct nlmsghdr *nlhstat; | ||
745 | struct iscsi_uevent *evstat; | ||
746 | int len = NLMSG_SPACE(sizeof(*ev) + | ||
747 | sizeof(struct iscsi_stats) + | ||
748 | sizeof(struct iscsi_stats_custom) * | ||
749 | ISCSI_STATS_CUSTOM_MAX); | ||
750 | int err = 0; | ||
751 | |||
752 | conn = iscsi_if_find_conn(ev->u.get_stats.conn_handle); | ||
753 | if (!conn) | ||
754 | return -EEXIST; | ||
755 | |||
756 | do { | ||
757 | int actual_size; | ||
758 | |||
759 | mempool_zone_complete(&conn->z_pdu); | ||
760 | |||
761 | skbstat = mempool_zone_get_skb(&conn->z_pdu); | ||
762 | if (!skbstat) { | ||
763 | printk(KERN_ERR "iscsi%d: can not deliver stats: OOM\n", | ||
764 | conn->host->host_no); | ||
765 | return -ENOMEM; | ||
766 | } | ||
767 | |||
768 | nlhstat = __nlmsg_put(skbstat, daemon_pid, 0, 0, | ||
769 | (len - sizeof(*nlhstat)), 0); | ||
770 | evstat = NLMSG_DATA(nlhstat); | ||
771 | memset(evstat, 0, sizeof(*evstat)); | ||
772 | evstat->transport_handle = iscsi_handle(conn->transport); | ||
773 | evstat->type = nlh->nlmsg_type; | ||
774 | if (atomic_read(&conn->z_pdu.allocated) >= conn->z_pdu.hiwat) | ||
775 | evstat->iferror = -ENOMEM; | ||
776 | evstat->u.get_stats.conn_handle = | ||
777 | ev->u.get_stats.conn_handle; | ||
778 | stats = (struct iscsi_stats *) | ||
779 | ((char*)evstat + sizeof(*evstat)); | ||
780 | memset(stats, 0, sizeof(*stats)); | ||
781 | 843 | ||
782 | transport->get_stats(ev->u.get_stats.conn_handle, stats); | 844 | if (transport->destroy_conn) |
783 | actual_size = NLMSG_SPACE(sizeof(struct iscsi_uevent) + | 845 | transport->destroy_conn(conn); |
784 | sizeof(struct iscsi_stats) + | ||
785 | sizeof(struct iscsi_stats_custom) * | ||
786 | stats->custom_length); | ||
787 | actual_size -= sizeof(*nlhstat); | ||
788 | actual_size = NLMSG_LENGTH(actual_size); | ||
789 | skb_trim(skb, NLMSG_ALIGN(actual_size)); | ||
790 | nlhstat->nlmsg_len = actual_size; | ||
791 | 846 | ||
792 | err = iscsi_unicast_skb(&conn->z_pdu, skbstat); | 847 | mempool_zone_destroy(z_pdu); |
793 | } while (err < 0 && err != -ECONNREFUSED); | 848 | mempool_zone_destroy(z_error); |
794 | 849 | ||
795 | return err; | 850 | return 0; |
796 | } | 851 | } |
797 | 852 | ||
798 | static int | 853 | static int |
@@ -916,8 +971,8 @@ iscsi_if_rx(struct sock *sk, int len) | |||
916 | err = iscsi_if_send_reply( | 971 | err = iscsi_if_send_reply( |
917 | NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq, | 972 | NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq, |
918 | nlh->nlmsg_type, 0, 0, ev, sizeof(*ev)); | 973 | nlh->nlmsg_type, 0, 0, ev, sizeof(*ev)); |
919 | if (atomic_read(&z_reply.allocated) >= | 974 | if (atomic_read(&z_reply->allocated) >= |
920 | z_reply.hiwat) | 975 | z_reply->hiwat) |
921 | ev->iferror = -ENOMEM; | 976 | ev->iferror = -ENOMEM; |
922 | } while (err < 0 && err != -ECONNREFUSED); | 977 | } while (err < 0 && err != -ECONNREFUSED); |
923 | skb_pull(skb, rlen); | 978 | skb_pull(skb, rlen); |
@@ -927,6 +982,9 @@ iscsi_if_rx(struct sock *sk, int len) | |||
927 | mutex_unlock(&rx_queue_mutex); | 982 | mutex_unlock(&rx_queue_mutex); |
928 | } | 983 | } |
929 | 984 | ||
985 | #define iscsi_cdev_to_conn(_cdev) \ | ||
986 | iscsi_dev_to_conn(_cdev->dev) | ||
987 | |||
930 | /* | 988 | /* |
931 | * iSCSI connection attrs | 989 | * iSCSI connection attrs |
932 | */ | 990 | */ |
@@ -935,12 +993,10 @@ static ssize_t \ | |||
935 | show_conn_int_param_##param(struct class_device *cdev, char *buf) \ | 993 | show_conn_int_param_##param(struct class_device *cdev, char *buf) \ |
936 | { \ | 994 | { \ |
937 | uint32_t value = 0; \ | 995 | uint32_t value = 0; \ |
938 | struct iscsi_if_conn *conn = iscsi_cdev_to_if_conn(cdev); \ | 996 | struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \ |
939 | struct iscsi_internal *priv; \ | 997 | struct iscsi_transport *t = conn->transport; \ |
940 | \ | 998 | \ |
941 | priv = to_iscsi_internal(conn->host->transportt); \ | 999 | t->get_conn_param(conn->dd_data, param, &value); \ |
942 | if (priv->param_mask & (1 << param)) \ | ||
943 | priv->iscsi_transport->get_param(conn->connh, param, &value); \ | ||
944 | return snprintf(buf, 20, format"\n", value); \ | 1000 | return snprintf(buf, 20, format"\n", value); \ |
945 | } | 1001 | } |
946 | 1002 | ||
@@ -955,6 +1011,9 @@ iscsi_conn_int_attr(data_digest, ISCSI_PARAM_DATADGST_EN, "%d"); | |||
955 | iscsi_conn_int_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN, "%d"); | 1011 | iscsi_conn_int_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN, "%d"); |
956 | iscsi_conn_int_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN, "%d"); | 1012 | iscsi_conn_int_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN, "%d"); |
957 | 1013 | ||
1014 | #define iscsi_cdev_to_session(_cdev) \ | ||
1015 | iscsi_dev_to_session(_cdev->dev) | ||
1016 | |||
958 | /* | 1017 | /* |
959 | * iSCSI session attrs | 1018 | * iSCSI session attrs |
960 | */ | 1019 | */ |
@@ -963,20 +1022,11 @@ static ssize_t \ | |||
963 | show_session_int_param_##param(struct class_device *cdev, char *buf) \ | 1022 | show_session_int_param_##param(struct class_device *cdev, char *buf) \ |
964 | { \ | 1023 | { \ |
965 | uint32_t value = 0; \ | 1024 | uint32_t value = 0; \ |
966 | struct iscsi_if_session *session = iscsi_cdev_to_if_session(cdev); \ | 1025 | struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \ |
967 | struct Scsi_Host *shost = iscsi_if_session_to_shost(session); \ | 1026 | struct Scsi_Host *shost = iscsi_session_to_shost(session); \ |
968 | struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \ | 1027 | struct iscsi_transport *t = session->transport; \ |
969 | struct iscsi_if_conn *conn = NULL; \ | ||
970 | unsigned long flags; \ | ||
971 | \ | ||
972 | spin_lock_irqsave(&connlock, flags); \ | ||
973 | if (!list_empty(&session->connections)) \ | ||
974 | conn = list_entry(session->connections.next, \ | ||
975 | struct iscsi_if_conn, session_list); \ | ||
976 | spin_unlock_irqrestore(&connlock, flags); \ | ||
977 | \ | 1028 | \ |
978 | if (conn && (priv->param_mask & (1 << param))) \ | 1029 | t->get_session_param(shost, param, &value); \ |
979 | priv->iscsi_transport->get_param(conn->connh, param, &value);\ | ||
980 | return snprintf(buf, 20, format"\n", value); \ | 1030 | return snprintf(buf, 20, format"\n", value); \ |
981 | } | 1031 | } |
982 | 1032 | ||
@@ -1005,23 +1055,18 @@ iscsi_session_int_attr(erl, ISCSI_PARAM_ERL, "%d"); | |||
1005 | count++; \ | 1055 | count++; \ |
1006 | } | 1056 | } |
1007 | 1057 | ||
1008 | static int iscsi_is_session_dev(const struct device *dev) | ||
1009 | { | ||
1010 | return dev->release == iscsi_if_session_dev_release; | ||
1011 | } | ||
1012 | |||
1013 | static int iscsi_session_match(struct attribute_container *cont, | 1058 | static int iscsi_session_match(struct attribute_container *cont, |
1014 | struct device *dev) | 1059 | struct device *dev) |
1015 | { | 1060 | { |
1016 | struct iscsi_if_session *session; | 1061 | struct iscsi_cls_session *session; |
1017 | struct Scsi_Host *shost; | 1062 | struct Scsi_Host *shost; |
1018 | struct iscsi_internal *priv; | 1063 | struct iscsi_internal *priv; |
1019 | 1064 | ||
1020 | if (!iscsi_is_session_dev(dev)) | 1065 | if (!iscsi_is_session_dev(dev)) |
1021 | return 0; | 1066 | return 0; |
1022 | 1067 | ||
1023 | session = iscsi_dev_to_if_session(dev); | 1068 | session = iscsi_dev_to_session(dev); |
1024 | shost = iscsi_if_session_to_shost(session); | 1069 | shost = iscsi_session_to_shost(session); |
1025 | if (!shost->transportt) | 1070 | if (!shost->transportt) |
1026 | return 0; | 1071 | return 0; |
1027 | 1072 | ||
@@ -1032,23 +1077,21 @@ static int iscsi_session_match(struct attribute_container *cont, | |||
1032 | return &priv->session_cont.ac == cont; | 1077 | return &priv->session_cont.ac == cont; |
1033 | } | 1078 | } |
1034 | 1079 | ||
1035 | static int iscsi_is_conn_dev(const struct device *dev) | ||
1036 | { | ||
1037 | return dev->release == iscsi_if_conn_dev_release; | ||
1038 | } | ||
1039 | |||
1040 | static int iscsi_conn_match(struct attribute_container *cont, | 1080 | static int iscsi_conn_match(struct attribute_container *cont, |
1041 | struct device *dev) | 1081 | struct device *dev) |
1042 | { | 1082 | { |
1043 | struct iscsi_if_conn *conn; | 1083 | struct iscsi_cls_session *session; |
1084 | struct iscsi_cls_conn *conn; | ||
1044 | struct Scsi_Host *shost; | 1085 | struct Scsi_Host *shost; |
1045 | struct iscsi_internal *priv; | 1086 | struct iscsi_internal *priv; |
1046 | 1087 | ||
1047 | if (!iscsi_is_conn_dev(dev)) | 1088 | if (!iscsi_is_conn_dev(dev)) |
1048 | return 0; | 1089 | return 0; |
1049 | 1090 | ||
1050 | conn = iscsi_dev_to_if_conn(dev); | 1091 | conn = iscsi_dev_to_conn(dev); |
1051 | shost = conn->host; | 1092 | session = iscsi_dev_to_session(conn->dev.parent); |
1093 | shost = iscsi_session_to_shost(session); | ||
1094 | |||
1052 | if (!shost->transportt) | 1095 | if (!shost->transportt) |
1053 | return 0; | 1096 | return 0; |
1054 | 1097 | ||
@@ -1059,7 +1102,8 @@ static int iscsi_conn_match(struct attribute_container *cont, | |||
1059 | return &priv->conn_cont.ac == cont; | 1102 | return &priv->conn_cont.ac == cont; |
1060 | } | 1103 | } |
1061 | 1104 | ||
1062 | int iscsi_register_transport(struct iscsi_transport *tt) | 1105 | struct scsi_transport_template * |
1106 | iscsi_register_transport(struct iscsi_transport *tt) | ||
1063 | { | 1107 | { |
1064 | struct iscsi_internal *priv; | 1108 | struct iscsi_internal *priv; |
1065 | unsigned long flags; | 1109 | unsigned long flags; |
@@ -1069,15 +1113,14 @@ int iscsi_register_transport(struct iscsi_transport *tt) | |||
1069 | 1113 | ||
1070 | priv = iscsi_if_transport_lookup(tt); | 1114 | priv = iscsi_if_transport_lookup(tt); |
1071 | if (priv) | 1115 | if (priv) |
1072 | return -EEXIST; | 1116 | return NULL; |
1073 | 1117 | ||
1074 | priv = kmalloc(sizeof(*priv), GFP_KERNEL); | 1118 | priv = kmalloc(sizeof(*priv), GFP_KERNEL); |
1075 | if (!priv) | 1119 | if (!priv) |
1076 | return -ENOMEM; | 1120 | return NULL; |
1077 | memset(priv, 0, sizeof(*priv)); | 1121 | memset(priv, 0, sizeof(*priv)); |
1078 | INIT_LIST_HEAD(&priv->list); | 1122 | INIT_LIST_HEAD(&priv->list); |
1079 | INIT_LIST_HEAD(&priv->sessions); | 1123 | INIT_LIST_HEAD(&priv->sessions); |
1080 | spin_lock_init(&priv->session_lock); | ||
1081 | priv->iscsi_transport = tt; | 1124 | priv->iscsi_transport = tt; |
1082 | 1125 | ||
1083 | priv->cdev.class = &iscsi_transport_class; | 1126 | priv->cdev.class = &iscsi_transport_class; |
@@ -1143,13 +1186,13 @@ int iscsi_register_transport(struct iscsi_transport *tt) | |||
1143 | spin_unlock_irqrestore(&iscsi_transport_lock, flags); | 1186 | spin_unlock_irqrestore(&iscsi_transport_lock, flags); |
1144 | 1187 | ||
1145 | printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name); | 1188 | printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name); |
1146 | return 0; | 1189 | return &priv->t; |
1147 | 1190 | ||
1148 | unregister_cdev: | 1191 | unregister_cdev: |
1149 | class_device_unregister(&priv->cdev); | 1192 | class_device_unregister(&priv->cdev); |
1150 | free_priv: | 1193 | free_priv: |
1151 | kfree(priv); | 1194 | kfree(priv); |
1152 | return err; | 1195 | return NULL; |
1153 | } | 1196 | } |
1154 | EXPORT_SYMBOL_GPL(iscsi_register_transport); | 1197 | EXPORT_SYMBOL_GPL(iscsi_register_transport); |
1155 | 1198 | ||
@@ -1165,14 +1208,6 @@ int iscsi_unregister_transport(struct iscsi_transport *tt) | |||
1165 | priv = iscsi_if_transport_lookup(tt); | 1208 | priv = iscsi_if_transport_lookup(tt); |
1166 | BUG_ON (!priv); | 1209 | BUG_ON (!priv); |
1167 | 1210 | ||
1168 | spin_lock_irqsave(&priv->session_lock, flags); | ||
1169 | if (!list_empty(&priv->sessions)) { | ||
1170 | spin_unlock_irqrestore(&priv->session_lock, flags); | ||
1171 | mutex_unlock(&rx_queue_mutex); | ||
1172 | return -EPERM; | ||
1173 | } | ||
1174 | spin_unlock_irqrestore(&priv->session_lock, flags); | ||
1175 | |||
1176 | spin_lock_irqsave(&iscsi_transport_lock, flags); | 1211 | spin_lock_irqsave(&iscsi_transport_lock, flags); |
1177 | list_del(&priv->list); | 1212 | list_del(&priv->list); |
1178 | spin_unlock_irqrestore(&iscsi_transport_lock, flags); | 1213 | spin_unlock_irqrestore(&iscsi_transport_lock, flags); |
@@ -1195,14 +1230,14 @@ iscsi_rcv_nl_event(struct notifier_block *this, unsigned long event, void *ptr) | |||
1195 | 1230 | ||
1196 | if (event == NETLINK_URELEASE && | 1231 | if (event == NETLINK_URELEASE && |
1197 | n->protocol == NETLINK_ISCSI && n->pid) { | 1232 | n->protocol == NETLINK_ISCSI && n->pid) { |
1198 | struct iscsi_if_conn *conn; | 1233 | struct iscsi_cls_conn *conn; |
1199 | unsigned long flags; | 1234 | unsigned long flags; |
1200 | 1235 | ||
1201 | mempool_zone_complete(&z_reply); | 1236 | mempool_zone_complete(z_reply); |
1202 | spin_lock_irqsave(&connlock, flags); | 1237 | spin_lock_irqsave(&connlock, flags); |
1203 | list_for_each_entry(conn, &connlist, conn_list) { | 1238 | list_for_each_entry(conn, &connlist, conn_list) { |
1204 | mempool_zone_complete(&conn->z_error); | 1239 | mempool_zone_complete(conn->z_error); |
1205 | mempool_zone_complete(&conn->z_pdu); | 1240 | mempool_zone_complete(conn->z_pdu); |
1206 | } | 1241 | } |
1207 | spin_unlock_irqrestore(&connlock, flags); | 1242 | spin_unlock_irqrestore(&connlock, flags); |
1208 | } | 1243 | } |
@@ -1235,15 +1270,15 @@ static __init int iscsi_transport_init(void) | |||
1235 | goto unregister_session_class; | 1270 | goto unregister_session_class; |
1236 | 1271 | ||
1237 | nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx, | 1272 | nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx, |
1238 | THIS_MODULE); | 1273 | THIS_MODULE); |
1239 | if (!nls) { | 1274 | if (!nls) { |
1240 | err = -ENOBUFS; | 1275 | err = -ENOBUFS; |
1241 | goto unregister_notifier; | 1276 | goto unregister_notifier; |
1242 | } | 1277 | } |
1243 | 1278 | ||
1244 | err = mempool_zone_init(&z_reply, Z_MAX_REPLY, | 1279 | z_reply = mempool_zone_init(Z_MAX_REPLY, |
1245 | NLMSG_SPACE(sizeof(struct iscsi_uevent)), Z_HIWAT_REPLY); | 1280 | NLMSG_SPACE(sizeof(struct iscsi_uevent)), Z_HIWAT_REPLY); |
1246 | if (!err) | 1281 | if (z_reply) |
1247 | return 0; | 1282 | return 0; |
1248 | 1283 | ||
1249 | sock_release(nls->sk_socket); | 1284 | sock_release(nls->sk_socket); |
@@ -1260,7 +1295,7 @@ unregister_transport_class: | |||
1260 | 1295 | ||
1261 | static void __exit iscsi_transport_exit(void) | 1296 | static void __exit iscsi_transport_exit(void) |
1262 | { | 1297 | { |
1263 | mempool_destroy(z_reply.pool); | 1298 | mempool_zone_destroy(z_reply); |
1264 | sock_release(nls->sk_socket); | 1299 | sock_release(nls->sk_socket); |
1265 | netlink_unregister_notifier(&iscsi_nl_notifier); | 1300 | netlink_unregister_notifier(&iscsi_nl_notifier); |
1266 | transport_class_unregister(&iscsi_connection_class); | 1301 | transport_class_unregister(&iscsi_connection_class); |
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index be1bc792ab18..3e5cb5ab2d34 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h | |||
@@ -168,6 +168,12 @@ typedef uint64_t iscsi_connh_t; /* iSCSI Data-Path connection handle */ | |||
168 | 168 | ||
169 | #define iscsi_ptr(_handle) ((void*)(unsigned long)_handle) | 169 | #define iscsi_ptr(_handle) ((void*)(unsigned long)_handle) |
170 | #define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr) | 170 | #define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr) |
171 | #define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata)) | ||
172 | |||
173 | /** | ||
174 | * iscsi_hostdata - get LLD hostdata from scsi_host | ||
175 | * @_hostdata: pointer to scsi host's hostdata | ||
176 | **/ | ||
171 | #define iscsi_hostdata(_hostdata) ((void*)_hostdata + sizeof(unsigned long)) | 177 | #define iscsi_hostdata(_hostdata) ((void*)_hostdata + sizeof(unsigned long)) |
172 | 178 | ||
173 | /* | 179 | /* |
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index f25041c386ec..16602a547a63 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h | |||
@@ -23,8 +23,14 @@ | |||
23 | #ifndef SCSI_TRANSPORT_ISCSI_H | 23 | #ifndef SCSI_TRANSPORT_ISCSI_H |
24 | #define SCSI_TRANSPORT_ISCSI_H | 24 | #define SCSI_TRANSPORT_ISCSI_H |
25 | 25 | ||
26 | #include <linux/device.h> | ||
26 | #include <scsi/iscsi_if.h> | 27 | #include <scsi/iscsi_if.h> |
27 | 28 | ||
29 | struct scsi_transport_template; | ||
30 | struct Scsi_Host; | ||
31 | struct mempool_zone; | ||
32 | struct iscsi_cls_conn; | ||
33 | |||
28 | /** | 34 | /** |
29 | * struct iscsi_transport - iSCSI Transport template | 35 | * struct iscsi_transport - iSCSI Transport template |
30 | * | 36 | * |
@@ -48,23 +54,31 @@ struct iscsi_transport { | |||
48 | char *name; | 54 | char *name; |
49 | unsigned int caps; | 55 | unsigned int caps; |
50 | struct scsi_host_template *host_template; | 56 | struct scsi_host_template *host_template; |
57 | /* LLD session/scsi_host data size */ | ||
51 | int hostdata_size; | 58 | int hostdata_size; |
59 | /* LLD iscsi_host data size */ | ||
60 | int ihostdata_size; | ||
61 | /* LLD connection data size */ | ||
62 | int conndata_size; | ||
52 | int max_lun; | 63 | int max_lun; |
53 | unsigned int max_conn; | 64 | unsigned int max_conn; |
54 | unsigned int max_cmd_len; | 65 | unsigned int max_cmd_len; |
55 | iscsi_sessionh_t (*create_session) (uint32_t initial_cmdsn, | 66 | struct Scsi_Host *(*create_session) (struct scsi_transport_template *t, |
56 | struct Scsi_Host *shost); | 67 | uint32_t initial_cmdsn); |
57 | void (*destroy_session) (iscsi_sessionh_t session); | 68 | void (*destroy_session) (struct Scsi_Host *shost); |
58 | iscsi_connh_t (*create_conn) (iscsi_sessionh_t session, uint32_t cid); | 69 | struct iscsi_cls_conn *(*create_conn) (struct Scsi_Host *shost, |
70 | uint32_t cid); | ||
59 | int (*bind_conn) (iscsi_sessionh_t session, iscsi_connh_t conn, | 71 | int (*bind_conn) (iscsi_sessionh_t session, iscsi_connh_t conn, |
60 | uint32_t transport_fd, int is_leading); | 72 | uint32_t transport_fd, int is_leading); |
61 | int (*start_conn) (iscsi_connh_t conn); | 73 | int (*start_conn) (iscsi_connh_t conn); |
62 | void (*stop_conn) (iscsi_connh_t conn, int flag); | 74 | void (*stop_conn) (iscsi_connh_t conn, int flag); |
63 | void (*destroy_conn) (iscsi_connh_t conn); | 75 | void (*destroy_conn) (struct iscsi_cls_conn *conn); |
64 | int (*set_param) (iscsi_connh_t conn, enum iscsi_param param, | 76 | int (*set_param) (iscsi_connh_t conn, enum iscsi_param param, |
65 | uint32_t value); | 77 | uint32_t value); |
66 | int (*get_param) (iscsi_connh_t conn, enum iscsi_param param, | 78 | int (*get_conn_param) (void *conndata, enum iscsi_param param, |
67 | uint32_t *value); | 79 | uint32_t *value); |
80 | int (*get_session_param) (struct Scsi_Host *shost, | ||
81 | enum iscsi_param param, uint32_t *value); | ||
68 | int (*send_pdu) (iscsi_connh_t conn, struct iscsi_hdr *hdr, | 82 | int (*send_pdu) (iscsi_connh_t conn, struct iscsi_hdr *hdr, |
69 | char *data, uint32_t data_size); | 83 | char *data, uint32_t data_size); |
70 | void (*get_stats) (iscsi_connh_t conn, struct iscsi_stats *stats); | 84 | void (*get_stats) (iscsi_connh_t conn, struct iscsi_stats *stats); |
@@ -73,7 +87,7 @@ struct iscsi_transport { | |||
73 | /* | 87 | /* |
74 | * transport registration upcalls | 88 | * transport registration upcalls |
75 | */ | 89 | */ |
76 | extern int iscsi_register_transport(struct iscsi_transport *tt); | 90 | extern struct scsi_transport_template *iscsi_register_transport(struct iscsi_transport *tt); |
77 | extern int iscsi_unregister_transport(struct iscsi_transport *tt); | 91 | extern int iscsi_unregister_transport(struct iscsi_transport *tt); |
78 | 92 | ||
79 | /* | 93 | /* |
@@ -83,4 +97,49 @@ extern void iscsi_conn_error(iscsi_connh_t conn, enum iscsi_err error); | |||
83 | extern int iscsi_recv_pdu(iscsi_connh_t conn, struct iscsi_hdr *hdr, | 97 | extern int iscsi_recv_pdu(iscsi_connh_t conn, struct iscsi_hdr *hdr, |
84 | char *data, uint32_t data_size); | 98 | char *data, uint32_t data_size); |
85 | 99 | ||
100 | struct iscsi_cls_conn { | ||
101 | struct list_head conn_list; /* item in connlist */ | ||
102 | void *dd_data; /* LLD private data */ | ||
103 | struct iscsi_transport *transport; | ||
104 | iscsi_connh_t connh; | ||
105 | int active; /* must be accessed with the connlock */ | ||
106 | struct device dev; /* sysfs transport/container device */ | ||
107 | struct mempool_zone *z_error; | ||
108 | struct mempool_zone *z_pdu; | ||
109 | struct list_head freequeue; | ||
110 | }; | ||
111 | |||
112 | #define iscsi_dev_to_conn(_dev) \ | ||
113 | container_of(_dev, struct iscsi_cls_conn, dev) | ||
114 | |||
115 | struct iscsi_cls_session { | ||
116 | struct list_head list; /* item in session_list */ | ||
117 | struct iscsi_transport *transport; | ||
118 | struct device dev; /* sysfs transport/container device */ | ||
119 | }; | ||
120 | |||
121 | #define iscsi_dev_to_session(_dev) \ | ||
122 | container_of(_dev, struct iscsi_cls_session, dev) | ||
123 | |||
124 | #define iscsi_session_to_shost(_session) \ | ||
125 | dev_to_shost(_session->dev.parent) | ||
126 | |||
127 | /* | ||
128 | * session and connection functions that can be used by HW iSCSI LLDs | ||
129 | */ | ||
130 | extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost, | ||
131 | struct iscsi_transport *t); | ||
132 | extern int iscsi_destroy_session(struct iscsi_cls_session *session); | ||
133 | extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess, | ||
134 | uint32_t cid); | ||
135 | extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn); | ||
136 | |||
137 | /* | ||
138 | * session functions used by software iscsi | ||
139 | */ | ||
140 | extern struct Scsi_Host * | ||
141 | iscsi_transport_create_session(struct scsi_transport_template *scsit, | ||
142 | struct iscsi_transport *transport); | ||
143 | extern int iscsi_transport_destroy_session(struct Scsi_Host *shost); | ||
144 | |||
86 | #endif | 145 | #endif |