<commit_before>/*	$OpenBSD: sdmmc_scsi.c,v 1.28 2011/07/09 00:39:29 matthew Exp $	*/

/*
 * Copyright (c) 2006 <NAME> <<EMAIL>>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/* A SCSI adapter emulation to access SD/MMC memory cards */

#include <sys/param.h>
#include <sys/buf.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/systm.h>

#include <scsi/scsi_all.h>
#include <scsi/scsi_disk.h>
#include <scsi/scsiconf.h>

#include <dev/sdmmc/sdmmc_scsi.h>
#include <dev/sdmmc/sdmmcvar.h>

#define SDMMC_SCSIID_HOST	0x00
#define SDMMC_SCSIID_MAX	0x0f

#define SDMMC_SCSI_MAXCMDS	8

struct sdmmc_scsi_target {
	struct sdmmc_function *card;
};

struct sdmmc_ccb {
	struct sdmmc_scsi_softc *ccb_scbus;
	struct scsi_xfer *ccb_xs;
	int ccb_flags;
#define SDMMC_CCB_F_ERR		0x0001
	u_int32_t ccb_blockno;
	u_int32_t ccb_blockcnt;
	volatile enum {
		SDMMC_CCB_FREE,
		SDMMC_CCB_READY,
		SDMMC_CCB_QUEUED
	} ccb_state;
	struct sdmmc_command ccb_cmd;
	struct sdmmc_task ccb_task;
	TAILQ_ENTRY(sdmmc_ccb) ccb_link;
};

TAILQ_HEAD(sdmmc_ccb_list, sdmmc_ccb);

struct sdmmc_scsi_softc {
	struct scsi_adapter sc_adapter;
	struct scsi_link sc_link;
	struct device *sc_child;
	struct sdmmc_scsi_target *sc_tgt;
	int sc_ntargets;
	struct sdmmc_ccb *sc_ccbs;		/* allocated ccbs */
	struct sdmmc_ccb_list sc_ccb_freeq;	/* free ccbs */
	struct sdmmc_ccb_list sc_ccb_runq;	/* queued ccbs */
	struct mutex sc_ccb_mtx;
	struct scsi_iopool sc_iopool;
};

int	sdmmc_alloc_ccbs(struct sdmmc_scsi_softc *, int);
void	sdmmc_free_ccbs(struct sdmmc_scsi_softc *);
void	*sdmmc_ccb_alloc(void *);
void	sdmmc_ccb_free(void *, void *);

void	sdmmc_scsi_cmd(struct scsi_xfer *);
void	sdmmc_inquiry(struct scsi_xfer *);
void	sdmmc_start_xs(struct sdmmc_softc *, struct sdmmc_ccb *);
void	sdmmc_complete_xs(void *);
void	sdmmc_done_xs(struct sdmmc_ccb *);
void	sdmmc_stimeout(void *);
void	sdmmc_scsi_minphys(struct buf *, struct scsi_link *);

#ifdef SDMMC_DEBUG
#define DPRINTF(s)	printf s
#else
#define DPRINTF(s)	/**/
#endif

void
sdmmc_scsi_attach(struct sdmmc_softc *sc)
{
	struct sdmmc_attach_args saa;
	struct sdmmc_scsi_softc *scbus;
	struct sdmmc_function *sf;

	rw_assert_wrlock(&sc->sc_lock);

	scbus = malloc(sizeof *scbus, M_DEVBUF, M_WAITOK | M_ZERO);

	scbus->sc_tgt = malloc(sizeof(*scbus->sc_tgt) *
	    (SDMMC_SCSIID_MAX+1), M_DEVBUF, M_WAITOK | M_ZERO);

	/*
	 * Each card that sent us a CID in the identification stage
	 * gets a SCSI ID > 0, whether it is a memory card or not.
	 */
	scbus->sc_ntargets = 1;
	SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list) {
		if (scbus->sc_ntargets >= SDMMC_SCSIID_MAX+1)
			break;
		scbus->sc_tgt[scbus->sc_ntargets].card = sf;
		scbus->sc_ntargets++;
	}

	/* Preallocate some CCBs and initialize the CCB lists. */
	if (sdmmc_alloc_ccbs(scbus, SDMMC_SCSI_MAXCMDS) != 0) {
		printf("%s: can't allocate ccbs\n", sc->sc_dev.dv_xname);
		goto free_sctgt;
	}

	sc->sc_scsibus = scbus;

	scbus->sc_adapter.scsi_cmd = sdmmc_scsi_cmd;
	scbus->sc_adapter.scsi_minphys = sdmmc_scsi_minphys;

	scbus->sc_link.adapter_target = SDMMC_SCSIID_HOST;
	scbus->sc_link.adapter_buswidth = scbus->sc_ntargets;
	scbus->sc_link.adapter_softc = sc;
	scbus->sc_link.luns = 1;
	scbus->sc_link.openings = 1;
	scbus->sc_link.adapter = &scbus->sc_adapter;
	scbus->sc_link.pool = &scbus->sc_iopool;

	bzero(&saa, sizeof(saa));
	saa.saa.saa_sc_link = &scbus->sc_link;

	scbus->sc_child = config_found(&sc->sc_dev, &saa.saa, scsiprint);
	if (scbus->sc_child == NULL) {
		printf("%s: can't attach scsibus\n", sc->sc_dev.dv_xname);
		goto free_ccbs;
	}
	return;

 free_ccbs:
	sc->sc_scsibus = NULL;
	sdmmc_free_ccbs(scbus);
 free_sctgt:
	free(scbus->sc_tgt, M_DEVBUF);
	free(scbus, M_DEVBUF);
}

void
sdmmc_scsi_detach(struct sdmmc_softc *sc)
{
	struct sdmmc_scsi_softc *scbus;
	struct sdmmc_ccb *ccb;<commit_msg>Simplify sdmmc_scsi by using SCSI_NO_ADAPTER_TARGET.<commit_after>/*	$OpenBSD: sdmmc_scsi.c,v 1.29 2011/07/09 02:11:29 matthew Exp $	*/

/*
 * Copyright (c) 2006 <NAME> <<EMAIL>>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/* A SCSI adapter emulation to access SD/MMC memory cards */

#include <sys/param.h>
#include <sys/buf.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/systm.h>

#include <scsi/scsi_all.h>
#include <scsi/scsi_disk.h>
#include <scsi/scsiconf.h>

#include <dev/sdmmc/sdmmc_scsi.h>
#include <dev/sdmmc/sdmmcvar.h>

#define SDMMC_SCSIID_MAX	0x10

#define SDMMC_SCSI_MAXCMDS	8

struct sdmmc_scsi_target {
	struct sdmmc_function *card;
};

struct sdmmc_ccb {
	struct sdmmc_scsi_softc *ccb_scbus;
	struct scsi_xfer *ccb_xs;
	int ccb_flags;
#define SDMMC_CCB_F_ERR		0x0001
	u_int32_t ccb_blockno;
	u_int32_t ccb_blockcnt;
	volatile enum {
		SDMMC_CCB_FREE,
		SDMMC_CCB_READY,
		SDMMC_CCB_QUEUED
	} ccb_state;
	struct sdmmc_command ccb_cmd;
	struct sdmmc_task ccb_task;
	TAILQ_ENTRY(sdmmc_ccb) ccb_link;
};

TAILQ_HEAD(sdmmc_ccb_list, sdmmc_ccb);

struct sdmmc_scsi_softc {
	struct scsi_adapter sc_adapter;
	struct scsi_link sc_link;
	struct device *sc_child;
	struct sdmmc_scsi_target *sc_tgt;
	int sc_ntargets;
	struct sdmmc_ccb *sc_ccbs;		/* allocated ccbs */
	struct sdmmc_ccb_list sc_ccb_freeq;	/* free ccbs */
	struct sdmmc_ccb_list sc_ccb_runq;	/* queued ccbs */
	struct mutex sc_ccb_mtx;
	struct scsi_iopool sc_iopool;
};

int	sdmmc_alloc_ccbs(struct sdmmc_scsi_softc *, int);
void	sdmmc_free_ccbs(struct sdmmc_scsi_softc *);
void	*sdmmc_ccb_alloc(void *);
void	sdmmc_ccb_free(void *, void *);

void	sdmmc_scsi_cmd(struct scsi_xfer *);
void	sdmmc_inquiry(struct scsi_xfer *);
void	sdmmc_start_xs(struct sdmmc_softc *, struct sdmmc_ccb *);
void	sdmmc_complete_xs(void *);
void	sdmmc_done_xs(struct sdmmc_ccb *);
void	sdmmc_stimeout(void *);
void	sdmmc_scsi_minphys(struct buf *, struct scsi_link *);

#ifdef SDMMC_DEBUG
#define DPRINTF(s)	printf s
#else
#define DPRINTF(s)	/**/
#endif

void
sdmmc_scsi_attach(struct sdmmc_softc *sc)
{
	struct sdmmc_attach_args saa;
	struct sdmmc_scsi_softc *scbus;
	struct sdmmc_function *sf;

	rw_assert_wrlock(&sc->sc_lock);

	scbus = malloc(sizeof *scbus, M_DEVBUF, M_WAITOK | M_ZERO);

	scbus->sc_tgt = malloc(sizeof(*scbus->sc_tgt) *
	    SDMMC_SCSIID_MAX, M_DEVBUF, M_WAITOK | M_ZERO);

	/*
	 * Each card that sent us a CID in the identification stage
	 * gets a SCSI ID, whether it is a memory card or not.
	 */
	scbus->sc_ntargets = 0;
	SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list) {
		if (scbus->sc_ntargets >= SDMMC_SCSIID_MAX)
			break;
		scbus->sc_tgt[scbus->sc_ntargets].card = sf;
		scbus->sc_ntargets++;
	}

	/* Preallocate some CCBs and initialize the CCB lists. */
	if (sdmmc_alloc_ccbs(scbus, SDMMC_SCSI_MAXCMDS) != 0) {
		printf("%s: can't allocate ccbs\n", sc->sc_dev.dv_xname);
		goto free_sctgt;
	}

	sc->sc_scsibus = scbus;

	scbus->sc_adapter.scsi_cmd = sdmmc_scsi_cmd;
	scbus->sc_adapter.scsi_minphys = sdmmc_scsi_minphys;

	scbus->sc_link.adapter_target = SCSI_NO_ADAPTER_TARGET;
	scbus->sc_link.adapter_softc = sc;
	scbus->sc_link.openings = 1;
	scbus->sc_link.adapter = &scbus->sc_adapter;
	scbus->sc_link.pool = &scbus->sc_iopool;

	bzero(&saa, sizeof(saa));
	saa.saa.saa_sc_link = &scbus->sc_link;
	saa.saa.saa_targets = scbus->sc_ntargets;
	saa.saa.saa_luns = 1;

	scbus->sc_child = config_found(&sc->sc_dev, &saa.saa, scsiprint);
	if (scbus->sc_child == NULL) {
		printf("%s: can't attach scsibus\n", sc->sc_dev.dv_xname);
		goto free_ccbs;
	}
	return;

 free_ccbs:
	sc->sc_scsibus = NULL;
	sdmmc_free_ccbs(scbus);
 free_sctgt:
	free(scbus->sc_tgt, M_DEVBUF);
	free(scbus, M_DEVBUF);
}

void
sdmmc_scsi_detach(struct sdmmc_softc *sc)
{
	struct sdmmc_scsi_softc *scbus;
	struct sdmmc_ccb *ccb;
{'fraction_non_alphanumeric': 0.10926130099228225, 'fraction_numerical': 0.008930540242557882, 'mean_word_length': 5.067558528428093, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 94, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3181376', 'n_tokens_mistral': 3952, 'n_tokens_neox': 3760, 'n_words': 849}