Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

srp.c 13KB

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