forked from gregkh/ndas
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconn.c
More file actions
2163 lines (1869 loc) · 65.5 KB
/
conn.c
File metadata and controls
2163 lines (1869 loc) · 65.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
Connection to unit device operations.
These functions should be called in single thread context
such as ndiod thread or blockable user function call
*/
#include "linux_ver.h"
#include "inc/xplatcfg.h"
#include "inc/sal/types.h"
#include "inc/netdisk/conn.h"
#include "inc/netdisk/scrc32.h"
#include "inc/lspx/lsp_util.h"
#include "inc/lspx/lsp.h"
#include "inc/ndasuser/ndasuser.h"
#include "lockmgmt.h"
#ifndef NDAS_NO_LANSCSI
#ifdef DEBUG
#define debug_conn(l, x...) do {\
if(l <= DEBUG_LEVEL_UCONN) { \
sal_debug_print("UN|%d|%s|",l,__FUNCTION__); \
sal_debug_println(x); \
} \
} while(0)
#else
#define debug_conn(l, x...) do {} while(0)
#endif
/* To do: remove this */
extern int udev_max_xfer_unit;
#define CONN_SECTOR_SIZE 512
#define CONN_SECTOR_SIZE_SHIFT 9
#define CONN_SECTOR_TO_BYTE(SECTOR) ((SECTOR) << CONN_SECTOR_SIZE_SHIFT)
#define CONN_BYTE_TO_SECTOR(BYTE) ((BYTE) >> CONN_SECTOR_SIZE_SHIFT)
/*
Used to split and contain user IO vectors.
*/
typedef struct _lsp_transfer_param {
lsp_large_integer_t start_sec;
xuint32 num_sec; // Number of sector to copy. The size of one sector is 512 for disk io
xuint32 translen; // used for general transfer
struct sal_mem_block *cur_uio; /* cur_uio */
int cur_uio_offset;
int nr_uio; /* number of array - uio */
struct sal_mem_block *uio; /* array of struct sal_mem_block that point the user supplied pointer to hold data */
lpx_aio aio;
} lsp_transfer_param_t;
#define CONN_MEMBLK_INDEX_FROM_HEAD(HEAD_BLK, CUR_BLK) \
((CUR_BLK) - (HEAD_BLK))
int aio_ndio_copy(
struct _lpx_aio * aio,
void *recvdata,
int ssz
)
{
uconn_t* conn = (uconn_t *)aio->userparam;
struct sal_mem_block* blocks = &aio->buf.blocks[aio->index];
char* sptr = (char *)recvdata, *dptr;
int dsz;
int tocopy;
debug_conn(4, "conn=%p nr_block=%d, blocks=%p offset=%d", conn, aio->nr_blocks, aio->buf.blocks, aio->offset);
sal_assert( aio->nr_blocks != 0);
sal_assert( ssz );
dptr = blocks->ptr + aio->offset;
dsz = blocks->len - aio->offset;
debug_conn(6, "dptr=%p dsz=%d i=%d", dptr, dsz, (int)aio->index);
debug_conn(6, "sptr=%p ssz=%d i=%d", sptr, ssz, (int)aio->index);
while(ssz > 0) {
if ( dsz < ssz ) {
tocopy = dsz;
} else {
tocopy = ssz;
}
debug_conn(3, "%p(%d)<-%d-%p(%d)", dptr, dsz,tocopy, sptr, ssz);
lsp_decrypt_recv_data(conn->lsp_handle, dptr, sptr, tocopy);
debug_conn(3,"done:%p(%d)<-%d-%p(%d)", dptr, dsz,tocopy, sptr, ssz);
dptr += tocopy;
sptr += tocopy;
dsz -= tocopy;
ssz -= tocopy;
if ( dsz == 0 ) {
aio->index ++;
aio->offset = 0;
if (aio->index < aio->nr_blocks) {
blocks ++;
dptr = blocks->ptr;
dsz = blocks->len;
debug_conn(6, "blocks[%d %p]={%p %d}", aio->index, blocks, dptr, dsz);
} else {
if (ssz!=0) {
debug_conn(1, "We got already what we wanted ssz=%d", ssz);
// TODO: Remove copied data from xb and enqueue to header
}
break;
}
} else {
sal_assert(dsz > 0);
aio->offset = blocks->len - dsz;
}
}
return NDAS_OK;
}
ndas_error_t uconn_convert_lsp_status_to_ndas_error(lsp_status_t status)
{
switch (status) {
case LSP_STATUS_SUCCESS:
return NDAS_OK;
case LSP_STATUS_WRITE_ACCESS_DENIED:
return NDAS_ERROR_NO_WRITE_ACCESS_RIGHT;
case LSP_STATUS_LOCK_FAILED:
return NDAS_ERROR_ACQUIRE_LOCK_FAILED;
case LSP_STATUS_INVALID_SESSION:
return NDAS_ERROR_INVALID_HANDLE;
case LSP_STATUS_IDE_COMMAND_FAILED:
return NDAS_ERROR_IDE_REMOTE_COMMAND_FAILED;
case LSP_STATUS_INVALID_PARAMETER:
/* Connection is invalid or closed */
return NDAS_ERROR_INVALID_HANDLE;
default:
{
lsp_status_detail_t detail;
detail.status = status;
debug_conn(1,"lsp error code %x(Respone=%x,Type=%x,Sequence=%x,Function=%x) not converted", status,
detail.detail.response, detail.detail.type, detail.detail.sequence, detail.detail.function);
sal_assert(0);
}
return NDAS_ERROR;
}
#if 0 /* To do: translate ide error code to NDAS_ERROR_xxx */
LOCAL ndas_error_t
translate_error_code(int response, int login_phase)
{
switch(response) {
case LANSCSI_RESPONSE_SUCCESS:
return NDAS_OK;
case LANSCSI_RESPONSE_RI_NOT_EXIST:
return NDAS_ERROR_IDE_REMOTE_INITIATOR_NOT_EXIST;
case LANSCSI_RESPONSE_RI_BAD_COMMAND:
return NDAS_ERROR_IDE_REMOTE_INITIATOR_BAD_COMMAND;
case LANSCSI_RESPONSE_RI_COMMAND_FAILED:
return NDAS_ERROR_IDE_REMOTE_COMMAND_FAILED;
case LANSCSI_RESPONSE_RI_VERSION_MISMATCH:
return NDAS_ERROR_UNSUPPORTED_HARDWARE_VERSION;
case LANSCSI_RESPONSE_RI_AUTH_FAILED:
return NDAS_ERROR_IDE_REMOTE_AUTH_FAILED;
case LANSCSI_RESPONSE_T_NOT_EXIST:
return NDAS_ERROR_IDE_TARGET_NOT_EXIST;
case LANSCSI_RESPONSE_T_BAD_COMMAND:
return NDAS_ERROR_HARDWARE_DEFECT; //NDAS_ERROR_IDE_TARGET_BAD_COMMAND;
case LANSCSI_RESPONSE_T_COMMAND_FAILED:
if (login_phase)
return NDAS_ERROR_NO_WRITE_ACCESS_RIGHT;
else
return NDAS_ERROR_BAD_SECTOR;
case LANSCSI_RESPONSE_T_BROKEN_DATA:
return NDAS_ERROR_IDE_TARGET_BROKEN_DATA;
}
if ( response >= LANSCSI_RESPONSE_VENDOR_SPECIFIC_MIN &&
response <= LANSCSI_RESPONSE_VENDOR_SPECIFIC_MAX )
return NDAS_ERROR_IDE_VENDOR_SPECIFIC;
return NDAS_ERROR;
}
#endif
}
LOCAL
ndas_error_t
conn_transport_process_transfer_send_userdata(
uconn_t* context, lsp_transfer_param_t* const reqdesc)
{
struct sal_mem_block* cur_uio = reqdesc->cur_uio;
int cur_uio_offset = reqdesc->cur_uio_offset;
//int remaining = CONN_SECTOR_TO_BYTE(reqdesc->num_sec);
int remaining = reqdesc->translen;
int to_send;
int ret;
debug_conn(4,"Sending user data %p, %d", cur_uio->ptr + cur_uio_offset, remaining);
while(remaining > 0) {
to_send = (cur_uio->len - cur_uio_offset ) <
remaining ? ( cur_uio->len - cur_uio_offset ) : remaining;
if (context->hwdata->data_encryption_algorithm) {
lsp_encrypt_send_data(context->lsp_handle,
context->encrypt_buffer,
cur_uio->ptr + cur_uio_offset,
to_send);
ret = lpx_send(context->sock, context->encrypt_buffer, to_send, 0);
} else {
ret = lpx_send(context->sock, cur_uio->ptr + cur_uio_offset, to_send, 0);
}
if (to_send != ret)
{
return NDAS_ERROR_NETWORK_FAIL;
}
remaining -= to_send;
if(cur_uio_offset + to_send == cur_uio->len) {
cur_uio ++;
cur_uio_offset = 0;
} else {
cur_uio_offset += to_send;
}
}
// Move the current UIO pointer if success.
reqdesc->cur_uio = cur_uio;
reqdesc->cur_uio_offset = cur_uio_offset;
return NDAS_OK;
}
ndas_error_t
conn_transport_process_transfer(
uconn_t* context, lsp_transfer_param_t* reqdesc, int flags )
{
int ret;
char *buffer;
lsp_uint32_t len_buffer;
int sockfd = context->sock;
lsp_status_t status;
for (
status = context->lsp_status;;
status = lsp_process_next(context->lsp_handle))
{
context->lsp_status = status;
switch(status) {
case LSP_REQUIRES_SEND_INTERNAL_DATA:
{
debug_conn(4, "LSP_REQUIRES_SEND_INTERNAL_DATA");
buffer = lsp_get_buffer_to_send(
context->lsp_handle, &len_buffer);
debug_conn(4,"Sending internal data %p:%d", buffer, len_buffer);
ret = lpx_send(sockfd, buffer, len_buffer, 0);
if (len_buffer != ret)
{
return NDAS_ERROR_NETWORK_FAIL;
}
break;
}
case LSP_REQUIRES_SEND_USER_DATA:
{
debug_conn(4, "LSP_REQUIRES_SEND_USER_DATA");
ret = conn_transport_process_transfer_send_userdata(context, reqdesc);
if(!NDAS_SUCCESS(ret)) {
return ret;
}
break;
}
case LSP_REQUIRES_RECEIVE_INTERNAL_DATA:
{
debug_conn(4, "LSP_REQUIRES_RECEIVE_INTERNAL_DATA");
buffer = lsp_get_buffer_to_receive(
context->lsp_handle, &len_buffer);
ret = lpx_recv(sockfd, buffer, len_buffer, flags);
if (len_buffer != ret)
{
debug_conn(1,"NDAS_ERROR_NETWORK_FAIL");
return NDAS_ERROR_NETWORK_FAIL;
}
debug_conn(2,"Receiving internal data %p, %d", buffer, len_buffer);
break;
}
case LSP_REQUIRES_RECEIVE_USER_DATA:
{
debug_conn(4, "LSP_REQUIRES_RECEIVE_USER_DATA");
/* lspx's call to receive */
buffer = lsp_get_buffer_to_receive(
context->lsp_handle, &len_buffer);
/* Receive to xbuf queue to remove data copy */
debug_conn(4,"Receiving user data %p, %d offset=%d", buffer, len_buffer, reqdesc->cur_uio_offset);
lpx_prepare_aio(
sockfd,
// Get the number of the remaining UIO entries
reqdesc->nr_uio - CONN_MEMBLK_INDEX_FROM_HEAD(reqdesc->uio, reqdesc->cur_uio),
(void *)reqdesc->cur_uio,
reqdesc->cur_uio_offset,
len_buffer,
flags,
&reqdesc->aio);
lpx_set_user_copy_routine(aio_ndio_copy, &reqdesc->aio);
lpx_set_userparam(context, &reqdesc->aio);
ret = lpx_recv_aio(&reqdesc->aio);
if (len_buffer != ret)
{
return NDAS_ERROR_NETWORK_FAIL;
}
// Move the current UIO pointer if success.
reqdesc->cur_uio += reqdesc->aio.index;
reqdesc->cur_uio_offset = reqdesc->aio.offset;
debug_conn(4,"UIO %p AIO index %d offset %d", reqdesc->cur_uio, reqdesc->aio.index, reqdesc->cur_uio_offset);
break;
}
case LSP_REQUIRES_DATA_DECODE:
{
debug_conn(4, "LSP_REQUIRES_DATA_DECODE");
/* We already did encode at receive stage. */
break;
}
case LSP_REQUIRES_DATA_ENCODE:
{
debug_conn(4, "LSP_REQUIRES_DATA_ENCODE");
/* We'll encode data when send. Do nothing right now. */
break;
}
case LSP_REQUIRES_SYNCHRONIZE:
{
debug_conn(4, "LSP_REQUIRES_SYNCHRONIZE");
/* wait until all pending tx/rx are completed */
/* nothing to do on synchronous socket */
break;
}
case LSP_REQUIRES_SEND: {
sal_assert(0);
break;
}
case LSP_REQUIRES_RECEIVE: {
sal_assert(0);
break;
}
default: {
/* all other return values indicate the completion or
error of the process */
return uconn_convert_lsp_status_to_ndas_error(status);
}
}
}
/* unreachable here */
}
ndas_error_t
conn_handshake(uconn_t *conn)
{
ndas_error_t ret;
conn->lsp_status = lsp_ata_handshake(conn->lsp_handle);
ret = conn_transport_process_transfer(conn, NULL, 0);
return ret;
}
ndas_error_t
conn_set_feature(uconn_t *conn,
xuint8 sub_com,
xuint8 sbu_com_specific_0,
xuint8 sbu_com_specific_1,
xuint8 sbu_com_specific_2,
xuint8 sbu_com_specific_3
)
{
ndas_error_t ret;
conn->lsp_status = lsp_ide_setfeatures(conn->lsp_handle,
sub_com,
sbu_com_specific_0,
sbu_com_specific_1,
sbu_com_specific_2,
sbu_com_specific_3
);
ret = conn_transport_process_transfer(conn, NULL, 0);
return ret;
}
#ifdef XPLAT_RECONNECT
/*
*
* Thread: i/O ndiod (user thread if block i/o)
*/
LOCAL
ndas_error_t do_reconnect(uconn_t *conn)
{
ndas_error_t err;
if (conn->err == NDAS_ERROR_SHUTDOWN_IN_PROGRESS ) {
debug_conn(1, "User want to stop reconnecting..");
return NDAS_ERROR_SHUTDOWN_IN_PROGRESS;
}
if ( conn->sock > 0 ) {
conn_disconnect(conn);
}
conn_reinit(conn);
debug_conn(1, "connecting");
err = conn_connect(conn, conn->reconnect_timeout);
debug_conn(1, "connect return");
if(!NDAS_SUCCESS(err)) {
conn->sock = 0;
debug_conn(1, "can't connect:err=%d",err);
goto disconnect;
}
err = conn_handshake(conn);
if ( !NDAS_SUCCESS(err) ) {
debug_conn(1, "fail to handshake");
goto disconnect;
}
//
// To do: check device information has changed since last discover/connect
//
return NDAS_OK;
disconnect:
conn_disconnect(conn);
return err;
}
ndas_error_t conn_reconnect(uconn_t *conn)
{
int retry_count=0;
ndas_error_t ret = conn->err;
sal_msec start_msec = sal_time_msec();
sal_msec timeout = conn->reconnect_timeout;
if (ret == NDAS_ERROR_SHUTDOWN_IN_PROGRESS ) {
debug_conn(1, "User wants to stop reconnecting..");
return NDAS_ERROR_SHUTDOWN_IN_PROGRESS;
}
for(retry_count=0; (sal_time_msec() - start_msec)<timeout ;retry_count++) {
debug_conn(1,"Reconnecting trial %d", retry_count+1);
ret = do_reconnect(conn);
if ( ret == NDAS_ERROR_SHUTDOWN_IN_PROGRESS ) {
return ret;
}
if (!NDAS_SUCCESS(ret)) {
debug_conn(1,"Login failed err=%d", ret);
sal_msleep(CONN_RECONN_INTERVAL_MSEC);
continue;
}
debug_conn(1,"Reconnected on trial %d", retry_count+1);
return NDAS_OK;
}
return ret;
}
#else
LOCAL
ndas_error_t conn_reconnect(uconn_t *conn)
{
return NDAS_ERROR;
}
#endif
ndas_error_t conn_reinit(uconn_t *conn)
{
debug_conn(3,"conn=%p", conn);
if (conn->encrypt_buffer) {
/* Encrypt buffer size may need to be changed. Free here and let it being created again */
sal_free(conn->encrypt_buffer);
conn->encrypt_buffer = NULL;
}
conn->lsp_handle = lsp_initialize_session(
conn->lsp_session_buffer,
LSP_SESSION_BUFFER_SIZE
);
/* Use external encoder/decoder to handle scatter/gather buffer and xbuf */
lsp_set_options(
conn->lsp_handle,
LSP_SO_USE_EXTERNAL_DATA_ENCODE |
LSP_SO_USE_EXTERNAL_DATA_DECODE |
LSP_SO_USE_DISTINCT_SEND_RECEIVE
);
conn_set_status(conn, CONN_STATUS_INIT);
return NDAS_OK;
}
/*
Initialize conn members for connection.
*/
ndas_error_t
conn_init(
uconn_t *conn,
xuchar* node,
xuint32 unit,
ndas_conn_mode_t mode,
BUFFLOCK_CONTROL* BuffLockCtl,
NDAS_DEVLOCK_INFO* LockInfo
)
{
debug_conn(3,"conn=%p", conn);
sal_memset(conn, 0, sizeof(uconn_t));
sal_memset(&conn->lpx_addr, 0, sizeof(conn->lpx_addr));
conn->lpx_addr.slpx_family = AF_LPX;
sal_memcpy(conn->lpx_addr.slpx_node, node, sizeof(conn->lpx_addr.slpx_node));
conn->lpx_addr.slpx_port = lsp_htons(10000);
conn->unit = unit;
conn->encrypt_buffer = NULL;
conn->mode = mode;
conn->BuffLockCtl = BuffLockCtl;
conn->LockInfo = LockInfo;
conn->lsp_session_buffer = sal_malloc(LSP_SESSION_BUFFER_SIZE);
conn->lsp_handle = lsp_initialize_session(
conn->lsp_session_buffer,
LSP_SESSION_BUFFER_SIZE
);
/* Use external encoder/decoder to handle scatter/gather buffer and xbuf */
lsp_set_options(
conn->lsp_handle,
LSP_SO_USE_EXTERNAL_DATA_ENCODE |
LSP_SO_USE_EXTERNAL_DATA_DECODE |
LSP_SO_USE_DISTINCT_SEND_RECEIVE
);
conn_set_status(conn, CONN_STATUS_INIT);
return NDAS_OK;
}
void conn_clean(uconn_t *conn)
{
if (conn->lsp_session_buffer) {
sal_free(conn->lsp_session_buffer);
conn->lsp_session_buffer = NULL;
conn->lsp_handle = NULL;
}
if (conn->encrypt_buffer) {
sal_free(conn->encrypt_buffer);
conn->encrypt_buffer = NULL;
}
}
/* No return value. Okay to fail */
void conn_logout(uconn_t *conn) {
debug_conn(1, "sock=%d", conn->sock);
sal_assert(conn->lsp_handle !=NULL);
conn->lsp_status = lsp_logout(conn->lsp_handle);
conn_transport_process_transfer(conn, NULL, 0);
}
/* No return value. Okay to fail */
void conn_disconnect(uconn_t *conn)
{
debug_conn(1, "sock=%d", conn->sock);
if (conn->sock) {
lpx_close(conn->sock);
conn->sock = 0;
}
conn_set_status(conn, CONN_STATUS_INIT);
debug_conn(2, "status=CONN_STATUS_INIT");
}
void conn_set_error(uconn_t *conn, ndas_error_t err)
{
debug_conn(2, "ing err = %d", err);
sal_assert(!NDAS_SUCCESS(err));
conn->err = err;
}
xbool conn_is_connected(uconn_t *conn)
{
if ( conn->sock <= 0 ) return FALSE;
return NDAS_SUCCESS(lpx_is_connected(conn->sock)) ? TRUE:FALSE;
}
ndas_error_t conn_connect(uconn_t *conn, sal_msec timeout)
{
ndas_error_t err;
int sock;
lsp_login_info_t lsp_login_info;
struct sockaddr_lpx bindaddr;
debug_conn(3, "conn=%p" , conn);
debug_conn(1, "Connecting via LANSCSI for %s:0x%x status=%d, unit=%d",
SAL_DEBUG_HEXDUMP_S(conn->lpx_addr.slpx_node, 6),
conn->lpx_addr.slpx_port,
conn->status, conn->unit);
sal_assert(conn->status == CONN_STATUS_INIT);
#ifdef DEBUG
if ( conn->status != CONN_STATUS_INIT )
debug_conn(1, "conn=%p conn->status=%x", conn, conn->status);
#endif
conn->sock = sock = lpx_socket(LPX_TYPE_STREAM, 0);
debug_conn(1, "sock=%d", sock);
if (sock < 0) {
err = sock;
goto errout;
}
/* Use any interface */
sal_memset(&bindaddr, 0, sizeof(bindaddr));
bindaddr.slpx_family = AF_LPX;
err = lpx_bind(sock, &bindaddr, sizeof(bindaddr));
if (!NDAS_SUCCESS(err)) {
debug_conn(1, "bind failed for sock %d:%d", sock, err);
goto errout;
}
err = lpx_connect(conn->sock, &conn->lpx_addr, sizeof(conn->lpx_addr));
if (!NDAS_SUCCESS(err)) {
err = NDAS_ERROR_CONNECT_FAILED;
goto errout;
}
err = lpx_set_rtimeout(conn->sock, timeout);
if (!NDAS_SUCCESS(err)) {
goto errout;
}
err = lpx_set_wtimeout(conn->sock, timeout);
if (!NDAS_SUCCESS(err)) {
goto errout;
}
conn_set_status(conn, CONN_STATUS_CONNECTING);
conn->reconnect_timeout = timeout;
/* default login values */
sal_memset(&lsp_login_info, 0, sizeof(lsp_login_info));
if (conn->mode == NDAS_CONN_MODE_SUPERVISOR) {
const lsp_uint8_t LSP_LOGIN_PASSWORD_DEFAULT_SUPERVISOR[8] = { 0x1E, 0x13, 0x50, 0x47, 0x1A, 0x32, 0x2B, 0x3E};
sal_memcpy(lsp_login_info.supervisor_password,
LSP_LOGIN_PASSWORD_DEFAULT_SUPERVISOR, sizeof(LSP_LOGIN_PASSWORD_DEFAULT_SUPERVISOR));
} else {
sal_memcpy(lsp_login_info.password, LSP_LOGIN_PASSWORD_ANY, sizeof(LSP_LOGIN_PASSWORD_ANY));
}
if (conn->mode == NDAS_CONN_MODE_DISCOVER) {
lsp_login_info.login_type = LSP_LOGIN_TYPE_DISCOVER;
} else {
lsp_login_info.login_type = LSP_LOGIN_TYPE_NORMAL;
}
if (conn->mode == NDAS_CONN_MODE_EXCLUSIVE_WRITE) {
lsp_login_info.write_access = 1;
} else {
lsp_login_info.write_access = 0;
}
lsp_login_info.unit_no = conn->unit;
conn->lsp_status = lsp_login(conn->lsp_handle, &lsp_login_info);
err = conn_transport_process_transfer(conn, NULL, 0);
if (NDAS_SUCCESS(err)) {
conn->hwdata = lsp_get_hardware_data(conn->lsp_handle);
conn->max_transfer_size = conn->hwdata->maximum_transfer_blocks * 512;
if (conn->hwdata->data_encryption_algorithm) {
sal_assert(conn->encrypt_buffer == NULL);
conn->encrypt_buffer = sal_malloc(conn->max_transfer_size);
if (conn->encrypt_buffer == NULL) {
err = NDAS_ERROR_OUT_OF_MEMORY;
goto errout;
}
}
if (conn->max_transfer_size > udev_max_xfer_unit) {
conn->max_split_bytes = udev_max_xfer_unit;
} else {
conn->max_split_bytes = conn->max_transfer_size;
}
debug_conn(1, "Using max split bytes: %dk", conn->max_split_bytes/1024);
#ifdef USE_FLOW_CONTROL
conn->read_split_bytes = conn->max_split_bytes;
conn->write_split_bytes = conn->max_split_bytes;
#endif
conn_set_status(conn, CONN_STATUS_CONNECTED);
return NDAS_OK;
}
errout:
if (conn->sock>0) {
conn_disconnect(conn);
}
return err;
}
void
inline
conn_adjust_read_split_size(uconn_t *conn, int rx_packet_loss)
{
#ifdef USE_FLOW_CONTROL
if (rx_packet_loss) {
conn->read_split_bytes /=2;
if (conn->read_split_bytes<4 * 1024) {
conn->read_split_bytes = 4 * 1024;
}
sal_error_print("read split = %d bytes\n", conn->read_split_bytes);
} else {
// Sector size will be increased after 128(=512/4) successful transfer.
conn->read_split_bytes += 4;
if (conn->read_split_bytes>conn->max_split_bytes) {
conn->read_split_bytes = conn->max_split_bytes;
}
}
debug_conn(4, "read split size: %d", conn->read_split_bytes);
#endif
}
void
inline
conn_adjust_write_split_size(uconn_t *conn, int tx_retransmit)
{
#ifdef USE_FLOW_CONTROL
if (tx_retransmit) {
conn->write_split_bytes /=2;
if (conn->write_split_bytes<4*1024) {
conn->write_split_bytes = 4*1024;
}
sal_error_print("write split = %d bytes\n", conn->write_split_bytes);
} else {
// Sector size will be increased after 128(=512/4) successful transfer.
conn->write_split_bytes+=4;
if (conn->write_split_bytes>conn->max_split_bytes) {
conn->write_split_bytes = conn->max_split_bytes;
}
}
debug_conn(4, "split size: %d, %d", conn->read_split_bytes, conn->write_split_bytes);
#endif
}
/*
* Connection IO functions
*/
ndas_error_t
conn_read_func(
uconn_t *conn,
lsp_transfer_param_t *reqd,
int *split_size
)
{
ndas_error_t err, reterr;
struct lpx_retransmits_count retxcnt;
debug_conn(4, "Reading start=%llu, len=%d. %d %d", (long long unsigned int)reqd->start_sec.quad, reqd->num_sec,
(int)CONN_MEMBLK_INDEX_FROM_HEAD(reqd->uio, reqd->cur_uio), reqd->cur_uio_offset);
conn->lsp_status = lsp_ide_read(
conn->lsp_handle,
&reqd->start_sec,
reqd->num_sec,
(void*)reqd,
CONN_SECTOR_TO_BYTE(reqd->num_sec));
err = conn_transport_process_transfer(conn, reqd, 0);
#ifdef USE_FLOW_CONTROL
reterr = lpx_get_retransmit_count(conn->sock, &retxcnt);
if (reterr == NDAS_OK) {
conn_adjust_read_split_size(conn, retxcnt.rx_packet_loss);
*split_size = CONN_BYTE_TO_SECTOR(conn->read_split_bytes);
}
#endif
return err;
}
ndas_error_t
conn_write_func(
uconn_t *conn,
lsp_transfer_param_t *reqd,
int *split_size
)
{
ndas_error_t err, reterr;
struct lpx_retransmits_count retxcnt;
debug_conn(4, "Writing start=%llu, len=%d sectors", (long long unsigned int)reqd->start_sec.quad, reqd->num_sec);
conn->lsp_status = lsp_ide_write(
conn->lsp_handle,
&reqd->start_sec,
reqd->num_sec,
(void*)reqd,
CONN_SECTOR_TO_BYTE(reqd->num_sec));
err = conn_transport_process_transfer(conn, reqd, 0);
#ifdef USE_FLOW_CONTROL
reterr = lpx_get_retransmit_count(conn->sock, &retxcnt);
if (reterr == NDAS_OK) {
conn_adjust_write_split_size(conn, retxcnt.tx_retransmit);
*split_size = CONN_BYTE_TO_SECTOR(conn->write_split_bytes);
}
#endif
return err;
}
ndas_error_t
conn_flush_func(
uconn_t *conn,
lsp_transfer_param_t *reqd
)
{
debug_conn(1, "Flushing");
conn->lsp_status = lsp_ide_flush(
conn->lsp_handle, &reqd->start_sec, reqd->num_sec, 0, 0);
return conn_transport_process_transfer(conn, reqd, 0);
}
ndas_error_t
conn_verify_func(
uconn_t *conn,
lsp_transfer_param_t *reqd
)
{
debug_conn(1, "verifying");
conn->lsp_status = lsp_ide_verify(
conn->lsp_handle, &reqd->start_sec, reqd->num_sec, (void*)reqd, 0);
return conn_transport_process_transfer(conn, reqd, 0);
}
/*
* Connection IO function type
*/
typedef ndas_error_t (* conn_io_func)(
uconn_t *conn,
lsp_transfer_param_t *reqd,
int *split_size);
conn_io_func conn_io_vec[CONNIO_RW_CMD_LAST + 1] = {
conn_read_func,
conn_write_func
};
inline
ndas_error_t
conn_rw_io_execute(
xint8 cmd,
uconn_t *conn,
lsp_transfer_param_t *reqd,
int *split_size)
{
sal_assert(cmd <= CONNIO_RW_CMD_LAST);
return (conn_io_vec[(int)cmd])(conn, reqd, split_size);
}
/*
* Execute vectored IO within the connection.
*/
ndas_error_t
conn_rw_vector(
uconn_t *conn,
xint8 cmd,
xuint64 start_sec,
xuint32 num_sec,
int nr_uio,
struct sal_mem_block *uio
) {
ndas_error_t err = NDAS_OK;
lsp_transfer_param_t reqd;
xuint32 transfered_sectors;
xuint32 to_transfer;
int split_size;
int retrial = 0;
#if 0
int i;
#endif
if(cmd > CONNIO_RW_CMD_LAST) {
return NDAS_ERROR_INVALID_PARAMETER;
}
#ifdef USE_FLOW_CONTROL
if (cmd == CONNIO_CMD_WRITE) {
split_size = conn->write_split_bytes/512;
} else {
split_size = conn->read_split_bytes/512;
}
#else
split_size = num_sec;
if (split_size > udev_max_xfer_unit)
split_size = udev_max_xfer_unit;
#endif
debug_conn(1, "ing conn=%p, sec=%llu, sec_len=%d, split size=%d nr_uio=%d",
conn, (long long unsigned int)start_sec, num_sec, split_size, nr_uio);
#if 0
for(i=0;i<nr_uio;i++) {
debug_conn(4, "ioreq.uio[%d]: %p:%d", i, uio[i].ptr, uio[i].len);
}
#endif
transfered_sectors = 0;
// Init LSP request
reqd.nr_uio = nr_uio;
reqd.uio = uio;
reqd.cur_uio = uio;
reqd.cur_uio_offset = 0;
do {
debug_conn(4, "req->num_sec=%d, split_size=%d",
num_sec, split_size);
to_transfer = (num_sec - transfered_sectors <= split_size) ? (num_sec - transfered_sectors) : split_size;
// Setup lsp_transfer_param_t structure
reqd.num_sec = to_transfer;
reqd.translen = CONN_SECTOR_TO_BYTE(to_transfer);
reqd.start_sec.quad = start_sec;
retry:
#ifdef USE_FLOW_CONTROL
lpx_reset_retransmit_count(conn->sock);
#endif
if (conn->mode & NDAS_CONN_MODE_LOCKED) {
sal_assert(conn->BuffLockCtl);
sal_assert(conn->LockInfo);
debug_conn(4, "Acquiring buffer lock");
err = NdasAcquireBufferLock(conn->BuffLockCtl, conn, conn->LockInfo, NULL, 0);
if (err == NDAS_ERROR_UNSUPPORTED_HARDWARE_VERSION) {
// This should not happen. Anyway ignore lock failure
debug_conn(1, "Unsupported version");
} else if (!NDAS_SUCCESS(err)) {
debug_conn(1, "Failed to take buffer lock");
break;
}
}
// Execute the command at the remote.
err = conn_rw_io_execute(cmd, conn, &reqd, &split_size);
if (!NDAS_SUCCESS(err)) {
debug_conn(4, "conn_transport_process_transfer() failed. %d", err);
if (err == NDAS_ERROR_IDE_REMOTE_COMMAND_FAILED) {
retrial++;
if (retrial < 5) {
debug_conn(1, "Retrying IO #%d", retrial);
reqd.num_sec = to_transfer;
reqd.translen = CONN_SECTOR_TO_BYTE(to_transfer);
goto retry;
}
} else {
err = conn_reconnect(conn);
}
if (NDAS_SUCCESS(err)) {
// Recovered from error. Continue
reqd.num_sec = to_transfer;
reqd.translen = CONN_SECTOR_TO_BYTE(to_transfer);
goto retry;
}
debug_conn(1, "Fatal error. Stopping IO");
break;
} else {
/* Succeeded in IO after retrial. Reset retrial count */
retrial = 0;
if (conn->mode & NDAS_CONN_MODE_LOCKED) {
debug_conn(4, "Releasing buffer lock");
err = NdasReleaseBufferLock(conn->BuffLockCtl, conn, conn->LockInfo, NULL, 0, FALSE, reqd.num_sec * 512);
if (err == NDAS_ERROR_UNSUPPORTED_HARDWARE_VERSION) {
// This should not happen. Anyway ignore lock failure
debug_conn(1, "Unsupported version");
} else if (!NDAS_SUCCESS(err)) {
debug_conn(1, "Failed to release buffer lock: err=%d", err);
break;