diff options
author | Krishna Gudipati <kgudipat@brocade.com> | 2012-09-21 20:27:14 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-10-07 06:26:53 -0400 |
commit | e6826c96ced7ea8161b2bae52686c99f6fbf8643 (patch) | |
tree | 9e95a4e581f2a854b2cfb88d3a6fc26a867d953f /drivers/scsi/bfa/bfa_ioc.c | |
parent | 4a49b044487dd04e41019b0c8c2aeec3ab090029 (diff) |
[SCSI] bfa: Add support to read/update the FRU data.
- Add FRU sub-module to support FRU read/write/update.
- Add support to read/write from the temp FRU module.
[jejb: fix checkpatch issues]
Signed-off-by: Krishna Gudipati <kgudipat@brocade.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/bfa/bfa_ioc.c')
-rw-r--r-- | drivers/scsi/bfa/bfa_ioc.c | 445 |
1 files changed, 445 insertions, 0 deletions
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index dea6a5e86776..0116c1032e25 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c | |||
@@ -5956,3 +5956,448 @@ bfa_dconf_modexit(struct bfa_s *bfa) | |||
5956 | struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa); | 5956 | struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa); |
5957 | bfa_sm_send_event(dconf, BFA_DCONF_SM_EXIT); | 5957 | bfa_sm_send_event(dconf, BFA_DCONF_SM_EXIT); |
5958 | } | 5958 | } |
5959 | |||
5960 | /* | ||
5961 | * FRU specific functions | ||
5962 | */ | ||
5963 | |||
5964 | #define BFA_FRU_DMA_BUF_SZ 0x02000 /* 8k dma buffer */ | ||
5965 | #define BFA_FRU_CHINOOK_MAX_SIZE 0x10000 | ||
5966 | #define BFA_FRU_LIGHTNING_MAX_SIZE 0x200 | ||
5967 | |||
5968 | static void | ||
5969 | bfa_fru_notify(void *cbarg, enum bfa_ioc_event_e event) | ||
5970 | { | ||
5971 | struct bfa_fru_s *fru = cbarg; | ||
5972 | |||
5973 | bfa_trc(fru, event); | ||
5974 | |||
5975 | switch (event) { | ||
5976 | case BFA_IOC_E_DISABLED: | ||
5977 | case BFA_IOC_E_FAILED: | ||
5978 | if (fru->op_busy) { | ||
5979 | fru->status = BFA_STATUS_IOC_FAILURE; | ||
5980 | fru->cbfn(fru->cbarg, fru->status); | ||
5981 | fru->op_busy = 0; | ||
5982 | } | ||
5983 | break; | ||
5984 | |||
5985 | default: | ||
5986 | break; | ||
5987 | } | ||
5988 | } | ||
5989 | |||
5990 | /* | ||
5991 | * Send fru write request. | ||
5992 | * | ||
5993 | * @param[in] cbarg - callback argument | ||
5994 | */ | ||
5995 | static void | ||
5996 | bfa_fru_write_send(void *cbarg, enum bfi_fru_h2i_msgs msg_type) | ||
5997 | { | ||
5998 | struct bfa_fru_s *fru = cbarg; | ||
5999 | struct bfi_fru_write_req_s *msg = | ||
6000 | (struct bfi_fru_write_req_s *) fru->mb.msg; | ||
6001 | u32 len; | ||
6002 | |||
6003 | msg->offset = cpu_to_be32(fru->addr_off + fru->offset); | ||
6004 | len = (fru->residue < BFA_FRU_DMA_BUF_SZ) ? | ||
6005 | fru->residue : BFA_FRU_DMA_BUF_SZ; | ||
6006 | msg->length = cpu_to_be32(len); | ||
6007 | |||
6008 | /* | ||
6009 | * indicate if it's the last msg of the whole write operation | ||
6010 | */ | ||
6011 | msg->last = (len == fru->residue) ? 1 : 0; | ||
6012 | |||
6013 | bfi_h2i_set(msg->mh, BFI_MC_FRU, msg_type, bfa_ioc_portid(fru->ioc)); | ||
6014 | bfa_alen_set(&msg->alen, len, fru->dbuf_pa); | ||
6015 | |||
6016 | memcpy(fru->dbuf_kva, fru->ubuf + fru->offset, len); | ||
6017 | bfa_ioc_mbox_queue(fru->ioc, &fru->mb); | ||
6018 | |||
6019 | fru->residue -= len; | ||
6020 | fru->offset += len; | ||
6021 | } | ||
6022 | |||
6023 | /* | ||
6024 | * Send fru read request. | ||
6025 | * | ||
6026 | * @param[in] cbarg - callback argument | ||
6027 | */ | ||
6028 | static void | ||
6029 | bfa_fru_read_send(void *cbarg, enum bfi_fru_h2i_msgs msg_type) | ||
6030 | { | ||
6031 | struct bfa_fru_s *fru = cbarg; | ||
6032 | struct bfi_fru_read_req_s *msg = | ||
6033 | (struct bfi_fru_read_req_s *) fru->mb.msg; | ||
6034 | u32 len; | ||
6035 | |||
6036 | msg->offset = cpu_to_be32(fru->addr_off + fru->offset); | ||
6037 | len = (fru->residue < BFA_FRU_DMA_BUF_SZ) ? | ||
6038 | fru->residue : BFA_FRU_DMA_BUF_SZ; | ||
6039 | msg->length = cpu_to_be32(len); | ||
6040 | bfi_h2i_set(msg->mh, BFI_MC_FRU, msg_type, bfa_ioc_portid(fru->ioc)); | ||
6041 | bfa_alen_set(&msg->alen, len, fru->dbuf_pa); | ||
6042 | bfa_ioc_mbox_queue(fru->ioc, &fru->mb); | ||
6043 | } | ||
6044 | |||
6045 | /* | ||
6046 | * Flash memory info API. | ||
6047 | * | ||
6048 | * @param[in] mincfg - minimal cfg variable | ||
6049 | */ | ||
6050 | u32 | ||
6051 | bfa_fru_meminfo(bfa_boolean_t mincfg) | ||
6052 | { | ||
6053 | /* min driver doesn't need fru */ | ||
6054 | if (mincfg) | ||
6055 | return 0; | ||
6056 | |||
6057 | return BFA_ROUNDUP(BFA_FRU_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); | ||
6058 | } | ||
6059 | |||
6060 | /* | ||
6061 | * Flash attach API. | ||
6062 | * | ||
6063 | * @param[in] fru - fru structure | ||
6064 | * @param[in] ioc - ioc structure | ||
6065 | * @param[in] dev - device structure | ||
6066 | * @param[in] trcmod - trace module | ||
6067 | * @param[in] logmod - log module | ||
6068 | */ | ||
6069 | void | ||
6070 | bfa_fru_attach(struct bfa_fru_s *fru, struct bfa_ioc_s *ioc, void *dev, | ||
6071 | struct bfa_trc_mod_s *trcmod, bfa_boolean_t mincfg) | ||
6072 | { | ||
6073 | fru->ioc = ioc; | ||
6074 | fru->trcmod = trcmod; | ||
6075 | fru->cbfn = NULL; | ||
6076 | fru->cbarg = NULL; | ||
6077 | fru->op_busy = 0; | ||
6078 | |||
6079 | bfa_ioc_mbox_regisr(fru->ioc, BFI_MC_FRU, bfa_fru_intr, fru); | ||
6080 | bfa_q_qe_init(&fru->ioc_notify); | ||
6081 | bfa_ioc_notify_init(&fru->ioc_notify, bfa_fru_notify, fru); | ||
6082 | list_add_tail(&fru->ioc_notify.qe, &fru->ioc->notify_q); | ||
6083 | |||
6084 | /* min driver doesn't need fru */ | ||
6085 | if (mincfg) { | ||
6086 | fru->dbuf_kva = NULL; | ||
6087 | fru->dbuf_pa = 0; | ||
6088 | } | ||
6089 | } | ||
6090 | |||
6091 | /* | ||
6092 | * Claim memory for fru | ||
6093 | * | ||
6094 | * @param[in] fru - fru structure | ||
6095 | * @param[in] dm_kva - pointer to virtual memory address | ||
6096 | * @param[in] dm_pa - frusical memory address | ||
6097 | * @param[in] mincfg - minimal cfg variable | ||
6098 | */ | ||
6099 | void | ||
6100 | bfa_fru_memclaim(struct bfa_fru_s *fru, u8 *dm_kva, u64 dm_pa, | ||
6101 | bfa_boolean_t mincfg) | ||
6102 | { | ||
6103 | if (mincfg) | ||
6104 | return; | ||
6105 | |||
6106 | fru->dbuf_kva = dm_kva; | ||
6107 | fru->dbuf_pa = dm_pa; | ||
6108 | memset(fru->dbuf_kva, 0, BFA_FRU_DMA_BUF_SZ); | ||
6109 | dm_kva += BFA_ROUNDUP(BFA_FRU_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); | ||
6110 | dm_pa += BFA_ROUNDUP(BFA_FRU_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); | ||
6111 | } | ||
6112 | |||
6113 | /* | ||
6114 | * Update fru vpd image. | ||
6115 | * | ||
6116 | * @param[in] fru - fru structure | ||
6117 | * @param[in] buf - update data buffer | ||
6118 | * @param[in] len - data buffer length | ||
6119 | * @param[in] offset - offset relative to starting address | ||
6120 | * @param[in] cbfn - callback function | ||
6121 | * @param[in] cbarg - callback argument | ||
6122 | * | ||
6123 | * Return status. | ||
6124 | */ | ||
6125 | bfa_status_t | ||
6126 | bfa_fruvpd_update(struct bfa_fru_s *fru, void *buf, u32 len, u32 offset, | ||
6127 | bfa_cb_fru_t cbfn, void *cbarg) | ||
6128 | { | ||
6129 | bfa_trc(fru, BFI_FRUVPD_H2I_WRITE_REQ); | ||
6130 | bfa_trc(fru, len); | ||
6131 | bfa_trc(fru, offset); | ||
6132 | |||
6133 | if (fru->ioc->asic_gen != BFI_ASIC_GEN_CT2) | ||
6134 | return BFA_STATUS_FRU_NOT_PRESENT; | ||
6135 | |||
6136 | if (fru->ioc->attr->card_type != BFA_MFG_TYPE_CHINOOK) | ||
6137 | return BFA_STATUS_CMD_NOTSUPP; | ||
6138 | |||
6139 | if (!bfa_ioc_is_operational(fru->ioc)) | ||
6140 | return BFA_STATUS_IOC_NON_OP; | ||
6141 | |||
6142 | if (fru->op_busy) { | ||
6143 | bfa_trc(fru, fru->op_busy); | ||
6144 | return BFA_STATUS_DEVBUSY; | ||
6145 | } | ||
6146 | |||
6147 | fru->op_busy = 1; | ||
6148 | |||
6149 | fru->cbfn = cbfn; | ||
6150 | fru->cbarg = cbarg; | ||
6151 | fru->residue = len; | ||
6152 | fru->offset = 0; | ||
6153 | fru->addr_off = offset; | ||
6154 | fru->ubuf = buf; | ||
6155 | |||
6156 | bfa_fru_write_send(fru, BFI_FRUVPD_H2I_WRITE_REQ); | ||
6157 | |||
6158 | return BFA_STATUS_OK; | ||
6159 | } | ||
6160 | |||
6161 | /* | ||
6162 | * Read fru vpd image. | ||
6163 | * | ||
6164 | * @param[in] fru - fru structure | ||
6165 | * @param[in] buf - read data buffer | ||
6166 | * @param[in] len - data buffer length | ||
6167 | * @param[in] offset - offset relative to starting address | ||
6168 | * @param[in] cbfn - callback function | ||
6169 | * @param[in] cbarg - callback argument | ||
6170 | * | ||
6171 | * Return status. | ||
6172 | */ | ||
6173 | bfa_status_t | ||
6174 | bfa_fruvpd_read(struct bfa_fru_s *fru, void *buf, u32 len, u32 offset, | ||
6175 | bfa_cb_fru_t cbfn, void *cbarg) | ||
6176 | { | ||
6177 | bfa_trc(fru, BFI_FRUVPD_H2I_READ_REQ); | ||
6178 | bfa_trc(fru, len); | ||
6179 | bfa_trc(fru, offset); | ||
6180 | |||
6181 | if (fru->ioc->asic_gen != BFI_ASIC_GEN_CT2) | ||
6182 | return BFA_STATUS_FRU_NOT_PRESENT; | ||
6183 | |||
6184 | if (fru->ioc->attr->card_type != BFA_MFG_TYPE_CHINOOK) | ||
6185 | return BFA_STATUS_CMD_NOTSUPP; | ||
6186 | |||
6187 | if (!bfa_ioc_is_operational(fru->ioc)) | ||
6188 | return BFA_STATUS_IOC_NON_OP; | ||
6189 | |||
6190 | if (fru->op_busy) { | ||
6191 | bfa_trc(fru, fru->op_busy); | ||
6192 | return BFA_STATUS_DEVBUSY; | ||
6193 | } | ||
6194 | |||
6195 | fru->op_busy = 1; | ||
6196 | |||
6197 | fru->cbfn = cbfn; | ||
6198 | fru->cbarg = cbarg; | ||
6199 | fru->residue = len; | ||
6200 | fru->offset = 0; | ||
6201 | fru->addr_off = offset; | ||
6202 | fru->ubuf = buf; | ||
6203 | bfa_fru_read_send(fru, BFI_FRUVPD_H2I_READ_REQ); | ||
6204 | |||
6205 | return BFA_STATUS_OK; | ||
6206 | } | ||
6207 | |||
6208 | /* | ||
6209 | * Get maximum size fru vpd image. | ||
6210 | * | ||
6211 | * @param[in] fru - fru structure | ||
6212 | * @param[out] size - maximum size of fru vpd data | ||
6213 | * | ||
6214 | * Return status. | ||
6215 | */ | ||
6216 | bfa_status_t | ||
6217 | bfa_fruvpd_get_max_size(struct bfa_fru_s *fru, u32 *max_size) | ||
6218 | { | ||
6219 | if (fru->ioc->asic_gen != BFI_ASIC_GEN_CT2) | ||
6220 | return BFA_STATUS_FRU_NOT_PRESENT; | ||
6221 | |||
6222 | if (!bfa_ioc_is_operational(fru->ioc)) | ||
6223 | return BFA_STATUS_IOC_NON_OP; | ||
6224 | |||
6225 | if (fru->ioc->attr->card_type == BFA_MFG_TYPE_CHINOOK) | ||
6226 | *max_size = BFA_FRU_CHINOOK_MAX_SIZE; | ||
6227 | else | ||
6228 | return BFA_STATUS_CMD_NOTSUPP; | ||
6229 | return BFA_STATUS_OK; | ||
6230 | } | ||
6231 | /* | ||
6232 | * tfru write. | ||
6233 | * | ||
6234 | * @param[in] fru - fru structure | ||
6235 | * @param[in] buf - update data buffer | ||
6236 | * @param[in] len - data buffer length | ||
6237 | * @param[in] offset - offset relative to starting address | ||
6238 | * @param[in] cbfn - callback function | ||
6239 | * @param[in] cbarg - callback argument | ||
6240 | * | ||
6241 | * Return status. | ||
6242 | */ | ||
6243 | bfa_status_t | ||
6244 | bfa_tfru_write(struct bfa_fru_s *fru, void *buf, u32 len, u32 offset, | ||
6245 | bfa_cb_fru_t cbfn, void *cbarg) | ||
6246 | { | ||
6247 | bfa_trc(fru, BFI_TFRU_H2I_WRITE_REQ); | ||
6248 | bfa_trc(fru, len); | ||
6249 | bfa_trc(fru, offset); | ||
6250 | bfa_trc(fru, *((u8 *) buf)); | ||
6251 | |||
6252 | if (fru->ioc->asic_gen != BFI_ASIC_GEN_CT2) | ||
6253 | return BFA_STATUS_FRU_NOT_PRESENT; | ||
6254 | |||
6255 | if (!bfa_ioc_is_operational(fru->ioc)) | ||
6256 | return BFA_STATUS_IOC_NON_OP; | ||
6257 | |||
6258 | if (fru->op_busy) { | ||
6259 | bfa_trc(fru, fru->op_busy); | ||
6260 | return BFA_STATUS_DEVBUSY; | ||
6261 | } | ||
6262 | |||
6263 | fru->op_busy = 1; | ||
6264 | |||
6265 | fru->cbfn = cbfn; | ||
6266 | fru->cbarg = cbarg; | ||
6267 | fru->residue = len; | ||
6268 | fru->offset = 0; | ||
6269 | fru->addr_off = offset; | ||
6270 | fru->ubuf = buf; | ||
6271 | |||
6272 | bfa_fru_write_send(fru, BFI_TFRU_H2I_WRITE_REQ); | ||
6273 | |||
6274 | return BFA_STATUS_OK; | ||
6275 | } | ||
6276 | |||
6277 | /* | ||
6278 | * tfru read. | ||
6279 | * | ||
6280 | * @param[in] fru - fru structure | ||
6281 | * @param[in] buf - read data buffer | ||
6282 | * @param[in] len - data buffer length | ||
6283 | * @param[in] offset - offset relative to starting address | ||
6284 | * @param[in] cbfn - callback function | ||
6285 | * @param[in] cbarg - callback argument | ||
6286 | * | ||
6287 | * Return status. | ||
6288 | */ | ||
6289 | bfa_status_t | ||
6290 | bfa_tfru_read(struct bfa_fru_s *fru, void *buf, u32 len, u32 offset, | ||
6291 | bfa_cb_fru_t cbfn, void *cbarg) | ||
6292 | { | ||
6293 | bfa_trc(fru, BFI_TFRU_H2I_READ_REQ); | ||
6294 | bfa_trc(fru, len); | ||
6295 | bfa_trc(fru, offset); | ||
6296 | |||
6297 | if (fru->ioc->asic_gen != BFI_ASIC_GEN_CT2) | ||
6298 | return BFA_STATUS_FRU_NOT_PRESENT; | ||
6299 | |||
6300 | if (!bfa_ioc_is_operational(fru->ioc)) | ||
6301 | return BFA_STATUS_IOC_NON_OP; | ||
6302 | |||
6303 | if (fru->op_busy) { | ||
6304 | bfa_trc(fru, fru->op_busy); | ||
6305 | return BFA_STATUS_DEVBUSY; | ||
6306 | } | ||
6307 | |||
6308 | fru->op_busy = 1; | ||
6309 | |||
6310 | fru->cbfn = cbfn; | ||
6311 | fru->cbarg = cbarg; | ||
6312 | fru->residue = len; | ||
6313 | fru->offset = 0; | ||
6314 | fru->addr_off = offset; | ||
6315 | fru->ubuf = buf; | ||
6316 | bfa_fru_read_send(fru, BFI_TFRU_H2I_READ_REQ); | ||
6317 | |||
6318 | return BFA_STATUS_OK; | ||
6319 | } | ||
6320 | |||
6321 | /* | ||
6322 | * Process fru response messages upon receiving interrupts. | ||
6323 | * | ||
6324 | * @param[in] fruarg - fru structure | ||
6325 | * @param[in] msg - message structure | ||
6326 | */ | ||
6327 | void | ||
6328 | bfa_fru_intr(void *fruarg, struct bfi_mbmsg_s *msg) | ||
6329 | { | ||
6330 | struct bfa_fru_s *fru = fruarg; | ||
6331 | struct bfi_fru_rsp_s *rsp = (struct bfi_fru_rsp_s *)msg; | ||
6332 | u32 status; | ||
6333 | |||
6334 | bfa_trc(fru, msg->mh.msg_id); | ||
6335 | |||
6336 | if (!fru->op_busy) { | ||
6337 | /* | ||
6338 | * receiving response after ioc failure | ||
6339 | */ | ||
6340 | bfa_trc(fru, 0x9999); | ||
6341 | return; | ||
6342 | } | ||
6343 | |||
6344 | switch (msg->mh.msg_id) { | ||
6345 | case BFI_FRUVPD_I2H_WRITE_RSP: | ||
6346 | case BFI_TFRU_I2H_WRITE_RSP: | ||
6347 | status = be32_to_cpu(rsp->status); | ||
6348 | bfa_trc(fru, status); | ||
6349 | |||
6350 | if (status != BFA_STATUS_OK || fru->residue == 0) { | ||
6351 | fru->status = status; | ||
6352 | fru->op_busy = 0; | ||
6353 | if (fru->cbfn) | ||
6354 | fru->cbfn(fru->cbarg, fru->status); | ||
6355 | } else { | ||
6356 | bfa_trc(fru, fru->offset); | ||
6357 | if (msg->mh.msg_id == BFI_FRUVPD_I2H_WRITE_RSP) | ||
6358 | bfa_fru_write_send(fru, | ||
6359 | BFI_FRUVPD_H2I_WRITE_REQ); | ||
6360 | else | ||
6361 | bfa_fru_write_send(fru, | ||
6362 | BFI_TFRU_H2I_WRITE_REQ); | ||
6363 | } | ||
6364 | break; | ||
6365 | case BFI_FRUVPD_I2H_READ_RSP: | ||
6366 | case BFI_TFRU_I2H_READ_RSP: | ||
6367 | status = be32_to_cpu(rsp->status); | ||
6368 | bfa_trc(fru, status); | ||
6369 | |||
6370 | if (status != BFA_STATUS_OK) { | ||
6371 | fru->status = status; | ||
6372 | fru->op_busy = 0; | ||
6373 | if (fru->cbfn) | ||
6374 | fru->cbfn(fru->cbarg, fru->status); | ||
6375 | } else { | ||
6376 | u32 len = be32_to_cpu(rsp->length); | ||
6377 | |||
6378 | bfa_trc(fru, fru->offset); | ||
6379 | bfa_trc(fru, len); | ||
6380 | |||
6381 | memcpy(fru->ubuf + fru->offset, fru->dbuf_kva, len); | ||
6382 | fru->residue -= len; | ||
6383 | fru->offset += len; | ||
6384 | |||
6385 | if (fru->residue == 0) { | ||
6386 | fru->status = status; | ||
6387 | fru->op_busy = 0; | ||
6388 | if (fru->cbfn) | ||
6389 | fru->cbfn(fru->cbarg, fru->status); | ||
6390 | } else { | ||
6391 | if (msg->mh.msg_id == BFI_FRUVPD_I2H_READ_RSP) | ||
6392 | bfa_fru_read_send(fru, | ||
6393 | BFI_FRUVPD_H2I_READ_REQ); | ||
6394 | else | ||
6395 | bfa_fru_read_send(fru, | ||
6396 | BFI_TFRU_H2I_READ_REQ); | ||
6397 | } | ||
6398 | } | ||
6399 | break; | ||
6400 | default: | ||
6401 | WARN_ON(1); | ||
6402 | } | ||
6403 | } | ||