On 07/16/2015 06:26 PM, Matthew R. Ochs wrote:
> +
> +/**
> + * ba_clone() - frees a block from the block allocator
> + * @ba_lun: Block allocator from which to allocate a block.
> + * @to_free: Block to free.
> + *
> + * Return: 0 on success, -1 on failure
> + */
> +static int ba_clone(struct ba_lun *ba_lun, u64 to_clone)
> +{
> + struct ba_lun_info *lun_info =
> + (struct ba_lun_info *)ba_lun->ba_lun_handle;
> +
> + if (validate_alloc(lun_info, to_clone)) {
> + pr_err("%s: AUN %llX is not allocated on lun_id %llX\n",
> + __func__, to_clone, ba_lun->lun_id);
Suggest using dev_err here instead to scope the error to the adapter.
> + return -1;
Might be nice to return a better error to the user in both of the error cases
in this code.
> + }
> +
> + pr_debug("%s: Received a request to clone AUN %llX on lun_id %llX\n",
> + __func__, to_clone, ba_lun->lun_id);
> +
> + if (lun_info->aun_clone_map[to_clone] == MAX_AUN_CLONE_CNT) {
> + pr_err("%s: AUN %llX on lun_id %llX hit max clones already\n",
> + __func__, to_clone, ba_lun->lun_id);
> + return -1;
> + }
> +
> + lun_info->aun_clone_map[to_clone]++;
> +
> + return 0;
> +}
> +
> +
> +/**
> + * init_ba() - initializes and allocates a block allocator
> + * @lun_info: LUN information structure that owns the block allocator.
> + *
> + * Return: 0 on success, -errno on failure
> + */
> +static int init_ba(struct llun_info *lli)
> +{
> + int rc = 0;
> + struct glun_info *gli = lli->parent;
> + struct blka *blka = &gli->blka;
> +
> + memset(blka, 0, sizeof(*blka));
> + mutex_init(&blka->mutex);
> +
> + /* LUN IDs are unique per port, save the index instead */
> + blka->ba_lun.lun_id = lli->lun_index;
> + blka->ba_lun.lsize = gli->max_lba + 1;
> + blka->ba_lun.lba_size = gli->blk_len;
> +
> + blka->ba_lun.au_size = MC_CHUNK_SIZE;
> + blka->nchunk = blka->ba_lun.lsize / MC_CHUNK_SIZE;
> +
> + rc = ba_init(&blka->ba_lun);
> + if (rc) {
> + pr_err("%s: cannot init block_alloc, rc=%d\n", __func__, rc);
> + goto init_ba_exit;
The goto here is unnecessary
> + }
> +
> +init_ba_exit:
> + pr_debug("%s: returning rc=%d lli=%p\n", __func__, rc, lli);
> + return rc;
> +}
> +
> +/**
> + * write_same16() - sends a SCSI WRITE_SAME16 (0) command to specified LUN
> + * @sdev: SCSI device associated with LUN.
> + * @lba: Logical block address to start write same.
> + * @nblks: Number of logical blocks to write same.
> + *
> + * Return: 0 on success, -1 on failure
> + */
> +static int write_same16(struct scsi_device *sdev,
> + u64 lba,
> + u32 nblks)
> +{
> + u8 scsi_cmd[MAX_COMMAND_SIZE];
> + u8 *cmd_buf = NULL;
> + u8 *sense_buf = NULL;
> + int rc = 0;
> + int result = 0;
> + int ws_limit = SISLITE_MAX_WS_BLOCKS;
> + u64 offset = lba;
> + int left = nblks;
> +
> + memset(scsi_cmd, 0, sizeof(scsi_cmd));
> + cmd_buf = kzalloc(CMD_BUFSIZE, GFP_KERNEL);
> + sense_buf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_NOIO);
> + if (!cmd_buf || !sense_buf) {
> + rc = -ENOMEM;
> + goto out;
> + }
> +
> + while (left > 0) {
> +
> + scsi_cmd[0] = WRITE_SAME_16;
> + put_unaligned_be64(offset, &scsi_cmd[2]);
> + put_unaligned_be32(ws_limit < left ? ws_limit : left,
> + &scsi_cmd[10]);
> +
> + left -= ws_limit;
> + offset += ws_limit;
> +
> + result = scsi_execute(sdev, scsi_cmd, DMA_TO_DEVICE, cmd_buf,
> + CMD_BUFSIZE, sense_buf,
> + (MC_DISCOVERY_TIMEOUT*HZ), 5, 0, NULL);
5 seconds seems a little on the short side for this command. Perhaps using
sdev->request_queue->rq_timeout would be better?
> +
> + if (result) {
> + pr_err("%s: command failed for offset %lld"
> + " result=0x%x\n", __func__, offset, result);
> + rc = -EIO;
> + goto out;
> + }
> + }
> +
> +out:
You need to free cmd_buf and sense_buf here.
> + pr_debug("%s: returning rc=%d\n", __func__, rc);
> + return rc;
> +}
> +
> +
> +/**
> + * _cxlflash_vlun_resize() - changes the size of a virtual lun
> + * @sdev: SCSI device associated with LUN owning virtual LUN.
> + * @ctxi: Context owning resources.
> + * @resize: Resize ioctl data structure.
> + *
> + * On successful return, the user is informed of the new size (in blocks)
> + * of the virtual lun in last LBA format. When the size of the virtual
> + * lun is zero, the last LBA is reflected as -1.
> + *
> + * Return: 0 on success, -errno on failure
> + */
> +int _cxlflash_vlun_resize(struct scsi_device *sdev,
> + struct ctx_info *ctxi,
> + struct dk_cxlflash_resize *resize)
> +{
> + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata;
> + struct llun_info *lli = sdev->hostdata;
> + struct glun_info *gli = lli->parent;
> + struct afu *afu = cfg->afu;
> + bool unlock_ctx = false;
> +
> + res_hndl_t rhndl = resize->rsrc_handle;
> + u64 new_size;
> + u64 nsectors;
> + u64 ctxid = DECODE_CTXID(resize->context_id),
> + rctxid = resize->context_id;
> +
> + struct sisl_rht_entry *rhte;
> +
> + int rc = 0;
> +
> + /* req_size is always assumed to be in 4k blocks. So we have to convert
> + * it from 4k to chunk size
> + */
> + nsectors = (resize->req_size * CXLFLASH_BLOCK_SIZE) / gli->blk_len;
> + new_size = (nsectors + MC_CHUNK_SIZE - 1) / MC_CHUNK_SIZE;
Use DIV_ROUND_UP instead.
> +
> + pr_debug("%s: ctxid=%llu rhndl=0x%llx, req_size=0x%llx,"
> + "new_size=%llx\n", __func__, ctxid, resize->rsrc_handle,
> + resize->req_size, new_size);
> +
> + if (unlikely(gli->mode != MODE_VIRTUAL)) {
> + pr_err("%s: LUN mode does not support resize! (%d)\n",
> + __func__, gli->mode);
> + rc = -EINVAL;
> + goto out;
> +
> + }
> +
> + if (!ctxi) {
> + ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK);
> + if (unlikely(!ctxi)) {
> + pr_err("%s: Bad context! (%llu)\n", __func__, ctxid);
> + rc = -EINVAL;
> + goto out;
> + }
> +
> + unlock_ctx = true;
> + }
> +
> + rhte = get_rhte(ctxi, rhndl, lli);
> + if (unlikely(!rhte)) {
> + pr_err("%s: Bad resource handle! (%u)\n", __func__, rhndl);
> + rc = -EINVAL;
> + goto out;
> + }
> +
> + if (new_size > rhte->lxt_cnt)
> + rc = grow_lxt(afu,
> + sdev,
> + ctxid,
> + rhndl,
> + rhte,
> + &new_size);
> + else if (new_size < rhte->lxt_cnt)
> + rc = shrink_lxt(afu,
> + sdev,
> + ctxid,
> + rhndl,
> + rhte,
> + &new_size);
> +
> + resize->hdr.return_flags = 0;
> + resize->last_lba = (new_size * MC_CHUNK_SIZE * gli->blk_len);
> + resize->last_lba /= CXLFLASH_BLOCK_SIZE;
> + resize->last_lba--;
> +
> +out:
> + if (unlock_ctx)
> + mutex_unlock(&ctxi->mutex);
> + pr_debug("%s: resized to %lld returning rc=%d\n",
> + __func__, resize->last_lba, rc);
> + return rc;
> +}
> +
> +int cxlflash_vlun_resize(struct scsi_device *sdev,
> + struct dk_cxlflash_resize *resize)
> +{
> + return _cxlflash_vlun_resize(sdev, NULL, resize);
> +}
> +
> +/**
> + * init_lun_table() - write an entry in the LUN table
> + * @cfg: Internal structure associated with the host.
> + * @lli: Per adapter LUN information structure.
> + *
> + * On successful return, a LUN table entry is created.
> + * At the top for LUNs visible on both ports.
> + * At the bottom for LUNs visible only on one port.
> + *
> + * Return: 0 on success, -errno on failure
> + */
> +static int init_lun_table(struct cxlflash_cfg *cfg, struct llun_info *lli)
> +{
> + u32 chan;
> + int rc = 0;
> + struct afu *afu = cfg->afu;
> +
> + if (lli->in_table)
> + goto out;
> +
> + if (lli->port_sel == BOTH_PORTS) {
> + /*
> + * If this LUN is visible from both ports, we will put
> + * it in the top half of the LUN table.
> + */
> + if ((cfg->promote_lun_index == cfg->last_lun_index[0]) ||
> + (cfg->promote_lun_index == cfg->last_lun_index[1])) {
> + rc = -ENOSPC;
> + goto out;
> + }
> +
> + lli->lun_index = cfg->promote_lun_index;
> + writeq_be(lli->lun_id[0],
> + &afu->afu_map->global.fc_port[0]
> + [cfg->promote_lun_index]);
Would improve readability IMHO if you either put the second parm all on one
line or used a local variable to make it better fit on one line, rather than
line breaking where you did.
> + writeq_be(lli->lun_id[1],
> + &afu->afu_map->global.fc_port[1]
> + [cfg->promote_lun_index]);
> + cfg->promote_lun_index++;
> + pr_debug("%s: Virtual LUN on slot %d id0=%llx, id1=%llx\n",
> + __func__, lli->lun_index, lli->lun_id[0],
> + lli->lun_id[1]);
Suggest changing the pr_debug calls to dev_dbg calls where possible to scope
the messages to an adapter.
> + } else {
> + /*
> + * If this LUN is visible only from one port, we will put
> + * it in the bottom half of the LUN table.
> + */
> + chan = PORT2CHAN(lli->port_sel);
> + if (cfg->promote_lun_index == cfg->last_lun_index[chan]) {
> + rc = -ENOSPC;
> + goto out;
> + }
> +
> + lli->lun_index = cfg->last_lun_index[chan];
> + writeq_be(lli->lun_id[chan],
> + &afu->afu_map->global.fc_port[chan]
> + [cfg->last_lun_index[chan]]);
> + cfg->last_lun_index[chan]--;
> + pr_debug("%s: Virtual LUN on slot %d chan=%d, id=%llx\n",
> + __func__, lli->lun_index, chan, lli->lun_id[chan]);
> + }
> +
> + lli->in_table = true;
> +out:
> + pr_debug("%s: returning rc=%d\n", __func__, rc);
> + return rc;
> +}
> +
--
Brian King
Power Linux I/O
IBM Linux Technology Center
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html