aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/bfa/bfa_ioc.c
diff options
context:
space:
mode:
authorKrishna Gudipati <kgudipat@brocade.com>2012-09-21 20:27:14 -0400
committerJames Bottomley <JBottomley@Parallels.com>2012-10-07 06:26:53 -0400
commite6826c96ced7ea8161b2bae52686c99f6fbf8643 (patch)
tree9e95a4e581f2a854b2cfb88d3a6fc26a867d953f /drivers/scsi/bfa/bfa_ioc.c
parent4a49b044487dd04e41019b0c8c2aeec3ab090029 (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.c445
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
5968static void
5969bfa_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 */
5995static void
5996bfa_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 */
6028static void
6029bfa_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 */
6050u32
6051bfa_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 */
6069void
6070bfa_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 */
6099void
6100bfa_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 */
6125bfa_status_t
6126bfa_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 */
6173bfa_status_t
6174bfa_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 */
6216bfa_status_t
6217bfa_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 */
6243bfa_status_t
6244bfa_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 */
6289bfa_status_t
6290bfa_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 */
6327void
6328bfa_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}