You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

srp.c 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761
  1. /*
  2. * Copyright (C) 2009 Fen Systems Ltd <mbrown@fensystems.co.uk>.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. *
  12. * Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in
  14. * the documentation and/or other materials provided with the
  15. * distribution.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  22. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  24. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  25. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  26. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  27. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  28. * OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. FILE_LICENCE ( BSD2 );
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <errno.h>
  34. #include <ipxe/scsi.h>
  35. #include <ipxe/xfer.h>
  36. #include <ipxe/features.h>
  37. #include <ipxe/srp.h>
  38. /**
  39. * @file
  40. *
  41. * SCSI RDMA Protocol
  42. *
  43. */
  44. FEATURE ( FEATURE_PROTOCOL, "SRP", DHCP_EB_FEATURE_SRP, 1 );
  45. /** Maximum length of any initiator-to-target IU that we will send
  46. *
  47. * The longest IU is a SRP_CMD with no additional CDB and two direct
  48. * data buffer descriptors, which comes to 80 bytes.
  49. */
  50. #define SRP_MAX_I_T_IU_LEN 80
  51. /* Error numbers generated by SRP login rejection */
  52. #define EINFO_SRP_LOGIN_REJ( reason, desc ) \
  53. __einfo_uniqify ( EINFO_EPERM, ( (reason) & 0x0f ), desc )
  54. #define EPERM_UNKNOWN \
  55. __einfo_error ( EINFO_EPERM_UNKNOWN )
  56. #define EINFO_EPERM_UNKNOWN EINFO_SRP_LOGIN_REJ ( \
  57. SRP_LOGIN_REJ_REASON_UNKNOWN, \
  58. "Unable to establish RDMA channel, no reason specified" )
  59. #define EPERM_INSUFFICIENT_RESOURCES \
  60. __einfo_error ( EINFO_EPERM_INSUFFICIENT_RESOURCES )
  61. #define EINFO_EPERM_INSUFFICIENT_RESOURCES EINFO_SRP_LOGIN_REJ ( \
  62. SRP_LOGIN_REJ_REASON_INSUFFICIENT_RESOURCES, \
  63. "Insufficient RDMA channel resources" )
  64. #define EPERM_BAD_MAX_I_T_IU_LEN \
  65. __einfo_error ( EINFO_EPERM_BAD_MAX_I_T_IU_LEN )
  66. #define EINFO_EPERM_BAD_MAX_I_T_IU_LEN EINFO_SRP_LOGIN_REJ ( \
  67. SRP_LOGIN_REJ_REASON_BAD_MAX_I_T_IU_LEN, \
  68. "Requested maximum initiator to target IU length value too large" )
  69. #define EPERM_CANNOT_ASSOCIATE \
  70. __einfo_error ( EINFO_EPERM_CANNOT_ASSOCIATE )
  71. #define EINFO_EPERM_CANNOT_ASSOCIATE EINFO_SRP_LOGIN_REJ ( \
  72. SRP_LOGIN_REJ_REASON_CANNOT_ASSOCIATE, \
  73. "Unable to associate RDMA channel with specified I_T nexus" )
  74. #define EPERM_UNSUPPORTED_BUFFER_FORMAT \
  75. __einfo_error ( EINFO_EPERM_UNSUPPORTED_BUFFER_FORMAT )
  76. #define EINFO_EPERM_UNSUPPORTED_BUFFER_FORMAT EINFO_SRP_LOGIN_REJ ( \
  77. SRP_LOGIN_REJ_REASON_UNSUPPORTED_BUFFER_FORMAT, \
  78. "One or more requested data buffer descriptor formats not supported" )
  79. #define EPERM_NO_MULTIPLE_CHANNELS \
  80. __einfo_error ( EINFO_EPERM_NO_MULTIPLE_CHANNELS )
  81. #define EINFO_EPERM_NO_MULTIPLE_CHANNELS EINFO_SRP_LOGIN_REJ ( \
  82. SRP_LOGIN_REJ_REASON_NO_MULTIPLE_CHANNELS, \
  83. "SRP target does not support multiple RDMA channels per I_T nexus" )
  84. #define EPERM_NO_MORE_CHANNELS \
  85. __einfo_error ( EINFO_EPERM_NO_MORE_CHANNELS )
  86. #define EINFO_EPERM_NO_MORE_CHANNELS EINFO_SRP_LOGIN_REJ ( \
  87. SRP_LOGIN_REJ_REASON_NO_MORE_CHANNELS, \
  88. "RDMA channel limit reached for this initiator" )
  89. #define EPERM_LOGIN_REJ( reason_nibble ) \
  90. EUNIQ ( EINFO_EPERM, (reason_nibble), EPERM_UNKNOWN, \
  91. EPERM_INSUFFICIENT_RESOURCES, EPERM_BAD_MAX_I_T_IU_LEN, \
  92. EPERM_CANNOT_ASSOCIATE, EPERM_UNSUPPORTED_BUFFER_FORMAT, \
  93. EPERM_NO_MULTIPLE_CHANNELS, EPERM_NO_MORE_CHANNELS )
  94. /** An SRP device */
  95. struct srp_device {
  96. /** Reference count */
  97. struct refcnt refcnt;
  98. /** SCSI command issuing interface */
  99. struct interface scsi;
  100. /** Underlying data transfer interface */
  101. struct interface socket;
  102. /** RDMA memory handle */
  103. uint32_t memory_handle;
  104. /** Login completed successfully */
  105. int logged_in;
  106. /** List of active commands */
  107. struct list_head commands;
  108. };
  109. /** An SRP command */
  110. struct srp_command {
  111. /** Reference count */
  112. struct refcnt refcnt;
  113. /** SRP device */
  114. struct srp_device *srpdev;
  115. /** List of active commands */
  116. struct list_head list;
  117. /** SCSI command interface */
  118. struct interface scsi;
  119. /** Command tag */
  120. uint32_t tag;
  121. };
  122. /**
  123. * Get reference to SRP device
  124. *
  125. * @v srpdev SRP device
  126. * @ret srpdev SRP device
  127. */
  128. static inline __attribute__ (( always_inline )) struct srp_device *
  129. srpdev_get ( struct srp_device *srpdev ) {
  130. ref_get ( &srpdev->refcnt );
  131. return srpdev;
  132. }
  133. /**
  134. * Drop reference to SRP device
  135. *
  136. * @v srpdev SRP device
  137. */
  138. static inline __attribute__ (( always_inline )) void
  139. srpdev_put ( struct srp_device *srpdev ) {
  140. ref_put ( &srpdev->refcnt );
  141. }
  142. /**
  143. * Get reference to SRP command
  144. *
  145. * @v srpcmd SRP command
  146. * @ret srpcmd SRP command
  147. */
  148. static inline __attribute__ (( always_inline )) struct srp_command *
  149. srpcmd_get ( struct srp_command *srpcmd ) {
  150. ref_get ( &srpcmd->refcnt );
  151. return srpcmd;
  152. }
  153. /**
  154. * Drop reference to SRP command
  155. *
  156. * @v srpcmd SRP command
  157. */
  158. static inline __attribute__ (( always_inline )) void
  159. srpcmd_put ( struct srp_command *srpcmd ) {
  160. ref_put ( &srpcmd->refcnt );
  161. }
  162. /**
  163. * Free SRP command
  164. *
  165. * @v refcnt Reference count
  166. */
  167. static void srpcmd_free ( struct refcnt *refcnt ) {
  168. struct srp_command *srpcmd =
  169. container_of ( refcnt, struct srp_command, refcnt );
  170. assert ( list_empty ( &srpcmd->list ) );
  171. srpdev_put ( srpcmd->srpdev );
  172. free ( srpcmd );
  173. }
  174. /**
  175. * Close SRP command
  176. *
  177. * @v srpcmd SRP command
  178. * @v rc Reason for close
  179. */
  180. static void srpcmd_close ( struct srp_command *srpcmd, int rc ) {
  181. struct srp_device *srpdev = srpcmd->srpdev;
  182. if ( rc != 0 ) {
  183. DBGC ( srpdev, "SRP %p tag %08x closed: %s\n",
  184. srpdev, srpcmd->tag, strerror ( rc ) );
  185. }
  186. /* Remove from list of commands */
  187. if ( ! list_empty ( &srpcmd->list ) ) {
  188. list_del ( &srpcmd->list );
  189. INIT_LIST_HEAD ( &srpcmd->list );
  190. srpcmd_put ( srpcmd );
  191. }
  192. /* Shut down interfaces */
  193. intf_shutdown ( &srpcmd->scsi, rc );
  194. }
  195. /**
  196. * Close SRP device
  197. *
  198. * @v srpdev SRP device
  199. * @v rc Reason for close
  200. */
  201. static void srpdev_close ( struct srp_device *srpdev, int rc ) {
  202. struct srp_command *srpcmd;
  203. struct srp_command *tmp;
  204. if ( rc != 0 ) {
  205. DBGC ( srpdev, "SRP %p closed: %s\n",
  206. srpdev, strerror ( rc ) );
  207. }
  208. /* Shut down interfaces */
  209. intf_shutdown ( &srpdev->socket, rc );
  210. intf_shutdown ( &srpdev->scsi, rc );
  211. /* Shut down any active commands */
  212. list_for_each_entry_safe ( srpcmd, tmp, &srpdev->commands, list ) {
  213. srpcmd_get ( srpcmd );
  214. srpcmd_close ( srpcmd, rc );
  215. srpcmd_put ( srpcmd );
  216. }
  217. }
  218. /**
  219. * Identify SRP command by tag
  220. *
  221. * @v srpdev SRP device
  222. * @v tag Command tag
  223. * @ret srpcmd SRP command, or NULL
  224. */
  225. static struct srp_command * srp_find_tag ( struct srp_device *srpdev,
  226. uint32_t tag ) {
  227. struct srp_command *srpcmd;
  228. list_for_each_entry ( srpcmd, &srpdev->commands, list ) {
  229. if ( srpcmd->tag == tag )
  230. return srpcmd;
  231. }
  232. return NULL;
  233. }
  234. /**
  235. * Choose an SRP command tag
  236. *
  237. * @v srpdev SRP device
  238. * @ret tag New tag, or negative error
  239. */
  240. static int srp_new_tag ( struct srp_device *srpdev ) {
  241. static uint16_t tag_idx;
  242. unsigned int i;
  243. for ( i = 0 ; i < 65536 ; i++ ) {
  244. tag_idx++;
  245. if ( srp_find_tag ( srpdev, tag_idx ) == NULL )
  246. return tag_idx;
  247. }
  248. return -EADDRINUSE;
  249. }
  250. /**
  251. * Transmit SRP login request
  252. *
  253. * @v srpdev SRP device
  254. * @v initiator Initiator port ID
  255. * @v target Target port ID
  256. * @v tag Command tag
  257. * @ret rc Return status code
  258. */
  259. static int srp_login ( struct srp_device *srpdev, union srp_port_id *initiator,
  260. union srp_port_id *target, uint32_t tag ) {
  261. struct io_buffer *iobuf;
  262. struct srp_login_req *login_req;
  263. int rc;
  264. /* Allocate I/O buffer */
  265. iobuf = xfer_alloc_iob ( &srpdev->socket, sizeof ( *login_req ) );
  266. if ( ! iobuf )
  267. return -ENOMEM;
  268. /* Construct login request IU */
  269. login_req = iob_put ( iobuf, sizeof ( *login_req ) );
  270. memset ( login_req, 0, sizeof ( *login_req ) );
  271. login_req->type = SRP_LOGIN_REQ;
  272. login_req->tag.dwords[0] = htonl ( SRP_TAG_MAGIC );
  273. login_req->tag.dwords[1] = htonl ( tag );
  274. login_req->max_i_t_iu_len = htonl ( SRP_MAX_I_T_IU_LEN );
  275. login_req->required_buffer_formats = SRP_LOGIN_REQ_FMT_DDBD;
  276. memcpy ( &login_req->initiator, initiator,
  277. sizeof ( login_req->initiator ) );
  278. memcpy ( &login_req->target, target, sizeof ( login_req->target ) );
  279. DBGC ( srpdev, "SRP %p tag %08x LOGIN_REQ:\n", srpdev, tag );
  280. DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );
  281. /* Send login request IU */
  282. if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) {
  283. DBGC ( srpdev, "SRP %p tag %08x could not send LOGIN_REQ: "
  284. "%s\n", srpdev, tag, strerror ( rc ) );
  285. return rc;
  286. }
  287. return 0;
  288. }
  289. /**
  290. * Receive SRP login response
  291. *
  292. * @v srpdev SRP device
  293. * @v data SRP IU
  294. * @v len Length of SRP IU
  295. * @ret rc Return status code
  296. */
  297. static int srp_login_rsp ( struct srp_device *srpdev,
  298. const void *data, size_t len ) {
  299. const struct srp_login_rsp *login_rsp = data;
  300. /* Sanity check */
  301. if ( len < sizeof ( *login_rsp ) ) {
  302. DBGC ( srpdev, "SRP %p LOGIN_RSP too short (%zd bytes)\n",
  303. srpdev, len );
  304. return -EINVAL;
  305. }
  306. DBGC ( srpdev, "SRP %p tag %08x LOGIN_RSP:\n",
  307. srpdev, ntohl ( login_rsp->tag.dwords[1] ) );
  308. DBGC_HDA ( srpdev, 0, data, len );
  309. /* Mark as logged in */
  310. srpdev->logged_in = 1;
  311. DBGC ( srpdev, "SRP %p logged in\n", srpdev );
  312. /* Notify of window change */
  313. xfer_window_changed ( &srpdev->scsi );
  314. return 0;
  315. }
  316. /**
  317. * Receive SRP login rejection
  318. *
  319. * @v srpdev SRP device
  320. * @v data SRP IU
  321. * @v len Length of SRP IU
  322. * @ret rc Return status code
  323. */
  324. static int srp_login_rej ( struct srp_device *srpdev,
  325. const void *data, size_t len ) {
  326. const struct srp_login_rej *login_rej = data;
  327. uint32_t reason;
  328. /* Sanity check */
  329. if ( len < sizeof ( *login_rej ) ) {
  330. DBGC ( srpdev, "SRP %p LOGIN_REJ too short (%zd bytes)\n",
  331. srpdev, len );
  332. return -EINVAL;
  333. }
  334. reason = ntohl ( login_rej->reason );
  335. DBGC ( srpdev, "SRP %p tag %08x LOGIN_REJ reason %08x:\n",
  336. srpdev, ntohl ( login_rej->tag.dwords[1] ), reason );
  337. DBGC_HDA ( srpdev, 0, data, len );
  338. /* Login rejection always indicates an error */
  339. return ( SRP_LOGIN_REJ_REASON_DEFINED ( reason ) ?
  340. -EPERM_LOGIN_REJ ( reason ) : -EACCES );
  341. }
  342. /**
  343. * Transmit SRP SCSI command
  344. *
  345. * @v srpdev SRP device
  346. * @v command SCSI command
  347. * @v tag Command tag
  348. * @ret rc Return status code
  349. */
  350. static int srp_cmd ( struct srp_device *srpdev,
  351. struct scsi_cmd *command,
  352. uint32_t tag ) {
  353. struct io_buffer *iobuf;
  354. struct srp_cmd *cmd;
  355. struct srp_memory_descriptor *data_out;
  356. struct srp_memory_descriptor *data_in;
  357. int rc;
  358. /* Sanity check */
  359. if ( ! srpdev->logged_in ) {
  360. DBGC ( srpdev, "SRP %p tag %08x cannot send CMD before "
  361. "login completes\n", srpdev, tag );
  362. return -EBUSY;
  363. }
  364. /* Allocate I/O buffer */
  365. iobuf = xfer_alloc_iob ( &srpdev->socket, SRP_MAX_I_T_IU_LEN );
  366. if ( ! iobuf )
  367. return -ENOMEM;
  368. /* Construct base portion */
  369. cmd = iob_put ( iobuf, sizeof ( *cmd ) );
  370. memset ( cmd, 0, sizeof ( *cmd ) );
  371. cmd->type = SRP_CMD;
  372. cmd->tag.dwords[0] = htonl ( SRP_TAG_MAGIC );
  373. cmd->tag.dwords[1] = htonl ( tag );
  374. memcpy ( &cmd->lun, &command->lun, sizeof ( cmd->lun ) );
  375. memcpy ( &cmd->cdb, &command->cdb, sizeof ( cmd->cdb ) );
  376. /* Construct data-out descriptor, if present */
  377. if ( command->data_out ) {
  378. cmd->data_buffer_formats |= SRP_CMD_DO_FMT_DIRECT;
  379. data_out = iob_put ( iobuf, sizeof ( *data_out ) );
  380. data_out->address =
  381. cpu_to_be64 ( user_to_phys ( command->data_out, 0 ) );
  382. data_out->handle = ntohl ( srpdev->memory_handle );
  383. data_out->len = ntohl ( command->data_out_len );
  384. }
  385. /* Construct data-in descriptor, if present */
  386. if ( command->data_in ) {
  387. cmd->data_buffer_formats |= SRP_CMD_DI_FMT_DIRECT;
  388. data_in = iob_put ( iobuf, sizeof ( *data_in ) );
  389. data_in->address =
  390. cpu_to_be64 ( user_to_phys ( command->data_in, 0 ) );
  391. data_in->handle = ntohl ( srpdev->memory_handle );
  392. data_in->len = ntohl ( command->data_in_len );
  393. }
  394. DBGC2 ( srpdev, "SRP %p tag %08x CMD " SCSI_CDB_FORMAT "\n",
  395. srpdev, tag, SCSI_CDB_DATA ( cmd->cdb ) );
  396. /* Send IU */
  397. if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) {
  398. DBGC ( srpdev, "SRP %p tag %08x could not send CMD: %s\n",
  399. srpdev, tag, strerror ( rc ) );
  400. return rc;
  401. }
  402. return 0;
  403. }
  404. /**
  405. * Receive SRP SCSI response
  406. *
  407. * @v srpdev SRP device
  408. * @v data SRP IU
  409. * @v len Length of SRP IU
  410. * @ret rc Returns status code
  411. */
  412. static int srp_rsp ( struct srp_device *srpdev,
  413. const void *data, size_t len ) {
  414. const struct srp_rsp *rsp = data;
  415. struct srp_command *srpcmd;
  416. struct scsi_rsp response;
  417. ssize_t data_out_residual_count;
  418. ssize_t data_in_residual_count;
  419. /* Sanity check */
  420. if ( ( len < sizeof ( *rsp ) ) ||
  421. ( len < ( sizeof ( *rsp ) +
  422. srp_rsp_response_data_len ( rsp ) +
  423. srp_rsp_sense_data_len ( rsp ) ) ) ) {
  424. DBGC ( srpdev, "SRP %p RSP too short (%zd bytes)\n",
  425. srpdev, len );
  426. return -EINVAL;
  427. }
  428. DBGC2 ( srpdev, "SRP %p tag %08x RSP stat %02x dores %08x dires "
  429. "%08x valid %02x%s%s%s%s%s%s\n",
  430. srpdev, ntohl ( rsp->tag.dwords[1] ), rsp->status,
  431. ntohl ( rsp->data_out_residual_count ),
  432. ntohl ( rsp->data_in_residual_count ), rsp->valid,
  433. ( ( rsp->valid & SRP_RSP_VALID_DIUNDER ) ? " diunder" : "" ),
  434. ( ( rsp->valid & SRP_RSP_VALID_DIOVER ) ? " diover" : "" ),
  435. ( ( rsp->valid & SRP_RSP_VALID_DOUNDER ) ? " dounder" : "" ),
  436. ( ( rsp->valid & SRP_RSP_VALID_DOOVER ) ? " doover" : "" ),
  437. ( ( rsp->valid & SRP_RSP_VALID_SNSVALID ) ? " sns" : "" ),
  438. ( ( rsp->valid & SRP_RSP_VALID_RSPVALID ) ? " rsp" : "" ) );
  439. /* Identify command by tag */
  440. srpcmd = srp_find_tag ( srpdev, ntohl ( rsp->tag.dwords[1] ) );
  441. if ( ! srpcmd ) {
  442. DBGC ( srpdev, "SRP %p tag %08x unrecognised RSP\n",
  443. srpdev, ntohl ( rsp->tag.dwords[1] ) );
  444. return -ENOENT;
  445. }
  446. /* Hold command reference for remainder of function */
  447. srpcmd_get ( srpcmd );
  448. /* Build SCSI response */
  449. memset ( &response, 0, sizeof ( response ) );
  450. response.status = rsp->status;
  451. data_out_residual_count = ntohl ( rsp->data_out_residual_count );
  452. data_in_residual_count = ntohl ( rsp->data_in_residual_count );
  453. if ( rsp->valid & SRP_RSP_VALID_DOOVER ) {
  454. response.overrun = data_out_residual_count;
  455. } else if ( rsp->valid & SRP_RSP_VALID_DOUNDER ) {
  456. response.overrun = -(data_out_residual_count);
  457. } else if ( rsp->valid & SRP_RSP_VALID_DIOVER ) {
  458. response.overrun = data_in_residual_count;
  459. } else if ( rsp->valid & SRP_RSP_VALID_DIUNDER ) {
  460. response.overrun = -(data_in_residual_count);
  461. }
  462. scsi_parse_sense ( srp_rsp_sense_data ( rsp ),
  463. srp_rsp_sense_data_len ( rsp ), &response.sense );
  464. /* Report SCSI response */
  465. scsi_response ( &srpcmd->scsi, &response );
  466. /* Close SCSI command */
  467. srpcmd_close ( srpcmd, 0 );
  468. /* Drop temporary command reference */
  469. srpcmd_put ( srpcmd );
  470. return 0;
  471. }
  472. /**
  473. * Receive SRP unrecognised response IU
  474. *
  475. * @v srpdev SRP device
  476. * @v data SRP IU
  477. * @v len Length of SRP IU
  478. * @ret rc Returns status code
  479. */
  480. static int srp_unrecognised ( struct srp_device *srpdev,
  481. const void *data, size_t len ) {
  482. const struct srp_common *common = data;
  483. DBGC ( srpdev, "SRP %p tag %08x unrecognised IU type %02x:\n",
  484. srpdev, ntohl ( common->tag.dwords[1] ), common->type );
  485. DBGC_HDA ( srpdev, 0, data, len );
  486. return -ENOTSUP;
  487. }
  488. /** SRP command SCSI interface operations */
  489. static struct interface_operation srpcmd_scsi_op[] = {
  490. INTF_OP ( intf_close, struct srp_command *, srpcmd_close ),
  491. };
  492. /** SRP command SCSI interface descriptor */
  493. static struct interface_descriptor srpcmd_scsi_desc =
  494. INTF_DESC ( struct srp_command, scsi, srpcmd_scsi_op );
  495. /**
  496. * Issue SRP SCSI command
  497. *
  498. * @v srpdev SRP device
  499. * @v parent Parent interface
  500. * @v command SCSI command
  501. * @ret tag Command tag, or negative error
  502. */
  503. static int srpdev_scsi_command ( struct srp_device *srpdev,
  504. struct interface *parent,
  505. struct scsi_cmd *command ) {
  506. struct srp_command *srpcmd;
  507. int tag;
  508. int rc;
  509. /* Allocate command tag */
  510. tag = srp_new_tag ( srpdev );
  511. if ( tag < 0 ) {
  512. rc = tag;
  513. goto err_tag;
  514. }
  515. /* Allocate and initialise structure */
  516. srpcmd = zalloc ( sizeof ( *srpcmd ) );
  517. if ( ! srpcmd ) {
  518. rc = -ENOMEM;
  519. goto err_zalloc;
  520. }
  521. ref_init ( &srpcmd->refcnt, srpcmd_free );
  522. intf_init ( &srpcmd->scsi, &srpcmd_scsi_desc, &srpcmd->refcnt );
  523. srpcmd->srpdev = srpdev_get ( srpdev );
  524. list_add ( &srpcmd->list, &srpdev->commands );
  525. srpcmd->tag = tag;
  526. /* Send command IU */
  527. if ( ( rc = srp_cmd ( srpdev, command, srpcmd->tag ) ) != 0 )
  528. goto err_cmd;
  529. /* Attach to parent interface, leave reference with command
  530. * list, and return.
  531. */
  532. intf_plug_plug ( &srpcmd->scsi, parent );
  533. return srpcmd->tag;
  534. err_cmd:
  535. srpcmd_close ( srpcmd, rc );
  536. err_zalloc:
  537. err_tag:
  538. return rc;
  539. }
  540. /**
  541. * Receive data from SRP socket
  542. *
  543. * @v srpdev SRP device
  544. * @v iobuf Datagram I/O buffer
  545. * @v meta Data transfer metadata
  546. * @ret rc Return status code
  547. */
  548. static int srpdev_deliver ( struct srp_device *srpdev,
  549. struct io_buffer *iobuf,
  550. struct xfer_metadata *meta __unused ) {
  551. struct srp_common *common = iobuf->data;
  552. int ( * type ) ( struct srp_device *srp, const void *data, size_t len );
  553. int rc;
  554. /* Sanity check */
  555. if ( iob_len ( iobuf ) < sizeof ( *common ) ) {
  556. DBGC ( srpdev, "SRP %p IU too short (%zd bytes)\n",
  557. srpdev, iob_len ( iobuf ) );
  558. rc = -EINVAL;
  559. goto err;
  560. }
  561. /* Determine IU type */
  562. switch ( common->type ) {
  563. case SRP_LOGIN_RSP:
  564. type = srp_login_rsp;
  565. break;
  566. case SRP_LOGIN_REJ:
  567. type = srp_login_rej;
  568. break;
  569. case SRP_RSP:
  570. type = srp_rsp;
  571. break;
  572. default:
  573. type = srp_unrecognised;
  574. break;
  575. }
  576. /* Handle IU */
  577. if ( ( rc = type ( srpdev, iobuf->data, iob_len ( iobuf ) ) ) != 0 )
  578. goto err;
  579. free_iob ( iobuf );
  580. return 0;
  581. err:
  582. DBGC ( srpdev, "SRP %p closing due to received IU (%s):\n",
  583. srpdev, strerror ( rc ) );
  584. DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );
  585. free_iob ( iobuf );
  586. srpdev_close ( srpdev, rc );
  587. return rc;
  588. }
  589. /**
  590. * Check SRP device flow-control window
  591. *
  592. * @v srpdev SRP device
  593. * @ret len Length of window
  594. */
  595. static size_t srpdev_window ( struct srp_device *srpdev ) {
  596. return ( srpdev->logged_in ? ~( ( size_t ) 0 ) : 0 );
  597. }
  598. /** SRP device socket interface operations */
  599. static struct interface_operation srpdev_socket_op[] = {
  600. INTF_OP ( xfer_deliver, struct srp_device *, srpdev_deliver ),
  601. INTF_OP ( intf_close, struct srp_device *, srpdev_close ),
  602. };
  603. /** SRP device socket interface descriptor */
  604. static struct interface_descriptor srpdev_socket_desc =
  605. INTF_DESC_PASSTHRU ( struct srp_device, socket, srpdev_socket_op,
  606. scsi );
  607. /** SRP device SCSI interface operations */
  608. static struct interface_operation srpdev_scsi_op[] = {
  609. INTF_OP ( scsi_command, struct srp_device *, srpdev_scsi_command ),
  610. INTF_OP ( xfer_window, struct srp_device *, srpdev_window ),
  611. INTF_OP ( intf_close, struct srp_device *, srpdev_close ),
  612. };
  613. /** SRP device SCSI interface descriptor */
  614. static struct interface_descriptor srpdev_scsi_desc =
  615. INTF_DESC_PASSTHRU ( struct srp_device, scsi, srpdev_scsi_op, socket );
  616. /**
  617. * Open SRP device
  618. *
  619. * @v block Block control interface
  620. * @v socket Socket interface
  621. * @v initiator Initiator port ID
  622. * @v target Target port ID
  623. * @v memory_handle RDMA memory handle
  624. * @v lun SCSI LUN
  625. * @ret rc Return status code
  626. */
  627. int srp_open ( struct interface *block, struct interface *socket,
  628. union srp_port_id *initiator, union srp_port_id *target,
  629. uint32_t memory_handle, struct scsi_lun *lun ) {
  630. struct srp_device *srpdev;
  631. int tag;
  632. int rc;
  633. /* Allocate and initialise structure */
  634. srpdev = zalloc ( sizeof ( *srpdev ) );
  635. if ( ! srpdev ) {
  636. rc = -ENOMEM;
  637. goto err_zalloc;
  638. }
  639. ref_init ( &srpdev->refcnt, NULL );
  640. intf_init ( &srpdev->scsi, &srpdev_scsi_desc, &srpdev->refcnt );
  641. intf_init ( &srpdev->socket, &srpdev_socket_desc, &srpdev->refcnt );
  642. INIT_LIST_HEAD ( &srpdev->commands );
  643. srpdev->memory_handle = memory_handle;
  644. DBGC ( srpdev, "SRP %p %08x%08x%08x%08x->%08x%08x%08x%08x\n", srpdev,
  645. ntohl ( initiator->dwords[0] ), ntohl ( initiator->dwords[1] ),
  646. ntohl ( initiator->dwords[2] ), ntohl ( initiator->dwords[3] ),
  647. ntohl ( target->dwords[0] ), ntohl ( target->dwords[1] ),
  648. ntohl ( target->dwords[2] ), ntohl ( target->dwords[3] ) );
  649. /* Attach to socket interface and initiate login */
  650. intf_plug_plug ( &srpdev->socket, socket );
  651. tag = srp_new_tag ( srpdev );
  652. assert ( tag >= 0 ); /* Cannot fail when no commands in progress */
  653. if ( ( rc = srp_login ( srpdev, initiator, target, tag ) ) != 0 )
  654. goto err_login;
  655. /* Attach SCSI device to parent interface */
  656. if ( ( rc = scsi_open ( block, &srpdev->scsi, lun ) ) != 0 ) {
  657. DBGC ( srpdev, "SRP %p could not create SCSI device: %s\n",
  658. srpdev, strerror ( rc ) );
  659. goto err_scsi_open;
  660. }
  661. /* Mortalise self and return */
  662. ref_put ( &srpdev->refcnt );
  663. return 0;
  664. err_scsi_open:
  665. err_login:
  666. srpdev_close ( srpdev, rc );
  667. ref_put ( &srpdev->refcnt );
  668. err_zalloc:
  669. return rc;
  670. }