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 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  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 <gpxe/scsi.h>
  35. #include <gpxe/xfer.h>
  36. #include <gpxe/features.h>
  37. #include <gpxe/ib_srp.h>
  38. #include <gpxe/srp.h>
  39. /**
  40. * @file
  41. *
  42. * SCSI RDMA Protocol
  43. *
  44. */
  45. FEATURE ( FEATURE_PROTOCOL, "SRP", DHCP_EB_FEATURE_SRP, 1 );
  46. /** Tag to be used for next SRP IU */
  47. static unsigned int srp_tag = 0;
  48. static void srp_login ( struct srp_device *srp );
  49. static void srp_cmd ( struct srp_device *srp );
  50. /**
  51. * Mark SRP SCSI command as complete
  52. *
  53. * @v srp SRP device
  54. * @v rc Status code
  55. */
  56. static void srp_scsi_done ( struct srp_device *srp, int rc ) {
  57. if ( srp->command )
  58. srp->command->rc = rc;
  59. srp->command = NULL;
  60. }
  61. /**
  62. * Handle SRP session failure
  63. *
  64. * @v srp SRP device
  65. * @v rc Reason for failure
  66. */
  67. static void srp_fail ( struct srp_device *srp, int rc ) {
  68. /* Close underlying socket */
  69. xfer_close ( &srp->socket, rc );
  70. /* Clear session state */
  71. srp->state = 0;
  72. /* If we have reached the retry limit, report the failure */
  73. if ( srp->retry_count >= SRP_MAX_RETRIES ) {
  74. srp_scsi_done ( srp, rc );
  75. return;
  76. }
  77. /* Otherwise, increment the retry count and try to reopen the
  78. * connection
  79. */
  80. srp->retry_count++;
  81. srp_login ( srp );
  82. }
  83. /**
  84. * Initiate SRP login
  85. *
  86. * @v srp SRP device
  87. */
  88. static void srp_login ( struct srp_device *srp ) {
  89. struct io_buffer *iobuf;
  90. struct srp_login_req *login_req;
  91. int rc;
  92. assert ( ! ( srp->state & SRP_STATE_SOCKET_OPEN ) );
  93. /* Open underlying socket */
  94. if ( ( rc = srp->transport->connect ( srp ) ) != 0 ) {
  95. DBGC ( srp, "SRP %p could not open socket: %s\n",
  96. srp, strerror ( rc ) );
  97. goto err;
  98. }
  99. srp->state |= SRP_STATE_SOCKET_OPEN;
  100. /* Allocate I/O buffer */
  101. iobuf = xfer_alloc_iob ( &srp->socket, sizeof ( *login_req ) );
  102. if ( ! iobuf ) {
  103. rc = -ENOMEM;
  104. goto err;
  105. }
  106. /* Construct login request IU */
  107. login_req = iob_put ( iobuf, sizeof ( *login_req ) );
  108. memset ( login_req, 0, sizeof ( *login_req ) );
  109. login_req->type = SRP_LOGIN_REQ;
  110. login_req->tag.dwords[1] = htonl ( ++srp_tag );
  111. login_req->max_i_t_iu_len = htonl ( SRP_MAX_I_T_IU_LEN );
  112. login_req->required_buffer_formats = SRP_LOGIN_REQ_FMT_DDBD;
  113. memcpy ( &login_req->port_ids, &srp->port_ids,
  114. sizeof ( login_req->port_ids ) );
  115. DBGC2 ( srp, "SRP %p TX login request tag %08x%08x\n",
  116. srp, ntohl ( login_req->tag.dwords[0] ),
  117. ntohl ( login_req->tag.dwords[1] ) );
  118. DBGC2_HDA ( srp, 0, iobuf->data, iob_len ( iobuf ) );
  119. /* Send login request IU */
  120. if ( ( rc = xfer_deliver_iob ( &srp->socket, iobuf ) ) != 0 ) {
  121. DBGC ( srp, "SRP %p could not send login request: %s\n",
  122. srp, strerror ( rc ) );
  123. goto err;
  124. }
  125. return;
  126. err:
  127. srp_fail ( srp, rc );
  128. }
  129. /**
  130. * Handle SRP login response
  131. *
  132. * @v srp SRP device
  133. * @v iobuf I/O buffer
  134. * @ret rc Return status code
  135. */
  136. static int srp_login_rsp ( struct srp_device *srp, struct io_buffer *iobuf ) {
  137. struct srp_login_rsp *login_rsp = iobuf->data;
  138. int rc;
  139. DBGC2 ( srp, "SRP %p RX login response tag %08x%08x\n",
  140. srp, ntohl ( login_rsp->tag.dwords[0] ),
  141. ntohl ( login_rsp->tag.dwords[1] ) );
  142. /* Sanity check */
  143. if ( iob_len ( iobuf ) < sizeof ( *login_rsp ) ) {
  144. DBGC ( srp, "SRP %p RX login response too short (%zd bytes)\n",
  145. srp, iob_len ( iobuf ) );
  146. rc = -EINVAL;
  147. goto out;
  148. }
  149. DBGC ( srp, "SRP %p logged in\n", srp );
  150. /* Mark as logged in */
  151. srp->state |= SRP_STATE_LOGGED_IN;
  152. /* Reset error counter */
  153. srp->retry_count = 0;
  154. /* Issue pending command */
  155. srp_cmd ( srp );
  156. rc = 0;
  157. out:
  158. free_iob ( iobuf );
  159. return rc;
  160. }
  161. /**
  162. * Handle SRP login rejection
  163. *
  164. * @v srp SRP device
  165. * @v iobuf I/O buffer
  166. * @ret rc Return status code
  167. */
  168. static int srp_login_rej ( struct srp_device *srp, struct io_buffer *iobuf ) {
  169. struct srp_login_rej *login_rej = iobuf->data;
  170. int rc;
  171. DBGC2 ( srp, "SRP %p RX login rejection tag %08x%08x\n",
  172. srp, ntohl ( login_rej->tag.dwords[0] ),
  173. ntohl ( login_rej->tag.dwords[1] ) );
  174. /* Sanity check */
  175. if ( iob_len ( iobuf ) < sizeof ( *login_rej ) ) {
  176. DBGC ( srp, "SRP %p RX login rejection too short (%zd "
  177. "bytes)\n", srp, iob_len ( iobuf ) );
  178. rc = -EINVAL;
  179. goto out;
  180. }
  181. /* Login rejection always indicates an error */
  182. DBGC ( srp, "SRP %p login rejected (reason %08x)\n",
  183. srp, ntohl ( login_rej->reason ) );
  184. rc = -EPERM;
  185. out:
  186. free_iob ( iobuf );
  187. return rc;
  188. }
  189. /**
  190. * Transmit SRP SCSI command
  191. *
  192. * @v srp SRP device
  193. */
  194. static void srp_cmd ( struct srp_device *srp ) {
  195. struct io_buffer *iobuf;
  196. struct srp_cmd *cmd;
  197. struct srp_memory_descriptor *data_out;
  198. struct srp_memory_descriptor *data_in;
  199. int rc;
  200. assert ( srp->state & SRP_STATE_LOGGED_IN );
  201. /* Allocate I/O buffer */
  202. iobuf = xfer_alloc_iob ( &srp->socket, SRP_MAX_I_T_IU_LEN );
  203. if ( ! iobuf ) {
  204. rc = -ENOMEM;
  205. goto err;
  206. }
  207. /* Construct base portion */
  208. cmd = iob_put ( iobuf, sizeof ( *cmd ) );
  209. memset ( cmd, 0, sizeof ( *cmd ) );
  210. cmd->type = SRP_CMD;
  211. cmd->tag.dwords[1] = htonl ( ++srp_tag );
  212. cmd->lun = srp->lun;
  213. memcpy ( &cmd->cdb, &srp->command->cdb, sizeof ( cmd->cdb ) );
  214. /* Construct data-out descriptor, if present */
  215. if ( srp->command->data_out ) {
  216. cmd->data_buffer_formats |= SRP_CMD_DO_FMT_DIRECT;
  217. data_out = iob_put ( iobuf, sizeof ( *data_out ) );
  218. data_out->address =
  219. cpu_to_be64 ( user_to_phys ( srp->command->data_out, 0 ) );
  220. data_out->handle = ntohl ( srp->memory_handle );
  221. data_out->len = ntohl ( srp->command->data_out_len );
  222. }
  223. /* Construct data-in descriptor, if present */
  224. if ( srp->command->data_in ) {
  225. cmd->data_buffer_formats |= SRP_CMD_DI_FMT_DIRECT;
  226. data_in = iob_put ( iobuf, sizeof ( *data_in ) );
  227. data_in->address =
  228. cpu_to_be64 ( user_to_phys ( srp->command->data_in, 0 ) );
  229. data_in->handle = ntohl ( srp->memory_handle );
  230. data_in->len = ntohl ( srp->command->data_in_len );
  231. }
  232. DBGC2 ( srp, "SRP %p TX SCSI command tag %08x%08x\n", srp,
  233. ntohl ( cmd->tag.dwords[0] ), ntohl ( cmd->tag.dwords[1] ) );
  234. DBGC2_HDA ( srp, 0, iobuf->data, iob_len ( iobuf ) );
  235. /* Send IU */
  236. if ( ( rc = xfer_deliver_iob ( &srp->socket, iobuf ) ) != 0 ) {
  237. DBGC ( srp, "SRP %p could not send command: %s\n",
  238. srp, strerror ( rc ) );
  239. goto err;
  240. }
  241. return;
  242. err:
  243. srp_fail ( srp, rc );
  244. }
  245. /**
  246. * Handle SRP SCSI response
  247. *
  248. * @v srp SRP device
  249. * @v iobuf I/O buffer
  250. * @ret rc Returns status code
  251. */
  252. static int srp_rsp ( struct srp_device *srp, struct io_buffer *iobuf ) {
  253. struct srp_rsp *rsp = iobuf->data;
  254. int rc;
  255. DBGC2 ( srp, "SRP %p RX SCSI response tag %08x%08x\n", srp,
  256. ntohl ( rsp->tag.dwords[0] ), ntohl ( rsp->tag.dwords[1] ) );
  257. /* Sanity check */
  258. if ( iob_len ( iobuf ) < sizeof ( *rsp ) ) {
  259. DBGC ( srp, "SRP %p RX SCSI response too short (%zd bytes)\n",
  260. srp, iob_len ( iobuf ) );
  261. rc = -EINVAL;
  262. goto out;
  263. }
  264. /* Report SCSI errors */
  265. if ( rsp->status != 0 ) {
  266. DBGC ( srp, "SRP %p response status %02x\n",
  267. srp, rsp->status );
  268. if ( srp_rsp_sense_data ( rsp ) ) {
  269. DBGC ( srp, "SRP %p sense data:\n", srp );
  270. DBGC_HDA ( srp, 0, srp_rsp_sense_data ( rsp ),
  271. srp_rsp_sense_data_len ( rsp ) );
  272. }
  273. }
  274. if ( rsp->valid & ( SRP_RSP_VALID_DOUNDER | SRP_RSP_VALID_DOOVER ) ) {
  275. DBGC ( srp, "SRP %p response data-out %srun by %#x bytes\n",
  276. srp, ( ( rsp->valid & SRP_RSP_VALID_DOUNDER )
  277. ? "under" : "over" ),
  278. ntohl ( rsp->data_out_residual_count ) );
  279. }
  280. if ( rsp->valid & ( SRP_RSP_VALID_DIUNDER | SRP_RSP_VALID_DIOVER ) ) {
  281. DBGC ( srp, "SRP %p response data-in %srun by %#x bytes\n",
  282. srp, ( ( rsp->valid & SRP_RSP_VALID_DIUNDER )
  283. ? "under" : "over" ),
  284. ntohl ( rsp->data_in_residual_count ) );
  285. }
  286. srp->command->status = rsp->status;
  287. /* Mark SCSI command as complete */
  288. srp_scsi_done ( srp, 0 );
  289. rc = 0;
  290. out:
  291. free_iob ( iobuf );
  292. return rc;
  293. }
  294. /**
  295. * Handle SRP unrecognised response
  296. *
  297. * @v srp SRP device
  298. * @v iobuf I/O buffer
  299. * @ret rc Returns status code
  300. */
  301. static int srp_unrecognised ( struct srp_device *srp,
  302. struct io_buffer *iobuf ) {
  303. struct srp_common *common = iobuf->data;
  304. DBGC ( srp, "SRP %p RX unrecognised IU tag %08x%08x type %02x\n",
  305. srp, ntohl ( common->tag.dwords[0] ),
  306. ntohl ( common->tag.dwords[1] ), common->type );
  307. free_iob ( iobuf );
  308. return -ENOTSUP;
  309. }
  310. /**
  311. * Receive data from underlying socket
  312. *
  313. * @v xfer Data transfer interface
  314. * @v iobuf Datagram I/O buffer
  315. * @v meta Data transfer metadata
  316. * @ret rc Return status code
  317. */
  318. static int srp_xfer_deliver_iob ( struct xfer_interface *xfer,
  319. struct io_buffer *iobuf,
  320. struct xfer_metadata *meta __unused ) {
  321. struct srp_device *srp =
  322. container_of ( xfer, struct srp_device, socket );
  323. struct srp_common *common = iobuf->data;
  324. int ( * type ) ( struct srp_device *srp, struct io_buffer *iobuf );
  325. int rc;
  326. /* Determine IU type */
  327. switch ( common->type ) {
  328. case SRP_LOGIN_RSP:
  329. type = srp_login_rsp;
  330. break;
  331. case SRP_LOGIN_REJ:
  332. type = srp_login_rej;
  333. break;
  334. case SRP_RSP:
  335. type = srp_rsp;
  336. break;
  337. default:
  338. type = srp_unrecognised;
  339. break;
  340. }
  341. /* Handle IU */
  342. if ( ( rc = type ( srp, iobuf ) ) != 0 )
  343. goto err;
  344. return 0;
  345. err:
  346. srp_fail ( srp, rc );
  347. return rc;
  348. }
  349. /**
  350. * Underlying socket closed
  351. *
  352. * @v xfer Data transfer interface
  353. * @v rc Reason for close
  354. */
  355. static void srp_xfer_close ( struct xfer_interface *xfer, int rc ) {
  356. struct srp_device *srp =
  357. container_of ( xfer, struct srp_device, socket );
  358. DBGC ( srp, "SRP %p socket closed: %s\n", srp, strerror ( rc ) );
  359. srp_fail ( srp, rc );
  360. }
  361. /** SRP data transfer interface operations */
  362. static struct xfer_interface_operations srp_xfer_operations = {
  363. .close = srp_xfer_close,
  364. .vredirect = ignore_xfer_vredirect,
  365. .window = unlimited_xfer_window,
  366. .alloc_iob = default_xfer_alloc_iob,
  367. .deliver_iob = srp_xfer_deliver_iob,
  368. .deliver_raw = xfer_deliver_as_iob,
  369. };
  370. /**
  371. * Issue SCSI command via SRP
  372. *
  373. * @v scsi SCSI device
  374. * @v command SCSI command
  375. * @ret rc Return status code
  376. */
  377. static int srp_command ( struct scsi_device *scsi,
  378. struct scsi_command *command ) {
  379. struct srp_device *srp =
  380. container_of ( scsi->backend, struct srp_device, refcnt );
  381. /* Store SCSI command */
  382. if ( srp->command ) {
  383. DBGC ( srp, "SRP %p cannot handle concurrent SCSI commands\n",
  384. srp );
  385. return -EBUSY;
  386. }
  387. srp->command = command;
  388. /* Log in or issue command as appropriate */
  389. if ( ! ( srp->state & SRP_STATE_SOCKET_OPEN ) ) {
  390. srp_login ( srp );
  391. } else if ( srp->state & SRP_STATE_LOGGED_IN ) {
  392. srp_cmd ( srp );
  393. } else {
  394. /* Still waiting for login; do nothing */
  395. }
  396. return 0;
  397. }
  398. /**
  399. * Attach SRP device
  400. *
  401. * @v scsi SCSI device
  402. * @v root_path Root path
  403. */
  404. int srp_attach ( struct scsi_device *scsi, const char *root_path ) {
  405. struct srp_transport_type *transport;
  406. struct srp_device *srp;
  407. int rc;
  408. /* Hard-code an IB SRP back-end for now */
  409. transport = &ib_srp_transport;
  410. /* Allocate and initialise structure */
  411. srp = zalloc ( sizeof ( *srp ) + transport->priv_len );
  412. if ( ! srp ) {
  413. rc = -ENOMEM;
  414. goto err_alloc;
  415. }
  416. xfer_init ( &srp->socket, &srp_xfer_operations, &srp->refcnt );
  417. srp->transport = transport;
  418. DBGC ( srp, "SRP %p using %s\n", srp, root_path );
  419. /* Parse root path */
  420. if ( ( rc = transport->parse_root_path ( srp, root_path ) ) != 0 ) {
  421. DBGC ( srp, "SRP %p could not parse root path: %s\n",
  422. srp, strerror ( rc ) );
  423. goto err_parse_root_path;
  424. }
  425. /* Attach parent interface, mortalise self, and return */
  426. scsi->backend = ref_get ( &srp->refcnt );
  427. scsi->command = srp_command;
  428. ref_put ( &srp->refcnt );
  429. return 0;
  430. err_parse_root_path:
  431. ref_put ( &srp->refcnt );
  432. err_alloc:
  433. return rc;
  434. }
  435. /**
  436. * Detach SRP device
  437. *
  438. * @v scsi SCSI device
  439. */
  440. void srp_detach ( struct scsi_device *scsi ) {
  441. struct srp_device *srp =
  442. container_of ( scsi->backend, struct srp_device, refcnt );
  443. /* Close socket */
  444. xfer_nullify ( &srp->socket );
  445. xfer_close ( &srp->socket, 0 );
  446. scsi->command = scsi_detached_command;
  447. ref_put ( scsi->backend );
  448. scsi->backend = NULL;
  449. }