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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828
  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. /** Initiator port ID (for boot firmware table) */
  107. union srp_port_id initiator;
  108. /** Target port ID (for boot firmware table) */
  109. union srp_port_id target;
  110. /** SCSI LUN (for boot firmware table) */
  111. struct scsi_lun lun;
  112. /** List of active commands */
  113. struct list_head commands;
  114. };
  115. /** An SRP command */
  116. struct srp_command {
  117. /** Reference count */
  118. struct refcnt refcnt;
  119. /** SRP device */
  120. struct srp_device *srpdev;
  121. /** List of active commands */
  122. struct list_head list;
  123. /** SCSI command interface */
  124. struct interface scsi;
  125. /** Command tag */
  126. uint32_t tag;
  127. };
  128. /**
  129. * Get reference to SRP device
  130. *
  131. * @v srpdev SRP device
  132. * @ret srpdev SRP device
  133. */
  134. static inline __attribute__ (( always_inline )) struct srp_device *
  135. srpdev_get ( struct srp_device *srpdev ) {
  136. ref_get ( &srpdev->refcnt );
  137. return srpdev;
  138. }
  139. /**
  140. * Drop reference to SRP device
  141. *
  142. * @v srpdev SRP device
  143. */
  144. static inline __attribute__ (( always_inline )) void
  145. srpdev_put ( struct srp_device *srpdev ) {
  146. ref_put ( &srpdev->refcnt );
  147. }
  148. /**
  149. * Get reference to SRP command
  150. *
  151. * @v srpcmd SRP command
  152. * @ret srpcmd SRP command
  153. */
  154. static inline __attribute__ (( always_inline )) struct srp_command *
  155. srpcmd_get ( struct srp_command *srpcmd ) {
  156. ref_get ( &srpcmd->refcnt );
  157. return srpcmd;
  158. }
  159. /**
  160. * Drop reference to SRP command
  161. *
  162. * @v srpcmd SRP command
  163. */
  164. static inline __attribute__ (( always_inline )) void
  165. srpcmd_put ( struct srp_command *srpcmd ) {
  166. ref_put ( &srpcmd->refcnt );
  167. }
  168. /**
  169. * Free SRP command
  170. *
  171. * @v refcnt Reference count
  172. */
  173. static void srpcmd_free ( struct refcnt *refcnt ) {
  174. struct srp_command *srpcmd =
  175. container_of ( refcnt, struct srp_command, refcnt );
  176. assert ( list_empty ( &srpcmd->list ) );
  177. srpdev_put ( srpcmd->srpdev );
  178. free ( srpcmd );
  179. }
  180. /**
  181. * Close SRP command
  182. *
  183. * @v srpcmd SRP command
  184. * @v rc Reason for close
  185. */
  186. static void srpcmd_close ( struct srp_command *srpcmd, int rc ) {
  187. struct srp_device *srpdev = srpcmd->srpdev;
  188. if ( rc != 0 ) {
  189. DBGC ( srpdev, "SRP %p tag %08x closed: %s\n",
  190. srpdev, srpcmd->tag, strerror ( rc ) );
  191. }
  192. /* Remove from list of commands */
  193. if ( ! list_empty ( &srpcmd->list ) ) {
  194. list_del ( &srpcmd->list );
  195. INIT_LIST_HEAD ( &srpcmd->list );
  196. srpcmd_put ( srpcmd );
  197. }
  198. /* Shut down interfaces */
  199. intf_shutdown ( &srpcmd->scsi, rc );
  200. }
  201. /**
  202. * Close SRP device
  203. *
  204. * @v srpdev SRP device
  205. * @v rc Reason for close
  206. */
  207. static void srpdev_close ( struct srp_device *srpdev, int rc ) {
  208. struct srp_command *srpcmd;
  209. struct srp_command *tmp;
  210. if ( rc != 0 ) {
  211. DBGC ( srpdev, "SRP %p closed: %s\n",
  212. srpdev, strerror ( rc ) );
  213. }
  214. /* Shut down interfaces */
  215. intf_shutdown ( &srpdev->socket, rc );
  216. intf_shutdown ( &srpdev->scsi, rc );
  217. /* Shut down any active commands */
  218. list_for_each_entry_safe ( srpcmd, tmp, &srpdev->commands, list ) {
  219. srpcmd_get ( srpcmd );
  220. srpcmd_close ( srpcmd, rc );
  221. srpcmd_put ( srpcmd );
  222. }
  223. }
  224. /**
  225. * Identify SRP command by tag
  226. *
  227. * @v srpdev SRP device
  228. * @v tag Command tag
  229. * @ret srpcmd SRP command, or NULL
  230. */
  231. static struct srp_command * srp_find_tag ( struct srp_device *srpdev,
  232. uint32_t tag ) {
  233. struct srp_command *srpcmd;
  234. list_for_each_entry ( srpcmd, &srpdev->commands, list ) {
  235. if ( srpcmd->tag == tag )
  236. return srpcmd;
  237. }
  238. return NULL;
  239. }
  240. /**
  241. * Choose an SRP command tag
  242. *
  243. * @v srpdev SRP device
  244. * @ret tag New tag, or negative error
  245. */
  246. static int srp_new_tag ( struct srp_device *srpdev ) {
  247. static uint16_t tag_idx;
  248. unsigned int i;
  249. for ( i = 0 ; i < 65536 ; i++ ) {
  250. tag_idx++;
  251. if ( srp_find_tag ( srpdev, tag_idx ) == NULL )
  252. return tag_idx;
  253. }
  254. return -EADDRINUSE;
  255. }
  256. /**
  257. * Transmit SRP login request
  258. *
  259. * @v srpdev SRP device
  260. * @v initiator Initiator port ID
  261. * @v target Target port ID
  262. * @v tag Command tag
  263. * @ret rc Return status code
  264. */
  265. static int srp_login ( struct srp_device *srpdev, union srp_port_id *initiator,
  266. union srp_port_id *target, uint32_t tag ) {
  267. struct io_buffer *iobuf;
  268. struct srp_login_req *login_req;
  269. int rc;
  270. /* Allocate I/O buffer */
  271. iobuf = xfer_alloc_iob ( &srpdev->socket, sizeof ( *login_req ) );
  272. if ( ! iobuf )
  273. return -ENOMEM;
  274. /* Construct login request IU */
  275. login_req = iob_put ( iobuf, sizeof ( *login_req ) );
  276. memset ( login_req, 0, sizeof ( *login_req ) );
  277. login_req->type = SRP_LOGIN_REQ;
  278. login_req->tag.dwords[0] = htonl ( SRP_TAG_MAGIC );
  279. login_req->tag.dwords[1] = htonl ( tag );
  280. login_req->max_i_t_iu_len = htonl ( SRP_MAX_I_T_IU_LEN );
  281. login_req->required_buffer_formats = SRP_LOGIN_REQ_FMT_DDBD;
  282. memcpy ( &login_req->initiator, initiator,
  283. sizeof ( login_req->initiator ) );
  284. memcpy ( &login_req->target, target, sizeof ( login_req->target ) );
  285. DBGC ( srpdev, "SRP %p tag %08x LOGIN_REQ:\n", srpdev, tag );
  286. DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );
  287. /* Send login request IU */
  288. if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) {
  289. DBGC ( srpdev, "SRP %p tag %08x could not send LOGIN_REQ: "
  290. "%s\n", srpdev, tag, strerror ( rc ) );
  291. return rc;
  292. }
  293. return 0;
  294. }
  295. /**
  296. * Receive SRP login response
  297. *
  298. * @v srpdev SRP device
  299. * @v data SRP IU
  300. * @v len Length of SRP IU
  301. * @ret rc Return status code
  302. */
  303. static int srp_login_rsp ( struct srp_device *srpdev,
  304. const void *data, size_t len ) {
  305. const struct srp_login_rsp *login_rsp = data;
  306. /* Sanity check */
  307. if ( len < sizeof ( *login_rsp ) ) {
  308. DBGC ( srpdev, "SRP %p LOGIN_RSP too short (%zd bytes)\n",
  309. srpdev, len );
  310. return -EINVAL;
  311. }
  312. DBGC ( srpdev, "SRP %p tag %08x LOGIN_RSP:\n",
  313. srpdev, ntohl ( login_rsp->tag.dwords[1] ) );
  314. DBGC_HDA ( srpdev, 0, data, len );
  315. /* Mark as logged in */
  316. srpdev->logged_in = 1;
  317. DBGC ( srpdev, "SRP %p logged in\n", srpdev );
  318. /* Notify of window change */
  319. xfer_window_changed ( &srpdev->scsi );
  320. return 0;
  321. }
  322. /**
  323. * Receive SRP login rejection
  324. *
  325. * @v srpdev SRP device
  326. * @v data SRP IU
  327. * @v len Length of SRP IU
  328. * @ret rc Return status code
  329. */
  330. static int srp_login_rej ( struct srp_device *srpdev,
  331. const void *data, size_t len ) {
  332. const struct srp_login_rej *login_rej = data;
  333. uint32_t reason;
  334. /* Sanity check */
  335. if ( len < sizeof ( *login_rej ) ) {
  336. DBGC ( srpdev, "SRP %p LOGIN_REJ too short (%zd bytes)\n",
  337. srpdev, len );
  338. return -EINVAL;
  339. }
  340. reason = ntohl ( login_rej->reason );
  341. DBGC ( srpdev, "SRP %p tag %08x LOGIN_REJ reason %08x:\n",
  342. srpdev, ntohl ( login_rej->tag.dwords[1] ), reason );
  343. DBGC_HDA ( srpdev, 0, data, len );
  344. /* Login rejection always indicates an error */
  345. return ( SRP_LOGIN_REJ_REASON_DEFINED ( reason ) ?
  346. -EPERM_LOGIN_REJ ( reason ) : -EACCES );
  347. }
  348. /**
  349. * Transmit SRP SCSI command
  350. *
  351. * @v srpdev SRP device
  352. * @v command SCSI command
  353. * @v tag Command tag
  354. * @ret rc Return status code
  355. */
  356. static int srp_cmd ( struct srp_device *srpdev,
  357. struct scsi_cmd *command,
  358. uint32_t tag ) {
  359. struct io_buffer *iobuf;
  360. struct srp_cmd *cmd;
  361. struct srp_memory_descriptor *data_out;
  362. struct srp_memory_descriptor *data_in;
  363. int rc;
  364. /* Sanity check */
  365. if ( ! srpdev->logged_in ) {
  366. DBGC ( srpdev, "SRP %p tag %08x cannot send CMD before "
  367. "login completes\n", srpdev, tag );
  368. return -EBUSY;
  369. }
  370. /* Allocate I/O buffer */
  371. iobuf = xfer_alloc_iob ( &srpdev->socket, SRP_MAX_I_T_IU_LEN );
  372. if ( ! iobuf )
  373. return -ENOMEM;
  374. /* Construct base portion */
  375. cmd = iob_put ( iobuf, sizeof ( *cmd ) );
  376. memset ( cmd, 0, sizeof ( *cmd ) );
  377. cmd->type = SRP_CMD;
  378. cmd->tag.dwords[0] = htonl ( SRP_TAG_MAGIC );
  379. cmd->tag.dwords[1] = htonl ( tag );
  380. memcpy ( &cmd->lun, &command->lun, sizeof ( cmd->lun ) );
  381. memcpy ( &cmd->cdb, &command->cdb, sizeof ( cmd->cdb ) );
  382. /* Construct data-out descriptor, if present */
  383. if ( command->data_out ) {
  384. cmd->data_buffer_formats |= SRP_CMD_DO_FMT_DIRECT;
  385. data_out = iob_put ( iobuf, sizeof ( *data_out ) );
  386. data_out->address =
  387. cpu_to_be64 ( user_to_phys ( command->data_out, 0 ) );
  388. data_out->handle = ntohl ( srpdev->memory_handle );
  389. data_out->len = ntohl ( command->data_out_len );
  390. }
  391. /* Construct data-in descriptor, if present */
  392. if ( command->data_in ) {
  393. cmd->data_buffer_formats |= SRP_CMD_DI_FMT_DIRECT;
  394. data_in = iob_put ( iobuf, sizeof ( *data_in ) );
  395. data_in->address =
  396. cpu_to_be64 ( user_to_phys ( command->data_in, 0 ) );
  397. data_in->handle = ntohl ( srpdev->memory_handle );
  398. data_in->len = ntohl ( command->data_in_len );
  399. }
  400. DBGC2 ( srpdev, "SRP %p tag %08x CMD " SCSI_CDB_FORMAT "\n",
  401. srpdev, tag, SCSI_CDB_DATA ( cmd->cdb ) );
  402. /* Send IU */
  403. if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) {
  404. DBGC ( srpdev, "SRP %p tag %08x could not send CMD: %s\n",
  405. srpdev, tag, strerror ( rc ) );
  406. return rc;
  407. }
  408. return 0;
  409. }
  410. /**
  411. * Receive SRP SCSI response
  412. *
  413. * @v srpdev SRP device
  414. * @v data SRP IU
  415. * @v len Length of SRP IU
  416. * @ret rc Returns status code
  417. */
  418. static int srp_rsp ( struct srp_device *srpdev,
  419. const void *data, size_t len ) {
  420. const struct srp_rsp *rsp = data;
  421. struct srp_command *srpcmd;
  422. struct scsi_rsp response;
  423. const void *sense;
  424. ssize_t data_out_residual_count;
  425. ssize_t data_in_residual_count;
  426. /* Sanity check */
  427. if ( len < sizeof ( *rsp ) ) {
  428. DBGC ( srpdev, "SRP %p RSP too short (%zd bytes)\n",
  429. srpdev, len );
  430. return -EINVAL;
  431. }
  432. DBGC2 ( srpdev, "SRP %p tag %08x RSP stat %02x dores %08x dires "
  433. "%08x valid %02x%s%s%s%s%s%s\n",
  434. srpdev, ntohl ( rsp->tag.dwords[1] ), rsp->status,
  435. ntohl ( rsp->data_out_residual_count ),
  436. ntohl ( rsp->data_in_residual_count ), rsp->valid,
  437. ( ( rsp->valid & SRP_RSP_VALID_DIUNDER ) ? " diunder" : "" ),
  438. ( ( rsp->valid & SRP_RSP_VALID_DIOVER ) ? " diover" : "" ),
  439. ( ( rsp->valid & SRP_RSP_VALID_DOUNDER ) ? " dounder" : "" ),
  440. ( ( rsp->valid & SRP_RSP_VALID_DOOVER ) ? " doover" : "" ),
  441. ( ( rsp->valid & SRP_RSP_VALID_SNSVALID ) ? " sns" : "" ),
  442. ( ( rsp->valid & SRP_RSP_VALID_RSPVALID ) ? " rsp" : "" ) );
  443. /* Identify command by tag */
  444. srpcmd = srp_find_tag ( srpdev, ntohl ( rsp->tag.dwords[1] ) );
  445. if ( ! srpcmd ) {
  446. DBGC ( srpdev, "SRP %p tag %08x unrecognised RSP\n",
  447. srpdev, ntohl ( rsp->tag.dwords[1] ) );
  448. return -ENOENT;
  449. }
  450. /* Hold command reference for remainder of function */
  451. srpcmd_get ( srpcmd );
  452. /* Build SCSI response */
  453. memset ( &response, 0, sizeof ( response ) );
  454. response.status = rsp->status;
  455. data_out_residual_count = ntohl ( rsp->data_out_residual_count );
  456. data_in_residual_count = ntohl ( rsp->data_in_residual_count );
  457. if ( rsp->valid & SRP_RSP_VALID_DOOVER ) {
  458. response.overrun = data_out_residual_count;
  459. } else if ( rsp->valid & SRP_RSP_VALID_DOUNDER ) {
  460. response.overrun = -(data_out_residual_count);
  461. } else if ( rsp->valid & SRP_RSP_VALID_DIOVER ) {
  462. response.overrun = data_in_residual_count;
  463. } else if ( rsp->valid & SRP_RSP_VALID_DIUNDER ) {
  464. response.overrun = -(data_in_residual_count);
  465. }
  466. sense = srp_rsp_sense_data ( rsp );
  467. if ( sense )
  468. memcpy ( &response.sense, sense, sizeof ( response.sense ) );
  469. /* Report SCSI response */
  470. scsi_response ( &srpcmd->scsi, &response );
  471. /* Close SCSI command */
  472. srpcmd_close ( srpcmd, 0 );
  473. /* Drop temporary command reference */
  474. srpcmd_put ( srpcmd );
  475. return 0;
  476. }
  477. /**
  478. * Receive SRP unrecognised response IU
  479. *
  480. * @v srpdev SRP device
  481. * @v data SRP IU
  482. * @v len Length of SRP IU
  483. * @ret rc Returns status code
  484. */
  485. static int srp_unrecognised ( struct srp_device *srpdev,
  486. const void *data, size_t len ) {
  487. const struct srp_common *common = data;
  488. DBGC ( srpdev, "SRP %p tag %08x unrecognised IU type %02x:\n",
  489. srpdev, ntohl ( common->tag.dwords[1] ), common->type );
  490. DBGC_HDA ( srpdev, 0, data, len );
  491. return -ENOTSUP;
  492. }
  493. /** SRP command SCSI interface operations */
  494. static struct interface_operation srpcmd_scsi_op[] = {
  495. INTF_OP ( intf_close, struct srp_command *, srpcmd_close ),
  496. };
  497. /** SRP command SCSI interface descriptor */
  498. static struct interface_descriptor srpcmd_scsi_desc =
  499. INTF_DESC ( struct srp_command, scsi, srpcmd_scsi_op );
  500. /**
  501. * Issue SRP SCSI command
  502. *
  503. * @v srpdev SRP device
  504. * @v parent Parent interface
  505. * @v command SCSI command
  506. * @ret tag Command tag, or negative error
  507. */
  508. static int srpdev_scsi_command ( struct srp_device *srpdev,
  509. struct interface *parent,
  510. struct scsi_cmd *command ) {
  511. struct srp_command *srpcmd;
  512. int tag;
  513. int rc;
  514. /* Allocate command tag */
  515. tag = srp_new_tag ( srpdev );
  516. if ( tag < 0 ) {
  517. rc = tag;
  518. goto err_tag;
  519. }
  520. /* Allocate and initialise structure */
  521. srpcmd = zalloc ( sizeof ( *srpcmd ) );
  522. if ( ! srpcmd ) {
  523. rc = -ENOMEM;
  524. goto err_zalloc;
  525. }
  526. ref_init ( &srpcmd->refcnt, srpcmd_free );
  527. intf_init ( &srpcmd->scsi, &srpcmd_scsi_desc, &srpcmd->refcnt );
  528. srpcmd->srpdev = srpdev_get ( srpdev );
  529. list_add ( &srpcmd->list, &srpdev->commands );
  530. srpcmd->tag = tag;
  531. /* Send command IU */
  532. if ( ( rc = srp_cmd ( srpdev, command, srpcmd->tag ) ) != 0 )
  533. goto err_cmd;
  534. /* Attach to parent interface, leave reference with command
  535. * list, and return.
  536. */
  537. intf_plug_plug ( &srpcmd->scsi, parent );
  538. return srpcmd->tag;
  539. err_cmd:
  540. srpcmd_close ( srpcmd, rc );
  541. err_zalloc:
  542. err_tag:
  543. return rc;
  544. }
  545. /**
  546. * Receive data from SRP socket
  547. *
  548. * @v srpdev SRP device
  549. * @v iobuf Datagram I/O buffer
  550. * @v meta Data transfer metadata
  551. * @ret rc Return status code
  552. */
  553. static int srpdev_deliver ( struct srp_device *srpdev,
  554. struct io_buffer *iobuf,
  555. struct xfer_metadata *meta __unused ) {
  556. struct srp_common *common = iobuf->data;
  557. int ( * type ) ( struct srp_device *srp, const void *data, size_t len );
  558. int rc;
  559. /* Sanity check */
  560. if ( iob_len ( iobuf ) < sizeof ( *common ) ) {
  561. DBGC ( srpdev, "SRP %p IU too short (%zd bytes)\n",
  562. srpdev, iob_len ( iobuf ) );
  563. rc = -EINVAL;
  564. goto err;
  565. }
  566. /* Determine IU type */
  567. switch ( common->type ) {
  568. case SRP_LOGIN_RSP:
  569. type = srp_login_rsp;
  570. break;
  571. case SRP_LOGIN_REJ:
  572. type = srp_login_rej;
  573. break;
  574. case SRP_RSP:
  575. type = srp_rsp;
  576. break;
  577. default:
  578. type = srp_unrecognised;
  579. break;
  580. }
  581. /* Handle IU */
  582. if ( ( rc = type ( srpdev, iobuf->data, iob_len ( iobuf ) ) ) != 0 )
  583. goto err;
  584. free_iob ( iobuf );
  585. return 0;
  586. err:
  587. DBGC ( srpdev, "SRP %p closing due to received IU (%s):\n",
  588. srpdev, strerror ( rc ) );
  589. DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );
  590. free_iob ( iobuf );
  591. srpdev_close ( srpdev, rc );
  592. return rc;
  593. }
  594. /**
  595. * Check SRP device flow-control window
  596. *
  597. * @v srpdev SRP device
  598. * @ret len Length of window
  599. */
  600. static size_t srpdev_window ( struct srp_device *srpdev ) {
  601. return ( srpdev->logged_in ? ~( ( size_t ) 0 ) : 0 );
  602. }
  603. /**
  604. * A (transport-independent) sBFT created by iPXE
  605. */
  606. struct ipxe_sbft {
  607. /** The table header */
  608. struct sbft_table table;
  609. /** The SCSI subtable */
  610. struct sbft_scsi_subtable scsi;
  611. /** The SRP subtable */
  612. struct sbft_srp_subtable srp;
  613. } __attribute__ (( packed, aligned ( 16 ) ));
  614. /**
  615. * Describe SRP device in an ACPI table
  616. *
  617. * @v srpdev SRP device
  618. * @v acpi ACPI table
  619. * @v len Length of ACPI table
  620. * @ret rc Return status code
  621. */
  622. static int srpdev_describe ( struct srp_device *srpdev,
  623. struct acpi_description_header *acpi,
  624. size_t len ) {
  625. struct ipxe_sbft *sbft =
  626. container_of ( acpi, struct ipxe_sbft, table.acpi );
  627. int rc;
  628. /* Sanity check */
  629. if ( len < sizeof ( *sbft ) )
  630. return -ENOBUFS;
  631. /* Populate table */
  632. sbft->table.acpi.signature = cpu_to_le32 ( SBFT_SIG );
  633. sbft->table.acpi.length = cpu_to_le32 ( sizeof ( *sbft ) );
  634. sbft->table.acpi.revision = 1;
  635. sbft->table.scsi_offset =
  636. cpu_to_le16 ( offsetof ( typeof ( *sbft ), scsi ) );
  637. memcpy ( &sbft->scsi.lun, &srpdev->lun, sizeof ( sbft->scsi.lun ) );
  638. sbft->table.srp_offset =
  639. cpu_to_le16 ( offsetof ( typeof ( *sbft ), srp ) );
  640. memcpy ( &sbft->srp.initiator, &srpdev->initiator,
  641. sizeof ( sbft->srp.initiator ) );
  642. memcpy ( &sbft->srp.target, &srpdev->target,
  643. sizeof ( sbft->srp.target ) );
  644. /* Ask transport layer to describe transport-specific portions */
  645. if ( ( rc = acpi_describe ( &srpdev->socket, acpi, len ) ) != 0 ) {
  646. DBGC ( srpdev, "SRP %p cannot describe transport layer: %s\n",
  647. srpdev, strerror ( rc ) );
  648. return rc;
  649. }
  650. return 0;
  651. }
  652. /** SRP device socket interface operations */
  653. static struct interface_operation srpdev_socket_op[] = {
  654. INTF_OP ( xfer_deliver, struct srp_device *, srpdev_deliver ),
  655. INTF_OP ( intf_close, struct srp_device *, srpdev_close ),
  656. };
  657. /** SRP device socket interface descriptor */
  658. static struct interface_descriptor srpdev_socket_desc =
  659. INTF_DESC_PASSTHRU ( struct srp_device, socket, srpdev_socket_op,
  660. scsi );
  661. /** SRP device SCSI interface operations */
  662. static struct interface_operation srpdev_scsi_op[] = {
  663. INTF_OP ( scsi_command, struct srp_device *, srpdev_scsi_command ),
  664. INTF_OP ( xfer_window, struct srp_device *, srpdev_window ),
  665. INTF_OP ( intf_close, struct srp_device *, srpdev_close ),
  666. INTF_OP ( acpi_describe, struct srp_device *, srpdev_describe ),
  667. };
  668. /** SRP device SCSI interface descriptor */
  669. static struct interface_descriptor srpdev_scsi_desc =
  670. INTF_DESC_PASSTHRU ( struct srp_device, scsi, srpdev_scsi_op, socket );
  671. /**
  672. * Open SRP device
  673. *
  674. * @v block Block control interface
  675. * @v socket Socket interface
  676. * @v initiator Initiator port ID
  677. * @v target Target port ID
  678. * @v memory_handle RDMA memory handle
  679. * @v lun SCSI LUN
  680. * @ret rc Return status code
  681. */
  682. int srp_open ( struct interface *block, struct interface *socket,
  683. union srp_port_id *initiator, union srp_port_id *target,
  684. uint32_t memory_handle, struct scsi_lun *lun ) {
  685. struct srp_device *srpdev;
  686. int tag;
  687. int rc;
  688. /* Allocate and initialise structure */
  689. srpdev = zalloc ( sizeof ( *srpdev ) );
  690. if ( ! srpdev ) {
  691. rc = -ENOMEM;
  692. goto err_zalloc;
  693. }
  694. ref_init ( &srpdev->refcnt, NULL );
  695. intf_init ( &srpdev->scsi, &srpdev_scsi_desc, &srpdev->refcnt );
  696. intf_init ( &srpdev->socket, &srpdev_socket_desc, &srpdev->refcnt );
  697. INIT_LIST_HEAD ( &srpdev->commands );
  698. srpdev->memory_handle = memory_handle;
  699. DBGC ( srpdev, "SRP %p %08x%08x%08x%08x->%08x%08x%08x%08x\n", srpdev,
  700. ntohl ( initiator->dwords[0] ), ntohl ( initiator->dwords[1] ),
  701. ntohl ( initiator->dwords[2] ), ntohl ( initiator->dwords[3] ),
  702. ntohl ( target->dwords[0] ), ntohl ( target->dwords[1] ),
  703. ntohl ( target->dwords[2] ), ntohl ( target->dwords[3] ) );
  704. /* Preserve parameters required for boot firmware table */
  705. memcpy ( &srpdev->initiator, initiator, sizeof ( srpdev->initiator ) );
  706. memcpy ( &srpdev->target, target, sizeof ( srpdev->target ) );
  707. memcpy ( &srpdev->lun, lun, sizeof ( srpdev->lun ) );
  708. /* Attach to socket interface and initiate login */
  709. intf_plug_plug ( &srpdev->socket, socket );
  710. tag = srp_new_tag ( srpdev );
  711. assert ( tag >= 0 ); /* Cannot fail when no commands in progress */
  712. if ( ( rc = srp_login ( srpdev, initiator, target, tag ) ) != 0 )
  713. goto err_login;
  714. /* Attach SCSI device to parent interface */
  715. if ( ( rc = scsi_open ( block, &srpdev->scsi, lun ) ) != 0 ) {
  716. DBGC ( srpdev, "SRP %p could not create SCSI device: %s\n",
  717. srpdev, strerror ( rc ) );
  718. goto err_scsi_open;
  719. }
  720. /* Mortalise self and return */
  721. ref_put ( &srpdev->refcnt );
  722. return 0;
  723. err_scsi_open:
  724. err_login:
  725. srpdev_close ( srpdev, rc );
  726. ref_put ( &srpdev->refcnt );
  727. err_zalloc:
  728. return rc;
  729. }