diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_bsg.c | 147 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_bsg.h | 2 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_fw.h | 5 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_glbl.h | 4 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_mbx.c | 52 |
5 files changed, 210 insertions, 0 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_bsg.c b/drivers/scsi/qla4xxx/ql4_bsg.c index de4db299bfcb..c47545356f7b 100644 --- a/drivers/scsi/qla4xxx/ql4_bsg.c +++ b/drivers/scsi/qla4xxx/ql4_bsg.c | |||
@@ -196,6 +196,147 @@ leave: | |||
196 | return rval; | 196 | return rval; |
197 | } | 197 | } |
198 | 198 | ||
199 | static int | ||
200 | qla4xxx_read_nvram(struct bsg_job *bsg_job) | ||
201 | { | ||
202 | struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); | ||
203 | struct scsi_qla_host *ha = to_qla_host(host); | ||
204 | struct iscsi_bsg_request *bsg_req = bsg_job->request; | ||
205 | struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; | ||
206 | uint32_t offset = 0; | ||
207 | uint32_t len = 0; | ||
208 | uint32_t total_len = 0; | ||
209 | dma_addr_t nvram_dma; | ||
210 | uint8_t *nvram = NULL; | ||
211 | int rval = -EINVAL; | ||
212 | |||
213 | bsg_reply->reply_payload_rcv_len = 0; | ||
214 | |||
215 | if (unlikely(pci_channel_offline(ha->pdev))) | ||
216 | goto leave; | ||
217 | |||
218 | /* Only 40xx adapters are supported */ | ||
219 | if (!(is_qla4010(ha) || is_qla4022(ha) || is_qla4032(ha))) | ||
220 | goto leave; | ||
221 | |||
222 | if (ql4xxx_reset_active(ha)) { | ||
223 | ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); | ||
224 | rval = -EBUSY; | ||
225 | goto leave; | ||
226 | } | ||
227 | |||
228 | offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; | ||
229 | len = bsg_job->reply_payload.payload_len; | ||
230 | total_len = offset + len; | ||
231 | |||
232 | /* total len should not be greater than max NVRAM size */ | ||
233 | if ((is_qla4010(ha) && total_len > QL4010_NVRAM_SIZE) || | ||
234 | ((is_qla4022(ha) || is_qla4032(ha)) && | ||
235 | total_len > QL40X2_NVRAM_SIZE)) { | ||
236 | ql4_printk(KERN_ERR, ha, "%s: offset+len greater than max" | ||
237 | " nvram size, offset=%d len=%d\n", | ||
238 | __func__, offset, len); | ||
239 | goto leave; | ||
240 | } | ||
241 | |||
242 | nvram = dma_alloc_coherent(&ha->pdev->dev, len, &nvram_dma, | ||
243 | GFP_KERNEL); | ||
244 | if (!nvram) { | ||
245 | ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for nvram " | ||
246 | "data\n", __func__); | ||
247 | rval = -ENOMEM; | ||
248 | goto leave; | ||
249 | } | ||
250 | |||
251 | rval = qla4xxx_get_nvram(ha, nvram_dma, offset, len); | ||
252 | if (rval) { | ||
253 | ql4_printk(KERN_ERR, ha, "%s: get nvram failed\n", __func__); | ||
254 | bsg_reply->result = DID_ERROR << 16; | ||
255 | rval = -EIO; | ||
256 | } else { | ||
257 | bsg_reply->reply_payload_rcv_len = | ||
258 | sg_copy_from_buffer(bsg_job->reply_payload.sg_list, | ||
259 | bsg_job->reply_payload.sg_cnt, | ||
260 | nvram, len); | ||
261 | bsg_reply->result = DID_OK << 16; | ||
262 | } | ||
263 | |||
264 | bsg_job_done(bsg_job, bsg_reply->result, | ||
265 | bsg_reply->reply_payload_rcv_len); | ||
266 | dma_free_coherent(&ha->pdev->dev, len, nvram, nvram_dma); | ||
267 | leave: | ||
268 | return rval; | ||
269 | } | ||
270 | |||
271 | static int | ||
272 | qla4xxx_update_nvram(struct bsg_job *bsg_job) | ||
273 | { | ||
274 | struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); | ||
275 | struct scsi_qla_host *ha = to_qla_host(host); | ||
276 | struct iscsi_bsg_request *bsg_req = bsg_job->request; | ||
277 | struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; | ||
278 | uint32_t offset = 0; | ||
279 | uint32_t len = 0; | ||
280 | uint32_t total_len = 0; | ||
281 | dma_addr_t nvram_dma; | ||
282 | uint8_t *nvram = NULL; | ||
283 | int rval = -EINVAL; | ||
284 | |||
285 | bsg_reply->reply_payload_rcv_len = 0; | ||
286 | |||
287 | if (unlikely(pci_channel_offline(ha->pdev))) | ||
288 | goto leave; | ||
289 | |||
290 | if (!(is_qla4010(ha) || is_qla4022(ha) || is_qla4032(ha))) | ||
291 | goto leave; | ||
292 | |||
293 | if (ql4xxx_reset_active(ha)) { | ||
294 | ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); | ||
295 | rval = -EBUSY; | ||
296 | goto leave; | ||
297 | } | ||
298 | |||
299 | offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; | ||
300 | len = bsg_job->request_payload.payload_len; | ||
301 | total_len = offset + len; | ||
302 | |||
303 | /* total len should not be greater than max NVRAM size */ | ||
304 | if ((is_qla4010(ha) && total_len > QL4010_NVRAM_SIZE) || | ||
305 | ((is_qla4022(ha) || is_qla4032(ha)) && | ||
306 | total_len > QL40X2_NVRAM_SIZE)) { | ||
307 | ql4_printk(KERN_ERR, ha, "%s: offset+len greater than max" | ||
308 | " nvram size, offset=%d len=%d\n", | ||
309 | __func__, offset, len); | ||
310 | goto leave; | ||
311 | } | ||
312 | |||
313 | nvram = dma_alloc_coherent(&ha->pdev->dev, len, &nvram_dma, | ||
314 | GFP_KERNEL); | ||
315 | if (!nvram) { | ||
316 | ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash " | ||
317 | "data\n", __func__); | ||
318 | rval = -ENOMEM; | ||
319 | goto leave; | ||
320 | } | ||
321 | |||
322 | sg_copy_to_buffer(bsg_job->request_payload.sg_list, | ||
323 | bsg_job->request_payload.sg_cnt, nvram, len); | ||
324 | |||
325 | rval = qla4xxx_set_nvram(ha, nvram_dma, offset, len); | ||
326 | if (rval) { | ||
327 | ql4_printk(KERN_ERR, ha, "%s: set nvram failed\n", __func__); | ||
328 | bsg_reply->result = DID_ERROR << 16; | ||
329 | rval = -EIO; | ||
330 | } else | ||
331 | bsg_reply->result = DID_OK << 16; | ||
332 | |||
333 | bsg_job_done(bsg_job, bsg_reply->result, | ||
334 | bsg_reply->reply_payload_rcv_len); | ||
335 | dma_free_coherent(&ha->pdev->dev, len, nvram, nvram_dma); | ||
336 | leave: | ||
337 | return rval; | ||
338 | } | ||
339 | |||
199 | /** | 340 | /** |
200 | * qla4xxx_process_vendor_specific - handle vendor specific bsg request | 341 | * qla4xxx_process_vendor_specific - handle vendor specific bsg request |
201 | * @job: iscsi_bsg_job to handle | 342 | * @job: iscsi_bsg_job to handle |
@@ -217,6 +358,12 @@ int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job) | |||
217 | case QLISCSI_VND_GET_ACB_STATE: | 358 | case QLISCSI_VND_GET_ACB_STATE: |
218 | return qla4xxx_get_acb_state(bsg_job); | 359 | return qla4xxx_get_acb_state(bsg_job); |
219 | 360 | ||
361 | case QLISCSI_VND_READ_NVRAM: | ||
362 | return qla4xxx_read_nvram(bsg_job); | ||
363 | |||
364 | case QLISCSI_VND_UPDATE_NVRAM: | ||
365 | return qla4xxx_update_nvram(bsg_job); | ||
366 | |||
220 | default: | 367 | default: |
221 | ql4_printk(KERN_ERR, ha, "%s: invalid BSG vendor command: " | 368 | ql4_printk(KERN_ERR, ha, "%s: invalid BSG vendor command: " |
222 | "0x%x\n", __func__, bsg_req->msgcode); | 369 | "0x%x\n", __func__, bsg_req->msgcode); |
diff --git a/drivers/scsi/qla4xxx/ql4_bsg.h b/drivers/scsi/qla4xxx/ql4_bsg.h index 0400e1a0b670..71df80d612da 100644 --- a/drivers/scsi/qla4xxx/ql4_bsg.h +++ b/drivers/scsi/qla4xxx/ql4_bsg.h | |||
@@ -11,5 +11,7 @@ | |||
11 | #define QLISCSI_VND_READ_FLASH 1 | 11 | #define QLISCSI_VND_READ_FLASH 1 |
12 | #define QLISCSI_VND_UPDATE_FLASH 2 | 12 | #define QLISCSI_VND_UPDATE_FLASH 2 |
13 | #define QLISCSI_VND_GET_ACB_STATE 3 | 13 | #define QLISCSI_VND_GET_ACB_STATE 3 |
14 | #define QLISCSI_VND_READ_NVRAM 4 | ||
15 | #define QLISCSI_VND_UPDATE_NVRAM 5 | ||
14 | 16 | ||
15 | #endif | 17 | #endif |
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h index 9dc439b0d75f..581ff7e4621c 100644 --- a/drivers/scsi/qla4xxx/ql4_fw.h +++ b/drivers/scsi/qla4xxx/ql4_fw.h | |||
@@ -201,6 +201,9 @@ static inline uint32_t clr_rmask(uint32_t val) | |||
201 | /* ISP 4022 nvram definitions */ | 201 | /* ISP 4022 nvram definitions */ |
202 | #define NVR_WRITE_ENABLE 0x00000010 /* 4022 */ | 202 | #define NVR_WRITE_ENABLE 0x00000010 /* 4022 */ |
203 | 203 | ||
204 | #define QL4010_NVRAM_SIZE 0x200 | ||
205 | #define QL40X2_NVRAM_SIZE 0x800 | ||
206 | |||
204 | /* ISP port_status definitions */ | 207 | /* ISP port_status definitions */ |
205 | 208 | ||
206 | /* ISP Semaphore definitions */ | 209 | /* ISP Semaphore definitions */ |
@@ -359,6 +362,8 @@ struct qla_flt_region { | |||
359 | #define MBOX_CMD_GET_FW_STATE 0x0069 | 362 | #define MBOX_CMD_GET_FW_STATE 0x0069 |
360 | #define MBOX_CMD_GET_INIT_FW_CTRL_BLOCK_DEFAULTS 0x006A | 363 | #define MBOX_CMD_GET_INIT_FW_CTRL_BLOCK_DEFAULTS 0x006A |
361 | #define MBOX_CMD_GET_SYS_INFO 0x0078 | 364 | #define MBOX_CMD_GET_SYS_INFO 0x0078 |
365 | #define MBOX_CMD_GET_NVRAM 0x0078 /* For 40xx */ | ||
366 | #define MBOX_CMD_SET_NVRAM 0x0079 /* For 40xx */ | ||
362 | #define MBOX_CMD_RESTORE_FACTORY_DEFAULTS 0x0087 | 367 | #define MBOX_CMD_RESTORE_FACTORY_DEFAULTS 0x0087 |
363 | #define MBOX_CMD_SET_ACB 0x0088 | 368 | #define MBOX_CMD_SET_ACB 0x0088 |
364 | #define MBOX_CMD_GET_ACB 0x0089 | 369 | #define MBOX_CMD_GET_ACB 0x0089 |
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index 5c8769651666..35bd0c1ede38 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h | |||
@@ -162,6 +162,10 @@ int qla4xxx_bootdb_by_index(struct scsi_qla_host *ha, | |||
162 | dma_addr_t fw_ddb_entry_dma, uint16_t ddb_index); | 162 | dma_addr_t fw_ddb_entry_dma, uint16_t ddb_index); |
163 | int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, | 163 | int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, |
164 | char *password, uint16_t idx); | 164 | char *password, uint16_t idx); |
165 | int qla4xxx_get_nvram(struct scsi_qla_host *ha, dma_addr_t nvram_dma, | ||
166 | uint32_t offset, uint32_t size); | ||
167 | int qla4xxx_set_nvram(struct scsi_qla_host *ha, dma_addr_t nvram_dma, | ||
168 | uint32_t offset, uint32_t size); | ||
165 | 169 | ||
166 | /* BSG Functions */ | 170 | /* BSG Functions */ |
167 | int qla4xxx_bsg_request(struct bsg_job *bsg_job); | 171 | int qla4xxx_bsg_request(struct bsg_job *bsg_job); |
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index aec72309f60f..011c822f5ff6 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c | |||
@@ -1690,3 +1690,55 @@ int qla4xxx_get_ip_state(struct scsi_qla_host *ha, uint32_t acb_idx, | |||
1690 | memcpy(sts, mbox_sts, sizeof(mbox_sts)); | 1690 | memcpy(sts, mbox_sts, sizeof(mbox_sts)); |
1691 | return status; | 1691 | return status; |
1692 | } | 1692 | } |
1693 | |||
1694 | int qla4xxx_get_nvram(struct scsi_qla_host *ha, dma_addr_t nvram_dma, | ||
1695 | uint32_t offset, uint32_t size) | ||
1696 | { | ||
1697 | int status = QLA_SUCCESS; | ||
1698 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
1699 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
1700 | |||
1701 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
1702 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
1703 | |||
1704 | mbox_cmd[0] = MBOX_CMD_GET_NVRAM; | ||
1705 | mbox_cmd[1] = LSDW(nvram_dma); | ||
1706 | mbox_cmd[2] = MSDW(nvram_dma); | ||
1707 | mbox_cmd[3] = offset; | ||
1708 | mbox_cmd[4] = size; | ||
1709 | |||
1710 | status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], | ||
1711 | &mbox_sts[0]); | ||
1712 | if (status != QLA_SUCCESS) { | ||
1713 | DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed " | ||
1714 | "status %04X\n", ha->host_no, __func__, | ||
1715 | mbox_sts[0])); | ||
1716 | } | ||
1717 | return status; | ||
1718 | } | ||
1719 | |||
1720 | int qla4xxx_set_nvram(struct scsi_qla_host *ha, dma_addr_t nvram_dma, | ||
1721 | uint32_t offset, uint32_t size) | ||
1722 | { | ||
1723 | int status = QLA_SUCCESS; | ||
1724 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
1725 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
1726 | |||
1727 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
1728 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
1729 | |||
1730 | mbox_cmd[0] = MBOX_CMD_SET_NVRAM; | ||
1731 | mbox_cmd[1] = LSDW(nvram_dma); | ||
1732 | mbox_cmd[2] = MSDW(nvram_dma); | ||
1733 | mbox_cmd[3] = offset; | ||
1734 | mbox_cmd[4] = size; | ||
1735 | |||
1736 | status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], | ||
1737 | &mbox_sts[0]); | ||
1738 | if (status != QLA_SUCCESS) { | ||
1739 | DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed " | ||
1740 | "status %04X\n", ha->host_no, __func__, | ||
1741 | mbox_sts[0])); | ||
1742 | } | ||
1743 | return status; | ||
1744 | } | ||